CAFIS Arch POS連動仕様について

CAFIS Arch POS連動 サンプルコード

シリアル

クラス構成図

  • 説明
  • サンプルコード
  • using System;
    using System.Collections.Generic;
    using System.IO.Ports;
    using System.Linq;
    using System.Text;
    using System.Timers;
    using Util;
    
    namespace SerialModule {
        public class Serial {
    
            enum State {
                IDLE,        // アイドル
                STX_WAITING, // STX待ち
                ETX_WAITING, // ETX待ち
                BCC_WAITING, // BCC待ち
                EOT_WAITING, // EOT待ち
                ACK_WAITING  // ACK待ち(ETBブロック送出後/ETXブロック送出後)
            }
    
            public delegate void Delegate(string message);
            Delegate callback;
            SerialPort serialPort;
            State state = State.IDLE;
            Queue messageBlock = new Queue();
            List receiveBuffer = new List();
            StringBuilder receiveMessage = new StringBuilder();
            Timer workingTimer;
コンストラクタ
  • 概要

    コンストラクタ

    パラメータ

    string portName ポート名

    int bauRate ボーレート

    string p パリティ

    Delegate function ファンクション

    戻り値

    なし

    処理

    ・初期処理

    ・指定したポート名、ボーレート、パリティビット、データビット(Archでは8ビット固定)、およびストップビット(Archでは1ビット固定)を使用して、SerialPort クラスのインスタンスを初期化

    ・コールバック登録

    ・データ受信イベントハンドラ登録

  • // コンストラクタ
    	public Serial(string portName, int bauRate, string p, Delegate function) {
    	    Parity parity = (Parity)Enum.Parse(typeof(Parity), p);
    	    serialPort = new SerialPort(portName, bauRate, parity, 8, StopBits.One);
    	    callback = function;
    	    serialPort.DataReceived += new SerialDataReceivedEventHandler(ReceiveMsg);
    	}
シリアルポートオープン
  • 概要

    シリアルポートを開く

    パラメータ

    なし

    戻り値

    bool 処理結果

    処理

    ・ポートオープン

  • 	// シリアルポートオープン
            public bool PortOpen() {
                bool isOpen = false;
                // ポートが開放されていない場合は開放する
                if (!serialPort.IsOpen) {
                    serialPort.Open();
                }
                if (serialPort.IsOpen) {
                    isOpen = true;
                }
                return isOpen;
            }
シリアルポートクローズ
  • 概要

    シリアルポートを閉じる

    パラメータ

    なし

    戻り値

    なし

    処理

    ・ポートクローズ

  • 	// シリアルポートクローズ
            public void PortClose() {
                // ポートオープン前はオブジェクトが無い為何もしない
                if (serialPort.IsOpen) {
                    serialPort.Close();
                }
            }
電文送信
  • 概要

    要求電文を送信する

    パラメータ

    string msg 要求電文

    例:クレジット売上の場合、以下のJSON文字列を設定
    {"mode":"1","service":"0100001","biz":"1","amount":"1000","taxOther":"80","goods":"0100","seqNo":"0001","logOutputMode":"0","outputId":"1001","printMode":"1"}

    ※各サービスの要求電文の設定内容については接続仕様書参照

    戻り値

    int 処理結果

    処理

    ・Base64エンコード処理呼び出し

    ・ブロック分割

    ・JIS-8符号化

    ・制御コード付与

  •         // 電文送信
            public int SendMsg(string msg) {
                // シリアルポートがオープンされていれば電文を送信する。
                if (serialPort.IsOpen) {
                    if (!string.IsNullOrEmpty(msg) && state == State.IDLE) {
                        // 引数がnullもしくは""でない かつ 状態がアイドルならば送信
                        // Base64エンコード
                        msg = Utility.EncodeBase64(msg);
                        // ブロック分割
                        messageBlock.Clear();
                        int blocksz = 2048 - 3; // 指定ブロックサイズ-制御コード(STX,ETX,BCC)
                        int cnt = 1;
                        for (int i = 0; i < msg.Length; i += blocksz) {
                            if (msg.Length > (cnt * blocksz)) {
                                // ブロック分を取り出してJIS-8符号化
                                byte[] msgArray = Utility.EncodeJis8(msg.Substring(i,blocksz));
                                // 制御コードを付与して格納
                                messageBlock.Enqueue(Utility.CreateMessage(msgArray, false));
                            } else {
                                // ブロック分を取り出してJIS-8符号化
                                byte[] msgArray = Utility.EncodeJis8(msg.Substring(i));
                                // 制御コードを付与して格納
                                messageBlock.Enqueue(Utility.CreateMessage(msgArray, true));
                            }
                            cnt++;
                        }
                        // 電文送信
                        SendData(messageBlock.Peek(), 0, messageBlock.Peek().Length);
                        // ACK待ちへ移行
                        state = State.ACK_WAITING;
                        ReceiveTimerStart(OnSendTimeOver);
                        return 0;
                    } else {
                        // 引数がnullもしくは""である または 状態がアイドルでないならば1(エラー)を返却
                        return 1;
                    }
                } else {
                    // ポートが開いてなければ1(エラー)を返却
                    return 1;
                }
            }
シリアル送信
  • 概要

    シリアル送信する

    パラメータ

    byte[] data 送信データを格納したバイト型の配列

    int i 送信を開始する配列の位置

    int length 送信するバイト数

    戻り値

    なし

    処理

    ・シリアル送信

  • 	// シリアル送信
            void SendData(byte[] data, int i, int length) {
                serialPort.Write(data, i, length);
            }
電文受信
  • 概要

    応答電文を受信する

    パラメータ

    object sender

    System.IO.Ports.

    SerialDataReceivedEventArgs e

    戻り値

    なし

    処理

    ・シリアル受信

    ・伝送制御(状態遷移)

    ・シリアル送信呼び出し

    ・タイムアウト処理呼び出し

    ・分割ブロックの結合

    ・Base64デコード処理呼び出し

  •         // 電文受信
            void ReceiveMsg(object sender, SerialDataReceivedEventArgs e) {
                // ポートからデータを受け取る
                string readdata = serialPort.ReadExisting();
                byte[] bdata = Encoding.GetEncoding("UTF-8").GetBytes(readdata);
    
                // フェーズ00:アイドル状態ならSTX待ちへ移行
                if (state == State.IDLE) {
                    state = State.STX_WAITING;
                }
                // データ受信イベント処理
                foreach (byte byteData in bdata) {
                    // 状態確認
                    switch (state) {
                        case State.STX_WAITING:
                            // フェーズ01:STX待ちのとき
    
                            // 受信データ確認
                            switch (byteData) {
                                case 0x02:
                                    // イベントR01:STX受信
    
                                    // 受信バッファをクリアしてSTXを格納
                                    receiveBuffer.Clear();
                                    receiveBuffer.Add(byteData);
    
                                    // ETX待ちへ移行
                                    state = State.ETX_WAITING;
                                    ReceiveTimerStart(OnReceiveTimeOver);
                                    break;
    
                            }
                            break;
    
                        case State.ETX_WAITING:
                            // フェーズ02:ETX待ちのとき
    
                            // 受信データ確認
                            switch (byteData) {
                                case 0x02:
                                    // イベントR01:STX受信
    
                                    // 何もしない
                                    break;
    
                                case 0x17:
                                    // イベントR03:ETB受信
                                case 0x03:
                                    // イベントR04:ETX受信
    
                                    // 受信バッファに格納
                                    receiveBuffer.Add(byteData);
    
                                    // BCC待ちへ移行
                                    state = State.BCC_WAITING;
                                    ReceiveTimerStart(OnReceiveTimeOver);
                                    break;
    
                                default:
                                    // イベントR02:一般データ受信
                                    // イベントR05:ACK受信
                                    // イベントR06:NAK受信
                                    // イベントR07:EOT受信
    
                                    // 受信バッファに格納
                                    receiveBuffer.Add(byteData);
                                    ReceiveTimerStart(OnReceiveTimeOver);
                                    break;
                            }
                            break;
    
                        case State.BCC_WAITING:
                            // フェーズ02:BCC待ちのとき
    
                            // BCCチェックをしてACK/NAK応答
                            byte receiveResponse = Utility.CheckMessage(receiveBuffer.ToArray(), byteData);
                            SendData(new byte[]{receiveResponse}, 0, 1);
    
                            // ブロック受信後処理
                            if (receiveResponse == 0x06) {
                                // ACK応答の場合
    
                                // 受信バッファからデータを取り出す
                                byte[] msgArray = receiveBuffer.Skip(1).Take(receiveBuffer.Count - 2).ToArray();
    
                                // JIS-8符号復号化
                                string msg = Utility.DecodeJis8(msgArray);
    
                                // 受信電文に結合
                                receiveMessage.Append(msg);
    
                                // 状態遷移処理
                                if (receiveBuffer.Last() == 0x03) {
                                    // ETXブロック受信のとき
    
                                    // EOT待ちへ移行
                                    state = State.EOT_WAITING;
                                    ReceiveTimerStart(OnEotReceiveTimeOver);
    
                                } else {
                                    // ETBブロック受信のとき
    
                                    // STX待ちへ移行
                                    state = State.STX_WAITING;
                                    ReceiveTimerStart(OnReceiveTimeOver);
    
                                }
    
                            } else {
                                // NAK応答の場合
    
                                // STX待ちへ移行
                                state = State.STX_WAITING;
                                ReceiveTimerStart(OnReceiveTimeOver);
    
                            }
                            break;
    
                        case State.EOT_WAITING:
                            // フェーズ03:EOT待ちのとき
    
                            // 受信データ確認
                            switch (byteData) {
                                case 0x04:
                                    // イベントR07:EOT受信
    
                                    // 受信電文をBase64デコード
                                    string message = Utility.DecodeBase64(receiveMessage.ToString());
                                    receiveMessage.Clear();
    
                                    // アイドルへ移行
                                    state = State.IDLE;
                                    ReceiveTimerStop();
    
                                    // デコードした電文を返却
                                    callback(message);
                                    break;
    
                            }
                            break;
    
                        case State.ACK_WAITING:
                            // フェーズ04:ACK待ちのとき
                            // フェーズ05:ACK待ちのとき
    
                            // 受信データ確認
                            switch (byteData) {
                                case 0x06:
                                    // イベントR05:ACK受信
    
                                    // 次ブロック読み込み
                                    messageBlock.Dequeue();
                                    if (messageBlock.Count == 0) {
                                        // 次ブロックがない場合
    
                                        // フェーズ05:ETXブロック送出後なのでEOT送信
                                        SendData(new byte[]{0x04}, 0, 1);
    
                                        // アイドルへ移行
                                        state = State.IDLE;
                                        ReceiveTimerStop();
    
                                    } else {
                                        // 次ブロックがある場合
    
                                        // フェーズ04:ETBブロック送出後なので次ブロック送信
                                        SendData(messageBlock.Peek(), 0, messageBlock.Peek().Length);
    
                                        // ACK待ちへ移行
                                        state = State.ACK_WAITING;
                                        ReceiveTimerStart(OnSendTimeOver);
    
                                    }
                                    break;
    
                                case 0x15:
                                    // イベントR06:NAK受信
    
                                    // ブロック再送
                                    SendData(messageBlock.Peek(), 0, messageBlock.Peek().Length);
    
                                    // ACK待ちへ移行
                                    state = State.ACK_WAITING;
                                    ReceiveTimerStart(OnSendTimeOver);
                                    break;
    
                            }
                            break;
    
                    }
                }
                // データ受信イベント処理終了
            }
受信タイマー開始
  • 概要

    受信タイマーを開始する

    パラメータ

    ElapsedEventHandler handler

    戻り値

    なし

    処理

    ・タイマー開始(10秒)

  • 	// 受信タイマー開始
            void ReceiveTimerStart(ElapsedEventHandler handler) {
                // 動作中のタイマーを停止
                if (workingTimer != null) {
                    workingTimer.Stop();
                }
                // 10秒のタイマーを作成
                workingTimer = new Timer(10000);
                workingTimer.AutoReset = false;
                workingTimer.Elapsed += handler;
                // タイマー開始
                workingTimer.Start();
            }
受信タイマー停止
  • 概要

    受信タイマーを停止する

    パラメータ

    なし

    戻り値

    なし

    処理

    ・タイマー停止

  • 	// 受信タイマー停止
            void ReceiveTimerStop() {
                if (workingTimer != null) {
                    workingTimer.Stop();
                    workingTimer = null;
                }
            }
            // フェーズ04イベントT01
            // フェーズ05イベントT01
送信タイムアウト処理(タイムアウトイベント処理)
  • 概要

    送信タイムアウト処理を行う

    パラメータ

    object sender

    ElapsedEventArgs e

    戻り値

    なし

    処理

    ・タイマー停止

    ・送信ブロック破棄

    ・フェーズを00に更新

  • 	// 送信タイムアウト処理(タイムアウトイベント処理)
            void OnSendTimeOver(object sender, ElapsedEventArgs e) {
                // タイマーの停止
                Timer timer = sender as Timer;
                if (timer != null) {
                    timer.Stop();
                }
                // 送信ブロック破棄
                messageBlock.Clear();
                // アイドルへ移行
                state = State.IDLE;
            }
            // フェーズ01イベントT01
            // フェーズ02イベントT01
データ受信タイムアウト処理(タイムアウトイベント処理)
  • 概要

    データ受信タイムアウト処理を行う

    パラメータ

    object sender

    ElapsedEventArgs e

    戻り値

    なし

    処理

    ・タイマー停止

    ・NAK送信

    ・フェーズを01に更新

  • 	// データ受信タイムアウト処理(タイムアウトイベント処理)
            void OnReceiveTimeOver(object sender, ElapsedEventArgs e) {
                // タイマーの停止
                Timer timer = sender as Timer;
                if (timer != null) {
                    timer.Stop();
                }
                // NAK送信
                SendData(new byte[]{0x15}, 0, 1);
                // STX待ちへ移行
                state = State.STX_WAITING;
                ReceiveTimerStart(OnReceiveTimeOver);
            }
            // フェーズ03イベントT01
EOT受信タイムアウト処理(タイムアウトイベント処理)
  • 概要

    EOT受信タイムアウト処理を行う

    パラメータ

    object sender

    ElapsedEventArgs e

    戻り値

    なし

    処理

    ・タイマー停止

    ・NAK送信

    ・フェーズを03に更新

  • 	// EOT受信タイムアウト処理(タイムアウトイベント処理)
            void OnEotReceiveTimeOver(object sender, ElapsedEventArgs e) {
                // タイマーの停止
                Timer timer = sender as Timer;
                if (timer != null) {
                    timer.Stop();
                }
                // NAK送信
                SendData(new byte[]{0x15}, 0, 1);
                // EOT待ちへ移行
                state = State.EOT_WAITING;
                ReceiveTimerStart(OnEotReceiveTimeOver);
            }
        }
    }
