ver1.0

Dependencies:   RingBuffer

main.cpp

Committer:
noboruk
Date:
2018-02-07
Revision:
0:7a3c39a4007a

File content as of revision 0:7a3c39a4007a:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 *  ------- BLE Peripheral/Server UART function --------------------------------
 *          communicate with BLE_UART_Client program
 *      --- Tested on Switch Science mbed TY51822r3 ---
 *
 *      http://www.page.sannet.ne.jp/kenjia/index.html
 *      http://mbed.org/users/kenjiArai/
 *
 *      Started:  March     7th, 2016
 *      Revised:  June     13th, 2016
 *      Revised:  October  22nd, 2017   Run on mbed-OS-5.6.2
 *
 *  Original program:
 *      BLE_LoopbackUART
 *      https://developer.mbed.org/teams/Bluetooth-Low-Energy/
 *                                  code/BLE_LoopbackUART/
 *  Tested Controller Device:
 *      BLE_Uart_Client
 *      https://developer.mbed.org/users/kenjiArai/code/BLE_Uart_Client/
 */

// 2018/02/07 太陽誘電 EYSGCNZWY 使用の試作機向けに改造


//  Include --------------------------------------------------------------------
#include "mbed.h"
#include "BLE.h"
#include "UARTService.h"
#include "RingBuffer.h"

//  Definition -----------------------------------------------------------------
#define     NUM_ONCE            20
#define     BFSIZE              (NUM_ONCE+4)

// If you set 1, you need to connected LED1 and P_0
// Please refer nRF51_WakeUP library
#define     GOTO_SLEEP_MODE     0   
                 
//#define    USE_DEBUG_MODE
#ifdef USE_DEBUG_MODE
#define DEBUG(...) { printf(__VA_ARGS__); }
#else
#define DEBUG(...)
#endif

#define LED1_PIN    P0_25
#define LED2_PIN    P0_23
#define LED3_PIN    P0_21
#define EXT_SW_PIN  P0_11
#define ROM_CS_PIN  P0_12
#define ROM_SCK_PIN P0_13
#define ROM_SDI_PIN P0_15

//  Object ---------------------------------------------------------------------
DigitalOut      alivenessLED(LED1_PIN,1);
DigitalOut      connectedLED(LED2_PIN,1);
DigitalOut      out_led(LED3_PIN,1);
DigitalIn       external_sw(EXT_SW_PIN);
//
// UARTの端子ははEEPROMの端子を流用
DigitalOut      dummy_cs(ROM_CS_PIN,1); //Disable Chip
Serial          pc(ROM_SDI_PIN,ROM_SCK_PIN, 19200);    //SDI=TXD,SCK=RXD

// Object
BLE             ble;
UARTService     *uartServicePtr;
Ticker          ticker;
Ticker          switch_read_ticker;
RingBuffer      ser_bf(1024);
Thread          tsk;
Mutex           bletx_mutex;

//  ROM / Constant data --------------------------------------------------------
//#warning "You need to confirm your device name."
const static char DEVICE_NAME[] = "UART_S";

//  RAM ------------------------------------------------------------------------
Gap::Address_t  my_mac;
uint8_t         tx_buf[BFSIZE];
uint8_t         tx_len                  = 0;
uint8_t         rx_buf[BFSIZE];
volatile bool   trigger_transmit        = false;
volatile bool   trigger_receive         = false;
volatile uint8_t command_continue       = 0;
uint16_t        time_out_cntr           = 3600;
volatile bool   time_out                = false;
uint32_t        sleep_time              = 30;   // unit:second
volatile bool   rx_isr_busy             = false;
//
bool            sw_now;
bool            sw_old;
uint16_t        push_cnt = 0;

//  Function prototypes --------------------------------------------------------
//      BLE
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *);
void connectionCallback(const Gap::ConnectionCallbackParams_t *params);
void onDataWritten_action(const GattWriteCallbackParams *);
//      Tasks
void pc_ser_rx(void);
void data_from_ble(void);
void Update_Values(void);
//      Application related
void command(uint8_t *cmd);
int  xatoi (char **, int32_t *);
void adjust_line(uint8_t *);
//      Interrupt related
void serialRxCallback(void);
void periodicCallback(void);
void switch_tickerCallback(void);

