library for enebular edge agent board(version p1)

Dependents:   ina-hack-2nd

Eeabp1.cpp

Committer:
koyo_take
Date:
2017-10-22
Revision:
3:f80f2838a956
Parent:
2:d48fcae8b5bd

File content as of revision 3:f80f2838a956:

#include "Eeabp1.h"
#include <string.h>

static const int lora_msg_max_len = 11;

Eeabp1::Eeabp1() : pwr_en(P0_0), led(P0_23), 
    lora_power(P0_5), lora_reset(P0_22), grove_power(P0_6),
    grv_sel2a(P0_19), grv_sel2g(P0_18), grv_sel1a(P0_17), grv_sel1g(P0_16),
    grv_p1s1a(P0_2), grv_p1s2a(P0_1),
    grv_p2s1a(P0_4), grv_p2s2a(P0_3)
{
    this->led_state = LED_OFF;
    this->led = 0;
    this->serial = new RawSerial(P0_9, P0_11);
    this->serial->baud(9600); /* use for LoRa */
    this->pwr_en = 1; // メイン電源投入
    this->lora_power = 0;
    this->lora_reset = 0;
    this->grove_power = 0;
    this->lora_enabled = false;
    this->grove_enabled = false;
    // Grove端子をHiZに
    this->grv_sel1g = 1;
    this->grv_sel1a = 1;
    this->grv_sel2g = 1;
    this->grv_sel2a = 1;
    grv_p1s1do = NULL, grv_p1s2do = NULL, grv_p1s1di = NULL, grv_p1s2di = NULL;
    grv_p2s1do = NULL, grv_p2s2do = NULL, grv_p2s1di = NULL, grv_p2s2di = NULL;
    temp_humid_sensor = NULL;
}

int Eeabp1::setLedState(EeabLedState state)
{
    this->led_state = state;

    if (this->led_state == LED_OFF) {
        this->led = 0;
    } else {
        this->led = 1;
    }

    return 0;
}

void Eeabp1::loop(void)
{
    switch (this->led_state) {
        case LED_OFF:
            /* fall through */
        case LED_ON:
            break;
        case LED_BLINK_FAST:
        case LED_BLINK_MID:
        case LED_BLINK_SLOW:
            this->led = !this->led;
            break;
    }
}

int Eeabp1::debug(const char * format, ...)
{
    char tmp[80];
    int ret;

    std::va_list arg;
    va_start(arg, format);
    vsnprintf(tmp, sizeof(tmp), format, arg);
    va_end(arg);

    delete this->serial;
    this->serial = new RawSerial(P0_8, P0_10);
    ret = this->serial->puts(tmp);
    delete this->serial;
    this->serial = new RawSerial(P0_9, P0_11);

    return ret;
}

static char linebuf[64];
int Eeabp1::setLoRaPower(bool on)
{
    int ret;
    int retry;
    const int retry_max = 10;

    if (on) {
        if (lora_enabled)
            return 0;  /* power is already on, do nothing */

        this->lora_power= 1;
        this->lora_reset = 1;
        wait_us(500000);
        serial->printf("mod set_echo off\r\n"); // ローカルエコー:無効
        wait(1);
        flushSerial();

        serial->printf("mod factory_reset\r\n"); // ファクトリーリセットを行い鍵をリフレッシュ
        ret = chkSerialCharOk();
        if (ret != 0)
            return ret;
        serial->printf("mod set_echo off\r\n"); // ローカルエコー:無効
        wait(1);
        for(retry=0; retry < retry_max; retry++) {
            serial->printf("lorawan join otaa\r\n"); // Gatewayに接続(OTAA)
            ret = chkSerialCharRes('a'); // 成功 ">> accepted" 失敗 ">> unsuccess"
            if (ret == 0)
                break;
            wait(10);
        }
        if (retry == retry_max)
            return __LINE__;

        serial->printf("lorawan set_dr 2\r\n"); // データレートの設定(11byte)
        ret = chkSerialCharOk();
        if (ret != 0)
            return ret;

        this->lora_enabled = true;
    } else { /* off */
        if (!lora_enabled)
            return 0;  /* power is already off, do nothing */

        lora_power= 0;
        lora_enabled = false;
    }
    
    return 0;
}

