diff --git a/common/transport/transport.c b/common/transport/transport.c index e9b5538f5e1c0c8f90d52b50878ab62993e207a9..ff5d62c2f773924e0b1930927e4279821aabdb81 100644 --- a/common/transport/transport.c +++ b/common/transport/transport.c @@ -2,7 +2,7 @@ #define USART_NAME USART #undef USART_USE_AS_STDOUT -#define BAUD 2400 +#define BAUD 9600 // #define USART_USE_AS_STDOUT //Debugging only! void USART_recv_interrupt(void); #define USART_NUMBER TRANSPORT_USART_NUMBER @@ -26,18 +26,82 @@ void USART_recv_interrupt(void); interrupt_msg_handler_t interrupt_msg_table[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; -volatile uint8_t msg_start_received = 0; - -uint16_t transport_receive_char(uint16_t timeout); +#define RECV_IDLE 0x00 +#define RECV_START 0x01 +#define RECV_BODY 0x02 +#define RECV_CHECKSUM 0x03 +#define RECV_FINISHED 0x04 +#define RECV_ERROR 0x0A +#define RECV_ESCAPE_FLAG 0x40 +#define RECV_INTERRUPT_FLAG 0x80 +#define RECV_SET_STATE(s) {msg_recv_state = (msg_recv_state & (RECV_ESCAPE_FLAG | RECV_INTERRUPT_FLAG)) | s;} +#define RECV_STATE() (msg_recv_state & ~(RECV_ESCAPE_FLAG | RECV_INTERRUPT_FLAG)) +volatile uint8_t msg_recv_state = RECV_IDLE; +volatile uint8_t msg_recv_pos = 0; +volatile uint8_t msg_recv_body_length = 0; +volatile uint16_t msg_recv_checksum = 0; +#define RECV_MAX_LENGTH 255 +volatile uint8_t msg_recv_buffer[RECV_MAX_LENGTH]; + +uint8_t transport_unescape(uint8_t c); void USART_recv_interrupt(void){ - uint16_t ret = transport_receive_char(400); -// printf("RXI %04x\n", ret); -// lcd_write_char('R'); - if (ret == RET_MSG_START){ - msg_start_received = 1; -// printf("Start\n"); - USART_disable_rx_interrupt(); + uint8_t c = USART_read_char(); + if (msg_recv_state & RECV_INTERRUPT_FLAG){ + if (c != INTERRUPT_NONE && interrupt_msg_table[INTERRUPT_NUM(c)]){ + interrupt_msg_table[INTERRUPT_NUM(c)](); + } + msg_recv_state &= ~RECV_INTERRUPT_FLAG; + } else if (c == SC_ESCAPE){ + msg_recv_state |= RECV_ESCAPE_FLAG; + } else if (c == SC_INTERRUPT){ + msg_recv_state |= RECV_INTERRUPT_FLAG; + } else if (c == SC_MSG_START){ + RECV_SET_STATE(RECV_START); + msg_recv_pos = 0; + } else if (c == SC_MSG_END){ + msg_recv_body_length = msg_recv_pos; + RECV_SET_STATE(RECV_CHECKSUM); + msg_recv_pos = 0; + } else { + + if (msg_recv_state & RECV_ESCAPE_FLAG){ + c = transport_unescape(c); + msg_recv_state &= ~RECV_ESCAPE_FLAG; + } + + if (RECV_STATE() == RECV_START){ + msg_recv_pos = 0; + RECV_SET_STATE(RECV_BODY); + } + + if (RECV_STATE() == RECV_BODY){ + if (msg_recv_pos < RECV_MAX_LENGTH){ + msg_recv_buffer[msg_recv_pos] = c; + msg_recv_pos++; + } + } else if (RECV_STATE() == RECV_CHECKSUM){ + if (msg_recv_pos == 0) msg_recv_checksum = c; + if (msg_recv_pos == 1) { + msg_recv_checksum |= c << 8; + RECV_SET_STATE(RECV_FINISHED); + } + msg_recv_pos++; + } + } +} + +uint8_t transport_unescape(uint8_t c){ + if (c == EC_2B){ + return 0x2B; + } else if (c == EC_D4){ + return 0xD4; + } else if (c == EC_5C){ + return 0x5C; + } else if (c == EC_AA){ + return 0xAA; + } else { + return c; } } @@ -89,12 +153,15 @@ void transport_send_message(uint8_t* body, uint8_t length){ for (uint8_t i = 0; i < length; i++){ transport_send_char(body[i]); +// printf(">%02x>", body[i]); checksum = _crc16_update(checksum, body[i]); } USART_transmit_char(SC_MSG_END); transport_send_char(checksum & 0xFF); transport_send_char(checksum >> 8); + + USART_flush(); } void transport_send_interrupt_message(uint8_t interrupt){ @@ -107,177 +174,31 @@ void transport_send_interrupt_message(uint8_t interrupt){ } uint8_t transport_data_available(void){ - return msg_start_received; -} - -uint16_t transport_handle_interrupt_msg(uint16_t timeout){ - uint8_t num_interrupts = 1; - uint16_t ret = SC_INTERRUPT; - -// while (ret == SC_INTERRUPT){ -// ret = USART_read_char_timeout(timeout); -// if (ret == ERR_TIMEOUT) return ERR_TIMEOUT; -// if (ret == SC_INTERRUPT){ -// if (num_interrupts < 255){ -// num_interrupts++; -// } else { //more than 255 nested interrupt msgs?! somebody is fucking with us. -// return TRANSPORT_ERR_NESTED_INTERRUPTS; -// } -// } -// } -// -// printf("Int"); - for (uint8_t i = 0; i < num_interrupts; i++){ - ret = USART_read_char_timeout(timeout); - if (ret == ERR_TIMEOUT) return ERR_TIMEOUT; - - if (ret != INTERRUPT_NONE && interrupt_msg_table[INTERRUPT_NUM(ret)]){ - interrupt_msg_table[INTERRUPT_NUM(ret)](); - } - } - return 0; + return msg_recv_state == RECV_FINISHED; } -uint16_t transport_receive_char(uint16_t timeout){ - uint16_t ret; - uint8_t c; +uint16_t transport_receive_message(uint8_t* buffer, uint8_t length, uint16_t timeout){ - while (1){ - ret = USART_read_char_timeout(timeout); - if (ret == ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - c = ret & 0xFF; - - if (c == SC_ESCAPE){ - - while(1){ - ret = USART_read_char_timeout(timeout); - if (ret == ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - c = ret & 0xFF; - - if (c == SC_INTERRUPT) { - ret = transport_handle_interrupt_msg(timeout); - if (ret == ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - if (ret == TRANSPORT_ERR_NESTED_INTERRUPTS) return TRANSPORT_ERR_NESTED_INTERRUPTS; - //loop again, to read the next char (the one that was about to be escaped, when this interrupt came in) - } else { - break; - } - } - - if (c == EC_2B){ - return 0x2B; - } else if (c == EC_D4){ - return 0xD4; - } else if (c == EC_5C){ - return 0x5C; - } else if (c == EC_AA){ - return 0xAA; - } else { - //keep unknown escape char unchanged //TODO: Handle this properly? Error? - return c; - } - } else if (c == SC_MSG_END){ - return RET_MSG_END; - } else if (c == SC_MSG_START){ - return RET_MSG_START; - } else if (c == SC_INTERRUPT){ - ret = transport_handle_interrupt_msg(timeout); - if (ret == ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - if (ret == TRANSPORT_ERR_NESTED_INTERRUPTS) return TRANSPORT_ERR_NESTED_INTERRUPTS; - //we have nothing to return, so loop again to read the next char. - - } else { //literal char - return c; - } + while (RECV_STATE() != RECV_FINISHED && timeout > 0){ + timeout--; + _delay_us(100); } -} - - -uint16_t _transport_receive_message(uint8_t* buffer, uint8_t length, uint16_t timeout){ - uint16_t ret = 0; - uint8_t c = 0; - uint8_t recv_length = 0; - uint16_t real_checksum = 0xFFFF; - uint16_t expected_checksum; - uint8_t has_body = 1; - //Wait for message start char (if the interrupt didn't pick it up for us already) - if (!msg_start_received){ - while (1){ - ret = transport_receive_char(timeout); - if (ret == TRANSPORT_ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - if (ret == RET_MSG_START) break; - } + if (RECV_STATE() != RECV_FINISHED){ + return TRANSPORT_ERR_TIMEOUT; + } else if (msg_recv_body_length > length) { + RECV_SET_STATE(RECV_IDLE); + return TRANSPORT_ERR_MESSAGE_TOO_LONG; } else { - msg_start_received = 0; - } - - //The start char can be repeated multiple times, wait for something else - while (1){ - ret = transport_receive_char(timeout); - if (ret == TRANSPORT_ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - if (ret == TRANSPORT_ERR_NESTED_INTERRUPTS) return TRANSPORT_ERR_NESTED_INTERRUPTS; - if (ret == RET_MSG_END) {has_body = 0; break;}; //end after start -> empty message - if (ret != RET_MSG_START) break; - } - - if (has_body){ - c = ret & 0xFF; - - //Receive the message body - while (1){ - if (recv_length < length){ //write byte to the buffer (if not full) - buffer[recv_length] = c; - recv_length++; - } else { - return TRANSPORT_ERR_MESSAGE_TOO_LONG; - } - - real_checksum = _crc16_update(real_checksum, c); //checksum byte - - //Receive next char - ret = transport_receive_char(timeout); - if (ret == TRANSPORT_ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - if (ret == TRANSPORT_ERR_NESTED_INTERRUPTS) return TRANSPORT_ERR_NESTED_INTERRUPTS; - if (ret == RET_MSG_START) return TRANSPORT_ERR_MESSAGE_ABORT; //no start char expected, this is an error (truncated message?) - if (ret == RET_MSG_END) break; //end char (literal) received - c = ret & 0xFF; + uint16_t checksum = 0xFFFF; + for (uint8_t i = 0; i < msg_recv_body_length; i++){ + checksum = _crc16_update(checksum, msg_recv_buffer[i]); + buffer[i] = msg_recv_buffer[i]; } + RECV_SET_STATE(RECV_IDLE); + + if (checksum != msg_recv_checksum) return TRANSPORT_ERR_CHECKSUM_FAIL; + + return msg_recv_body_length; } - - //checksum (low byte) - ret = transport_receive_char(timeout); - if (ret == TRANSPORT_ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - if (ret == TRANSPORT_ERR_NESTED_INTERRUPTS) return TRANSPORT_ERR_NESTED_INTERRUPTS; - if (ret == RET_MSG_START) return TRANSPORT_ERR_MESSAGE_ABORT; //no start char expected, this is an error (truncated message?) - if (ret == RET_MSG_END) return TRANSPORT_ERR_UNEXPCETED_END; //doesnt belong here, don't know how to handle that - expected_checksum = ret & 0xFF; - - //checksum (high byte) - ret = transport_receive_char(timeout); - if (ret == TRANSPORT_ERR_TIMEOUT) return TRANSPORT_ERR_TIMEOUT; - if (ret == TRANSPORT_ERR_NESTED_INTERRUPTS) return TRANSPORT_ERR_NESTED_INTERRUPTS; - if (ret == RET_MSG_START) return TRANSPORT_ERR_MESSAGE_ABORT; //no start char expected, this is an error (truncated message?) - if (ret == RET_MSG_END) return TRANSPORT_ERR_UNEXPCETED_END; //doesnt belong here, don't know how to handle that - expected_checksum |= (ret & 0xFF) << 8; - - - if (expected_checksum != real_checksum){ -// lcd_clear(); -// lcd_home(); -// for (uint8_t i = 0; i < recv_length; i++){ -// lcd_write_byte_hex(buffer[i]); -// } -// _delay_ms(10000); - return TRANSPORT_ERR_CHECKSUM_FAIL; - } - - return recv_length; } - -uint16_t transport_receive_message(uint8_t* buffer, uint8_t length, uint16_t timeout){ - USART_disable_rx_interrupt(); //Disable RX interrupt, we are going to poll rx from here now. - uint16_t ret = _transport_receive_message(buffer,length, timeout); - USART_enable_rx_interrupt(); //Enable RX interrupt again. - return ret; -} \ No newline at end of file diff --git a/common/transport/transport.h b/common/transport/transport.h index ce65972aa469fd435371397e53ef4368d210d431..f970d03671e07e7b4523560a7391b0ff8ef92226 100644 --- a/common/transport/transport.h +++ b/common/transport/transport.h @@ -8,10 +8,7 @@ #define TRANSPORT_ERR_TIMEOUT 0xFFFF #define TRANSPORT_ERR_CHECKSUM_FAIL 0xFFEE -#define TRANSPORT_ERR_MESSAGE_ABORT 0xFFDD #define TRANSPORT_ERR_MESSAGE_TOO_LONG 0xFFCC -#define TRANSPORT_ERR_UNEXPCETED_END 0xFFBB -#define TRANSPORT_ERR_NESTED_INTERRUPTS 0xFFAA #define TRANSPORT_IS_ERROR(ret) (((ret) & 0xFF00) != 0) typedef void (*interrupt_msg_handler_t)(void);