IM920地温観測システム CQ 2017ARMセミナー用サンプルプログラム

Dependencies:   C027_Support_ForIM920

Fork of C027_SupportTest by u-blox

main.cpp

Committer:
ntaka206
Date:
2017-07-13
Revision:
36:b89a6e114339
Parent:
35:7838543282c2

File content as of revision 36:b89a6e114339:

#include "mbed.h"
#include "rtos.h"

//------------------------------------------------------------------------------------
/*
 地中温度観測システム親機プログラム
 C027_SupportTestをベースにしているがmain.cのコードはほとんで入れ替え
 (c) NT System Design
*/
#include "MDM.h"
#include "DebugPrint.h"
#include "RingBuf.h"

//------------------------------------------------------------------------------------
// You need to configure these cellular modem / SIM parameters.
// These parameters are ignored for LISA-C200 variants and can be left NULL.
//------------------------------------------------------------------------------------
//! Set your secret SIM pin here (e.g. "1234"). Check your SIM manual.
#define SIMPIN      "0000"
/*! The APN of your network operator SIM, sometimes it is "internet" check your 
    contract with the network operator. You can also try to look-up your settings in 
    google: https://www.google.de/search?q=APN+list */
#define APN         "soracom.io"
//! Set the user name for your APN, or NULL if not needed
#define USERNAME    "sora"
//! Set the password for your APN, or NULL if not needed
#define PASSWORD    "sora"
//------------------------------------------------------------------------------------

#define IM920_TX  P4_28
#define IM920_RX  P4_29
Serial im920(IM920_TX, IM920_RX);

#define AD_NUM 3
#define MV_LSB (1500/1024.) 
#define DEGC_MV (1/10.)
#define PV_LSB (2*1.5/1024)

#define M2X_SERVER   "api-m2x.att.com"
#define M2X_DEVICE_ID   "964d05b1a6f4a8bb02c2a5aaf6e7e268"
#define M2X_API_KEY "602d38e9e8dfcf62e7f87a59c80784ec"
#define M2X_CHID_TEMP0  "temp0"

DigitalOut led(LED1);

// リングバッファサイズ
#define RINGBUF_SIZE    60    // 毎分データで1時間ぶん
// リングバッファ
RingBuf ring(RINGBUF_SIZE);

/*
IM920から受信したADデータをデコードする
sn: IM920 SN
*ad: ADデータ配列 LSB
ret: 0=OK -1=ERR
*/
int im920_conv(char *in, int *sn, int *ad)
{
    char *p;
    char *endptr;
    int l, h;
    int i;
    
    p = strtok(in, ",");
    // SN
    p = strtok(NULL, ",");
    *sn = strtol(p, &endptr, 16);
    // SUM
    p = strtok(NULL, ":");
//    printf("%s ", p);
    // AD0-2
    for(i = 0; i < AD_NUM; i++) {
        p = strtok(NULL, ",");
//    printf("%s ", p);
        l = strtol(p, &endptr, 16);
        p = strtok(NULL, ",");
//    printf("%s ", p);
        h = strtol(p, &endptr, 16);
        ad[i] = l + h*256;
    }
    
    return 0;
}

/**
 * M2X HTTP送信
 * @param http HTTP送信する文字列
 * @param hostname 
 * @return 0=OK -1=ERR
 */
int cloud_http_socket_send(MDMSerial *mdm, char *http, const char *hostname)
{
    int socket;
    char data[512];  // receive
    char    *strtokptr;
    char    *ptr;

    socket = mdm->socketSocket(MDMParser::IPPROTO_TCP);
    if (socket >= 0) {
        mdm->socketSetBlocking(socket, 60*1000); // timeout im msec
        // 指定されたhostにSocket Connect
        if (!mdm->socketConnect(socket, hostname, 80)) {
            ERROR("ERROR socket connect\r\n");
            ERROR("hostname=%s\r\n", hostname);
            return -1;
        }
        TRACE("socketConnect() OK\r\n");
    } else {
        ERROR("sockeSocket() < 0\r\n");
        ERROR("hostname=%s\r\n", hostname);
        return -1;
    }
    int ret = mdm->socketSend(socket, http, strlen(http));
    TRACE("socketSend()=%d\r\n", ret);
    // Recv responce 十分な大きさの変数を渡す必要あり
    ret = mdm->socketRecv(socket, data, sizeof(data)-1);
    TRACE("socketRecv()=%d\r\n", ret);
    // 毎回Socket Closeが必要みたい
    mdm->socketClose(socket);
    mdm->socketFree(socket);
    // HTTPレスポンス受信出来た
    if (ret > 0) {
        TRACE("Socket Recv \"%s\"\r\n", data);
        // HTTPレスポンスcheck
        // 1行目抽出
        ptr = strtok_r(data, "\r\n", &strtokptr);
        // Status Code抽出
        ptr = strtok_r(ptr, " ", &strtokptr);
        ptr = strtok_r(NULL, " ", &strtokptr);
        int code = atoi(ptr);
        // ログにレスポンスコードout
        INFO("HTTP Res=%d\r\n", code);
        // Code=200番台以外ならばエラー
        // m2x 202(Accepted)
        if (code < 200 || code >= 300) {
            ERROR("HTTP Response ERR code=%d\r\n", code);
            return -1;
        }
    } else {
        // レスポンス受信できず
        ERROR("HTTP Response rcv ERR ret=%d\r\n", ret);
        return -1;
    }
    return 0;
}
/**
 * M2X にHTTP PUT送信する
 * HTTPデータを作って送信する
 * API V2 POST
 * @param *data JSONデータ (mag+powerv data)
 * @return 0=OK -1=ERR
 */
