ver:init
Diff: source/bluenrg-hci/hci/controller/bluenrg_utils.c
- Revision:
- 0:88b85febcb45
diff -r 000000000000 -r 88b85febcb45 source/bluenrg-hci/hci/controller/bluenrg_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/bluenrg-hci/hci/controller/bluenrg_utils.c Sun Jun 18 16:10:28 2017 +0000 @@ -0,0 +1,430 @@ + +#include "ble_hal.h" +#include "ble_hal_types.h" +#include "ble_status.h" +#include "bluenrg_aci.h" +#include "bluenrg_utils.h" +#include "ble_hci.h" +#include "ble_osal.h" +#include "string.h" +#include "stm32_bluenrg_ble.h" + +#define SUPPORTED_BOOTLOADER_VERSION_MIN 3 +#define SUPPORTED_BOOTLOADER_VERSION_MAX 5 + +#define BASE_ADDRESS 0x10010000 + +#define FW_OFFSET (2*1024) // 2 KB +#define FW_OFFSET_MS 0 +#define FULL_STACK_SIZE (66*1024) // 66 KB +#define BOOTLOADER_SIZE (2*1024) // 2 kB +#define SECTOR_SIZE (2*1024) // 2 KB +#define DATA_SIZE 64 // 64 bytes + +// x**32 + x**26 + x**23 + x ** 22 + x**16 + x**12 + x**11 + +// x**10 + x**8 + x**7 + x**5 + x**4 + x**2 + x**1 + x**0 +#define CRC_POLY 0x04C11DB7 // the poly without the x**32 + +#define BOOTLOADER_CRC_NOT_PATCHED 0x878FB3FC + +#define IFR_SIZE 192 +#define IFR_BASE_ADDRESS 0x10020000 +#define IFR_CONFIG_DATA_OFFSET (SECTOR_SIZE-IFR_SIZE) // Offset in IFR sector containing configuration data + +#if BLUENRG_MS +#define IFR_WRITE_OFFSET_BEGIN IFR_CONFIG_DATA_OFFSET +#else +#define IFR_WRITE_OFFSET_BEGIN 0 +#endif + + +#define BLUE_FLAG_OFFSET 0x8C0 +#define MAX_ERASE_RETRIES 2 +#define MAX_WRITE_RETRIES 2 +#define MIN_WRITE_BLOCK_SIZE 4 + +#define RETRY_COMMAND(func, num_ret, error) \ +{ \ + uint8_t num_retries; \ + num_retries = 0; \ + error = 0; \ + while (num_retries++ < num_ret) { \ + if (func == BLE_STATUS_SUCCESS) \ + break; \ + if (num_retries == num_ret) \ + error = BLE_UTIL_ACI_ERROR; \ + } \ +} + +typedef struct{ + uint8_t cold_ana_act_config_table[64]; +}cold_table_TypeDef; + +/* This function calculates the CRC of a sector of flash, if bytes passed are less than sector size, + they are extended with 0xFF until sector size is reached +*/ +static uint32_t updater_calc_crc(const uint8_t* data, uint16_t nr_of_bytes) +{ + uint32_t i, j, a1; + uint32_t crc, value; + + crc = 0; + for (i = 0; i < SECTOR_SIZE; i += 4) { + uint8_t *dataw = (uint8_t *) &value; + + dataw[0] = (i < nr_of_bytes) ? data[i] : 0xFF; + dataw[1] = ((i + 1) < nr_of_bytes) ? data[i+1] : 0xFF; + dataw[2] = ((i + 2) < nr_of_bytes) ? data[i+2] : 0xFF; + dataw[3] = ((i + 3) < nr_of_bytes) ? data[i+3] : 0xFF; + + crc = crc ^ value; + for (j = 0; j < 32; j ++) { + a1 = (crc >> 31) & 0x1; + crc = (crc << 1) ^ (a1 * CRC_POLY); + } + } + + return crc; +} + +int program_device(const uint8_t *fw_image, uint32_t fw_size) +{ + uint8_t version, num_erase_retries=0, status, data_size; + uint8_t number_sectors, module; + uint32_t address, j; + uint32_t crc, crc2, crc_size; + uint32_t fw_offset = FW_OFFSET; + + BlueNRG_HW_Bootloader(); + HCI_Process(); // To receive the EVT_INITIALIZED + + if(aci_get_updater_version(&version)) + return BLE_UTIL_ACI_ERROR; + + if(version < SUPPORTED_BOOTLOADER_VERSION_MIN || version > SUPPORTED_BOOTLOADER_VERSION_MAX) + return BLE_UTIL_UNSUPPORTED_VERSION; + + if(aci_updater_hw_version(&version)) + return BLE_UTIL_ACI_ERROR; + + if(version==0x31){ + // It does not contain bootloader inside first sector. It may contain code. + fw_offset = FW_OFFSET_MS; + } + + if (fw_size != FULL_STACK_SIZE) + return BLE_UTIL_WRONG_IMAGE_SIZE; + + if (fw_size % MIN_WRITE_BLOCK_SIZE) + return BLE_UTIL_WRONG_IMAGE_SIZE; + + /* Calculate the number of sectors necessary to contain the fw image.*/ + number_sectors = ((fw_size + SECTOR_SIZE - 1) / SECTOR_SIZE); + + /*********************************************************************** + * Erase BLUE flag + ************************************************************************/ + RETRY_COMMAND(aci_erase_blue_flag(), MAX_WRITE_RETRIES, status); + if (status != BLE_STATUS_SUCCESS) + return status; + + /*********************************************************************** + * Erase and Program sectors + ************************************************************************/ + for(unsigned int i = fw_offset; i < (number_sectors * SECTOR_SIZE); i += SECTOR_SIZE) { + num_erase_retries = 0; + while (num_erase_retries++ < MAX_ERASE_RETRIES) { + aci_updater_erase_sector(BASE_ADDRESS + i); + if ((i/SECTOR_SIZE) < (unsigned int)(number_sectors-1)) + data_size = DATA_SIZE; + else + data_size = MIN_WRITE_BLOCK_SIZE; + for (j=i; ((j<SECTOR_SIZE+i)&&(j<fw_size)); j += data_size) { + RETRY_COMMAND(aci_updater_program_data_block(BASE_ADDRESS+j, data_size, fw_image+j), MAX_WRITE_RETRIES, status); + if (status != BLE_STATUS_SUCCESS) + break; + } + if (status == BLE_STATUS_SUCCESS) + break; + } + if (num_erase_retries == MAX_ERASE_RETRIES) + return BLE_UTIL_ACI_ERROR; + } + + /*********************************************************************** + * Verify firmware + ************************************************************************/ + module = fw_size % SECTOR_SIZE; + crc_size = SECTOR_SIZE; + for(int i = fw_offset; i < (number_sectors*SECTOR_SIZE); i += SECTOR_SIZE){ + address = BASE_ADDRESS + i; + if(aci_updater_calc_crc(address, 1, &crc)) + return BLE_UTIL_ACI_ERROR; + + if ((module != 0) && ((i/SECTOR_SIZE) == (number_sectors-1))) + crc_size = module; + + crc2 = updater_calc_crc(fw_image+i,crc_size); + if(crc!=crc2) + return BLE_UTIL_CRC_ERROR; + } + + /*********************************************************************** + * Write BLUE flag + ************************************************************************/ + RETRY_COMMAND(aci_reset_blue_flag(), MAX_WRITE_RETRIES, status); + if (status != BLE_STATUS_SUCCESS) + return status; + + BlueNRG_RST(); + HCI_Process(); // To receive the EVT_INITIALIZED + + return BLE_STATUS_SUCCESS; +} + +int read_IFR(uint8_t *data) +{ + uint8_t version, offset; + tBleStatus ret; + + offset = 0; + aci_updater_start(); + if(aci_get_updater_version(&version)) + return BLE_UTIL_ACI_ERROR; + + if(version < SUPPORTED_BOOTLOADER_VERSION_MIN || version > SUPPORTED_BOOTLOADER_VERSION_MAX) + return BLE_UTIL_UNSUPPORTED_VERSION; + + /*********************************************************************** + * Reading last 3 IFR 64-byte blocks + ************************************************************************/ + for(int i = (FULL_STACK_SIZE - IFR_SIZE); i < FULL_STACK_SIZE; i += DATA_SIZE){ + ret = aci_updater_read_data_block(BASE_ADDRESS+i, DATA_SIZE, (data+offset)); + offset += DATA_SIZE; + if(ret) return BLE_UTIL_ACI_ERROR; + } + + BlueNRG_RST(); + HCI_Process(); // To receive the EVT_INITIALIZED + + return BLE_STATUS_SUCCESS; + +} + +void parse_IFR_data_config(const uint8_t data[64], IFR_config2_TypeDef *IFR_config) +{ + IFR_config->stack_mode = data[0]; + IFR_config->slave_sca_ppm = LE_TO_HOST_16(data+28); + IFR_config->master_sca = data[30]; + IFR_config->hs_startup_time = LE_TO_HOST_16(data+32); + IFR_config->year = BCD_TO_INT(data[41]); + IFR_config->month = BCD_TO_INT(data[42]); + IFR_config->day = BCD_TO_INT(data[43]); +} + +int IFR_validate(IFR_config2_TypeDef *IFR_config) +{ +#if BLUENRG_MS + if(IFR_config->stack_mode < 1 || IFR_config->stack_mode > 4) +#else + if(IFR_config->stack_mode < 1 || IFR_config->stack_mode > 3) +#endif + return BLE_UTIL_PARSE_ERROR; // Unknown Stack Mode + if(IFR_config->master_sca > 7) + return BLE_UTIL_PARSE_ERROR; // Invalid Master SCA + if(IFR_config->month > 12 || IFR_config->month < 1) + return BLE_UTIL_PARSE_ERROR; // Invalid date + if(IFR_config->day > 31 || IFR_config->day < 1) + return BLE_UTIL_PARSE_ERROR; // Invalid date + if(IFR_config->month > 12 || IFR_config->month < 1) + return BLE_UTIL_PARSE_ERROR; // Invalid date + + return BLE_STATUS_SUCCESS; +} + +/* TODO: Function to generate data from given options. */ + +void change_IFR_data_config(IFR_config2_TypeDef *IFR_config, uint8_t data[64]) +{ + data[0] = IFR_config->stack_mode; + HOST_TO_LE_16(data+28, IFR_config->slave_sca_ppm); + data[30] = IFR_config->master_sca; + HOST_TO_LE_16(data+32, IFR_config->hs_startup_time); + data[41] = INT_TO_BCD(IFR_config->year); + data[42] = INT_TO_BCD(IFR_config->month); + data[43] = INT_TO_BCD(IFR_config->day); +} + + +int program_IFR(const IFR_config_TypeDef *ifr_image) +{ + uint8_t version, num_erase_retries; + tBleStatus ret; +#if BLUENRG_MS + const uint8_t *ifr_data = (uint8_t *)ifr_image; +#else + uint8_t ifr_data[SECTOR_SIZE]; +#endif + uint8_t hwVersion; + uint16_t fwVersion; + + if(getBlueNRGVersion(&hwVersion, &fwVersion)) + return BLE_UTIL_ACI_ERROR; + + BlueNRG_HW_Bootloader(); + HCI_Process(); // To receive the EVT_INITIALIZED + + if(aci_get_updater_version(&version)) + return BLE_UTIL_ACI_ERROR; + + if(version < SUPPORTED_BOOTLOADER_VERSION_MIN || version > SUPPORTED_BOOTLOADER_VERSION_MAX) + return BLE_UTIL_UNSUPPORTED_VERSION; + +#ifndef BLUENRG_MS + /*********************************************************************** + * READ IFR data + ************************************************************************/ + for(int i = 0; i < SECTOR_SIZE; i += DATA_SIZE){ + ret = aci_updater_read_data_block(IFR_BASE_ADDRESS+i, DATA_SIZE, ifr_data+i); + if(ret != BLE_STATUS_SUCCESS){ + return ret; + } + } +#endif + + /*********************************************************************** + * Erase & Flashing IFR sectors + ************************************************************************/ +#ifndef BLUENRG_MS + Osal_MemCpy(&ifr_data[SECTOR_SIZE-IFR_SIZE], ifr_image, IFR_SIZE); +#endif + num_erase_retries = 0; + while (num_erase_retries++ < MAX_ERASE_RETRIES) { + aci_updater_erase_sector(IFR_BASE_ADDRESS); + for(int i = IFR_WRITE_OFFSET_BEGIN, j = 0; i < SECTOR_SIZE; i += DATA_SIZE, j += DATA_SIZE) { + RETRY_COMMAND(aci_updater_program_data_block(IFR_BASE_ADDRESS+i, DATA_SIZE, ifr_data+j), MAX_WRITE_RETRIES, ret); + if (ret != BLE_STATUS_SUCCESS) + break; + } + if (ret == BLE_STATUS_SUCCESS) + break; + } + if (num_erase_retries == MAX_ERASE_RETRIES) + return BLE_UTIL_ACI_ERROR; + + /*********************************************************************** + * Verify IFR + ************************************************************************/ + { + uint8_t ifr_updated[DATA_SIZE]; + for(int i = IFR_WRITE_OFFSET_BEGIN, j = 0; i < SECTOR_SIZE; i += DATA_SIZE, j += DATA_SIZE){ + ret = aci_updater_read_data_block(IFR_BASE_ADDRESS+i, DATA_SIZE, ifr_updated); + if(ret != BLE_STATUS_SUCCESS){ + return ret; + } + if (memcmp(ifr_updated, ifr_data+j, DATA_SIZE) != 0) + return BLE_UTIL_WRONG_VERIFY; + } + } + + BlueNRG_RST(); + HCI_Process(); // To receive the EVT_INITIALIZED + + return BLE_STATUS_SUCCESS; +} + +uint8_t verify_IFR(const IFR_config_TypeDef *ifr_data) +{ + uint8_t ifr_updated[DATA_SIZE]; + uint8_t version, ret = BLE_STATUS_SUCCESS; + + aci_updater_start(); + if(aci_get_updater_version(&version)) + return BLE_UTIL_ACI_ERROR; + for(int i = 0; i < IFR_SIZE; i += DATA_SIZE){ + ret = aci_updater_read_data_block((IFR_BASE_ADDRESS+SECTOR_SIZE-IFR_SIZE)+i, DATA_SIZE, ifr_updated); + if(ret != BLE_STATUS_SUCCESS){ + return ret; + } + if (memcmp(ifr_updated, ((uint8_t*)ifr_data)+i, DATA_SIZE) != 0) + { + ret = BLE_UTIL_WRONG_VERIFY; + break; + } + } + + BlueNRG_RST(); + HCI_Process(); // To receive the EVT_INITIALIZED + + return ret; +} + +uint8_t getBlueNRGVersion(uint8_t *hwVersion, uint16_t *fwVersion) +{ + uint8_t status; + uint8_t hci_version, lmp_pal_version; + uint16_t hci_revision, manufacturer_name, lmp_pal_subversion; + + status = hci_le_read_local_version(&hci_version, &hci_revision, &lmp_pal_version, + &manufacturer_name, &lmp_pal_subversion); + + if (status == BLE_STATUS_SUCCESS) { + *hwVersion = hci_revision >> 8; + *fwVersion = (hci_revision & 0xFF) << 8; // Major Version Number + *fwVersion |= ((lmp_pal_subversion >> 4) & 0xF) << 4; // Minor Version Number + *fwVersion |= lmp_pal_subversion & 0xF; // Patch Version Number + } + + return status; +} + +uint8_t getBlueNRGUpdaterVersion(uint8_t *version) +{ + + BlueNRG_HW_Bootloader(); + HCI_Process(); // To receive the EVT_INITIALIZED + + if(aci_get_updater_version(version)) + return BLE_UTIL_ACI_ERROR; + + if(*version < SUPPORTED_BOOTLOADER_VERSION_MIN || *version > SUPPORTED_BOOTLOADER_VERSION_MAX) + return BLE_UTIL_UNSUPPORTED_VERSION; + + BlueNRG_RST(); + HCI_Process(); // To receive the EVT_INITIALIZED + + return BLE_STATUS_SUCCESS; +} + +uint8_t getBlueNRGUpdaterHWVersion(uint8_t *version) +{ + + BlueNRG_HW_Bootloader(); + HCI_Process(); // To receive the EVT_INITIALIZED + + if(aci_updater_hw_version(version)) + return BLE_UTIL_ACI_ERROR; + + BlueNRG_RST(); + HCI_Process(); // To receive the EVT_INITIALIZED + + return BLE_STATUS_SUCCESS; +} + +uint8_t isHWBootloader_Patched(void) +{ + uint8_t status, version; + uint32_t crc, address = 0x10010000; + + if(aci_get_updater_version(&version)) + return BLE_UTIL_ACI_ERROR; + + RETRY_COMMAND(aci_updater_calc_crc(address, 1, &crc), 2, status); + if (status != BLE_STATUS_SUCCESS) + return 0; + + if (crc == BOOTLOADER_CRC_NOT_PATCHED) + return 0; + + return 1; +}