
fork test
Dependencies: BLE_API WIFI_API_32kRAM mbed nRF51822
Fork of NNN40_CLI by
CLI_Source/ble_cli.cpp
- Committer:
- gillwei7
- Date:
- 2016-01-25
- Revision:
- 9:ff3ccba5dc16
- Parent:
- 8:291b32452887
- Child:
- 10:5f1fa331d07c
File content as of revision 9:ff3ccba5dc16:
/** * File: ble-cli.c * Description: BLE CLI commands used by all applications BLE of profile. * * Copyright 2014 by CYNTEC Corporation. All rights reserved. */ #include "ble_cli.h" // All #include define in ble_cli.h // Genral configuration parameters //#define BLE_DEBUG #define MAX_DEVNAME_LEN 32 #define CLI_FWVERION "DELTA_CLI_V1.8" #define MODULE_NAME "DFCM-NNN40-DT1R" // Advertising configuration parameters #define APP_ADV_INTERVAL 40 /**< The advertising interval (in units of ms). */ #define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout (in units of seconds). */ #define APP_ADV_INTERVAL_MAX 10240 // correspond to 10.24s #define APP_ADV_INTERVAL_MIN 20 // correspond to 20ms #define APP_ADV_DATA_OFFSET 2 // Offset for Advertising Data. //#define ADVERTISING_LED_PIN_NO LED1 // Peripheral mode operation parameters #define CLI_SERVICE_MAX_NUM 10 #define CLI_CHAR_MAX_NUM 10 #define MAX_VALUE_LENGTH 20 // Central mode operation parameters #define DEFAULT_SCAN_INTERVAL 500 #define DEFAULT_SCAN_WINDOW 400 #define DEFAULT_SCAN_TIMEOUT 0x0005 #define BLE_MAX_ADDRESS_NUMBER 10 #define TARGET_DEVNAME_LEN 30 typedef struct bufferGattChar { uint32_t props; UUID char_uuid; uint8_t value[MAX_VALUE_LENGTH]; uint16_t char_value_handle; uint8_t valueLength; } bufferGattChar_t; typedef struct bufferGattService { UUID ser_uuid; bufferGattChar_t bufferGattChar[CLI_CHAR_MAX_NUM]; //uint16_t service_handle; } bufferGattService_t; // gill 20150916 for scan typedef struct { const uint8_t * p_data; /**< Pointer to data. */ uint8_t data_len; /**< Length of data. */ } data_t; /*************** General parameters**********************************/ bufferGattService_t bufferService[CLI_SERVICE_MAX_NUM]; /* save entry services */ static GattCharacteristic *charAry[CLI_SERVICE_MAX_NUM][CLI_CHAR_MAX_NUM]; extern Serial console; BLE deltaBLE; //gill 0904 extern const char* cyntecCommandErrorNames[]; //extern uint8_t isValidGPIO(uint8_t); /*************** GATT Configuration parameters************************/ static bool connState = false; // gill 0904, define currently connecting state static uint8_t service_count=0; static uint8_t char_count=0; static uint16_t test_conn_handle; //Connection handle, assign after trigger onConnectionCallback //extern bool advState; // currently no use static Gap::Address_t saveAddr[BLE_MAX_ADDRESS_NUMBER]; // check in advertisementCallback static uint8_t bleDevInd; static char targetDevName[TARGET_DEVNAME_LEN]; // For connect target device //static char DEVICE_NAME[] = "nRF5x"; // default device name, same as defined in Gap.h static bool conn_action = false; // Gill add 20151015 static ble_gap_addr_t m_peer_addr; //DigitalOut led1(p7); //DigitalOut led2(p13); DigitalOut WriteInterrupt(p30); // used in OnDataWritten() /****************************************************** * Function Definitions ******************************************************/ //DiscoveredCharacteristic ledCharacteristic; void serviceDiscoveryCallback(const DiscoveredService *service) { console.printf("serviceDiscoveryCallback\r\n"); if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); } else { printf("S UUID-"); const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { printf("%02x", longUUIDBytes[i]); } printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); } } void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) { console.printf("characteristicDiscoveryCallback\r\n"); //printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast()); //if (characteristicP->getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */ //if(1) { // ledCharacteristic = *characteristicP; // } } void discoveryTerminationCallback(Gap::Handle_t connectionHandle) { printf("terminated SD for handle %u\r\n", connectionHandle); } void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) { test_conn_handle = params->handle; connState = true; #ifdef BLE_DEBUG console.printf("Connect: connState write to %d\r\n",connState); #endif // gill test //if (params->role == Gap::CENTRAL) { // //deltaBLE.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback); // deltaBLE.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, 0xa000, 0xa001); // } } void onTimeoutCallback(Gap::TimeoutSource_t source) { //led1 = !led1; } void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { //console.printf("connState:%d\r\n",connState); //Gap::GapState_t->connected = 0; connState = false; } void onDataWrittenCallback(const GattWriteCallbackParams *params) { #ifdef BLE_DEBUG console.printf("onDataWritten\r\n"); #endif // trigger Host GPIO interrupt WriteInterrupt = !WriteInterrupt; WriteInterrupt = !WriteInterrupt; #ifdef BLE_DEBUG console.printf("handle:%04X\r\n",params->handle); console.printf("conn_handle:%04X,writeOp:%d,offset:%04X\r\n",params->connHandle,params->writeOp,params->offset); #endif console.printf("w%d,",params->writeOp); const uint8_t* cpSerBaseUUID; const uint8_t* cpCharBaseUUID; // Find specific handle Characteristic for ( int i = 0 ; i < service_count ; i++ ) { for (int j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) { GattAttribute& tempValueAttr = charAry[i][j]->getValueAttribute(); if (tempValueAttr.getHandle()==params->handle) { #ifdef BLE_DEBUG console.printf("ser_count,char_count:%d,%d\r\n",i,j); #endif if (bufferService[i].ser_uuid.shortOrLong()==0) console.printf("%04X",bufferService[i].ser_uuid.getShortUUID()); else { cpSerBaseUUID = bufferService[i].ser_uuid.getBaseUUID(); for (int i=15; i>=0; i--) { console.printf("%02X",cpSerBaseUUID[i]); } } console.printf(","); //console.printf("char_uuid:"); if (bufferService[i].bufferGattChar[j].char_uuid.shortOrLong()==0) // Short UUID console.printf("%04X",bufferService[i].bufferGattChar[j].char_uuid.getShortUUID()); else { // Long UUID cpCharBaseUUID = bufferService[i].bufferGattChar[j].char_uuid.getBaseUUID(); for (int i=15; i>=0; i--) { console.printf("%02X",cpCharBaseUUID[i]); } } console.printf(","); break; } } } console.printf("%d,",params->len); for(int i=0; i<params->len; i++) { console.printf("%02X",params->data[i]); } console.printf(";\r\n"); } 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"); } static void cynAdvertiseStartCommand(void) { uint8_t argLen = 0; uint8_t *arg; 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(0,&argLen); advInterval = cyntecAtoiUint16( arg, argLen ); advTimeout = APP_ADV_TIMEOUT_IN_SECONDS; break; case 4: arg = cyntecGetCommandArgument(0,&argLen); advInterval = cyntecAtoiUint16( arg, argLen ); arg = cyntecGetCommandArgument(1,&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 BLE_DEBUG console.printf("advInterval:%d,advTimeout:%d",advInterval,advTimeout); #endif 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); #ifdef BLE_DEBUG console.printf("%08X,%s\r\n",err_code,bleName+APP_ADV_DATA_OFFSET); #endif deltaBLE.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); //deltaBLE.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); deltaBLE.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, bleName+APP_ADV_DATA_OFFSET, bleLen); deltaBLE.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); deltaBLE.gap().setAdvertisingInterval(advInterval); /* minisecond. */ deltaBLE.gap().setAdvertisingTimeout(advTimeout); /* second. */ deltaBLE.gap().startAdvertising(); cyntecPrintOk(); //nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO); } /**@brief Function for stop advertising. */ static void cynAdvertiseStopCommand(void) { deltaBLE.gap().stopAdvertising(); cyntecPrintOk(); //nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO); } //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; 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) { console.printf("\r\nOK;"); for(i = 0; i < cyntecGetTotalIndex()-12; i++) { console.printf("%c",argName2[11+i]); } console.printf("\r\n"); } else { console.printf("ERROR;%04X\r\n",err_code); } //APP_ERROR_CHECK(err_code); //#ifdef BLE_DEBUG //console.printf("\r\nSet BLE Name: "); // uint8_t i = 0; // for(i = 0; i < nameLen; i++) // { // console.printf("%c",argName[i]); // } //#endif } 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; } } static void cynBLEInfoCommand(void) { console.printf("\r\nOK;"); console.printf(CLI_FWVERION); console.printf(";"); 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) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } uint32_t err_code; uint8_t txLen=0; uint8_t *arg = cyntecGetCommandArgument(0,&txLen); 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); 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 cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); } clearBuffer(); // clear the commandState.buffer 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 BLE_DEBUG // 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; } static uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata) { uint32_t index = 0; const uint8_t * p_data; p_data = p_advdata->p_data; while (index < p_advdata->data_len) { uint8_t field_length = p_data[index]; uint8_t field_type = p_data[index+1]; if (field_type == type) { p_typedata->p_data = &p_data[index+2]; p_typedata->data_len = field_length-1; return NRF_SUCCESS; } index += field_length+1; } return NRF_ERROR_NOT_FOUND; } void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) { bool flagRepeat=false; Gap::Address_t newAddr[6]; memcpy(newAddr,params->peerAddr,6); for(int i=0; i<BLE_MAX_ADDRESS_NUMBER; i++) { if (memcmp(newAddr,saveAddr[i],6)==0) { #ifdef BLE_DEBUG console.printf("Repeated\r\n"); #endif flagRepeat = true; //return; } } #ifdef BLE_DEBUG console.printf("addr cmp result :%i\r\n",memcmp(newAddr,params->peerAddr,6)); console.printf("ADV data:%X,%i\r\n",&(params->advertisingData),params->advertisingDataLen); #endif data_t adv_data; data_t type_data; //Initialize advertisement report for parsing. adv_data.p_data = params->advertisingData; adv_data.data_len = params->advertisingDataLen; // Parsing Device Name uint32_t err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, &adv_data, &type_data); #ifdef BLE_DEBUG console.printf("error code:%X\r\n",err_code); console.printf("type_data.data_len:%i\r\n",type_data.data_len); #endif if (flagRepeat == false) { if (err_code == 0) { for (int i=0; i<type_data.data_len; i++) { console.printf("%c",type_data.p_data[i]); } //console.printf("\r\n"); } console.printf(",ADV,[%02X %02X %02X %02X %02X %02X],%d,%u\r\n",params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],params->rssi,params->type); memcpy(saveAddr[bleDevInd],params->peerAddr,6); bleDevInd++; } /* Check short name, not implemented */ //else // { // uint32_t err_code_2 = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, // &adv_data, // &type_data); // console.printf("error code:%X\r\n",err_code_2); // console.printf("%i\r\n",type_data.data_len); // console.printf("%s\r\n",type_data.p_data); // // } if (conn_action == true) { conn_action = false; deltaBLE.gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); } } /**@brief Function to start scanning. */ static void scan_start(void) { deltaBLE.gap().startScan(advertisementCallback); //APP_ERROR_CHECK(err_code); } static void scan_stop(void) { deltaBLE.stopScan(); //APP_ERROR_CHECK(err_code); } // gill 20150916 modify static void cynBLEScanCommand(void) { uint16_t setInterval = DEFAULT_SCAN_INTERVAL; uint16_t setWindow = DEFAULT_SCAN_WINDOW; uint16_t setTimeout = DEFAULT_SCAN_TIMEOUT; if (cyntecGetCommandTokenCnt()!= 2 & cyntecGetCommandTokenCnt()!= 5) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } // If user input scan parameters, overwrite the default value if (cyntecGetCommandTokenCnt()== 5) { uint8_t argLen = 0; uint8_t *arg = cyntecGetCommandArgument(0,&argLen); setInterval = cyntecAtoiUint16( arg, argLen ); arg = cyntecGetCommandArgument(1,&argLen); setWindow = cyntecAtoiUint16( arg, argLen ); arg = cyntecGetCommandArgument(2,&argLen); setTimeout = cyntecAtoiUint16( arg, argLen ); } #ifdef BLE_DEBUG console.printf("Interval:%d,Window:%d,timeout:%d\r\n",setInterval,setWindow,setTimeout); #endif memset(saveAddr,0,sizeof(saveAddr)); // Clear saving address set //deltaBLE.gap().setScanParams(setInterval,setWindow,setTimeout,false); deltaBLE.gap().setScanInterval(setInterval); deltaBLE.gap().setScanWindow(setWindow); deltaBLE.gap().setScanTimeout(setTimeout); console.printf("Start Scan\r\n"); scan_start(); } static void cynBLEScanStopCommand(void) { console.printf("\r\nStop Scanning\r\n"); scan_stop(); } static void cynBLEConnectCommand(void) { if (cyntecGetCommandTokenCnt() != 3) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } 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'; // } memset( targetDevName , 0, TARGET_DEVNAME_LEN); memcpy( targetDevName, argDevName, devNameLen); #ifdef BLE_DEBUG console.printf("Search for device name:%s\r\n",argDevName); console.printf("Target:%s\r\n",targetDevName); #endif conn_action = true; scan_start(); } static void cynBLEDisconnectCommand(void) { ble_error_t err_code; err_code = deltaBLE.gap().disconnect(Gap::REMOTE_USER_TERMINATED_CONNECTION); //err_code = sd_ble_gap_disconnect(test_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); //err_code = sd_ble_gap_connect_cancel(); // No function defined currently #ifdef BLE_DEBUG console.printf("Error:%d\r\n",err_code); #endif cyntecPrintOk(); } //uint8_t isValidGPIO(uint8_t num) //{ // uint8_t cfgPin[] = {0,4,5,6,7,13,21,23,24,25,29,30,31}; // 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(); } void triggerRead(const GattReadCallbackParams *response) { //if (response->handle == ledCharacteristic.getValueHandle()) { #if DUMP_READ_DATA printf("triggerToggledWrite: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len); for (unsigned index = 0; index < response->len; index++) { printf("%c[%02x]", response->data[index], response->data[index]); } printf("\r\n"); #endif // // uint8_t toggledValue = response->data[0] ^ 0x1; // ledCharacteristic.write(1, &toggledValue); // } } static void cynBLEUpdateUUIDCommand(void) { if (cyntecGetCommandTokenCnt() != 5) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } UUID buf_ser_uuid ; uint8_t bufferUuidVs[16]; UUID buf_char_uuid; uint8_t bufVal[MAX_VALUE_LENGTH] = {0}; uint16_t valueLen = 0; bool readmatchFlag = false; uint8_t argLen = 0; uint8_t *arg = cyntecGetCommandArgument(0,&argLen); // Handle input parameter - Service UUID if ( argLen == 6 && arg[0] == '0' && arg[1] == 'x') { buf_ser_uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); } if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) { for (uint8_t i=0; i<16; i++) { bufferUuidVs[i] = cyntecArgToUint8( (arg + 2+2*i), 2); } buf_ser_uuid.setupLong(bufferUuidVs); } // Handle input parameter - Characteristic UUID argLen = 0; arg = cyntecGetCommandArgument(1,&argLen); if ( argLen == 6 && arg[0] == '0' && arg[1] == 'x') { buf_char_uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); } if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) { for (uint8_t i=0; i<16; i++) { bufferUuidVs[i] = cyntecArgToUint8( (arg + 2+2*i), 2); } buf_char_uuid.setupLong(bufferUuidVs); } // Input value arg = cyntecGetCommandArgument(2,&argLen); valueLen = (argLen-2)/2; // uint8_t to uint16_t transform for (int i=0 ; i < (argLen-2)/2; i++) { bufVal[i] = cyntecArgToUint8(arg+2*(i+1), 2); } for ( int i = 0 ; i < service_count ; i++ ) { if ( (bufferService[i].ser_uuid == buf_ser_uuid) & (readmatchFlag == false)) { for (int j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) { if (( bufferService[i].bufferGattChar[j].char_uuid == buf_char_uuid)& (readmatchFlag == false)) { GattAttribute& valueAttr = charAry[i][j]->getValueAttribute(); ble_error_t err; if (!connState) err = deltaBLE.gattServer().write(valueAttr.getHandle(),bufVal,valueLen,true); else err = deltaBLE.gattServer().write(test_conn_handle,valueAttr.getHandle(),bufVal,valueLen,false); #ifdef BLE_DEBUG console.printf("Write ERR:%i\r\n",err); #endif console.printf("\r\nOK;"); for (uint16_t n=0; n<valueLen; n++) { console.printf("%02X",bufVal[n]); } console.printf("\r\n"); readmatchFlag = true; return; } } } } // no matched case, can not read if (readmatchFlag == false) { cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); } } static void cynBLEReadDataCommand(void) { #ifdef BLE_DEBUG printf("Saved Char:\r\n"); for (int i=0; i<service_count; i++) { console.printf("ser_uuid:%04X",bufferService[service_count-1].ser_uuid.getShortUUID()); for (int j=0; j<CLI_CHAR_MAX_NUM; j++) { printf(" %i,char_uuid%04X,",j,bufferService[service_count-1].bufferGattChar[char_count-1].char_uuid.getShortUUID()); printf("len%d,",bufferService[service_count-1].bufferGattChar[char_count-1].valueLength); printf("val%02X;",bufferService[service_count-1].bufferGattChar[char_count-1].value[0]); } } printf("\r\n"); #endif if (cyntecGetCommandTokenCnt() != 4) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } UUID buf_ser_uuid ; uint8_t bufferUuidVs[16]; UUID buf_char_uuid; uint8_t bufVal[MAX_VALUE_LENGTH] = {0}; uint16_t valueLen=0; uint16_t * valueLenPtr; bool readmatchFlag = false; uint8_t argLen = 0; uint8_t *arg = cyntecGetCommandArgument(0,&argLen); // Handle input parameter - Service UUID if ( argLen == 6 && arg[0] == '0' && arg[1] == 'x') { buf_ser_uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); } if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) { for (uint8_t i=0; i<16; i++) { bufferUuidVs[i] = cyntecArgToUint8( (arg + 2+2*i), 2); } buf_ser_uuid.setupLong(bufferUuidVs); } // Handle input parameter - Characteristic UUID argLen = 0; arg = cyntecGetCommandArgument(1,&argLen); if ( argLen == 6 && arg[0] == '0' && arg[1] == 'x') { buf_char_uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); } if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) { for (uint8_t i=0; i<16; i++) { bufferUuidVs[i] = cyntecArgToUint8( (arg + 2+2*i), 2); } buf_char_uuid.setupLong(bufferUuidVs); } for ( int i = 0 ; i < service_count ; i++ ) { if ( (bufferService[i].ser_uuid == buf_ser_uuid) & (readmatchFlag == false)) { for (int j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) { if (( bufferService[i].bufferGattChar[j].char_uuid == buf_char_uuid)& (readmatchFlag == false)) { GattAttribute& valueAttr = charAry[i][j]->getValueAttribute(); valueLenPtr = valueAttr.getLengthPtr(); valueLen = valueAttr.getLength(); ble_error_t err = deltaBLE.gattServer().read(valueAttr.getHandle(),bufVal,valueLenPtr); #ifdef BLE_DEBUG console.printf("Read ERR:%i\r\n",err); #endif console.printf("\r\nOK;"); console.printf("0x"); for (uint16_t n=0; n<valueLen; n++) { console.printf("%02X",bufVal[n]); } console.printf("\r\n"); readmatchFlag = true; return; } } } } // no matched case, can not read if (readmatchFlag == false) { cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); } } static void cynGattCharCommand(void) { uint8_t i; uint8_t valueLengthBuffer; if (cyntecGetCommandTokenCnt() != 5) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } /* handle parameter - UUID */ /* Only support 16-bit or 128-bit UUID type */ uint8_t argLen = 0; uint8_t *arg = cyntecGetCommandArgument(0,&argLen); if (arg[0] != '0' || arg[1] != 'x' || (argLen != 6 && argLen != 34)) { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); return; } /* len: 6 => 0xXXXX */ if ( argLen == 6 && arg[0] == '0' && arg[1] == 'x') { UUID::ShortUUIDBytes_t buffer_uuid_short; buffer_uuid_short = cyntecArgToUint16( (arg + 2), (argLen - 2)); UUID uuid_short(buffer_uuid_short); bufferService[service_count-1].bufferGattChar[char_count].char_uuid = uuid_short; } if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) { // Initialize LongUUIDBytes_t, then use default constructor to setupLong(longUUID) UUID::LongUUIDBytes_t buffer_uuid_vs; for (uint8_t i=0; i<16; i++) { buffer_uuid_vs[i] = cyntecArgToUint8( (arg + 2+2*i), 2); } bufferService[service_count-1].bufferGattChar[char_count].char_uuid.setupLong(buffer_uuid_vs); } /* handle 3rd parameter - attribute mode */ argLen = 0; arg = cyntecGetCommandArgument(1,&argLen); if (arg[0] != '0' || arg[1] != 'x' ) { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); return; } uint32_t prop = cyntecHexToUint32(arg+2,argLen-2); /* 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; } valueLengthBuffer = (argLen-2)/2; memset(bufferService[service_count-1].bufferGattChar[char_count].value,0,MAX_VALUE_LENGTH); for (i=0 ; i < (argLen-2)/2; i++) { bufferService[service_count-1].bufferGattChar[char_count].value[i] = cyntecArgToUint8(arg+2*(i+1), 2); //console.printf("%02X ",bufferService[service_count-1].bufferGattChar[char_count].value[i]); } #ifdef BLE_DEBUG console.printf("valueLengthBuffer:%d\r\n",valueLengthBuffer); console.printf("value:"); for (i=0 ; i < valueLengthBuffer; i++) { console.printf("%02X",bufferService[service_count-1].bufferGattChar[char_count].value[i]); } #endif bufferService[service_count-1].bufferGattChar[char_count].valueLength = valueLengthBuffer; bufferService[service_count-1].bufferGattChar[char_count].props = prop; //bufferService[service_count-1].bufferGattChar[char_count].char_value_handle = testHandle; if (char_count>CLI_CHAR_MAX_NUM) { cyntecPrintError(CYNTEC_CMD_ERR_CALL_FAIL); #ifdef BLE_DEBUG console.printf("Error: char_count>CLI_CHAR_MAX_NUM\r\n"); #endif return; } cyntecPrintOk(); char_count++; } static void cynRegServiceCommand(void) { //GattCharacteristic *charAry[char_count]; //GattCharacteristic **charAry; //charAry = new GattCharacteristic *[char_count]; #ifdef BLE_DEBUG console.printf("Current char_count:%d\r\n",char_count); console.printf("Current service_count:%d\r\n",service_count); #endif for (uint8_t i=0; i<char_count; i++) { charAry[service_count-1][i] = new GattCharacteristic ( bufferService[service_count-1].bufferGattChar[i].char_uuid, bufferService[service_count-1].bufferGattChar[i].value, bufferService[service_count-1].bufferGattChar[i].valueLength, MAX_VALUE_LENGTH, bufferService[service_count-1].bufferGattChar[i].props ); } GattService newService(bufferService[service_count-1].ser_uuid, charAry[service_count-1], char_count ); ble_error_t err_code; err_code = deltaBLE.addService(newService); if (err_code != 0) { #ifdef BLE_DEBUG console.printf("addService error:%d\r\n",err_code); #endif cyntecPrintError(CYNTEC_CMD_ERR_CALL_FAIL); } else cyntecPrintOk(); //char_count = 0; // already did in gattService } static void cynGattServiceCommand(void) { if (cyntecGetCommandTokenCnt() != 3) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } /* 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') { UUID::ShortUUIDBytes_t buffer_uuid_short; buffer_uuid_short = cyntecArgToUint16( (arg + 2), (argLen - 2)); #ifdef BLE_DEBUG console.printf("%4X",buffer_uuid_short); #endif UUID uuid_short(buffer_uuid_short); bufferService[service_count].ser_uuid = uuid_short; //buffer_uuid = cyntecArgToUint16( (arg + 2), (argLen - 2)); } /* Service uuid is 128 bits */ if ( argLen == 34 && arg[0] == '0' && arg[1] == 'x' ) { // Initialize LongUUIDBytes_t, then use default constructor to setupLong(longUUID) UUID::LongUUIDBytes_t buffer_uuid_vs; for (uint8_t i=0; i<16; i++) { buffer_uuid_vs[i] = cyntecArgToUint8( (arg + 2+2*i), 2); #ifdef BLE_DEBUG console.printf("%2X ",buffer_uuid_vs[i]); #endif } UUID uuid_long(buffer_uuid_vs); bufferService[service_count].ser_uuid = uuid_long; } cyntecPrintOk(); service_count++; char_count = 0; } static void cynBLEInitCommand(void) { deltaBLE.init(); deltaBLE.onDisconnection(disconnectionCallback); deltaBLE.onConnection(onConnectionCallback); deltaBLE.onTimeout(onTimeoutCallback); deltaBLE.gattServer().onDataRead(triggerRead); cyntecPrintOk(); } static void cynBLEDataIntCommand(void) { cyntecPrintOk(); deltaBLE.gattServer().onDataWritten().add(onDataWrittenCallback); } static void cynBLEDisDataIntCommand(void) { cyntecPrintOk(); deltaBLE.gattServer().onDataWritten().detach(onDataWrittenCallback); } #ifdef BLE_DEBUG static void cynBLETestCommand(void) { // gill test 1021 uint8_t bufVal[20] = {0}; //uint8_t valWrite[2] = {0x22,0x33}; //uint16_t bufhandle = 0x0001; //uint8_t valRead[2] = {0,0}; // uint16_t handle = charAry[0][0]->getValueHandle(); // No used? GattAttribute& valueAttr = charAry[0][0]->getValueAttribute(); //valueAttr.setHandle(bufhandle); console.printf("Handle:%04X ",valueAttr.getHandle()); console.printf("UUID:%04X ",valueAttr.getUUID().getShortUUID()); uint16_t* valueLenPtr = valueAttr.getLengthPtr(); deltaBLE.gattServer().read(valueAttr.getHandle(),bufVal,valueLenPtr); console.printf("gatt val[0][1]:%02X %02X\r\n",bufVal[0],bufVal[1]); } #endif CyntecCommandEntry bleCommandSets[] = { // General #ifdef BLE_DEBUG {"TEST", cynBLETestCommand, NULL, "test"}, #endif // #if SIMPLE_CMD_NAME {"INT", cynBLEInitCommand, NULL, "Init BLE stack"}, {"GIO", cynBLEGPIOCommand, NULL, "Config gpio, Usage: <GPIO NO> <set|clear>"}, {"SLP", cynBLESystemOffCommand, NULL, "System off mode, Usage: <GPIO NO>"}, {"RST", cynResetCommand, NULL, "Soft reset"}, {"INF", cynBLEInfoCommand, NULL, "Module information"}, {"POW", cynBLESetTxPowerCommand, NULL, "Set BLE tx power, Usage: <POW setting>"}, {"NAM", cynBLENameCommand, NULL, "Set/Get friendly for BLE module, Usage: <name>"}, // GATT {"GRS", cynRegServiceCommand, NULL, "Register standby service"}, {"GAC", cynGattCharCommand, NULL, "Set SIG defined characteristic or Create your own"}, {"GAS", cynGattServiceCommand, NULL, "Set SIG defined service or Create your own"}, {"ADS", cynAdvertiseStartCommand, NULL, "Start broadcast advertise packet"}, {"ADP", cynAdvertiseStopCommand, NULL, "Stop broadcast advertise packet"}, {"SCS", cynBLEScanCommand, NULL, "Start to scan BLE device"}, {"SCP", cynBLEScanStopCommand, NULL, "Stop to scan BLE device"}, {"CON", cynBLEConnectCommand, NULL, "Connect to specific BLE device by Device Name"}, {"DCN", cynBLEDisconnectCommand, NULL, "Disconnection, Usage: cynb disconn"}, {"ADR", cynBLEAddressCommand, NULL, "Set/Get Bluetooth address"}, {"WRT", cynBLEUpdateUUIDCommand, NULL, "Update value of specific characteristics"}, {"RED", cynBLEReadDataCommand, NULL, "Read value of specific characteristics"}, {"EDI", cynBLEDataIntCommand, NULL, "Trigger remote write detection, give interrupt to Host."}, {"DDI", cynBLEDisDataIntCommand, NULL, "Disable remote write detection."}, {NULL, NULL, NULL, NULL}, #else {"init", cynBLEInitCommand, NULL, "Init BLE stack"}, {"gpio", cynBLEGPIOCommand, NULL, "Config gpio, Usage: <GPIO NO> <set|clear>"}, {"sleep", cynBLESystemOffCommand, NULL, "System off mode, Usage: <GPIO NO>"}, {"reset", cynResetCommand, NULL, "Soft reset"}, {"info", cynBLEInfoCommand, NULL, "Get module information"}, {"txPow", cynBLESetTxPowerCommand, NULL, "Set BLE tx power, Usage: <POWER>"}, {"name", cynBLENameCommand, NULL, "Set/Get friendly for BLE module, Usage: *<NAME>*"}, // GATT {"regService", cynRegServiceCommand, NULL, "Register standby service"}, {"gattChar", cynGattCharCommand, NULL, "Set SIG defined characteristic or Create your own,Usage: <CHAR UUID> <PROPS> <VALUE>"}, {"gattService", cynGattServiceCommand, NULL, "Set SIG defined service or Create your own,Usage: <SERVICE UUID>"}, {"advStart", cynAdvertiseStartCommand, NULL, "Start broadcast advertise packet,Usage: <INTERVAL> <WINDOW>"}, {"advStop", cynAdvertiseStopCommand, NULL, "Stop broadcast advertise packet"}, {"scanStart", cynBLEScanCommand, NULL, "Start to scan BLE device, Usage: <INTERVAL> <WINDOW> <TIMEOUT>"}, {"scanStop", cynBLEScanStopCommand, NULL, "Stop to scan BLE device"}, {"connect", cynBLEConnectCommand, NULL, "Connect to specific BLE device by Device Name, Usage: <NAME>"}, {"disconn", cynBLEDisconnectCommand, NULL, "Disconnection, Usage: cynb disconn"}, {"bleAddr", cynBLEAddressCommand, NULL, "Set/Get Bluetooth address, Usage: <ADDR>"}, {"update", cynBLEUpdateUUIDCommand, NULL, "Update value of specific characteristics, Usage: <UUID> <VALUE>"}, {"readData", cynBLEReadDataCommand, NULL, "Read value of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {"enInt", cynBLEDataIntCommand, NULL, "Trigger remote write detection, give interrupt to Host."}, {"disInt", cynBLEDisDataIntCommand, NULL, "Disable remote write detection."}, {NULL, NULL, NULL, NULL}, #endif };