int Eeabp1::sendLoRaString(const char * format, ...)
{
    char str[lora_msg_max_len+1] = {0x00, };
    char msg[64];
    char *p = msg;

    std::va_list arg;
    va_start(arg, format);
    vsnprintf(str, sizeof(str), format, arg);
    va_end(arg);

    p += sprintf(msg, "lorawan tx ucnf %d ", getLoraPort());
    for (unsigned int i = 0; i < strlen(str); i++) {
        p += sprintf(p, "%02x", str[i]);
    }
    sprintf(p, "\r\n");

    flushSerial();
    serial->puts(msg);

    return 0;
}

int Eeabp1::sendLoRaStringAndReceiveResponse(char res[], const char * format, ...)
{
    char str[lora_msg_max_len+1] = {0x00, };
    char msg[64];
    char *p = msg;
//    int count;
    char *tp;
    int ret;

    std::va_list arg;
    va_start(arg, format);
    vsnprintf(str, sizeof(str), format, arg);
    va_end(arg);

    p += sprintf(msg, "lorawan tx ucnf %d ", getLoraPort());
    for (unsigned int i = 0; i < strlen(str); i++) {
        p += sprintf(p, "%02x", str[i]);
    }
    sprintf(p, "\r\n");

    flushSerial();
    serial->puts(msg);

    getline(linebuf, sizeof(linebuf), 10000);
//    count = getline(linebuf, sizeof(linebuf), 10000);
//    this->debug("%d '%s'\r\n", count, linebuf);
    
    ret = -1;
    res[0] = '\0';
    tp = strtok(linebuf, " \r\n");
    while(tp != NULL){
//        this->debug("%s\r\n", tp);
        if (strcmp(tp, "tx_ok") == 0) {
            ret = 0;
        } else if (strcmp(tp, "err") == 0) {
            ret = -2;
        } else if (strcmp(tp, "rx") == 0) {
//            this->debug("rx found\r\n");
            tp = strtok(NULL, " \r\n");
//            this->debug("%s\r\n", tp);
            tp = strtok(NULL, " \r\n");
//            this->debug("%s\r\n", tp);
            strcpy(res, tp);
        }
        tp = strtok(NULL, " \r\n");
    }

    return ret;
}

int Eeabp1::sendLoRaBinary(const char *payload, size_t len)
{
    char msg[64];
    char *p = msg;

    if (lora_msg_max_len < len)
        return -1;

    p += sprintf(msg, "lorawan tx ucnf %d ", getLoraPort());
    for (unsigned int i = 0; i < len; i++) {
        p += sprintf(p, "%02x", payload[i]);
    }
    sprintf(p, "\r\n");

    flushSerial();
    serial->puts(msg);

    return 0;
}

void Eeabp1::setGrovePower(bool on)
{
    if (on) {
        if (grove_enabled)
            return; /* power is already on, do nothing */

        grove_power = 1;
    } else {
        if (!grove_enabled)
            return; /* power is already off, do nothing */
        
        // Grove端子をHiZに
        grv_sel1g = 1;
        grv_sel1a = 1;
        grv_sel2g = 1;
        grv_sel2a = 1;
        grove_power = 0;
    }
}

int Eeabp1::setGrovePortType(EeabGrovePort port, EeabGrovePortType type)
{
    switch (port) {
        case GROVE_CH1:
            if (type == GROVE_ANALOG) {
                grv_sel1g = 1;
                grv_sel1a = 0;
            } else {
                grv_sel1g = 0;
                grv_sel1a = 1;
            }
            break;
        case GROVE_CH2:
            if (type == GROVE_ANALOG) {
                grv_sel2g = 1;
                grv_sel2a = 0;
            } else {
                grv_sel2g = 0;
                grv_sel2a = 1;
            }
            break;
        default:
            /* do nothing */
            break;
    }

    return 0;
}

