iアプリによるUART通信

最近のFOMAにはUARTが装備されているらしいです.
バーコードリーダーやなんかも出ているらしいですが,なんか活用してみようと思い立ちました.

資料:FOMA UART インタフェースを利用するための技術参考資料


パケホーダイ枠で使えるデータ通信用端末


■構成
[PC] ←UART→ [FOMA] ←http→ [WebServer]

こんな感じで繋げばiアプリで利用可能なhttpに限っては閲覧可能かもなんて思いました.

データ通信で携帯を繋いでインターネットを楽しむ手もありますが、
未だに料金が従量制なんていう欠点もあります。
この方法だとパケホーダイさえ入っておけば安心して使えます。

PC側では携帯にUARTでリクエストを投げてくれるソフトウェアプロキシを,携帯側ではWebProxyにリクエストを投げてレスポンスをゲット、PCに投げ返すのiアプリを起動しておきます.
接続先のWebサーバーにはiアプリ用のWebProxyを設置しておきます.
これはiアプリをダウンロードしたサイトにしかアクセスできないという悲しい制約のための対策.

動作としてはブラウザからソフトウェアプロキシに投げられたURLをUART経由でFOMAに転送,iアプリでそれを取得してWebServerにリクエスト送信,レスポンスが得られたらUART経由でPCに返すというごく単純なもの.


FOMA接続ケーブルの作成


UART接続のためのケーブルを作ります.

FOMAのコネクタ形状はIMT-2000って言うらしいです.
SoftBankの3Gケータイなんかもこれの様子.

ケーブル選びに関してですが,100円ショップとかで売っている充電用ケーブルだと電源の2芯(ないし3芯)しか入ってなかったりするのでNGです.
10芯の物を探してください。正直見てもわからないのでデータ通信用のケーブルを買ってみました。

今回はこれをつかうことに.

081119_d906113e6fc7a302c60800542c15db66.jpg

買って速攻バラす.

バラしてみると,USB接続を前提としているためか中の数ピンがNCピンになっていた.10芯でよかった。

10ピン分引っ張り出して完了.

081119_91622733813481254e0dc3165294183b.jpg

つないでみる


今回テストした環境はこんな感じ.
3664ボードはただレベルコンバータ繋ぐの面倒だったので使いました.あと電源供給用.
ややこしくてごめんなさい.
中身のマイコンは全く利用しておりません^^

081119_ffd4e0fe8a337249875216fcc5a39bcd.jpg

こんなかんじ.

081119_85033d7a1d6f5844ff07dd68e8c74c26.jpg


FOMA側アプリケーションの作成



iアプリを作ります。送受信部はこんな感じになります。
	StreamConnection uart;
	public void read()
	{
		String str = "";
		try
		{
			uart = (StreamConnection)Connector.open("comm:/0;baudrate=115200,databitlen=8,parity=NO,stopbitlen=1,flowctrl=OFF",Connector.READ,true);
			InputStreamReader in =  new InputStreamReader(uart.openInputStream(), "SJIS");
			while (true) {
				byte recv = (byte)in.read();
				str += String.valueOf((char)recv);
				System.out.print((char)recv);
				if((char)recv == '\n') break;
			}
			in.close();
			this.url =str;
		}catch(ConnectionException ce){
		}catch(Exception e){
		}finally{
			try{
				uart.close();
			}catch (Exception e) {
			}
		}
	}
	public void send()
	{
		System.out.println("send()");
		try
		{
			uart = (StreamConnection)Connector.open("comm:/0;baudrate=115200,databitlen=8,parity=NO,stopbitlen=1,flowctrl=OFF",Connector.WRITE,true);
			OutputStreamWriter out = new OutputStreamWriter(uart.openOutputStream(), "SJIS");
			out.write(this.html);
			out.flush();
			out.close();
			uart.close();
		}catch(ConnectionException ce){
		}catch(Exception e){
		}finally{
			try{
				uart.close();
			}catch (Exception e) {
			}
		}
	}

Connector.open()の引数の詳細に関しては参考資料に記載されていますが、あまり自由度はない模様。
通信できたのでひとまずこのようにしておきました。

"comm:/0;baudrate=115200,databitlen=8,parity=NO,stopbitlen=1,flowctrl=OFF"


PC側プロキシサーバーの作成


PC側のプロキシサーバを作ります。
お手軽そうなのでC#を使います.

機能としては

■リクエストを蓄積する
■携帯側から要求があったらシリアルポート経由でリクエストを送る。
■コンテンツを受け取る。

