| 1 | = T&D TR-73U おんどとり用IOC = |
| 2 | |
| 3 | |
| 4 | 今回は、RS-232Cで取得したバイナリデータをStreamDeviceでwaveformとして取得し、sequencerでデータ変換するパターン。 |
| 5 | |
| 6 | == 通信マニュアル == |
| 7 | * 会社サポートに問い合わせて、パスワードを教えてもらってダウロード |
| 8 | |
| 9 | == 接続 == |
| 10 | |
| 11 | [http://www.tandd.co.jp/product/dataloggers/tr73u/ T&D TR-73U]からデータを取得するには、[http://www.tandd.co.jp/product/dataloggers/tr73u/option.html 専用のRS-232Cケーブル(TR-07C)]で接続する必要がある。そこから先はいつも通りのMOXAのEther-Serialコンバータで接続する。 |
| 12 | |
| 13 | || baud rate || 19200 || |
| 14 | || parity || none || |
| 15 | || data bits || 8 || |
| 16 | || stop bits || 1 || |
| 17 | || flow ctrl || none || |
| 18 | |
| 19 | |
| 20 | == 通信フォーマット == |
| 21 | |
| 22 | 現在値のデータを取得するコマンドだけを実装する。 |
| 23 | |
| 24 | データはlittle endian |
| 25 | |
| 26 | * 測定値要求コマンド |
| 27 | |
| 28 | 送信 |
| 29 | |
| 30 | || 項目名 || サイズ(byte) || 説明 || |
| 31 | || SOH || 1 || 0x01固定 || |
| 32 | || コマンド || 1 || || |
| 33 | || コマンド予備 || 1 || || |
| 34 | || データ長 || 2 || データの長さ || |
| 35 | || データ || 4~ || || |
| 36 | || SUM || 2 || チェックSUM SOH~データまでの総和 || |
| 37 | |
| 38 | 受信 |
| 39 | |
| 40 | || 項目名 || サイズ(byte) || 説明 || |
| 41 | || SOH || 1 || 0x01固定 || |
| 42 | || コマンド || 1 || || |
| 43 | || 応答コード || 1 || ACK(0x06),etc || |
| 44 | || データ長 || 2 || データの長さ || |
| 45 | || データ || 0~ || || |
| 46 | || SUM || 2 || チェックSUM SOH~データまでの総和 || |
| 47 | |
| 48 | |
| 49 | データフォーマットは[wiki:Epics/tandd/manual マニュアル]を参照。 |
| 50 | |
| 51 | == protocol file == |
| 52 | |
| 53 | 今回のデータは固定長なので、Max_Inputでデータ長を設定。[[br]] |
| 54 | ターミネーター、セパレーターは"なし"に設定。[[br]] |
| 55 | プロトコルファイルは以下の様になる。 |
| 56 | |
| 57 | {{{ |
| 58 | Terminator = ""; |
| 59 | # |
| 60 | setWakeup { |
| 61 | out 0x00; |
| 62 | } |
| 63 | |
| 64 | getData { |
| 65 | ExtraInput = Ignore; |
| 66 | InTerminator = ""; |
| 67 | ReplyTimeout = 3000; |
| 68 | MaxInput = 26; |
| 69 | separator = ""; |
| 70 | |
| 71 | out 0x01 0x33 0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x38 0x00; |
| 72 | in "%0r"; |
| 73 | |
| 74 | @replytimeout{;} |
| 75 | } |
| 76 | }}} |
| 77 | |
| 78 | '''%0r'''のところをwaveformとして取り込んで、sequenceで処理する。 |
| 79 | |
| 80 | |
| 81 | == sequence file == |
| 82 | |
| 83 | |
| 84 | 必要なデータをwaveformから切り出して、データ用のレコードに設定する。[[br]] |
| 85 | データ取得用レコードをPROCしてからデータが出力されるまでにタイムラグがあるので、0.5秒待ちを入れる。[[br]] |
| 86 | データの収集間隔は現在は5秒に設定。 |
| 87 | |
| 88 | {{{ |
| 89 | program sncTR73U |
| 90 | |
| 91 | unsigned char wfByte[26]; |
| 92 | assign wfByte to "{user}:getData"; |
| 93 | |
| 94 | int wfProc; |
| 95 | assign wfProc to "{user}:getData.PROC"; |
| 96 | |
| 97 | float vals[3]; |
| 98 | assign vals[0] to "{user}:getTemperature"; |
| 99 | assign vals[1] to "{user}:getHumidity"; |
| 100 | assign vals[2] to "{user}:getPressure"; |
| 101 | |
| 102 | int wkup; |
| 103 | assign wkup to "{user}:wakeup"; |
| 104 | |
| 105 | int ack; |
| 106 | int i; |
| 107 | int hsbIndex; |
| 108 | int lsbIndex; |
| 109 | /*unsigned short chkSum;*/ |
| 110 | unsigned int shtVal; |
| 111 | float calcVal; |
| 112 | |
| 113 | ss sncTR73U { |
| 114 | state init { |
| 115 | when () { |
| 116 | } state getData |
| 117 | } |
| 118 | |
| 119 | state getData { |
| 120 | when (delay(5)) { |
| 121 | wkup = TRUE; |
| 122 | pvPut(wkup, SYNC); |
| 123 | |
| 124 | } state setWakeup |
| 125 | } |
| 126 | |
| 127 | state setWakeup { |
| 128 | when (pvPutComplete(wkup)) { |
| 129 | |
| 130 | for(i=0 ; i<26 ; i++) { |
| 131 | wfByte[i] = 0; |
| 132 | } |
| 133 | |
| 134 | wfProc = 1; |
| 135 | pvPut(wfProc); |
| 136 | } state waitGetData |
| 137 | } |
| 138 | state waitGetData { |
| 139 | when (delay(0.5)) { |
| 140 | pvGet(wfByte); |
| 141 | ack = wfByte[2]; |
| 142 | } state calcData |
| 143 | |
| 144 | when (delay(3)) { |
| 145 | printf("Read Timeout\n"); |
| 146 | } state getData |
| 147 | } |
| 148 | |
| 149 | state calcData { |
| 150 | when (ack == 0x06) { |
| 151 | for(i=0, hsbIndex=5, lsbIndex=6 ; i<3 ; i++, hsbIndex+=2, lsbIndex+=2) { |
| 152 | shtVal = (wfByte[hsbIndex] | (wfByte[lsbIndex] << 8)); |
| 153 | |
| 154 | calcVal = shtVal; |
| 155 | if(i != 2) { |
| 156 | calcVal -= 1000; |
| 157 | } |
| 158 | vals[i] = calcVal / 10.0; |
| 159 | printf("Calc Val: vals[%d]=%.1f\n", i, vals[i]); |
| 160 | pvPut(vals[i]); |
| 161 | } |
| 162 | } state getData |
| 163 | when (ack == 0x00) { |
| 164 | } state getData |
| 165 | } |
| 166 | } |
| 167 | }}} |
| 168 | |
| 169 | == db file == |
| 170 | |
| 171 | {{{ |
| 172 | record(bo, "$(user):wakeup") |
| 173 | { |
| 174 | field(DESC, "Set wakeup device") |
| 175 | field(DTYP, "stream") |
| 176 | field(OUT, "@TR73U.proto setWakeup $(DEV)") |
| 177 | } |
| 178 | |
| 179 | record(waveform, "$(user):getData") |
| 180 | { |
| 181 | field(DESC, "Get data binary") |
| 182 | field(DTYP, "stream") |
| 183 | field(INP, "@TR73U.proto getData $(DEV)") |
| 184 | field(NELM, "26") |
| 185 | field(FTVL, "UCHAR") |
| 186 | } |
| 187 | |
| 188 | record(ai, "$(user):getTemperature") |
| 189 | { |
| 190 | field(DESC, "Get temperature") |
| 191 | field(EGU, "degC") |
| 192 | field(PREC, "1") |
| 193 | } |
| 194 | |
| 195 | record(ai, "$(user):getHumidity") |
| 196 | { |
| 197 | field(DESC, "Get humidity") |
| 198 | field(EGU, "percent") |
| 199 | field(PREC, "1") |
| 200 | } |
| 201 | |
| 202 | record(ai, "$(user):getPressure") |
| 203 | { |
| 204 | field(DESC, "Get atmosphere pressure") |
| 205 | field(EGU, "hPa") |
| 206 | field(PREC, "1") |
| 207 | } |
| 208 | }}} |
| 209 | |
| 210 | |
| 211 | |