diff --git a/stack/apps/gateway/CMakeLists.txt b/stack/apps/gateway/CMakeLists.txt index 7fee991da..f351f576e 100644 --- a/stack/apps/gateway/CMakeLists.txt +++ b/stack/apps/gateway/CMakeLists.txt @@ -31,7 +31,7 @@ IF(${MODULE_LORAWAN}) SET(libs alp d7ap d7ap_fs lorawan framework) ELSE() - SET(libs alp d7ap d7ap_fs framework) + SET(libs alp d7ap framework d7ap_fs) ENDIF() APP_BUILD(NAME ${APP_NAME} SOURCES app.c LIBS ${libs}) diff --git a/stack/apps/modem/CMakeLists.txt b/stack/apps/modem/CMakeLists.txt index 70cae7957..5a91eecc8 100644 --- a/stack/apps/modem/CMakeLists.txt +++ b/stack/apps/modem/CMakeLists.txt @@ -32,7 +32,7 @@ IF(${MODULE_LORAWAN}) SET(libs alp d7ap d7ap_fs lorawan framework) ELSE() - SET(libs alp d7ap d7ap_fs framework) + SET(libs alp d7ap framework d7ap_fs) ENDIF() APP_BUILD(NAME ${APP_NAME} SOURCES modem.c LIBS ${libs}) diff --git a/stack/apps/sensor_action/sensor.c b/stack/apps/sensor_action/sensor.c index 5ee33daa5..0c499af58 100644 --- a/stack/apps/sensor_action/sensor.c +++ b/stack/apps/sensor_action/sensor.c @@ -149,6 +149,7 @@ void bootstrap() { log_print_string("Device booted\n"); + d7ap_fs_init(); d7ap_init(); alp_layer_init(NULL, false); diff --git a/stack/apps/sensor_without_alp/CMakeLists.txt b/stack/apps/sensor_without_alp/CMakeLists.txt index 9985e05e7..0260f62d2 100644 --- a/stack/apps/sensor_without_alp/CMakeLists.txt +++ b/stack/apps/sensor_without_alp/CMakeLists.txt @@ -32,7 +32,7 @@ IF(${MODULE_LORAWAN}) SET(libs d7ap d7ap_fs lorawan framework) ELSE() - SET(libs d7ap d7ap_fs framework) + SET(libs d7ap framework d7ap_fs) ENDIF() APP_BUILD(NAME ${APP_NAME} SOURCES sensor_without_alp.c LIBS ${libs}) diff --git a/stack/apps/sensor_without_alp/sensor_without_alp.c b/stack/apps/sensor_without_alp/sensor_without_alp.c index 65b19974c..ec0478636 100644 --- a/stack/apps/sensor_without_alp/sensor_without_alp.c +++ b/stack/apps/sensor_without_alp/sensor_without_alp.c @@ -71,7 +71,7 @@ static d7ap_session_config_t d7ap_session_config = (d7ap_session_config_t){ void on_receive(uint16_t trans_id, uint8_t* payload, uint8_t len, d7ap_session_result_t result); void on_transmitted(uint16_t trans_id, error_t error); -bool on_unsolicited_response(uint8_t* payload, uint8_t len, d7ap_session_result_t result); +bool on_unsolicited_response(uint8_t* payload, uint16_t len, d7ap_session_result_t result); d7ap_resource_desc_t callbacks = { .receive_cb = &on_receive, @@ -83,17 +83,17 @@ uint8_t d7_client_id; void execute_sensor_measurement() { - // first get the sensor reading ... - int16_t temperature = 0; // in decicelsius. When there is no sensor, we just transmit 0 degrees + int8_t metadata[1024]; -#if defined USE_HTS221 - HTS221_Get_Temperature(hts221_handle, &temperature); -#endif - - temperature = __builtin_bswap16(temperature); // convert to big endian before transmission + for (int i = 0, j = 0x30; i < 1024; i++) + { + metadata[i] = j++; + if (j == 0x3A) + j = 0x30; + } uint16_t trans_id; - d7ap_send(d7_client_id, &d7ap_session_config, (uint8_t*)&temperature, sizeof(temperature), 0, &trans_id); + d7ap_send(d7_client_id, &d7ap_session_config, metadata, sizeof(metadata), 0, &trans_id); } void on_receive(uint16_t trans_id, uint8_t* payload, uint8_t len, d7ap_session_result_t result) @@ -107,7 +107,7 @@ void on_transmitted(uint16_t trans_id, error_t error) timer_post_task_delay(&execute_sensor_measurement, SENSOR_INTERVAL_SEC); } -bool on_unsolicited_response(uint8_t* payload, uint8_t len, d7ap_session_result_t result) +bool on_unsolicited_response(uint8_t* payload, uint16_t len, d7ap_session_result_t result) { log_print_string("Unsolicited response received\n"); return false; @@ -117,6 +117,7 @@ void bootstrap() { log_print_string("Device booted\n"); + d7ap_fs_init(); d7ap_init(); d7_client_id = d7ap_register(&callbacks); diff --git a/stack/framework/components/crc/crc.c b/stack/framework/components/crc/crc.c index 5283a04aa..e9db088f1 100644 --- a/stack/framework/components/crc/crc.c +++ b/stack/framework/components/crc/crc.c @@ -38,7 +38,7 @@ static void update_crc(uint8_t x) crc = crc_new; } -uint16_t crc_calculate(uint8_t* data, uint8_t length) +uint16_t crc_calculate(uint8_t* data, uint16_t length) { crc = 0xffff; uint8_t i = 0; diff --git a/stack/framework/components/fs/fs.c b/stack/framework/components/fs/fs.c index 33a833f91..1204af7e7 100644 --- a/stack/framework/components/fs/fs.c +++ b/stack/framework/components/fs/fs.c @@ -37,8 +37,10 @@ #if defined(FRAMEWORK_LOG_ENABLED) && defined(FRAMEWORK_FS_LOG_ENABLED) #define DPRINT(...) log_print_string( __VA_ARGS__) + #define DPRINT_DATA(...) log_print_data(__VA_ARGS__) #else #define DPRINT(...) + #define DPRINT_DATA(...) #endif static fs_file_t files[FRAMEWORK_FS_FILE_COUNT] = { 0 }; // TODO do not keep all file metadata in RAM but use smaller MRU cache to save RAM @@ -87,7 +89,7 @@ error_t fs_register_block_device(blockdevice_t* block_device, uint8_t bd_index) uint32_t fs_get_address(uint8_t file_id) { return files[file_id].addr; } -void fs_init() +void fs_init(void) { if (is_fs_init_completed) return /*0*/; @@ -106,7 +108,7 @@ void fs_init() DPRINT("fs_init OK"); } -int _fs_init() +int _fs_init(void) { uint8_t expected_magic_number[FS_MAGIC_NUMBER_SIZE] = FS_MAGIC_NUMBER; uint32_t number_of_files; @@ -126,6 +128,7 @@ int _fs_init() #endif assert(number_of_files < FRAMEWORK_FS_FILE_COUNT); + DPRINT("number_of_files: %ld", number_of_files); for(int file_id = 0; file_id < FRAMEWORK_FS_FILE_COUNT; file_id++) { blockdevice_read(bd[FS_BLOCKDEVICE_TYPE_METADATA], (uint8_t*)&files[file_id], @@ -146,12 +149,12 @@ int _fs_init() bd_data_offset[files[file_id].blockdevice_index] += files[file_id].length; } } - + return 0; } //TODO: CRC MAGIC -static int _fs_create_magic() +static int _fs_create_magic(void) { assert(!is_fs_init_completed); uint8_t magic[] = FS_MAGIC_NUMBER; @@ -169,6 +172,9 @@ static int _fs_verify_magic(uint8_t* expected_magic_number) uint8_t magic_number[FS_MAGIC_NUMBER_SIZE]; memset(magic_number,0,FS_MAGIC_NUMBER_SIZE); blockdevice_read(bd[FS_BLOCKDEVICE_TYPE_METADATA], magic_number, 0, FS_MAGIC_NUMBER_SIZE); + + DPRINT("READ MAGIC NUMBER:"); + DPRINT_DATA(magic_number, FS_MAGIC_NUMBER_SIZE); if(memcmp(expected_magic_number, magic_number, FS_MAGIC_NUMBER_SIZE) != 0) // if not the FS on EEPROM is not compatible with the current code return -EINVAL; @@ -191,7 +197,7 @@ int _fs_create_file(uint8_t file_id, fs_blockdevice_types_t bd_type, const uint8 if (bd_type == FS_BLOCKDEVICE_TYPE_VOLATILE) { files[file_id].addr = bd_data_offset[bd_type]; - bd_data_offset[bd_type] += length; + bd_data_offset[bd_type] += length; } else { @@ -221,7 +227,7 @@ int _fs_create_file(uint8_t file_id, fs_blockdevice_types_t bd_type, const uint8 blockdevice_program(bd[bd_type], current_data, current_address, remaining_length); remaining_length = 0; - /* else if this is the starting block, only write untill the end of the first write_block */ + /* else if this is the starting block, only write until the end of the first write_block */ } else if(current_address == files[file_id].addr) { remaining_length -= bd[bd_type]->driver->write_block_size - (current_address & (bd[bd_type]->driver->write_block_size - 1)); @@ -303,7 +309,7 @@ int fs_write_file(uint8_t file_id, uint32_t offset, const uint8_t* buffer, uint3 } while (remaining_length > 0); - DPRINT("fs write_file (file_id %d, offset %d, addr %lu, length %d)\n", + DPRINT("fs write_file (file_id %d, offset %lu, addr %lu, length %lu)", file_id, offset, files[file_id].addr, length); return 0; diff --git a/stack/framework/components/log/log.c b/stack/framework/components/log/log.c index 615e154a5..182f3d616 100644 --- a/stack/framework/components/log/log.c +++ b/stack/framework/components/log/log.c @@ -69,9 +69,7 @@ __LINK_C void log_print_data(uint8_t* message, uint32_t length) for( uint32_t i=0 ; i> 8) & 0x00FF) || header[SERIAL_FRAME_CRC2]!=(calculated_crc & 0x00FF)) { @@ -352,7 +354,7 @@ static void process_rx_fifo(void *arg) } parsed_header = true; fifo_skip(&rx_fifo, SERIAL_FRAME_HEADER_SIZE); - payload_len = header[SERIAL_FRAME_SIZE]; + payload_len = ((header[SERIAL_FRAME_SIZE_MSB] << 8) | header[SERIAL_FRAME_SIZE_LSB]); DPRINT("UART RX, payload size = %i", payload_len); sched_post_task(&process_rx_fifo); } @@ -485,7 +487,7 @@ void modem_interface_init(uint8_t idx, uint32_t baudrate, pin_id_t uart_state_pi modem_interface_transfer_bytes(&reboot_reason, 1, SERIAL_MESSAGE_TYPE_REBOOTED); } -void modem_interface_transfer_bytes(uint8_t* bytes, uint8_t length, serial_message_type_t type) +void modem_interface_transfer_bytes(uint8_t* bytes, uint16_t length, serial_message_type_t type) { uint8_t header[SERIAL_FRAME_HEADER_SIZE]; uint16_t crc=crc_calculate(bytes,length); @@ -496,7 +498,8 @@ void modem_interface_transfer_bytes(uint8_t* bytes, uint8_t length, serial_messa header[SERIAL_FRAME_COUNTER] = packet_up_counter; header[SERIAL_FRAME_TYPE] = type; - header[SERIAL_FRAME_SIZE] = length; + header[SERIAL_FRAME_SIZE_MSB] = ((length & 0xFF00) >> 8); + header[SERIAL_FRAME_SIZE_LSB] = (length & 0x00FF); header[SERIAL_FRAME_CRC1] = (crc >> 8) & 0x00FF; header[SERIAL_FRAME_CRC2] = crc & 0x00FF; diff --git a/stack/framework/hal/common/blockdevice_ram.c b/stack/framework/hal/common/blockdevice_ram.c index 0eeddc34a..6d934363f 100644 --- a/stack/framework/hal/common/blockdevice_ram.c +++ b/stack/framework/hal/common/blockdevice_ram.c @@ -50,7 +50,8 @@ blockdevice_driver_t blockdevice_driver_ram = { static void init(blockdevice_t* bd) { blockdevice_ram_t* bd_ram = (blockdevice_ram_t*)bd; - DPRINT("init RAM block device of size %i\n", bd_ram->size); + (void)bd_ram; + DPRINT("init RAM block device of size %i\n", bd_ram->base.size); } static error_t read(blockdevice_t* bd, uint8_t* data, uint32_t addr, uint32_t size) { diff --git a/stack/framework/inc/alp.h b/stack/framework/inc/alp.h index dd34b0491..874de4648 100644 --- a/stack/framework/inc/alp.h +++ b/stack/framework/inc/alp.h @@ -301,7 +301,7 @@ typedef struct { alp_itf_id_t itf_id; uint8_t itf_cfg_len; uint8_t itf_status_len; - error_t (*send_command)(uint8_t* payload, uint8_t payload_length, uint8_t expected_response_length, uint16_t* trans_id, alp_interface_config_t* itf_cfg); + error_t (*send_command)(uint8_t* payload, uint16_t payload_length, uint8_t expected_response_length, uint16_t* trans_id, alp_interface_config_t* itf_cfg); interface_init init; interface_deinit deinit; bool unique; // TODO diff --git a/stack/framework/inc/crc.h b/stack/framework/inc/crc.h index 89112867d..feef25605 100644 --- a/stack/framework/inc/crc.h +++ b/stack/framework/inc/crc.h @@ -33,7 +33,7 @@ #include -uint16_t crc_calculate(uint8_t* data, uint8_t length); +uint16_t crc_calculate(uint8_t* data, uint16_t length); #endif /* CRC_H_ */ diff --git a/stack/framework/inc/d7ap.h b/stack/framework/inc/d7ap.h index 2f8ed7eaf..c5ef0b66e 100644 --- a/stack/framework/inc/d7ap.h +++ b/stack/framework/inc/d7ap.h @@ -44,7 +44,7 @@ #define ID_TYPE_IS_BROADCAST(id_type) (id_type == ID_TYPE_NBID || id_type == ID_TYPE_NOID) -#define D7A_PAYLOAD_MAX_SIZE 255 // TODO confirm this value when FEC and security are disabled +#define D7A_PAYLOAD_MAX_SIZE 233 // TODO confirm this value when FEC and security are disabled typedef enum { @@ -148,6 +148,7 @@ typedef struct { typedef struct __attribute__((__packed__)) { d7ap_session_qos_t qos; uint8_t dormant_timeout; + uint8_t te; d7ap_addressee_t addressee; } d7ap_session_config_t; @@ -157,7 +158,7 @@ typedef void (*d7ap_receive_callback)(uint16_t trans_id, uint8_t* payload, uint8 * @returns true when the unsolicited request will result in a response payload from the upper layer. If no response is expected * the upper layer should return false, so the stack can respond with an ack immediately (if requested by origin). */ -typedef bool (*d7ap_receive_unsolicited_callback)(uint8_t* payload, uint8_t len, d7ap_session_result_t result); +typedef bool (*d7ap_receive_unsolicited_callback)(uint8_t* payload, uint16_t len, d7ap_session_result_t result); typedef void (*d7ap_transmitted_callback)(uint16_t trans_id, error_t error); typedef struct{ @@ -192,9 +193,9 @@ void d7ap_stop(void); * * @param[in] desc pointer to the client resource * - * @return the client Id + * @return the client Id (-1 when trying to register whereas the D7A stack is not initialised) */ -uint8_t d7ap_register(d7ap_resource_desc_t* desc); +int8_t d7ap_register(d7ap_resource_desc_t* desc); /** @@ -232,7 +233,7 @@ uint8_t d7ap_get_payload_max_size(nls_method_t nls_method); * @return an error (errno.h) in case of failure */ error_t d7ap_send(uint8_t clientId, d7ap_session_config_t* config, uint8_t* payload, - uint8_t len, uint8_t expected_response_len, uint16_t* trans_id); + uint16_t len, uint8_t expected_response_len, uint16_t* trans_id); /** diff --git a/stack/framework/inc/d7ap_fs.h b/stack/framework/inc/d7ap_fs.h index ccb603078..2324b1770 100644 --- a/stack/framework/inc/d7ap_fs.h +++ b/stack/framework/inc/d7ap_fs.h @@ -118,7 +118,7 @@ bool d7ap_fs_unregister_file_modified_callback(uint8_t file_id); bool d7ap_fs_register_file_modifying_callback(uint8_t file_id, d7ap_fs_modifying_file_callback_t callback); bool d7ap_fs_unregister_file_modifying_callback(uint8_t file_id); -void d7ap_fs_init(); +void d7ap_fs_init(void); int d7ap_fs_init_file(uint8_t file_id, const d7ap_fs_file_header_t* file_header, const uint8_t* initial_data); int d7ap_fs_init_file_on_blockdevice(uint8_t file_id, uint8_t blockdevice_index, const d7ap_fs_file_header_t* file_header, const uint8_t* initial_data); diff --git a/stack/framework/inc/fs.h b/stack/framework/inc/fs.h index 68fea53ed..e5df160aa 100644 --- a/stack/framework/inc/fs.h +++ b/stack/framework/inc/fs.h @@ -48,7 +48,7 @@ #endif #ifndef FRAMEWORK_FS_PERMANENT_STORAGE_SIZE -#define FRAMEWORK_FS_PERMANENT_STORAGE_SIZE 1900 +#define FRAMEWORK_FS_PERMANENT_STORAGE_SIZE 2200 #endif #ifndef FRAMEWORK_FS_VOLATILE_STORAGE_SIZE @@ -87,7 +87,7 @@ typedef struct __attribute__((__packed__)) uint32_t addr; } fs_file_t; -void fs_init(); +void fs_init(void); int fs_init_file(uint8_t file_id, fs_blockdevice_types_t bd_type, const uint8_t* initial_data, uint32_t initial_data_length, uint32_t length); int fs_read_file(uint8_t file_id, uint32_t offset, uint8_t* buffer, uint32_t length); int fs_write_file(uint8_t file_id, uint32_t offset, const uint8_t* buffer, uint32_t length); diff --git a/stack/framework/inc/modem_interface.h b/stack/framework/inc/modem_interface.h index 1ae5acaee..7410fb990 100644 --- a/stack/framework/inc/modem_interface.h +++ b/stack/framework/inc/modem_interface.h @@ -21,7 +21,7 @@ typedef void (*target_rebooted_callback_t)(system_reboot_reason_t reboot_reason) /* ---------------HEADER(bytes)--------------------- -|sync|sync|counter|message type|length|crc1|crc2| +|sync|sync|counter|message type|length_msb|length_lsb|crc1|crc2| ------------------------------------------------- */ @@ -41,7 +41,7 @@ void modem_interface_init(uint8_t idx, uint32_t baudrate, pin_id_t uart_state_pi * @param type type of message (SERIAL_MESSAGE_TYPE_ALP, SERIAL_MESSAGE_TYPE_PING_REQUEST, SERIAL_MESSAGE_TYPE_LOGGING, ...) * @return Void. */ -void modem_interface_transfer_bytes(uint8_t* bytes, uint8_t length, serial_message_type_t type); +void modem_interface_transfer_bytes(uint8_t* bytes, uint16_t length, serial_message_type_t type); /** @brief Transmits a string by adding a header and putting it in the UART fifo * @param string Bytes that need to be transmitted * @return Void. diff --git a/stack/modules/alp/alp_layer.c b/stack/modules/alp/alp_layer.c index 9c34095a1..9d76604aa 100644 --- a/stack/modules/alp/alp_layer.c +++ b/stack/modules/alp/alp_layer.c @@ -480,7 +480,7 @@ static alp_status_codes_t process_op_indirect_forward( { DPRINT("indirect fwd"); bool re_read = false; - alp_control_t ctrl; + alp_control_t ctrl = action->ctrl; if ((previous_interface_file_id != action->indirect_interface_operand.interface_file_id) || interface_file_changed) { re_read = true; @@ -851,7 +851,8 @@ static void process_async(void* arg) if (command->use_d7aactp) { DPRINT("Using D7AActP, transmit response to the configured interface"); resp_command->forward_itf_id = command->d7aactp_interface_config.itf_id; - forward_command(resp_command, &command->d7aactp_interface_config); + if (forward_command(resp_command, &command->d7aactp_interface_config) == false) // if interface is not registered, free the resp command + free_command(resp_command); free_command(command); return; } diff --git a/stack/modules/alp/d7ap_interface.c b/stack/modules/alp/d7ap_interface.c index d027f1ae8..8e561f445 100644 --- a/stack/modules/alp/d7ap_interface.c +++ b/stack/modules/alp/d7ap_interface.c @@ -31,7 +31,7 @@ #endif static void response_from_d7ap(uint16_t trans_id, uint8_t* payload, uint8_t len, d7ap_session_result_t result); -static bool command_from_d7ap(uint8_t* payload, uint8_t len, d7ap_session_result_t result); +static bool command_from_d7ap(uint8_t* payload, uint16_t len, d7ap_session_result_t result); static void d7ap_command_completed(uint16_t trans_id, error_t error); static alp_interface_t d7_alp_interface; @@ -108,7 +108,7 @@ static void response_from_d7ap(uint16_t trans_id, uint8_t* payload, uint8_t len, alp_layer_received_response(trans_id, payload, len, &d7_status); } -static bool command_from_d7ap(uint8_t* payload, uint8_t len, d7ap_session_result_t result) { +static bool command_from_d7ap(uint8_t* payload, uint16_t len, d7ap_session_result_t result) { DPRINT("command from d7 with len %i result linkbudget %i", len, result.link_budget); alp_interface_status_t d7_status = serialize_session_result_to_alp_interface_status(&result); alp_command_t* command = alp_layer_command_alloc(false, false); @@ -124,7 +124,7 @@ static bool command_from_d7ap(uint8_t* payload, uint8_t len, d7ap_session_result return alp_layer_process(command); } -static error_t d7ap_alp_send(uint8_t* payload, uint8_t payload_length, uint8_t expected_response_length, uint16_t* trans_id, alp_interface_config_t* itf_cfg) { +static error_t d7ap_alp_send(uint8_t* payload, uint16_t payload_length, uint8_t expected_response_length, uint16_t* trans_id, alp_interface_config_t* itf_cfg) { DPRINT("sending D7 packet"); if(itf_cfg != NULL) { diff --git a/stack/modules/d7ap/d7anp.c b/stack/modules/d7ap/d7anp.c index ebbc77e88..ff34ed4dd 100644 --- a/stack/modules/d7ap/d7anp.c +++ b/stack/modules/d7ap/d7anp.c @@ -279,7 +279,7 @@ error_t d7anp_tx_foreground_frame(packet_t* packet, bool should_include_origin_t d7anp_prev_state = d7anp_state; // No need to initialize the packet field in case of retry, except the security frame counter - if (packet->type == RETRY_REQUEST) + if ((packet->type == RETRY_REQUEST) && (!packet->d7atp_ctrl.ctrl_fragment)) goto security; if (!should_include_origin_template) diff --git a/stack/modules/d7ap/d7ap.c b/stack/modules/d7ap/d7ap.c index a421f6762..f5c087f71 100644 --- a/stack/modules/d7ap/d7ap.c +++ b/stack/modules/d7ap/d7ap.c @@ -55,11 +55,11 @@ void d7ap_init() { if(inited) return; - inited = true; // Initialize the D7AP stack d7ap_stack_init(); registered_client_nb = 0; + inited = true; } void d7ap_stop() @@ -76,12 +76,16 @@ void d7ap_stop() * * @return the client Id */ -uint8_t d7ap_register(d7ap_resource_desc_t* desc) +int8_t d7ap_register(d7ap_resource_desc_t* desc) { - assert(inited); assert(registered_client_nb < MODULE_D7AP_MAX_CLIENT_COUNT); + + if (inited == false) + return -1; + registered_client[registered_client_nb] = *desc; registered_client_nb++; + DPRINT("\r\nD7A = %d", registered_client_nb-1); return (registered_client_nb-1); } @@ -171,7 +175,7 @@ uint8_t d7ap_get_payload_max_size(nls_method_t nls_method) * @return an error (errno.h) in case of failure */ error_t d7ap_send(uint8_t client_id, d7ap_session_config_t* config, uint8_t* payload, - uint8_t len, uint8_t expected_response_len, uint16_t *trans_id) + uint16_t len, uint8_t expected_response_len, uint16_t *trans_id) { error_t error; diff --git a/stack/modules/d7ap/d7ap_stack.c b/stack/modules/d7ap/d7ap_stack.c index c6305e229..2e8f65977 100644 --- a/stack/modules/d7ap/d7ap_stack.c +++ b/stack/modules/d7ap/d7ap_stack.c @@ -52,6 +52,7 @@ typedef struct { uint8_t client_id; uint8_t request_nb; uint16_t trans_id[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; + bool fragmentation; } session_t; static session_t sessions[MODULE_D7AP_MAX_SESSION_COUNT]; @@ -157,6 +158,7 @@ static void free_session(session_t* session) { session->request_nb = 0; session->client_id = INVALID_CLIENT_ID; session->token = 0; + session->fragmentation = false; }; static session_t* alloc_session(uint8_t client_id) { @@ -232,8 +234,10 @@ static session_t* get_session_by_session_token(uint8_t session_token) }*/ error_t d7ap_stack_send(uint8_t client_id, d7ap_session_config_t* config, uint8_t* payload, - uint8_t len, uint8_t expected_response_length, uint16_t *trans_id) + uint16_t len, uint8_t expected_response_length, uint16_t *trans_id) { + uint8_t request_id; + bool fragmentation = (len > D7A_PAYLOAD_MAX_SIZE) ? true : false; // When an application response is expected, forward the payload directly to the current D7A session // TODO how to filter by client Id since we don't know to which client the request is addressed? @@ -245,7 +249,7 @@ error_t d7ap_stack_send(uint8_t client_id, d7ap_session_config_t* config, uint8_ } // Create or return the master session if the current one is compatible with the given session configuration. - uint8_t session_token = d7asp_master_session_create(config); + uint8_t session_token = d7asp_master_session_create(config, fragmentation); if(session_token == 0) return ERETRY; @@ -267,26 +271,42 @@ error_t d7ap_stack_send(uint8_t client_id, d7ap_session_config_t* config, uint8_ //TODO handle here the fragmentation if needed? - uint8_t request_id = d7asp_queue_request(session->token, - payload, len, - expected_response_length); + if ((len / D7A_PAYLOAD_MAX_SIZE) > MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT) + return -ESIZE; - session->trans_id[session->request_nb] = ((uint16_t)session->token << 8) | (request_id & 0x00FF); + if (len > D7A_PAYLOAD_MAX_SIZE) + session->fragmentation = true; - if (trans_id != NULL) { - *trans_id = session->trans_id[session->request_nb]; - DPRINT("[D7AP] request posted with trans_id %02X and request_nb %d", *trans_id, session->request_nb); - } else { - DPRINT("[D7AP] request posted with request_nb %d", session->request_nb); + while(len) + { + request_id = d7asp_queue_request(session->token, + payload + session->request_nb * D7A_PAYLOAD_MAX_SIZE, + len > D7A_PAYLOAD_MAX_SIZE ? D7A_PAYLOAD_MAX_SIZE : len, + expected_response_length); + + session->trans_id[session->request_nb] = ((uint16_t)session->token << 8) | (request_id & 0x00FF); + + if (trans_id != NULL) { + *trans_id = session->trans_id[session->request_nb]; + DPRINT("[D7AP] request posted with trans_id %02X and request_nb %d", *trans_id, session->request_nb); + } else { + DPRINT("[D7AP] request posted with request_nb %d", session->request_nb); + } + + DPRINT_DATA(payload + session->request_nb * D7A_PAYLOAD_MAX_SIZE, + len > D7A_PAYLOAD_MAX_SIZE ? D7A_PAYLOAD_MAX_SIZE : len); + + session->request_nb++; + if (len > D7A_PAYLOAD_MAX_SIZE) + len -= D7A_PAYLOAD_MAX_SIZE; + else + len = 0; } - - DPRINT_DATA(payload, len); - session->request_nb++; return SUCCESS; } -bool d7ap_stack_process_unsolicited_request(uint8_t *payload, uint8_t length, d7ap_session_result_t result) +bool d7ap_stack_process_unsolicited_request(uint8_t *payload, uint16_t length, d7ap_session_result_t result) { bool expect_upper_layer_resp_payload = false; @@ -340,7 +360,7 @@ void d7ap_stack_process_received_response(uint8_t *payload, uint8_t length, d7ap registered_client[session->client_id].receive_cb(trans_id, payload, length, result); } -void d7ap_stack_session_completed(uint8_t session_token, uint8_t* progress_bitmap, uint8_t* success_bitmap, uint8_t bitmap_byte_count) +void d7ap_stack_session_completed(uint8_t session_token, uint8_t* progress_bitmap, uint8_t* success_bitmap, uint8_t bitmap_size) { DPRINT("[D7AP] session is completed"); error_t error; @@ -352,6 +372,14 @@ void d7ap_stack_session_completed(uint8_t session_token, uint8_t* progress_bitma if (registered_client[session->client_id].transmitted_cb == NULL) goto free_session; + if (session->fragmentation) + { + // find if at least one fragment is not set as success + error = bitmap_search(success_bitmap, false, bitmap_size) == -1 ? SUCCESS : FAIL; + registered_client[session->client_id].transmitted_cb(session->trans_id[session->request_nb -1], error); + goto free_session; + } + for(uint8_t i = 0; i < session->request_nb; i++) { request_id = (uint8_t)(session->trans_id[i] & 0xFF); @@ -360,9 +388,8 @@ void d7ap_stack_session_completed(uint8_t session_token, uint8_t* progress_bitma registered_client[session->client_id].transmitted_cb(session->trans_id[i], error); } - switch_state(D7AP_STACK_STATE_IDLE); - free_session: + switch_state(D7AP_STACK_STATE_IDLE); free_session(session); } diff --git a/stack/modules/d7ap/d7ap_stack.h b/stack/modules/d7ap/d7ap_stack.h index 4aca1c5ad..fd844bf4b 100644 --- a/stack/modules/d7ap/d7ap_stack.h +++ b/stack/modules/d7ap/d7ap_stack.h @@ -42,9 +42,9 @@ void d7ap_stack_init(void); void d7ap_stack_stop(); error_t d7ap_stack_send(uint8_t client_id, d7ap_session_config_t* config, uint8_t* payload, - uint8_t len, uint8_t expected_response_length, uint16_t *trans_id); + uint16_t len, uint8_t expected_response_length, uint16_t *trans_id); -bool d7ap_stack_process_unsolicited_request(uint8_t* payload, uint8_t length, d7ap_session_result_t result); +bool d7ap_stack_process_unsolicited_request(uint8_t* payload, uint16_t length, d7ap_session_result_t result); void d7ap_stack_process_received_response(uint8_t* payload, uint8_t length, d7ap_session_result_t result); diff --git a/stack/modules/d7ap/d7asp.c b/stack/modules/d7ap/d7asp.c index 3a8d89c76..34781c796 100644 --- a/stack/modules/d7ap/d7asp.c +++ b/stack/modules/d7ap/d7asp.c @@ -61,6 +61,7 @@ struct d7asp_master_session { d7ap_session_config_t config; d7asp_master_session_state_t state; uint8_t token; + bool fragmentation; uint8_t progress_bitmap[REQUESTS_BITMAP_BYTE_COUNT]; uint8_t success_bitmap[REQUESTS_BITMAP_BYTE_COUNT]; uint8_t next_request_id; @@ -68,19 +69,31 @@ struct d7asp_master_session { uint8_t requests_indices[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; /**< Contains for every request ID the index in command_buffer the index where the request begins */ uint8_t requests_lengths[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; /**< Contains for every request ID the index in command_buffer the length of the ALP payload in that request */ uint8_t response_lengths[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; /**< Contains for every request ID the index in command_buffer the expected length of the ALP response for the specific request */ - uint8_t request_buffer[MODULE_D7AP_FIFO_COMMAND_BUFFER_SIZE]; + uint8_t request_buffer[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT * D7A_PAYLOAD_MAX_SIZE]; + uint8_t retry_count[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; d7ap_addressee_t preferred_addressee; + uint16_t tx_duration[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; + dae_access_profile_t active_addressee_access_profile; }; +typedef struct { + d7ap_session_config_t config; + //d7asp_master_session_state_t state; + uint8_t token; + uint8_t received_fragment_nb; + uint8_t total_fragments_nb; + uint8_t fragment_buffer_tail_idx; + uint8_t fragment_indices[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; /**< Contains for every fragment ID the index in fragments_buffer the index where the fragment payload begins */ + uint8_t fragment_lengths[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT]; /**< Contains for every fragment ID the index in fragments_buffer the length of the payload in that fragment */ + uint8_t fragments_buffer[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT * D7A_PAYLOAD_MAX_SIZE]; +} d7asp_fragmentation_session_t; + static d7asp_master_session_t NGDEF(_current_master_session); // TODO we only use 1 fifo for now, should be multiple later (1 per on unique addressee and QoS combination) #define current_master_session NG(_current_master_session) static uint8_t NGDEF(_current_request_id); // TODO move ? #define current_request_id NG(_current_request_id) -static uint8_t NGDEF(_current_request_retry_count); -#define current_request_retry_count NG(_current_request_retry_count) - static packet_t* NGDEF(_current_request_packet); #define current_request_packet NG(_current_request_packet) @@ -90,6 +103,10 @@ static uint8_t NGDEF(_single_request_retry_limit); static packet_t* NGDEF(_current_response_packet); #define current_response_packet NG(_current_response_packet) +static d7asp_fragmentation_session_t NGDEF(_fragmentation_session); +#define fragmentation_session NG(_fragmentation_session) + + static timer_event current_session_timer; static timer_event dormant_session_timer; @@ -133,6 +150,7 @@ static void init_master_session(d7asp_master_session_t* session) { do { session->token = get_rnd() % 0xFF; } while(session->token == 0); + session->fragmentation = false; memset(session->progress_bitmap, 0x00, REQUESTS_BITMAP_BYTE_COUNT); memset(session->success_bitmap, 0x00, REQUESTS_BITMAP_BYTE_COUNT); session->next_request_id = 0; @@ -140,7 +158,9 @@ static void init_master_session(d7asp_master_session_t* session) { memset(session->requests_indices, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); memset(session->requests_lengths, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); memset(session->response_lengths, 255, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); - memset(session->request_buffer, 0x00, MODULE_D7AP_FIFO_COMMAND_BUFFER_SIZE); + memset(session->request_buffer, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT * D7A_PAYLOAD_MAX_SIZE); + memset(session->retry_count, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); + memset(session->tx_duration, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT * sizeof(uint16_t)); // TODO we don't reset preferred_addressee field for now // for now one ALP command execution mostly results one new session, which @@ -148,6 +168,17 @@ static void init_master_session(d7asp_master_session_t* session) { // over the session, until we decide on session lifetime etc } +static void init_fragmentation_session(d7asp_fragmentation_session_t* session) { + + //memset(session, 0x00, sizeof(d7asp_fragmentation_session_t)); + session->received_fragment_nb = 0; + session->total_fragments_nb = 0; + session->fragment_buffer_tail_idx = 0; + memset(session->fragment_indices, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); + memset(session->fragment_lengths, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); + memset(session->fragments_buffer, 0x00, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT * D7A_PAYLOAD_MAX_SIZE); +} + static void flush_completed() { DPRINT("FIFO flush completed"); @@ -156,7 +187,7 @@ static void flush_completed() { // single flush of the FIFO without retry d7ap_stack_session_completed(current_master_session.token, current_master_session.progress_bitmap, - current_master_session.success_bitmap, current_master_session.next_request_id - 1); + current_master_session.success_bitmap, current_master_session.next_request_id - 1); init_master_session(¤t_master_session); current_master_session.state = D7ASP_MASTER_SESSION_IDLE; d7atp_signal_dialog_termination(); @@ -206,7 +237,7 @@ static void flush_fifos() if (current_request_id == NO_ACTIVE_REQUEST_ID) { // find first request which is not acked or dropped - int8_t found_next_req_index = bitmap_search(current_master_session.progress_bitmap, false, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); + int8_t found_next_req_index = bitmap_search(current_master_session.progress_bitmap, false, current_master_session.next_request_id); if (found_next_req_index == -1 || found_next_req_index == current_master_session.next_request_id) { // we handled all requests ... @@ -216,7 +247,17 @@ static void flush_fifos() current_request_id = found_next_req_index; DPRINT("Found request Id %x", current_request_id); - current_request_retry_count = 0; + + DPRINT("Current request retry count: %i", current_master_session.retry_count[current_request_id]); + if (current_master_session.retry_count[current_request_id] == single_request_retry_limit) + { + // mark request as failed and pop + mark_current_request_done(); + DPRINT("Request reached single request retry limit (%i), skipping request", single_request_retry_limit); + current_request_id = NO_ACTIVE_REQUEST_ID; + schedule_current_session(); + return; + } current_request_packet = packet_queue_alloc_packet(); assert(current_request_packet); @@ -242,7 +283,9 @@ static void flush_fifos() } else { - if (current_request_id == 0) + if (current_master_session.retry_count[current_request_id] > 0) + current_request_packet->type = RETRY_REQUEST; + else if (current_request_id == 0) current_request_packet->type = INITIAL_REQUEST; else current_request_packet->type = SUBSEQUENT_REQUEST; @@ -254,8 +297,8 @@ static void flush_fifos() else { // retrying request ... - DPRINT("Current request retry count: %i", current_request_retry_count); - if (current_request_retry_count == single_request_retry_limit) + DPRINT("Current request retry count: %i", current_master_session.retry_count[current_request_id]); + if (current_master_session.retry_count[current_request_id] == single_request_retry_limit) { // mark request as failed and pop mark_current_request_done(); @@ -272,8 +315,28 @@ static void flush_fifos() } uint8_t listen_timeout = 0; // TODO calculate timeout (and update during transaction lifetime) (based on Tc, channel, cs, payload size, # msgs, # retries) - ret = d7atp_send_request(current_master_session.token, current_request_id, (current_request_id == current_master_session.next_request_id - 1), - current_request_packet, ¤t_master_session.config.qos, listen_timeout, current_master_session.response_lengths[current_request_id]); + + if (current_master_session.fragmentation) + { + uint16_t Te = 500; //FIXME adjust the value + uint16_t Tl = 0; + for (uint8_t request_id = 0; request_id < current_master_session.next_request_id; request_id++) + { + if (!bitmap_get(current_master_session.success_bitmap, request_id)) + { + Tl += (current_master_session.tx_duration[request_id] + Te) * (single_request_retry_limit - current_master_session.retry_count[current_request_id]); + } + } + + listen_timeout = compress_data(Tl, true); + DPRINT("TL is set to %d compressed to %d", Tl, listen_timeout); + } + + ret = d7atp_send_request(current_master_session.token, current_request_id, + (current_request_id == current_master_session.next_request_id - 1), + current_request_packet, ¤t_master_session.config.qos, + listen_timeout, current_master_session.response_lengths[current_request_id], + current_master_session.fragmentation, current_master_session.next_request_id); if (ret == EPERM) { // this is probably because no further encryption is possible (frame counter reaches the maximum value) @@ -394,11 +457,17 @@ void d7asp_stop() timer_cancel_event(&dormant_session_timer); } -uint8_t d7asp_master_session_create(d7ap_session_config_t* d7asp_master_session_config) { +uint8_t d7asp_master_session_create(d7ap_session_config_t* d7asp_master_session_config, bool fragmentation) { // TODO for now we assume only one concurrent session, in the future we should dynamically allocate (or return from pool) a session if (current_master_session.state != D7ASP_MASTER_SESSION_IDLE) { + if (fragmentation) + { + DPRINT("current master session state %d prevents to create a fragmentation session", current_master_session.state); + return 0; + } + // Requests can be pushed in the FIFO by upper layer anytime if ((current_master_session.config.addressee.access_class == d7asp_master_session_config->addressee.access_class) && (current_master_session.config.addressee.ctrl.nls_method == d7asp_master_session_config->addressee.ctrl.nls_method) && @@ -413,16 +482,18 @@ uint8_t d7asp_master_session_create(d7ap_session_config_t* d7asp_master_session_ DPRINT("current master session state %d", current_master_session.state); - init_master_session(¤t_master_session); + current_master_session.fragmentation = fragmentation; - DPRINT("Create master session %d", current_master_session.token); + DPRINT("Create %s session %d", fragmentation ? "fragmentation" : "master", current_master_session.token); current_master_session.config.qos = d7asp_master_session_config->qos; current_master_session.config.dormant_timeout = d7asp_master_session_config->dormant_timeout; current_master_session.config.addressee.ctrl = d7asp_master_session_config->addressee.ctrl; current_master_session.config.addressee.access_class = d7asp_master_session_config->addressee.access_class; + d7ap_fs_read_access_class(current_master_session.config.addressee.access_specifier, ¤t_master_session.active_addressee_access_profile); + if(current_master_session.config.qos.qos_resp_mode != SESSION_RESP_MODE_PREFERRED) { memcpy(current_master_session.config.addressee.id, d7asp_master_session_config->addressee.id, sizeof(current_master_session.config.addressee.id)); } else { @@ -489,14 +560,14 @@ error_t d7asp_send_response(uint8_t* payload, uint8_t length) return(d7atp_send_response(current_response_packet)); } -uint8_t d7asp_queue_request(uint8_t session_token, uint8_t* alp_payload_buffer, uint8_t alp_payload_length, uint8_t expected_alp_response_length) +uint8_t d7asp_queue_request(uint8_t session_token, uint8_t* payload_buffer, uint8_t payload_length, uint8_t expected_alp_response_length) { DPRINT("Queuing request in the session queue"); d7asp_master_session_t *session = get_master_session_from_token(session_token); // TODO can be called in all session states? assert(session != NULL); - assert(session->request_buffer_tail_idx + alp_payload_length < MODULE_D7AP_FIFO_COMMAND_BUFFER_SIZE); + assert(session->request_buffer_tail_idx + payload_length < (MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT * D7A_PAYLOAD_MAX_SIZE)); assert(session->next_request_id < MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); // TODO do not assert but let upper layer handle this assert(!(expected_alp_response_length > 0 && (session->config.qos.qos_resp_mode == SESSION_RESP_MODE_NO || session->config.qos.qos_resp_mode == SESSION_RESP_MODE_NO_RPT))); // TODO return error @@ -506,10 +577,14 @@ uint8_t d7asp_queue_request(uint8_t session_token, uint8_t* alp_payload_buffer, // TODO request can contain 1 or more ALP commands, find a way to group commands in requests instead of dumping all requests in one buffer uint8_t request_id = session->next_request_id; session->requests_indices[request_id] = session->request_buffer_tail_idx; - session->requests_lengths[request_id] = alp_payload_length; + session->requests_lengths[request_id] = payload_length; session->response_lengths[request_id] = expected_alp_response_length; - memcpy(session->request_buffer + session->request_buffer_tail_idx, alp_payload_buffer, alp_payload_length); - session->request_buffer_tail_idx += alp_payload_length + 1; + memcpy(session->request_buffer + session->request_buffer_tail_idx, payload_buffer, payload_length); + session->request_buffer_tail_idx += payload_length + 1; + session->tx_duration[request_id] = phy_calculate_tx_duration(session->active_addressee_access_profile.channel_header.ch_class, + session->active_addressee_access_profile.channel_header.ch_coding, + payload_length + expected_alp_response_length, false); + session->next_request_id++; if(current_master_session.state == D7ASP_MASTER_SESSION_IDLE) { @@ -534,6 +609,37 @@ uint8_t d7asp_queue_request(uint8_t session_token, uint8_t* alp_payload_buffer, void d7asp_process_received_response(packet_t* packet, bool extension) { hw_watchdog_feed(); // TODO do here? + + assert(d7asp_state == D7ASP_STATE_MASTER); + assert(packet->d7atp_dialog_id == current_master_session.token); + assert(packet->d7atp_transaction_id == current_request_id); + + if (current_master_session.fragmentation) + { + // handle the ACK_BITMAP + if (packet->d7atp_ctrl.ctrl_ack_not_void) + { + /* in case of broadcast, the success bitmap is an AND between the current bitmap and the bitmap provided by the node + for (int8_t i = 0; i < ACK_BITMAP_BYTE_COUNT; i++) + current_master_session.success_bitmap[i] &= packet->d7atp_ack_template.bitmap[i];*/ + /* + * For now, the fragmentation is allowed in unicast only + */ + memcpy(current_master_session.progress_bitmap, packet->d7atp_ack_template.bitmap, ACK_BITMAP_BYTE_COUNT); + memcpy(current_master_session.success_bitmap, packet->d7atp_ack_template.bitmap, ACK_BITMAP_BYTE_COUNT); + } + else + memset(current_master_session.success_bitmap, 0xFF, ACK_BITMAP_BYTE_COUNT); + + packet_queue_free_packet(packet); + current_request_id = NO_ACTIVE_REQUEST_ID; + schedule_current_session(); // continue flushing until all request handled ... + + // stop the current transaction + d7atp_stop_transaction(); + return; + } + d7ap_session_result_t result = { .channel = { .channel_header = packet->phy_config.rx.channel_id.channel_header_raw, @@ -554,10 +660,6 @@ void d7asp_process_received_response(packet_t* packet, bool extension) // .fifo_token and .seqnr filled below }; - assert(d7asp_state == D7ASP_STATE_MASTER); - assert(packet->d7atp_dialog_id == current_master_session.token); - assert(packet->d7atp_transaction_id == current_request_id); - // received ack DPRINT("Received ACK for request ID %d", current_request_id); if (current_master_session.config.qos.qos_resp_mode != SESSION_RESP_MODE_NO @@ -616,7 +718,7 @@ void d7asp_process_received_response(packet_t* packet, bool extension) current_request_id = NO_ACTIVE_REQUEST_ID; schedule_current_session(); // continue flushing until all request handled ... // stop the current transaction - // d7atp_stop_transaction(); //TO BE CHECKED THAT COMMENTING THIS OUT HAS NO NEGATIVE EFFECT + d7atp_stop_transaction(); } // switch to the state slave when the D7ATP Dialog Extension Procedure is initiated and all request are handled else if ((extension) && (current_request_id == current_master_session.next_request_id - 1)) @@ -639,13 +741,70 @@ bool d7asp_process_received_packet(packet_t* packet) d7asp_state == D7ASP_STATE_PENDING_MASTER || d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER); + if ((packet->d7atp_ctrl.ctrl_fragment) && + (d7asp_state == D7ASP_STATE_IDLE || d7asp_state == D7ASP_STATE_PENDING_MASTER)) + { + DPRINT("Fragmentation session is starting"); + init_fragmentation_session(&fragmentation_session); + fragmentation_session.total_fragments_nb = packet->d7atp_fragments_number; + } + // received a request, start slave session, process and respond if (d7asp_state == D7ASP_STATE_IDLE) switch_state(D7ASP_STATE_SLAVE); // don't switch when already in slave state else if (d7asp_state == D7ASP_STATE_PENDING_MASTER) switch_state(D7ASP_STATE_SLAVE_PENDING_MASTER); - if (packet->payload_length > 0) + // check if a fragmentation session is ongoing + if (packet->d7atp_ctrl.ctrl_fragment) + { + assert(fragmentation_session.received_fragment_nb < MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); + + // add fragment to buffer + fragmentation_session.fragment_indices[packet->d7atp_transaction_id] = fragmentation_session.fragment_buffer_tail_idx; + fragmentation_session.fragment_lengths[packet->d7atp_transaction_id] = packet->payload_length; + memcpy(fragmentation_session.fragments_buffer + fragmentation_session.fragment_buffer_tail_idx, packet->payload, packet->payload_length); + fragmentation_session.fragment_buffer_tail_idx += packet->payload_length + 1; + fragmentation_session.received_fragment_nb++; + + // check if fragmentation session is completed + if (fragmentation_session.received_fragment_nb == fragmentation_session.total_fragments_nb) + { + //re-assembly of the fragments + uint8_t payload[MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT * D7A_PAYLOAD_MAX_SIZE]; + uint16_t payload_length = 0; + for(uint8_t i = 0; i < fragmentation_session.total_fragments_nb; i++) + { + memcpy(payload + payload_length, + fragmentation_session.fragments_buffer + fragmentation_session.fragment_indices[i], + fragmentation_session.fragment_lengths[i]); + payload_length += fragmentation_session.fragment_lengths[i]; + } + d7ap_session_result_t result = { + .channel = { + .channel_header = packet->phy_config.rx.channel_id.channel_header_raw, + .center_freq_index = packet->phy_config.rx.channel_id.center_freq_index, + }, + .rx_level = - packet->hw_radio_packet.rx_meta.rssi, + .link_budget = (packet->dll_header.control_eirp_index - 32) - packet->hw_radio_packet.rx_meta.rssi, + .target_rx_level = 80, // TODO not implemented yet, use default for now + .status = { + .ucast = 0, // TODO + .nls = (packet->d7anp_ctrl.nls_method ? true : false), + .retry = false, // TODO + .missed = false, // TODO + }, + .response_to = packet->d7atp_tc, + .response_expected = packet->d7atp_ctrl.ctrl_is_ack_requested, + .addressee = *packet->d7anp_addressee, + .fifo_token = packet->d7atp_dialog_id, + .seqnr = packet->d7atp_transaction_id // the request ID is identified by the last fragment Id + }; + + expect_upper_layer_resp_payload = d7ap_stack_process_unsolicited_request(payload, payload_length, result); + } + } + else if (packet->payload_length > 0) { d7ap_session_result_t result = { .channel = { @@ -708,7 +867,11 @@ bool d7asp_process_received_packet(packet_t* packet) packet->d7atp_tl = compress_data(estimated_tl, true); } else - packet->d7atp_ctrl.ctrl_is_start = 0; + { + packet->d7atp_ctrl.ctrl_is_start = false; + packet->d7atp_ctrl.ctrl_tl = false; + packet->d7atp_ctrl.ctrl_te = false; + } // execute slave transaction if (packet->d7atp_ctrl.ctrl_is_ack_requested) @@ -745,6 +908,9 @@ static void on_request_completed() DPRINT_DATA(current_master_session.preferred_addressee.id, 8); } + // increment the retry counter + current_master_session.retry_count[current_request_id] += 1; + if (!bitmap_get(current_master_session.progress_bitmap, current_request_id)) { if(current_master_session.config.qos.qos_resp_mode == SESSION_RESP_MODE_PREFERRED @@ -754,7 +920,7 @@ static void on_request_completed() current_responder_lowest_lb.lb = LB_MAX; memcpy(current_master_session.preferred_addressee.id, (uint8_t[8]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8); } - current_request_retry_count++; + // the request may be retransmitted, don't free yet (this will be done in flush_fifo() when failed) } else @@ -762,10 +928,10 @@ static void on_request_completed() // request completed, no retries needed so we can free the packet packet_queue_free_packet(current_request_packet); - // terminate the dialog if all request handled + // terminate the dialog if all request handled and if we are not in a fragmentation session // we need to switch to the state idle otherwise we may receive a new packet before the task flush_fifos is handled // in this case, we may assert since the state remains MASTER - if (current_request_id == current_master_session.next_request_id - 1) + if ((current_request_id == current_master_session.next_request_id - 1) && (!current_master_session.fragmentation)) { flush_completed(); return; @@ -788,6 +954,11 @@ void d7asp_signal_packet_transmitted(packet_t *packet) mark_current_request_done(); mark_current_request_successful(); } + else if (current_master_session.fragmentation) + { + // success bitmap is set when receiving the ACK_template from the node if ACK_REQ is set + mark_current_request_done(); + } } else if (d7asp_state == D7ASP_STATE_SLAVE || d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER) { diff --git a/stack/modules/d7ap/d7asp.h b/stack/modules/d7ap/d7asp.h index 347de2c2f..28ae12e84 100644 --- a/stack/modules/d7ap/d7asp.h +++ b/stack/modules/d7ap/d7asp.h @@ -47,7 +47,7 @@ // index [8 .. 15] --> byte 2 // index [16.. 23] --> byte 3 // so the byte count can be calculated as the integer quotient of the division + 1 byte -#define REQUESTS_BITMAP_BYTE_COUNT (MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT/8) + 1 +#define REQUESTS_BITMAP_BYTE_COUNT (MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT/8) + (MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT%8 ? 1 : 0) /** * /brief The state of a session FIFO @@ -56,9 +56,9 @@ typedef struct d7asp_master_session d7asp_master_session_t; void d7asp_init(); void d7asp_stop(); -uint8_t d7asp_master_session_create(d7ap_session_config_t* d7asp_master_session_config); +uint8_t d7asp_master_session_create(d7ap_session_config_t* d7asp_master_session_config, bool fragmentation); -uint8_t d7asp_queue_request(uint8_t session_token, uint8_t* alp_payload_buffer, uint8_t alp_payload_length, uint8_t expected_alp_response_length); +uint8_t d7asp_queue_request(uint8_t session_token, uint8_t* payload_buffer, uint8_t payload_length, uint8_t expected_response_length); error_t d7asp_send_response(uint8_t* payload, uint8_t length); @@ -76,7 +76,7 @@ void d7asp_process_received_response(packet_t* packet, bool extension); bool d7asp_process_received_packet(packet_t* packet); /** - * @brief Called by DLL to signal the CSMA/CA process completed succesfully and packet can be ack-ed for QoS = None + * @brief Called by DLL to signal the CSMA/CA process completed successfully and packet can be ack-ed for QoS = None */ void d7asp_signal_packet_transmitted(packet_t* packet); diff --git a/stack/modules/d7ap/d7atp.c b/stack/modules/d7ap/d7atp.c index 6357710ac..aae83982c 100644 --- a/stack/modules/d7ap/d7atp.c +++ b/stack/modules/d7ap/d7atp.c @@ -23,6 +23,7 @@ #include #include "debug.h" +#include "bitmap.h" #include "hwdebug.h" #include "d7ap.h" #include "d7atp.h" @@ -70,10 +71,14 @@ static dae_access_profile_t NGDEF(_active_addressee_access_profile); static bool NGDEF(_stop_dialog_after_tx); #define stop_dialog_after_tx NG(_stop_dialog_after_tx) +static bool NGDEF(_terminate_transaction); +#define terminate_transaction NG(_terminate_transaction) + static timer_event d7atp_response_period_expired_timer; static timer_event d7atp_execution_delay_expired_timer; static bool ctrl_xoff; +static d7atp_ack_template_t recorded_ack_bitmap; typedef enum { D7ATP_STATE_STOPPED, @@ -137,6 +142,14 @@ static void execution_delay_timeout_handler() // After the Execution Delay period, the Requester engages in a DLL foreground scan for a duration of TC DPRINT("Execution Delay period is expired @%i", timer_get_counter_value()); + if (terminate_transaction) + { + current_transaction_id = NO_ACTIVE_REQUEST_ID; + d7asp_signal_transaction_terminated(); + terminate_transaction = false; + return; + } + d7anp_start_foreground_scan(); } @@ -147,7 +160,10 @@ static void terminate_dialog() switch_state(D7ATP_STATE_IDLE); current_dialog_id = 0; current_transaction_id = NO_ACTIVE_REQUEST_ID; + current_Tl_received = 0; stop_dialog_after_tx = false; + terminate_transaction = false; + memset(&recorded_ack_bitmap, 0, sizeof(d7atp_ack_template_t)); // Discard eventually the Tc timer timer_cancel_event(&d7atp_response_period_expired_timer); @@ -283,11 +299,14 @@ void d7atp_init() current_dialog_id = 0; current_Tl_received = 0; stop_dialog_after_tx = false; + terminate_transaction = false; timer_init_event(&d7atp_response_period_expired_timer, &response_period_timeout_handler); timer_init_event(&d7atp_execution_delay_expired_timer, &execution_delay_timeout_handler); d7ap_fs_register_file_modified_callback(D7A_FILE_SEL_CONF_FILE_ID, &sel_config_modified_callback); sel_config_modified_callback(D7A_FILE_SEL_CONF_FILE_ID); + + memset(&recorded_ack_bitmap, 0, sizeof(d7atp_ack_template_t)); } void d7atp_notify_access_profile_file_changed(uint8_t file_id) @@ -304,12 +323,10 @@ void d7atp_stop() } error_t d7atp_send_request(uint8_t dialog_id, uint8_t transaction_id, bool is_last_transaction, - packet_t* packet, d7ap_session_qos_t* qos_settings, uint8_t listen_timeout, uint8_t expected_response_length) + packet_t* packet, d7ap_session_qos_t* qos_settings, + uint8_t listen_timeout, uint8_t expected_response_length, + bool fragmentation, uint8_t total_fragments) { - // unused parameters - (void)is_last_transaction; - (void)listen_timeout; - /* check that we are not initiating a different dialog if a dialog is still ongoing */ if (current_dialog_id) { @@ -319,7 +336,8 @@ error_t d7atp_send_request(uint8_t dialog_id, uint8_t transaction_id, bool is_la if (d7atp_state != D7ATP_STATE_MASTER_TRANSACTION_REQUEST_PERIOD) switch_state(D7ATP_STATE_MASTER_TRANSACTION_REQUEST_PERIOD); - if ( packet->type == RETRY_REQUEST ) + // In case of fragmentation, request may be retried but after the end of the pool of requests + if ((packet->type == RETRY_REQUEST) && (!packet->d7atp_ctrl.ctrl_fragment)) { DPRINT("Retry the transmission with the same packet content"); current_transaction_id = transaction_id; @@ -345,20 +363,34 @@ error_t d7atp_send_request(uint8_t dialog_id, uint8_t transaction_id, bool is_la && expected_response_length == 0) ack_requested = false; + // ACK only requested for the last fragment + if ((ack_requested) && (fragmentation) && (!is_last_transaction)) + ack_requested = false; + // TODO based on what do we calculate Tc? payload length alone is not enough, depends on for example use of FEC, encryption .. // keep the same as transmission timeout for now // FG scan timeout is set (and scan started) in d7atp_signal_packet_transmitted() for now, to be verified packet->d7atp_ctrl = (d7atp_ctrl_t){ - .ctrl_is_start = true, + .ctrl_is_start = (packet->type == INITIAL_REQUEST) ? true : false, .ctrl_is_ack_requested = ack_requested, .ctrl_ack_not_void = qos_settings->qos_resp_mode == SESSION_RESP_MODE_ON_ERR? true : false, - .ctrl_te = false, + .ctrl_te = fragmentation, //Te is required in case of fragmentation .ctrl_agc = false, - .ctrl_ack_record = false + .ctrl_tl = listen_timeout ? true : false, + .ctrl_fragment = fragmentation }; + if (fragmentation) + { + packet->d7atp_fragments_number = total_fragments; + packet->d7atp_te = 100; //FIXME how to adjust this value? should come from upper layer + } + + if (listen_timeout) + packet->d7atp_tl = listen_timeout; + if (ack_requested) { // TODO payload length does not include headers ... + hardcoded subband @@ -394,8 +426,23 @@ error_t d7atp_send_response(packet_t* packet) d7atp_ctrl_t* d7atp = &(packet->d7atp_ctrl); // leave ctrl_is_ack_requested as is, keep the requester value - d7atp->ctrl_ack_not_void = false; // TODO - d7atp->ctrl_ack_record = false; // TODO validate + d7atp->ctrl_ack_not_void = false; + d7atp->ctrl_tl = false; + d7atp->ctrl_te = false; + + if (d7atp->ctrl_fragment) // TODO valid also if ACK_RECORD bit is set + { + int8_t first_missing_fragment = bitmap_search(recorded_ack_bitmap.bitmap, false, packet->d7atp_fragments_number); + if (first_missing_fragment != -1) + { + d7atp->ctrl_ack_not_void = true; + packet->d7atp_ack_template.ack_transaction_id_start = first_missing_fragment; + packet->d7atp_ack_template.ack_transaction_id_stop = current_transaction_id; + } + + // fragment flag is not set in the response + d7atp->ctrl_fragment = false; + } bool should_include_origin_template = false; // we don't need to send origin ID, the requester will filter based on dialogID, but ... @@ -436,6 +483,13 @@ uint8_t d7atp_assemble_packet_header(packet_t* packet, uint8_t* data_ptr) (*data_ptr) = packet->d7atp_ctrl.ctrl_raw; data_ptr++; (*data_ptr) = packet->d7atp_dialog_id; data_ptr++; (*data_ptr) = packet->d7atp_transaction_id; data_ptr++; + + // add the fragment total number only if it is a request + if ((packet->d7atp_ctrl.ctrl_fragment) && (d7atp_state == D7ATP_STATE_MASTER_TRANSACTION_REQUEST_PERIOD)) { + (*data_ptr) = packet->d7atp_fragments_number; + data_ptr++; + } + if (packet->d7atp_ctrl.ctrl_agc) { (*data_ptr) = packet->d7atp_target_rx_level_i; data_ptr++; @@ -462,9 +516,13 @@ uint8_t d7atp_assemble_packet_header(packet_t* packet, uint8_t* data_ptr) if (packet->d7atp_ctrl.ctrl_is_ack_requested && packet->d7atp_ctrl.ctrl_ack_not_void) { // add Responder ACK template - (*data_ptr) = packet->d7atp_transaction_id; data_ptr++; // transaction ID start - (*data_ptr) = packet->d7atp_transaction_id; data_ptr++; // transaction ID stop - // TODO ACK bitmap, support for multiple segments to ack not implemented yet + (*data_ptr) = packet->d7atp_ack_template.ack_transaction_id_start; data_ptr++; // transaction ID start + (*data_ptr) = packet->d7atp_ack_template.ack_transaction_id_stop; data_ptr++; // transaction ID stop + + //FIXME send compressed ACK_BITMAP + // for now, we send the entire BITMAP since the ACK_WIN is limited + memcpy(data_ptr, recorded_ack_bitmap.bitmap, ACK_BITMAP_BYTE_COUNT); + data_ptr += ACK_BITMAP_BYTE_COUNT; } return data_ptr - d7atp_header_start; @@ -475,6 +533,12 @@ bool d7atp_disassemble_packet_header(packet_t *packet, uint8_t *data_idx) packet->d7atp_ctrl.ctrl_raw = packet->hw_radio_packet.data[(*data_idx)]; (*data_idx)++; packet->d7atp_dialog_id = packet->hw_radio_packet.data[(*data_idx)]; (*data_idx)++; packet->d7atp_transaction_id = packet->hw_radio_packet.data[(*data_idx)]; (*data_idx)++; + + if (packet->d7atp_ctrl.ctrl_fragment) { + packet->d7atp_fragments_number = packet->hw_radio_packet.data[(*data_idx)]; + (*data_idx)++; + } + if (packet->d7atp_ctrl.ctrl_agc) { packet->d7atp_target_rx_level_i = packet->hw_radio_packet.data[(*data_idx)]; (*data_idx)++; @@ -503,7 +567,14 @@ bool d7atp_disassemble_packet_header(packet_t *packet, uint8_t *data_idx) { packet->d7atp_ack_template.ack_transaction_id_start = packet->hw_radio_packet.data[(*data_idx)]; (*data_idx)++; packet->d7atp_ack_template.ack_transaction_id_stop = packet->hw_radio_packet.data[(*data_idx)]; (*data_idx)++; - // TODO ACK bitmap, support for multiple segments to ack not implemented yet + + //FIXME receive compressed ACK_BITMAP + // for now, we send the entire BITMAP since the ACK_WIN is limited + //uint8_t bitmap_indexes = (packet->d7atp_ack_template.ack_transaction_id_stop -packet->d7atp_ack_template.ack_transaction_id_start); + //uint8_t bitmap_len = bitmap_indexes/8 + (bitmap_indexes%8 ? 1 : 0); + + memcpy(packet->d7atp_ack_template.bitmap, packet->hw_radio_packet.data + (*data_idx), ACK_BITMAP_BYTE_COUNT); + (*data_idx) += ACK_BITMAP_BYTE_COUNT; } return true; @@ -545,6 +616,19 @@ void d7atp_signal_packet_transmitted(packet_t* packet) } else { + // Wait the execution delay before terminating the transaction and flushing the next fragment + if ((packet->d7atp_ctrl.ctrl_fragment) && (packet->d7atp_ctrl.ctrl_te)) + { + timer_tick_t Te = adjust_timeout_value(CT_DECOMPRESS(packet->d7atp_te), packet->hw_radio_packet.tx_meta.timestamp); + if (Te) + { + d7atp_execution_delay_expired_timer.next_event = Te; + timer_add_event(&d7atp_execution_delay_expired_timer); + terminate_transaction = true; + return; + } + } + current_transaction_id = NO_ACTIVE_REQUEST_ID; d7asp_signal_transaction_terminated(); } @@ -585,20 +669,22 @@ void d7atp_signal_transmission_failure() void d7atp_process_received_packet(packet_t* packet) { bool extension = false; - timer_tick_t Tc; + timer_tick_t Tc = 0; assert(d7atp_state == D7ATP_STATE_MASTER_TRANSACTION_RESPONSE_PERIOD + || d7atp_state == D7ATP_STATE_SLAVE_TRANSACTION_RECEIVED_REQUEST || d7atp_state == D7ATP_STATE_SLAVE_TRANSACTION_RESPONSE_PERIOD || d7atp_state == D7ATP_STATE_IDLE); // IDLE: when doing channel scanning outside of transaction // copy addressee from NP origin current_addressee.ctrl.id_type = packet->d7anp_ctrl.origin_id_type; current_addressee.access_class = packet->origin_access_class; - DPRINT("ORI AC=0x%02x", packet->origin_access_class); + DPRINT("ORIGINE AC=0x%02x", packet->origin_access_class); memcpy(current_addressee.id, packet->origin_access_id, 8); packet->d7anp_addressee = ¤t_addressee; DPRINT("Recvd dialog %i trans id %i, curr %i - %i", packet->d7atp_dialog_id, packet->d7atp_transaction_id, current_dialog_id, current_transaction_id); + DPRINT("Transaction start flag <%d> ACK_req <%d>", packet->d7atp_ctrl.ctrl_is_start, packet->d7atp_ctrl.ctrl_is_ack_requested); if (packet->d7atp_tl) current_Tl_received = CT_DECOMPRESS(packet->d7atp_tl); @@ -656,10 +742,20 @@ void d7atp_process_received_packet(packet_t* packet) // When not participating in a Dialog if ((!current_dialog_id) && (!packet->d7atp_ctrl.ctrl_is_start)) { - //Responders discard segments marked with START flag set to 0 until they receive a segment with START flag set to 1 - DPRINT("Filtered frame with START cleared"); - packet_queue_free_packet(packet); - return; + // check if Frame is part of a fragmented transmission but not the first part. + if (packet->d7atp_ctrl.ctrl_fragment) + { + DPRINT("Start dialog with fragments but we may have probably already lost some fragments. Expect %d fragments", packet->d7atp_fragments_number); + // set the Transaction ID of the first non-received segment of the Dialog + recorded_ack_bitmap.ack_transaction_id_start = 0; // assuming that the dialog starts with transaction_id equal zero + } + else + { + //Responders discard segments marked with START flag set to 0 until they receive a segment with START flag set to 1 + DPRINT("Filtered frame with START cleared"); + packet_queue_free_packet(packet); + return; + } } // The FG scan is only started when the response period expires. @@ -706,11 +802,20 @@ void d7atp_process_received_packet(packet_t* packet) } } - switch_state(D7ATP_STATE_SLAVE_TRANSACTION_RECEIVED_REQUEST); + if (d7atp_state == D7ATP_STATE_IDLE || d7atp_state == D7ATP_STATE_SLAVE_TRANSACTION_RESPONSE_PERIOD) + switch_state(D7ATP_STATE_SLAVE_TRANSACTION_RECEIVED_REQUEST); + + if ((packet->d7atp_ctrl.ctrl_fragment) && (packet->d7atp_ctrl.ctrl_is_start)) + { + DPRINT("Start dialog containing fragments. Expect %d fragments", packet->d7atp_fragments_number); + } current_dialog_id = packet->d7atp_dialog_id; current_transaction_id = packet->d7atp_transaction_id; + // received segment is marked with 1 in the ack_bitmap + bitmap_set(recorded_ack_bitmap.bitmap, current_transaction_id); + // store the received timestamp for later usage (eg CCA). the rx_meta.timestamp can be // overwritten since it is stored in a union with tx_meta and can thus be changed when // trying to transmit diff --git a/stack/modules/d7ap/d7atp.h b/stack/modules/d7ap/d7atp.h index 53ad390f9..b1380ee97 100644 --- a/stack/modules/d7ap/d7atp.h +++ b/stack/modules/d7ap/d7atp.h @@ -35,8 +35,11 @@ #include "stdint.h" #include "stdbool.h" +#include "MODULE_D7AP_defs.h" #include "d7ap.h" +#define ACK_BITMAP_BYTE_COUNT (MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT/8) + (MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT%8 ? 1 : 0) + typedef struct packet packet_t; /*! \brief The D7ATP CTRL header @@ -50,7 +53,7 @@ typedef struct { uint8_t ctrl_raw; struct { uint8_t ctrl_agc : 1; - bool ctrl_ack_record : 1; + bool ctrl_fragment : 1; bool ctrl_ack_not_void : 1; bool ctrl_is_ack_requested : 1; bool ctrl_te : 1; @@ -76,15 +79,17 @@ typedef struct { } d7a_segment_filter_options_t; typedef struct { - uint8_t ack_transaction_id_start; - uint8_t ack_transaction_id_stop; - // TODO ACK bitmap + uint8_t ack_transaction_id_start; // Transaction ID of the first non-received segment of the Dialog + uint8_t ack_transaction_id_stop; // Transaction ID of the last received segment of the Dialog + uint8_t bitmap[ACK_BITMAP_BYTE_COUNT]; } d7atp_ack_template_t; void d7atp_init(); void d7atp_stop(); error_t d7atp_send_request(uint8_t dialog_id, uint8_t transaction_id, bool is_last_transaction, - packet_t* packet, d7ap_session_qos_t* qos_settings, uint8_t listen_timeout, uint8_t expected_response_length); + packet_t* packet, d7ap_session_qos_t* qos_settings, + uint8_t listen_timeout, uint8_t expected_response_length, + bool fragmentation, uint8_t total_fragments); error_t d7atp_send_response(packet_t* packet); uint8_t d7atp_assemble_packet_header(packet_t* packet, uint8_t* data_ptr); bool d7atp_disassemble_packet_header(packet_t* packet, uint8_t* data_idx); diff --git a/stack/modules/d7ap/dll.c b/stack/modules/d7ap/dll.c index f810dddfd..3946cec73 100644 --- a/stack/modules/d7ap/dll.c +++ b/stack/modules/d7ap/dll.c @@ -325,6 +325,14 @@ void start_background_scan() .rssi_thr = E_CCA, }; error_t err = phy_start_background_scan(&config, &dll_signal_packet_received); + + if (err == FAIL) + { DPRINT("RSSI < minimum --> phy_start_background_scan failed"); + + //TODO + // handle the case where the RSSI is not reached + } + if(rx_nf_method == D7ADLL_MEDIAN_OF_THREE) { uint8_t position = get_position_channel(); //if current_channel in array of channels AND gotten rssi_thr smaller than pre-programmed Ecca diff --git a/stack/modules/d7ap/packet.c b/stack/modules/d7ap/packet.c index f208d282a..6bbafa03f 100644 --- a/stack/modules/d7ap/packet.c +++ b/stack/modules/d7ap/packet.c @@ -75,14 +75,16 @@ void packet_assemble(packet_t* packet) data_ptr += d7anp_secure_payload(packet, nwl_payload, data_ptr - nwl_payload); #endif - packet->hw_radio_packet.length = data_ptr - packet->hw_radio_packet.data + 2; // exclude the CRC bytes + packet->hw_radio_packet.length = data_ptr - packet->hw_radio_packet.data + 2; // include the CRC bytes packet->hw_radio_packet.data[0] = packet->hw_radio_packet.length - 1; // exclude the length byte + if (has_hardware_crc) + packet->hw_radio_packet.length -= 2; // exclude the CRC bytes + // TODO network protocol footer // add CRC - SW CRC when using FEC - if (!has_hardware_crc || - packet->phy_config.tx.channel_id.channel_header.ch_coding == PHY_CODING_FEC_PN9) + if (!has_hardware_crc) { uint16_t crc = __builtin_bswap16(crc_calculate(packet->hw_radio_packet.data, packet->hw_radio_packet.length - 2)); memcpy(data_ptr, &crc, 2); diff --git a/stack/modules/d7ap/packet.h b/stack/modules/d7ap/packet.h index 87b7ba0c4..9675bbcdf 100644 --- a/stack/modules/d7ap/packet.h +++ b/stack/modules/d7ap/packet.h @@ -30,6 +30,7 @@ #include "stdint.h" #include "d7atp.h" #include "dll.h" +#include "d7ap.h" #include "d7anp.h" #include "phy.h" #include "hwradio.h" @@ -59,6 +60,7 @@ struct packet d7atp_ack_template_t d7atp_ack_template; uint8_t d7atp_dialog_id; uint8_t d7atp_transaction_id; + uint8_t d7atp_fragments_number; uint8_t d7atp_tc; uint8_t d7atp_tl; uint8_t d7atp_te; @@ -66,9 +68,8 @@ struct packet packet_type type; uint16_t ETA; uint16_t tx_duration; - // TODO d7atp ack template uint8_t payload_length; - uint8_t payload[239]; // TODO make max size configurable using cmake + uint8_t payload[D7A_PAYLOAD_MAX_SIZE]; // TODO make max size configurable using cmake // TODO store payload here or only pointer to file where we need to fetch it? can we assume data will not be changed in between phy_config_t phy_config; hw_radio_packet_t hw_radio_packet; // TODO we might not need all metadata included in hw_radio_packet_t. If not copy needed data fields diff --git a/stack/modules/d7ap/phy.c b/stack/modules/d7ap/phy.c index ab7d5bcd0..c293733d3 100644 --- a/stack/modules/d7ap/phy.c +++ b/stack/modules/d7ap/phy.c @@ -629,6 +629,8 @@ error_t phy_init(void) { error_t phy_stop() { d7ap_fs_unregister_file_modified_callback(D7A_FILE_FACTORY_SETTINGS_FILE_ID); timer_cancel_event(&continuous_tx_expiration_timer); + + return SUCCESS; } void status_write() { @@ -765,6 +767,7 @@ error_t phy_send_packet(hw_radio_packet_t* packet, phy_tx_config_t* config, phy_ DPRINT("start sending @ %i\n", timer_get_counter_value()); + hw_radio_set_payload_length(fg_frame.encoded_length + 2); hw_radio_send_payload(fg_frame.encoded_packet, fg_frame.encoded_length); return SUCCESS; // TODO other return codes