/*
 * File:   btle_command.c
 * Author: Brandon Mitchell
 *
 * Created on February 10, 2015, 11:49 AM
 * 
 * List of RN4020 commands with some default example parameters and responses
 * These commands can be used as is, or custom commands can be created and sent
 */

#include "btle.h"
#include "crc16.h"
#ifdef _DEBUG
//#include "led.h"
#endif

////////////////////////////////////////////////////////////////////////////////
// MACROS

#define TO_HEX(i) (i <= 9 ? '0' + i : 'A' + (i - 10))

////////////////////////////////////////////////////////////////////////////////
// Public Data

const btleCommand_t btleCommandTable[] = {

    //Set Commands
    {"S-,MPGRN1\r\n",           "AOK\r\n", 5,    50}, //Serialized Name
    {"SB,0\r\n",                "AOK\r\n", 5,    50}, //Baud Rate (2400)
    {"SF,1\r\n",                "AOK\r\n", 5,    50}, //Factory (partial) reset
    {"SM,1,00002710\r\n",       "",        0,    50}, //Timer 1 - 10000us
    {"SM,2,00002710\r\n",       "",        0,    50}, //Timer 2 - 10000us
    {"SM,3,00002710\r\n",       "",        0,    50}, //Timer 3 - 10000us
    {"SN,MpgPed\r\n",           "AOK\r\n", 5,    50}, //Central Name
    {"SN,MpgHub\r\n",           "AOK\r\n", 5,    50}, //Peripheral Name
    {"SR,90000000\r\n",         "AOK\r\n", 5,    50}, //Central Resources
    {"SR,30000000\r\n",         "AOK\r\n", 5,    50}, //Peripheral Resources
    {"SS,C0000001\r\n",         "AOK\r\n", 5,    50}, //Central Server service
    {"SS,30000001\r\n",         "AOK\r\n", 5,    50}, //Peripheral Server service
    {"ST,0006,0000,0064\r\n",   "AOK\r\n", 5,    50}, //Interval, timing, latency

    //Get Commands
    {"G-\r\n",  "AOK\r\n",          5,  50},
    {"GB\r\n",  "0\r\n",            3,  50},
    {"GDF\r\n", "1.10\r\n",         6,  50},
    {"GDH\r\n", "2.1\r\n",          5,  50},
    {"GDM\r\n", "RN4020\r\n",       8,  50},
    {"GDN\r\n", "Microchip\r\n",    11, 50},
    {"GDR\r\n", "1.10\r\n",         6,  50},
    {"GDS\r\n", "001EC01B27EF\r\n", 14, 50},
    {"GN\r\n",  "MpgCentral1\r\n",  13, 50},
    {"GR\r\n",  "00000000\r\n",     10, 50},
    {"GS\r\n",  "80000000\r\n",     10, 50},
    {"GT\r\n",  "0006,0000,0064\r\n", 16, 50},

    //Action Commands
    {"+\r",             "Echo On\r\n"       , 9, 50},  //Echo On
    {"+\r\n",           "+\rEcho Off\r\n"   , 12, 50}, //Echo Off
    {"ECHO TEST\r\n",   "ECHO TEST"         , 9, 50},  //Informal Echo test
    {"A,0064,1388\r\n",         "", 5, 50}, //Peripheral: start advertisement  //TODO: Finish discovering replies for commands
    {"B,0\r\n",                 "", 5, 50}, //Bond - volatile
    {"D\r\n",                   "", 103, 50}, //Display device information
    {"E,0,001EC01B27EF\r\n",    "", 18, 50},  //Central: establish connection
    {"F\r\n",                   "", 45, 2000}, //Central: query peripheral devices before connection
    {"H\r\n",                   "", 5, 50}, //Display help page
    {"J,1\r\n",                 "", 5, 50}, //Enter Observer Mode
    {"J,0\r\n",                 "", 5, 50}, //Exit Observer Mode
    {"K\r\n",                   "", 5, 50}, //Kill active connection
    {"M\r\n",                   "", 5, 50}, //Check signal strength
    {"N,11223344\r\n",          "", 5, 50}, //Enter Broadcaster mode; set advertisement content
    {"O\r\n",                   "", 5, 50}, //Enter Dormant Mode
    {"R,1\r\n",                 "Reboot\r\n", 8, 2000}, //Reboot
    {"T,0006,0000,0064\r\n",    "", 5, 50}, //Change timing interval, latency, and timeout
    {"U\r\n",                   "AOK\r\n", 5, 50}, //Unbond
    {"V\r\n",                   "", 5, 50}, //Display firmware version
    {"X\r\n",                   "", 5, 50}, //Central: stop inquiry process started with "F"
    {"Y\r\n",                   "", 5, 50}, //Peripheral: stop advertisement started with "A"
    {"Z\r\n",                   "", 5, 50}, //Central: stop connection process started with "E"

    //List services and characteristics
    {"LC\r\n",                  "", 255, 50}, //List client services
    {"LS\r\n",                  "", 265, 50}, //List server services

    //Private services and characteristics
    {"PC,12348765123487651234876512348765,1A,14\r\n",   "AOK\r\n", 5, 50}, //set private characteristic - 20 bytes of text
    {"PS,876512349876234509873456ABCDEF55\r\n",         "AOK\r\n", 5, 50}, //set private service
    {"PZ\r\n",                                          "AOK\r\n", 5, 50}, //clear private service
    
    //MLDP
    {"I\r\n",       "", 5, 50}, //Enter MLDP mode
    {"SE,0\r\n",    "", 5, 50}, //Set MDLP security mode (none)
    {"SE,1\r\n",    "", 5, 50}  //Set MDLP security mode (encrypted)
};

