レンタルサーバーと連携したsakura.ioの運用例

Dependencies:   mbed SakuraIO MPU9250_SPI BME280 gps AQM0802A

main.cpp

Committer:
punix
Date:
2018-11-27
Revision:
2:48e7e85cb169
Parent:
1:11957db1faa5

File content as of revision 2:48e7e85cb169:

#include <mbed.h>
#include <AQM0802A.h>
#include <BME280.h>
#include <MPU9250.h>
#include <SakuraIO.h>
#include "SakuraPinNames.h"
#include "sensors.h"
#include "gps.h"

//LED制御メッセージのタイプ種別の定数
#define MESG_NORMAL 0
#define MESG_INIT 1


// Serial over CMSIS_DAP
Serial pc(DAP_UART_TX, DAP_UART_RX, 9600);

// GPS
Serial gps(GPS_TX, GPS_RX, 9600);
DigitalOut gps_en(GPS_EN);

// LED
DigitalOut led_1(LED1);
DigitalOut led_2(LED2);
DigitalOut led_3(LED3);
DigitalOut led_4(LED4);

// LCD backlight
DigitalOut lcd_led(LED_LCD);

// Switch
DigitalIn sw_1(SW1);
DigitalIn sw_2(SW2);
DigitalIn sw_3(SW3);
DigitalIn sw_4(SW4);
DigitalIn sw_5(SW5);
DigitalIn sw_6(SW6);

// Internal I2C
I2C internal_i2c(I2C_INTERNAL_SDA, I2C_INTERNAL_SCL);
AQM0802A lcd(internal_i2c);
BME280 bme280(internal_i2c);

// SPI
SPI internal_mpu9250_spi(SPI_MPU_MOSI, SPI_MPU_MISO, SPI_MPU_SCK);
mpu9250_spi mpu9250(internal_mpu9250_spi, SPI_MPU_CS);

// sakura.io
//SakuraIO_I2C sakuraio(I2C_SDA, I2C_SCL);
#define SPI_FREQ (350000)
SPI sakuraio_spi(PB_15, PB_14, PB_13);
DigitalOut sakuraio_cs(PB_12);
SakuraIO_SPI sakuraio(sakuraio_spi, sakuraio_cs);

SensorData sensor_data;

// GPS UART buffer
char uart_buffer[128] = {0};
int uart_buffer_index = 0;

//LED応対s申告の為のLTE接続した直後を検出するためのフラグ
// 0:切断、1:接続直後でLED情報送信中、2:LED状態到達確認済み
int connected_now = 0;

// NMEA Decoder
GPSDecoder gps_decoder;

void gps_uart_buffering_handler();

const int SEND_INTERVAL_TICKS_PAR_COUNT = 1500;

const int RETRY_INTERVAL_TICKS_PAR_COUNT = 50;

void setup()
{
    lcd_led = 1;
    pc.printf("Hello World !\r\n");
    lcd.cls();
    lcd.printf("Hello");
    connected_now = 0;

    // Initialize sensors
    bme280.initialize();
    pc.printf("BME280 ok.\r\n");
    mpu9250.init(1, BITS_DLPF_CFG_188HZ);
    pc.printf("MPU9250 ok. WHOAMI=%02x\r\n", mpu9250.whoami());
    if (mpu9250.whoami() != 0x71) {
        pc.printf("[ERROR] MPU9250 init fail.\r\n");
    }

    mpu9250.set_gyro_scale(BITS_FS_2000DPS);    //Set full scale range for gyros
    mpu9250.set_acc_scale(BITS_FS_16G);          //Set full scale range for accs
    mpu9250.calib_acc();
    mpu9250.AK8963_calib_Magnetometer();

    // active high
    gps_en = 1;
    gps.attach(&gps_uart_buffering_handler, Serial::RxIrq);

    led_1 = 1;
    led_2 = 0;
    
    pc.printf("Send par %d seconds.\r\n", (SEND_INTERVAL_TICKS_PAR_COUNT * 200) / 1000);
}

void read_sensor_data()
{
    sensor_data.bme280.temperature = bme280.getTemperature();
    sensor_data.bme280.pressure = bme280.getPressure();
    sensor_data.bme280.humidity = bme280.getHumidity();

    mpu9250.read_all();
    sensor_data.mpu9250.temperature = mpu9250.Temperature;
    for (int cnt_send = 0; cnt_send < 3; cnt_send++) {
        sensor_data.mpu9250.accelerometer[cnt_send] = mpu9250.accelerometer_data[cnt_send];
        sensor_data.mpu9250.gyroscope[cnt_send] = mpu9250.gyroscope_data[cnt_send];
        sensor_data.mpu9250.magnetometer[cnt_send] =  mpu9250.Magnetometer[cnt_send];
    }
}

