MLAのFrameworkでTCP/IPを試して見るその4
(SMTPクライアント:Eメール送信)

〔PICの動かせ方入門に戻る〕
〔その1〕 〔PING〕 〔TELNET〕   〔XC16編〕 〔TCPclient〕 〔TCPserver〕 〔HTTPserver〕


前ページの"その1"では、FrameworkのTCP/IPスタックファイルの話と、tcpip プ ロ ジェクト作成方法の
話を書きましたので先ずはそちらからご覧下さい。
このページでは、SMTPモジュールを 使ってEメールの送信動作を実験してみます。
尚、PING動作の実験と”データのカプセル化”の話は"その2(PING)"を参照下さい。


これが今回のSMTPクライアント構成でのモデルです。
ア プリケーション層
DNS SMTP
ト ランスポー ト層 
UDP TCP
インターネット 層
IP (ICMP)
ARP
Stack Task
物理層
     ENC28J60

Stack Task
 着信パケットのチェックを行い、上層のスタックモジュールにルーティングします。
 このタスクが"ENC28J60.c"のドライバーを呼び出す事になります。
 タイムリーな応答を確保するために、この関数を定期的に呼び出さなければなりません。
 なのでぇ、アプリケーションを作成する場合は必要最小限のDelayを使い、ステートマシン的な
 小刻みな処理を施す必要が有ります。

ARP
 インターネットの世界ではIPアドレスで送受信を行っていますが、インターネットは
 イーサネットプロトコルを利用しているので相手先のMACアドレスを知らないと送る事が出来ません。
 でぇ、このIPアドレスからMACアドレスの交換を行ってくれるのがARPです。
 交換の仕方はこちら「ア ドレス解決とARP」を参照下さい。
 通知されたMACアドレスは通常キャッシュに記憶されるのですが、このARPにはキャッシュ無りません

IP
 TCP/IPのデバイス間でIPアドレスによるデータの送受信を行います。
 単純にパケットの交換のみが役割で、データの分割も 行う。
 IPプロトコルのフレームフォーマットやヘッダ内容はこちらこちらを 参照しましょう。

ICMP
 IPは通信異常が発生しても報告する機能が無いのでこれを補う為にICMPで通信エラーや
 ネットワークの状況を通知してくれるらしい。
 ICMPには色々な要求メッセージが有る様だが、TCP/IPスタックのICMPは”エコー要求”と
 ”エコー応答”のみっぽいです。
 ICMPのフレームフォーマットは「ICMPとPINGコマンド」を参照しましょう、
 ICMPヘッダについてはこちらも参照しましょう。

 ※ ICMPの実験は、"その2(PING)"の実験1を参照下さい。


UDP
 送信完了等の確認を行わない比較的単純なプロトコル(こち らも見ておこう)。
 通信中のデータ異常への対応などは上位のプロトコル(アプリケーション層)で行います。
 信頼性を重視する必要が無く、速度を重視するアプリケーション で使用されます
 信頼性を重視する場合は"TCPプロトコル"を使用します

TCP
 通信異常や送信完了等の確認を行わない比較的単純な通信を行うUDPに対して
 TCPは1対1 の通信を確立し、送信確認やパケット順のチェックに欠損パケットの再送といった
 事を行うので信頼性の必要な通信で使用されます。
 TCPヘッダについてはこちらも参照しましょう。

DNS
 今回追加するのは、"DNSクライアント"部分のみで す、"DNSサーバー"側は含まれません。
 DNSは名前解決機能が有り、ホスト名からIPアドレスに変換する為にDNSサーバーへ
 問い合わせパケット(正引き) の発行処理を行います。

 ※ 今回は"SMTPサーバー"の名前解決に用いる為に"DNS"が追加されます。
 (ここの実験では、YAHOO!のSMTPサーバー:"smtp.mail.yahoo.co.jp"の名前解決で使用されます)
 ※ DNSの実験は、"その2(PING)"の実験3を参照下さい。

SMTP
 SMTPサーバーに接続してEメールの送信を行う事が出来ます。
 SMTPの話はこちらを参照下さい、プロトコルコマンドも 読んで置きましょう。
 メール送信時のヘッダにマルチパートMIME(Multipurpose Internet Mail Extensions:
 多目的インターネットメール拡張)も見て置く事をお勧めします。

《ファイル構成》