////////////////////////////////////////////////////////////////////////////////
// Interface Function Definitions

// Converts a 32-bit number to its ascii HEX equivalent
// Useful for sending "numbers" to the RN4020 as character strings
// Assumes that solution can hold 9 chars.
void BtleMaskToString( const unsigned long bitMask, unsigned char * solution ) {

    solution[0] = TO_HEX((( bitMask & 0xF0000000UL ) >> 28 ));
    solution[1] = TO_HEX((( bitMask & 0x0F000000UL ) >> 24 ));
    solution[2] = TO_HEX((( bitMask & 0x00F00000UL ) >> 20 ));
    solution[3] = TO_HEX((( bitMask & 0x000F0000UL ) >> 16 ));
    solution[4] = TO_HEX((( bitMask & 0x0000F000UL ) >> 12 ));
    solution[5] = TO_HEX((( bitMask & 0x00000F00UL ) >>  8 ));
    solution[6] = TO_HEX((( bitMask & 0x000000F0UL ) >>  4 ));
    solution[7] = TO_HEX((( bitMask & 0x0000000FUL )       ));
    solution[8] = '\0';
}

// takes "HELLO", and returns HEX ascii encoding: "48454C4C4F"
// Then caluclates and encodes a 16 bit CRC, and appends it to outString
// assumes that outString is large enough to hold the output;
// if not, returns as much of the encoding as will fit in outString
void BtleStringToAsciiEncode(const unsigned char * inString, unsigned char * outString, const unsigned char maxOutStringLength ) {

    int ii, jj;
    for ( ii = 0, jj = 0; (*(inString + ii) && ii < maxOutStringLength - 5); ++ii ) {

        *( outString + jj++ ) = TO_HEX(( ( *( inString + ii ) & 0xF0 ) >> 4 ));
        *( outString + jj++ ) = TO_HEX(( ( *( inString + ii ) & 0x0F )      ));
    }
   CRC16 crc = CalcCrc16( INITIAL_CRC16_VALUE, outString, 10 );

   *( outString + jj++ ) = TO_HEX(( ( crc & 0xF000 ) >> 12 ));
   *( outString + jj++ ) = TO_HEX(( ( crc & 0x0F00 ) >>  8 ));
   *( outString + jj++ ) = TO_HEX(( ( crc & 0x00F0 ) >>  4 ));
   *( outString + jj++ ) = TO_HEX(( ( crc & 0x000F )       ));
   *( outString + jj ) = '\0';
}

// takes hex ASCII encoded string: "48454C4C4F", returns outString, "HELLO"
void BtleAsciiHexToString( const unsigned char * hex, unsigned char * outString ) {

    int ii = 0, jj = 0;
    unsigned char tens = 0, ones = 0;
    while( hex[ii + 1] && hex[ii] ) {

        tens = hex[ii];
        ones = hex[ii + 1];

        tens -= '0';
        tens *= 16;

        if( ones > '9' ) {
            ones -= 'A';
            tens += 10;
        } else {
            ones -= '0';
        }
        outString[jj] = tens + ones;
        ++jj;
        ii += 2;
    }
    outString[jj] = '\0';
}