//------------------------------------------------------------------------------
//  Control Program
//------------------------------------------------------------------------------
int main(void)
{
    connectedLED = 1;
    out_led = 1;
    dummy_cs = 1;
    sw_now = !external_sw;
    sw_old = sw_now;

    pc.attach(&serialRxCallback, Serial::RxIrq);
    ticker.attach(periodicCallback, 1);
    switch_read_ticker.attach(switch_tickerCallback, 0.1);
    tsk.start(pc_ser_rx);

    // clear terminal output
    for (int k = 0; k < 5; k++) { pc.printf("\r\n");}
    // opening message          
    pc.printf("UART Communication / Peripheral side\r\n");
    pc.printf("  need Central module (run BLE_Central_EYSGCNZWY program)\r\n");

    ble.init();
    Gap::AddressType_t my_mac_type;
    ble.gap().getAddress(&my_mac_type, my_mac);
    DEBUG(
        "  my_MAC %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n",
        my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0],
        (my_mac_type == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random"
    );
    pc.printf(
        "  my_MAC 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x \r\n",
        my_mac[0], my_mac[1], my_mac[2], my_mac[3], my_mac[4], my_mac[5]
    );

    ble.onDisconnection(disconnectionCallback);
    ble.onConnection(connectionCallback);
    ble.onDataWritten(onDataWritten_action);

    /* setup advertising */
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.accumulateAdvertisingPayload(
        GapAdvertisingData::COMPLETE_LOCAL_NAME,
        (const uint8_t *)DEVICE_NAME,
        sizeof(DEVICE_NAME)
    );
    ble.accumulateAdvertisingPayload(
        GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
        (const uint8_t *)UARTServiceUUID_reversed,
         sizeof(UARTServiceUUID_reversed)
    );

    // Advertize Interval
    ble.setAdvertisingInterval(1000); /* 1000ms; in multiples of 0.625ms. */

    // Start
    ble.startAdvertising();
    UARTService uartService(ble);
    uartServicePtr = &uartService;
    while(true){
        if (time_out){
        }
        if (trigger_transmit){
            static uint8_t cmd_buf[BFSIZE];
            static volatile bool   flag_continue = 0;
            trigger_transmit = false;
            pc.printf((const char*)rx_buf);
            if (flag_continue == true){
                strcat((char *)cmd_buf, (char *)rx_buf);
                if (strchr((const char*)cmd_buf,(int)'\r') == 0){
                    flag_continue = true;
                } else {
                    command(cmd_buf);
                    for(uint8_t i = 0; i < BFSIZE; i++){ cmd_buf[i] = 0;}
                    flag_continue = false;
                }
            }
            if ((rx_buf[0] == '~')){
                strcpy((char *)cmd_buf, (char *)rx_buf);
                if (strchr((const char*)cmd_buf,(int)'\r') == 0){
                    flag_continue = true;
                } else {
                    command(cmd_buf);
                    for(uint8_t i = 0; i < BFSIZE; i++){ cmd_buf[i] = 0;}
                    flag_continue = false; 
                }
            }
        }
        ble.waitForEvent();        
    }
}

void command(uint8_t *cmd)
{
    uint8_t *p = cmd;

    while(*p == ' '){ ++p;}  // skip space
    if (*p++ == '~'){
        while(*p < '!'){ ++p;}  // skip space
        uint8_t c = *p;
        //pc.printf("c=%c\r\n", c);
        switch (c){
            default:
                //pc.printf("\r\nStep(%u)\r\n", __LINE__);
                break;
        }
    }
}

void periodicCallback(void)
{
    if (rx_isr_busy == true){
        rx_isr_busy = false;
    } else {
        tsk.signal_set(0x01);
    }
    alivenessLED = !alivenessLED; 
}

void switch_tickerCallback(void)
{
    sw_old = sw_now;
    sw_now = !external_sw;
    if( sw_now )
    {
        out_led = 0;
    }
    else
    {
        out_led = 1;
    }
    if( ( sw_now != sw_old ) && ( sw_now ) )
    {
        // push triger
        push_cnt++;
        sprintf((char *)tx_buf,"%04X\r\n",push_cnt);
        tx_len = strlen((const char *)tx_buf); 
        Update_Values();
    }
}

void serialRxCallback()
{
    ser_bf.save(pc.getc());
    rx_isr_busy = true;
    tsk.signal_set(0x01);
}

