CC254x HID Project – Name changing feature added

After many weeks working on this particular feature, I have finally succeeded. Strangely enough, the solution is so simple, making all the other ways I have thought of seems dumb and unnecessary.

The name is stored in CC2540/1’s non-volatile (NV) memory. Along with the name, its CRC checksum and length are stored in separate NV memory slots as well. Upon start-up, the name and its CRC value is retrieved from the NV memory. A new CRC value is generated from the stored name and compared with the stored CRC value. If the two CRC values matches, the device will go on and set this stored name as the scan response data string and the device’s name. Otherwise, it will use the default names.

Before today, I have been trying the idea of dynamically allocating an array and filling it with appropriate elements to make up a new scan response. This approach has been fruitless. Then I realized, why not use the static scan response variable that is going to be available every time the device starts up and modify its elements instead. This new approach works flawlessly (after only a few tests).

The code should be pushed and available on Git (one of those repositories) soon enough. However, for future debugging, these are the relevant sections to this feature:

0. Local variables and constants

#define SNV_ID_DEVICE_NAME              0x80
#define SNV_ID_DEVICE_NAME_LENGTH       0x81
#define SNV_ID_DEVICE_NAME_CRC          0x82

uint8 *device_name_crc;
uint8 *device_name;
uint8 *device_name_length;
    
// GAP Profile - Name attribute for SCAN RSP data - Name shown up when scanned
static uint8 default_scanData[] =
{
  0x15,                             // length of this data => (name's size = 20 bytes) + 1
  GAP_ADTYPE_LOCAL_NAME_COMPLETE,   // AD Type = Complete local name
  'H',
  'I',
  'D',
  ' ',
  'K',
  'e',
  'y',
  'b',
  'o',
  'a',
  'r',
  'd',
  ' ',
  '&',
  ' ',
  'M',
  'o',
  'u',
  's',
  'e'
};

1. Local functions

//Pololu's CRC functions with minimal changes
uint8 CRCPoly = 0x89;  // the value of our CRC-7 polynomial
uint8 CRCTable[256];

void GenerateCRCTable()
{
    int i, j;
 
    // generate a table value for all 256 possible byte values
    for (i = 0; i < 256; i++)
    {
        CRCTable[i] = (i & 0x80) ? i ^ CRCPoly : i;
        for (j = 1; j < 8; j++)
        {
            CRCTable[i] <<= 1;
            if (CRCTable[i] & 0x80)
                CRCTable[i] ^= CRCPoly;
        }
    }
}
 
 
// adds a message byte to the current CRC-7 to get a the new CRC-7
uint8 CRCAdd(uint8 CRC, uint8 message_byte)
{
    return CRCTable[(CRC << 1) ^ message_byte];
}
 
 
// returns the CRC-7 for a message of "length" bytes
uint8 getCRC(uint8 message[], uint8 length)
{
    uint8 i;
    uint8 CRC = 0;
 
    for (i = 0; i < length; i++)
        CRC = CRCAdd(CRC, message[i]);
 
    return CRC;
}

3. Initialization in hidKbdMouse.c

void HidKbdMouse_Init( uint8 task_id )
{
  setupUART();
  GenerateCRCTable();
//......

4. Name checking during initlization

//about line 354 in source code
if(*device_name_crc != getCRC(device_name, *device_name_length)) {
      printf("Using default scan response name\r\n");
      GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( default_scanData ), default_scanData );
    } else {      
      //make changes directly to the default_scanData. Since this variable is set at start-up, it should not matter
      uint8 len = *device_name_length;
      uint8 default_name_length = default_scanData[0];
      default_scanData[0] = len + 1;
      uint8 i;
      for(i = 0; i < len; i++) {
        default_scanData[i+2] = device_name[i];
      }      
      GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( default_scanData ), default_scanData );
    }

//...
//about line 377 in source code
 if(*device_name_crc != getCRC(device_name, *device_name_length)) {
    GGS_SetParameter( GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, (void *) attDeviceName );
  } else {
    GGS_SetParameter( GGS_DEVICE_NAME_ATT, *device_name_length + 1, (void *) device_name );
  }

5. UART name changing section

//...
else if((rxBuffer[1] == 'N') && (rxBuffer[2] == ',')) {
      uint8 i;
      uint8 deviceNewName[20];
      uint8 deviceNewNameLength;
      uint8 deviceNewNameCRC;
      
      deviceNewNameLength = rxBufferIndex-3;
      if(deviceNewNameLength > 20) {
        printf("Name exceeds permitted length\r\n");
      } else {
        for(i = 3; i < rxBufferIndex; i++) {
          deviceNewName[i-3] = rxBuffer[i];
        }   
        deviceNewName[deviceNewNameLength] = '\0';
        deviceNewNameCRC = getCRC(deviceNewName, deviceNewNameLength);

        osal_snv_write(SNV_ID_DEVICE_NAME, 20, deviceNewName);
        osal_snv_write(SNV_ID_DEVICE_NAME_LENGTH, 1, &deviceNewNameLength);
        osal_snv_write(SNV_ID_DEVICE_NAME_CRC, 1, &deviceNewNameCRC);
        printf("Name is being set, reset to set new name\r\n");
      }
  • To change the device’s scan response data and device’s name, first it must be put into CMD mode by sending 3’s @, ie. @@@
  • Then, the name can be set to be stored with SN,<value> where is the new name and it must be less than 20 characters long.
  • To see changes, the device needs to be restarted with S,R.
Advertisements

5 thoughts on “CC254x HID Project – Name changing feature added

  1. I just tore down my worse-for-wear T61 and found your site after a few minutes of Googling for a project like this. Oh, I want one of these. I’m never as fast as I am on a ThinkPad keyboard, and this would be the ultimate portable.

    Got any resources for a total PCB newbie to start out? I’d like to build one of these someday. It’s open sourced, correct?

    1. I use Altium Designer for PCB designing, it’s the industry-standard PCB design tool but you can use any PCB design suite. I personally dislike Eagle despite its popularity for its limited capability in PCB layout like traces hug-and-push feature and real-time design rule check. Have a look at OrCad Lite, KiCad.

      I’m going to release the schematic and some documentation. The source code stays with me. It’s not good enough to be made public.

  2. Hi, great article!
    Tested your compiled HEX “experimental” cca2541 works fine.
    When I recompiled (IAR 7) your original files from GIT then the HEX “experimental” doesn’t work. HM-10 is not discoverable and doesn’t response on commands including printf.
    Where can be a problem?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s