"tcpip_config.h"の変更
#define STACK_USE_ICMP_SERVER     // ICMP(PING)はサーバ(Ping query応答)機能を実装する
#define STACK_USE_SMTP_CLIENT // SMTP クライアントの実装
上記の2モジュールのみ実装しましょう。
"STACK_USE_ICMP_SERVER"のみなのでPING応答のみ可能です。
これにより"DNS/UDP/SMTP/TCP"モジュールが追加されます。

追加されるファイル構成

smtp.c SMTP クライアントプロトコルのモジュールファイル(RFC 5321)(RFC 5322)
Simple Mail Transfer Protocol
SMTPのTCPポートは25番で、電子メールを送信する機能を提供します
dns_client.c DNS クライアントプロトコルのモジュールファイル(RFC 1035)
Domain Name System
ホスト名からIPアドレスへの変換を提供します
udp.c UDP プ ロトコルのモジュールファイル(RFC 768)
User Datagram Protocol
アプリケーション・データグラム(パケット)指向のデータの信頼性が低く、
最小遅延のトランスポートを提供します。
tcp.c
TCPプ ロトコルのモジュールファイル(RFC 793)
Transmission Control Protocol
信頼性の高い、フ ロー制御によるアプリケーションストリーム指向データのハンドシェイク転送を 提供します。

※ ”その2”の最小ファイル構成にC:\microchip\mla\v2016_11_07\framework\tcpip\srcフォルダー
  のtcp.c/smtp.c/udp.c/dns_client.cを加えたものになります。

※ この構成でコンパイルすると、使用メモリは「Program=42582byte Data=922byte」です。
  PIC18F26K22では、65%もプログラムメモリを消費しました。

※ "STACK_USE_SSL_SERVER"のコメントを外せばSSLモジュールが追加されてSMTPで使用出来る
  仕掛けが有るのでやってみたがぁ...下記の様なエラー出現じゃ〜ぁ。

コンパイルエラー画面
メモリの関係か?PIC18ではサポートしないと来たもんじゃやき。

《実験回路》

ENC28J60モジュールの ピン構成
ENC28J60モジュール VCC
電源3.3V パケット転送中動作電流180mA
十分に流せる電源を準備しましょう。
GND
グランド
RESET
LOWでリセットなので通常はHIGH
CS
SPIのチップセレクト入力ピン
SCK
SPIのクロック入力ピン
SI
SPIのデータ入力ピン
SO
SPIのデータ出力ピン
WOL
ウェイク アップ用割り込み出力
新チップはNCになっている。
INT
割り込み 出力ピン
CLKOUT
クロック 出力ピン
灰色背景色のピンは今回利用しません。


実態配線図

LCD表示 器についての配線等の詳細はこ ちらのページを参照下さい。
又、半固定抵抗は10kΩか20kΩ辺りで良いでしょう。

ENC28J60 のRESETピンについて
RESETピンはPICのRC1ピンに接続されていますが、これは"ENC28J60,c"の初期化関数(MACInit)でHIGHを出力しているだけ なので、直接VDDに配線すればPICピンが1本利用可となります。
その際は、"system_config.h"の"#define ENC_RST_IO"をコメントにします。

回路電源について
ENC28J60モジュールが3.3Vなので回路電源は3.3Vで統一していますが、
ENC28J60自体の消費電流がパケット転送中で最大 180mA、転送していない時で120mAと
結構電気食いで変動も激しいです。十分に流せる安定化された電源を準備しましょう

《ダウンロードファイルにつ いて》

↓ここからプログラムソースをダウンロードして下さい。
SMTP_ENC28J60.zip
ファイルの説明とプロジェクトの作成方法は”その1”を参照下さい。
MPLAB X IDE v3.60MPLAB(R) XC8 C Compiler Version 1.40コンパイラを使用しています。

"TestSMTP_basic.c"     :実験1と実験2で使用する、単純なメール送信サンプルプログラムです
"TestSMTP_japanese.c":実験3で使用する、日本語でのメール送信サンプルプログラムです
"TestSMTP_multi.c"      :実験4で使用する、添付ファイルを送るサンプルプログラムです

※ SMTPの送信例は、"C:\microchip\mla\v2016_11_07\apps\tcpip\wifi_demo_app\ firmware\src"
  フォルダーの"smtp_demo.c"ファイルから作成しました。