Base64エンコード
  • 概要

    Base64エンコードする

    パラメータ

    string msg 変換前文字列

    戻り値

    string 変換後文字列

    処理

    ・Base64エンコード(76 文字ごとに改行を挿入)

  • namespace Util {
        public static class Utility {
            // Base64エンコード
            public static string EncodeBase64(string msg) {
                return Convert.ToBase64String(Encoding.UTF8.GetBytes(msg), Base64FormattingOptions.InsertLineBreaks);
            }
Base64デコード
  • 概要

    Base64デコードする

    パラメータ

    string msg 変換前文字列

    戻り値

    string 変換後文字列

    処理

    ・Base64デコード

  •         // Base64デコード
            public static string DecodeBase64(string msg) {
                return Encoding.UTF8.GetString(Convert.FromBase64String(msg));
            }
JIS8単位符号化
  • 概要

    JIS-8単位符号化する

    パラメータ

    string msg 変換前文字列

    戻り値

    byte[] 変換後バイト型配列

    処理

    ・JIS-8単位符号化

  •         // JIS8単位符号化
            public static byte[] EncodeJis8(string msg) {
                return Encoding.UTF8.GetBytes(msg);
            }
JIS8単位符号復号化
  • 概要

    JIS-8単位符号復号化する

    パラメータ

    byte[] msgArray 変換前バイト型配列

    戻り値

    string msg 変換後文字列

    処理

    ・JIS-8単位符号復号化

  •         // JIS8単位符号復号化
            public static string DecodeJis8(byte[] msgArray) {
                return Encoding.UTF8.GetString(msgArray);
            }
STX,ETX,BCC等の付与
  • 概要

    制御コードを付与する

    パラメータ

    byte [] msgArray 変換前バイト型配列

    bool flg 最終電文フラグ

    戻り値

    byte[] 変換後バイト型配列

    処理

    ・STX、ETB、ETXの付与

    ・BCC作成処理呼び出し

    ・BCCの付与

  •         // STX,ETX,BCC等の付与
            public static byte[] CreateMessage(byte[] msgArray, bool flg) {
                // STX
                byte[] startbit = {0x02};
                // ETB,ETX
                byte[] endbit = {0x17};
                // BCC
                byte[] bcc = new byte[1];
                if (flg) {
                    // 最終電文ならETXを付与する
                    endbit[0] = 0x03;
                }
                //BCCの計算
                msgArray = Enumerable.Concat(startbit, msgArray).ToArray();
                msgArray = Enumerable.Concat(msgArray, endbit).ToArray();
                bcc[0] = Convert.ToByte(CreateBcc(msgArray));
                msgArray = Enumerable.Concat(msgArray, bcc).ToArray();
                return msgArray;
            }
BCC作成
  • 概要

    BCCを作成する

    パラメータ

    byte[] msg バイト型配列

    戻り値

    byte BCC

    処理

    ・引数「バイト型配列」を元にBCCを作成

  •         // BCC作成
            public static byte CreateBcc(byte[] msg) {
                byte bcc = 0;
                for (int i = 0; i < msg.Length; i++){
                    bcc = (byte)(bcc ^ msg[i]);
                }
                return bcc;
            }
受信電文妥当性チェック
  • 概要

    受信電文の妥当性チェックを行う

    受信電文のBCCチェックを行い、内容に応じて

    ACK/NAKを返す

    パラメータ

    byte[] msgArray バイト型配列

    byte receiveBcc バイト型配列のBCC

    戻り値

    byte ACK/NAK

    処理

    ・引数「バイト型配列」を元にBCCを作成

    ・引数「バイト型配列のBCC」と作成したBCCを比較

    ・一致した場合ACKを返却、一致しなかった場合NAKを返却

  •         // 受信電文妥当性チェック
            // 内容に応じてACK/NAKを返す
            public static byte CheckMessage(byte[] msgArray, byte receiveBcc){
                byte buff;
                byte checkbcc = CreateBcc(msgArray);
                // BCCチェック
                if(receiveBcc == checkbcc){
                    // ACK
                    buff = 0x06;
                } else {
                    // NAK
                    buff = 0x15;
                }
                return buff;
            }
        }
    }

コードをコピーしました