/** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * ****************************************************************************** */ /* Standard library includes */ #include /* Library includes */ #include #include #include "FreeRTOS.h" #include "task.h" /* Project includes */ #include "main.h" #include "devices.h" #include "config.h" #include "dataflow.h" #include "handshake.pb.h" #include "data.pb.h" #include "semphr.h" /* Private Macros */ #define device_MDR s2m_MDR_response #define GET_IDX_FROM_ADDR(i2c_addr) (i2c_addr>>1)-1 #define GET_ADDR_FROM_IDX(idx) (idx+1)<<1 #define GET_BIT_FROM_IDX(a, b) a[b>>5]&(1<<(b%32)) #define SET_BIT_FROM_IDX(a, b) a[b>>5]|=(1<<(b%32)) #define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__))) /* #define I2C_ADDRESS 0x05 */ #define BUS_DEVICE_LIMIT 16 /* Macro to toggle between master and slave firmware */ #define MASTER #define mainHANDSHAKE_TASK_PRIORITY (tskIDLE_PRIORITY + 2) #define mainROUTING_TASK_PRIORITY (tskIDLE_PRIORITY + 2) #define mainDATAFLOW_TASK_PRIORITY (tskIDLE_PRIORITY + 1) #define mainHS_FREQUENCY_MS (2000 / portTICK_PERIOD_MS) #define mainQUEUE_LENGTH (1) /* Private globals */ I2C_HandleTypeDef hi2c1; UART_HandleTypeDef huart1; device_info_t *device_info[BUS_DEVICE_LIMIT] = {NULL}; subscription_info_t* subs_info[BUS_DEVICE_LIMIT]; uint32_t allocated[4]={0}; uint8_t dev_sts[BUS_DEVICE_LIMIT] = {OFFLINE}; uint8_t data_idx; _datapoint routing_buffer[ROUTING_BUFSIZE]; /* Index information for each datapoint */ uint8_t routing_idx_buffer[ROUTING_BUFSIZE]; /* Pointer to tail of both data and idx buffers */ uint32_t routing_ptr = 0; /* Function prototypes */ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_I2C1_Init(void); static void MX_USART1_UART_Init(void); hs_status_t handshake(uint32_t i2c_addr); dataflow_status_t device_dataflow(uint8_t i2c_addr, uint32_t SOR_code, uint8_t routing_buf_idx); bool routing(void); static void prvHandshakeTask(void *pvParameters); static void prvRoutingTask(void *prvParam); static void prvDataflowTask(void *prvParam); bool todo_hs_or_not_todo_hs(uint8_t i2c_addr); state_t get_state_from_hs_status(uint16_t device_addr, hs_status_t hs_status); bool decode_subscriptions_callback(pb_istream_t *istream, const pb_field_t *field, void **args); bool encode_subscription_callback(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg); bool encode_datapoint_callback(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg); bool decode_data_callback(pb_istream_t *istream, const pb_field_t *field, void **args); bool master_encode_MDR_callback(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg); /** * @brief The application entry point. * @retval int */ int main(void) { /* MCU Configuration */ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); #ifdef TESTING_ENABLE #ifdef MASTER uint8_t reset_string[] = "\r\n\n==========MASTER RESET=========\r\n\n"; HAL_UART_Transmit(&huart1, reset_string, sizeof(reset_string), 100); #else uint8_t reset_string[] = "\r\n\n==========SLAVE RESET=========\r\n\n"; HAL_UART_Transmit(&huart1, reset_string, sizeof(reset_string), 100); #endif /* MASTER */ #endif /* TESTING_ENABLE */ uint8_t priority_counter = 0, debug_buf[128]; xTaskCreate(prvHandshakeTask, "handshake", configMINIMAL_STACK_SIZE, NULL, mainHANDSHAKE_TASK_PRIORITY,NULL); xTaskCreate(prvRoutingTask, "routing", configMINIMAL_STACK_SIZE, NULL, mainROUTING_TASK_PRIORITY, NULL); xTaskCreate(prvDataflowTask, "dataflow", configMINIMAL_STACK_SIZE, NULL, mainDATAFLOW_TASK_PRIORITY, NULL); /* Start the tasks and timer running. */ vTaskStartScheduler(); for( ;; ); } static void prvHandshakeTask(void *pvParameters) { TickType_t xNextWakeTime; (void) pvParameters; xNextWakeTime = xTaskGetTickCount(); for( ;; ) { /* Place this task in the blocked state until it is time to run again. */ vTaskDelayUntil( &xNextWakeTime, mainHS_FREQUENCY_MS ); hs_status_t hs_status; for (uint8_t curr_addr=0x1; curr_addr <= BUS_DEVICE_LIMIT; curr_addr++) { if (todo_hs_or_not_todo_hs(curr_addr)) { hs_status = handshake(curr_addr); dev_sts[GET_IDX_FROM_ADDR(curr_addr)] = get_state_from_hs_status(curr_addr, hs_status); } } } } static void prvRoutingTask(void *prvParam) { TickType_t xNextWakeTime; (void) prvParam; xNextWakeTime = xTaskGetTickCount(); for( ;; ) { /* Place this task in the blocked state until it is time to run again. */ vTaskDelayUntil( &xNextWakeTime, mainHS_FREQUENCY_MS ); if (routing_ptr > 0) { routing(); } } } static void prvDataflowTask(void *prvParam) { TickType_t xNextWakeTime; (void) prvParam; xNextWakeTime = xTaskGetTickCount(); for( ;; ) { /* Place this task in the blocked state until it is time to run again. */ vTaskDelayUntil( &xNextWakeTime, mainHS_FREQUENCY_MS ); for (int device_idx = 0; device_idx < BUS_DEVICE_LIMIT-1; device_idx++) { if (dev_sts[device_idx] == REGISTERED) { device_dataflow(GET_ADDR_FROM_IDX(device_idx), SLAVE_TX, 0); } } } } hs_status_t handshake(uint32_t i2c_addr) { /* Handshake variables */ uint8_t hs_sts = IDLE; uint8_t *MDR_buf; uint32_t AF_error_counter = 0; uint32_t dev_idx = GET_IDX_FROM_ADDR(i2c_addr); uint16_t MDR_len = 0; s2m_MDR_response MDR_res_message = s2m_MDR_response_init_default; #if defined(TESTING_ENABLE) || defined(DEBUG_ENABLE) uint8_t debug_buf[128]; #endif #ifdef TESTING_ENABLE uint8_t term[] = "\r\n"; #endif while (hs_sts != HS_FAILED && hs_sts != HS_REGISTERED) { switch (hs_sts) { case (IDLE): { uint8_t MDR_req_buf[2] = {0x0, 0x1}; if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2c_addr, MDR_req_buf, 2, 10000) != HAL_OK) { hs_sts = HS_FAILED; #ifdef DEBUG_ENABLE goto __HS_MDR_REQ_I2C_ERROR; __HS_MDR_REQ_I2C_ERROR_END: __asm__("nop"); #endif } else { hs_sts = HS_MDR_ACK; } break; } case (HS_MDR_ACK): { HAL_Delay(MASTER_I2C_BUS_INTERVAL); uint8_t MDR_ACK_buf[2] = {0x0, 0x0}; AF_error_counter = 0; while (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)i2c_addr, MDR_ACK_buf, 2, 100) != HAL_OK) { if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) { hs_sts = HS_FAILED; } if (++AF_error_counter > 1500) { hs_sts = HS_FAILED; } if (hs_sts == HS_FAILED) { #ifdef DEBUG_ENABLE goto __HS_MDR_ACK_I2C_ERROR; __HS_MDR_ACK_I2C_ERROR_END: __asm__("nop"); #endif break; } } if (hs_sts != HS_FAILED) { uint8_t ACK_flag = MDR_ACK_buf[1]; if (ACK_flag == 0xFF) { MDR_len = MDR_ACK_buf[0]; hs_sts = HS_MDR_CTS; } else { hs_sts = HS_FAILED; } } break; } case (HS_MDR_CTS): { uint8_t MDR_CTS_buf[2] = {0x0, 0x02}; if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2c_addr, MDR_CTS_buf, 2, 10000) != HAL_OK) { hs_sts = HS_FAILED; #ifdef DEBUG_ENABLE goto __HS_CTS_I2C_ERROR; __HS_CTS_I2C_ERROR_END: __asm__("nop"); #endif } else { hs_sts = HS_MDR_MDR; } break; } case (HS_MDR_MDR): { MDR_buf = (uint8_t*)malloc(MDR_len); AF_error_counter = 0; while (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)i2c_addr, (uint8_t*)MDR_buf, MDR_len, 1000) != HAL_OK) { if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) { hs_sts = HS_FAILED; #ifdef DEBUG_ENABLE goto __HS_MDR_I2C_ERROR; __HS_MDR_I2C_ERROR_END: __asm__("nop"); #endif break; } else if (++AF_error_counter > 1500) { hs_sts = HS_FAILED; break; } } if (hs_sts != HS_FAILED) { #ifdef TESTING_ENABLE goto __HS_MDR_MDR_TESTING; __HS_MDR_MDR_TESTING_END: __asm__("nop"); #endif MDR_res_message.subscriptions.funcs.decode = decode_subscriptions_callback; MDR_res_message.subscriptions.arg = (void*)dev_idx; pb_istream_t MDR_res_stream = pb_istream_from_buffer(MDR_buf, MDR_len); if (!pb_decode(&MDR_res_stream, s2m_MDR_response_fields, &MDR_res_message)) { hs_sts = HS_FAILED; #ifdef DEBUG_ENABLE goto __HS_MDR_DEC_ERROR; __HS_MDR_DEC_ERROR_END: __asm__("nop"); #endif } else { #ifdef TESTING_ENABLE goto __MDR_DEC_TESTING; __MDR_DEC_TESTING_END: __asm__("nop"); #endif device_info[dev_idx] = malloc(sizeof(device_info_t)); device_info[dev_idx]->i2c_addr = i2c_addr; device_info[dev_idx]->device_id = dev_idx; device_info[dev_idx]->MDR = MDR_res_message; hs_sts = HS_REGISTERED; } } break; } } } #ifdef TESTING_ENABLE { goto __TESTING_BLOCK_END; __HS_MDR_MDR_TESTING: for (int x=0; xmodule_ids[1]); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); goto __MDR_DEC_TESTING_END; } __TESTING_BLOCK_END: __asm__("nop"); #endif #ifdef DEBUG_ENABLE { goto __DEBUG_BLOCK_END; __HS_MDR_REQ_I2C_ERROR: sprintf((char*)debug_buf, "Unable to send MDR request to %lx. I2C error: %ld\r\n", i2c_addr, HAL_I2C_GetError(&hi2c1)); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); goto __HS_MDR_REQ_I2C_ERROR_END; __HS_MDR_ACK_I2C_ERROR: sprintf((char*)debug_buf, "Unable to get MDR ACK. I2C error: %ld\r\n", HAL_I2C_GetError(&hi2c1)); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); goto __HS_MDR_ACK_I2C_ERROR_END; __HS_CTS_I2C_ERROR: sprintf((char*)debug_buf, "Unable to send MDR CTS. I2C error: %ld\r\n", HAL_I2C_GetError(&hi2c1)); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); goto __HS_CTS_I2C_ERROR_END; __HS_MDR_I2C_ERROR: sprintf((char*)debug_buf, "Unable to get MDR. I2C error: %ld\n\tError counter: %ld\r\n", HAL_I2C_GetError(&hi2c1), AF_error_counter); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); goto __HS_MDR_I2C_ERROR_END; __HS_MDR_DEC_ERROR: sprintf((char*)debug_buf, "MDR decode error\r\n"); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); goto __HS_MDR_DEC_ERROR_END; __DEBUG_BLOCK_END: __asm__("nop"); } #endif return hs_sts; } dataflow_status_t device_dataflow(uint8_t i2c_addr, uint32_t SOR_code, uint8_t rbuf_data_idx) { uint8_t dev_idx = GET_IDX_FROM_ADDR(i2c_addr); dataflow_status_t df_status = DF_IDLE; uint8_t DOC_buf[4]; uint8_t *data_buf; uint32_t AF_error_counter = 0; uint32_t data_len = 0; _datapoint datapoints[16]; /* TODO Add default values to the CTS message in proto */ s2m_data data_message = s2m_data_init_zero; #if defined(TESTING_ENABLE) || defined(DEBUG_ENABLE) uint8_t debug_buf[128]; #endif #ifdef TESTING_ENABLE uint8_t term[] = "\r\n"; #endif while (df_status != DF_SUCCESS && df_status != DF_FAIL) { switch (df_status) { case (DF_IDLE): { HAL_Delay(MASTER_I2C_BUS_INTERVAL); uint8_t SOR_buf[2] = {SOR_code, 0x0}; if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2c_addr, SOR_buf, 2, 500) != HAL_OK) { df_status = DF_FAIL; #ifdef DEBUG_ENABLE goto __DF_SOR_I2C_ERROR; __DF_SOR_I2C_ERROR_END: __asm__("nop"); #endif } else { if (SOR_code == SLAVE_TX) { df_status = DF_RX_DOC; } else if (SOR_code == SLAVE_RX_DATAPOINT) { /* TODO */ df_status = DF_LEN_TX; } else if (SOR_code == SLAVE_RX_COMMAND) { /* TODO */ } } break; } case (DF_RX_DOC): { HAL_Delay(MASTER_I2C_BUS_INTERVAL); AF_error_counter = 0; while (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)i2c_addr, (uint8_t*)DOC_buf, 4, 10000) != HAL_OK) { if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) { df_status = DF_FAIL; #ifdef DEBUG_ENABLE goto __DF_DOC_I2C_ERROR; __DF_DOC_I2C_ERROR_END: __asm__("nop"); #endif break; } else if (++AF_error_counter > 1500) { df_status = DF_FAIL; break; } } if (df_status != DF_FAIL) { if (DOC_buf[1] == DATA) { df_status = DF_CTS; data_len = DOC_buf[3]; } else if (DOC_buf[1] == CMD_UNICAST) { /* TODO */ } else if (DOC_buf[1] == CMD_MULTICAST) { /* TODO */ } else if (DOC_buf[1] == CMD_BROADCAST) { /* TODO */ } else { df_status = DF_FAIL; } } break; } case (DF_CTS): { HAL_Delay(MASTER_I2C_BUS_INTERVAL); uint8_t CTS_buf[2] = {0x2, 0xFF}; if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2c_addr, CTS_buf, 2, 10000) != HAL_OK) { df_status = DF_FAIL; #ifdef DEBUG_ENABLE goto __DF_CTS_I2C_ERROR; __DF_CTS_I2C_ERROR_END: __asm__("nop"); #endif } else { if (DOC_buf[1] == DATA) { df_status = DF_RX_DATA; } else { /* TODO RX CMD stuff */ } } break; } case (DF_RX_DATA): { HAL_Delay(MASTER_I2C_BUS_INTERVAL); sprintf((char*)debug_buf, "data len: %ld\r\n", data_len); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); data_buf = (uint8_t*)malloc(128); AF_error_counter = 0; while (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)i2c_addr, (uint8_t*)data_buf, data_len, 1000) != HAL_OK) { if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) { df_status = DF_FAIL; #ifdef DEBUG_ENABLE goto __DF_DATA_I2C_ERROR; __DF_DATA_I2C_ERROR_END: __asm__("nop"); #endif break; } else if (++AF_error_counter > 1500) { df_status = DF_FAIL; break; } } if (df_status != DF_FAIL) { data_idx = 0; data_message.datapoints.funcs.decode = decode_data_callback; data_message.datapoints.arg = (void*)datapoints; pb_istream_t data_istream = pb_istream_from_buffer(data_buf, data_len); if (!pb_decode(&data_istream, s2m_data_fields, &data_message)) { df_status = DF_FAIL; #ifdef DEBUG_ENABLE goto __DF_DATA_DECODE_ERROR; __DF_DATA_DECODE_ERROR_END: __asm__("nop"); #endif } else { /* This could be done in the callback itself */ for (int i = 0; i < data_idx && routing_ptr < ROUTING_BUFSIZE; i++) { routing_idx_buffer[routing_ptr] = dev_idx; routing_buffer[routing_ptr++] = datapoints[i]; } df_status = DF_SUCCESS; } } break; } case (DF_LEN_TX): { HAL_Delay(MASTER_I2C_BUS_INTERVAL); /* TODO error checking */ /* Will need to package datapoint and MDR to know their lengths Once cached, will not need to do this */ /* Do this after handshake to cache ================================================== */ uint8_t MDR_buf[128], data_buf[128], CTS_buf[2]; uint8_t src_device_idx = routing_idx_buffer[rbuf_data_idx]; s2m_MDR_response data_src_MDR = device_info[src_device_idx]->MDR; pb_ostream_t MDR_ostream = pb_ostream_from_buffer(MDR_buf, sizeof(MDR_buf)); data_src_MDR.subscriptions.funcs.encode=master_encode_MDR_callback; pb_encode(&MDR_ostream, s2m_MDR_response_fields, &data_src_MDR); uint8_t MDR_len = MDR_ostream.bytes_written; /* =================================================================================== */ _datapoint data = routing_buffer[rbuf_data_idx]; pb_ostream_t data_ostream = pb_ostream_from_buffer(data_buf, sizeof(data_buf)); pb_encode(&data_ostream, _datapoint_fields, &data); uint8_t data_len = data_ostream.bytes_written; uint8_t data_MDR_len_buf[4] = {0, MDR_len, 0, data_len}; AF_error_counter = 0; while (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)i2c_addr, CTS_buf, 2, 10000) != HAL_OK) { if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) { df_status = DF_FAIL; } if (++AF_error_counter > 3000) { df_status = DF_FAIL; } if (df_status == DF_FAIL) { sprintf((char*)debug_buf, "Failed to get LEN CTS\r\n"); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); break; } } HAL_Delay(MASTER_I2C_BUS_INTERVAL); if (df_status != DF_FAIL && HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2c_addr, data_MDR_len_buf, 4, 10000) == HAL_OK) { sprintf((char*)debug_buf, "MDR len: %d data len: %d SENT\r\n", MDR_len, data_len); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); } else { sprintf((char*)debug_buf, "Failed to send lengths\r\n"); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); } AF_error_counter = 0; while (df_status != DF_FAIL && HAL_I2C_Master_Receive(&hi2c1, (uint16_t)i2c_addr, CTS_buf, 2, 10000) != HAL_OK) { if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) { df_status = DF_FAIL; } if (++AF_error_counter > 3000) { df_status = DF_FAIL; } if (df_status == DF_FAIL) { sprintf((char*)debug_buf, "Failed to get TX CTS\r\n"); HAL_UART_Transmit(&huart1, debug_buf, sizeof(debug_buf), 100); memset(debug_buf, 0, 128); break; } } #ifdef TESTING_ENABLE uint8_t buf_title[64]; sprintf((char*)buf_title, "MDR buffer: "); HAL_UART_Transmit(&huart1, buf_title, sizeof(buf_title), 100); memset(buf_title, 0, 64); for(int x=0; xmod_idx && !alloc; dev_sub_idx++) { if (subs_info[dev_idx]->module_ids[dev_sub_idx] == device_info[src_module_idx]->MDR.module_id) { SET_BIT_FROM_IDX(routing_table[rbuf_data_idx], dev_idx); alloc = true; } } /* TODO entity ID, I2C addr and class routing, should go in the if condition above */ } } for (uint8_t rbuf_data_idx = 0; rbuf_data_idx < routing_ptr; rbuf_data_idx++) { for (uint8_t device_idx = 0; device_idx < BUS_DEVICE_LIMIT; device_idx++) { if (GET_BIT_FROM_IDX(allocated, device_idx) && GET_BIT_FROM_IDX(routing_table[rbuf_data_idx], device_idx)) { device_dataflow(GET_ADDR_FROM_IDX(device_idx), SLAVE_RX_DATAPOINT, rbuf_data_idx); } } } /* Reset the routing pointer, since all data in buffer should have been routed */ routing_ptr = 0; return true; } bool decode_subscriptions_callback(pb_istream_t *istream, const pb_field_t *field, void **args) { _subscriptions subs; int *subs_idx = (int*)args; /* Check is storage is allocated; if not, allocate it */ if ((GET_BIT_FROM_IDX(allocated, *subs_idx)) == 0) { subs_info[*subs_idx] = (subscription_info_t*)malloc(sizeof(subscription_info_t)); SET_BIT_FROM_IDX(allocated, *subs_idx); subs_info[*subs_idx]->mod_idx = subs_info[*subs_idx]->entity_idx = subs_info[*subs_idx]->class_idx = subs_info[*subs_idx]->i2c_idx = 0; } if(!pb_decode(istream, _subscriptions_fields, &subs)) return false; /* Parse all fields if they're included */ if (subs.has_module_id) subs_info[*subs_idx]->module_ids[subs_info[*subs_idx]->mod_idx++] = subs.module_id; if (subs.has_entity_id) subs_info[*subs_idx]->entity_ids[subs_info[*subs_idx]->entity_idx++] = subs.entity_id; if (subs.has_module_class) subs_info[*subs_idx]->module_class[subs_info[*subs_idx]->class_idx++] = subs.module_class; if (subs.has_i2c_address) subs_info[*subs_idx]->i2c_address[subs_info[*subs_idx]->i2c_idx++] = subs.i2c_address; return true; } bool todo_hs_or_not_todo_hs(uint8_t i2c_addr) { uint8_t device_idx = GET_IDX_FROM_ADDR(i2c_addr); state_t device_curr_state = dev_sts[device_idx]; bool do_hs = false; switch(device_curr_state) { case NO_HS: case CONNECTED: case FAILED: case OFFLINE: do_hs = true; break; case REGISTERED: case NO_DATA: do_hs = false; break; } return do_hs; } state_t get_state_from_hs_status(uint16_t device_addr, hs_status_t hs_status) { state_t device_state = OFFLINE; switch(hs_status) { case IDLE: case HS_FAILED: device_state = OFFLINE; break; case HS_MDR_ACK: case HS_MDR_CTS: case HS_MDR_MDR: device_state = FAILED; break; case HS_REGISTERED: device_state = REGISTERED; break; } return device_state; } bool master_encode_MDR_callback(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg) { if (!pb_encode_tag_for_field(ostream, field)) { return false; } return true; } bool encode_subscription_callback(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg) { if(ostream!=NULL && field->tag == s2m_MDR_response_subscriptions_tag) { for (int x=0; x<2; x++) { _subscriptions subs; subs.module_id = x+10*x; subs.i2c_address = x+1; subs.has_entity_id=false; subs.has_module_class=false; subs.has_module_id=true; subs.has_i2c_address=true; if(!pb_encode_tag_for_field(ostream, field)){ printf("ERR1\n"); return false; } if(!pb_encode_submessage(ostream, _subscriptions_fields, &subs)){ printf("ERR2\n"); return false; } } } else{ return false; } return true; } bool encode_datapoint_callback(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg) { if (ostream != NULL && field->tag == s2m_data_datapoints_tag) { for (int i = 0; i < 4; i++) { _datapoint datapoint = _datapoint_init_zero; datapoint.entity_id = 1; datapoint.data = 20.70+((float)i/100); if (!pb_encode_tag_for_field(ostream, field)) return false; if (!pb_encode_submessage(ostream, _datapoint_fields, &datapoint)) return false; } } else return false; return true; } bool decode_data_callback(pb_istream_t *istream, const pb_field_t *field, void **args) { _datapoint loc_datapoint = _datapoint_init_zero; _datapoint *datapoint = *args; if (!pb_decode(istream, _datapoint_fields, &loc_datapoint)) return false; datapoint[data_idx].data = datapoint[data_idx].entity_id = 0; datapoint[data_idx].entity_id = loc_datapoint.entity_id; datapoint[data_idx].data = loc_datapoint.data; if (loc_datapoint.has_channel_id) { datapoint[data_idx].has_channel_id = true; datapoint[data_idx].channel_id = loc_datapoint.channel_id; } if (loc_datapoint.has_unit_id) { datapoint[data_idx].has_unit_id = true; datapoint[data_idx].unit_id = loc_datapoint.unit_id; } if (loc_datapoint.has_timestamp) { datapoint[data_idx].has_timestamp = true; datapoint[data_idx].timestamp = loc_datapoint.timestamp; } data_idx++; return true; } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } /** * @brief I2C1 Initialization Function * @param None * @retval None */ static void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0xFF; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; /* hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE; */ if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } } /** * @brief USART1 Initialization Function * @param None * @retval None */ static void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : led_Pin */ GPIO_InitStruct.Pin = led_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(led_GPIO_Port, &GPIO_InitStruct); } /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while (1) { HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin); HAL_Delay(1000); } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ // Macro to use CCM (Core Coupled Memory) in STM32F4 #define CCM_RAM __attribute__((section(".ccmram"))) #define FPU_TASK_STACK_SIZE 256 StackType_t fpuTaskStack[FPU_TASK_STACK_SIZE] CCM_RAM; // Put task stack in CCM StaticTask_t fpuTaskBuffer CCM_RAM; // Put TCB in CCM void vApplicationTickHook(void) { } /* vApplicationMallocFailedHook() will only be called if configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook function that will get called if a call to pvPortMalloc() fails. pvPortMalloc() is called internally by the kernel whenever a task, queue, timer or semaphore is created. It is also called by various parts of the demo application. If heap_1.c or heap_2.c are used, then the size of the heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used to query the size of free heap space that remains (although it does not provide information on how the remaining heap might be fragmented). */ void vApplicationMallocFailedHook(void) { taskDISABLE_INTERRUPTS(); for(;;); } /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle task. It is essential that code added to this hook function never attempts to block in any way (for example, call xQueueReceive() with a block time specified, or call vTaskDelay()). If the application makes use of the vTaskDelete() API function (as this demo application does) then it is also important that vApplicationIdleHook() is permitted to return to its calling function, because it is the responsibility of the idle task to clean up memory allocated by the kernel to any task that has since been deleted. */ void vApplicationIdleHook(void) { } void vApplicationStackOverflowHook(xTaskHandle pxTask, signed char *pcTaskName) { (void) pcTaskName; (void) pxTask; /* Run time stack overflow checking is performed if configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is called if a stack overflow is detected. */ taskDISABLE_INTERRUPTS(); for(;;); } StaticTask_t xIdleTaskTCB CCM_RAM; StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE] CCM_RAM; /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an implementation of vApplicationGetIdleTaskMemory() to provide the memory that is used by the Idle task. */ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { /* Pass out a pointer to the StaticTask_t structure in which the Idle task's state will be stored. */ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; /* Pass out the array that will be used as the Idle task's stack. */ *ppxIdleTaskStackBuffer = uxIdleTaskStack; /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. Note that, as the array is necessarily of type StackType_t, configMINIMAL_STACK_SIZE is specified in words, not bytes. */ *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; } static StaticTask_t xTimerTaskTCB CCM_RAM; static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH] CCM_RAM; /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the application must provide an implementation of vApplicationGetTimerTaskMemory() to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; *ppxTimerTaskStackBuffer = uxTimerTaskStack; *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; }