static char m2x_http_send(MDMSerial *mdm, RingBufType *rd)
{
    char http_data[512];
    char    json[128];
    // JSONデータ作る
//    sprintf(json, "{ \"value\": \"%6.1f\" }", (rd->ad[0]*MV_LSB-500)*DEGC_MV);
    sprintf(json, "{ \"values\": {\"%04d-temp0\": %6.2f,\"%04d-temp1\": %6.2f,\"%04d-power\": %6.2f}}",
        rd->sn, (rd->ad[0]*MV_LSB-500)*DEGC_MV,
        rd->sn, (rd->ad[1]*MV_LSB-500)*DEGC_MV,
        rd->sn, rd->ad[2]*PV_LSB);

    // HTTP PUTデータ作る
//    snprintf(http_data, sizeof(http_data), "PUT /v2/devices/%s/streams/%04d-temp0/value HTTP/1.0\r\n"
    snprintf(http_data, sizeof(http_data), "POST /v2/devices/%s/update HTTP/1.0\r\n"
        "X-M2X-KEY: %s\r\n"
        "Host: %s\r\n"
        "Content-Type: application/json\r\n"
        "Content-Length: %d\r\n\r\n%s\r\n",
        M2X_DEVICE_ID, M2X_API_KEY, M2X_SERVER,
        strlen(json), json);
    TRACE(http_data);
    // HTTP PUTする
    return cloud_http_socket_send(mdm, http_data, M2X_SERVER);
}
/*
 M2Xへの送信スレッド
*/
void m2x_post_thread(void const *args) {
    RingBufType *rd;
    MDMSerial *mdm = (MDMSerial*)args; // 3Gモデムのインスタンス
    
    while (true) {
        // リングバッファにデータあれば送信
        if (ring.len_get() > 0) {
            led = 1;
            rd = ring.pop();    // リングバッファからPOP
            m2x_http_send(mdm, rd); // M2Xへデータ送信
            led = 0;
        }
        Thread::wait(1000); // 1sec
    }
}

int main(void)
{
    int ret;
    char buf[512] = "";
    const int wait = 100;
    int ad[AD_NUM];
    int sn;
    RingBufType data_im920;

    led = 1;
    printf("start\r\n");
    im920.baud(19200);
    im920.format(8, Serial::None, 1);

    // modem object
    MDMSerial mdm;
    //mdm.setDebug(4); // enable this for debugging issues 
    // initialize the modem 
    MDMParser::DevStatus devStatus = {};
    MDMParser::NetStatus netStatus = {};
    bool mdmOk = mdm.init(SIMPIN, &devStatus);
    mdm.dumpDevStatus(&devStatus);
    if (mdmOk) {
        // wait until we are connected
        mdmOk = mdm.registerNet(&netStatus);
        mdm.dumpNetStatus(&netStatus);
    }
    if (mdmOk)
    {
        // join the internet connection 
        MDMParser::IP ip = mdm.join(APN,USERNAME,PASSWORD);
        if (ip == NOIP)
            printf("Not able to join network");
        else
        {
            mdm.dumpIp(ip);
        }
    } else {
        printf("Modem init ERROR!");
        return 0;
    }
    led = 0;
    // M2X送信スレッド
    Thread thread(m2x_post_thread,&mdm);
    /*
        MAIN LOOP
    */
    printf("LOOP START\r\n");
    while(true) {
        if (im920.gets(buf, 128) > 0) {
            printf("%s", buf);
            if (!im920_conv(buf, &sn, ad)) {
                printf ("IM920: %06d, %04d, %04d, %04d\r\n", sn, ad[0], ad[1], ad[2]);
                printf ("IM920: %06d, %f, %f, %f\r\n", sn, (ad[0]*MV_LSB-500)*DEGC_MV,  (ad[1]*MV_LSB-500)*DEGC_MV, ad[2]*PV_LSB);
                // リングバッファに保存
                data_im920.sn = sn;
                for(int i = 0; i < AD_NUM; i++) {
                    data_im920.ad[i] = ad[i];
                }
                ring.push(&data_im920);
            }
        }
        Thread::wait(wait);
    }
    mdm.powerOff();
    return 0;
}