fork test
Dependencies: BLE_API WIFI_API_32kRAM mbed nRF51822
Fork of NNN40_CLI by
CLI_Source/ble_cli.cpp
- Committer:
- gillwei7
- Date:
- 2015-09-11
- Revision:
- 0:5c195ab2f696
- Child:
- 3:38ec8ad317f4
File content as of revision 0:5c195ab2f696:
/** * 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}, };