3GIMで画像をアップロードする

タブレイン社の3GIMを使ってSDカードに保存している画像データをAWSに送信してみました。
今回使用したカメラはアドバリーシステム様のDRE-LTE-CAMを使いました。

#環境
* [Genuino 101](http://ssci.to/2670) [^Genuino]
* [3GIMシールドV2.0 for Arduino](http://ssci.to/2984)
* [3GIM V2.1 ](http://ssci.to/2607) [^3GIM]
* [SORACOM Air SIMカード（データ通信のみ） (マイクロ)](https://www.amazon.co.jp/SORACOM-Air-SIM%E3%82%AB%E3%83%BC%E3%83%89%EF%BC%88%E3%83%87%E3%83%BC%E3%82%BF%E9%80%9A%E4%BF%A1%E3%81%AE%E3%81%BF%EF%BC%89-%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%AD/dp/B015FFCY9O)
* [DRE-LTE-CAM 鮮明化カメラユニット](https://msls.kddi.ne.jp/products/details.php?id=38)
* [Arduino イーサネットシールド2](http://ssci.to/2270)

[^Genuino]: Genuino 101は生産終了とのことなので、ArduinoMega等で代用してください。
[^3GIM]: 3GIM V2.1は現在[3GIM V2.2](http://ssci.to/3432)が出ています

#処理の流れ
カメラで撮影したデータを一度SDカードに保存、SDカードに保存している画像データを
3GIMを使ってTCP送信してクラウドへアップロードしています。

![構成図.png](https://qiita-image-store.s3.amazonaws.com/0/154355/5b78d5e4-0967-e9c7-e672-4e3dd36425f0.png)

#処理説明
カメラから画像を取得する処理は割愛します。
今回はSDカードに保存された後を想定して行います。

###1. 3GIM初期化とSDカード初期化
ここからArduinoのプログラムを書いていきます。
まず、3GIMとSDカードの初期化を行います。

```sketch_DRE_LTE_CAM_AWS.ino
// 3GIM初期化
if (a3gs.start() == 0 && a3gs.begin(0, baudrate) == 0) {
    Serial.println("ok");
    delay(15000);   // 電波安定までウェイトをかませる
} else {
    // 接続失敗
    Serial.println("3Fin");
}

// sdカード初期化
Serial.print("SDカード初期化 ...");
if (!SD.begin(chipSelect)) {
    Serial.println("SDカード初期化失敗!");
    return;
}
```

###2. 3GIMをTCP接続する
3GIMをTCP接続して送信の準備をします。
接続がOKなら0が返ってきます。
connectTCPというメソッドで接続先IPとポート番号を指定します。

```sketch_DRE_LTE_CAM_AWS.ino
resflag = a3gs.connectTCP(server_aws, xxxxxxx);

if (resflag == 0) {
    Serial.println("TCP connect OK");
    // 読み取り開始
    done = 1;

} else {
    Serial.print("TCP 接続失敗");
}
```

###3. SDカードを読み取ってサーバーに送信する
SD.open処理で画像ファイルを読み取り、対象バイト数を超えるか、画像ファイルを読み取るまで処理を続けます。
`a3gs.writeBegin`で書き込むデータ数を指定
`a3gSerial.write`で実際に送信するデータを指定します。

```sketch_DRE_LTE_CAM_AWS.ino
// ファイル読み込み
myFile = SD.open("test.jpg");

~省略~

// 既定バイト数読み込み終わった or 全ファイル読み取り終わった
if ((ii == MAX_BYTE) || EndFlag) {

    // TCPサーバーに書き込み処理開始
    a3gs.writeBegin(sizeof(data));
    a3gSerial.write((uint8_t*) data, sizeof(data));
}
```


###全体の流れ

```sketch_DRE_LTE_CAM_AWS.ino
#include <SD.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include <Ethernet2.h>
#include "a3gim2.h"

#define baudrate   115200UL     // ボーレートを速い設定にしておく
boolean EndFlag=0;              // 読み取り終了フラグ
const int chipSelect = 4;       // SDカードチップ番号
File myFile;                    // SDカードファイル
byte readingbyte;
uint8_t done = 0;               // 完了処理番号

#define MAX_BYTE 800    // 800バイトで安定している
const char *server_aws = "xxx.xxx.xxx.xxx"; // TCP接続先サーバーIPアドレス

int resflag;
byte data[MAX_BYTE];

void setup() {
  while(!Serial);
  // ボーレート設定
  Serial.begin(baudrate);
  delay(3000);
  Serial.println("Ready.");

  // 3GIM初期化
  if (a3gs.start() == 0 && a3gs.begin(0, baudrate) == 0) {
    Serial.println("ok");
    delay(15000);   // 電波安定までウェイトをかませる
  } else {
    // 接続失敗
    Serial.println("3Fin");
  }

  // sdカード初期化
  Serial.print("SDカード初期化 ...");
  if (!SD.begin(chipSelect)) {
    Serial.println("SDカード初期化失敗!");
    return;
  }

  // 待ち1秒
  delay(1000);

  // スタート処理開始
  startAction();

}

// スタート処理
void startAction()
{
  // 念のため一旦TCP切断しておく
  a3gs.disconnectTCP();

  // TCPサーバー接続
  do {
    resflag=0;
    done = 0;

    // TCPサーバー接続　お好きなポート番号を指定しましょう
    resflag = a3gs.connectTCP(server_aws, xxxxxxx);
    if (resflag == 0) {
        Serial.println("TCP connect OK");
        // 読み取り開始
        done = 1;

    } else {
      Serial.print("TCP 接続失敗");
    }

  } while(resflag != 0);



}

void loop()
{
    if (done >= 3) {
        // 30秒待ってから再度カメラ画像取得する
        Serial.println("wait Time!");
        delay(30000);
        Serial.println("re start!");

        startAction();
    }

    if (done == 1) {
        // ファイル読み込み
        myFile = SD.open("test.jpg");

        if (myFile) {

            EndFlag=0;
            while(!EndFlag)
            {
                int ii=0; 
                
                while(myFile.available())
                {
                    // 800バイトずつ読み込む
                    if((ii < MAX_BYTE)&&(!EndFlag)) {
                        readingbyte=myFile.read();
                        data[ii]=readingbyte;
                        if((data[ii-1]==0xFF)&&(data[ii]==0xD9)) EndFlag=1;  // ファイルの終了チェック                     
                        ii++;
                    }

                    // 既定バイト数読み込み終わった or 全ファイル読み取り終わった
                    if ((ii == MAX_BYTE) || EndFlag) {

                        // TCPサーバーに書き込み処理開始
                        a3gs.writeBegin(sizeof(data));
                        a3gSerial.write((uint8_t*) data, sizeof(data));

                        delay(50);
                        
                        ii = 0;
                        memset(data,' ',sizeof(data));

                        // 画像ファイル読み取り終了確認            
                        if (EndFlag) {
                            Serial.println("画像読み取り終了!");
                            myFile.close();
                            
                            do {
                                resflag=0;

                                // TCP処理終わらせる
                                a3gs.write("exit");
                                delay(5);

                                // TCP切断する
                                resflag = a3gs.disconnectTCP();

                                if (resflag == 0) {
                                    Serial.println("disconnect OK");
                                } else {
                                    Serial.print("disconnect Failed! ");
                                    Serial.print(resflag);
                                    Serial.println(res);
                                }

                            } while(resflag != 0);

                            done = 2;
                            break;
                        }
                    }
                }
            }
        }

    } else if (done == 2) {
        Serial.println("ALL Fin.");
        done = 3;
        return;
    }

}

```

#サーバーの処理
3GIMから送信されたデータを受け取るための処理をPHPで実装します。
今回はAWSに仮想サーバーを設置し、そこにPHPをインストールしました。

AWSのEC2にPHPで動くTCPサーバーを構築TCPサーバーは`xinetd`を使用しました。
http://rys.hatenablog.com/entry/2012/12/03/php-tcp-server

```server.php

<?php
$test_file="/var/www/html/test.jpg";
$stdin = fopen('php://stdin','r');

if (is_file($test_file)===TRUE) {
    unlink($test_file);
}   
touch($test_file);

while (true) {
    $img = fgets($stdin);
    
    $buffer = trim($img);
    
    if ('exit' === $buffer) {
        // exitが来たら終了する
        break; 
    }   
    
    file_put_contents($test_file, $img, FILE_APPEND);    
}
?>
```

#まとめ
とても簡単に3GIMから画像をアップロードすることが出来ました。
監視カメラ等で利用出来るシーンがあると思います。