int Eeabp1::setGroveDioDirection(EeabGrovePort port, EeabGroveDioDirection dir, Callback<void()> f)
{
    switch (port) {
        case GROVE_CH1:
            if(dir == GROVE_DIO_OUT) {
                if (grv_p1s1di) {
                    delete grv_p1s1di;
                    grv_p1s1di = NULL;
                }
                grv_p1s1do = new DigitalOut(P0_13);

                if (grv_p1s2di) {
                    delete grv_p1s2di;
                    grv_p1s2di = NULL;
                }
                grv_p1s2do = new DigitalOut(P0_12);
            } else { /* GROVE_DIO_IN */
                if (grv_p1s1do) {
                    delete grv_p1s1do;
                    grv_p1s1do = NULL;
                }
                grv_p1s1di = new InterruptIn(P0_13);
                if (f)
                    grv_p1s1di->rise(f);

                if (grv_p1s2do) {
                    delete grv_p1s2do;
                    grv_p1s2do = NULL;
                }
                grv_p1s2di = new InterruptIn(P0_12);
                grv_p1s2di->rise(f);
            }
            break;
        case GROVE_CH2:
            if(dir == GROVE_DIO_OUT) {
                if (grv_p2s1di) {
                    delete grv_p2s1di;
                    grv_p2s1di = NULL;
                }
                grv_p2s1do = new DigitalOut(P0_15);

                if (grv_p2s2di) {
                    delete grv_p2s2di;
                    grv_p2s2di = NULL;
                }
                grv_p2s2do = new DigitalOut(P0_14);
            } else { /* GROVE_DIO_IN */
                if (grv_p2s1do) {
                    delete grv_p2s1do;
                    grv_p2s1do = NULL;
                }
                grv_p2s1di = new InterruptIn(P0_15);
                if (f)
                    grv_p2s1di->rise(f);

                if (grv_p2s2do) {
                    delete grv_p2s2do;
                    grv_p2s2do = NULL;
                }
                grv_p2s2di = new InterruptIn(P0_14);
                grv_p2s2di->rise(f);
            }
            break;
        default:
            /* do nothing */
            break;
    }

    return 0;
}

int Eeabp1::setGroveDio(EeabGrovePort port, EeabGroveDio val)
{
    switch (port) {
        case GROVE_CH1:
            *grv_p1s1do = val;
            *grv_p1s2do = val;
            break;
        case GROVE_CH2:
            *grv_p2s1do = val;
            *grv_p2s2do = val;
            break;
        default:
            break;
    }

    return 0;
}

int Eeabp1::setGroveDio(EeabGrovePort port, EeabGroveSig sig , EeabGroveDio val)
{
    switch (port) {
        case GROVE_CH1:
                    (sig == GROVE_SIG1) ? *grv_p1s1do = val : *grv_p1s2do = val;
            break;
        case GROVE_CH2:
                    (sig == GROVE_SIG1) ? *grv_p2s1do = val : *grv_p2s2do = val;
            break;
        default:
            break;
    }
    return 0;
}


int Eeabp1::getGroveDio(EeabGrovePort port, EeabGroveSig sig)
{
    switch (port) {
        case GROVE_CH1:
            if (grv_p1s1di == NULL)
                return -1;
            return (sig == GROVE_SIG1) ?
                grv_p1s1di->read() : grv_p1s2di->read();
        case GROVE_CH2:
            if (grv_p2s1di == NULL)
                return -1;
            return (sig == GROVE_SIG1) ?
                grv_p2s1di->read() : grv_p2s2di->read();
        default:
            break;
    }

    return -1;
}

float Eeabp1::getGroveAnalog(EeabGrovePort port, EeabGroveSig sig)
{
    switch (port) {
        case GROVE_CH1:
            return (sig == GROVE_SIG1) ?
                grv_p1s1a.read() : grv_p1s2a.read();
        case GROVE_CH2:
            return (sig == GROVE_SIG1) ?
                grv_p2s1a.read() : grv_p2s2a.read();
        default:
            break;
    }

    return -1;
}

int Eeabp1::enableTempHumidSensor(void)
{
    temp_humid_sensor = new Sht31(P0_30, P0_7);    
    return 0;
}

float Eeabp1::getTemp(void)
{
    if (!temp_humid_sensor)
        return -1;

    return temp_humid_sensor->readTemperature();
}

float Eeabp1::getHumid(void)
{
    if (!temp_humid_sensor)
        return -1;

    return temp_humid_sensor->readHumidity();
}

