my fork

Dependencies:   mbed

src/bluenrg_utils.c

Committer:
filartrix
Date:
2015-04-08
Revision:
4:987b201ec4b1

File content as of revision 4:987b201ec4b1:


#include "hal.h"
#include "hal_types.h"
#include "ble_status.h"
#include "bluenrg_aci.h"
#include "bluenrg_utils.h"
#include "hci.h"
#include "osal.h"
#include "string.h"
//#include "SDK_EVAL_Spi_Driver.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 FULL_STACK_SIZE (66*1024) // 66 KB
#define BOOTLOADER_SIZE (2*1024)  // 2 kB
#define DATA_SIZE       64        // 64 bytes
#define SECTOR_SIZE     (2*1024)  // 2 KB

// 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 IFR_SIZE 192
#define IFR_BASE_ADDRESS 0x10020000

typedef struct{
  uint8_t cold_ana_act_config_table[64];
}cold_table_TypeDef;

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 < nr_of_bytes; i += 4) {
      value = data[i]|((uint32_t)data[i+1]<<8)|((uint32_t)data[i+2]<<16)|((uint32_t)data[i+3]<<24);
      
        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 skip_bootloader_verif)
{
  uint8_t version;
  uint8_t verify_from_sector = 0;
  uint8_t number_sectors;
  uint8_t last_sector[SECTOR_SIZE];
  const uint8_t *last_image, *addr_image;
  uint16_t last_size;
  uint32_t address;
  uint32_t crc, crc2;
  tBleStatus ret;  
  
  BlueNRG_HW_Bootloader();
  HCI_Process();

  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(skip_bootloader_verif){
    verify_from_sector = 1;
  }

  if (fw_size > FULL_STACK_SIZE)
    return BLE_UTIL_WRONG_IMAGE_SIZE;

  /***********************************************************************
  * Erase BLUE flag
  ************************************************************************/
  
  if(aci_erase_blue_flag()) 
    return BLE_UTIL_ACI_ERROR;
  
  /***********************************************************************
  * Erase sectors
  ************************************************************************/  
  
  for(int i = FW_OFFSET; i < FULL_STACK_SIZE; i += SECTOR_SIZE){
    ret = aci_updater_erase_sector(BASE_ADDRESS + i);
    if(ret) return BLE_UTIL_ACI_ERROR;
    HCI_Process();
  }
  
  /***********************************************************************
  * Flashing firmware
  ************************************************************************/

  /* Calculate the number of sectors necessary to contain the fw image.
     If the fw image is the bootloader we need to add a sector because 
     the flashing start with an offset of 2 KB 
  */
  number_sectors = (fw_size / SECTOR_SIZE);
  if (skip_bootloader_verif)
    number_sectors++;

  for(int i = FW_OFFSET; i < (number_sectors*SECTOR_SIZE); i += DATA_SIZE){
    /* If bootloader image we need to subtract the 2KB offset */
    if (skip_bootloader_verif)
      addr_image = fw_image + i - FW_OFFSET;
    else
      addr_image = fw_image + i;
    ret = aci_updater_program_data_block(BASE_ADDRESS+i, DATA_SIZE, addr_image);
    if(ret) return BLE_UTIL_ACI_ERROR;
    HCI_Process();
  }
  
  /* If the image is not multiple of a sector size */
  if (fw_size % SECTOR_SIZE) {
    /* If bootloader image we need to subtract the 2KB offset */
    if (skip_bootloader_verif) {
      last_image = fw_image + (number_sectors-1) * SECTOR_SIZE;
      last_size = fw_size -(number_sectors-1) * SECTOR_SIZE;
    } else {
      last_image = fw_image + number_sectors * SECTOR_SIZE;
      last_size = fw_size - number_sectors * SECTOR_SIZE;
    }
    memset(last_sector, 0xFF, SECTOR_SIZE);
    memcpy (last_sector, last_image, last_size);
    address = BASE_ADDRESS + (number_sectors * SECTOR_SIZE);
    for(int i = 0; i < SECTOR_SIZE; i += DATA_SIZE){
      ret = aci_updater_program_data_block(address+i, DATA_SIZE, last_sector+i);
      if(ret) return BLE_UTIL_ACI_ERROR;
      HCI_Process();
    }
  }

  /***********************************************************************
  * Verify firmware
  ************************************************************************/
  
  for(int i = (verify_from_sector*SECTOR_SIZE); 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 bootloader image we need to subtract the 2KB offset */
    if (skip_bootloader_verif) {
      crc2 = updater_calc_crc(fw_image+i-FW_OFFSET,SECTOR_SIZE);
    } else {
      crc2 = updater_calc_crc(fw_image+i,SECTOR_SIZE);
    }
    
    if(crc!=crc2)
      return BLE_UTIL_CRC_ERROR;

    HCI_Process();
  }

  /* If the image is not multiple of a sector size */
  if (fw_size % SECTOR_SIZE) {
    address = BASE_ADDRESS + (number_sectors*SECTOR_SIZE);
    if(aci_updater_calc_crc(address, 1, &crc))
      return BLE_UTIL_ACI_ERROR;
    
    crc2 = updater_calc_crc(last_sector,SECTOR_SIZE);
    
    if(crc!=crc2)
      return BLE_UTIL_CRC_ERROR;

    HCI_Process();

  }    
  
  if(aci_reset_blue_flag())
    return BLE_UTIL_ACI_ERROR;
  
  BlueNRG_RST();
  
  HCI_Process();

  return 0;
}