※ 同じフォルダーの"custom_http_app.c"ファイルも含めて置きました、このファイルの
  "HTTPPostEmail( )"関数を参考に"TestSMTP_multi.c"を作成しましたが、
  オリジナルは、HTMLファイル記述の電子メールフォームからの設定されたデータ内容でメールを
  送信するサンプルの様です、コメントを日本語にしたので付けて置きます。

《実験1》

このサンプルでは"YAHOO!プロバイダー"のSMTPサーバーに自分宛てに送信した実験です。

実験1のプログラムソースは"TestSMTP_basic.c"で、半固定抵抗 の現在値を送信しています。
これはPICのRAMに本文データ内容を格納し、それを送信する 簡単な短い送信例です、この例は
"SMTPDemo1( )"関数を実装します。

メール情報の設定

"TestSMTP.c"に下記の様な記述が有るので自分の環境に合わせて変更しましょう。
static uint8_t RAMStringTo[]     = "txnw????@ybb.ne.jp" ;   // 送信相手アドレス
static ROM uint8_t strServer[] = "smtp.mail.yahoo.co.jp"; // SMTPサーバーアドレス
static ROM uint8_t strUsername[] = "txnw????"; // ユーザ名
static ROM uint8_t strPassword[] = "xxxxxxx"; // パスワード
static ROM uint8_t strFrom[] = "\"SMTP Service\" <txnw????@yahoo.co.jp>" ; // 送信元
static ROM uint8_t strSubject[] = "Hello world! SMTP Test."; // タイトル


@ "tcpip_config.h"のMACアドレス・IPアドレ ス・サブネットマスクは”その1”を見て自分ちの
  ネット環境に合わせて設定は完了していますね。

A プログラムをコンパイルしPICに書き込みましょう。
  ”framework/tcpip/src/tcp.c:1943: warning: (343) implicit return at end of non-void function”
  ”framework/tcpip/src/tcp.c:2107: warning: (343) implicit return at end of non-void function”
  ”framework/tcpip/src/common/helpers.c:1370: warning: (1496) arithmetic on pointer to void
   yields Undefined Behavior”
  とワーニングが出るかもですがぁ、気にしなくても良いでしょう、たぶん。

B ENC28J60をネットワークに接続し、回路電源を入れましょう。
  (私はYAHOO!プロバイダーのトリオモデムのAPに繋いでの 実験です)

C LCDの1行目に[   Test to SMTP  ]が表示されます。

D でぇ、3秒後に処理開始です、LED()が1秒毎に点滅します
  LCDの2行目に"tcpip_config.h"で設定した IPアドレスが表示されます。
  [ My IP Address  ]
  [192.168.3.105   ]

E さあ、スイッチをポチっとな。
  LED()が送信中点灯し完了で消えます。(瞬 間ですたぶん)
  LCDには[Start send Email]が表示 され[Mail sent done!!]が完了で表示され ますがぁ、
  おそらく[Start send Email]は見えな いかもね。
  もぉしぃ、失敗した場合は[Error code: xxxx]と表示されエラーコード(xxxx)が表示されるはずです。
     8000: SMTPサーバーを解決できませんでした。
     8001: サーバーへの接続に失敗したか、途中で終了しました。
     1-199および300-399はSMTPサーバー通信時の最後の応答コード(421-554はエラーの応答コード)

F 送信されたかメールを確認しましょう。

実験1での送信内容
  こんな感じに送られている事と思います。

《実験2》

実験2のプログラムソースは"TestSMTP_basic.c"で、実験1の時 よりも
より長いメッセージ(一度にRAMに存在しないメッセージ)を送 信する例で、メッセージ本体が
動的に生成され、RAMに収まる必要がない複数の部分からなりま す
この例は"SMTPDemo2( )"関数を実装しま す。

TestSMTP.cの変更点

main( )関数のループ内に
          // SMTPクライアントの使用例コード
          SMTPDemo1() ;
と有るので"SMTPDemo2( )"と書き換えて 再コンパイルをして下さい。

操作は実験1と同じです。
下図の様に0番地〜0x0E7F番地までのPICのRAM内容がメモリダンプ型式で送信されます。

実験2での送信内容

《実験3》

実験3のプログラムソースは"TestSMTP_japanese.c"を使いま す。
これは実験1の内容を日本語メッセージで送信する例で す。

下図の様に送信されるでしょう、おそらく。

実験3での送信内容

タイトル部(Subject)の日本語化について