これだけです。
普段はLANポートから出て行くリクエストをシリアルポートにしてしまえという構成になってます。

FOMA(UART)⇔PC(Proxy)で通信するためのサンプルです。VS2008のC#で書きました。
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.IO.Ports;

namespace FomaUARTProxy
{
    class Proxy
    {
        HttpListener listener;
        SerialConnection port;

        public Proxy(SerialConnection com)
        {
            this.port = com;
        }
        public void Start()
        {
            Console.WriteLine("Start", "HttpServer");
            if (listener == null)
            {
                listener = new HttpListener();
                listener.Prefixes.Add(string.Format("http://127.0.0.1:8080/", IPAddress.Loopback, 8080));
            }
            listener.Start();
            listener.BeginGetContext(OnGetContext, listener);
        }
        public void Stop()
        {
            listener.Stop();
            Console.WriteLine("Stop", "HttpServer");
        }
        private void OnGetContext(IAsyncResult ar)
        {
            try
            {
                HttpListenerContext context = ((HttpListener)ar.AsyncState).EndGetContext(ar);
                OnRequest(context);
                listener.BeginGetContext(OnGetContext, listener);
            }
            catch (HttpListenerException e)
            {
                Console.WriteLine(e);
            }
        }
        private void OnRequest(HttpListenerContext context)
        {
            Console.WriteLine(context.Request.RawUrl); // 加工されてないアドレス
            Console.WriteLine(context.Request.UserHostAddress); // どこから接続されたか

            string response = this.port.WritePort(context.Request.RawUrl);

            //
            // レスポンスの作成
            //

            HttpWebResponse webResponse = null;
            if (webResponse == null)
            {
                context.Response.ProtocolVersion = HttpVersion.Version11;
                context.Response.StatusCode = 503;
                context.Response.StatusDescription = "Response Error";
                context.Response.ContentLength64 = 0;
                context.Response.Close();
                return;
            }

            // ブラウザへ返すレスポンスの設定。あるていど。
            context.Response.ProtocolVersion = webResponse.ProtocolVersion;
            context.Response.StatusCode = (int)webResponse.StatusCode;
            context.Response.StatusDescription = webResponse.StatusDescription;

            context.Response.AddHeader("Server", webResponse.Server);
            context.Response.ContentType = webResponse.ContentType;

            if (webResponse.ContentLength >= 0)
            {
                Console.WriteLine("Content-Length=" + webResponse.ContentLength, context.Request.RawUrl);
                context.Response.ContentLength64 = webResponse.ContentLength;
            }

            if (webResponse.GetResponseHeader("Transfer-Encoding").ToLower().Equals("chunked"))
            {
                Console.WriteLine("chunked", context.Request.RawUrl);
                context.Response.SendChunked = true;
            }
            context.Response.KeepAlive = context.Request.KeepAlive;

            // ボディの送受信
            Stream instream = new MemoryStream(Encoding.Unicode.GetBytes(response));
            Stream outstream = context.Response.OutputStream;

            try
            {
                while (true)
                {
                    int read = instream.Read(buffer, 0, buffer.Length);
                    Console.WriteLine(read + " bytes received", context.Request.RawUrl);
                    if (read == 0)
                        break;
                    outstream.Write(buffer, 0, read);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            try
            {
                webResponse.Close();
                context.Response.Close();
            }
            catch (InvalidOperationException e)
            {
                Console.WriteLine(e);
            }
            catch (HttpListenerException he)
            {
                Console.WriteLine(he);
            }
        }
    }

    class SerialConnection
    {
        SerialPort port;

        public SerialConnection()
        {
            port = new SerialPort("COM10", 115200);
        }

        public string WritePort(string text)
        {
            string buffer = "";
            string response = "";
            text = text.Substring(7, text.Length - 8);
            port.Open();
            this.port.WriteLine(text + "\n");
            port.Close();

            port.Open();
            while ((buffer = port.ReadLine()) != null)
            {
                Console.WriteLine(buffer);
                response += buffer;
            }
            port.Close();
            Console.WriteLine("Response:" + response);
            return (response);
        }
    }
}


Proxy.Start()で起動します.
一度受信すると終わるのでスレッドに載せて動かしたりとかするといいとおもいます.そうしました.

テストしてみる


作ったPC用のプロキシサーバを起動します。
その際にInternetExplorerのプロキシ設定を忘れずに。
(プロキシサーバのURLはプロキシソフトウェアで設定したものに)



コメント(0)

コメントを投稿する