void pc_ser_rx()
{
    static uint8_t linebf_irq[BFSIZE];
    static volatile uint8_t linebf_irq_len = 0;

    while(true){
        Thread::signal_wait(0x01);
        if (ser_bf.check() == 0){
            if (linebf_irq_len != 0){
                linebf_irq[linebf_irq_len] = 0;
                adjust_line(linebf_irq);
                linebf_irq_len = 0;
                bletx_mutex.lock();
                ble.updateCharacteristicValue(
                    uartServicePtr->getRXCharacteristicHandle(),
                    linebf_irq,
                    NUM_ONCE
                );
                bletx_mutex.unlock();
            }
        }
        while(ser_bf.check() != 0){
            char c = ser_bf.read();
            if (c == '\b'){
                linebf_irq_len--;
                pc.putc(c);
                pc.putc(' ');
                pc.putc(c);
            } else if ((c >= ' ') || (c == '\r') || (c == '\n')){
                bool overflow = false;
                if ((c == '\r') || (c == '\n')) {
                    if (linebf_irq_len == NUM_ONCE - 1){// remain only 1 buffer
                        overflow = true;
                        linebf_irq[linebf_irq_len++] = '\r';
                        pc.putc('\r');
                    } else {
                        overflow = false;
                        linebf_irq[linebf_irq_len++] = '\r';
                        linebf_irq[linebf_irq_len++] = '\n';
                        pc.printf("\r\n");
                    }
                } else {
                    linebf_irq[linebf_irq_len++] = c;
                    pc.putc(c);
                }
                if (linebf_irq_len >= NUM_ONCE ){
                    linebf_irq[linebf_irq_len] = 0;
                    adjust_line(linebf_irq);
                    linebf_irq_len = 0;
                    bletx_mutex.lock();
                    ble.updateCharacteristicValue(
                        uartServicePtr->getRXCharacteristicHandle(),
                        linebf_irq,
                        NUM_ONCE
                    );
                    bletx_mutex.unlock();
                    if (overflow == true){
                        overflow = false;
                        linebf_irq[linebf_irq_len++] = '\n';
                        pc.putc('\n');
                    }
                }
            }
        }
    }
}

void adjust_line(uint8_t *bf)
{
    uint8_t i, c;

    for (i = 0; i <NUM_ONCE; bf++, i++){
        c = *bf;
        if (c == 0){ break;}
    }
    for (; i < NUM_ONCE; bf++, i++){ *bf = 0x11;}
    *(bf + 1) = 0;
}

void onDataWritten_action(const GattWriteCallbackParams *params)
{
    if ((uartServicePtr != NULL) && 
        (params->handle == uartServicePtr->getTXCharacteristicHandle()))
    {
        strcpy((char *)rx_buf, (const char *)params->data);
        trigger_transmit = true;
    }
}


void action_tx_wait_time(uint8_t *cmd)
{
    int32_t dt;
    char *p;

    p = (char *)(cmd);
    p += 2; // point to time value
    if (xatoi(&p, &dt)){
        if (dt <= 5){ dt = 5;}
        sleep_time = dt;    // set next wake-up period
    } else {
        DEBUG("data is unknown!\r\n");
        sleep_time = 30;
    }
    DEBUG("slp_t:%d\r\n", sleep_time);
    //pc.printf("slp_t:%d\r\n", sleep_time);
                //          12345678901234567890
    sprintf((char *)tx_buf, "W: %d sec\r\n", sleep_time);
    tx_len = strlen((const char *)tx_buf);
    Update_Values();
}

//  Change string -> integer
int xatoi (char **str, int32_t *res)
{
    unsigned long val;
    unsigned char c, radix, s = 0;

    for (;;){
        c = **str;
        if (c == 0){ return 0;}
        if (c == '-'){ break;}
        if (c == '+'){
            (*str)++;
            c = **str;
        }
        if (c>='0'&& c<='9'){
            break;
        } else {
            (*str)++;
            c = **str;
        }
    }
    if (c == '-') {
        s = 1;
        c = *(++(*str));
    }
    if (c == '0') {
        c = *(++(*str));
        if (c <= ' ') {
            *res = 0;
            return 1;
        }
        if (c == 'x') {
            radix = 16;
            c = *(++(*str));
        } else {
            if (c == 'b') {
                radix = 2;
                c = *(++(*str));
            } else {
                if ((c >= '0')&&(c <= '9')) {
                    radix = 8;
                }   else {
                    return 0;
                }
            }
        }
    } else {
        if ((c < '1')||(c > '9')) {
            return 0;
        }
        radix = 10;
    }
    val = 0;
    while (c > ' ') {
        if (c >= 'a') c -= 0x20;
        c -= '0';
        if (c >= 17) {
            c -= 7;
            if (c <= 9) return 0;
        }
        if (c >= radix) return 0;
        val = val * radix + c;
        c = *(++(*str));
    }
    if (s) val = -val;
    *res = val;
    return 1;
}

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    DEBUG("Disconnected!\r\n");
    DEBUG("Restarting the advertising process\r\n");
    ble.startAdvertising();
    connectedLED = 1;
}

void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
    DEBUG("Connected!\r\n");
    connectedLED = 0;
}

void Update_Values(void)
{
    bletx_mutex.lock();
    ble.updateCharacteristicValue(
        uartServicePtr->getRXCharacteristicHandle(),
        tx_buf,
        tx_len
    );
    bletx_mutex.unlock();
    tx_len = 0;
}