こんにちは! SMTP テスト ”の文字は
    static ROM uint8_t strSubject[]  = "=?ISO-2022-JP?B?GyRCJDMkcyRLJEEkTyEqGyhC?= SMTP "
"=?ISO-2022-JP?B?GyRCJUYlOSVIGyhC?=" ;
といった感じに、"=?ISO-2022-JP?B?..............? ="で変換されたデータをはさんで送信します。
(B=BASE64  Q=Quoted-Printable の変換コードの種別を表します)
この話は、"きっぷみー" さんのこち らを参考にして下さい。
変換(エンコード)方法は下記の方を読みましょう。

本文部の日本語化について

本文部を日本語にするにはメールヘッダフィールドに日本語を使う旨を宣言します。
    SMTPClient.OtherHeaders.szROM = (ROM uint8_t *) // MIMEヘッダ
"MIME-version: 1.0\r\nContent-type: text/plain; charset=\"iso-2022-jp\"\r\n
Content-Transfer-Encoding:7bit\r\n";
SMTPClient.ROMPointers.OtherHeaders = 1;
とこんな感じです、この話は"ASCII.jpxTECH"さんのこちらを 参考にして下さい。

stack v5.47 によって生成れたメッセージ
 アナログ値: 0506
の文字は
    static uint8_t RAMStringBody[] = "stack v5.47 \x1b$B$K$h$C$F@8@.$l$?%a%C%;!<%8\x1b(B\r\n"
"\x1b$B%\"%J%m%0CM\x1b(B: 0000" ;
の様に変換したコードを\x1b$B\x1b(Bではさみます。(因みに\x1bはエスケープコードです)

文字の変換(エンコード)について

変換先サイトは"SEO 対策 & tools"さんのこ ちらをご覧下さい。

エンコード画面1
これは本文部分のエンコード例です。
変換後文字列をコピッペしましょう。
注意点

 

 コピッペするとぉこんな感じになります、□は0x1B(ESC)のコードが埋め込まれているので書換えます
 □を消し「\x1b」と書き換え先頭には埋め込まれていないが「\x1b」を追加します、
 「\x1b$B%"%J%m%0CM\x1b(B」となります。

 次に「%"」の「"」の前に「\」を付けて下さい、「\x1b$B%\"%J%m%0CM\x1b(B」で完成です。



下は、タイトル(Subject)部分のエンコード例です。
変換後はこれも文字列をコピッペしましょう。

エンコード画面2

《実験4》

実験4のプログラムソースは"TestSMTP_multi.c"を使いま す。
このサンプルは、マルチパートメールで構成され本文と添付ファイルの送信を行う例です。

起動させた後に、スイッチを押せばメールにファイルが添付され送信されます。
スイッチを押すとLCDに[measure ?st    ]が表示されます、1〜10が表示されます。
これは、1分間で10回のアナログ値計測を行います、なのでこの間に半固定抵抗の値を変化させます。
この計測が終わると、LED()が送信中点灯し完了で消えます。
LCDには[Start send Email]が表示 され[Mail sent done!!]が完了で表示され ます。

送信されたかメールを確認しましょう、下の様に送られていると思います。

実験4での送信内容
添付ファイルは計測したアナログ値をCSV型式で送っています。

送付ファイルをEXCELで開いた図
 EXCELで添付ファイル(test.csv)を開いて見た所です。
 10回分のアナログ計測値データが有ります。

 マルチパートメール
について

 メールのヘッダ部のContent-Typeが下の記述の様になります。

 "MIME-version: 1.0\r\nContent-type: multipart/mixed;  
  boundary=\"frontier\"\r\n"

 複数のコンテンツを
frontier文字列で仕切り一つのメッセージメール
 として送信する物でここでは、本文と添付ファイルを送るサンプルです、
 マルチパートについてはこちらを参照下さい。

《その他》

次回以降はHTTPのクライアントとサーバーを行う予定ですがぁ...
現状消費メモリが67パーセントでぇ、HTTPサーバーを行うとぉかなり厳しそうな予感がします。
なのでぇ、PIC24EP256MC202(16ビット)を使おうと思います、だから次回はこのMCUでぇ
PING/TELNET/SMTPを動作させた記事にしたいと思います。




【きむ茶工房ガ レージハウス】
Copyright (C) 2006-2017 Shigehiro Kimura All Rights Reserved.