summaryrefslogtreecommitdiff
path: root/src/ipa/ipu3
AgeCommit message (Expand)Author
2024-12-06ipa: ipu3: Add constructor to the IPA contextMilan Zamazal
2024-11-26ipa: libipa: colour: Use the RGB class to model RGB valuesLaurent Pinchart
2024-11-26ipa: ipu3: awb: Replace Awb::RGB class with ipa::RGBLaurent Pinchart
2024-11-26libcamera: Rename "shutter speed" to "exposure time"Laurent Pinchart
2024-11-18ipa: ipu3: Use centralised libipa helpersDaniel Scally
2024-11-11libcamera: Rationalize IPA and handlers namesJacopo Mondi
2024-09-03libcamera: ipa: Drop unneded includes from ipa_interface.hLaurent Pinchart
2024-09-02libcamera: ipu3: Formatting improvementsMilan Zamazal
2024-09-02libcamera: ipu3: Remove unused includesMilan Zamazal
2024-08-07libcamera: Drop libcamera_generated_ipa_headers from sourcesLaurent Pinchart
2024-06-11meson: Group libipa and libipa_includes in a dependency objectLaurent Pinchart
2024-05-14libcamera: pipeline: Rename pipelines to a shorter nameJulien Vuillaumier
2024-05-09libcamera: Drop remaining file name from header comment blocksLaurent Pinchart
2024-05-08libcamera: Drop file name from header comment blocksLaurent Pinchart
2024-05-08ipa: ipu3: Remove bespoke AGC functions from IPU3Daniel Scally
2024-05-08ipa: ipu3: Derive ipu3::algorithms::Agc from AgcMeanLuminanceDaniel Scally
2023-12-07meson: Tag all installed filesLaurent Pinchart
2023-06-06ipa: ipu3: agc: Drop hard-codec analogue gain maxJacopo Mondi
2023-05-04ipa: meson: Allow nested IPA directory structuresNaushir Patuck
2022-11-23libcamera: Move IPA sensor controls validation to CameraSensorJacopo Mondi
2022-11-09ipa: Sort algorithm operations based on calling orderLaurent Pinchart
2022-10-24ipa: ipu3: Fill AGC and AWB metadata in algorithmsLaurent Pinchart
2022-10-24ipa: Pass metadata to Algorithm::process() functionLaurent Pinchart
2022-10-19ipa: Drop period at end of \brief or \paramLaurent Pinchart
2022-10-18camera_sensor: Add minimum and maximum line length to IPACameraSensorInfoNaushir Patuck
2022-10-07ipa: camera_sensor_helper: Implement factories through class templatesLaurent Pinchart
2022-10-07ipa: ipu3: Fix minor Doxygen issues in IPAFrameContextLaurent Pinchart
2022-10-03ipa: ipu3: Correct context during configure()Kieran Bingham
2022-09-30Documentation: Add missing SPDX headersLaurent Pinchart
2022-09-28ipa: ipu3: Pass controls to algorithm's queueRequest() handlerLaurent Pinchart
2022-09-28ipa: ipu3: Use the FCQueueLaurent Pinchart
2022-09-28ipa: ipu3: Use base FrameContext classLaurent Pinchart
2022-09-28ipa: libipa: algorithm: process(): Pass frame numberKieran Bingham
2022-09-28ipa: libipa: algorithm: prepare(): Pass frame and frame ContextKieran Bingham
2022-09-27ipa: libipa: Pass a reference instead of pointer to Algorithm::process()Laurent Pinchart
2022-09-27ipa: ipu3: af: Pass context reference to afIsOutOfFocus()Laurent Pinchart
2022-09-27ipa: ipu3: Fix style of Doxygen comment blocksLaurent Pinchart
2022-08-30ipa: ipu3: Remove redundant call of std::string::c_str()Marvin Schmidt
2022-08-09ipa: ipu3: Add YAML tuning file supportLaurent Pinchart
2022-08-09ipa: ipu3: Register algorithmsLaurent Pinchart
2022-08-09ipa: ipu3: Add an uncalibrated.yaml tuning data fileLaurent Pinchart
2022-07-20libcamera: Remove extra ':' after '\todo'Laurent Pinchart
2022-06-29ipa: libipa: Introduce a Module class templateLaurent Pinchart
2022-06-18ipa: ipu3: awb: Correct the gains calculationJean-Michel Hautbois
2022-05-18ipa: ipu3: Put IPAFrameContext(s) in a ring bufferUmang Jain
2022-05-18ipa: libipa: Add frame context pointer in process()Umang Jain
2022-05-18ipa: ipu3: Rework IPAFrameContextUmang Jain
2022-04-14ipa: ipu3: af: A not initialized frame ignore counter fixingKate Hsuan
2022-04-09ipa: ipu3: af: Simplify accumulations of y_itemsKieran Bingham
2022-04-09ipa: ipu3: af: Use Span for y_table_item_tKieran Bingham
#include <poll.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> #include "log.h" /** * \file ipc_unixsocket.h * \brief IPC mechanism based on Unix sockets */ namespace libcamera { LOG_DEFINE_CATEGORY(IPCUnixSocket) /** * \struct IPCUnixSocket::Payload * \brief Container for an IPC payload * * Holds an array of bytes and an array of file descriptors that can be * transported across a IPC boundary. */ /** * \var IPCUnixSocket::Payload::data * \brief Array of bytes to cross IPC boundary */ /** * \var IPCUnixSocket::Payload::fds * \brief Array of file descriptors to cross IPC boundary */ /** * \class IPCUnixSocket * \brief IPC mechanism based on Unix sockets * * The Unix socket IPC allows bidirectional communication between two processes * through unnamed Unix sockets. It implements datagram-based communication, * transporting entire payloads with guaranteed ordering. * * The IPC design is asynchronous, a message is queued to a receiver which gets * notified that a message is ready to be consumed by the \ref readyRead * signal. The sender of the message gets no notification when a message is * delivered nor processed. If such interactions are needed a protocol specific * to the users use-case should be implemented on top of the IPC objects. * * Establishment of an IPC channel is asymmetrical. The side that initiates * communication first instantiates a local side socket and creates the channel * with create(). The method returns a file descriptor for the remote side of * the channel, which is passed to the remote process through an out-of-band * communication method. The remote side then instantiates a socket, and binds * it to the other side by passing the file descriptor to bind(). At that point * the channel is operation and communication is bidirectional and symmmetrical. */ IPCUnixSocket::IPCUnixSocket() : fd_(-1), headerReceived_(false), notifier_(nullptr) { } IPCUnixSocket::~IPCUnixSocket() { close(); } /** * \brief Create an new IPC channel * * This method creates a new IPC channel. The socket instance is bound to the * local side of the channel, and the method returns a file descriptor bound to * the remote side. The caller is responsible for passing the file descriptor to * the remote process, where it can be used with IPCUnixSocket::bind() to bind * the remote side socket. * * \return A file descriptor on success, negative error code on failure */ int IPCUnixSocket::create() { int sockets[2]; int ret; ret = socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sockets); if (ret) { ret = -errno; LOG(IPCUnixSocket, Error) << "Failed to create socket pair: " << strerror(-ret); return ret; } ret = bind(sockets[0]); if (ret) return ret; return sockets[1]; } /** * \brief Bind to an existing IPC channel * \param[in] fd File descriptor * * This method binds the socket instance to an existing IPC channel identified * by the file descriptor \a fd. The file descriptor is obtained from the * IPCUnixSocket::create() method. * * \return 0 on success or a negative error code otherwise */ int IPCUnixSocket::bind(int fd) { if (isBound()) return -EINVAL; fd_ = fd; notifier_ = new EventNotifier(fd_, EventNotifier::Read); notifier_->activated.connect(this, &IPCUnixSocket::dataNotifier); return 0; } /** * \brief Close the IPC channel * * No communication is possible after close() has been called. */ void IPCUnixSocket::close() { if (!isBound()) return; delete notifier_; notifier_ = nullptr; ::close(fd_); fd_ = -1; headerReceived_ = false; } /** * \brief Check if the IPC channel is bound * \return True if the IPC channel is bound, false otherwise */ bool IPCUnixSocket::isBound() const { return fd_ != -1; } /** * \brief Send a message payload * \param[in] payload Message payload to send * * This method queues the message payload for transmission to the other end of * the IPC channel. It returns immediately, before the message is delivered to * the remote side. * * \return 0 on success or a negative error code otherwise */ int IPCUnixSocket::send(const Payload &payload) { int ret; if (!isBound()) return -ENOTCONN; Header hdr; hdr.data = payload.data.size(); hdr.fds = payload.fds.size(); if (!hdr.data && !hdr.fds) return -EINVAL; ret = ::send(fd_, &hdr, sizeof(hdr), 0); if (ret < 0) { ret = -errno; LOG(IPCUnixSocket, Error) << "Failed to send: " << strerror(-ret); return ret; } return sendData(payload.data.data(), hdr.data, payload.fds.data(), hdr.fds); } /** * \brief Receive a message payload * \param[out] payload Payload where to write the received message * * This method receives the message payload from the IPC channel and writes it * to the \a payload. If no message payload is available, it returns * immediately with -EAGAIN. The \ref readyRead signal shall be used to receive * notification of message availability. * * \todo Add state machine to make sure we don't block forever and that * a header is always followed by a payload. * * \return 0 on success or a negative error code otherwise * \retval -EAGAIN No message payload is available * \retval -ENOTCONN The socket is not connected (neither create() nor bind() * has been called) */ int IPCUnixSocket::receive(Payload *payload) { if (!isBound()) return -ENOTCONN; if (!headerReceived_) return -EAGAIN; payload->data.resize(header_.data); payload->fds.resize(header_.fds); int ret = recvData(payload->data.data(), header_.data, payload->fds.data(), header_.fds); if (ret < 0) return ret; headerReceived_ = false; notifier_->setEnabled(true); return 0; } /** * \var IPCUnixSocket::readyRead * \brief A Signal emitted when a message is ready to be read */ int IPCUnixSocket::sendData(const void *buffer, size_t length, const int32_t *fds, unsigned int num) { struct iovec iov[1]; iov[0].iov_base = const_cast<void *>(buffer); iov[0].iov_len = length; char buf[CMSG_SPACE(num * sizeof(uint32_t))]; memset(buf, 0, sizeof(buf)); struct cmsghdr *cmsg = (struct cmsghdr *)buf; cmsg->cmsg_len = CMSG_LEN(num * sizeof(uint32_t)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; struct msghdr msg; msg.msg_name = nullptr; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = cmsg; msg.msg_controllen = cmsg->cmsg_len; msg.msg_flags = 0; memcpy(CMSG_DATA(cmsg), fds, num * sizeof(uint32_t)); if (sendmsg(fd_, &msg, 0) < 0) { int ret = -errno; LOG(IPCUnixSocket, Error) << "Failed to sendmsg: " << strerror(-ret); return ret; } return 0; } int IPCUnixSocket::recvData(void *buffer, size_t length, int32_t *fds, unsigned int num) { struct iovec iov[1]; iov[0].iov_base = buffer; iov[0].iov_len = length; char buf[CMSG_SPACE(num * sizeof(uint32_t))]; memset(buf, 0, sizeof(buf)); struct cmsghdr *cmsg = (struct cmsghdr *)buf; cmsg->cmsg_len = CMSG_LEN(num * sizeof(uint32_t)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; struct msghdr msg; msg.msg_name = nullptr; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = cmsg; msg.msg_controllen = cmsg->cmsg_len; msg.msg_flags = 0; if (recvmsg(fd_, &msg, 0) < 0) { int ret = -errno; if (ret != -EAGAIN) LOG(IPCUnixSocket, Error) << "Failed to recvmsg: " << strerror(-ret); return ret; } memcpy(fds, CMSG_DATA(cmsg), num * sizeof(uint32_t)); return 0; } void IPCUnixSocket::dataNotifier(EventNotifier *notifier) { int ret; if (!headerReceived_) { /* Receive the header. */ ret = ::recv(fd_, &header_, sizeof(header_), 0); if (ret < 0) { ret = -errno; LOG(IPCUnixSocket, Error) << "Failed to receive header: " << strerror(-ret); return; } headerReceived_ = true; } /* * If the payload has arrived, disable the notifier and emit the * readyRead signal. The notifier will be reenabled by the receive() * method. */ struct pollfd fds = { fd_, POLLIN, 0 }; ret = poll(&fds, 1, 0); if (ret < 0) return; if (!(fds.revents & POLLIN)) return; notifier_->setEnabled(false); readyRead.emit(this); } } /* namespace libcamera */