int read_IFR(uint8_t *data)
{
  uint8_t version;
  tBleStatus ret;
  
  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 = 66*1024 - 3*64; i < 66*1024; i += 64){
    ret = aci_updater_read_data_block(BASE_ADDRESS+i, 64, data);
    if(ret) return BLE_UTIL_ACI_ERROR;
  }
  
  BlueNRG_RST();

  return 0;
  
}

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(IFR_config->stack_mode < 1 || IFR_config->stack_mode > 3)
    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 0;
}

/* 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;
  tBleStatus ret;  
  uint8_t ifr_data[2*1024];
  
  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;
  
  /***********************************************************************
   * READ IFR data
   ************************************************************************/  
  for(int i = 0; i < (2*1024); i += 64){
    ret = aci_updater_read_data_block(IFR_BASE_ADDRESS+i, 64, ifr_data+i);
    if(ret != BLE_STATUS_SUCCESS){
      return ret;
    }
  }
  
  /***********************************************************************
  * Erase IFR sectors
  ************************************************************************/  
  ret = aci_updater_erase_sector(IFR_BASE_ADDRESS);
  if(ret != BLE_STATUS_SUCCESS) 
    return BLE_UTIL_ACI_ERROR;
  
  /***********************************************************************
  * Flashing IFR
  ************************************************************************/
  Osal_MemCpy(&ifr_data[2*1024-IFR_SIZE], ifr_image, IFR_SIZE);
  for(int i = 0; i < (2*1024); i += 64){
    ret = aci_updater_program_data_block(IFR_BASE_ADDRESS+i, 64, ifr_data+i);
    if(ret != BLE_STATUS_SUCCESS) 
      return BLE_UTIL_ACI_ERROR;
  }

  /***********************************************************************
  * Verify IFR
  ************************************************************************/  
  {
    uint8_t ifr_updated[64];
    for(int i = 0; i < (2*1024); i += 64){
      ret = aci_updater_read_data_block(IFR_BASE_ADDRESS+i, 64, ifr_updated);
      if(ret != BLE_STATUS_SUCCESS){
	return ret;
      }
      if (memcmp(ifr_updated, ifr_data+i, 64) != 0)
	return BLE_UTIL_WRONG_VERIFY;
    }
  }

  BlueNRG_RST();
    
  return 0;
}

uint8_t verify_IFR(const IFR_config_TypeDef *ifr_data)
{
  uint8_t ifr_updated[64];
  uint8_t version, ret;
    
  aci_updater_start();
  if(aci_get_updater_version(&version))
    return BLE_UTIL_ACI_ERROR;
  for(int i = 0; i < (3*64); i += 64){
    ret = aci_updater_read_data_block((IFR_BASE_ADDRESS+2048-IFR_SIZE)+i, 64, ifr_updated);
    if(ret != BLE_STATUS_SUCCESS){
      return ret;
    }
    if (memcmp(ifr_updated, ((uint8_t*)ifr_data)+i, 64) != 0)
      return BLE_UTIL_WRONG_VERIFY;
  }

  BlueNRG_RST();
  
  return 0;
}

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
  }

  HCI_Process();

  return status;
}

uint8_t getBlueNRGUpdaterVersion(uint8_t *version)
{
  HCI_Process();

  BlueNRG_HW_Bootloader();

  HCI_Process();

  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();

  return BLE_STATUS_SUCCESS;
}