void enqueue_sensor_data(int counter)
{
    sakuraio.enqueueTx(0, (int32_t)counter);
    sakuraio.enqueueTx(1, sensor_data.bme280.temperature);
    sakuraio.enqueueTx(2, sensor_data.bme280.pressure);
    sakuraio.enqueueTx(3, sensor_data.bme280.humidity);
    sakuraio.enqueueTx(4, sensor_data.mpu9250.accelerometer[0]);
    sakuraio.enqueueTx(5, sensor_data.mpu9250.accelerometer[1]);
    sakuraio.enqueueTx(6, sensor_data.mpu9250.accelerometer[2]);
    sakuraio.enqueueTx(7, sensor_data.mpu9250.gyroscope[0]);
    sakuraio.enqueueTx(8, sensor_data.mpu9250.gyroscope[1]);
    sakuraio.enqueueTx(9, sensor_data.mpu9250.gyroscope[2]);
    sakuraio.enqueueTx(10, sensor_data.mpu9250.magnetometer[0]);
    sakuraio.enqueueTx(11, sensor_data.mpu9250.magnetometer[1]);
    sakuraio.enqueueTx(12, sensor_data.mpu9250.magnetometer[2]);
    sakuraio.enqueueTx(13, gps_decoder.get_longitude());
    sakuraio.enqueueTx(14, gps_decoder.get_latitude());
    sakuraio.enqueueTx(15, gps_decoder.get_unixtime());
}

void gps_uart_buffering_handler()
{
    while (gps.readable() == 1) {
        char c = gps.getc();
        if (c == '\r') {
            continue;
        }
        uart_buffer[uart_buffer_index] = c;
        uart_buffer_index++;
        if (c == '\n') {
            uart_buffer[uart_buffer_index - 1] = '\0';
            gps_decoder.set_nmea_message(uart_buffer);
            gps_decoder.decode();
            uart_buffer_index = 0;
        }
    }
}


