this is a new program based on BLE_Uart_Peripheral. Change program name due to relation Client&Peripheral to Client&Server

Dependencies:   RingBuffer nRF51_Vdd nRF51_WakeUp

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 /*
00018  *  ------- BLE Peripheral/Server UART function --------------------------------
00019  *          communicate with BLE_UART_Client program
00020  *      --- Tested on Switch Science mbed TY51822r3 ---
00021  *
00022  *      http://www.page.sannet.ne.jp/kenjia/index.html
00023  *      https://os.mbed.com/users/kenjiArai/
00024  *
00025  *      Started:  March     7th, 2016
00026  *      Revised:  June     13th, 2016
00027  *      Revised:  Feburary 10th, 2018   Not set mac addr but use device name
00028  *      Revised:  Feburary 11th, 2018   use mbed-os5.7.4 with CircularBuffer
00029  *
00030  *  Original program:
00031  *      BLE_LoopbackUART
00032  *      https://developer.mbed.org/teams/Bluetooth-Low-Energy/
00033  *                                  code/BLE_LoopbackUART/
00034  *  Reference program:
00035  *      BLE_Peripheral_test by noboru koshinaka
00036  *      https://os.mbed.com/users/noboruk/code/BLE_Peripheral_test/
00037  *  Tested Client Device:
00038  *      BLE_Uart_Client
00039  *      https://os.mbed.com/users/kenjiArai/code/BLE_Uart_Client/
00040  */
00041 
00042 //  Include --------------------------------------------------------------------
00043 #include "mbed.h"
00044 #include "BLE.h"
00045 #include "UARTService.h"
00046 #include "nRF51_Vdd.h"
00047 #include "nRF51_WakeUp.h"
00048 #include "CircularBuffer.h"
00049 
00050 //  Definition -----------------------------------------------------------------
00051 //#define     USE_MAC           // if you use mac address, please define it
00052 
00053 #define     NUM_ONCE            20
00054 #define     BFSIZE              (NUM_ONCE+4)
00055 
00056 // Please refer nRF51_WakeUP library
00057 #define     GOTO_SLEEP_MODE     0
00058 #if GOTO_SLEEP_MODE
00059 #warning "Make sure!! -> You need to connected P0_21(LED1) and P0_0"
00060 #endif
00061 
00062 //#define    USE_DEBUG_MODE
00063 #ifdef USE_DEBUG_MODE
00064 #define DEBUG(...) { printf(__VA_ARGS__); }
00065 #else
00066 #define DEBUG(...)
00067 #endif
00068 
00069 //  Object ---------------------------------------------------------------------
00070 BLE&            ble_uart = BLE::Instance();
00071 DigitalOut      connectedLED(LED2);
00072 InterruptIn     wake_up_sw(P0_1);
00073 nRF51_WakeUp    wakeup(P0_21, P0_0);
00074 nRF51_Vdd       vdd(3.0f, 2.2f);
00075 Serial          pc(USBTX, USBRX, 115200);
00076 //Serial        pc(P0_3, P0_1, 115200);     // for another board
00077 UARTService     *uartServicePtr;
00078 Ticker          ticker;
00079 CircularBuffer<char, 1536> ser_bf;
00080 Thread          tsk;
00081 Mutex           bletx_mutex;
00082 
00083 //  ROM / Constant data --------------------------------------------------------
00084 #warning "You need to confirm your device name."
00085 const static char DEVICE_NAME[] = "UART_PJL";
00086 
00087 //  RAM ------------------------------------------------------------------------
00088 Gap::Address_t  my_mac;
00089 uint8_t         tx_buf[BFSIZE];
00090 uint8_t         tx_len                  = 0;
00091 uint8_t         rx_buf[BFSIZE];
00092 volatile bool   trigger_transmit        = false;
00093 volatile bool   trigger_receive         = false;
00094 volatile uint8_t command_continue       = 0;
00095 uint16_t        time_out_cntr           = 3600;
00096 volatile bool   time_out                = false;
00097 uint32_t        sleep_time              = 30;   // unit:second
00098 volatile bool   rx_isr_busy             = false;
00099 
00100 //  Function prototypes --------------------------------------------------------
00101 //      BLE
00102 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *);
00103 void onDataWritten_action(const GattWriteCallbackParams *);
00104 //      Tasks
00105 void pc_ser_rx(void);
00106 void data_from_ble(void);
00107 void Update_Values(void);
00108 //      Application related
00109 void command(uint8_t *cmd);
00110 void action_tx_help(void);
00111 void action_tx_vdd(void);
00112 void action_tx_temperature(void);
00113 void action_tx_wait_time(uint8_t *);
00114 void action_tx_quit(void);
00115 int  xatoi (char **, int32_t *);
00116 void adjust_line(uint8_t *);
00117 //      Interrupt related
00118 void interrupt_by_sw(void);
00119 void serialRxCallback(void);
00120 void periodicCallback(void);
00121 
00122 //------------------------------------------------------------------------------
00123 //  Control Program
00124 //------------------------------------------------------------------------------
00125 int main(void)
00126 {
00127     connectedLED = 0;
00128     pc.attach(&serialRxCallback, Serial::RxIrq);
00129     ticker.attach(periodicCallback, 1);
00130     tsk.start(pc_ser_rx);
00131     // clear terminal output
00132     for (int k = 0; k < 3; k++) {
00133         pc.printf("\r\n");
00134     }
00135     // opening message
00136     pc.printf("UART Communication / Server(Peripheral) side\r\n");
00137     pc.printf("  need Client module (run BLE_Uart_Client program)\r\n");
00138     // Interrupt by switch
00139     wake_up_sw.fall(&interrupt_by_sw);
00140     ble_uart.init();
00141     Gap::AddressType_t my_mac_type;
00142     ble_uart.gap().getAddress(&my_mac_type, my_mac);
00143     DEBUG(
00144         "  my_MAC %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n",
00145         my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0],
00146         (my_mac_type == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random"
00147     );
00148     pc.printf(
00149         "  My device name : %s\r\n", DEVICE_NAME);
00150     pc.printf(
00151         "  My mac data %02x:%02x:%02x:%02x:%02x:%02x\r\n",
00152         my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0]
00153     );
00154 #ifdef USE_MAC
00155     pc.printf(
00156         "  mac_board_x   = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x};\r\n",
00157         my_mac[0], my_mac[1], my_mac[2], my_mac[3], my_mac[4], my_mac[5]
00158     );
00159     pc.printf(
00160         "  Please write above data(mac_board_x line (x=0,1,2,...))\r\n");
00161     pc.printf(
00162         "  into Client/main.cpp [ROM / Constant data] area\r\n");
00163 #endif
00164     ble_uart.onDisconnection(disconnectionCallback);
00165     ble_uart.onDataWritten(onDataWritten_action);
00166     /* setup advertising */
00167     ble_uart.accumulateAdvertisingPayload(
00168         GapAdvertisingData::BREDR_NOT_SUPPORTED);
00169     ble_uart.setAdvertisingType(
00170         GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00171     ble_uart.accumulateAdvertisingPayload(
00172         GapAdvertisingData::COMPLETE_LOCAL_NAME,
00173         (const uint8_t *)DEVICE_NAME,
00174         sizeof(DEVICE_NAME)
00175     );
00176     ble_uart.accumulateAdvertisingPayload(
00177         GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
00178         (const uint8_t *)UARTServiceUUID_reversed,
00179         sizeof(UARTServiceUUID_reversed)
00180     );
00181     // Advertize Interval
00182     ble_uart.setAdvertisingInterval(1000); /* 1000ms;in multiples of 0.625ms.*/
00183     // Start
00184     ble_uart.startAdvertising();
00185     UARTService uartService(ble_uart);
00186     uartServicePtr = &uartService;
00187     while(true) {
00188         if (time_out) {
00189 #if GOTO_SLEEP_MODE
00190             wakeup.set_and_wait(sleep_time);
00191             while(true) {   // never come here but just in case
00192                 deepsleep();
00193             }
00194 #endif
00195         }
00196         if (trigger_transmit) {
00197             static uint8_t cmd_buf[BFSIZE];
00198             static volatile bool   flag_continue = 0;
00199             trigger_transmit = false;
00200             pc.printf((const char*)rx_buf);
00201             if (flag_continue == true) {
00202                 strcat((char *)cmd_buf, (char *)rx_buf);
00203                 if (strchr((const char*)cmd_buf,(int)'\r') == 0) {
00204                     flag_continue = true;
00205                 } else {
00206                     command(cmd_buf);
00207                     for(uint8_t i = 0; i < BFSIZE; i++) {
00208                         cmd_buf[i] = 0;
00209                     }
00210                     flag_continue = false;
00211                 }
00212             }
00213             if ((rx_buf[0] == '~')) {
00214                 strcpy((char *)cmd_buf, (char *)rx_buf);
00215                 if (strchr((const char*)cmd_buf,(int)'\r') == 0) {
00216                     flag_continue = true;
00217                 } else {
00218                     command(cmd_buf);
00219                     for(uint8_t i = 0; i < BFSIZE; i++) {
00220                         cmd_buf[i] = 0;
00221                     }
00222                     flag_continue = false;
00223                 }
00224             }
00225         }
00226         ble_uart.waitForEvent();
00227     }
00228 }
00229 
00230 void command(uint8_t *cmd)
00231 {
00232     uint8_t *p = cmd;
00233 
00234     while(*p == ' ') {
00235         ++p;   // skip space
00236     }
00237     if (*p++ == '~') {
00238         while(*p < '!') {
00239             ++p;   // skip space
00240         }
00241         uint8_t c = *p;
00242         //pc.printf("c=%c\r\n", c);
00243         switch (c) {
00244             case 'v':
00245                 action_tx_vdd();
00246                 break;
00247             case 't':
00248                 action_tx_temperature();
00249                 break;
00250             case 'q':
00251                 action_tx_quit();
00252                 break;
00253             case 'w':
00254                 action_tx_wait_time(cmd);
00255                 break;
00256             case 'h':
00257             case '?':
00258                 action_tx_help();
00259                 break;
00260             default:
00261                 //pc.printf("\r\nStep(%u)\r\n", __LINE__);
00262                 break;
00263         }
00264     }
00265 }
00266 
00267 void periodicCallback(void)
00268 {
00269 #if GOTO_SLEEP_MODE
00270     if (--time_out_cntr == 0) {
00271         time_out = true;
00272     }
00273 #endif
00274     if (rx_isr_busy == true) {
00275         rx_isr_busy = false;
00276     } else {
00277         tsk.signal_set(0x01);
00278     }
00279 }
00280 
00281 void serialRxCallback()
00282 {
00283     ser_bf.push(pc.getc());
00284     rx_isr_busy = true;
00285     tsk.signal_set(0x01);
00286 }
00287 
00288 void pc_ser_rx()
00289 {
00290     static uint8_t linebf_irq[BFSIZE];
00291     static volatile uint8_t linebf_irq_len = 0;
00292 
00293     while(true) {
00294         Thread::signal_wait(0x01);
00295         if (ser_bf.empty()) {
00296             if (linebf_irq_len != 0) {
00297                 linebf_irq[linebf_irq_len] = 0;
00298                 adjust_line(linebf_irq);
00299                 linebf_irq_len = 0;
00300                 bletx_mutex.lock();
00301                 ble_uart.updateCharacteristicValue(
00302                     uartServicePtr->getRXCharacteristicHandle(),
00303                     linebf_irq,
00304                     NUM_ONCE
00305                 );
00306                 bletx_mutex.unlock();
00307             }
00308         }
00309         while(!ser_bf.empty()) {
00310             char c;
00311             ser_bf.pop(c);
00312             if (c == '\b') {
00313                 linebf_irq_len--;
00314                 pc.putc(c);
00315                 pc.putc(' ');
00316                 pc.putc(c);
00317             } else if ((c >= ' ') || (c == '\r') || (c == '\n')) {
00318                 bool overflow = false;
00319                 if ((c == '\r') || (c == '\n')) {
00320                     if (linebf_irq_len == NUM_ONCE - 1) { // remain only 1 buffer
00321                         overflow = true;
00322                         linebf_irq[linebf_irq_len++] = '\r';
00323                         pc.putc('\r');
00324                     } else {
00325                         overflow = false;
00326                         linebf_irq[linebf_irq_len++] = '\r';
00327                         linebf_irq[linebf_irq_len++] = '\n';
00328                         pc.printf("\r\n");
00329                     }
00330                 } else {
00331                     linebf_irq[linebf_irq_len++] = c;
00332                     pc.putc(c);
00333                 }
00334                 if (linebf_irq_len >= NUM_ONCE ) {
00335                     linebf_irq[linebf_irq_len] = 0;
00336                     adjust_line(linebf_irq);
00337                     linebf_irq_len = 0;
00338                     bletx_mutex.lock();
00339                     ble_uart.updateCharacteristicValue(
00340                         uartServicePtr->getRXCharacteristicHandle(),
00341                         linebf_irq,
00342                         NUM_ONCE
00343                     );
00344                     bletx_mutex.unlock();
00345                     if (overflow == true) {
00346                         overflow = false;
00347                         linebf_irq[linebf_irq_len++] = '\n';
00348                         pc.putc('\n');
00349                     }
00350                 }
00351             }
00352         }
00353     }
00354 }
00355 
00356 void adjust_line(uint8_t *bf)
00357 {
00358     uint8_t i, c;
00359 
00360     for (i = 0; i <NUM_ONCE; bf++, i++) {
00361         c = *bf;
00362         if (c == 0) {
00363             break;
00364         }
00365     }
00366     for (; i < NUM_ONCE; bf++, i++) {
00367         *bf = 0x11;
00368     }
00369     *(bf + 1) = 0;
00370 }
00371 
00372 void onDataWritten_action(const GattWriteCallbackParams *params)
00373 {
00374     if ((uartServicePtr != NULL) &&
00375             (params->handle == uartServicePtr->getTXCharacteristicHandle())) {
00376         strcpy((char *)rx_buf, (const char *)params->data);
00377         trigger_transmit = true;
00378     }
00379 }
00380 
00381 void action_tx_help()
00382 {
00383     //          12345678901234567890
00384     sprintf((char *)tx_buf,"  ~?:help\r\n");
00385     tx_len = strlen((const char *)tx_buf);
00386     Update_Values();
00387     Thread::wait(200);
00388     //          12345678901234567890
00389     sprintf((char *)tx_buf,"  ~v:vdd\r\n");
00390     tx_len = strlen((const char *)tx_buf);
00391     Update_Values();
00392     Thread::wait(200);
00393     //          12345678901234567890
00394     sprintf((char *)tx_buf,"  ~t:temperature\r\n");
00395     tx_len = strlen((const char *)tx_buf);
00396     Update_Values();
00397     Thread::wait(200);
00398     //          12345678901234567890
00399     sprintf((char *)tx_buf,"  ~w:wait, w 120\r\n");
00400     tx_len = strlen((const char *)tx_buf);
00401     Update_Values();
00402     Thread::wait(200);
00403     //          12345678901234567890
00404     sprintf((char *)tx_buf,"  ~q:quit/sleep\r\n");
00405     tx_len = strlen((const char *)tx_buf);
00406     Update_Values();
00407     Thread::wait(200);
00408 }
00409 
00410 void action_tx_vdd()
00411 {
00412     sprintf((char *)tx_buf,"Vdd: %3.2f V\r\n", vdd.read_real_value());
00413     tx_len = strlen((const char *)tx_buf);
00414     Update_Values();
00415 }
00416 
00417 void action_tx_temperature()
00418 {
00419     int32_t p_temp;
00420     float temperature;
00421 
00422     // Update a temperature (inside nRF51822 chip)
00423     sd_temp_get(&p_temp);
00424     // -16.0f is offset vale for chip die temp
00425     //         to ambient temp (depend on your board)
00426     temperature = float(p_temp) / 4; // Original = float(p_temp)/4.0f - 16.0f;
00427     sprintf((char *)tx_buf,"T: %+4.1f dC\r\n", temperature);
00428     tx_len = strlen((const char *)tx_buf);
00429     Update_Values();
00430 }
00431 
00432 void action_tx_wait_time(uint8_t *cmd)
00433 {
00434     int32_t dt;
00435     char *p;
00436 
00437     p = (char *)(cmd);
00438     p += 2; // point to time value
00439     if (xatoi(&p, &dt)) {
00440         if (dt <= 5) {
00441             dt = 5;
00442         }
00443         sleep_time = dt;    // set next wake-up period
00444     } else {
00445         DEBUG("data is unknown!\r\n");
00446         sleep_time = 30;
00447     }
00448     DEBUG("slp_t:%d\r\n", sleep_time);
00449     //pc.printf("slp_t:%d\r\n", sleep_time);
00450     //          12345678901234567890
00451     sprintf((char *)tx_buf, "W: %d sec\r\n", sleep_time);
00452     tx_len = strlen((const char *)tx_buf);
00453     Update_Values();
00454 }
00455 
00456 void action_tx_quit()
00457 {
00458 #if GOTO_SLEEP_MODE
00459     ticker.detach();
00460     //          12345678901234567890
00461     sprintf((char *)tx_buf,"Terminated the BLE");
00462     tx_len = strlen((const char *)tx_buf);
00463     Update_Values();
00464     Thread::wait(1000);
00465     wakeup.set_and_wait(sleep_time);
00466     while(true) {   // never come here but just in case
00467         deepsleep();
00468     }
00469 #else
00470     SCB->AIRCR = 0x05fa0004;    // System RESET!!
00471 #endif
00472 }
00473 
00474 //  Change string -> integer
00475 int xatoi (char **str, int32_t *res)
00476 {
00477     unsigned long val;
00478     unsigned char c, radix, s = 0;
00479 
00480     for (;;) {
00481         c = **str;
00482         if (c == 0) {
00483             return 0;
00484         }
00485         if (c == '-') {
00486             break;
00487         }
00488         if (c == '+') {
00489             (*str)++;
00490             c = **str;
00491         }
00492         if (c>='0'&& c<='9') {
00493             break;
00494         } else {
00495             (*str)++;
00496             c = **str;
00497         }
00498     }
00499     if (c == '-') {
00500         s = 1;
00501         c = *(++(*str));
00502     }
00503     if (c == '0') {
00504         c = *(++(*str));
00505         if (c <= ' ') {
00506             *res = 0;
00507             return 1;
00508         }
00509         if (c == 'x') {
00510             radix = 16;
00511             c = *(++(*str));
00512         } else {
00513             if (c == 'b') {
00514                 radix = 2;
00515                 c = *(++(*str));
00516             } else {
00517                 if ((c >= '0')&&(c <= '9')) {
00518                     radix = 8;
00519                 }   else {
00520                     return 0;
00521                 }
00522             }
00523         }
00524     } else {
00525         if ((c < '1')||(c > '9')) {
00526             return 0;
00527         }
00528         radix = 10;
00529     }
00530     val = 0;
00531     while (c > ' ') {
00532         if (c >= 'a') c -= 0x20;
00533         c -= '0';
00534         if (c >= 17) {
00535             c -= 7;
00536             if (c <= 9) return 0;
00537         }
00538         if (c >= radix) return 0;
00539         val = val * radix + c;
00540         c = *(++(*str));
00541     }
00542     if (s) val = -val;
00543     *res = val;
00544     return 1;
00545 }
00546 
00547 void interrupt_by_sw() // Go to sleep
00548 {
00549     NVIC_SystemReset();
00550     // Not come here (Just in case)
00551     sleep();
00552 }
00553 
00554 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
00555 {
00556     DEBUG("Disconnected!\r\n");
00557     DEBUG("Restarting the advertising process\r\n");
00558     ble_uart.startAdvertising();
00559 }
00560 
00561 void Update_Values(void)
00562 {
00563     bletx_mutex.lock();
00564     ble_uart.updateCharacteristicValue(
00565         uartServicePtr->getRXCharacteristicHandle(),
00566         tx_buf,
00567         tx_len
00568     );
00569     bletx_mutex.unlock();
00570     tx_len = 0;
00571 }