1st release version. Set TYBLE16 as Central mode

Dependencies:   mbed

Fork of TYBLE16_BME280_data_sender by Kenji Arai

Please refer following page.
/users/kenjiArai/notebook/tyble16-module--uart-communication-between-central/#

Revision:
2:17fdd6d3877f
Parent:
1:f2982d4f4037
--- a/main.cpp	Sun Oct 29 23:25:26 2017 +0000
+++ b/main.cpp	Sun Nov 19 09:43:39 2017 +0000
@@ -12,186 +12,317 @@
  *  http://www.page.sannet.ne.jp/kenjia/index.html
  *  http://mbed.org/users/kenjiArai/
  *      Created:    October   27th, 2017
- *      Revised:    October   30th, 2017
+ *      Revised:    November  19th, 2017
  */
 
 /*
     Tested condition
-        mbed-os-5.6.3 & mbed Rev.154
-    Nucleo-F446RE   TYBLE16 /also F411RE & F042K6(only mbed & pin assign differ)
-        PA_9         pin5 / P0.03(UART_RX)
-        PA_10        pin6 / P0.01(UART_TX)
-                     pin7 / P0.02(UART_CTS) connected to pin8 / P0.00(UART_RTS)
+        mbed-os-5.6.4 & mbed Rev.157(release 155)
+    Nucleo-F446RE   TYBLE16 /also F411RE
+        PA_9 (D8)    pin5  / P0.03(UART_RX)
+        PA_10(D2)    pin6  / P0.01(UART_TX)
+                     pin7  / P0.02(UART_CTS) connected to pin8 / P0.00(UART_RTS)
         +3.3v        pin14 / +V
         GND          pin13 / GND
-    Nucleo-F446RE   BME280
-        PB_9(SDA)    SDI
-        PB_8(SCL)    SDK
-                     SDO = GND, CSB = +3.3V
-    Communcation with iPhone 7 iOS 11.0.3
-        TYs Terminal App
-        https://itunes.apple.com/jp/app/tys-terminal-app/id1184640145?mt=8
+ */
+
+/*
+  --- HOW TO SET "CENTRAL(CLIENT) MODE" ---
+    TYBLE16 default setting is "Peripheral(Server) Mode"
+    If you want to use it as "Central mode", you need to proceed follows
+    1) You run this program on a Mbed board connected with TYBLE16 module
+    2) Just after running the program, you can identify the mode "Central" or
+       "Peripheral" in your terminal screen
+    3) If your module is "Peripheral", please enter 'c' for switching the mode
+    4) Power off the module then restart again and check the mode
+    5) Please use
+       "TYBLE16_UART_Central_and_Peripheral" program as sample application
  */
 
 //  Include --------------------------------------------------------------------
 #include "mbed.h"
-#include "BME280.h"
 
 //  Definition -----------------------------------------------------------------
-#define     TIME_OUT         5       // 5 sec
-#define     ADT_TIME        15       // 15 sec
+enum operating_mode_t {
+    MODE_UNKNOWN            = -1,   // Unknown Error
+    MODE_CENTRAL            =  0,   // Central
+    MODE_PERIPHERAL         =  1,   // Peripheral
+};
 
 //  Object/ Constructor --------------------------------------------------------
 Serial      pc(USBTX,USBRX);
-Serial      tyble16(PA_9, PA_10);
-BME280      bme280(I2C_SDA, I2C_SCL);
+Serial      tyble16(D8, D2);    // Choose proper pin assignment in your Mbed
+Ticker      t;
 
 //  RAM ------------------------------------------------------------------------
-bool        state_connection    = false;
-bool        received_data       = false;
-uint32_t    cmd_timeout_cntr    = ADT_TIME;
-Ticker      t;
+uint8_t timeout_readable;
+operating_mode_t my_role;
+uint8_t cmd[8];
 
 //  ROM / Constant data --------------------------------------------------------
+char *const msg =
+    "Set TYBLE16 Central or Peripheral, created on UTC: "__TIME__","__DATE__"";
+char *const err_msg =
+    "Cannot detect BLE! Please check the hardware!\r\n";
+char *const ble_msg = "-- From BLE(followed line) --";
+char *const cmd_force_reset = "BRS\r\n";
+char *const cmd_advert_stop = "BCD0\r\n";
+char *const cmd_change_to_c = "BRL1\r\n";
+char *const cmd_change_to_p = "BRL0\r\n";
 
 //  Function prototypes --------------------------------------------------------
