From: Nathael Pajani Date: Wed, 18 Nov 2015 20:28:00 +0000 (+0100) Subject: Rename and move dtplug protocol files under approriate directory in lib/protocols... X-Git-Url: http://git.techno-innov.fr/?a=commitdiff_plain;h=b743be736870f09cb98e8debd12f67c26148638d;p=soft%2Flpc122x%2Fcore Rename and move dtplug protocol files under approriate directory in lib/protocols Associated changes in source files --- diff --git a/Makefile b/Makefile index ad467e0..63412d3 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ OBJDIR = objs SRC = $(wildcard */*.c) SRC += $(wildcard lib/*/*.c) +SRC += $(wildcard lib/protocols/*/*.c) OBJS = ${SRC:%.c=${OBJDIR}/%.o} DEPS = ${OBJS:%.o=$(OBJDIR)/%.d} diff --git a/include/lib/dtplug_protocol.h b/include/lib/dtplug_protocol.h deleted file mode 100644 index 186356c..0000000 --- a/include/lib/dtplug_protocol.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * lib/dtplug_protocol.h - * - * - * Copyright 2013-2014 Nathael Pajani - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#ifndef LIB_DTPLUG_PROTOCOL_H -#define LIB_DTPLUG_PROTOCOL_H - - -#include - -/******************************************************************************/ -/* These structures define the packets used to transfer data over the serial link - * between the dtplug (or domotab or any computing platform) and a module - */ - -/* The header is included in each and every packet we need to transfer - * It holds information about the message type and content and provides checksum - * information of the header and the data part of the packet if any. - * - * Checksums information : - * The header checksum is a value such that the sum of all bytes of the header - * modulo 256 is equal to 0. (Use a mask with 0xFF to get the modulo) - * The data checksum the sum of all data bytes modulo 256. - * - * Sequence numbers, data checksums and error codes - * The sequence number is on the 6 least significant bits of the sequence number field. - * this gives 64 sequence numbers which is more than enough. - * When the most significant bit (bit 7) of the sequence number field (seq_num) is set - * in a request (master to slave), the slave MUST send an acknowledge packet or a reply - * with the same sequence number. - * This may help checking which packet triggered the reply and packet losses. - * When bit 7 is set in a reply, it indicates that the packet is an error packet and that - * the union holds error information (error code and aditional error information. - * No data should be present in the packet. - * When set, bit 6 of the sequence number indicates that the union holds 'quick_data'. - * This bit cannot be used for error packets. - * A packet with "quick-data" cannot have additional data. - * When bit 6 is not set, and the packet is not an error packet, the union holds a - * 'data_information' structure whith the packet data 'size' (if any) and 'data_checksum' - * for the packet data part. - * - * Data size and big (continued) data packets - * When a packet does not have enough room for the whole data the most significant bit - * (bit 7) of the data size is set to mark a packet whose data will be continued in a - * subsequent PKT_TYPE_CONTINUED_DATA packet. - * this bit must be set in all but the last one of a continued data packet serie. -*/ - -/* Normal packets 'sel' field information : holds information about the data part. - * A 'size' of 0 indicates that there is no data part. - */ -struct data_information { - uint8_t size; /* Size of the data part. The header size is fixed, so not included */ - uint8_t checksum; /* Checksum for the data part */ -} __attribute__ ((__packed__)); -/* Error packet 'sel' field */ -struct error_information { - uint8_t error_code; - uint8_t info; -} __attribute__ ((__packed__)); - -/* Packet header */ -struct header { - char start; /* Start of paquet indicator */ - uint8_t type; /* Packet type, used to provide information on the data structure */ - uint8_t checksum; /* Header checksum */ - uint8_t seq_num; /* Packet sequence number on bits 0:5, error indicator on bit 7 */ - union { - struct data_information data; - struct error_information err; - uint8_t quick_data[2]; - }; -} __attribute__ ((__packed__)); - -#define FIRST_PACKET_CHAR '#' -/* Sequence byte decoding */ -#define PACKET_NEEDS_REPLY (0x01 << 7) /* Host to slave */ -#define PACKET_IS_ERROR (0x01 << 7) /* Slave to host */ -#define QUICK_DATA_PACKET (0x01 << 6) -#define SEQUENCE_MASK (0x3F) -/* Data size decoding */ -#define BIG_DATA_PKT (0x01 << 7) /* The total data size is above PACKET_DATA_SIZE, the packet will be continued. */ -#define PKT_SIZE_MASK (0x7F) - -/* The following struct defines a generic packet. - * Specific packets should be defined in specific structures. - */ -#define PACKET_DATA_SIZE 64 -struct packet { - struct header info; /* Packet header */ - uint8_t data[PACKET_DATA_SIZE]; /* packet data */ -} __attribute__ ((__packed__)); - - - -enum packet_types { - /* Common packet types, must be handled by all the slaves */ - PKT_TYPE_RESET = 0, /* Soft reset of board */ - PKT_TYPE_PING, /* Reply with no data or urgent data */ - PKT_TYPE_GET_BOARD_INFO, /* Return board name, version, module version, and programm version. */ - PKT_TYPE_SET_TIME, /* Set current time for events timestamping */ - PKT_TYPE_GET_NUM_PACKETS, /* Get the number of packets received since system start */ - PKT_TYPE_GET_ERRORS, /* Ask the slave to return any active error code in the data */ - PKT_TYPE_GET_NUM_ERRORS, /* Get the number of errors since system start */ - PKT_TYPE_SET_USER_INFO, /* Change the current board user information (and reset board) */ - - /* Config */ - PKT_TYPE_ADD_GPIO, /* Configure one of the GPIO or ADC as GPIO */ - PKT_TYPE_ADD_CS, /* Configure one of the GPIO or ADC as SPI Chip select */ - /* ADC config specifies : - * the channel number, - * periodicity of sample (from on request up to continuous), - * and number of values for the continuous average computation - */ - PKT_TYPE_ADD_ADC, /* Configure one of the ADC as ADC */ - /* PWM config specifies : - * the channel number, - * the PWM period, - * the channel duty cycle, - */ - PKT_TYPE_ADD_PWM, /* Configure one of the PWM capable GPIO as PWM */ - - /* Continued data. Use for protocols with data size that goes beyond PACKET_DATA_SIZE */ - PKT_TYPE_CONTINUED_DATA, - - /* Temperature packets */ - PKT_TYPE_START_TEMP_CONVERSION, /* Requiered to update the temperature value */ - PKT_TYPE_GET_TEMPERATURE, /* Get temprature values */ - - /* ADC, PWM and GPIO packets */ - PKT_TYPE_START_ADC_CONVERSION, - PKT_TYPE_GET_ADC_VALUE, - PKT_TYPE_SET_GPIO, - PKT_TYPE_GET_GPIO, - PKT_TYPE_SET_PWM_CHAN, - - /* Communication */ - SEND_ON_BUS, -}; - -/* Error / status codes */ -enum reply_statuses { - NO_ERROR = 0, - GOT_MANY_ERRORS, /* This one is returned when there's not only one error */ - ERROR_PKT_NOT_HANDLED, - ERROR_LAST_PKT_IN_PROCESS, - ERROR_IN_PKT_STRUCTURE, - ERROR_IN_DATA_CHECKSUM, - ERROR_IN_DATA_VALUES, - ERROR_IN_DATA_SIZE, /* To many data */ - ERROR_IN_UART_TX, /* This one is critical if received, and much more critical when it occurs and cannot be sent. */ - /* Temperature */ - ERROR_NO_TEMP_SENSOR, - ERROR_TEMP_CONVERSION, - TEMPERATURE_ALERT, - /* Configuration problem */ - ERROR_FLASH_ERASE, /* Error, unable to erase the user information block */ - ERROR_FLASH_WRITE, /* Error, unable to write the user information block */ - /* RF */ - RF_RX_QUEUE_EMPTY, /* Na RX packet in RX queue */ - ERROR_IN_RF_RX, - ERROR_IN_RF_TX, - /* Last error number ... must not be above 255 */ - LAST_ERROR_NUM, /* This one is here to get the value of the last enum. */ -}; - - - -/******************************************************************************/ -/* Other information on the protocol */ - -/* When a packet is received and requires an ACK but no particular data, the slave replies - * using a PING packet, with the sequence field set to the sequence number of the last received packet). - * When the slave has urgent data to send (either errors or alerts), it uses the corresponding bits in - * the sequence byte and places the 'appropriate data (error_information or quick_dtaa) in the 'sel' field. - */ - -/* Multiple-bytes data are sent in Big Endian (network endian) !!!! - * This is the usual way to send data over a network, and even if most of our boards and computers are little endian - * there are very little multi-byte information in our protocol so it's OK - * The endianness transformation may be done before or after the checksum control, it has no influence on the - * checksum algorithm we chose. - */ - -/* What to do on error, and error recovery procedure. - * When a slave has an internal error, it has two options. - * Either it's the first one, and the master requested a reply. The slave can then send the error - * code in the reply. - * Or it's not the first one or the master did not ask for an reply or ACK. Then the slave stores the - * error code for future transmission. - * When the master asked for a reply, the slave then uses "GOT_MANY_ERRORS" as error code. - * When the master receives the "GOT_MANY_ERRORS" error code, it must send a "PKT_TYPE_GET_ERRORS" request. - * The slave then replies with a list of all errors in the packet data with a header which does not indicate an - * error packet (this is the normal reply to a PKT_TYPE_GET_ERRORS request. - * A slave cannot store more than 8 error codes, if the count is 8, consider that there is a BIG problem ! - */ - - - - -#endif /* LIB_DTPLUG_PROTOCOL_H */ diff --git a/include/lib/dtplug_protocol_slave.h b/include/lib/dtplug_protocol_slave.h deleted file mode 100644 index c3dbb15..0000000 --- a/include/lib/dtplug_protocol_slave.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * lib/dtplug_protocol_slave.h - * - * - * Copyright 2013-2014 Nathael Pajani - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#ifndef LIB_DTPLUG_PROTOCOL_SLAVE_H -#define LIB_DTPLUG_PROTOCOL_SLAVE_H - - -#include -#include "lib/dtplug_protocol.h" - - -/******************************************************************************/ -/* DTPlug (or DomoTab, PC, ...) Communication */ - -#define DTPP_MAX_ERROR_STORED 8 - -struct dtplug_protocol_handle { - /* Store two packets, one being received, one being used */ - struct packet packets[2]; - struct packet* rx_packet; - volatile struct packet* packet_ok; - - uint32_t packet_count; - - uint32_t errors_count; - uint8_t error_storage[(DTPP_MAX_ERROR_STORED * 2)]; - uint8_t num_errors_stored; - - /* Set to 1 when the packet is handled to tell the decoder we can handle a new one. - * MUST be initialised to 1 or the handle will think we have a valid packet to handle upon - * system startup */ - uint8_t done_with_old_packet; - uint8_t uart; -}; - - -/* Setup the UART used for communication with the host / master (the module is slave) */ -void dtplug_protocol_set_dtplug_comm_uart(uint8_t uart_num, struct dtplug_protocol_handle* handle); - - -/* Tell the receive routine that the "packet_ok" packet is no more in use and that - * we are ready to handle a new one */ -void dtplug_protocol_release_old_packet(struct dtplug_protocol_handle* handle); - - -/* Get a pointer to the new packet received. - * Return NULL when no new packet were received since last packet was released. - */ -struct packet* dtplug_protocol_get_next_packet_ok(struct dtplug_protocol_handle* handle); - - -/* When a packet has not been handled we must not count it as acknowledged - * On the next ping request the master will then see wich packet caused the problem. - */ -void dtplug_protocol_add_error_to_list(struct dtplug_protocol_handle* handle, struct header* info, uint8_t error_code); - - -/* This function handle sending replies when requested by the host. - * When there is an error but the host did not request a reply, this function stores the error for - * future request. - * When a reply is effectively sent, the PACKET_NEEDS_REPLY bit is removed from the sequence filed - * packet handling code will know if there is still a PING request to be answered. - */ -void dtplug_protocol_send_reply(struct dtplug_protocol_handle* handle, - struct packet* question, uint8_t error, int size, uint8_t* data); - - - -#endif /* LIB_DTPLUG_PROTOCOL_SLAVE_H */ diff --git a/include/lib/protocols/dtplug/defs.h b/include/lib/protocols/dtplug/defs.h new file mode 100644 index 0000000..f2b525f --- /dev/null +++ b/include/lib/protocols/dtplug/defs.h @@ -0,0 +1,218 @@ +/* + * lib/protocols/dtplug/defs.h + * + * + * Copyright 2013-2015 Nathael Pajani + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef LIB_PROTOCOLS_DTPLUG_DEFS_H +#define LIB_PROTOCOLS_DTPLUG_DEFS_H + + +#include + +/******************************************************************************/ +/* These structures define the packets used to transfer data over the serial link + * between the dtplug (or domotab or any computing platform) and a module + */ + +/* The header is included in each and every packet we need to transfer + * It holds information about the message type and content and provides checksum + * information of the header and the data part of the packet if any. + * + * Checksums information : + * The header checksum is a value such that the sum of all bytes of the header + * modulo 256 is equal to 0. (Use a mask with 0xFF to get the modulo) + * The data checksum the sum of all data bytes modulo 256. + * + * Sequence numbers, data checksums and error codes + * The sequence number is on the 6 least significant bits of the sequence number field. + * this gives 64 sequence numbers which is more than enough. + * When the most significant bit (bit 7) of the sequence number field (seq_num) is set + * in a request (master to slave), the slave MUST send an acknowledge packet or a reply + * with the same sequence number. + * This may help checking which packet triggered the reply and packet losses. + * When bit 7 is set in a reply, it indicates that the packet is an error packet and that + * the union holds error information (error code and aditional error information. + * No data should be present in the packet. + * When set, bit 6 of the sequence number indicates that the union holds 'quick_data'. + * This bit cannot be used for error packets. + * A packet with "quick-data" cannot have additional data. + * When bit 6 is not set, and the packet is not an error packet, the union holds a + * 'data_information' structure whith the packet data 'size' (if any) and 'data_checksum' + * for the packet data part. + * + * Data size and big (continued) data packets + * When a packet does not have enough room for the whole data the most significant bit + * (bit 7) of the data size is set to mark a packet whose data will be continued in a + * subsequent PKT_TYPE_CONTINUED_DATA packet. + * this bit must be set in all but the last one of a continued data packet serie. +*/ + +/* Normal packets 'sel' field information : holds information about the data part. + * A 'size' of 0 indicates that there is no data part. + */ +struct data_information { + uint8_t size; /* Size of the data part. The header size is fixed, so not included */ + uint8_t checksum; /* Checksum for the data part */ +} __attribute__ ((__packed__)); +/* Error packet 'sel' field */ +struct error_information { + uint8_t error_code; + uint8_t info; +} __attribute__ ((__packed__)); + +/* Packet header */ +struct header { + char start; /* Start of paquet indicator */ + uint8_t type; /* Packet type, used to provide information on the data structure */ + uint8_t checksum; /* Header checksum */ + uint8_t seq_num; /* Packet sequence number on bits 0:5, error indicator on bit 7 */ + union { + struct data_information data; + struct error_information err; + uint8_t quick_data[2]; + }; +} __attribute__ ((__packed__)); + +#define FIRST_PACKET_CHAR '#' +/* Sequence byte decoding */ +#define PACKET_NEEDS_REPLY (0x01 << 7) /* Host to slave */ +#define PACKET_IS_ERROR (0x01 << 7) /* Slave to host */ +#define QUICK_DATA_PACKET (0x01 << 6) +#define SEQUENCE_MASK (0x3F) +/* Data size decoding */ +#define BIG_DATA_PKT (0x01 << 7) /* The total data size is above PACKET_DATA_SIZE, the packet will be continued. */ +#define PKT_SIZE_MASK (0x7F) + +/* The following struct defines a generic packet. + * Specific packets should be defined in specific structures. + */ +#define PACKET_DATA_SIZE 64 +struct packet { + struct header info; /* Packet header */ + uint8_t data[PACKET_DATA_SIZE]; /* packet data */ +} __attribute__ ((__packed__)); + + + +enum packet_types { + /* Common packet types, must be handled by all the slaves */ + PKT_TYPE_RESET = 0, /* Soft reset of board */ + PKT_TYPE_PING, /* Reply with no data or urgent data */ + PKT_TYPE_GET_BOARD_INFO, /* Return board name, version, module version, and programm version. */ + PKT_TYPE_SET_TIME, /* Set current time for events timestamping */ + PKT_TYPE_GET_NUM_PACKETS, /* Get the number of packets received since system start */ + PKT_TYPE_GET_ERRORS, /* Ask the slave to return any active error code in the data */ + PKT_TYPE_GET_NUM_ERRORS, /* Get the number of errors since system start */ + PKT_TYPE_SET_USER_INFO, /* Change the current board user information (and reset board) */ + + /* Config */ + PKT_TYPE_ADD_GPIO, /* Configure one of the GPIO or ADC as GPIO */ + PKT_TYPE_ADD_CS, /* Configure one of the GPIO or ADC as SPI Chip select */ + /* ADC config specifies : + * the channel number, + * periodicity of sample (from on request up to continuous), + * and number of values for the continuous average computation + */ + PKT_TYPE_ADD_ADC, /* Configure one of the ADC as ADC */ + /* PWM config specifies : + * the channel number, + * the PWM period, + * the channel duty cycle, + */ + PKT_TYPE_ADD_PWM, /* Configure one of the PWM capable GPIO as PWM */ + + /* Continued data. Use for protocols with data size that goes beyond PACKET_DATA_SIZE */ + PKT_TYPE_CONTINUED_DATA, + + /* Temperature packets */ + PKT_TYPE_START_TEMP_CONVERSION, /* Requiered to update the temperature value */ + PKT_TYPE_GET_TEMPERATURE, /* Get temprature values */ + + /* ADC, PWM and GPIO packets */ + PKT_TYPE_START_ADC_CONVERSION, + PKT_TYPE_GET_ADC_VALUE, + PKT_TYPE_SET_GPIO, + PKT_TYPE_GET_GPIO, + PKT_TYPE_SET_PWM_CHAN, + + /* Communication */ + SEND_ON_BUS, +}; + +/* Error / status codes */ +enum reply_statuses { + NO_ERROR = 0, + GOT_MANY_ERRORS, /* This one is returned when there's not only one error */ + ERROR_PKT_NOT_HANDLED, + ERROR_LAST_PKT_IN_PROCESS, + ERROR_IN_PKT_STRUCTURE, + ERROR_IN_DATA_CHECKSUM, + ERROR_IN_DATA_VALUES, + ERROR_IN_DATA_SIZE, /* To many data */ + ERROR_IN_UART_TX, /* This one is critical if received, and much more critical when it occurs and cannot be sent. */ + /* Temperature */ + ERROR_NO_TEMP_SENSOR, + ERROR_TEMP_CONVERSION, + TEMPERATURE_ALERT, + /* Configuration problem */ + ERROR_FLASH_ERASE, /* Error, unable to erase the user information block */ + ERROR_FLASH_WRITE, /* Error, unable to write the user information block */ + /* RF */ + RF_RX_QUEUE_EMPTY, /* Na RX packet in RX queue */ + ERROR_IN_RF_RX, + ERROR_IN_RF_TX, + /* Last error number ... must not be above 255 */ + LAST_ERROR_NUM, /* This one is here to get the value of the last enum. */ +}; + + + +/******************************************************************************/ +/* Other information on the protocol */ + +/* When a packet is received and requires an ACK but no particular data, the slave replies + * using a PING packet, with the sequence field set to the sequence number of the last received packet). + * When the slave has urgent data to send (either errors or alerts), it uses the corresponding bits in + * the sequence byte and places the 'appropriate data (error_information or quick_dtaa) in the 'sel' field. + */ + +/* Multiple-bytes data are sent in Big Endian (network endian) !!!! + * This is the usual way to send data over a network, and even if most of our boards and computers are little endian + * there are very little multi-byte information in our protocol so it's OK + * The endianness transformation may be done before or after the checksum control, it has no influence on the + * checksum algorithm we chose. + */ + +/* What to do on error, and error recovery procedure. + * When a slave has an internal error, it has two options. + * Either it's the first one, and the master requested a reply. The slave can then send the error + * code in the reply. + * Or it's not the first one or the master did not ask for a reply or ACK. Then the slave stores the + * error code for future transmission. + * If the master asked for a reply and the slave has many errors, the slave send "GOT_MANY_ERRORS" as error code. + * When the master receives the "GOT_MANY_ERRORS" error code, it must send a "PKT_TYPE_GET_ERRORS" request. + * The slave then replies with a list of all errors in the packet data with a header which does not indicate an + * error packet (this is the normal reply to a PKT_TYPE_GET_ERRORS request. + * A slave cannot store more than 8 error codes, if the count is 8, consider that there is a BIG problem ! + */ + + + + +#endif /* LIB_PROTOCOLS_DTPLUG_DEFS_H */ diff --git a/include/lib/protocols/dtplug/slave.h b/include/lib/protocols/dtplug/slave.h new file mode 100644 index 0000000..e0bec14 --- /dev/null +++ b/include/lib/protocols/dtplug/slave.h @@ -0,0 +1,87 @@ +/* + * lib/protocols/dtplug/slave.h + * + * + * Copyright 2013-2014 Nathael Pajani + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef LIB_PROTOCOLS_DTPLUG_SLAVE_H +#define LIB_PROTOCOLS_DTPLUG_SLAVE_H + + +#include +#include "lib/protocols/dtplug/defs.h" + + +/******************************************************************************/ +/* DTPlug (or DomoTab, PC, ...) Communication */ + +#define DTPP_MAX_ERROR_STORED 8 + +struct dtplug_protocol_handle { + /* Store two packets, one being received, one being used */ + struct packet packets[2]; + struct packet* rx_packet; + volatile struct packet* packet_ok; + + uint32_t packet_count; + + uint32_t errors_count; + uint8_t error_storage[(DTPP_MAX_ERROR_STORED * 2)]; + uint8_t num_errors_stored; + + /* Set to 1 when the packet is handled to tell the decoder we can handle a new one. + * MUST be initialised to 1 or the handle will think we have a valid packet to handle upon + * system startup */ + uint8_t done_with_old_packet; + uint8_t uart; +}; + + +/* Setup the UART used for communication with the host / master (the module is slave) */ +void dtplug_protocol_set_dtplug_comm_uart(uint8_t uart_num, struct dtplug_protocol_handle* handle); + + +/* Tell the receive routine that the "packet_ok" packet is no more in use and that + * we are ready to handle a new one */ +void dtplug_protocol_release_old_packet(struct dtplug_protocol_handle* handle); + + +/* Get a pointer to the new packet received. + * Return NULL when no new packet were received since last packet was released. + */ +struct packet* dtplug_protocol_get_next_packet_ok(struct dtplug_protocol_handle* handle); + + +/* When a packet has not been handled we must not count it as acknowledged + * On the next ping request the master will then see wich packet caused the problem. + */ +void dtplug_protocol_add_error_to_list(struct dtplug_protocol_handle* handle, struct header* info, uint8_t error_code); + + +/* This function handle sending replies when requested by the host. + * When there is an error but the host did not request a reply, this function stores the error for + * future request. + * When a reply is effectively sent, the PACKET_NEEDS_REPLY bit is removed from the sequence filed + * packet handling code will know if there is still a PING request to be answered. + */ +void dtplug_protocol_send_reply(struct dtplug_protocol_handle* handle, + struct packet* question, uint8_t error, int size, uint8_t* data); + + + +#endif /* LIB_PROTOCOLS_DTPLUG_SLAVE_H */ diff --git a/lib/dtplug_protocol.c b/lib/dtplug_protocol.c deleted file mode 100644 index 91267e8..0000000 --- a/lib/dtplug_protocol.c +++ /dev/null @@ -1,487 +0,0 @@ -/**************************************************************************** - * lib/dtplug_protocol.c - * - * - * Copyright 2013-2015 Nathael Pajani - * - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - ****************************************************************************/ - -#include -#include "core/system.h" -#include "core/iap.h" -#include "core/user_information_block.h" -#include "lib/stdio.h" -#include "lib/string.h" -#include "drivers/serial.h" -#include "extdrv/status_led.h" -#include "lib/time.h" -#include "lib/dtplug_protocol.h" - -#include "lib/dtplug_protocol_slave.h" - -/******************************************************************************/ -/* DTPlug (or DomoTab, PC, ...) Communication */ - -#define DTPP_MAX_HANDLERS 2 -static struct dtplug_protocol_handle* dtpp_handles[DTPP_MAX_HANDLERS] = {0}; - - - -static void dtplug_protocol_decode(struct dtplug_protocol_handle* handle, uint8_t c); - -static void dtplug_protocol_decoder_0(uint8_t c) -{ - dtplug_protocol_decode(dtpp_handles[0], c); -} -static void dtplug_protocol_decoder_1(uint8_t c) -{ - dtplug_protocol_decode(dtpp_handles[1], c); -} - - -/* Setup the UART used for communication with the host / master (the module is slave) */ -void dtplug_protocol_set_dtplug_comm_uart(uint8_t uart_num, struct dtplug_protocol_handle* handle) -{ - void* decoder = dtplug_protocol_decoder_0; - - /* Basic parameter checks */ - if (uart_num >= DTPP_MAX_HANDLERS) { - return; - } - if (handle == NULL) { - return; - } - - /* Configure and register handle and configure uart */ - handle->rx_packet = handle->packets; - handle->packet_ok = NULL; - handle->done_with_old_packet = 1; - handle->uart = uart_num; - dtpp_handles[uart_num] = handle; - switch (uart_num) { - case 1: - decoder = dtplug_protocol_decoder_1; - break; - case 0: - default: - break; - } - uart_on(uart_num, 115200, decoder); -} - - -/* Tell the receive and decode routine that the "handle->packet_ok" packet is no more in use and that - * we are ready to handle a new one. - */ -void dtplug_protocol_release_old_packet(struct dtplug_protocol_handle* handle) -{ - handle->packet_ok = NULL; - handle->done_with_old_packet = 1; -} - - - -/* When a packet has not been handled we must not count it as acknowledged - * On the next ping request the master will then see wich packet caused the problem. - */ -void dtplug_protocol_add_error_to_list(struct dtplug_protocol_handle* handle, struct header* info, uint8_t error_code) -{ - if (handle->num_errors_stored < (DTPP_MAX_ERROR_STORED * 2)) { - if (error_code == NO_ERROR) { - error_code = ERROR_PKT_NOT_HANDLED; - } - handle->error_storage[handle->num_errors_stored++] = error_code; - handle->error_storage[handle->num_errors_stored++] = (info->seq_num & SEQUENCE_MASK); - } -} - - -/* Handle packet reception, including checksums */ -/* 'sum' is used to sum all the received characters, and if the last byte of sum is 0 for each - * part (header and data) then the packet is valid. - * 'full_size' is the size of the whole packet, including header, updated as soon as the header - * is checked and valid - */ -static void dtplug_protocol_decode(struct dtplug_protocol_handle* handle, uint8_t c) -{ - static uint8_t rx_ptr = 0; - static uint8_t sum = 0; - static uint8_t full_size = 0; - static struct header* info = NULL; - - status_led(red_on); - /* Do not start reception before receiving the packet start character */ - if ((rx_ptr == 0) && (c != FIRST_PACKET_CHAR)) { - return; - } - - /* Store the new byte in the packet */ - if (rx_ptr < sizeof(struct packet)) { - ((uint8_t*)handle->rx_packet)[rx_ptr++] = c; - sum += c; - } else { - goto next_packet; - } - - /* Is this packet valid ? (at end of header reception) */ - if (rx_ptr == sizeof(struct header)) { - if (sum != 0) { - goto next_packet; - } - /* Start the new checksum for data (if any) */ - sum = 0; - - info = (struct header*)handle->rx_packet; - full_size = sizeof(struct header); - if (!(info->seq_num & QUICK_DATA_PACKET)) { - /* Do not care about big data packets here */ - full_size += (info->data.size & PKT_SIZE_MASK); - } - } - - /* Did we receive the whole packet ? */ - if (rx_ptr == full_size) { - /* From here on, the packet is valid, we can provide some feedback */ - /* Check data checksum */ - if (!(info->seq_num & QUICK_DATA_PACKET) && (sum != info->data.checksum)) { - dtplug_protocol_add_error_to_list(handle, info, ERROR_IN_DATA_CHECKSUM); - handle->errors_count++; - goto next_packet; - } - /* Warning, if we are still using the old packet there's a problem */ - if (handle->done_with_old_packet == 0) { - /* FIXME : what to do then ? inform the master ? ignore the new packet ? */ - dtplug_protocol_add_error_to_list(handle, info, ERROR_LAST_PKT_IN_PROCESS); - handle->errors_count++; - goto next_packet; - } - /* Count received packets */ - handle->packet_count++; - /* Mark packet as OK : switch pointers */ - handle->packet_ok = handle->rx_packet; - handle->done_with_old_packet = 0; - /* Switch our receiving buffer (do not overide the last received packet !) */ - if (handle->rx_packet == handle->packets) { - handle->rx_packet = handle->packets + 1; - } else { - handle->rx_packet = handle->packets; - } - status_led(green_on); - /* And get ready to receive the next packet */ - goto next_packet; - } - - return; - -next_packet: -#ifdef DEBUG - if (handle->done_with_old_packet != 0) { - uprintf(handle->uart, "Rx:%d, f:%d, cnt:%d\n", rx_ptr, full_size, handle->packet_count); - if (rx_ptr >= sizeof(struct header)) { - struct header* h = &(handle->rx_packet->info); - uprintf(handle->uart, "P: type:%03d, seq:%d, e:%d, q:%d\n", h->type, h->seq_num, - (h->seq_num & PACKET_IS_ERROR), (h->seq_num & QUICK_DATA_PACKET)); - } - } -#endif - /* Wether the packet was OK or not doesn't matter, go on for a new one :) */ - full_size = 0; - rx_ptr = 0; - sum = 0; -} - -/* This function handle sending replies when requested by the host. - * When there is an error but the host did not request a reply, store the error for future request. - * When a reply is effectively sent, the PACKET_NEEDS_REPLY bit is removed from the sequence number so the - * packet handling code will know if there is still a PING request to be answered. - */ -void dtplug_protocol_send_reply(struct dtplug_protocol_handle* handle, - struct packet* question, uint8_t error, int size, uint8_t* data) -{ - struct packet reply; - struct header* tx_info = &(reply.info); - int i = 0, sent = 0, len = 0; - uint8_t sum = 0; - int data_send_size = size, data_sent = 0; - uint8_t* data_src = data; - uint8_t type = question->info.type; - - if (error != NO_ERROR) { - handle->errors_count++; - } - /* If no reply requested : we were called thus there have been an error. We should store the error and return. */ - if (!(question->info.seq_num & PACKET_NEEDS_REPLY)) { - /* If we still have some room for the error, then keep track of it (if any), - * otherwise ... drop it, we don't have that much memory to keep track of hundreds of errors */ - if (error != NO_ERROR) { - dtplug_protocol_add_error_to_list(handle, &(question->info), error); - } - return; - } - - /* Remove the PACKET_NEEDS_REPLY bit as the reply is being built to prevent multiple replies to the - * same packet. (do it now to prevent the mask when building the type field of the reply) */ - question->info.seq_num &= ~(PACKET_NEEDS_REPLY); - - /* If any error stored, send "got many errors" reply and store the error, but if - * the host is reading the error table, no need to say there is an error table. - * Rather send any possible new error. - */ - if (handle->num_errors_stored != 0) { - /* Store the new error if any */ - if (error != NO_ERROR) { - dtplug_protocol_add_error_to_list(handle, &(question->info), error); - } - /* The master wants to get all errors, give them even if there is an error in the sequence number */ - if (question->info.type == PKT_TYPE_GET_ERRORS) { - data_send_size = handle->num_errors_stored; - size = handle->num_errors_stored; - data_src = handle->error_storage; - handle->num_errors_stored = 0; - } else { - error = GOT_MANY_ERRORS; - data_send_size = 0; - size = 0; - } - } - - do { - /* Does the data fit in the message ? */ - if (data_send_size > PACKET_DATA_SIZE) { - data_send_size = PACKET_DATA_SIZE; - } - - /* Build the reply */ - tx_info->start = FIRST_PACKET_CHAR; - tx_info->type = type; - tx_info->seq_num = question->info.seq_num; - - len = sizeof(struct header); /* At least, send header on serial link */ - if (error) { - tx_info->seq_num |= PACKET_IS_ERROR; - tx_info->err.error_code = error; - if (error == GOT_MANY_ERRORS) { - tx_info->err.info = handle->num_errors_stored; - } - } else { - /* Append possible data */ - if ((data_src != NULL) && (data_send_size != 0)) { - /* Can we send a quick data packet ? */ - if (size && (size <= 2)) { - tx_info->seq_num |= QUICK_DATA_PACKET; - tx_info->quick_data[0] = data_src[0]; - tx_info->quick_data[1] = data_src[1]; - } else { - /* Copy data, compute checksum (also OK for a data_send_size of 0) */ - sum = 0; - for (i = 0; i < data_send_size; i++) { - reply.data[i] = data_src[i]; - sum += data_src[i]; /* Build checksum */ - } - /* And update header information */ - tx_info->data.size = data_send_size; - /* Will this packet be continued in the following one ? */ - if (data_send_size < (size - data_sent)) { - tx_info->data.size |= BIG_DATA_PKT; - } - tx_info->data.checksum = sum; - /* Update length of data to send on serial link */ - len += data_send_size; - } - } - } - - /* Compute header checksum */ - sum = 0; - tx_info->checksum = 0; - for (i = 0; i < sizeof(struct header); i++) { - sum += ((uint8_t*)tx_info)[i]; - } - tx_info->checksum = ((uint8_t)(256 - sum)); - - /* And send the reply */ - sent = 0; - while (sent < len) { - int ret = serial_write(handle->uart, (((char*)(&reply)) + sent), (len - sent)); - if (ret >= 0) { - sent += ret; - } else { - /* Store a sending error, though it may never be sent ... */ - dtplug_protocol_add_error_to_list(handle, &(question->info), ERROR_IN_UART_TX); - handle->errors_count++; - return; - } - /* The serial baud rate is 115200, which means 64 bytes are sent in a little less than 6 ms. - * When there is not enougth place in the buffer, the return value should be 64, meaning 64 byte - * were stored for transmission. Sleep for 6ms and try sending the next part. - */ - if (sent < len) { - msleep(5); - } - } - data_sent += data_send_size; - - /* Need to send more ? */ - if (data_sent < size) { - /* Move data pointer */ - data_src += data_send_size; - /* Update size to send. check against PACKET_DATA_SIZE is done at beginning of loop */ - data_send_size = (size - data_sent); - /* Set packet type to continued data packet for following packets */ - type = PKT_TYPE_CONTINUED_DATA; - } - } while (data_sent < size); -} - - -/******************************************************************************/ -/* User information block re-programming - * Make sure that data is aligned on 4 bytes boundary, and that size is a multiple of 4. - */ -static int dtplug_protocol_user_flash_update(struct dtplug_protocol_handle* handle, - struct packet* question, void* data, int size) -{ - int ret = 0; - /* Erase the user flash information pages */ - ret = iap_erase_info_page(0, 2); - if (ret != 0) { - dtplug_protocol_send_reply(handle, question, ERROR_FLASH_ERASE, 0, NULL); - return -1; - } - ret = iap_copy_ram_to_flash((uint32_t)get_user_info(), (uint32_t)data, size); - if (ret != 0) { - dtplug_protocol_send_reply(handle, question, ERROR_FLASH_WRITE, 0, NULL); - return -1; - } - return 0; -} - - -/******************************************************************************/ -/* Common packets handlers. - * Return 1 when packet has been handled, or 0 if the type is not a common one and some - * board or application specific code should take care of it. - */ -static int dtplug_protocol_common_handles(struct dtplug_protocol_handle* handle, struct packet* question) -{ - uint32_t tmp_val_swap = 0; - /* These we can always handle */ - switch (question->info.type) { - case PKT_TYPE_PING: - question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ - dtplug_protocol_send_reply(handle, question, NO_ERROR, 0, NULL); /* A ping needs no aditional data */ - dtplug_protocol_release_old_packet(handle); - break; - case PKT_TYPE_RESET: - /* Software reset of the board. No way out. */ - NVIC_SystemReset(); - break; - case PKT_TYPE_SET_TIME: - { - struct time_spec new_time, time_diff; - uint32_t* seconds = (uint32_t*)question->data; - uint16_t* msec = (uint16_t*)&(question->data[4]); - uint8_t time_buff[6]; - if (question->info.seq_num & QUICK_DATA_PACKET) { - dtplug_protocol_send_reply(handle, question, ERROR_IN_PKT_STRUCTURE, 0, NULL); - break; - } - if (question->info.data.size != 6) { - dtplug_protocol_send_reply(handle, question, ERROR_IN_DATA_VALUES, 0, NULL); - break; - } - new_time.seconds = byte_swap_32(*seconds); - new_time.msec = (uint16_t)byte_swap_16(*msec); - if (!(question->info.seq_num & PACKET_NEEDS_REPLY)) { - set_time(&new_time); - } else { - set_time_and_get_difference(&new_time, &time_diff); - time_to_buff_swapped(time_buff, &time_diff); - dtplug_protocol_send_reply(handle, question, NO_ERROR, 6, time_buff); - } - } - dtplug_protocol_release_old_packet(handle); - break; - case PKT_TYPE_SET_USER_INFO: - { - uint8_t tmp_data[sizeof(struct user_info)] __attribute__ ((__aligned__(4))) = {}; - uint8_t offset = question->data[0]; - uint8_t size = question->data[1]; - if (question->info.seq_num & QUICK_DATA_PACKET) { - dtplug_protocol_send_reply(handle, question, ERROR_IN_PKT_STRUCTURE, 0, NULL); - break; - } - /* Check that amount of data provided is OK and does not go beyond user_info structure end */ - if ((question->info.data.size != (size + 2)) || ((offset + size) > sizeof(struct user_info))) { - dtplug_protocol_send_reply(handle, question, ERROR_IN_DATA_VALUES, 0, NULL); - break; - } - /* Copy all board data before flash erase */ - memcpy(tmp_data, get_user_info(), sizeof(struct user_info)); - /* Update information in the copy */ - memcpy(&(tmp_data[offset]), &(question->data[2]), size); - /* Update the user flash information pages */ - if (dtplug_protocol_user_flash_update(handle, question, tmp_data, sizeof(struct user_info)) != 0) { - /* Reply got sent, if return value is not 0 */ - break; - } - } - /* Software reset of the board. No way out. */ - NVIC_SystemReset(); - break; - case PKT_TYPE_GET_NUM_PACKETS: - question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ - tmp_val_swap = byte_swap_32(handle->packet_count); - dtplug_protocol_send_reply(handle, question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap)); - dtplug_protocol_release_old_packet(handle); - break; - case PKT_TYPE_GET_ERRORS: - question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ - dtplug_protocol_send_reply(handle, question, NO_ERROR, 0, NULL); /* Error handling code will take care of filling the message */ - dtplug_protocol_release_old_packet(handle); - break; - case PKT_TYPE_GET_NUM_ERRORS: - question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ - tmp_val_swap = byte_swap_32(handle->errors_count); - dtplug_protocol_send_reply(handle, question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap)); - dtplug_protocol_release_old_packet(handle); - break; - default: - /* We do not handle this type, it must be a board specific one */ - return 0; - } - /* Packet handled */ - status_led(green_off); - return 1; -} - - -/* Get a pointer to the new packet received. - * Return NULL when no new packet were received since last packet was released. - * If a new packet is present, call the common handles first. - */ -struct packet* dtplug_protocol_get_next_packet_ok(struct dtplug_protocol_handle* handle) -{ - if (handle->packet_ok != NULL) { - struct packet* pkt_tmp = (struct packet*)handle->packet_ok; - if (dtplug_protocol_common_handles(handle, pkt_tmp) == 0) { - return pkt_tmp; - } - } - return NULL; -} - diff --git a/lib/protocols/dtplug/slave.c b/lib/protocols/dtplug/slave.c new file mode 100644 index 0000000..81e5d67 --- /dev/null +++ b/lib/protocols/dtplug/slave.c @@ -0,0 +1,487 @@ +/**************************************************************************** + * lib/protocol/dtplug/slave.c + * + * + * Copyright 2013-2015 Nathael Pajani + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + ****************************************************************************/ + +#include +#include "core/system.h" +#include "core/iap.h" +#include "core/user_information_block.h" +#include "lib/stdio.h" +#include "lib/string.h" +#include "drivers/serial.h" +#include "extdrv/status_led.h" +#include "lib/time.h" + +#include "lib/protocols/dtplug/defs.h" +#include "lib/protocols/dtplug/slave.h" + +/******************************************************************************/ +/* DTPlug (or DomoTab, PC, ...) Communication */ + +#define DTPP_MAX_HANDLERS 2 +static struct dtplug_protocol_handle* dtpp_handles[DTPP_MAX_HANDLERS] = {0}; + + + +static void dtplug_protocol_decode(struct dtplug_protocol_handle* handle, uint8_t c); + +static void dtplug_protocol_decoder_0(uint8_t c) +{ + dtplug_protocol_decode(dtpp_handles[0], c); +} +static void dtplug_protocol_decoder_1(uint8_t c) +{ + dtplug_protocol_decode(dtpp_handles[1], c); +} + + +/* Setup the UART used for communication with the host / master (the module is slave) */ +void dtplug_protocol_set_dtplug_comm_uart(uint8_t uart_num, struct dtplug_protocol_handle* handle) +{ + void* decoder = dtplug_protocol_decoder_0; + + /* Basic parameter checks */ + if (uart_num >= DTPP_MAX_HANDLERS) { + return; + } + if (handle == NULL) { + return; + } + + /* Configure and register handle and configure uart */ + handle->rx_packet = handle->packets; + handle->packet_ok = NULL; + handle->done_with_old_packet = 1; + handle->uart = uart_num; + dtpp_handles[uart_num] = handle; + switch (uart_num) { + case 1: + decoder = dtplug_protocol_decoder_1; + break; + case 0: + default: + break; + } + uart_on(uart_num, 115200, decoder); +} + + +/* Tell the receive and decode routine that the "handle->packet_ok" packet is no more in use and that + * we are ready to handle a new one. + */ +void dtplug_protocol_release_old_packet(struct dtplug_protocol_handle* handle) +{ + handle->packet_ok = NULL; + handle->done_with_old_packet = 1; +} + + + +/* When a packet has not been handled we must not count it as acknowledged + * On the next ping request the master will then see wich packet caused the problem. + */ +void dtplug_protocol_add_error_to_list(struct dtplug_protocol_handle* handle, struct header* info, uint8_t error_code) +{ + if (handle->num_errors_stored < (DTPP_MAX_ERROR_STORED * 2)) { + if (error_code == NO_ERROR) { + error_code = ERROR_PKT_NOT_HANDLED; + } + handle->error_storage[handle->num_errors_stored++] = error_code; + handle->error_storage[handle->num_errors_stored++] = (info->seq_num & SEQUENCE_MASK); + } +} + + +/* Handle packet reception, including checksums */ +/* 'sum' is used to sum all the received characters, and if the last byte of sum is 0 for each + * part (header and data) then the packet is valid. + * 'full_size' is the size of the whole packet, including header, updated as soon as the header + * is checked and valid + */ +static void dtplug_protocol_decode(struct dtplug_protocol_handle* handle, uint8_t c) +{ + static uint8_t rx_ptr = 0; + static uint8_t sum = 0; + static uint8_t full_size = 0; + static struct header* info = NULL; + + status_led(red_on); + /* Do not start reception before receiving the packet start character */ + if ((rx_ptr == 0) && (c != FIRST_PACKET_CHAR)) { + return; + } + + /* Store the new byte in the packet */ + if (rx_ptr < sizeof(struct packet)) { + ((uint8_t*)handle->rx_packet)[rx_ptr++] = c; + sum += c; + } else { + goto next_packet; + } + + /* Is this packet valid ? (at end of header reception) */ + if (rx_ptr == sizeof(struct header)) { + if (sum != 0) { + goto next_packet; + } + /* Start the new checksum for data (if any) */ + sum = 0; + + info = (struct header*)handle->rx_packet; + full_size = sizeof(struct header); + if (!(info->seq_num & QUICK_DATA_PACKET)) { + /* Do not care about big data packets here */ + full_size += (info->data.size & PKT_SIZE_MASK); + } + } + + /* Did we receive the whole packet ? */ + if (rx_ptr == full_size) { + /* From here on, the packet is valid, we can provide some feedback */ + /* Check data checksum */ + if (!(info->seq_num & QUICK_DATA_PACKET) && (sum != info->data.checksum)) { + dtplug_protocol_add_error_to_list(handle, info, ERROR_IN_DATA_CHECKSUM); + handle->errors_count++; + goto next_packet; + } + /* Warning, if we are still using the old packet there's a problem */ + if (handle->done_with_old_packet == 0) { + /* FIXME : what to do then ? inform the master ? ignore the new packet ? */ + dtplug_protocol_add_error_to_list(handle, info, ERROR_LAST_PKT_IN_PROCESS); + handle->errors_count++; + goto next_packet; + } + /* Count received packets */ + handle->packet_count++; + /* Mark packet as OK : switch pointers */ + handle->packet_ok = handle->rx_packet; + handle->done_with_old_packet = 0; + /* Switch our receiving buffer (do not overide the last received packet !) */ + if (handle->rx_packet == handle->packets) { + handle->rx_packet = handle->packets + 1; + } else { + handle->rx_packet = handle->packets; + } + status_led(green_on); + /* And get ready to receive the next packet */ + goto next_packet; + } + + return; + +next_packet: +#ifdef DEBUG + if (handle->done_with_old_packet != 0) { + uprintf(handle->uart, "Rx:%d, f:%d, cnt:%d\n", rx_ptr, full_size, handle->packet_count); + if (rx_ptr >= sizeof(struct header)) { + struct header* h = &(handle->rx_packet->info); + uprintf(handle->uart, "P: type:%03d, seq:%d, e:%d, q:%d\n", h->type, h->seq_num, + (h->seq_num & PACKET_IS_ERROR), (h->seq_num & QUICK_DATA_PACKET)); + } + } +#endif + /* Wether the packet was OK or not doesn't matter, go on for a new one :) */ + full_size = 0; + rx_ptr = 0; + sum = 0; +} + +/* This function handle sending replies when requested by the host. + * When there is an error but the host did not request a reply, store the error for future request. + * When a reply is effectively sent, the PACKET_NEEDS_REPLY bit is removed from the sequence number so the + * packet handling code will know if there is still a PING request to be answered. + */ +void dtplug_protocol_send_reply(struct dtplug_protocol_handle* handle, + struct packet* question, uint8_t error, int size, uint8_t* data) +{ + struct packet reply; + struct header* tx_info = &(reply.info); + int i = 0, sent = 0, len = 0; + uint8_t sum = 0; + int data_send_size = size, data_sent = 0; + uint8_t* data_src = data; + uint8_t type = question->info.type; + + if (error != NO_ERROR) { + handle->errors_count++; + } + /* If no reply requested : we were called thus there have been an error. We should store the error and return. */ + if (!(question->info.seq_num & PACKET_NEEDS_REPLY)) { + /* If we still have some room for the error, then keep track of it (if any), + * otherwise ... drop it, we don't have that much memory to keep track of hundreds of errors */ + if (error != NO_ERROR) { + dtplug_protocol_add_error_to_list(handle, &(question->info), error); + } + return; + } + + /* Remove the PACKET_NEEDS_REPLY bit as the reply is being built to prevent multiple replies to the + * same packet. (do it now to prevent the mask when building the type field of the reply) */ + question->info.seq_num &= ~(PACKET_NEEDS_REPLY); + + /* If any error stored, send "got many errors" reply and store the error, but if + * the host is reading the error table, no need to say there is an error table. + * Rather send any possible new error. + */ + if (handle->num_errors_stored != 0) { + /* Store the new error if any */ + if (error != NO_ERROR) { + dtplug_protocol_add_error_to_list(handle, &(question->info), error); + } + /* The master wants to get all errors, give them even if there is an error in the sequence number */ + if (question->info.type == PKT_TYPE_GET_ERRORS) { + data_send_size = handle->num_errors_stored; + size = handle->num_errors_stored; + data_src = handle->error_storage; + handle->num_errors_stored = 0; + } else { + error = GOT_MANY_ERRORS; + data_send_size = 0; + size = 0; + } + } + + do { + /* Does the data fit in the message ? */ + if (data_send_size > PACKET_DATA_SIZE) { + data_send_size = PACKET_DATA_SIZE; + } + + /* Build the reply */ + tx_info->start = FIRST_PACKET_CHAR; + tx_info->type = type; + tx_info->seq_num = question->info.seq_num; + + len = sizeof(struct header); /* At least, send header on serial link */ + if (error) { + tx_info->seq_num |= PACKET_IS_ERROR; + tx_info->err.error_code = error; + if (error == GOT_MANY_ERRORS) { + tx_info->err.info = handle->num_errors_stored; + } + } else { + /* Append possible data */ + if ((data_src != NULL) && (data_send_size != 0)) { + /* Can we send a quick data packet ? */ + if (size && (size <= 2)) { + tx_info->seq_num |= QUICK_DATA_PACKET; + tx_info->quick_data[0] = data_src[0]; + tx_info->quick_data[1] = data_src[1]; + } else { + /* Copy data, compute checksum (also OK for a data_send_size of 0) */ + sum = 0; + for (i = 0; i < data_send_size; i++) { + reply.data[i] = data_src[i]; + sum += data_src[i]; /* Build checksum */ + } + /* And update header information */ + tx_info->data.size = data_send_size; + /* Will this packet be continued in the following one ? */ + if (data_send_size < (size - data_sent)) { + tx_info->data.size |= BIG_DATA_PKT; + } + tx_info->data.checksum = sum; + /* Update length of data to send on serial link */ + len += data_send_size; + } + } + } + + /* Compute header checksum */ + sum = 0; + tx_info->checksum = 0; + for (i = 0; i < sizeof(struct header); i++) { + sum += ((uint8_t*)tx_info)[i]; + } + tx_info->checksum = ((uint8_t)(256 - sum)); + + /* And send the reply */ + sent = 0; + while (sent < len) { + int ret = serial_write(handle->uart, (((char*)(&reply)) + sent), (len - sent)); + if (ret >= 0) { + sent += ret; + } else { + /* Store a sending error, though it may never be sent ... */ + dtplug_protocol_add_error_to_list(handle, &(question->info), ERROR_IN_UART_TX); + handle->errors_count++; + return; + } + /* The serial baud rate is 115200, which means 64 bytes are sent in a little less than 6 ms. + * When there is not enougth place in the buffer, the return value should be 64, meaning 64 byte + * were stored for transmission. Sleep for 6ms and try sending the next part. + */ + if (sent < len) { + msleep(5); + } + } + data_sent += data_send_size; + + /* Need to send more ? */ + if (data_sent < size) { + /* Move data pointer */ + data_src += data_send_size; + /* Update size to send. check against PACKET_DATA_SIZE is done at beginning of loop */ + data_send_size = (size - data_sent); + /* Set packet type to continued data packet for following packets */ + type = PKT_TYPE_CONTINUED_DATA; + } + } while (data_sent < size); +} + + +/******************************************************************************/ +/* User information block re-programming + * Make sure that data is aligned on 4 bytes boundary, and that size is a multiple of 4. + */ +static int dtplug_protocol_user_flash_update(struct dtplug_protocol_handle* handle, + struct packet* question, void* data, int size) +{ + int ret = 0; + /* Erase the user flash information pages */ + ret = iap_erase_info_page(0, 2); + if (ret != 0) { + dtplug_protocol_send_reply(handle, question, ERROR_FLASH_ERASE, 0, NULL); + return -1; + } + ret = iap_copy_ram_to_flash((uint32_t)get_user_info(), (uint32_t)data, size); + if (ret != 0) { + dtplug_protocol_send_reply(handle, question, ERROR_FLASH_WRITE, 0, NULL); + return -1; + } + return 0; +} + + +/******************************************************************************/ +/* Common packets handlers. + * Return 1 when packet has been handled, or 0 if the type is not a common one and some + * board or application specific code should take care of it. + */ +static int dtplug_protocol_common_handles(struct dtplug_protocol_handle* handle, struct packet* question) +{ + uint32_t tmp_val_swap = 0; + /* These we can always handle */ + switch (question->info.type) { + case PKT_TYPE_PING: + question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ + dtplug_protocol_send_reply(handle, question, NO_ERROR, 0, NULL); /* A ping needs no aditional data */ + dtplug_protocol_release_old_packet(handle); + break; + case PKT_TYPE_RESET: + /* Software reset of the board. No way out. */ + NVIC_SystemReset(); + break; + case PKT_TYPE_SET_TIME: + { + struct time_spec new_time, time_diff; + uint32_t* seconds = (uint32_t*)question->data; + uint16_t* msec = (uint16_t*)&(question->data[4]); + uint8_t time_buff[6]; + if (question->info.seq_num & QUICK_DATA_PACKET) { + dtplug_protocol_send_reply(handle, question, ERROR_IN_PKT_STRUCTURE, 0, NULL); + break; + } + if (question->info.data.size != 6) { + dtplug_protocol_send_reply(handle, question, ERROR_IN_DATA_VALUES, 0, NULL); + break; + } + new_time.seconds = byte_swap_32(*seconds); + new_time.msec = (uint16_t)byte_swap_16(*msec); + if (!(question->info.seq_num & PACKET_NEEDS_REPLY)) { + set_time(&new_time); + } else { + set_time_and_get_difference(&new_time, &time_diff); + time_to_buff_swapped(time_buff, &time_diff); + dtplug_protocol_send_reply(handle, question, NO_ERROR, 6, time_buff); + } + } + dtplug_protocol_release_old_packet(handle); + break; + case PKT_TYPE_SET_USER_INFO: + { + uint8_t tmp_data[sizeof(struct user_info)] __attribute__ ((__aligned__(4))) = {}; + uint8_t offset = question->data[0]; + uint8_t size = question->data[1]; + if (question->info.seq_num & QUICK_DATA_PACKET) { + dtplug_protocol_send_reply(handle, question, ERROR_IN_PKT_STRUCTURE, 0, NULL); + break; + } + /* Check that amount of data provided is OK and does not go beyond user_info structure end */ + if ((question->info.data.size != (size + 2)) || ((offset + size) > sizeof(struct user_info))) { + dtplug_protocol_send_reply(handle, question, ERROR_IN_DATA_VALUES, 0, NULL); + break; + } + /* Copy all board data before flash erase */ + memcpy(tmp_data, get_user_info(), sizeof(struct user_info)); + /* Update information in the copy */ + memcpy(&(tmp_data[offset]), &(question->data[2]), size); + /* Update the user flash information pages */ + if (dtplug_protocol_user_flash_update(handle, question, tmp_data, sizeof(struct user_info)) != 0) { + /* Reply got sent, if return value is not 0 */ + break; + } + } + /* Software reset of the board. No way out. */ + NVIC_SystemReset(); + break; + case PKT_TYPE_GET_NUM_PACKETS: + question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ + tmp_val_swap = byte_swap_32(handle->packet_count); + dtplug_protocol_send_reply(handle, question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap)); + dtplug_protocol_release_old_packet(handle); + break; + case PKT_TYPE_GET_ERRORS: + question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ + dtplug_protocol_send_reply(handle, question, NO_ERROR, 0, NULL); /* Error handling code will take care of filling the message */ + dtplug_protocol_release_old_packet(handle); + break; + case PKT_TYPE_GET_NUM_ERRORS: + question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ + tmp_val_swap = byte_swap_32(handle->errors_count); + dtplug_protocol_send_reply(handle, question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap)); + dtplug_protocol_release_old_packet(handle); + break; + default: + /* We do not handle this type, it must be a board specific one */ + return 0; + } + /* Packet handled */ + status_led(green_off); + return 1; +} + + +/* Get a pointer to the new packet received. + * Return NULL when no new packet were received since last packet was released. + * If a new packet is present, call the common handles first. + */ +struct packet* dtplug_protocol_get_next_packet_ok(struct dtplug_protocol_handle* handle) +{ + if (handle->packet_ok != NULL) { + struct packet* pkt_tmp = (struct packet*)handle->packet_ok; + if (dtplug_protocol_common_handles(handle, pkt_tmp) == 0) { + return pkt_tmp; + } + } + return NULL; +} +