Develop and Download Open Source Software

Browse Subversion Repository

Contents of /tags/FeliCa2Money-2.5/Suica.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 166 - (show annotations) (download)
Thu Mar 20 14:04:13 2008 UTC (16 years ago) by tmurakam
File size: 11315 byte(s)
2.5 tag

1 /*
2 * FeliCa2Money
3 *
4 * Copyright (C) 2001-2008 Takuya Murakami
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 // Suica/PASMO/ICOCA/PiTaPa/Toica など交通系カード処理
22
23 using System;
24 using System.Collections.Generic;
25 using System.Text;
26 using FelicaLib;
27
28 namespace FeliCa2Money
29 {
30 class Suica : CardWithFelicaLib
31 {
32 // 物販エリアコード
33 public const int AreaSuica = 1;
34 public const int AreaIcoca = 2;
35 public const int AreaIruca = 4;
36
37 private StationCode stCode;
38
39 public Suica()
40 {
41 org = "Suica";
42 cardName = "Suica";
43
44 systemCode = (int)SystemCode.Suica;
45 serviceCode = 0x090f; // 履歴エリアのサービスコード
46 needReverse = true;
47
48 stCode = new StationCode();
49 }
50
51 public override void Dispose()
52 {
53 base.Dispose();
54 stCode.Dispose();
55 }
56
57 // カード ID を取得
58 // Suica では IDm を用いる
59 public override void analyzeCardId(Felica f)
60 {
61 byte[] data = f.IDm();
62 if (data == null)
63 {
64 throw new Exception("IDm を読み取れません");
65 }
66
67 accountId = "";
68 for (int i = 0; i < 8; i++) {
69 accountId += data[i].ToString("X2");
70 }
71 }
72
73 // 後処理
74 // Suica の場合、履歴には残高しか記録されていない。
75 // ここでは、残高の差額から各トランザクションの金額を計算する
76 // (このため、最も古いエントリは金額を計算できない)
77 protected override void PostProcess(List<Transaction> list)
78 {
79 int prevBalance = 0;
80
81 foreach (Transaction t in list)
82 {
83 t.value = t.balance - prevBalance;
84 prevBalance = t.balance;
85 }
86 list.RemoveAt(0); // 最古のエントリは捨てる
87 }
88
89 // トランザクション解析
90 public override bool analyzeTransaction(Transaction t, byte[] data)
91 {
92 int ctype = data[0]; // 端末種
93 int proc = data[1]; // 処理
94 int date = read2b(data, 4); // 日付
95 int balance = read2l(data, 10); // 残高(little endian)
96 int seq = read3b(data, 12); // 連番
97 int region = data[15]; // リージョン
98
99 // 処理
100 t.desc = procType(proc);
101
102 // 残高
103 t.balance = balance;
104
105 // 金額は PostProcess で計算する
106 t.value = 0;
107
108 // 日付
109 int yy = (date >> 9) + 2000;
110 int mm = (date >> 5) & 0xf;
111 int dd = date & 0x1f;
112 try
113 {
114 t.date = new DateTime(yy, mm, dd, 0, 0, 0);
115 }
116 catch
117 {
118 // 日付異常(おそらく空エントリ)
119 return false;
120 }
121
122 // ID
123 t.id = seq;
124
125 // 駅名/店舗名などを調べる
126 int in_line = -1;
127 int in_sta = -1;
128 int out_line, out_sta;
129 string[] in_name = null, out_name = null;
130 int area;
131
132 switch (ctype)
133 {
134 case CT_SHOP:
135 case CT_VEND:
136 // 物販/自販機
137 area = Properties.Settings.Default.ShopAreaPriority;
138
139 //time = (data[6] << 8) | data[7];
140 out_line = data[8];
141 out_sta = data[9];
142
143 // 優先エリアで検索
144 out_name = stCode.getShopName(area, ctype, out_line, out_sta);
145 if (out_name == null)
146 {
147 // 全エリアで検索
148 out_name = stCode.getShopName(-1, ctype, out_line, out_sta);
149 }
150 break;
151
152 case CT_CAR:
153 // 車載端末(バス)
154 out_line = read2b(data, 6);
155 out_sta = read2b(data, 8);
156 out_name = stCode.getBusName(out_line, out_sta);
157 break;
158
159 default:
160 // それ以外(運賃、チャージなど)
161 in_line = data[6];
162 in_sta = data[7];
163 out_line = data[8];
164 out_sta = data[9];
165 if (in_line == 0 && in_sta == 0 && out_line == 0 && out_sta == 0)
166 {
167 break;
168 }
169
170 // エリアを求める
171 if (region >= 1) {
172 area = 2; // 関西公営・私鉄
173 }
174 else if (in_line >= 0x80)
175 {
176 area = 1; // 関東公営・私鉄
177 }
178 else
179 {
180 area = 0; // JR
181 }
182
183 in_name = stCode.getStationName(area, in_line, in_sta);
184 out_name = stCode.getStationName(area, out_line, out_sta);
185 break;
186 }
187
188 // 備考の先頭には端末種を入れる
189 t.memo = consoleType(ctype);
190
191 switch (ctype)
192 {
193 case CT_SHOP:
194 case CT_VEND:
195 if (out_name != null)
196 {
197 // 適用に店舗名を入れる
198 t.desc += " " + out_name[0] + " " + out_name[1];
199 }
200 else
201 {
202 // 店舗名が不明の場合、適用には出線区/出駅順コードをそのまま付与する。
203 // こうしないと Money が過去の履歴から誤って店舗名を補完してしまい
204 // 都合がわるいため
205 t.desc += " 店舗コード:" + out_line.ToString("X02") + out_sta.ToString("X02");
206 }
207 break;
208
209 case CT_CAR:
210 if (out_name != null)
211 {
212 // 適用にバス会社名、備考に停留所名を入れる
213 t.desc += " " + out_name[0];
214 t.memo += " " + out_name[1];
215 }
216 break;
217
218 default:
219 if (in_line == 0 && in_sta == 0 & out_line == 0 && out_sta == 0)
220 {
221 // チャージなどの場合は、何も追加しない
222 break;
223 }
224
225 // 適用に入会社または出会社を追加
226 if (in_name != null)
227 {
228 t.desc += " " + in_name[0];
229 }
230 else if (out_name != null)
231 {
232 t.desc += " " + out_name[0];
233 }
234
235 // 備考に入出会社/駅名を記載
236 if (in_name != null) {
237 t.memo += " " + in_name[0] + "(" + in_name[1] + ")";
238 } else {
239 t.memo += " 未登録";
240 }
241 t.memo += " - ";
242
243 if (out_name != null) {
244 t.memo += out_name[0] + "(" + out_name[1] + ")";
245 } else {
246 t.memo += "未登録";
247 }
248 break;
249 }
250
251 return true;
252 }
253
254 private const int CT_SHOP = 199; // 物販端末
255 private const int CT_VEND = 200; // 自販機
256 private const int CT_CAR = 5; // 車載端末(バス)
257
258 // 端末種文字列を返す
259 private string consoleType(int ctype)
260 {
261 switch (ctype) {
262 case CT_SHOP: return "物販端末";
263 case CT_VEND: return "自販機";
264 case CT_CAR: return "車載端末";
265 case 3: return "清算機";
266 case 4: return "携帯型端末";
267 case 8: return "券売機";
268 case 9: return "入金機";
269 case 18: return "券売機";
270 case 20:
271 case 21: return "券売機等";
272 case 22: return "改札機";
273 case 23: return "簡易改札機";
274 case 24:
275 case 25: return "窓口端末";
276 case 26: return "改札端末";
277 case 27: return "携帯電話";
278 case 28: return "乗継精算機";
279 case 29: return "連絡改札機";
280 case 31: return "簡易入金機";
281 case 70:
282 case 72: return "VIEW ALTTE";
283 }
284 return "不明";
285 }
286
287 // 処理種別文字列を返す
288 private string procType(int proc)
289 {
290 switch (proc) {
291 case 1: return "運賃";
292 case 2: return "チャージ";
293 case 3: return "券購";
294 case 4:
295 case 5: return "清算";
296 case 6: return "窓出";
297 case 7: return "新規";
298 case 8: return "控除";
299 case 13: return "バス"; //PiTaPa系
300 case 15: return "バス"; //IruCa系
301 case 17: return "再発行";
302 case 19: return "支払";
303 case 20:
304 case 21: return "オートチャージ";
305 case 31: return "バスチャージ";
306 case 35: return "券購";
307 case 70: return "物販";
308 case 72: return "特典";
309 case 73: return "入金";
310 case 74: return "物販取消";
311 case 75: return "入場物販";
312 case 132: return "精算(他社)";
313 case 133: return "精算(他社入場)";
314 case 198: return "物販(現金併用)";
315 case 203: return "物販(入場現金併用)";
316 }
317 return "不明";
318 }
319 }
320 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26