/** * @brief Callback for data receiving * * The callback function provided to device driver for being notified when * driver received a data stream. * * This function Must be called from interrupt context. * * It put the current operation to received queue and gets another operation to * continue receiving. Then notifies rx thread to process. * * @param buffer Data buffer. * @param length Received data length. * @param error Error code when driver receiving. * @return None. */ static void uart_rx_callback(uint8_t *buffer, int length, int error) { struct op_node *node; int ret; *info->rx_node->data_size = cpu_to_le16(length); put_node_back(&info->data_queue, info->rx_node); /* notify rx thread to process this data*/ sem_post(&info->rx_sem); node = get_node_from(&info->free_queue); if (!node) { /* * there is no free buffer, inform the rx thread to engage another uart * receiver. */ info->require_node = 1; return; } info->rx_node = node; ret = device_uart_start_receiver(info->dev, node->buffer, info->rx_buf_size, NULL, NULL, uart_rx_callback); if (ret) { uart_report_error(GB_UART_EVENT_PROTOCOL_ERROR, __func__); } }
/** * @brief Allocate operations for receiver buffers * * This function is allocating operation and use them as receiving buffers. * * @param max_nodes Maximum nodes. * @param buf_size Buffer size in operation. * @param queue Target queue. * @return 0 for success, -errno for failures. */ static int uart_alloc_op(int max_nodes, int buf_size, sq_queue_t *queue) { struct gb_operation *operation = NULL; struct gb_uart_receive_data_request *request = NULL; struct op_node *node = NULL; int i = 0; for (i = 0; i < max_nodes; i++) { operation = gb_operation_create(info->cport, GB_UART_PROTOCOL_RECEIVE_DATA, sizeof(*request) + buf_size); if (!operation) { goto err_free_op; } node = malloc(sizeof(struct op_node)); if (!node) { gb_operation_destroy(operation); goto err_free_op; } node->operation = operation; request = gb_operation_get_request_payload(operation); node->data_size = &request->size; node->buffer = request->data; put_node_back(queue, node); } return 0; err_free_op: uart_free_op(queue); return -ENOMEM; }
/** * @brief Data receiving process thread * * This function is the thread for processing data receiving tasks. When * it wake up, it checks the receiving queue for processing the come in data. * If protocol is running out of buffer, as soon as it gets a free buffer, * it passes to driver for continuing the receiving. * * @param data The regular thread data. * @return None. */ static void *uart_rx_thread(void *data) { struct gb_operation *operation = NULL; struct gb_uart_receive_data_request *request = NULL; struct buf_node *node = NULL; struct gb_bundle *bundle = data; struct gb_uart_info *info = bundle->priv; struct device *dev = bundle->dev; int ret; while (1) { sem_wait(&info->rx_sem); if (info->thread_stop) { break; } node = get_node_from(&info->data_queue); if (node) { operation = gb_operation_create(info->cport, GB_UART_PROTOCOL_RECEIVE_DATA, sizeof(*request) + node->data_size); if (!operation) { uart_report_error(GB_UART_EVENT_PROTOCOL_ERROR, __func__); } else { request = gb_operation_get_request_payload(operation); request->size = cpu_to_le16(node->data_size); request->flags = node->data_flags; memcpy(request->data, node->buffer, node->data_size); ret = gb_operation_send_request(operation, NULL, false); if (ret) { uart_report_error(GB_UART_EVENT_PROTOCOL_ERROR, __func__); } gb_operation_destroy(operation); } put_node_back(&info->free_queue, node); } /* * In case there is no free node in callback. */ if (info->require_node) { node = get_node_from(&info->free_queue); info->rx_node = node; ret = device_uart_start_receiver(dev, node->buffer, info->rx_buf_size, NULL, NULL, uart_rx_callback); if (ret) { uart_report_error(GB_UART_EVENT_DEVICE_ERROR, __func__); } info->require_node = 0; } } return NULL; }
/** * @brief Callback for data receiving * * The callback function provided to device driver for being notified when * driver received a data stream. * * This function Must be called from interrupt context. * * It put the current buffer to received queue and gets another buffer to * continue receiving. Then notifies rx thread to process. * * @param dev Pointer to the UART device controller * @param data Pointer to struct gb_uart_info. * @param buffer Data buffer. * @param length Received data length. * @param error Error code when driver receiving. * @return None. */ static void uart_rx_callback(struct device *dev, void *data, uint8_t *buffer, int length, int error) { struct gb_uart_info *info; struct buf_node *node; int ret; uint8_t flags = 0; DEBUGASSERT(data); info = data; info->rx_node->data_size = length; if (error & LSR_OE) { flags |= GB_UART_RECV_FLAG_OVERRUN; } if (error & LSR_PE) { flags |= GB_UART_RECV_FLAG_PARITY; } if (error & LSR_FE) { flags |= GB_UART_RECV_FLAG_FRAMING; } if (error & LSR_BI) { flags |= GB_UART_RECV_FLAG_BREAK; } info->rx_node->data_flags = flags; put_node_back(&info->data_queue, info->rx_node); /* notify rx thread to process this data*/ sem_post(&info->rx_sem); node = get_node_from(&info->free_queue); if (!node) { /* * there is no free buffer, inform the rx thread to engage another uart * receiver. */ info->require_node = 1; return; } info->rx_node = node; ret = device_uart_start_receiver(dev, node->buffer, info->rx_buf_size, NULL, NULL, uart_rx_callback); if (ret) { uart_report_error(GB_UART_EVENT_PROTOCOL_ERROR, __func__); } }
/** * @brief Allocate receiver buffers * * This function is allocating receiving buffers. * * @param max_nodes Maximum nodes. * @param buf_size Buffer size in operation. * @param queue Target queue. * @return 0 for success, errno for failures. */ static int uart_alloc_buf(int max_nodes, int buf_size, sq_queue_t *queue) { struct buf_node *node = NULL; int i = 0; for (i = 0; i < max_nodes; i++) { node = malloc(sizeof(*node) + buf_size); if (!node) { /* * It may have some buffers already be allocated, caller should * free them. */ return ENOMEM; /* Keeping consistency with Nuttx APIs, so returns positive num */ } put_node_back(queue, node); } return 0; }
/** * @brief Data receiving process thread * * This function is the thread for processing data receiving tasks. When * it wake up, it checks the receiving queue for processing the come in data. * If protocol is running out of operation, once it gets a free operation, * it passes to driver for continuing the receiving. * * @param data The regular thread data. * @return None. */ static void *uart_rx_thread(void *data) { struct op_node *node = NULL; int ret; while (1) { sem_wait(&info->rx_sem); if (info->thread_stop) { break; } node = get_node_from(&info->data_queue); if (node) { ret = gb_operation_send_request(node->operation, NULL, false); if (ret) { uart_report_error(GB_UART_EVENT_PROTOCOL_ERROR, __func__); } put_node_back(&info->free_queue, node); } /* * In case there is no free node in callback. */ if (info->require_node) { node = get_node_from(&info->free_queue); info->rx_node = node; ret = device_uart_start_receiver(info->dev, node->buffer, info->rx_buf_size, NULL, NULL, uart_rx_callback); if (ret) { uart_report_error(GB_UART_EVENT_DEVICE_ERROR, __func__); } info->require_node = 0; } } return NULL; }