void esp_sj_uart_dispatcher(void *arg) { int uart_no = (int) arg; struct esp_sj_uart_state *us = &sj_us[uart_no]; cs_rbuf_t *txb = esp_uart_tx_buf(uart_no); us->dispatch_pending = 0; esp_uart_dispatch_rx_top(uart_no); uint16_t tx_used_before = txb->used; /* ignore unused because of CS_DISABLE_JS below */ (void) tx_used_before; esp_uart_dispatch_tx_top(uart_no); #ifndef CS_DISABLE_JS cs_rbuf_t *rxb = esp_uart_rx_buf(uart_no); if (us->v7 != NULL) { /* Detect the edge of TX buffer becoming empty. */ if (tx_used_before > 0 && txb->used == 0) { v7_val_t txcb = v7_get(us->v7, us->obj, "_txcb", 5); if (v7_is_callable(us->v7, txcb)) { sj_invoke_cb(us->v7, txcb, us->obj, V7_UNDEFINED); } } if (rxb->used > 0) { /* Check for JS recv handler. */ v7_val_t rxcb = esp_sj_uart_get_recv_handler(uart_no); if (v7_is_callable(us->v7, rxcb)) { if (!us->recv_pending) { us->recv_pending = 1; sj_invoke_cb(us->v7, rxcb, us->obj, V7_UNDEFINED); /* Note: Callback has not run yet, it has been scheduled. */ } } else if (us->prompt) { uint8_t *cp; while (rxb != NULL && cs_rbuf_get(rxb, 1, &cp) == 1) { char c = (char) *cp; cs_rbuf_consume(rxb, 1); sj_prompt_process_char(c); /* UART could've been re-initialized by the command from prompt. */ rxb = esp_uart_rx_buf(uart_no); } } } } #endif esp_uart_dispatch_bottom(uart_no); }
static enum v7_err UART_recv(struct v7 *v7, v7_val_t *res) { struct esp_sj_uart_state *us; enum v7_err ret = esp_sj_uart_get_state(v7, &us); if (ret != V7_OK) return ret; cs_rbuf_t *rxb = esp_uart_rx_buf(us->uart_no); size_t len = MIN((size_t) v7_to_number(v7_arg(v7, 0)), rxb->used); uint8_t *data; len = cs_rbuf_get(rxb, len, &data); *res = v7_mk_string(v7, (const char *) data, len, 1 /* copy */); cs_rbuf_consume(rxb, len); us->recv_pending = 0; /* This is required to unblock interrupts after buffer has been filled. * And won't hurt in general. */ esp_sj_uart_schedule_dispatcher(us->uart_no); return V7_OK; }
IRAM void miot_uart_dev_dispatch_tx_top(struct miot_uart_state *us) { int uart_no = us->uart_no; cs_rbuf_t *txb = &us->tx_buf; uint32_t txn = 0; /* TX */ if (txb->used > 0) { while (txb->used > 0) { int i; uint8_t *data; uint16_t len; int tx_av = us->cfg->tx_fifo_full_thresh - esp_uart_tx_fifo_len(uart_no); if (tx_av <= 0) break; len = cs_rbuf_get(txb, tx_av, &data); for (i = 0; i < len; i++, data++) { tx_byte(uart_no, *data); } txn += len; cs_rbuf_consume(txb, len); } us->stats.tx_bytes += txn; } }
void mgos_uart_hal_dispatch_rx_top(struct mgos_uart_state *us) { bool recd; struct cc32xx_uart_state *ds = (struct cc32xx_uart_state *) us->dev_data; cs_rbuf_t *irxb = &ds->isr_rx_buf; MAP_UARTIntDisable(ds->base, UART_RX_INTS); recv_more: recd = false; cc32xx_uart_rx_bytes(ds->base, irxb); while (irxb->used > 0 && mgos_uart_rxb_free(us) > 0) { int num_recd = 0; do { uint8_t *data; int num_to_get = MIN(mgos_uart_rxb_free(us), irxb->used); num_recd = cs_rbuf_get(irxb, num_to_get, &data); mbuf_append(&us->rx_buf, data, num_recd); cs_rbuf_consume(irxb, num_recd); us->stats.rx_bytes += num_recd; if (num_recd > 0) recd = true; cc32xx_uart_rx_bytes(ds->base, irxb); } while (num_recd > 0); } /* If we received something during this cycle and there is buffer space * available, "linger" for some more, maybe there's more to come. */ if (recd && mgos_uart_rxb_free(us) > 0 && us->cfg.rx_linger_micros > 0) { /* Magic constants below are tweaked so that the loop takes at most the * configured number of microseconds. */ int ctr = us->cfg.rx_linger_micros * 31 / 12; // HWREG(GPIOA1_BASE + GPIO_O_GPIO_DATA + 8) = 0xFF; /* Pin 64 */ while (ctr-- > 0) { if (MAP_UARTCharsAvail(ds->base)) { us->stats.rx_linger_conts++; goto recv_more; } } // HWREG(GPIOA1_BASE + GPIO_O_GPIO_DATA + 8) = 0; /* Pin 64 */ } MAP_UARTIntClear(ds->base, UART_RX_INTS); }