static void handle_signals(const char *req, int *req_index) { // No arguments (void) req; (void) req_index; if (!uart_is_open(uart)) { send_error_response("ebadf"); return; } struct uart_signals sig; if (uart_get_signals(uart, &sig) >= 0) { char resp[128]; int resp_index = sizeof(uint16_t); resp[resp_index++] = response_id; ei_encode_version(resp, &resp_index); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "ok"); ei_encode_map_header(resp, &resp_index, 8); encode_kv_bool(resp, &resp_index, "dsr", sig.dsr); encode_kv_bool(resp, &resp_index, "dtr", sig.dtr); encode_kv_bool(resp, &resp_index, "rts", sig.rts); encode_kv_bool(resp, &resp_index, "st", sig.st); encode_kv_bool(resp, &resp_index, "sr", sig.sr); encode_kv_bool(resp, &resp_index, "cts", sig.cts); encode_kv_bool(resp, &resp_index, "cd", sig.cd); encode_kv_bool(resp, &resp_index, "rng", sig.rng); erlcmd_send(resp, resp_index); } else send_error_response(uart_last_error()); }
static void handle_flush(const char *req, int *req_index) { char dirstr[MAXATOMLEN]; if (ei_decode_atom(req, req_index, dirstr) < 0) { send_error_response("einval"); return; } enum uart_direction direction; if (strcmp(dirstr, "receive") == 0) direction = UART_DIRECTION_RECEIVE; else if (strcmp(dirstr, "transmit") == 0) direction = UART_DIRECTION_TRANSMIT; else if (strcmp(dirstr, "both") == 0) direction = UART_DIRECTION_BOTH; else { send_error_response("einval"); return; } if (!uart_is_open(uart)) { send_error_response("ebadf"); return; } if (uart_flush(uart, direction) >= 0) send_ok_response(); else send_error_response(uart_last_error()); }
static void handle_write_completed(int rc, const uint8_t *data) { free((uint8_t *) data); if (rc == 0) send_ok_response(); else send_error_response(uart_last_error()); }
static void handle_drain(const char *req, int *req_index) { (void) req; (void) req_index; if (!uart_is_open(uart)) { send_error_response("ebadf"); return; } if (uart_drain(uart) >= 0) send_ok_response(); else send_error_response(uart_last_error()); }
/* Called when uart_read completes or fails */ static void handle_read_completed(int rc, const uint8_t *data, size_t len) { if (rc >= 0) { char *resp = malloc(32 + len); int resp_index = sizeof(uint16_t); ei_encode_version(resp, &resp_index); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "ok"); ei_encode_binary(resp, &resp_index, data, len); erlcmd_send(resp, resp_index); free(resp); } else send_error_response(uart_last_error()); }
static void handle_configure(const char *req, int *req_index) { struct uart_config config = current_config; if (parse_option_list(req, req_index, &config) < 0) { send_error_response("einval"); return; } if (uart_configure(uart, &config) >= 0) { current_config = config; send_ok_response(); } else { send_error_response(uart_last_error()); } }
static void handle_set_break(const char *req, int *req_index) { int val; if (ei_decode_boolean(req, req_index, &val) < 0) { send_error_response("einval"); return; } if (!uart_is_open(uart)) { send_error_response("ebadf"); return; } if (uart_set_break(uart, !!val) >= 0) send_ok_response(); else send_error_response(uart_last_error()); }
/* Called in active mode when there's a read or an error */ static void handle_notify_read(int error_reason, const uint8_t *data, size_t len) { char *resp = malloc(64 + len); int resp_index = sizeof(uint16_t); ei_encode_version(resp, &resp_index); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "notif"); if (error_reason == 0) { // Normal receive ei_encode_binary(resp, &resp_index, data, len); } else { // Error notification ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, uart_last_error()); } erlcmd_send(resp, resp_index); free(resp); }
/* * Handle {name, kv_list} * * name is the serial port name * kv_list a list of configuration values (speed, parity, etc.) */ static void handle_open(const char *req, int *req_index) { int term_type; int term_size; if (ei_decode_tuple_header(req, req_index, &term_size) < 0 || term_size != 2) errx(EXIT_FAILURE, ":open requires a 2-tuple"); char name[32]; long binary_len; if (ei_get_type(req, req_index, &term_type, &term_size) < 0 || term_type != ERL_BINARY_EXT || term_size >= (int) sizeof(name) || ei_decode_binary(req, req_index, name, &binary_len) < 0) { // The name is almost certainly too long, so report that it // doesn't exist. send_error_response("enoent"); return; } name[term_size] = '\0'; struct uart_config config = current_config; if (parse_option_list(req, req_index, &config) < 0) { send_error_response("einval"); return; } // If the uart was already open, close and open it again if (uart_is_open(uart)) uart_close(uart); if (uart_open(uart, name, &config) >= 0) { current_config = config; send_ok_response(); } else { send_error_response(uart_last_error()); } }
//-------------------------------------------------------------------------- // Transmit message over the bus. Message is readed from the given // buffer position. While transmitting we check if bus is free and if // same bit was recieved as transmitted. This ensures correct handling // This method is time critical and interrupts will be disabled. //-------------------------------------------------------------------------- posptr_t ibus_transmit_msg(posptr_t from, posptr_t len) { posptr_t oldFrom = from; #ifdef RXTX_COMPARE if (g_ibus_State != IBUS_STATE_TRANSMITTING) return from; IBUS_RX_DIS_INT(); #else if (IBUS_SENSTA_VALUE()) return from; // we currently disable interrupt of TH3122, we will ask it manually here IBUS_SENSTA_DIS_INT(); #endif while(len > 0) { // load byte to transmit uint8_t byte = g_ibus_TxBuffer[from]; uint8_t sent = byte; uint8_t par = 0; // transmit start bit and check if collision happens bit_clear(IBUS_TX_PORT, IBUS_TX_PIN); #ifdef RXTX_COMPARE IBUS_BAUD_HDELAY(); if (IBUS_RX_VALUE() != 0) goto collision; IBUS_BAUD_HDELAY(); #else IBUS_BAUD_DELAY(); if (IBUS_SENSTA_VALUE()) goto collision; #endif // transmit bitwise and compute parity bit // while transmitting check if collision was detected int8_t i; for (i = 0; i < 8; i++, byte>>=1) { par ^= (byte & 1); if (byte & 1) bit_set(IBUS_TX_PORT, IBUS_TX_PIN); else bit_clear(IBUS_TX_PORT, IBUS_TX_PIN); #ifdef RXTX_COMPARE IBUS_BAUD_HDELAY(); if (IBUS_RX_VALUE() != (byte & 1)) goto collision; IBUS_BAUD_HDELAY(); #else IBUS_BAUD_DELAY(); if (IBUS_SENSTA_VALUE()) goto collision; #endif } // send parity bit if (par & 1) bit_set(IBUS_TX_PORT, IBUS_TX_PIN); else bit_clear(IBUS_TX_PORT, IBUS_TX_PIN); #ifdef RXTX_COMPARE IBUS_BAUD_HDELAY(); if (IBUS_RX_VALUE() != (par & 1)) goto collision; IBUS_BAUD_HDELAY(); #else IBUS_BAUD_DELAY(); if (IBUS_SENSTA_VALUE()) goto collision; #endif // send stop bit bit_set(IBUS_TX_PORT, IBUS_TX_PIN); #ifdef RXTX_COMPARE IBUS_BAUD_HDELAY(); if (IBUS_RX_VALUE() != 1) goto collision; IBUS_BAUD_HDELAY(); #else IBUS_BAUD_DELAY(); if (IBUS_SENSTA_VALUE()) goto collision; #endif // update current pointers from = inc_posptr_tx(from); len--; // we should have now received the same byte through uart rx // check if there was no frame error and if the received byte is the right one if (!uart_available()) goto collision; if (uart_lastc() != sent) goto collision; if (uart_last_error()) goto collision; } // if everything went fine, then we will return new from position oldFrom = from; // return on failure collision: IBUS_TX_SETUP(); #ifdef RXTX_COMPARE IBUS_RX_ENA_INT(); #else IBUS_SENSTA_ENA_INT(); #endif //END_ATOMAR; return oldFrom; }
//-------------------------------------------------------------------------- void ibus_tick() { // if we have data in the receive buffer, then handle it while(uart_available()) { uint8_t data = uart_getc(); if (uart_last_error()) { uart_clear_error(); g_ibus_State = IBUS_STATE_WAIT_FREE_BUS; IBUS_TIMEOUT_RECEIVE_ERROR(); break; }else ibus_recieveCallback(data); } // if no data in the buffer or we are not idle, then do nothing if (!ibus_readyToTransmit()) return; // ok we are idle and we have data in the buffer, then first, wait for free buffer #ifndef RXTX_COMPARE if (IBUS_SENSTA_VALUE()) { g_ibus_State = IBUS_STATE_WAIT_FREE_BUS; IBUS_TIMEOUT_WAIT_FREE_BUS(); return; } #endif g_ibus_State = IBUS_STATE_TRANSMITTING; uart_clear_error(); // start fresh :) // ok bus is free, we can submit a message posptr_t tryCounterPos = g_ibus_TxReadPos; int8_t numberOfTries = g_ibus_TxBuffer[g_ibus_TxReadPos]; g_ibus_TxReadPos = inc_posptr_tx(g_ibus_TxReadPos); posptr_t len = (posptr_t)g_ibus_TxBuffer[(g_ibus_TxReadPos + 1) & IBUS_MSG_TX_BUFFER_SIZE_MASK]; // transmit message posptr_t oldTxPos = g_ibus_TxReadPos; posptr_t newTxPos = ibus_transmit_msg(g_ibus_TxReadPos, len + 2); // from here we are free to clear all errors uart_clear_error(); // if there was a collision, then resend message if we still have trials if (newTxPos == oldTxPos) { numberOfTries--; if (numberOfTries >= 0) { g_ibus_TxBuffer[tryCounterPos] = numberOfTries; g_ibus_TxReadPos = tryCounterPos; g_ibus_State = IBUS_STATE_WAIT_FREE_BUS; IBUS_TIMEOUT_COLLISION(); return; } newTxPos = (posptr_t)(oldTxPos + len + 2) & IBUS_MSG_TX_BUFFER_SIZE_MASK; // if there was no collision, then we have received the same message as sent, so just flush it }else uart_flush(0); // ok message was either submitted successfully or message trials // counter is elapsed, we flush tx buffer and continue g_ibus_TxReadPos = newTxPos; g_ibus_State = IBUS_STATE_WAIT_FREE_BUS; IBUS_TIMEOUT_AFTER_TRANSMIT(); }