Rename and move dtplug protocol files under approriate directory in lib/protocols...
authorNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 18 Nov 2015 20:28:00 +0000 (21:28 +0100)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 8 Nov 2022 16:03:04 +0000 (17:03 +0100)
Makefile
include/lib/dtplug_protocol.h [deleted file]
include/lib/dtplug_protocol_slave.h [deleted file]
include/lib/protocols/dtplug/defs.h [new file with mode: 0644]
include/lib/protocols/dtplug/slave.h [new file with mode: 0644]
lib/dtplug_protocol.c [deleted file]
lib/protocols/dtplug/slave.c [new file with mode: 0644]

index ad467e0..63412d3 100644 (file)
--- 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 (file)
index 186356c..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * lib/dtplug_protocol.h
- *
- *
- * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef LIB_DTPLUG_PROTOCOL_H
-#define LIB_DTPLUG_PROTOCOL_H
-
-
-#include <stdint.h>
-
-/******************************************************************************/
-/* 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 (file)
index c3dbb15..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * lib/dtplug_protocol_slave.h
- *
- *
- * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef LIB_DTPLUG_PROTOCOL_SLAVE_H
-#define LIB_DTPLUG_PROTOCOL_SLAVE_H
-
-
-#include <stdint.h>
-#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 (file)
index 0000000..f2b525f
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * lib/protocols/dtplug/defs.h
+ *
+ *
+ * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef LIB_PROTOCOLS_DTPLUG_DEFS_H
+#define LIB_PROTOCOLS_DTPLUG_DEFS_H
+
+
+#include <stdint.h>
+
+/******************************************************************************/
+/* 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 (file)
index 0000000..e0bec14
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * lib/protocols/dtplug/slave.h
+ *
+ *
+ * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef LIB_PROTOCOLS_DTPLUG_SLAVE_H
+#define LIB_PROTOCOLS_DTPLUG_SLAVE_H
+
+
+#include <stdint.h>
+#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 (file)
index 91267e8..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-/****************************************************************************
- *   lib/dtplug_protocol.c
- *
- *
- * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- ****************************************************************************/
-
-#include <stdint.h>
-#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 (file)
index 0000000..81e5d67
--- /dev/null
@@ -0,0 +1,487 @@
+/****************************************************************************
+ *   lib/protocol/dtplug/slave.c
+ *
+ *
+ * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#include <stdint.h>
+#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;
+}
+