-void check_connection(void);
-void parse_input(char *buf);
+void set_central_mode(void);
+void one_sec(void);
+void get_line (char *, int);
+void stop_broadcasting(char *);
+char *get_ble_message(char *);
+void command_preparation(void);
 
 //------------------------------------------------------------------------------
 //  Control Program
 //------------------------------------------------------------------------------
-// special command for BME280 data collection
-bool excute_command(char *buf)
-{
-    char c = buf[1];
-    switch (c){
-        case 'a':       // All data
-        case 'A':
-            tyble16.printf("Pressure: %04.2f hPa\r\n",
-                            bme280.getPressure());
-            tyble16.printf("Temperature: %2.2f degC\r\n",
-                            bme280.getTemperature());
-            tyble16.printf("Humidity: %2.2f %%\r\n",
-                            bme280.getHumidity());
-            break;
-        case 'p':       // Pressure
-        case 'P':
-            tyble16.printf("Pressure: %04.2f hPa\r\n",
-                            bme280.getPressure());
-            break;
-        case 't':       // Temperature
-        case 'T':
-            tyble16.printf("Temperature: %2.2f degC\r\n",
-                            bme280.getTemperature());
-            break;
-        case 'h':       // Humidity
-        case 'H':
-            tyble16.printf("Humidity: %2.2f %%\r\n",
-                            bme280.getHumidity());
-            break;
-        case '?':       // Help
-            tyble16.printf("Command syntax\r\n");
-            tyble16.printf("@a All of data\r\n");
-            tyble16.printf("@p Pressure\r\n");
-            tyble16.printf("@t Temperature\r\n");
-            tyble16.printf("@h Humidity\r\n");
-            break;
-        default:        // no available command
-            tyble16.printf("ommand not available, hit '@?'\r\n");
-            break;
-    }
-    return true;
-}
-
 int main()
 {
-    static char rcv_bf[128];
-    static uint8_t n = 0;
-    char c = 0;
-
-    pc.printf("\r\n\r\nApplication for AE-TYBLE16 Module ");
-    pc.printf(" Peripheral(Sever) side\r\n");
-    pc.printf("  created on %s %s\r\n", __DATE__, __TIME__);
-    tyble16.printf("I'm TYBLE16 module!\r\n");
-    // warming up the sensor
-    for (int n = 0; n < 6; n++){
-        bme280.getPressure();
-        bme280.getTemperature();
-        bme280.getHumidity();
-    }
-    t.attach(check_connection, 1);
+    command_preparation();
+    pc.printf("\r\n\r\n%s\r\n", msg); 
+    t.attach(&one_sec, 1.0f);
     while(true){
-        while(tyble16.readable()){
-            //----- data receive from Client -----------------------------------
-            received_data = true;
-            c = tyble16.getc();         // received data from client
-            pc.putc(c);                 // show to console
-            rcv_bf[n++] = c;            // save int buf
-            if (c == '\n'){             // end one line
-                pc.putc('\r');
-                rcv_bf[n] = 0;
-                if (n >3){
-                    parse_input(rcv_bf);    // ckeck command or not
-                    /*for (int i=0;; i++){
-                        if (rcv_bf[i] == 0){break;}
-                        pc.printf("0x%x,", rcv_bf[i]);
-                    }*/
-                    if ((rcv_bf[0] == '@') && (rcv_bf[2] == '\r')){
-                        excute_command(rcv_bf); // BME280 data output 
-                    }
-                }
-                n = 0;  // Clear buffer
+        set_central_mode();
+    }
+}
+
+// Every 1 second
+void one_sec(void){               // execute every 1second
+    if( timeout_readable){        --timeout_readable; }
+}
+
+// Peripheral mode (Default setting) change to Central mode
+void set_central_mode(void)
+{
+    static char linebuf[64];
+    static char blebuf[64];
+    char *ptr;
+    char c;
+
+    // Reset BLE
+    pc.printf("Start from BLE reset\r\n");
+    {   // need to keep this order (does not divide each other)
+        tyble16.puts(cmd_force_reset);
+        pc.printf("force to reset\r\n%s%s\r\n",
+                ble_msg, get_ble_message(blebuf));
+    }
+    if (strstr(blebuf , "Ver.") != NULL){
+        ;
+    } else {
+        pc.printf(err_msg);
+        while(true){;}
+    }  
+    wait_ms(10);
+    // Stop current action
+    {   // need to keep this order (does not divide each other)
+        tyble16.puts(cmd_advert_stop);
+        get_ble_message(blebuf);
+    }
+    if (strstr(blebuf , "ACK") != NULL){
+        my_role = MODE_PERIPHERAL;
+    } else if (strstr(blebuf , "NAK") != NULL){
+        {   // need to keep this order (does not divide each other)
+            tyble16.printf("%s", cmd);
+            get_ble_message(blebuf);
+        }
+        if (strstr(blebuf , "ACK") != NULL){
+            my_role = MODE_CENTRAL;
+        } else {
+            pc.printf(err_msg);
+            while(true){;}
+        }
+    } else {
+        pc.printf(err_msg);
+        while(true){;}
+    }
+    pc.printf("Current mode: ");
+    if (my_role == MODE_CENTRAL){
+        pc.printf("Central\r\n");
+    } else if (my_role == MODE_PERIPHERAL){
+        pc.printf("Peripheral\r\n");
+    } else {
+        pc.printf("unknown\r\n");
+    }
+    c = linebuf[0];
+    stop_broadcasting(blebuf);
+    pc.printf("Define Central or Peripheral\r\n");
+    pc.printf("Central -> c, Peripheral -> p, ");
+    pc.printf("Keep current setting -> any key\r\n");
+    pc.printf("Please enter c or p\r\n=");
+    ptr = linebuf;
+    get_line(ptr, sizeof(linebuf));
+    pc.putc('\r');
+    c = linebuf[0];
+    if ((c == 'c') || (c == 'C')){
+        pc.printf(cmd_change_to_c);
+        {   // need to keep this order (does not divide each other)
+            tyble16.printf(cmd_change_to_c);
+            pc.printf("Switch to Central\r\n%s%s\r\n",
+                    ble_msg, get_ble_message(blebuf));
+        }
+        if (strstr(blebuf , "ACK") != NULL){     // check ACK words
+            my_role = MODE_CENTRAL;
+            pc.printf("BST5010000\r\n");
+            {// need to keep this order (does not divide each other)
+                tyble16.printf("BST5010000\r\n");
+                pc.printf("Set PSKEY value\r\n");
+                pc.printf("Checking paired signal forever\r\n");
+            }
+            pc.printf("Changed to Central mode\r\nPlease power-off");
+            pc.printf(" then Peripheral will active!\r\n");
+        } else if (strstr(blebuf , "NAK") != NULL){
+            if (my_role == MODE_PERIPHERAL){
+                pc.printf("Stay in Periphral mode\r\n");
+            } else {
+                pc.printf("Stay in Central mode\r\n");
+            }
+        } else {
+            pc.printf("??\r\n");
+        }
+    } else if ((c == 'p') || (c == 'P')){
+        pc.printf(cmd_change_to_p);
+        {   // need to keep this order (does not divide each other)
+            tyble16.printf(cmd_change_to_p);
+            pc.printf("Switch to Peripheral\r\n%s%s\r\n",
+                    ble_msg, get_ble_message(blebuf));
+        }
+        if (strstr(blebuf , "ACK") != NULL){     // check ACK words
+            my_role = MODE_PERIPHERAL;
+            pc.printf("BST501003C\r\n");
+            {// need to keep this order (does not divide each other)
+                tyble16.printf("BST501003C\r\n"); // default data 60 sec
+                pc.printf("Set PSKEY value\r\n");
+                pc.printf("Advertising 60sec timeout\r\n");
+            }
+            pc.printf("Changed to Periphral mode\r\nPlease power-off");
+            pc.printf(" then Peripheral will active!\r\n");
+        } else if (strstr(blebuf , "NAK") != NULL){
+            if (my_role == MODE_PERIPHERAL){
+                pc.printf("Stay in Periphral mode\r\n");
+            } else {
+                pc.printf("Stay in Central mode\r\n");
+            }
+        } else {
+            pc.printf("??\r\n");
+        }
+    } else {
+        pc.printf("Keep current setting\r\n");
+    }
+    pc.printf("Hit any key to go again!\r\n");
+    while(pc.getc() == 0){;}
+}
+
+void stop_broadcasting(char *buf)
+{
+    // Stop Advertising or Scanning (just in case)
+    if (my_role == MODE_PERIPHERAL){
+        pc.printf("Stop Advertising\r\n");
+        tyble16.puts(cmd_advert_stop);
+    } else {
+        pc.printf("Stop Central action\r\n");
+        tyble16.printf("%s", cmd);
+    }
+    // need to keep this order (does not divide puts & get_ble_message)
+    pc.printf("%s%s\r\n", ble_msg, get_ble_message(buf));
+    if (buf[2] == 'A'){
+        if (buf[3] ==  'C'){
+            if (buf[4] ==  'K'){
+                return;
             }
         }
-        while(pc.readable()){
-            //----- data send to Client ----------------------------------------
-            char c = pc.getc();
-            tyble16.putc(c);
-            pc.putc(c);                 // echo back
-            if(c == '\r'){              // if CR then put LF
-                tyble16.putc('\n');
-                pc.putc('\n');
+    }
+    if (my_role == MODE_PERIPHERAL){
+        pc.printf("Try again,Stop Central action\r\n");
+        tyble16.printf("%s", cmd);
+    } else {
+        pc.printf("Try again,Stop Advertising\r\n");
+        tyble16.puts(cmd_advert_stop);   // try Peripheral
+    }
+    // need to keep this order (does not divide puts & get_ble_message)
+    pc.printf("n%s%s\r\n", ble_msg, get_ble_message(buf));
+    if (buf[2] == 'A'){
+        if (buf[3] ==  'C'){
+            if (buf[4] ==  'K'){
+                // change role C to P or P to C
+                if (my_role == MODE_PERIPHERAL){
+                    my_role = MODE_CENTRAL;
+                    pc.printf("Mode changes to Central\r\n");
+                } else {
+                    my_role = MODE_PERIPHERAL;
+                    pc.printf("Mode changes to Peripheral\r\n");
+                }
+                return;
             }
         }
     }
 }
 
-// Check Response Events
-void parse_input(char *buf)
+char *get_ble_message(char *buf)
+{
+    char c;
+
+    uint8_t cr_cnt = 0;
+    uint16_t i = 0;
+    timeout_readable = 5u;  // 5sec
+    while (true){
+        c = tyble16.getc();
+        buf[i++] = c;
+        if (c == '\n'){
+            ++cr_cnt;
+        }
+        if ((cr_cnt == 2u) || (timeout_readable == 0)){
+            buf[i] = 0;
+            break;
+        }
+    }
+    return buf;
+}
+
+//  Get key input data
+void get_line (char *buff, int len)
 {
-    if        (strstr(buf, "CON")){     // Connection successful
-        state_connection = true;
-    } else if (strstr(buf, "DCO")){     // Disconnect
-        state_connection = false; 
-    } else if (strstr(buf, "ADT")){     // Advertising Timeout
-        state_connection = false;
-        cmd_timeout_cntr = 0;
-    } else if (strstr(buf, "NAK")){     // Failed
-        state_connection = false;
-        if (cmd_timeout_cntr == 0){
-            // Both Advertising Start. Connectable and Discoverable.
-            tyble16.printf("BCD3\r\n");     // send Advertising command
-            cmd_timeout_cntr = ADT_TIME;
+    char c;
+    int idx = 0;
+
+    for (;;) {
+        c = pc.getc();
+        if (c == '\r') {
+            buff[idx++] = c;
+            break;
+        }
+        if ((c == '\b') && idx) {
+            idx--;
+            pc.putc(c);
+            pc.putc(' ');
+            pc.putc(c);
+        }
+        if (((uint8_t)c >= ' ') && (idx < len - 1)) {
+            buff[idx++] = c;
+            pc.putc(c);
         }
     }
+    buff[idx++] = '\r';     // <CR>
+    buff[idx++] = '\n';     // <LF>
+    buff[idx] = 0;
+    pc.putc('\n');
+}
+
+// You do not need to understand & just execute
+void command_preparation(void)
+{
+    char *const cmd_abc    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
+    char cmd_abc_order[10] = {1,18,2,0x80,26,27,0xff,0xff,0xff,0xff};
+
+    char *p = cmd_abc;
+    for(uint32_t i = 0; i < 8;i++){
+        char c = cmd_abc_order[i];
+        if(c == 0x80){cmd[i] = '0';} else
+        if(c == 0xff){cmd[i] = 0;} else
+                     {cmd[i] = *(p + c);}
+    }
 }
-
-// Every one second, check communication status
-void check_connection(void)
-{
-    static int8_t counter = 0;
-
-    if ((received_data == false) && (state_connection == false)){
-        if (++counter >= TIME_OUT){
-            tyble16.putc('\n');
-            counter = 0;
-        }
-    } else {
-        counter = 0;
-    }
-    if (cmd_timeout_cntr != 0){
-        --cmd_timeout_cntr;
-    }
-    received_data = false;
-}