source: mac/PaSoRi/trunk/SuicaExample/MyAppController.m @ 36

Revision 36, 10.0 KB checked in by gnue, 3 years ago (diff)

1.0.1

Line 
1#import "PasoriKit/pasori.h"
2#import "PasoriKit/felica.h"
3#import "PasoriKit/suica.h"
4#import "PasoriKit/PasoriRequest.h"
5
6#import "MyAppController.h"
7#import "SFCardDB.h"
8
9
10@implementation MyAppController
11
12
13- (id)init
14{
15    self = [super init];
16    if (self) {
17        suicaValues = [[NSMutableArray array] retain];
18    }
19    return self;
20}
21
22
23- (void)dealloc
24{
25    [suicaValues release];
26    [usbPasori release];
27
28    // PaSoRi のノーティフィケーション通知を削除
29    [usbNotify release];
30
31    [super dealloc];
32}
33
34
35#pragma mark -
36
37
38/// バイナリを16進数文字列に変換する
39- (NSString *)bin2hex:(uint8_t *)data length:(int)len
40{
41    NSMutableString *   str = [NSMutableString stringWithString:@"0x"];
42    int     i;
43   
44    for (i = 0; i < len; i++)
45    {
46        [str appendFormat:@"%02X", data[i]];
47    }
48   
49    return str;
50}
51
52
53/// Suica処理の説明文を取得
54- (NSString *)suicaDescription:(int)proc
55{
56    NSString *  note = nil;
57   
58    switch (proc)
59    {
60        case 1:
61            // 運賃支払(改札出場)
62            break;
63           
64        case 2:
65            note = @"チャージ";
66            break;
67           
68        case 3:
69            note = @"券購(磁気券購入)";
70            break;
71           
72        case 4:
73            note = @"精算";
74            break;
75           
76        case 5:
77            note = @"精算 (入場精算)";
78            break;
79           
80        case 6:
81            note = @"窓出 (改札窓口処理)";
82            break;
83           
84        case 7:
85            note = @"新規 (新規発行)";
86            break;
87           
88        case 8:
89            note = @"控除 (窓口控除)";
90            break;
91           
92        case 13:
93            note = @"バス (PiTaPa系)";
94            break;
95           
96        case 15:
97            note = @"バス (IruCa系)";
98            break;
99           
100        case 17:
101            note = @"再発 (再発行処理)";
102            break;
103           
104        case 19:
105            note = @"支払 (新幹線利用)";
106            break;
107           
108        case 20:
109            note = @"入A (入場時オートチャージ)";
110            break;
111           
112        case 21:
113            note = @"出A (出場時オートチャージ)";
114            break;
115           
116        case 31:
117            note = @"入金 (バスチャージ)";
118            break;
119           
120        case 35:
121            note = @"券購 (バス路面電車企画券購入)";
122            break;
123           
124        case 70:
125            note = @"物販";
126            break;
127           
128        case 72:
129            note = @"特典 (特典チャージ)";
130            break;
131           
132        case 73:
133            note = @"入金 (レジ入金)";
134            break;
135           
136        case 74:
137            note = @"物販取消";
138            break;
139           
140        case 75:
141            note = @"入物 (入場物販)";
142            break;
143           
144        case 198:
145            note = @"物現 (現金併用物販)";
146            break;
147           
148        case 203:
149            note = @"入物 (入場現金併用物販)";
150            break;
151           
152        case 132:
153            note = @"精算 (他社精算)";
154            break;
155           
156        case 133:
157            note = @"精算 (他社入場精算)";
158            break;
159           
160        default:
161            note = @"不明";
162            break;
163    }
164   
165    return note;
166}
167
168
169/// Suica 利用履歴のアップデート
170- (void)updateSuicaValue:(uint8_t *)binary index:(uint8_t)index
171{
172    suica_value_t *         value = (suica_value_t *)binary;
173    NSMutableDictionary *   suicaValue = [NSMutableDictionary dictionary];
174   
175    [suicaValue setObject:[NSData dataWithBytes:value length:sizeof(suica_value_t)] forKey:@"data"];
176   
177    // 利用年月日
178    NSCalendarDate *    date = [NSCalendarDate dateWithYear:2000+suica_year(value) month:suica_month(value) day:suica_day(value) hour:0 minute:0 second:0 timeZone:nil];
179    [suicaValue setObject:date forKey:@"date"];
180   
181    // 残額
182    [suicaValue setObject:[NSNumber numberWithUnsignedShort:suica_balacne(value)] forKey:@"balacne"];
183    if (index == 0)
184    {   // 先頭の残額を残高として表示
185        [balacneView setIntValue:suica_balacne(value)];
186    }
187
188    switch (value->proc)
189    {
190        case 1:
191            // 運賃支払(改札出場)
192            [suicaValue setObject:[self bin2hex:value->in_station length:sizeof(value->in_station)] forKey:@"in_station"];
193            [suicaValue setObject:[self bin2hex:value->out_station length:sizeof(value->out_station)] forKey:@"out_station"];
194            break;
195    }
196   
197    // 備考
198    NSString *  note = [self suicaDescription:value->proc];
199   
200    if (note)
201    {
202        [suicaValue setObject:note forKey:@"note"];
203    }
204   
205    // データの更新
206    [suicaValues addObject:suicaValue];
207    [suicaTableView noteNumberOfRowsChanged];
208}
209
210
211/// Suicaデータをクリアする
212- (void)suicaValueClean
213{
214    [balacneView setStringValue:@""];
215
216    [suicaValues removeAllObjects];
217    [suicaTableView reloadData];
218}
219
220
221#pragma mark -
222
223
224// アプリケーション起動完了通知
225- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
226{
227    // ① PaSoRi のノーティフィケーション通知を登録
228    usbNotify = [[USBNotification usbNotificationWithClass:[USBDevicePasori class]
229                                                  delegate:self
230                                                    vendor:PASORI_USB_VENDOR
231                                                   product:PASORI_USB_PRODUCT] retain];
232}
233
234
235/// ② USBコネクタにデバイスが挿入された
236- (BOOL)usbAddDevice:(USBDevice *)usbDevice
237{
238    if (usbPasori)
239    {   // 既に使っているので新しく挿入されたデバイスは使わない
240        return NO;
241    }
242
243    // あとで使う場合はインスタンス変数に登録しておく
244    usbPasori = (USBDevicePasori *)[usbDevice retain];
245
246    // 接続インディケータを変更
247    [levelIndicator setIntValue:1];
248
249    // このデバイスは使うので YES を返す
250    return YES;
251}
252
253
254/// ③ USBコネクタからデバイスが抜かれた
255- (void)usbRemoveDevice:(USBDevice *)usbDevice
256{
257    if ([usbDevice isEqual:usbPasori])
258    {   // 使っているデバイスならば後始末をする
259        [usbPasori release];
260        usbPasori = nil;
261        // 接続インディケータを変更
262        [levelIndicator setIntValue:0];
263    }
264}
265
266
267/// ④ PaSoRiからのイベント通知
268- (BOOL)pasoriEvent:(USBDevicePasori *)pasori state:(pasori_state_t)state
269{
270    BOOL    handled = NO;
271
272    switch (state)
273    {
274        case PASORI_STATE_INITED:
275            // PaSoRiの初期化完了
276            // 接続インディケータを変更
277            [levelIndicator setIntValue:2];
278            // ポーリングを行う
279            [pasori felicaPolling:FELICA_POLLING_SUICA];
280            handled = YES;
281            break;
282
283        case PASORI_STATE_POLLING_DONE:
284            // ポーリング成功
285            // 接続インディケータを変更
286            [levelIndicator setIntValue:3];
287            // プログレスインディケータを開始
288            [progressIndicator startAnimation:self];
289
290            // Suicaの表示データをクリア
291            [self suicaValueClean];
292            // Suicaの履歴を読出す
293            [pasori felicaReadWithoutEncryption02:FELICA_SC_SUICA_VALUE];
294            handled = YES;
295            break;
296
297        case PASORI_STATE_READING_DONE:
298            // データの読出し終了
299            if ([lookupSFCardFanDbCheckbox state] == 1)
300            {   // 「IC SFCard Fan DB Service参照」チェックボックスが ON の場合
301                // SFCard Fan DB Service から駅名を取得する
302                [self lookupSFCardFanDb];
303            }
304            // プログレスインディケータを終了
305            [progressIndicator stopAnimation:self];
306            break;
307           
308        case PASORI_STATE_UNTOUCHED:
309            // カードがアンタッチされた
310            // 接続インディケータを変更
311            [levelIndicator setIntValue:2];
312            // 再度ポーリングを行う
313            [pasori felicaPolling:FELICA_POLLING_SUICA];
314            // 実行中だったかもしれないのでプログレスインディケータを終了しておく
315            [progressIndicator stopAnimation:self];
316            handled = YES;
317            break;
318    }
319
320    return handled;
321}
322
323
324/// ⑤ Felicaデータの受信
325- (BOOL)felicaReceive:(USBDevicePasori *)pasori data:(felica_ans_t *)ans numBytesRead:(uint32_t)numBytesRead
326{
327    BOOL    handled = NO;
328
329    switch (ans->as.normal.cmd)
330    {
331        case FELICA_ANS_READ_WITHOUT_ENCRYPTION:
332            {
333                PasoriRequest * currRequest = [pasori currRequest];
334//              int     serviceCode = [[[currRequest param] objectForKey:@"serviceCode"] unsignedShortValue];
335                int     index = [[[currRequest param] objectForKey:@"address"] unsignedShortValue];
336
337                // Suica 利用履歴のアップデート
338                [self updateSuicaValue:ans->as.read_wo_enc02.data index:index];
339            }
340            handled = YES;
341            break;
342    }
343
344    return handled;
345}
346
347
348/// ⑥ USBデータの受信
349- (BOOL)usbReceive:(USBDevicePasori *)pasori data:(uint8_t *)buffer numBytesRead:(uint32_t)numBytesRead
350{
351    int     i;
352
353    for (i = 0; i < numBytesRead; i++)
354    {
355        printf("0x%02x, ", buffer[i]);
356    }
357
358    printf("(len = %d)\n", numBytesRead);
359
360    return YES;
361}
362
363
364#pragma mark -
365
366
367/// サービスコードリストの要求
368- (IBAction)requestServiceCode:(id)sender
369{
370    [usbPasori felicaRequestServiceCode];
371}
372
373
374/// システムコードリストの要求
375- (IBAction)requestSystemCode:(id)sender
376{
377    [usbPasori felicaRequestSystemCode];
378}
379
380
381/// 「IC SFCard Fan DB Service参照」チェックボックスが変更されたときの処理
382- (IBAction)toggleLookupSFCard:(id)sender
383{
384    if ([lookupSFCardFanDbCheckbox state] == 1)
385    {
386        // プログレスインディケータを開始
387        [progressIndicator startAnimation:self];
388        // SFCard Fan DB Service から駅名を取得する
389        [self lookupSFCardFanDb];
390        // プログレスインディケータを終了
391        [progressIndicator stopAnimation:self];
392    }
393}
394
395
396/// SFCard Fan DB Service から駅名を取得する
397- (void)lookupSFCardFanDb
398{
399    int     i;
400   
401    for (i = 0; i < [suicaValues count]; i++)
402    {
403        NSMutableDictionary *   suicaValue = [suicaValues objectAtIndex:i];
404        NSData *        data = [suicaValue objectForKey:@"data"];
405        suica_value_t * value = (suica_value_t *)[data bytes];
406       
407        SFCardDB *  sfCardDB = [SFCardDB sharedSFCardDB];
408
409        if ([[suicaValue objectForKey:@"in_station"] hasPrefix:@"0x"])
410        {   // 入場駅がコード表記のまま
411            NSDictionary *  station1;
412           
413            station1 = [sfCardDB getStationNameWithStation:value->in_station regionCode:value->region];
414            NSString *  name1 = [station1 objectForKey:@"StationName"];
415            if (! [name1 isEqual:[NSNull null]]) [suicaValue setObject:name1 forKey:@"in_station"];
416        }
417       
418        if ([[suicaValue objectForKey:@"out_station"] hasPrefix:@"0x"])
419        {   // 出場駅がコード表記のまま
420            NSDictionary *  station2;
421           
422            station2 = [sfCardDB getStationNameWithStation:value->out_station regionCode:value->region];
423            NSString *  name2 = [station2 objectForKey:@"StationName"];
424            if (! [name2 isEqual:[NSNull null]]) [suicaValue setObject:name2 forKey:@"out_station"];
425        }
426
427        // 取得に時間がかかるので逐次表示を更新する
428        [suicaTableView display];
429    }
430   
431//  [suicaTableView setNeedsDisplay:YES];
432}
433
434
435#pragma mark -
436
437
438- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
439{
440    return [suicaValues count];
441}
442
443
444- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
445{
446    return [[suicaValues objectAtIndex:row] objectForKey:[tableColumn identifier]];
447}
448
449
450
451@end
Note: See TracBrowser for help on using the repository browser.