void loop()
{
    static int cnt_send = 1;
    static int tick_by_200ms = 0;
    static int stat_sw5 = -1;
    uint8_t rx_available = 0;
    uint8_t rx_queued = 0;
    uint8_t rx_ch=0;
    uint8_t rx_type=0;
    uint8_t rx_value[8];
    int64_t rx_offset=0;
    int64_t rx_val;
    uint32_t tx_tmp;
    uint8_t ch20_ctrl;
    uint32_t ch20_id;
    uint8_t ch20_mesg;

    if((sakuraio.getConnectionStatus() & 0x80) == 0x00) {
        //Offline
        lcd.cls();
        lcd.printf("Offline");
        pc.printf("Network is offline.\r\n(After 1 sec to running retry.)\r\n");
        wait(1);
        connected_now = 0;
        return;    
    }
    else {
        //ON_LINEだったとき
        if(0 == connected_now){
            //接続直後(直前までオフラインだった)時
            
            //現在のLED状態を申告する送信
            tx_tmp = (MESG_INIT << 8) | (lcd_led & 0xFF);
            sakuraio.enqueueTx(20, tx_tmp);
            sakuraio.send();
            
            //接続直後でLED情報送信中
            connected_now = 1;
            
            //過去の送信カウント数クリアと、Offlineになってしまった液晶のsend再表示の為
            stat_sw5 = -1;
        }
        if(1 == connected_now){
            //現在のLED状態を申告に対する応答がプラットフォームから帰ってきてない時
            if((tick_by_200ms % RETRY_INTERVAL_TICKS_PAR_COUNT) == 0){
                //一定時間経過していたら再度LED状態を申告
                tx_tmp = (MESG_INIT<<8) | (lcd_led & 0xFF);
                sakuraio.enqueueTx(20, tx_tmp);
                sakuraio.send();
            }
        }   
    }

            
            
    //スイッチ状態が切り替わった時、もしくは、LTE接続が一旦切れて復帰した時
    if (stat_sw5 != sw_5) {
        stat_sw5 = sw_5;
        led_3 = stat_sw5;   //State: `Send Enable'
        if (stat_sw5 == 0) {
            lcd.cls();
            lcd.printf("Send:OFF");
        } else {
            cnt_send = 1;
            tick_by_200ms = 0;
            lcd.cls();
            lcd.printf("Send:ON");
        }
    }
    
    if (stat_sw5 == 1) {
        //送信スイッチONの時。送信処理開始
        if ((tick_by_200ms % SEND_INTERVAL_TICKS_PAR_COUNT) == 0) {  //Send data intarval is 5 minutes.
            pc.printf("\r\n\r\n--------------------\r\n");
            read_sensor_data();
            pc.printf("BME280\r\n");
            pc.printf("\tTemp: %.2fC\r\n", sensor_data.bme280.temperature);
            pc.printf("\tPres: %.2fhPa\r\n", sensor_data.bme280.pressure);
            pc.printf("\tHum: %.2f%%\r\n", sensor_data.bme280.humidity);
            pc.printf("MPU9250\r\n");
            pc.printf("\tTemp: %.2fC\r\n", sensor_data.mpu9250.temperature);
            for (int j = 0; j < 3; j++) {
                pc.printf("\tacc[%d]: %.2f\r\n", j, sensor_data.mpu9250.accelerometer[j]);
                pc.printf("\tgyro[%d]: %.2f\r\n", j, sensor_data.mpu9250.gyroscope[j]);
                pc.printf("\tmag[%d]: %.2f\r\n", j, sensor_data.mpu9250.magnetometer[j]);
            }
            pc.printf("GPS\r\n");
            pc.printf("\tlat: %f%c\r\n", 
                    gps_decoder.get_latitude(), 
                    gps_decoder.get_latitude() >= 0 ? 'N' : 'S');
            pc.printf("\tlon: %f%c\r\n", 
                    gps_decoder.get_longitude(),
                    gps_decoder.get_longitude() >= 0 ? 'E' : 'W');
            pc.printf("\tspeed: %fkm/h\r\n", gps_decoder.get_speed());
            pc.printf("\tmove_direction: %f\r\n", gps_decoder.get_move_direction());
            pc.printf("\tdate: %d/%02d/%02d %02d:%02d:%02d (UTC)\r\n",
                    gps_decoder.get_year(), gps_decoder.get_month(), gps_decoder.get_day(),
                    gps_decoder.get_hour(), gps_decoder.get_min(), gps_decoder.get_sec());
            pc.printf("\tUNIX time: %d\r\n", gps_decoder.get_unixtime());
            led_2 = 1;
            pc.printf("Send:%d\r\n", cnt_send);
            lcd.setCursor(0, 1);
            lcd.printf("%d", cnt_send);
            enqueue_sensor_data(cnt_send);
            sakuraio.send();
            cnt_send++;
            led_2 = 0;
            pc.printf("After %d sec to send.\r\n", (int)(SEND_INTERVAL_TICKS_PAR_COUNT * 0.2));
        }
    }
    
    //受信確認処理
    do {
        rx_available = 0;
        if ( CMD_ERROR_NONE == sakuraio.getRxQueueLength(&rx_available, &rx_queued)) {
            //getRxQueueLengthが成功したとき
            if (0 < rx_queued) {
                 //sakura.ioモジュールの受信キューにデータが入っているとき
                 //キューからひとつデータを取り出す
                if ( CMD_ERROR_NONE == sakuraio.dequeueRx(&rx_ch, &rx_type, rx_value, &rx_offset)) {
                    //正常に受信キューからデータを取り出せたとき
                    if ( (20 == rx_ch) && (0x49 == rx_type) ) {
                        //LED状態の要求、もしくは、LED状態申告の回答のとき
                        
                        //受信した32bit整数値が、8bit値が4つの配列になって届くので、ひとつの整数値に整形
                        rx_val = ( (int64_t)rx_value[3] << 24) + ( (int64_t)rx_value[2] << 16) + ( (int64_t)rx_value[1] << 8) + ( (int64_t)rx_value[0] << 0);
                        
                        //受信した32bit値からbitmapに従ってそれぞれの情報の切り出し
                        ch20_ctrl = rx_val & 0xFF;
                        ch20_mesg = (rx_val>>8) & 0xFF;
                        ch20_id = (rx_val>>16) & 0xFFFF;
                        
                        
                        if ( (1 == ch20_ctrl) && (MESG_NORMAL == ch20_mesg)) {
                            //LED状態の要求だったとき
                            tx_tmp = (ch20_id<<16) | (MESG_NORMAL<<8) | (lcd_led & 0xFF);
                            sakuraio.enqueueTx(20, tx_tmp);
                            sakuraio.send();
                        }
                        if ( (1 == ch20_ctrl) && (MESG_INIT == ch20_mesg)) {
                            //LED状態申告の回答だったとき
                            //フラグを進めて、LED状態到達確認済みとし、再送処理を止める
                            connected_now = 2;
                        }
                    }
                    if ( (21 == rx_ch) && (0x49 == rx_type) ) {
                        //LED設定のとき
                        
                        //受信した32bit整数値が、8bit値が4つの配列になって届くので、ひとつの整数値に整形
                        rx_val = ( (int64_t)rx_value[3] << 24) + ( (int64_t)rx_value[2] << 16) + ( (int64_t)rx_value[1] << 8) + ( (int64_t)rx_value[0] << 0);
                        
                        //受信した32bit値からbitmapに従ってそれぞれの情報の切り出し
                        ch20_ctrl = rx_val & 0xFF;
                        ch20_mesg = (rx_val>>8) & 0xFF;
                        ch20_id = (rx_val>>16) & 0xFFFF;
                        
                        
                        if ( 1 == ch20_ctrl || 0 == ch20_ctrl ) {
                            //LED制御値が、0(OFF) or 1(ON)だったとき
                            
                            //LEDに制御値を設定
                            lcd_led = ch20_ctrl;
                            
                            //設定後の値をプラットフォームへ返送
                            tx_tmp = (ch20_id<<16) | (MESG_NORMAL<<8) | (lcd_led & 0xFF);
                            sakuraio.enqueueTx(20, tx_tmp);
                            sakuraio.send();
                        }
                    }
                }
            }
        }
    }while(0 < rx_queued); //受信キューが空になるまで回す
                            
                
    
    led_1 = !led_1;
    led_4 = !sw_4;
    tick_by_200ms++;
    wait(0.2);
}


int main()
{
    setup();
    while(1) {
        loop();
    }
}