From f8f3ac279b692667a27a0656afadfe0da1a44575 Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Wed, 2 Sep 2015 11:19:18 +0200 Subject: [PATCH] DTPlug protocol implementation To be fully tested --- include/lib/dtplug_protocol.h | 198 ++++++++++++ include/lib/dtplug_protocol_slave.h | 65 ++++ lib/dtplug_protocol.c | 464 ++++++++++++++++++++++++++++ 3 files changed, 727 insertions(+) create mode 100644 include/lib/dtplug_protocol.h create mode 100644 include/lib/dtplug_protocol_slave.h create mode 100644 lib/dtplug_protocol.c diff --git a/include/lib/dtplug_protocol.h b/include/lib/dtplug_protocol.h new file mode 100644 index 0000000..7997c91 --- /dev/null +++ b/include/lib/dtplug_protocol.h @@ -0,0 +1,198 @@ +/* + * 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) */ + /* 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, + /* RF */ + SEND_ON_RF, +}; + +/* 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 new file mode 100644 index 0000000..663d1cc --- /dev/null +++ b/include/lib/dtplug_protocol_slave.h @@ -0,0 +1,65 @@ +/* + * 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 */ + + +/* Setup the UART used for communication with the host / master (the module is slave) */ +void set_dtplug_comm_uart(uint8_t uart_num); + + +/* 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 release_old_packet(void); + + +/* Get a pointer to the new packet received. + * Return NULL when no new packet were received since last packet was released. + */ +struct packet* get_next_packet_ok(void); + + +/* 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 add_error_to_list(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 send_reply(struct packet* question, uint8_t error, int size, uint8_t* data); + + + +#endif /* LIB_DTPLUG_PROTOCOL_SLAVE_H */ diff --git a/lib/dtplug_protocol.c b/lib/dtplug_protocol.c new file mode 100644 index 0000000..6ccffda --- /dev/null +++ b/lib/dtplug_protocol.c @@ -0,0 +1,464 @@ +/**************************************************************************** + * 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" + + +/******************************************************************************/ +/* DTPlug (or DomoTab, PC, ...) Communication */ + +/* Store two packets, one being received, one being used */ +struct packet packets[2]; +static struct packet* rx_packet = packets; +static volatile struct packet* packet_ok = NULL; + +static uint32_t packet_count = 0; + +#define MAX_ERROR_STORED 8 +static uint32_t errors_count = 0; +static uint8_t error_storage[(MAX_ERROR_STORED * 2)]; +static uint8_t num_errors_stored = 0; + +/* 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 handler will think we have a valid packet to handle upon + * system startup */ +static uint8_t done_with_old_packet = 1; +static uint8_t dtplug_uart = 0; + +static void dtplug_protocol_decode(uint8_t c); + + +/* Setup the UART used for communication with the host / master (the module is slave) */ +void set_dtplug_comm_uart(uint8_t uart_num) { + dtplug_uart = uart_num; + uart_on(uart_num, 115200, dtplug_protocol_decode); +} + + +/* Tell the receive and decode routine that the "packet_ok" packet is no more un use and that + * we are ready to handle a new one. + */ +void release_old_packet(void) +{ + packet_ok = NULL; + 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 add_error_to_list(struct header* info, uint8_t error_code) +{ + if (num_errors_stored < (MAX_ERROR_STORED * 2)) { + if (error_code == NO_ERROR) { + error_code = ERROR_PKT_NOT_HANDLED; + } + error_storage[num_errors_stored++] = error_code; + error_storage[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(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*)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*)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)) { + add_error_to_list(info, ERROR_IN_DATA_CHECKSUM); + errors_count++; + goto next_packet; + } + /* Warning, if we are still using the old packet there's a problem */ + if (done_with_old_packet == 0) { + /* FIXME : what to do then ? inform the master ? ignore the new packet ? */ + add_error_to_list(info, ERROR_LAST_PKT_IN_PROCESS); + errors_count++; + goto next_packet; + } + /* Count received packets */ + packet_count++; + /* Mark packet as OK : switch pointers */ + packet_ok = rx_packet; + done_with_old_packet = 0; + /* Switch our receiving buffer (do not overide the last received packet !) */ + if (rx_packet == packets) { + rx_packet = packets + 1; + } else { + rx_packet = packets; + } + status_led(green_on); + /* And get ready to receive the next packet */ + goto next_packet; + } + + return; + +next_packet: +#ifdef DEBUG + if (done_with_old_packet != 0) { + uprintf(dtplug_uart, "Rx:%d, f:%d, cnt:%d\n", rx_ptr, full_size, packet_count); + if (rx_ptr >= sizeof(struct header)) { + struct header* h = &(rx_packet->info); + uprintf(dtplug_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 send_reply(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) { + 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) { + add_error_to_list(&(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 (num_errors_stored != 0) { + /* Store the new error if any */ + if (error != NO_ERROR) { + add_error_to_list(&(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 = num_errors_stored; + size = num_errors_stored; + data_src = error_storage; + 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 = 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(dtplug_uart, (((char*)(&reply)) + sent), (len - sent)); + if (ret >= 0) { + sent += ret; + } else { + /* Store a sending error, though it may never be sent ... */ + add_error_to_list(&(question->info), ERROR_IN_UART_TX); + 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 user_flash_update(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) { + send_reply(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) { + send_reply(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 common_handles(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 */ + send_reply(question, NO_ERROR, 0, NULL); /* A ping needs no aditional data */ + release_old_packet(); + 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) { + send_reply(question, ERROR_IN_PKT_STRUCTURE, 0, NULL); + break; + } + if (question->info.data.size != 6) { + send_reply(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); + send_reply(question, NO_ERROR, 6, time_buff); + } + } + release_old_packet(); + 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) { + send_reply(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))) { + send_reply(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 (user_flash_update(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(packet_count); + send_reply(question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap)); + release_old_packet(); + break; + case PKT_TYPE_GET_ERRORS: + question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */ + send_reply(question, NO_ERROR, 0, NULL); /* Error handling code will take care of filling the message */ + release_old_packet(); + 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(errors_count); + send_reply(question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap)); + release_old_packet(); + 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* get_next_packet_ok(void) +{ + if (packet_ok != NULL) { + struct packet* pkt_tmp = (struct packet*)packet_ok; + if (common_handles(pkt_tmp) == 0) { + return pkt_tmp; + } + } + return NULL; +} + -- 2.43.0