int Eeabp1::enableAccelerometer(void)
{
    accelerometer = new ADXL345_I2C(P0_30, P0_7);

    this->debug("Device ID is: 0x%02x\n", accelerometer->getDeviceID());
    wait(.001);
    
    // These are here to test whether any of the initialization fails. It will print the failure
    if (accelerometer->setPowerControl(0x00)) {
         this->debug("didn't intitialize power control\n"); 
         return -1;
    }
    wait(.001);
     
    //Full resolution, +/-16g, 4mg/LSB.
    if(accelerometer->setDataFormatControl(0x0B)) {
        this->debug("didn't set data format\n");
        return -1;
    }
     wait(.001);
     
    //3.2kHz data rate.
    if(accelerometer->setDataRate(ADXL345_3200HZ)) {
        this->debug("didn't set data rate\n");
        return -1;
    }
    wait(.001);
     
    //Measurement mode.
    if(accelerometer->setPowerControl(MeasurementMode)) {
        this->debug("didn't set the power control to measurement\n");
        return -1;
    }
    
    return 0;
}

int Eeabp1::getAcc(int *x, int *y, int *z)
{
    int readings[3] = {0, 0, 0};
    accelerometer->getOutput(readings);
    *x = readings[0];
    *y = readings[1];
    *z = readings[2];
    
    return 0;
}

/* private functions */
void Eeabp1::flushSerial()
{
    while(serial->readable() == true) {
        serial->getc();
        wait_us(1000);
    }
}

inline ssize_t Eeabp1::getline(char *buf, size_t bufsize, int timeout_ms)
{
    char c;
    size_t receivedChars = 0;
    Timer t;

    t.start();

    *buf = '\0';
    do {
        if (!serial->readable()) {
            wait_us(50);
            continue;
        }

        c = serial->getc();
        /*
        if (c == '\r' || c == '\n') {
            if (receivedChars == 0) {
                continue; //Ignore if first character is delimiter    
            }
            if (serial->readable()) {
                continue; //continue to read next line    
            }
            break;
        }
        */
        if (receivedChars < bufsize - 1)
        {
            *buf++ = c;
            receivedChars++;
        }
    } while(t.read_ms() < timeout_ms);
    *buf++ = '\0';

    t.stop();

    return receivedChars;
}

int Eeabp1::chkSerialChar(const char ch, uint16_t timeout_ms)
{
    uint32_t timeoutCount = 0;

    while(serial->readable() == false) {
        wait_us(50);
        timeoutCount++;
        if((timeoutCount  / 20) >= timeout_ms)
            return -2;
    }

    return (serial->getc() == ch) ? 0 : -1;
}

int Eeabp1::waitSerialChar(const char ch,uint16_t timeout_ms)
{
    uint32_t timeoutCount = 0;

    do {
        while(serial->readable() == false) {
            wait_us(50);
            timeoutCount++;
            if((timeoutCount  / 20) >= timeout_ms)
                return -2;
        }
    } while(serial->getc() != ch);

    return 0;
}

int Eeabp1::chkSerialCharOk()
{
    int ret;
    ret = waitSerialChar('>',4000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar('>',2000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar(' ',2000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar('O',2000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar('k',2000);
    if (ret != 0)
        return __LINE__;

    ret = waitSerialChar('>',4000);
    if (ret != 0)
        return __LINE__;

    wait_us(1000);

    return 0;
}

int Eeabp1::chkSerialCharRes(char chkchr)
{
    int ret;
    ret = waitSerialChar('>', 10000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar('>',2000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar(' ',2000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar('O',2000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar('k',2000);
    if (ret != 0)
        return __LINE__;

    ret = waitSerialChar('>',16000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar('>',2000);
    if (ret != 0)
        return __LINE__;

    ret = chkSerialChar(' ',2000);
    if (ret != 0)
        return __LINE__;

    ret = waitSerialChar(chkchr,4000);
    if (ret != 0)
        return __LINE__;

    ret = waitSerialChar('>',4000);
    if (ret != 0)
        return __LINE__;

    wait_us(1000);

    return 0;
}