int usb_cdc_write(usb_cdc_class_t * cl, const void * buf, unsigned int len) { struct usb_cdc_acm_dev * dev = (struct usb_cdc_acm_dev *)cl; uint8_t * ptr = (uint8_t *)buf; unsigned int rem = len; int n; if (dev == NULL) { DCC_LOG(LOG_ERROR, "dev == NULL"); return -1; } #if 0 if (dev->usb == NULL) { DCC_LOG(LOG_ERROR, "dev->usb == NULL"); return -1; } #endif while (rem) { #if 0 FIXME: Flexnet pannel do not set DTE_PRESENT nor ACTIVATE_CARRIER .... // while ((dev->acm.control & CDC_DTE_PRESENT) == 0) { while ((dev->acm.control & CDC_ACTIVATE_CARRIER) == 0) { DCC_LOG(LOG_INFO, "CTL wait..."); thinkos_flag_wait(CTL_FLAG); DCC_LOG(LOG_INFO, "CTL wakeup..."); thinkos_flag_clr_i(CTL_FLAG); } #endif DCC_LOG2(LOG_INFO, "len=%d rem=%d", len, rem); thinkos_flag_take(TX_LOCK); DCC_LOG1(LOG_INFO, "ptr=%p wakeup.", ptr); if ((n = usb_dev_ep_tx_start(dev->usb, dev->in_ep, ptr, rem)) < 0) { DCC_LOG(LOG_WARNING, "usb_dev_ep_tx_start() failed!!"); thinkos_flag_give(TX_LOCK); return n; } if (n == 0) { DCC_LOG(LOG_WARNING, "n == 0!!"); } /* wait for end of transmission */ thinkos_flag_take(TX_DONE); thinkos_flag_give(TX_LOCK); rem -= n; ptr += n; } return len; }
void serdrv_flush(struct serdrv * dev) { unsigned int head; head = dev->tx_fifo.head; thinkos_flag_take(SERDRV_TX_FLAG); if (((int8_t)head - dev->tx_fifo.tail) > 0) thinkos_flag_take(SERDRV_TX_FLAG); stm32_usart_flush(STM32_USART2); thinkos_flag_give(SERDRV_TX_FLAG); }
int serdrv_send(struct serdrv * dev, const void * buf, int len) { uint8_t * cp = (uint8_t *)buf; int rem = len; DCC_LOG1(LOG_INFO, "len=%d", len); while (rem) { unsigned int head; int free; int n; int i; thinkos_flag_take(SERDRV_TX_FLAG); head = dev->tx_fifo.head; free = UART_TX_FIFO_BUF_LEN - (int8_t)(head - dev->tx_fifo.tail); DCC_LOG3(LOG_MSG, "head=%d tail=%d n=%d", head, dev->tx_fifo.tail, n); n = MIN(rem, free); for (i = 0; i < n; ++i) dev->tx_fifo.buf[head++ & (UART_TX_FIFO_BUF_LEN - 1)] = *cp++; dev->tx_fifo.head = head; *dev->txie = 1; if (free > n) thinkos_flag_give(SERDRV_TX_FLAG); rem -= n; DCC_LOG1(LOG_INFO, "rem=%d", rem); } return len; }
int stm32f_serial_flush(struct stm32f_serial_drv * drv) { do { thinkos_flag_take(drv->tx_flag); } while (((int32_t)drv->tx_fifo.head - drv->tx_fifo.tail) > 0); stm32_usart_flush(drv->uart); thinkos_flag_give(drv->tx_flag); return 0; }
int stm32f_serial_write(struct stm32f_serial_drv * drv, const void * buf, unsigned int len) { uint8_t * cp = (uint8_t *)buf; int rem = len; DCC_LOG1(LOG_INFO, "len=%d", len); #if SERIAL_ENABLE_TX_MUTEX thinkos_mutex_lock(drv->tx_mutex); #endif while (rem) { unsigned int head; int free; int n; int i; thinkos_flag_take(drv->tx_flag); head = drv->tx_fifo.head; free = SERIAL_TX_FIFO_LEN - (int32_t)(head - drv->tx_fifo.tail); DCC_LOG3(LOG_MSG, "head=%d tail=%d n=%d", head, drv->tx_fifo.tail, n); n = MIN(rem, free); for (i = 0; i < n; ++i) drv->tx_fifo.buf[head++ & (SERIAL_TX_FIFO_LEN - 1)] = *cp++; drv->tx_fifo.head = head; *drv->txie = 1; if (free > n) thinkos_flag_give(drv->tx_flag); rem -= n; DCC_LOG1(LOG_INFO, "rem=%d", rem); } #if SERIAL_ENABLE_TX_MUTEX thinkos_mutex_unlock(drv->tx_mutex); #endif return len; }
int telnet_svc_read(struct telnet_svc * tn, void * buf, unsigned int len, unsigned int msec) { char * cp = (char *) buf; unsigned int tail; int max; int cnt; int pos; DCC_LOG3(LOG_TRACE, "<%d> len=%d msec=%d", __os_thread_self(), len, msec); /* rx.tail can oly be changed inside this function, it is declared as volatile, for performance reasons we read it only once at the beginning and write it back at the end. */ tail = tn->rx.tail; while (1) { DCC_LOG(LOG_INFO, "flag clr..."); /* get the maximum number of chars we can read from the buffer */ if ((max = tn->rx.head - tail) > 0) break; DCC_LOG(LOG_INFO, "waiting..."); /* wait for a signal indicating that there is some data in the input buffer */ thinkos_flag_take(tn->rx.nonempty_flag); } /* cnt is the number of chars we will read from the buffer, it should be the the minimum of max and len */ cnt = MIN(max, len); /* get the tail position in the buffer */ pos = (tail % TELNET_SVC_RX_BUF_LEN); /* check whether to wrap arround or on not */ if ((pos + cnt) > TELNET_SVC_RX_BUF_LEN) { /* we need to perform two reads */ int n; int m; /* get the number of chars from tail pos until the end of buffer */ n = TELNET_SVC_RX_BUF_LEN - pos; /* the remaining chars are at the beginning of the buffer */ m = cnt - n; DCC_LOG2(LOG_TRACE, "n=%d m=%d", n, m); memcpy(cp, &tn->rx.buf[pos], n); cp += n; memcpy(cp, &tn->rx.buf[0], m); } else { memcpy(cp, &tn->rx.buf[pos], cnt); } tn->rx.tail = tail += cnt; if (cnt) { DCC_LOG(LOG_TRACE, "rx buffer non empty signal"); thinkos_flag_give(tn->rx.nonfull_flag); } return cnt; }
int __attribute__((noreturn)) telnet_input_task(struct telnet_svc * tn) { struct tcp_pcb * svc; struct tcp_pcb * tp; char buf[128]; int sb_len; int len; char * src; int rem; int binary; int state; int c; struct tn_opt opt; unsigned int head; svc = tn->svc; for (;;) { INF("TELNET wating for connection."); DCC_LOG(LOG_TRACE, "TELNET: waiting for connection..."); if ((tp = tcp_accept(svc)) == NULL) { DCC_LOG(LOG_ERROR, "tcp_accept()."); break; } INF("TELNET connection accepted."); DCC_LOG(LOG_TRACE, "TELNET: accepted."); tn->tp = tp; tn_opt_clr(&opt); sb_len = 0; binary = 0; state = TN_DATA; tn_opt_will(tp, &opt, TELOPT_SGA); tn_opt_do(tp, &opt, TELOPT_SGA); tn_opt_will(tp, &opt, TELOPT_ECHO); tn_opt_will(tp, &opt, TELOPT_BINARY); tn_opt_do(tp, &opt, TELOPT_BINARY); head = tn->rx.head; for (;;) { if (head != tn->rx.tail) { /* update the head */ tn->rx.head = head; DCC_LOG1(LOG_TRACE, "rx nonempty: head=%d", head); /* signal the head update */ thinkos_flag_give(tn->rx.nonempty_flag); } /* receive data form network */ if ((len = tcp_recv(tp, buf, 128)) <= 0) { DCC_LOG1(LOG_WARNING, "tcp_recv(): %d", len); break; } DCC_LOG1(LOG_TRACE, "recv: %d", len); /* set the input processing pointer */ src = buf; /* input remaining (to be processed) bytes */ rem = len; while (rem > 0) { c = *src++; rem--; if (state == TN_DATA) { if (c == IAC) { state = TN_IAC_RCVD; } else { if ((binary) || ((c >= 3) && (c < 127))) { /* ASCII characters */ DCC_LOG1(LOG_TRACE, "rx nonempty: head=%d", head); /* buffer is full */ if (head == (tn->rx.tail + TELNET_SVC_RX_BUF_LEN)) { /* update the head */ tn->rx.head = head; /* signal the head update */ thinkos_flag_give(tn->rx.nonempty_flag); /* wait for space in the input buffer */ while (1) { if (head < (tn->rx.tail + TELNET_SVC_RX_BUF_LEN)) { break; } thinkos_flag_take(tn->rx.nonfull_flag); } } tn->rx.buf[head++ % TELNET_SVC_RX_BUF_LEN] = c; } } continue; } /* handles TELNET inputs options */ switch (state) { case TN_IAC_RCVD: switch (c) { case IAC: state = TN_DATA; break; case DONT: state = TN_DONT_RCVD; break; case DO: state = TN_DO_RCVD; break; case WONT: state = TN_WONT_RCVD; break; case WILL: state = TN_WILL_RCVD; break; case SB: state = TN_SUBOPTION_ID; break; case EL: case EC: case AYT: case AO: case IP: case BREAK: case DM: case NOP: case SE: case EOR: case ABORT: case SUSP: case xEOF: default: state = TN_DATA; break; } break; case TN_DONT_RCVD: DCC_LOG1(LOG_TRACE, "DONT %s", TELOPT(c)); tn_opt_wont(tp, &opt, c); state = TN_DATA; break; case TN_DO_RCVD: DCC_LOG1(LOG_TRACE, "DO %s", TELOPT(c)); switch (c) { case TELOPT_SGA: tn_opt_will(tp, &opt, c); break; case TELOPT_ECHO: tn_opt_will(tp, &opt, c); break; case TELOPT_BINARY: tn_opt_will(tp, &opt, c); break; default: tn_opt_wont(tp, &opt, c); } state = TN_DATA; break; case TN_WONT_RCVD: DCC_LOG1(LOG_TRACE, "WONT %s", TELOPT(c)); tn_opt_dont(tp, &opt, c); state = TN_DATA; break; case TN_WILL_RCVD: DCC_LOG1(LOG_TRACE, "WILL %s", TELOPT(c)); switch (c) { case TELOPT_ECHO: tn_opt_dont(tp, &opt, c); break; case TELOPT_SGA: tn_opt_do(tp, &opt, c); break; case TELOPT_BINARY: tn_opt_do(tp, &opt, c); binary = 1; break; default: tn_opt_dont(tp, &opt, c); } state = TN_DATA; break; case TN_SUBOPTION_ID: state = TN_SUBOPTION; break; case TN_SUBOPTION: if (c == IAC) state = TN_SB_IAC_RCVD; if (sb_len < TN_SB_BUF_LEN) { DCC_LOG1(LOG_TRACE, "suboption: %d", c); } // sb_buf[sb_len++] = c; break; case TN_SB_IAC_RCVD: if (c == SE) { state = TN_DATA; // tn_suboption(cpc, sb_buf, sb_len); } else { state = TN_SUBOPTION; // sb_buf[sb_len++] = c; } break; case TN_INVALID_SUBOPTION: if (c == IAC) state = TN_INVALID_SB_IAC_RCVD; break; case TN_INVALID_SB_IAC_RCVD: if (c == SE) state = TN_DATA; else state = TN_INVALID_SUBOPTION; break; default: DCC_LOG1(LOG_WARNING, "invalid state: %d!!", state); break; } } } DCC_LOG(LOG_TRACE, "close..."); tcp_close(tp); INF("TELNET connection closed."); tn->tp = NULL; } DCC_LOG(LOG_ERROR, "thread loop break!!!"); for(;;); }