This CLI (Command Line Interface) is based mbed-os. Both NNN50 and NQ620 are supported.
Fork of NNN40_CLI by
BLE CLI Document can be downloaded here .
Note that when evaluate using Windows PC as the host, the Serial driver need to be installed in advance. The instruction is explained in the link below
https://developer.mbed.org/handbook/Windows-serial-configuration
Once installed, a device called 'mbed Serial Port (COM#)' should be recognized in Device Manager, as shown below
Please open the com port at 115200 8n1 as default
CLI_Source/ble_cli.cpp
- Committer:
- tsungta
- Date:
- 2017-05-12
- Revision:
- 25:1423b707b705
- Parent:
- 24:838a0b25934b
File content as of revision 25:1423b707b705:
/** * 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 0 #define MAX_DEVNAME_LEN 32 #define CLI_FWVERION "DELTA_CLI_V1.18" //0920 Silvia modify #if defined(TARGET_DELTA_DFBM_NQ620) #define MODULE_NAME "DFBM-NQ620" #else if defined(TARGET_DELTA_DFCM_NNN50) #define MODULE_NAME "DFCM-NNN50" #endif //0920 Silvia modify // 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_TIMEOUT_LIMITED_MAX 16383 //1102 Silvia add #define APP_ADV_TIMEOUT_LIMITED_MIN 1 //1102 Silvia add #define APP_ADV_DATA_OFFSET 2 // Offset for Advertising Data. //#define ADVERTISING_LED_PIN_NO LED1 //1102 Silvia add //Scanning configuration parameters #define BLE_SCAN_INTERVAL_LIMITED_MAX 10240 #define BLE_SCAN_INTERVAL_LIMITED_MIN 3 #define BLE_SCAN_WINDOW_LIMITED_MAX 10240 #define BLE_SCAN_WINDOW_LIMITED_MIN 3 #define BLE_SCAN_TIMEOUT_LIMITED_MAX 16383 #define BLE_SCAN_TIMEOUT_LIMITED_MIN 1 // 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 { uint8_t props; UUID char_uuid; uint8_t value[MAX_VALUE_LENGTH]; uint16_t char_value_handle; uint16_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]; DiscoveredService discoverServiceArr[CLI_SERVICE_MAX_NUM]; //Silvia add DiscoveredCharacteristic discoverCharArr[CLI_SERVICE_MAX_NUM][CLI_CHAR_MAX_NUM]; //Silvia add extern Serial console; BLE deltaBLE; //gill 0904 extern const char* cyntecCommandErrorNames[]; /*************** 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 uint8_t discoverService_count=0; //Silvia add static uint8_t discoverChar_count=0; //Silvia add 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 const unsigned ADDR_LEN = BLEProtocol::ADDR_LEN; //Silvia add, Length (in octets) of the BLE MAC address static BLEProtocol::AddressBytes_t targetAddr; //Silvia add, For connect target device 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 BLEWriteInt(p13); // 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) { console.printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); } else { console.printf("S UUID-"); const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { console.printf("%02x", longUUIDBytes[i]); } console.printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); } discoverServiceArr[discoverService_count] = *service; discoverService_count++; discoverChar_count = 0; } void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) { //Silvia modify if (characteristicP->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { console.printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast()); } else { console.printf(" C UUID-"); const uint8_t *longUUIDBytes = characteristicP->getUUID().getBaseUUID(); for (unsigned i = (UUID::LENGTH_OF_LONG_UUID) - 1; i < UUID::LENGTH_OF_LONG_UUID; i--) { console.printf("%02x ", longUUIDBytes[i]); } console.printf(" valueAttr[%u] props[%x]\r\n", characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast()); // uvCharacteristic = *characteristicP; } discoverCharArr[discoverService_count - 1][discoverChar_count] = *characteristicP; discoverChar_count++; } void discoveryTerminationCallback(Gap::Handle_t connectionHandle) { console.printf("terminated SD for handle %u\r\n", connectionHandle); } void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) { test_conn_handle = params->handle; connState = true; #if BLE_DEBUG console.printf("Connect: connState write to %d\r\n",connState); #endif //Silvia modify if (params->role == Gap::CENTRAL) { deltaBLE.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback); deltaBLE.gattClient().launchServiceDiscovery(test_conn_handle, serviceDiscoveryCallback, characteristicDiscoveryCallback); } //Silvia modify } void onTimeoutCallback(Gap::TimeoutSource_t source) { //led1 = !led1; //Silvia add switch (source) { case Gap::TIMEOUT_SRC_ADVERTISING: console.printf("Advertising timeout\r\n"); break; case Gap::TIMEOUT_SRC_SECURITY_REQUEST: console.printf("Security request timeout\r\n"); break; case Gap::TIMEOUT_SRC_SCAN: console.printf("Scanning timeout\r\n"); break; case Gap::TIMEOUT_SRC_CONN: console.printf("Connection timeout\r\n"); break; } //Silvia add } void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { console.printf("Disconnected\r\n"); //Silvia add //console.printf("connState:%d\r\n",connState); //Gap::GapState_t->connected = 0; connState = false; } void onDataWrittenCallback(const GattWriteCallbackParams *params) { #if BLE_DEBUG console.printf("onDataWritten\r\n"); #endif // trigger Host GPIO interrupt BLEWriteInt = !BLEWriteInt; BLEWriteInt = !BLEWriteInt; #if 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) { #if 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(","); // update char value length bufferService[i].bufferGattChar[j].valueLength = params->len; 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 < APP_ADV_TIMEOUT_LIMITED_MIN | advTimeout > APP_ADV_TIMEOUT_LIMITED_MAX ) { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); return; } #if 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); #if 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); } //Silvia modify static void cynBLENameCommand(void) { uint8_t nameLen = 0; // Name char number, max is TARGET_DEVNAME_LEN uint8_t nameLenCharNum = 0; // Name length number is 1 or 2 uint8_t *nameLeng = cyntecGetCommandArgument(0,&nameLenCharNum); nameLen = cyntecAtoi(nameLeng,nameLenCharNum); #ifdef BLE_DEUG console.printf("nameLenCharNum:%i\r\nOK;",nameLenCharNum); console.printf("nameLen:%i\r\nOK;",nameLen); #endif uint8_t bleName[BLE_GAP_DEVNAME_MAX_LEN] = {"\0"}; uint16_t bleLen = BLE_GAP_DEVNAME_MAX_LEN - APP_ADV_DATA_OFFSET; ble_gap_conn_sec_mode_t sec_mode; uint32_t err_code; uint8_t * argName2 = cyntecGetCommandTotalBuffer(); // Get name string if (cyntecGetCommandTokenCnt() == 2) { err_code = sd_ble_gap_device_name_get(&bleName[APP_ADV_DATA_OFFSET], &bleLen); console.printf("\r\nOK;"); console.printf("%s",bleName+APP_ADV_DATA_OFFSET); console.printf(";\r\n"); } // Set name if (cyntecGetCommandTokenCnt() >= 3) { if (nameLen>TARGET_DEVNAME_LEN || nameLen <=0) cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *) &argName2[11+nameLenCharNum], (uint16_t) nameLen);//(uint16_t) (cyntecGetTotalIndex()-11-nameLenCharNum)); if (err_code == NRF_SUCCESS) cyntecPrintOk(); else cyntecPrintError(CYNTEC_CMD_ERR_CALL_FAIL); #ifdef BLE_DEUG console.printf("LengNum:%i,string:%s,index:%i\r\n",nameLenCharNum,(const uint8_t *) &argName2[11+nameLenCharNum],cyntecGetTotalIndex()); #endif } } static void cynBLEInfoCommand(void) { console.printf("\r\nOK;%s;%s\r\n\r\n", CLI_FWVERION, MODULE_NAME); } //Silvia modify /**@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); bool inputSwitch = false; // if find matched case in TxPow, assign true #if defined(TARGET_DELTA_DFBM_NQ620) const uint8_t NUM_TXPOW = 7; int8_t validTxPow[NUM_TXPOW] = {-20, -16, -12, -8, -4, 0, 4}; #else if defined(TARGET_DELTA_DFCM_NNN50) const uint8_t NUM_TXPOW = 9; int8_t validTxPow[NUM_TXPOW] = {-40, -30, -20, -16, -12, -8, -4, 0, 4}; #endif uint8_t i; int8_t setValue; if ( arg != NULL ) { #if defined(TARGET_DELTA_DFBM_NQ620) setValue = atoi((const char *)arg); #else if defined(TARGET_DELTA_DFCM_NNN50) setValue = cyntecAtoInt(arg);//work around for NNN50 since somehow atoi doesn't work properly #endif 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; } //#if 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("OK;[%02X %02X %02X %02X %02X %02X];\r\n", 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) { //Silvia modify Gap::Address_t newAddr[6]; memcpy(newAddr,params->peerAddr,6); if (conn_action == true) { conn_action = false; if (memcmp(targetAddr,newAddr,6)==0) { deltaBLE.gap().connect(params->peerAddr, Gap::ADDR_TYPE_PUBLIC, NULL, NULL); //0920 Silvia change address type return; } } else { bool flagRepeat=false; for(int i=0; i<BLE_MAX_ADDRESS_NUMBER; i++) { if (memcmp(newAddr,saveAddr[i],6)==0) { #if BLE_DEBUG console.printf("Repeated\r\n"); #endif flagRepeat = true; //return; } } #if 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); #if 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); // // } } /**@brief Function to start scanning. */ static void scan_start(void) { memset(saveAddr,0,sizeof(saveAddr)); //Silvia add, Clear saving address set 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 ); } //1102 Silvia modify if ( setInterval < BLE_SCAN_INTERVAL_LIMITED_MIN | setInterval > BLE_SCAN_INTERVAL_LIMITED_MAX | setWindow < BLE_SCAN_WINDOW_LIMITED_MIN | setWindow > BLE_SCAN_WINDOW_LIMITED_MAX | setTimeout > BLE_SCAN_TIMEOUT_LIMITED_MAX | (setTimeout < BLE_SCAN_TIMEOUT_LIMITED_MIN && setTimeout != 0 ) | (setInterval < setWindow)) { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); return; } #if 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) { //Silvia modify for specific address if (cyntecGetCommandTokenCnt() != 3) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } uint8_t argLen = 0; uint8_t *arg = cyntecGetCommandArgument(0, &argLen); ble_error_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; } memset(targetAddr,0,sizeof(targetAddr)); for ( i = 1 ; i < 7 ; i++) { addr = cyntecArgToUint8(arg+2*i, 2); /* 5 - (i-1) */ targetAddr[6-i] = addr; } for(int i=0; i<BLE_MAX_ADDRESS_NUMBER; i++) { if (memcmp(targetAddr,saveAddr[i],6)==0) { err_code = deltaBLE.gap().connect(targetAddr, Gap::ADDR_TYPE_PUBLIC, NULL, NULL); //0920 Silvia change address type if (err_code != 0) { console.printf("Error:%d\r\n",err_code); } else { cyntecPrintOk(); } return; } } conn_action = true; scan_start(); } else { //argLen != 14 cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_SYNTAX_ERROR); return; } //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); //#if 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 #if BLE_DEBUG console.printf("Error:%d\r\n",err_code); #endif cyntecPrintOk(); } static void cynBLESystemOffCommand(void) { if (cyntecGetCommandTokenCnt() == 3) { uint8_t argLen = 0; uint8_t *arg = cyntecGetCommandArgument(0,&argLen); uint8_t gpioNum = cyntecAtoi( arg, argLen ); if (gpioNum < 1 || gpioNum > 4) { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); return; } if (gpioNum == 1) nrf_gpio_cfg_sense_input(BUTTON1, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); #if defined(TARGET_DELTA_DFBM_NQ620)//Tsungta, temp use only, will be fix in NNN50 else if (gpioNum == 2) nrf_gpio_cfg_sense_input(BUTTON2, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); else if (gpioNum == 3) nrf_gpio_cfg_sense_input(BUTTON3, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); else if (gpioNum == 4) nrf_gpio_cfg_sense_input(BUTTON4, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); #endif else { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); return; } 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); return; } 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 (gpioNum < 1 || gpioNum > 4) { 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 ) { if (gpioNum == 1) { DigitalOut CLI_LED(LED1); CLI_LED = 1; } else if (gpioNum == 2) { DigitalOut CLI_LED(LED2); CLI_LED = 1; } else if (gpioNum == 3) { DigitalOut CLI_LED(LED3); CLI_LED = 1; } else if (gpioNum == 4) { DigitalOut CLI_LED(LED4); CLI_LED = 1; } cyntecPrintOk(); } else if ( cyntecStrCmp(action,(unsigned char *)"clear",argLen) == 1 ) { if (gpioNum == 1) { DigitalOut CLI_LED(LED1); CLI_LED = 0; } else if (gpioNum == 2) { DigitalOut CLI_LED(LED2); CLI_LED = 0; } else if (gpioNum == 3) { DigitalOut CLI_LED(LED3); CLI_LED = 0; } else if (gpioNum == 4) { DigitalOut CLI_LED(LED4); CLI_LED = 0; } 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); // } } //Silvia modify void centralReadCallback(const GattReadCallbackParams *response) { // printf("centralReadCallback Handle: %d\r\n", response->handle); for (unsigned index = 0; index < response->len; index++) { console.printf("[%02x]", response->data[index]); } console.printf("\r\n"); } void centralWriteCallback(const GattWriteCallbackParams *response) { // printf("centralWriteCallback: %d\r\n", response->len); for (unsigned index = 0; index < response->len; index++) { console.printf("[%02x]", response->data[index]); } console.printf("\r\n"); } void centralHvxCallback(const GattHVXCallbackParams *response) { // printf("centralHvxCallback handle %u, type %02x, len %u\r\n", response->handle, response->type, response->len); for (unsigned index = 0; index < response->len; index++) { console.printf("[%02x]", response->data[index]); } console.printf("\r\n"); } //Silvia modify static void cynBLEUpdateDataCommand(void) { if (cyntecGetCommandTokenCnt() != 6) { 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 Type arg = cyntecGetCommandArgument(2,&argLen); uint8_t type = *arg; //type = cyntecArgToUint8(arg,2); //printf("type:%d\r\n",type); if(type != '0' && type != '1') // Original Data { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); } // Input value arg = cyntecGetCommandArgument(3,&argLen); if(type == '0') // Original Data { valueLen = argLen; memcpy(bufVal,arg,argLen); } if(type == '1') // Char Data { valueLen = (argLen-2)/2; // uint8_t to uint16_t transform for (int i=0 ; i < valueLen; i++) { bufVal[i] = cyntecArgToUint8(arg+2+2*i,2); } } #if BLE_DEBUG printf("type:%i,bufVal:",type); printf("valueLength:%i\r\n",valueLen); for (int i=0 ; i < valueLen; i++) { printf("%02X ",bufVal[i]); } printf("\r\n"); #endif 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); // update valueLength bufferService[i].bufferGattChar[j].valueLength = valueLen; #if BLE_DEBUG console.printf("Write ERR:%i\r\n",err); printf("valueLen:%i\r\n",valueLen); #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) { //#if 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 = bufferService[i].bufferGattChar[j].valueLength; uint16_t * valueLenPtr = &bufferService[i].bufferGattChar[j].valueLength; ble_error_t err = deltaBLE.gattServer().read(valueAttr.getHandle(),bufVal,valueLenPtr); #if BLE_DEBUG console.printf("Read ERR:%i\r\n",err); printf("valueLen:%i\r\n",valueLen); #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; } //Silvia add if (service_count == 0) { cyntecPrintError(CYNTEC_CMD_ERR_INVALID_STATE_TO_PERFORM_OPERATION); return; } //Silvia add if (char_count >= CLI_CHAR_MAX_NUM) { cyntecPrintError(CYNTEC_CMD_ERR_CALL_FAIL); #if BLE_DEBUG console.printf("Error: char_count>CLI_CHAR_MAX_NUM\r\n"); #endif 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; } uint8_t prop = cyntecArgToUint8(arg+2,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]); } #if BLE_DEBUG printf("prop:%02X\r\n",prop); 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; cyntecPrintOk(); char_count++; } static void cynRegServiceCommand(void) { //GattCharacteristic *charAry[char_count]; //GattCharacteristic **charAry; //charAry = new GattCharacteristic *[char_count]; #if 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) { #if 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)); #if 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); #if 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; } /*Tsungta, @0913 modify to compatiable with mbed os 5.0*/ //#include <mbed-events/events.h> void onBleInitError(BLE &ble, ble_error_t error) { (void)ble; (void)error; /* Initialization error handling should go here */ } void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { } static EventQueue eventQueue( /* event count */ 16 * /* event size */ 32 ); void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { BLE &deltaBLE = BLE::Instance(); eventQueue.call(Callback<void()>(&deltaBLE, &BLE::processEvents)); } void cynBLEInitCommand(void) { BLE &deltaBLE = BLE::Instance(); deltaBLE.onEventsToProcess(scheduleBleEventsProcessing); deltaBLE.init(bleInitComplete); deltaBLE.onDisconnection(disconnectionCallback); deltaBLE.onConnection(onConnectionCallback); deltaBLE.onTimeout(onTimeoutCallback); deltaBLE.gattServer().onDataRead(triggerRead); console.printf("\r\nOK;%s;%s\r\n\r\n", CLI_FWVERION, MODULE_NAME); //0920 Silvia add while (true) { eventQueue.dispatch(); } } /*Tsungta, end of @0913 modification*/ //Silvia modify static void cynBLECenInitCommand(void) { deltaBLE.init(); deltaBLE.onDisconnection(disconnectionCallback); deltaBLE.onConnection(onConnectionCallback); deltaBLE.onTimeout(onTimeoutCallback); deltaBLE.gattClient().onDataRead(centralReadCallback); deltaBLE.gattClient().onDataWrite(centralWriteCallback); deltaBLE.gattClient().onHVX(centralHvxCallback); cyntecPrintOk(); } static void cynBLECenReadDataCommand(void) { if (cyntecGetCommandTokenCnt() != 4) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } UUID buf_ser_uuid ; uint8_t bufferUuidVs[16]; UUID buf_char_uuid; 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 < discoverService_count ; i++ ) { UUID sUUID, cUUID; if (discoverServiceArr[i].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { sUUID = UUID(discoverServiceArr[i].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverServiceArr[i].getUUID().getBaseUUID(); sUUID = UUID(longUUIDBytes); } if ((sUUID == buf_ser_uuid) & (readmatchFlag == false)) { for (int j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) { if (discoverCharArr[i][j].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { cUUID = UUID(discoverCharArr[i][j].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverCharArr[i][j].getUUID().getBaseUUID(); cUUID = UUID(longUUIDBytes); } if ((cUUID == buf_char_uuid) & (readmatchFlag == false)) { cyntecPrintOk(); discoverCharArr[i][j].read(); readmatchFlag = true; return; } } } } // no matched case, can not read if (readmatchFlag == false) { cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); } } static void cynBLECenWriteDataCommand(void) { if (cyntecGetCommandTokenCnt() != 6) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } UUID buf_ser_uuid ; uint8_t bufferUuidVs[16]; UUID buf_char_uuid; bool readmatchFlag = false; uint16_t valueLen = 0; uint8_t argLen = 0; uint8_t *arg = cyntecGetCommandArgument(0,&argLen); uint8_t bufVal[MAX_VALUE_LENGTH] = {0}; // 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 Type arg = cyntecGetCommandArgument(2,&argLen); uint8_t type = *arg; //type = cyntecArgToUint8(arg,2); // printf("type:%d\r\n",type); if(type != '0' && type != '1') { cyntecPrintError(CYNTEC_CMD_ERR_ARGUMENT_OUT_OF_RANGE); } // Input value arg = cyntecGetCommandArgument(3,&argLen); if(type == '0') { valueLen = argLen; memcpy(bufVal,arg,argLen); } if(type == '1') { valueLen = (argLen-2)/2; // uint8_t to uint16_t transform for (int i=0 ; i < valueLen; i++) { bufVal[i] = cyntecArgToUint8(arg+2+2*i,2); } } #if BLE_DEBUG printf("type:%i,bufVal:",type); printf("valueLength:%i\r\n",valueLen); for (int i=0 ; i < valueLen; i++) { printf("%02X ",bufVal[i]); } printf("\r\n"); #endif for ( int i = 0 ; i < discoverService_count ; i++ ) { UUID sUUID, cUUID; if (discoverServiceArr[i].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { sUUID = UUID(discoverServiceArr[i].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverServiceArr[i].getUUID().getBaseUUID(); sUUID = UUID(longUUIDBytes); } if ((sUUID == buf_ser_uuid) & (readmatchFlag == false)) { for (int j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) { if (discoverCharArr[i][j].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { cUUID = UUID(discoverCharArr[i][j].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverCharArr[i][j].getUUID().getBaseUUID(); cUUID = UUID(longUUIDBytes); } if ((cUUID == buf_char_uuid) & (readmatchFlag == false)) { console.printf("OK;"); for (int i=0 ; i < valueLen; i++) { console.printf("%02X",bufVal[i]); } console.printf("\r\n"); deltaBLE.gattClient().write(GattClient::GATT_OP_WRITE_REQ, discoverCharArr[i][j].getConnectionHandle(), discoverCharArr[i][j].getValueHandle(), valueLen, bufVal); readmatchFlag = true; return; } } } } // no matched case, can not read if (readmatchFlag == false) { cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); } } static void cynBLECenEnNotifyCommand(void) { if (cyntecGetCommandTokenCnt() != 4) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } UUID buf_ser_uuid ; uint8_t bufferUuidVs[16]; UUID buf_char_uuid; 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 < discoverService_count ; i++ ) { UUID sUUID, cUUID; if (discoverServiceArr[i].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { sUUID = UUID(discoverServiceArr[i].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverServiceArr[i].getUUID().getBaseUUID(); sUUID = UUID(longUUIDBytes); } if ((sUUID == buf_ser_uuid) & (readmatchFlag == false)) { for (int j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) { if (discoverCharArr[i][j].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { cUUID = UUID(discoverCharArr[i][j].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverCharArr[i][j].getUUID().getBaseUUID(); cUUID = UUID(longUUIDBytes); } if ((cUUID == buf_char_uuid) & (readmatchFlag == false)) { cyntecPrintOk(); uint16_t value = BLE_HVX_NOTIFICATION; deltaBLE.gattClient().write(GattClient::GATT_OP_WRITE_REQ, discoverCharArr[i][j].getConnectionHandle(), discoverCharArr[i][j].getValueHandle() + 1, 2, (uint8_t *)&value); readmatchFlag = true; return; } } } } // no matched case, can not read if (readmatchFlag == false) { cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); } } static void cynBLECenDisNotifyCommand(void) { if (cyntecGetCommandTokenCnt() != 4) { cyntecPrintError(CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS); return; } UUID buf_ser_uuid ; uint8_t bufferUuidVs[16]; UUID buf_char_uuid; 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 < discoverService_count ; i++ ) { UUID sUUID, cUUID; if (discoverServiceArr[i].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { sUUID = UUID(discoverServiceArr[i].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverServiceArr[i].getUUID().getBaseUUID(); sUUID = UUID(longUUIDBytes); } if ((sUUID == buf_ser_uuid) & (readmatchFlag == false)) { for (int j = 0 ; j < CLI_CHAR_MAX_NUM ; j++ ) { if (discoverCharArr[i][j].getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { cUUID = UUID(discoverCharArr[i][j].getUUID().getShortUUID()); } else { const uint8_t *longUUIDBytes = discoverCharArr[i][j].getUUID().getBaseUUID(); cUUID = UUID(longUUIDBytes); } if ((cUUID == buf_char_uuid) & (readmatchFlag == false)) { cyntecPrintOk(); uint16_t value = 0x00; deltaBLE.gattClient().write(GattClient::GATT_OP_WRITE_REQ, discoverCharArr[i][j].getConnectionHandle(), discoverCharArr[i][j].getValueHandle() + 1, 2, (uint8_t *)&value); readmatchFlag = true; return; } } } } // no matched case, can not read if (readmatchFlag == false) { cyntecPrintError(CYNTEC_CMD_ERR_NO_MATCHED_ARGUMENT); } } //Silvia modify static void cynBLEDataIntCommand(void) { cyntecPrintOk(); deltaBLE.gattServer().onDataWritten().add(onDataWrittenCallback); } static void cynBLEDisDataIntCommand(void) { cyntecPrintOk(); deltaBLE.gattServer().onDataWritten().detach(onDataWrittenCallback); } #if 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 #if BLE_DEBUG {"TEST", cynBLETestCommand, NULL, "test"}, #endif // #if SIMPLE_CMD_NAME //{"INT", cynBLEInitCommand, NULL, "Init BLE stack"},//Tsungta, INT is called in main.cpp {"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, "Get module information"}, {"POW", cynBLESetTxPowerCommand, NULL, "Set BLE tx power, Usage: <TX POWER>"}, {"NAM", cynBLENameCommand, NULL, "Set/Get friendly for BLE module, Usage: <LENGTH> <NAME>"}, // GATT {"GRS", cynRegServiceCommand, NULL, "Register standby service"}, {"GAC", cynGattCharCommand, NULL, "Set SIG defined characteristic or Create your own,Usage: <CHAR UUID> <PROPS> <VALUE>"}, {"GAS", cynGattServiceCommand, NULL, "Set SIG defined service or Create your own,Usage: <SERVICE UUID>"}, {"ADS", cynAdvertiseStartCommand, NULL, "Start broadcast advertise packet,Usage: <INTERVAL> <WINDOW>"}, {"ADP", cynAdvertiseStopCommand, NULL, "Stop broadcast advertise packet"}, {"SCS", cynBLEScanCommand, NULL, "Start to scan BLE device, Usage: <INTERVAL> <WINDOW> <TIMEOUT>"}, {"SCP", cynBLEScanStopCommand, NULL, "Stop to scan BLE device"}, {"CON", cynBLEConnectCommand, NULL, "Connect to specific BLE device by Device Address, Usage: <ADDR>"}, {"DCN", cynBLEDisconnectCommand, NULL, "Disconnection"}, {"ADR", cynBLEAddressCommand, NULL, "Set/Get Bluetooth address, Usage: <ADDR>"}, {"WRT", cynBLEUpdateDataCommand, NULL, "Update value of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID> <TYPE> <VALUE>"}, {"RED", cynBLEReadDataCommand, NULL, "Read value of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {"EDI", cynBLEDataIntCommand, NULL, "Trigger remote write detection, give interrupt to Host."}, {"DDI", cynBLEDisDataIntCommand, NULL, "Disable remote write detection."}, //Silvia add BLE central commands {"CIN", cynBLECenInitCommand, NULL, "Init BLE Central stack"}, {"CRD", cynBLECenReadDataCommand, NULL, "BLE Central read value of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {"CWD", cynBLECenWriteDataCommand, NULL, "BLE Central write value to specific characteristics, Usage: <SERVICE UUID> <CHAR UUID> <TYPE> <VALUE>"}, {"CEN", cynBLECenEnNotifyCommand, NULL, "BLE Central enable notification of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {"CDN", cynBLECenDisNotifyCommand, NULL, "BLE Central disable notification of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {NULL, NULL, NULL, NULL}, #else //{"init", cynBLEInitCommand, NULL, "Init BLE stack"},//Tsungta, init is called in main.cpp {"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: <TX POWER>"}, {"name", cynBLENameCommand, NULL, "Set/Get friendly for BLE module, Usage: <LENGTH> <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>"}, //BLE central {"scanStop", cynBLEScanStopCommand, NULL, "Stop to scan BLE device"}, //BLE central {"connect", cynBLEConnectCommand, NULL, "Connect to specific BLE device by Device Address, Usage: <ADDR>"}, //Silvia modify, BLE central {"disconn", cynBLEDisconnectCommand, NULL, "Disconnection, Usage: cynb disconn"}, {"bleAddr", cynBLEAddressCommand, NULL, "Set/Get Bluetooth address, Usage: <ADDR>"}, {"update", cynBLEUpdateDataCommand, NULL, "Update value of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID> <TYPE> <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."}, //Silvia add BLE central commands {"initBleCen", cynBLECenInitCommand, NULL, "Init BLE Central stack"}, {"cenReadData", cynBLECenReadDataCommand, NULL, "BLE Central read value of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {"cenWriteData", cynBLECenWriteDataCommand, NULL, "BLE Central write value to specific characteristics, Usage: <SERVICE UUID> <CHAR UUID> <TYPE> <VALUE>"}, {"cenEnNotify", cynBLECenEnNotifyCommand, NULL, "BLE Central enable notification of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {"cenDisNotify", cynBLECenDisNotifyCommand, NULL, "BLE Central disable notification of specific characteristics, Usage: <SERVICE UUID> <CHAR UUID>"}, {NULL, NULL, NULL, NULL}, #endif };