
fork test
Dependencies: BLE_API WIFI_API_32kRAM mbed nRF51822
Fork of NNN40_CLI by
Diff: CLI_Source/ble_cli.cpp
- Revision:
- 0:5c195ab2f696
- Child:
- 3:38ec8ad317f4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CLI_Source/ble_cli.cpp Fri Sep 11 07:29:31 2015 +0000 @@ -0,0 +1,1297 @@ +/** + * File: ble-cli.c + * Description: BLE CLI commands used by all applications BLE of profile. + * + * Copyright 2014 by CYNTEC Corporation. All rights reserved. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include "command-interpreter.h" +#include "simple_uart.h" +#include "mbed.h" +#include "BLE.h" +#include "Gap.h" +#include "nrf_gpio.h" +#include "nrf_soc.h" +#include "ble_cli.h" +#include "ble_hci.h" +#include "app_error.h" +#include "PinNames.h" +//#include "custom_helper.h" +extern "C" { + #include "ble_advdata.h" +} + +#define S110_BLE_PERIPHERAL + +#define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */ +#define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout (in units of seconds). */ +#define APP_ADV_INTERVAL_MAX 16384 // correspond to 10.24s +#define APP_ADV_INTERVAL_MIN 32 // correspond to 20ms +// Offset for Advertising Data. +#define APP_ADV_DATA_OFFSET 2 + +#define MAX_DEVNAME_LEN 32 +#define CLI_SERVICE_MAX_NUM 10 +#define CLI_CHAR_MAX_NUM 10 +#define MAX_VALUE_LENGTH 20 + +#define CLI_CHAR_MODE_NONE 0 +#define CLI_CHAR_MODE_READ 1 +#define CLI_CHAR_MODE_WRITE 2 +#define CLI_CHAR_MODE_INDICATE 3 +#define CLI_CHAR_MODE_NOTIFY 4 + +#define CLI_FWVERION "DELTA_CLI_V1.6" +#define MODULE_NAME "DFCM-NNN40-DT1R" +#define ADVERTISING_LED_PIN_NO LED1 +#define DELTA_DEBUG 1 +//#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00} +#define NEW_VS_SERVICE 0x0001 + + +static ble_gap_addr_t m_peer_addr; +extern Serial console; +BLE deltaBLE; //gill 0904 +extern const char* cyntecCommandErrorNames[]; +extern void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason); +// gill 0904 +static bool connState = false; + +typedef struct bufferGattChar { +// bool flag; + uint8_t mode; + ble_uuid_t char_uuid; + //uint8_t value[MAX_VALUE_LENGTH]; + uint16_t char_value_handle; + uint8_t valueLength; +} bufferGattChar_t; + +typedef struct bufferGattService { +// uint16_t service_uuid_vs[8]; +// uint16_t service_uuid; +// bool flag; + ble_uuid_t service_uuid; + bufferGattChar_t bufferGattChar[CLI_CHAR_MAX_NUM]; + uint16_t service_handle; +} bufferGattService_t; + +/* save entry services */ +bufferGattService_t bufferGattTest; +bufferGattService_t bufferService[CLI_SERVICE_MAX_NUM]; + + +//static uint8_t debugMess[20]; // used in print debug +uint8_t service_count=0; +uint8_t char_count=0; +static uint16_t test_conn_handle; //Connection handle, assign after connected +extern bool advState; // currently no use + +DigitalOut led1(p7); +DigitalOut led2(p13); + +/****************************************************** + * Function Definitions + ******************************************************/ + +void onTimeoutCallback(Gap::TimeoutSource_t source) +{ + led1 = !led1; +} + +void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) +{ + test_conn_handle = params->handle; + //console.printf("connState:%d\r\n",connState); + connState = true; + led2 = !led2; +} + +void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) +{ + //console.printf("connState:%d\r\n",connState); + connState = false; +} + + +static void cyntecPrintOk(void) +{ + console.printf("\r\nOK\r\n\r\n"); +} + +static void cyntecPrintError(uint8_t errIdx) +{ + console.printf("\r\nERROR;"); + console.printf(cyntecCommandErrorNames[errIdx]); + console.printf("\r\n\r\n"); +} + +#ifdef S120_BLE_CENTRAL +/** + * @brief Scan parameters requested for scanning and connection. + */ +static const ble_gap_scan_params_t m_scan_param = +{ + 0, // Active scanning set. + 0, // Selective scanning not set. + NULL, // White-list not set. + (uint16_t)SCAN_INTERVAL, // Scan interval. + (uint16_t)SCAN_WINDOW, // Scan window. + 0 // Never stop scanning unless explicit asked to. +}; +#endif + +#ifdef S110_BLE_PERIPHERAL +/**@brief Function for the Advertising functionality initialization. + * + * @details Encodes the required advertising data and passes it to the stack. + * Also builds a structure to be passed to the stack when starting advertising. + */ +static void advertising_init(void) +{ + uint32_t err_code; + ble_advdata_t advdata; + ble_advdata_t scanrsp; + //uint8_t flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; + + ble_uuid_t adv_uuids[] = {{bufferService[0].service_uuid.uuid, 0x01}}; + + memset(&advdata, 0, sizeof(advdata)); + advdata.name_type = BLE_ADVDATA_FULL_NAME; + advdata.include_appearance = false; + advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; +// advdata.flags.size = sizeof(flags); +// advdata.flags.p_data = &flags; + + memset(&scanrsp, 0, sizeof(scanrsp)); + scanrsp.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]); + scanrsp.uuids_complete.p_uuids = adv_uuids; + + err_code = ble_advdata_set(&advdata, &scanrsp); + APP_ERROR_CHECK(err_code); +} + + +/**@brief Function for starting advertising. + */ +static uint8_t advertising_start(uint16_t advInterval, uint16_t advTimeout) +{ + uint32_t err_code; + ble_gap_adv_params_t adv_params; + + // Start advertising + memset(&adv_params, 0, sizeof(adv_params)); + + adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; /**< Connectable undirected. */ + adv_params.p_peer_addr = NULL; + adv_params.fp = BLE_GAP_ADV_FP_ANY; /**< Allow scan requests and connect requests from any device. */ + adv_params.interval = advInterval; + adv_params.timeout = advTimeout; + + err_code = sd_ble_gap_adv_start(&adv_params); + //APP_ERROR_CHECK(err_code); + return err_code; +} + + + +static void cynAdvertiseStartCommand(void) +{ + // adv start or adv stop or syntax error + uint8_t argLen = 0; + uint8_t *arg; + /* arg0 is start or stop advertising */ + uint8_t *action = cyntecGetCommandArgument(0,&argLen); + uint16_t advInterval; + uint16_t advTimeout; + + switch (cyntecGetCommandTokenCnt()) + { + case 2: + advInterval = APP_ADV_INTERVAL; + advTimeout = APP_ADV_TIMEOUT_IN_SECONDS; + break; + + case 3: + /* arg1 is adv interval parameter */ + arg = cyntecGetCommandArgument(1,&argLen); + advInterval = cyntecAtoiUint16( arg, argLen ); + advTimeout = APP_ADV_TIMEOUT_IN_SECONDS; + break; + + case 4: + arg = cyntecGetCommandArgument(1,&argLen); + advInterval = cyntecAtoiUint16( arg, argLen ); + arg = cyntecGetCommandArgument(2,&argLen); + advTimeout = cyntecAtoiUint16( arg, argLen ); + break; + + default: + advInterval = APP_ADV_INTERVAL; + advTimeout = APP_ADV_TIMEOUT_IN_SECONDS; + break; + } + + if ( advInterval< APP_ADV_INTERVAL_MIN | advInterval> APP_ADV_INTERVAL_MAX | advTimeout < 1| advTimeout > BLE_GAP_ADV_TIMEOUT_LIMITED_MAX ) + { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); + return; + } +//#ifdef DELTA_DEBUG +//sprintf((char *)&debugMess[0],"[%d][%d]", advInterval,advTimeout); +//console.printf(debugMess); +//#endif +// service_Test(); + advertising_init(); + uint8_t error_code = advertising_start(advInterval, advTimeout); + + if (error_code==NRF_SUCCESS) + { + cyntecPrintOk(); + nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO); + } + else if (error_code==NRF_ERROR_INVALID_STATE) + { + cyntecPrintError(CYNTEC_CMD_ERR_INVALID_STATE_TO_PERFORM_OPERATION); + return; + } + else + { + console.printf("ERROR;\r\n"); + } +} + +/**@brief Function for stop advertising. + */ +static void cynAdvertiseStopCommand(void) +{ + uint8_t advStopErr = 0; + advStopErr = sd_ble_gap_adv_stop(); + if (advStopErr == NRF_SUCCESS) + { + cyntecPrintOk(); + nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO); + } + else if (advStopErr==NRF_ERROR_INVALID_STATE) + { + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + return; + } + else{ + console.printf("ERROR;\r\n"); + } +} + +//gill modify 20150904 for accept blank in name +static void cynBLENameCommand(void) +{ + if (cyntecGetCommandTokenCnt() >= 3) + { + uint8_t tempNameLen = 0; + // check first and last char is " + uint8_t *argName1 = cyntecGetCommandArgument(0, &tempNameLen); + uint8_t *argNameLast = cyntecGetCommandArgument(cyntecGetCommandTokenCnt() - 3, &tempNameLen); + char bracket = '*'; + //console.printf("%02X\r\n",tempNameLen); + if (!memcmp(&argName1[0],&bracket,sizeof(char)) && !memcmp(&argNameLast[tempNameLen - 1],&bracket,sizeof(char))) + //if (!memcmp(&argName1[0],&bracket,sizeof(char))) + { + uint8_t nameLen = 0; + uint8_t *argName = cyntecGetCommandArgument(0, &nameLen); + uint8_t * argName2 = cyntecGetCommandTotalBuffer(); + uint32_t err_code; + ble_gap_conn_sec_mode_t sec_mode; + //console.printf("%02X\r\n",cyntecGetTotalIndex()); + console.printf("\r\nSet BLE Name: "); + uint8_t i = 0; + for(i = 0; i < cyntecGetTotalIndex()-12; i++) { + console.printf("%c",argName2[11+i]); + } + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + err_code = sd_ble_gap_device_name_set(&sec_mode, + (const uint8_t *) &argName2[11], + (uint16_t) (cyntecGetTotalIndex()-12)); + if (err_code == NRF_SUCCESS) { + cyntecPrintOk(); + } + else { + console.printf("ERROR;%04X\r\n",err_code); + } + APP_ERROR_CHECK(err_code); + + +//#ifdef DELTADEBUG + //console.printf("\r\nSet BLE Name: "); +// uint8_t i = 0; +// for(i = 0; i < nameLen; i++) +// { +// console.printf("%c",argName[i]); +// } + +//#endif + //console.printf("\r\nPrint buffer:\r\n"); + //console.printf("%s\r\n",cyntecGetCommandTotalBuffer()); + + /* Re-init application setting */ + //cyntecCLIAppInit(); + } + else + { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); + } + } else if (cyntecGetCommandTokenCnt() == 2){ + uint8_t bleName[BLE_GAP_DEVNAME_MAX_LEN] = {"\0"}; + uint16_t bleLen = BLE_GAP_DEVNAME_MAX_LEN - APP_ADV_DATA_OFFSET; + uint32_t err_code; + + err_code = sd_ble_gap_device_name_get(&bleName[APP_ADV_DATA_OFFSET], &bleLen); + APP_ERROR_CHECK(err_code); + + console.printf("\r\nOK;"); + console.printf("%s",bleName+APP_ADV_DATA_OFFSET); + console.printf(";\r\n"); + } + else{ + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + return; + } +} +#endif + +static void cynBLEInfoCommand(void) +{ + console.printf("\r\nOK;F/W version:"); + console.printf(CLI_FWVERION); + console.printf(";Module name:"); + console.printf(MODULE_NAME); + console.printf("\r\n\r\n"); +} + +/**@brief Set the radio's transmit power. + * + * @param[in] tx_power Radio transmit power in dBm (accepted values are -40, -30, -20, -16, -12, -8, -4, 0, and 4 dBm). + * + * @note -40 dBm will not actually give -40 dBm, but will instead be remapped to -30 dBm. + */ +static void cynBLESetTxPowerCommand (void) +{ + if (cyntecGetCommandTokenCnt() == 3) + { + uint32_t err_code; + uint8_t txLen=0; + uint8_t *arg = cyntecGetCommandArgument(0,&txLen); + +// uint8_t *arg = cyntecGetMinusArgument(0,&txLen); + +// cyntecGetMinusArgument(); +// const char *value = (const char *)arg; +// sprintf((char *)&debugMess[0],"\r\n[%i]\r\n",*value); +// console.printf(debugMess); + const uint8_t NUM_TXPOW = 9; + bool inputSwitch = false; // if find matched case in TxPow, assign true + + int8_t validTxPow[NUM_TXPOW] = {-40, -30, -20, -16, -12, -8, -4, 0, 4}; + uint8_t i; + int8_t setValue; + + if ( arg != NULL ) { + setValue = atoi((const char *)arg); +// sprintf((char *)&debugMess[0],"\r\n[%i]\r\n",setValue); +// console.printf(debugMess); + for (i = 0; i < NUM_TXPOW; i++) + { + if (setValue == validTxPow[i]) + { + err_code = sd_ble_gap_tx_power_set(setValue); + APP_ERROR_CHECK(err_code); + inputSwitch = true; + break; + } + } + + if ( inputSwitch ) + cyntecPrintOk(); + else + console.printf("\r\nWrong Input; Accept Tx Pow: -40, -30, -20, -16, -12, -8, -4, 0, 4\r\n"); + } + clearBuffer(); // clear the commandState.buffer + return; + } + else{ + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + return; + } +} + +static void cynBLEAddressCommand(void) +{ + if (cyntecGetCommandTokenCnt() == 3) + { + uint8_t argLen = 0; + uint8_t *arg = cyntecGetCommandArgument(0, &argLen); + uint32_t err_code; + uint8_t addr,i; + + /* should with "0x" + 12 len addr */ + if (argLen == 14) { + if (arg[0] != '0' || arg[1] != 'x') { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); + return; + } + + m_peer_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; + + for ( i = 1 ; i < 7 ; i++) + { + addr = cyntecArgToUint8(arg+2*i, 2); + /* 5 - (i-1) */ + m_peer_addr.addr[6-i] = addr; + } + + err_code = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &m_peer_addr); + APP_ERROR_CHECK(err_code); + + } else { //argLen != 14 + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); + return; + } + +//#ifdef DELTADEBUG +// uint8_t buf2[20]; +// console.printf("\r\nSet BLE Address: "); +// sprintf((char *)&buf2[0],(const char *)"[%02X %02X %02X %02X %02X %02X]", +// m_peer_addr.addr[0], m_peer_addr.addr[1], m_peer_addr.addr[2], +// m_peer_addr.addr[3], m_peer_addr.addr[4], m_peer_addr.addr[5]); +// console.printf(buf2); +//#endif + + cyntecPrintOk(); + } else if (cyntecGetCommandTokenCnt() == 2){ + + uint32_t err_code; + err_code = sd_ble_gap_address_get(&m_peer_addr); + APP_ERROR_CHECK(err_code); + + cyntecPrintOk(); + + console.printf("[%02X %02X %02X %02X %02X %02X]", + m_peer_addr.addr[5], m_peer_addr.addr[4], m_peer_addr.addr[3], + m_peer_addr.addr[2], m_peer_addr.addr[1], m_peer_addr.addr[0]); + } + else { //cyntecGetCommandTokenCnt() not equal to 2 or 3 + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + } + return; +} + +#ifdef S120_BLE_CENTRAL +/**@breif Function to start scanning. + */ +static void scan_start(void) +{ + uint32_t err_code = sd_ble_gap_scan_start(&m_scan_param); + APP_ERROR_CHECK(err_code); +} + +/**@breif Function to start scanning. + */ +static void scan_stop(void) +{ + uint32_t err_code = sd_ble_gap_scan_stop(); + APP_ERROR_CHECK(err_code); +} + +static void cynBLEScanCommand(void) +{ + uint8_t *arg = cyntecGetCommandArgument(0,NULL); + + if ( arg != NULL ) { + if ( arg[0] == '1' ) { + console.printf("\r\nStart Scanning"); + scan_start(); + } + else if ( arg[0] == '0' ) { + console.printf("\r\nStop Scanning"); + scan_stop(); + } + else + console.printf("\r\nUsage: cynb scan <1|0>"); + console.printf("\r\n"); + } +} + +static void cynBLEConnectCommand(void) +{ + if (cyntecGetCommandTokenCnt() == 3) + { + uint8_t devNameLen = 0; + uint8_t *argDevName = cyntecGetCommandArgument(0, &devNameLen); + + if ( argDevName != NULL ) { + uint8_t i; + for (i = 0; i < devNameLen; i++) { + targetDevName[i] = argDevName[i]; + } + if (i < devNameLen) + targetDevName[i] = '\0'; + } + + console.printf("\r\nSearch for device name:"); + console.printf(argDevName); + + scan_start(); + } else { + console.printf("\r\nUsage: cynb connect <Device Name>"); + console.printf("\r\n(Ex:cynb connect CYN_DEVICE"); + } +} +#endif + +static void cynBLEDisconnectCommand(void) +{ + uint32_t err_code; +#ifdef S110_BLE_PERIPHERAL + //marcus need to modify + err_code = sd_ble_gap_disconnect(test_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); +#endif + +#ifdef S120_BLE_CENTRAL + err_code = sd_ble_gap_connect_cancel(); // No function defined currently +#endif + if (err_code == NRF_SUCCESS) + { + + cyntecPrintOk(); +// APP_ERROR_CHECK(err_code); + } + else if (err_code ==NRF_ERROR_INVALID_STATE){ + cyntecPrintError(CYNTEC_CMD_ERR_INVALID_STATE_TO_PERFORM_OPERATION); + } + else { + console.printf("ERROR;\r\n"); + } +} + +static uint8_t isValidGPIO(uint8_t num) +{ + uint8_t cfgPin[] = {0,1,2,3,4,5,6,7,13,16,17,23,24,25,29}; + uint8_t i; + + for ( i = 0; i < sizeof(cfgPin) ; i++ ) + { + if ( num == cfgPin[i] ) + return 1; + } + + return 0; +} + +static void cynBLESystemOffCommand(void) +{ + if (cyntecGetCommandTokenCnt() == 3) + { + uint8_t argLen = 0; + uint8_t *arg = cyntecGetCommandArgument(0,&argLen); + uint8_t gpioNum = cyntecAtoi( arg, argLen ); + // Can only use 0,1,2,3,4,5,6,7,13,16,17,23,24,25,29 + if (!isValidGPIO(gpioNum)) + { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); + return; + } + nrf_gpio_cfg_sense_input(gpioNum, + NRF_GPIO_PIN_PULLUP, + NRF_GPIO_PIN_SENSE_LOW); + cyntecPrintOk(); + } else if (cyntecGetCommandTokenCnt() == 2){ + /* default wake up pin is uart Rx pin */ + nrf_gpio_cfg_sense_input(RX_PIN_NUMBER, + NRF_GPIO_PIN_PULLUP, + NRF_GPIO_PIN_SENSE_LOW); + cyntecPrintOk(); + } else{ + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + } + sd_power_system_off(); +} + +static void cynBLEGPIOCommand(void) +{ + + if (cyntecGetCommandTokenCnt() == 4) + { + uint8_t argLen = 0; + uint8_t *arg = cyntecGetCommandArgument(0,&argLen); + uint8_t gpioNum = cyntecAtoi( arg, argLen ); + + if (!isValidGPIO(gpioNum)) + { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); + return; + } + + /* arg2 is set or clear */ + uint8_t *action = cyntecGetCommandArgument(1,&argLen); + + if ( cyntecStrCmp(action,(unsigned char *)"set",argLen) == 1 ) + { + nrf_gpio_cfg_output(gpioNum); + nrf_gpio_pin_set(gpioNum); + cyntecPrintOk(); + } else if ( cyntecStrCmp(action,(unsigned char *)"clear",argLen) == 1 ) { + nrf_gpio_cfg_output(gpioNum); + nrf_gpio_pin_clear(gpioNum); + cyntecPrintOk(); + } else { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); + } + } else { + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + } +} + +static void cynResetCommand(void) +{ + cyntecPrintOk(); + // On assert, the system can only recover with a reset. + NVIC_SystemReset(); +} + +// gill modify for update value in non-connect state 20150904 +// Change set value connection handle +static void cynBLEUpdateUUIDCommand(void) +{ + uint8_t i,j; + uint8_t value[MAX_VALUE_LENGTH]; + memset(value, 0, sizeof(value)); +// uint8_t buf_char_uuid_type; + ble_uuid_t buf_service_uuid; + ble_uuid_t buf_char_uuid; + uint8_t argLen = 0; + uint8_t *arg; + uint8_t valueLengthBuffer = 0; + uint8_t modeType; + bool updatematchFlag = false; // Check matched characteristic found + uint16_t len = MAX_VALUE_LENGTH; + uint32_t err_code; + // check if argument count is right + if (cyntecGetCommandTokenCnt() != 5) + { + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + return; + } + else + { + arg = cyntecGetCommandArgument(0,&argLen); + if (arg[0] != '0' | arg[1] != 'x' | argLen%2 != 0) { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); + return; + } + else { + // Handle input parameter - Service UUID + arg = cyntecGetCommandArgument(0,&argLen); + + if (argLen == 6 && arg[0] == '0' && arg[1] == 'x') + { + buf_service_uuid.uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); + buf_service_uuid.type = BLE_UUID_TYPE_BLE; + } + if (argLen == 34 && arg[0] == '0' && arg[1] == 'x') + { + buf_service_uuid.uuid = cyntecArgToUint16( (arg + 6), 4); + buf_service_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN; + } + + // Handle input parameter - Characteristic UUID + argLen = 0; + arg = cyntecGetCommandArgument(1,&argLen); + + if (argLen == 6 && arg[0] == '0' && arg[1] == 'x') + { + buf_char_uuid.uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); + buf_char_uuid.type = BLE_UUID_TYPE_BLE; + } + if (argLen == 34 && arg[0] == '0' && arg[1] == 'x') + { + buf_char_uuid.uuid = cyntecArgToUint16( (arg + 6), 4); + buf_char_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN; + } +// sprintf((char *)&debugMess[0],"buf_service_uuid[%d,%4X]\r\n",buf_service_uuid.type,buf_service_uuid.uuid); +// console.printf(debugMess); + + // Handle input parameter - value + arg = cyntecGetCommandArgument(2,&argLen); + valueLengthBuffer = (argLen-2)/2; + for (i=0 ; i < (argLen-2)/2; i++) + { + value[i] = cyntecArgToUint8(arg+2*(i+1), 2); + // debug + // sprintf((char *)&buf[0],"[%2X]",value[i]); + // console.printf(buf); + } + + } + // debug message +// sprintf((char *)&buf[0],"value:[%02X]", value); +// console.printf(buf); + + for ( i = 0 ; i < CLI_SERVICE_MAX_NUM ; i++ ) + { + if ( (bufferService[i].service_uuid.uuid == buf_service_uuid.uuid) &(bufferService[i].service_uuid.type == buf_service_uuid.type)& (updatematchFlag == false)) + { + //readmatchFlag = true; + for ( j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) + { + if ( (bufferService[i].bufferGattChar[j].char_uuid.uuid == buf_char_uuid.uuid) &(bufferService[i].bufferGattChar[j].char_uuid.type == buf_char_uuid.type)& (updatematchFlag == false)) + { + modeType = bufferService[i].bufferGattChar[j].mode; + //memset(bufferService[i].bufferGattChar[j].value, 0, sizeof(bufferService[i].bufferGattChar[j].value)); + // Identify characteristic property is notify or indicate + if (((modeType & (1 << CLI_CHAR_MODE_INDICATE)) | (modeType & (1 << CLI_CHAR_MODE_NOTIFY))) ) + { + if (bufferService[i].bufferGattChar[j].mode & (1 << CLI_CHAR_MODE_INDICATE)) + modeType = BLE_GATT_HVX_INDICATION ; + if (bufferService[i].bufferGattChar[j].mode & (1 << CLI_CHAR_MODE_NOTIFY)) + modeType = BLE_GATT_HVX_NOTIFICATION; + ble_gatts_hvx_params_t hvx_params; + memset(&hvx_params, 0, sizeof(hvx_params)); + hvx_params.handle = bufferService[i].bufferGattChar[j].char_value_handle; + hvx_params.type = modeType; + hvx_params.offset = 0; + hvx_params.p_len = &len; + hvx_params.p_data = value; + if (connState) // If connected, send notification/indication + { + err_code = sd_ble_gatts_hvx(test_conn_handle, &hvx_params); + + if (err_code == NRF_SUCCESS) + { + //do nothing + } + else if ((err_code != NRF_SUCCESS) && + (err_code != NRF_ERROR_INVALID_STATE) && + (err_code != BLE_ERROR_NO_TX_BUFFERS) && + (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) + ) + { + console.printf("HVX ERROR;%04X\r\n",err_code); + } + } + + } + + // Update database + bufferService[i].bufferGattChar[j].valueLength = valueLengthBuffer; + ble_gatts_value_t bufGattsValue; + memset(&bufGattsValue, 0, sizeof(bufGattsValue)); + bufGattsValue.len = len; + bufGattsValue.offset = 0; + bufGattsValue.p_value = value; + //err_code = sd_ble_gatts_value_set(bufferService[i].bufferGattChar[j].char_value_handle, +// 0, +// &len, +// value); + err_code = sd_ble_gatts_value_set( + //test_conn_handle, + BLE_CONN_HANDLE_INVALID, // User can update in non-connected state + bufferService[i].bufferGattChar[j].char_value_handle, + &bufGattsValue + ); + + if (err_code == NRF_SUCCESS) + { + cyntecPrintOk(); + } + else + { + console.printf("Set ERROR;%04X\r\n",err_code); + } + updatematchFlag = true; + return; + } + } + } + } + if (updatematchFlag == false){ + cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); + } + } +} + +static void cynBLEReadDataCommand(void) +{ + + if (cyntecGetCommandTokenCnt() != 4) + { + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + } + else + { + //uint16_t buf_char_uuid ; + uint8_t i,j; + uint8_t value[MAX_VALUE_LENGTH]; + //uint8_t buf[20]; +// uint8_t buf_char_uuid_type; + ble_uuid_t buf_service_uuid; + ble_uuid_t buf_char_uuid; + uint8_t valueLengthBuffer; + bool readmatchFlag = false; + // debug message +// sprintf((char *)&debugMess[0],"buf_char_uuid:[%04X]", buf_char_uuid); +// console.printf(debugMess); + uint8_t argLen = 0; + uint8_t *arg = cyntecGetCommandArgument(0,&argLen); + + // Print out the service & char uuids table +// for ( i = 0 ; i < CLI_SERVICE_MAX_NUM ; i++ ) +// { +// for ( j = 0 ; j < CLI_SERVICE_MAX_NUM ; j++ ) +// { +// sprintf((char *)&debugMess[0],"[%4X,%d][%4X,%d]\r\n",bufferService[i].service_uuid.uuid,bufferService[i].service_uuid.type,bufferService[i].bufferGattChar[j].char_uuid.uuid,bufferService[i].bufferGattChar[j].char_uuid.type); +// console.printf(debugMess); +// } +// } + + // Handle input parameter - Service UUID + if (argLen == 6 && arg[0] == '0' && arg[1] == 'x') + { + buf_service_uuid.uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); + buf_service_uuid.type = BLE_UUID_TYPE_BLE; + } + if (argLen == 34 && arg[0] == '0' && arg[1] == 'x') + { + buf_service_uuid.uuid = cyntecArgToUint16( (arg + 6), 4); + buf_service_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN; + } + + // Handle input parameter - Characteristic UUID + argLen = 0; + arg = cyntecGetCommandArgument(1,&argLen); + if (argLen == 6 && arg[0] == '0' && arg[1] == 'x') + { + buf_char_uuid.uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); + buf_char_uuid.type = BLE_UUID_TYPE_BLE; + } + if (argLen == 34 && arg[0] == '0' && arg[1] == 'x') + { + buf_char_uuid.uuid = cyntecArgToUint16( (arg + 6), 4); + buf_char_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN; + } +// sprintf((char *)&debugMess[0],"buf_service_uuid[%d,%4X]\r\n",buf_service_uuid.type,buf_service_uuid.uuid); +// console.printf(debugMess); + for ( i = 0 ; i < CLI_SERVICE_MAX_NUM ; i++ ) + { + if ( (bufferService[i].service_uuid.uuid == buf_service_uuid.uuid) &(bufferService[i].service_uuid.type == buf_service_uuid.type)& (readmatchFlag == false)) + { + //readmatchFlag = true; + for ( j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) + { + if ( (bufferService[i].bufferGattChar[j].char_uuid.uuid == buf_char_uuid.uuid) &(bufferService[i].bufferGattChar[j].char_uuid.type == buf_char_uuid.type)& (readmatchFlag == false)) + { + // uint8_t value[] = "88"; + uint16_t len = MAX_VALUE_LENGTH; + ble_gatts_value_t bufGattsValue; + memset(&bufGattsValue, 0, sizeof(bufGattsValue)); + bufGattsValue.len = len; + bufGattsValue.offset = 0; + bufGattsValue.p_value = value; + //sd_ble_gatts_value_get(bufferService[i].bufferGattChar[j].char_value_handle, +// 0, +// &len, +// value); + sd_ble_gatts_value_get( test_conn_handle, + bufferService[i].bufferGattChar[j].char_value_handle, + &bufGattsValue + ); + console.printf("\r\nOK;0x"); + valueLengthBuffer = bufferService[i].bufferGattChar[j].valueLength; + // sprintf((char *)&debugMess[0],"[%i]",valueLengthBuffer); + // console.printf(debugMess); + + for (i=0 ; i < valueLengthBuffer; i++) + { + console.printf("%02X",value[i]); + } + console.printf(";\r\n"); + readmatchFlag = true; + return; + } + } + } + } + // no matched case, can not read + if (readmatchFlag == false){ + cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); + } + } + + +} +/* Set characteristics */ +static void cyntecInsertCharUUID(ble_uuid_t char_UUID, uint16_t charValueHandle,uint8_t valueLengthBuffer,uint8_t mode) +{ + uint8_t j; + j=char_count; +// sprintf((char *)&debugMess[0],"char_uuid:%4X\r\n",char_UUID.uuid); +// console.printf(debugMess); + bufferService[service_count-1].bufferGattChar[j].char_uuid.uuid = char_UUID.uuid; + bufferService[service_count-1].bufferGattChar[j].char_uuid.type = char_UUID.type; + bufferService[service_count-1].bufferGattChar[j].valueLength = valueLengthBuffer; + bufferService[service_count-1].bufferGattChar[j].mode = mode; + bufferService[service_count-1].bufferGattChar[j].char_value_handle = charValueHandle; + return; +} + +static void cynGattCharCommand(void) +{ +// uint16_t service_uuid_ble; +// uint8_t service_uuid_vs[16]; + + uint8_t attrMode=0; + uint8_t attrValue[MAX_VALUE_LENGTH]; + memset(&attrValue, 0, sizeof(attrValue)); + + uint8_t i; +// uint8_t valueBuffer; + uint8_t err_code; + uint16_t buffer_char_uuid; +// uint16_t buffer_char_uuid_ble; + uint16_t buffer_uuid_vs[8]; + ble_uuid_t char_uuid; + ble_uuid128_t char_uuid_vs; + + ble_gatts_char_md_t char_md; + ble_gatts_attr_t attr_char_value; + + ble_gatts_attr_md_t cccd_md; + ble_gatts_attr_md_t attr_md; +// uint8_t init_value_encoded[2] = "77"; +// uint8_t init_value_len; + uint8_t valueLengthBuffer; + extern uint8_t char_count; + + if (cyntecGetCommandTokenCnt() != 5) + { + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + return; + } + else + { + +//#ifdef DELTA_DEBUG +//sprintf((char *)&debugMess[0],"[%04X]", service_uuid); +//console.printf(debugMess); +//#endif + + /* handle second parameter - UUID */ + uint8_t argLen = 0; + uint8_t *arg = cyntecGetCommandArgument(0,&argLen); + + /* len: 6 => 0xXXXX */ + if ( argLen == 6 && arg[0] == '0' && arg[1] == 'x') + { + buffer_char_uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); + BLE_UUID_BLE_ASSIGN(char_uuid, buffer_char_uuid); + char_uuid.type = BLE_UUID_TYPE_BLE; + } + + if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) + { + for ( i=0;i<8;i++) + { + buffer_uuid_vs[7-i] = cyntecArgToUint16( (arg + 2+4*i), 4); + if (i==1) + { + char_uuid.uuid = cyntecArgToUint16( (arg + 2+4*i), 4); + } +//#ifdef DELTA_DEBUG +// sprintf((char *)&debugMess[0],"%2X/",buffer_uuid_vs[7-i]); +// console.printf(debugMess); +//#endif + } + memcpy(&char_uuid_vs,buffer_uuid_vs,16); + err_code = sd_ble_uuid_vs_add(&char_uuid_vs, &char_uuid.type); + } +//#ifdef DELTA_DEBUG +// sprintf((char *)&debugMess[0],"char_uuid_type:[%d]\r\n",char_uuid.type); +// console.printf(debugMess); +//#endif + + +//#ifdef DELTA_DEBUG +// sprintf((char *)&debugMess[0],"vs_add_Error:%d\r\n",err_code); +// console.printf(debugMess); +//#endif + + /* handle 3rd parameter - attribute mode */ + argLen = 0; + arg = cyntecGetCommandArgument(1,&argLen); + + for ( i = 0 ; i < argLen ; i++ ) + { + switch(arg[i]) { + case 'r': + attrMode |= (1 << CLI_CHAR_MODE_READ); + break; + case 'w': + attrMode |= (1 << CLI_CHAR_MODE_WRITE); + break; + case 'i': + attrMode |= (1 << CLI_CHAR_MODE_INDICATE); + break; + case 'n': + attrMode |= (1 << CLI_CHAR_MODE_NOTIFY); + break; + default: + break; + } + } + + /* handle 4th parameter - attribute value */ + argLen = 0; + arg = cyntecGetCommandArgument(2,&argLen); + + if (arg[0] != '0' || arg[1] != 'x' | argLen%2 != 0) { + cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); + return; + } + else { + valueLengthBuffer = (argLen-2)/2; + for (i=0 ; i < (argLen-2)/2; i++) + { + attrValue[i] = cyntecArgToUint8(arg+2*(i+1), 2); + + } + //cyntecInsertCharUUID(service_uuid, char_uuid, attrMode, attrValue,valueLengthBuffer); + //cyntecPrintOk(); + } + } + + + //debug +// sprintf((char *)&debugMess[0],"value:[%02X][%02X]", value[0],value[1]); +// console.printf(debugMess); + + //write read permission + ble_gap_conn_sec_mode_t local_all_perm; + local_all_perm.lv = 1; + local_all_perm.sm = 1; + + memset(&cccd_md, 0, sizeof(cccd_md)); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); + cccd_md.write_perm = local_all_perm; + cccd_md.vloc = BLE_GATTS_VLOC_STACK; + + memset(&char_md, 0, sizeof(char_md)); + + if ( attrMode & (1 << CLI_CHAR_MODE_READ)) + char_md.char_props.read = 1; + if (attrMode & (1 << CLI_CHAR_MODE_WRITE)) + char_md.char_props.write = 1; + if (attrMode & (1 << CLI_CHAR_MODE_NOTIFY)) + char_md.char_props.notify = 1; + if (attrMode & (1 << CLI_CHAR_MODE_INDICATE)) + char_md.char_props.indicate = 1; + + char_md.p_char_user_desc = NULL; + char_md.p_char_pf = NULL; + char_md.p_user_desc_md = NULL; + char_md.p_cccd_md = &cccd_md; + char_md.p_sccd_md = NULL; + + memset(&attr_md, 0, sizeof(attr_md)); + + attr_md.vloc = BLE_GATTS_VLOC_STACK; + attr_md.read_perm = local_all_perm; + attr_md.write_perm = local_all_perm; + attr_md.rd_auth = 0; + attr_md.wr_auth = 0; + attr_md.vlen = 0; + + memset(&attr_char_value, 0, sizeof(attr_char_value)); + +// init_value_len = MAX_VALUE_LENGTH; + + attr_char_value.p_uuid = &char_uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = MAX_VALUE_LENGTH; + attr_char_value.init_offs = 0; + attr_char_value.max_len = MAX_VALUE_LENGTH; + attr_char_value.p_value = attrValue; + //debug +// sprintf((char *)&debugMess[0],"value:[%s]", attr_char_value.p_value); +// console.printf(debugMess); + ble_gatts_char_handles_t testHandle; + err_code = sd_ble_gatts_characteristic_add(bufferGattTest.service_handle, + &char_md, + &attr_char_value, + &testHandle); +//#ifdef DELTA_DEBUG +// sprintf((char *)&debugMess[0],"char_uuid:%4X\r\n",char_uuid.uuid); +// console.printf(debugMess); +//#endif + if (err_code == NRF_SUCCESS) + { + cyntecPrintOk(); + cyntecInsertCharUUID(char_uuid, testHandle.value_handle,valueLengthBuffer,attrMode); +// sprintf((char *)&debugMess[0],"char_count:%d\r\n",char_count); +// console.printf(debugMess); + char_count++; + if (char_count>10) + char_count=0; + } + else if (err_code == NRF_ERROR_INVALID_STATE) + { + cyntecPrintError(CYNTEC_CMD_ERR_INVALID_STATE_TO_PERFORM_OPERATION); + return; + } + else + { + console.printf("ERROR;\r\n"); + } + +} + +static void cyntecInsertServiceUUID(ble_uuid_t service_UUID) +{ + /* find if the service uuid is exist */ + bufferService[service_count].service_uuid.uuid = service_UUID.uuid; + bufferService[service_count].service_uuid.type = service_UUID.type; + return; + +} + +static void cynGattServiceCommand(void) +{ +// uint16_t service_uuid; +// uint8_t attrValue[MAX_VALUE_LENGTH]; +// memset(&attrValue, 0, sizeof(attrValue)); +// uint8_t i; +// uint8_t valueBuffer; + extern uint8_t service_count; + + uint32_t err_code; + ble_uuid_t ble_uuid; + ble_uuid128_t ble_uuid128; + uint16_t buffer_uuid; + uint16_t buffer_uuid_vs[8]; + int i; + + if (cyntecGetCommandTokenCnt() != 3) + { + cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); + return; + } + else + { + /* handle first parameter - Service UUID */ + uint8_t argLen = 0; + uint8_t *arg = cyntecGetCommandArgument(0,&argLen); + + /* Service uuid is 16 bits */ + if ( argLen == 6 && arg[0] == '0' && arg[1] == 'x') + { + buffer_uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); + //ble_uuid.type = BLE_UUID_TYPE_BLE; //type assign in BLE_UUID_BLE_ASSIGN + BLE_UUID_BLE_ASSIGN(ble_uuid, buffer_uuid); + + err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &bufferGattTest.service_handle); + ble_uuid.type = BLE_UUID_TYPE_BLE; + + } + + /* Service uuid is 128 bits */ + if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) + { +// uint8_t uuid_type = custom_add_uuid_base(CFG_CUSTOM_UUID_BASE); + //ASSERT(uuid_type > 0, ERROR_NOT_FOUND); + for ( i=0;i<8;i++) + { + buffer_uuid_vs[7-i] = cyntecArgToUint16( (arg + 2+4*i), 4); + if (i==1) + { + ble_uuid.uuid = cyntecArgToUint16( (arg + 2+4*i), 4); + } +#ifdef DELTA_DEBUG + console.printf("%2X/",buffer_uuid_vs[7-i]); +#endif + } + memcpy(&ble_uuid128.uuid128,buffer_uuid_vs,16); +//#ifdef DELTA_DEBUG +// sprintf((char *)&debugMess[0],"%32X\r\n",ble_uuid128.uuid128); +// console.printf(debugMess); +//#endif + err_code = sd_ble_uuid_vs_add(&ble_uuid128, &ble_uuid.type); +//#ifdef DELTA_DEBUG +// sprintf((char *)&debugMess[0],"service_uuid_type:%d\r\n",ble_uuid.type); +// console.printf(debugMess); +//#endif + + err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &bufferGattTest.service_handle); + + ble_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN; + + } + if (err_code == NRF_SUCCESS) + { + cyntecPrintOk(); + cyntecInsertServiceUUID(ble_uuid); + service_count++; + char_count = 0; +// sprintf((char *)&debugMess[0],"service_count:%d\r\n",service_count); +// console.printf(debugMess); + } + else + { + console.printf("ERROR;\r\n"); + + } + + } + } + +static void cynBLEInitCommand(void) +{ + const char DEVICE_NAME[] = "DELTA_CLI"; + + deltaBLE.init(); + deltaBLE.onDisconnection(disconnectionCallback); + deltaBLE.onConnection(onConnectionCallback); + deltaBLE.onTimeout(onTimeoutCallback); + + /* Setup advertising. */ + deltaBLE.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + deltaBLE.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); + deltaBLE.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + deltaBLE.setAdvertisingInterval(1000); + + cyntecPrintOk(); +} + +CyntecCommandEntry bleCommandSets[] = { + {"init", cynBLEInitCommand, NULL, "Init BLE stack, Usage: cynb init"}, + {"gpio", cynBLEGPIOCommand, NULL, "Config gpio, Usage: cynb gpio <GPIO NO> <set|clear>"}, + {"sleep", cynBLESystemOffCommand, NULL, "System off mode, Usage: cynb sleep <GPIO NO>"}, + {"disconn", cynBLEDisconnectCommand, NULL, "Disconnection, Usage: cynb disconn"}, + {"reset", cynResetCommand, NULL, "Soft reset, Usage: cynb reset"}, + {"info", cynBLEInfoCommand, NULL, "Module information, Usage: cynb info"}, +#ifdef S110_BLE_PERIPHERAL + {"gattChar", cynGattCharCommand, NULL, "Set SIG defined characteristic or Create your own"}, + {"gattService", cynGattServiceCommand, NULL, "Set SIG defined service or Create your own"}, + {"name", cynBLENameCommand, NULL, "Set/Get friendly for BLE module"}, + {"advStart", cynAdvertiseStartCommand, NULL, "Start broadcast advertise packet"}, + {"advStop", cynAdvertiseStopCommand, NULL, "Stop broadcast advertise packet"}, +#endif +#ifdef S120_BLE_CENTRAL + {"scan", cynBLEScanCommand, NULL, "Start/Stop(1/0) to scan BLE device"}, + {"connect", cynBLEConnectCommand, NULL, "Connect to specific BLE device by Device Name"}, +#endif + {"txPow", cynBLESetTxPowerCommand, NULL, "Set BLE tx power"}, + {"bleAddr", cynBLEAddressCommand, NULL, "Set/Get Bluetooth address"}, + {"update", cynBLEUpdateUUIDCommand, NULL, "Update value of specific characteristics"}, + {"readData", cynBLEReadDataCommand, NULL, "Read value of specific characteristics"}, + {NULL, NULL, NULL, NULL}, +};