Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1702 - 1
#include "devinfoparser.h"
2
 
3
const char* DevInfoParser::ptpopNames[] PROGMEM =
4
{
5
        msgUndefined,                          
6
        msgGetDeviceInfo,                      
7
        msgOpenSession,                
8
        msgCloseSession,                       
9
        msgGetStorageIDs,                      
10
        msgGetStorageInfo,             
11
        msgGetNumObjects,                      
12
        msgGetObjectHandles,           
13
        msgGetObjectInfo,                      
14
        msgGetObject,                          
15
        msgGetThumb,                           
16
        msgDeleteObject,                       
17
        msgSendObjectInfo,             
18
        msgSendObject,                 
19
        msgInitiateCapture,            
20
        msgFormatStore,                
21
        msgResetDevice,                
22
        msgSelfTest,                           
23
        msgSetObjectProtection,
24
        msgPowerDown,                          
25
        msgGetDevicePropDesc,          
26
        msgGetDevicePropValue, 
27
        msgSetDevicePropValue, 
28
        msgResetDevicePropValue,       
29
        msgTerminateOpenCapture,       
30
        msgMoveObject,                 
31
        msgCopyObject,                 
32
        msgGetPartialObject,           
33
        msgInitiateOpenCapture 
34
};
35
 
36
const char* DevInfoParser::mtpopNames[] PROGMEM =
37
{
38
        msgUndefined,                          
39
        msgGetObjectPropsSupported,    
40
        msgGetObjectPropDesc,                  
41
        msgGetObjectPropValue,         
42
        msgSetObjectPropValue,         
43
        msgGetObjectPropList,                  
44
        msgSetObjectPropList,                  
45
        msgGetInterdependentPropDesc,  
46
        msgSendObjectPropList          
47
};
48
 
49
const char* DevInfoParser::ptpevNames[] PROGMEM =
50
{
51
        msgUndefined,
52
        msgCancelTransaction,
53
        msgObjectAdded,
54
        msgObjectRemoved,
55
        msgStoreAdded,
56
        msgStoreRemoved,
57
        msgDevicePropChanged,
58
        msgObjectInfoChanged,
59
        msgDeviceInfoChanged,
60
        msgRequestObjectTransfer,
61
        msgStoreFull,
62
        msgDeviceReset,
63
        msgStorageInfoChanged,
64
        msgCaptureComplete,
65
        msgUnreportedStatus
66
};
67
 
68
const char* DevInfoParser::mtpevNames[] PROGMEM =
69
{
70
        msgUndefined,
71
        msgObjectPropChanged,          
72
        msgObjectPropDescChanged,      
73
        msgObjectReferencesChanged
74
};
75
 
76
const char* DevInfoParser::ptpprNames[] PROGMEM =
77
{
78
        msgUndefined,                                  
79
        msgBatteryLevel,                               
80
        msgFunctionalMode,                     
81
        msgImageSize,                                  
82
        msgCompressionSetting,         
83
        msgWhiteBalance,                               
84
        msgRGBGain,                                    
85
        msgFNumber,                                    
86
        msgFocalLength,                        
87
        msgFocusDistance,                              
88
        msgFocusMode,                                  
89
        msgExposureMeteringMode,               
90
        msgFlashMode,                                  
91
        msgExposureTime,                               
92
        msgExposureProgramMode,        
93
        msgExposureIndex,                              
94
        msgExposureBiasCompensation,   
95
        msgDateTime,                                   
96
        msgCaptureDelay,                               
97
        msgStillCaptureMode,                   
98
        msgContrast,                                   
99
        msgSharpness,                                  
100
        msgDigitalZoom,                        
101
        msgEffectMode,                         
102
        msgBurstNumber,                        
103
        msgBurstInterval,                              
104
        msgTimelapseNumber,                    
105
        msgTimelapseInterval,                  
106
        msgFocusMeteringMode,                  
107
        msgUploadURL,                                  
108
        msgArtist,                                     
109
        msgCopyrightInfo                               
110
};
111
 
112
const char* DevInfoParser::mtpprNames[] PROGMEM =
113
{
114
        msgUndefined,                                  
115
        msgSynchronization_Partner,            
116
        msgDevice_Friendly_Name,                       
117
        msgVolume,                                             
118
        msgSupportedFormatsOrdered,            
119
        msgDeviceIcon,                                 
120
        msgSession_Initiator_Version_Info,
121
        msgPerceived_Device_Type,                      
122
        msgPlayback_Rate,                                      
123
        msgPlayback_Object,                            
124
        msgPlayback_Container                  
125
};
126
 
127
const char* DevInfoParser::acNames[] PROGMEM =
128
{
129
        msgUndefined,
130
        msgAssociation,
131
        msgScript,             
132
        msgExecutable, 
133
        msgText,                       
134
        msgHTML,                       
135
        msgDPOF,                       
136
        msgAIFF,                       
137
        msgWAV,                
138
        msgMP3,        
139
        msgAVI,                
140
        msgMPEG,                       
141
        msgASF,                
142
        msgQT                  
143
};
144
 
145
const char* DevInfoParser::imNames[] PROGMEM =
146
{
147
        msgUndefined,
148
        msgEXIF_JPEG,                  
149
        msgTIFF_EP,                    
150
        msgFlashPix,                   
151
        msgBMP,                        
152
        msgCIFF,                               
153
        msgUndefined_0x3806,   
154
        msgGIF,                        
155
        msgJFIF,                               
156
        msgPCD,                        
157
        msgPICT,                               
158
        msgPNG,                        
159
        msgUndefined_0x380C,   
160
        msgTIFF,                               
161
        msgTIFF_IT,                    
162
        msgJP2,                        
163
        msgJPX,                        
164
};
165
 
166
DevInfoParser::DevInfoParser() :
167
        nStage(0),
168
        strByteCountDown(0),
169
        waStage(0),
170
        waLenCountDown(0),
171
        waByteCountDown(0),
172
        fmByteCountDown(0),
173
        idVendor(0)
174
{
175
        for (uint8_t i=0; i<4; i++) waLen[i];
176
        waWord.word = 0;
177
        fmBytes[0] = 0;
178
        fmBytes[1] = 0;
179
};
180
 
181
bool DevInfoParser::PrintFunctMode(uint8_t **pp, uint16_t &count)
182
{
183
        if (!count)
184
                return true;
185
 
186
        if (!fmByteCountDown)
187
                fmByteCountDown = 2;
188
 
189
        for (; fmByteCountDown && count; fmByteCountDown--, count--, (*pp)++)
190
                fmBytes[fmByteCountDown & 1] = (**pp);
191
 
192
        if (fmByteCountDown)
193
                return false;
194
 
195
        Notify(PSTR("Func.Mode:\t0x")); Serial.println((uint16_t)fmBytes, HEX);
196
        return true;
197
}
198
 
199
void DevInfoParser::PrintOperation(uint16_t op)
200
{
201
        bool bResult = false;
202
 
203
        Serial.print(op, HEX);
204
        Notify(msgTab);
205
 
206
        switch (((op >> 8) & 0xFF))
207
        {
208
        case 0x10:
209
                bResult = PrintPTPOperation(op);
210
                break;
211
        case 0x98:
212
                bResult = PrintMTPOperation(op);
213
                break;
214
        default:
215
                switch (idVendor)
216
                {
217
                case PTP_VENDOR_MICROSOFT:
218
                case PTP_VENDOR_CANON:
219
                        if ((bResult = PrintPSOperation(op)))
220
                                break;
221
                        bResult = PrintEOSOperation(op);
222
                        break;
223
                default:
224
                        Notify(msgVendorDefined);
225
                        bResult = true;
226
                }
227
        }
228
        if (!bResult)
229
                Notify(msgVendorDefined);
230
        Notify(msgCRLF);
231
}
232
 
233
bool DevInfoParser::PrintPTPOperation(uint16_t op)
234
{
235
        if ((op & 0xFF) <= (PTP_OC_InitiateOpenCapture & 0xFF))
236
        {
237
                Notify((char*)pgm_read_word(&ptpopNames[(op & 0xFF)]));
238
                return true;
239
        }
240
        return false;
241
}
242
 
243
bool DevInfoParser::PrintMTPOperation(uint16_t op)
244
{
245
        if ((op & 0xFF) <= (MTP_OC_SendObjectPropList & 0xFF))
246
                Notify((char*)pgm_read_word(&mtpopNames[(op & 0xFF)]));
247
        else
248
        {
249
                switch (op)
250
                {
251
                case MTP_OC_GetObjectReferences:
252
                        Notify(msgGetObjectReferences);
253
                        break;
254
                case MTP_OC_SetObjectReferences:
255
                        Notify(msgSetObjectReferences);
256
                        break;
257
                case MTP_OC_Skip:
258
                        Notify(msgSkip);
259
                        break;
260
                default:
261
                        return false;
262
                }
263
        }
264
        return true;
265
}
266
 
267
bool DevInfoParser::PrintPSOperation(uint16_t op)
268
{
269
        const char* msg;
270
 
271
        switch (op)
272
        {
273
        case PTP_OC_PS_GetObjectSize:
274
                msg = msgPS_GetObjectSize;
275
                break;
276
        case PTP_OC_PS_StartShootingMode:
277
                msg = msgPS_StartShootingMode;
278
                break;
279
        case PTP_OC_PS_EndShootingMode:                
280
                msg = msgPS_EndShootingMode;
281
                break;
282
        case PTP_OC_PS_ViewfinderOn:                           
283
                msg = msgPS_ViewfinderOn;
284
                break;
285
        case PTP_OC_PS_ViewfinderOff:                  
286
                msg = msgPS_ViewfinderOff;
287
                break;
288
        case PTP_OC_PS_ReflectChanges:                 
289
                msg = msgPS_ReflectChanges;
290
                break;
291
        case PTP_OC_PS_CheckEvent:                             
292
                msg = msgPS_CheckEvent;
293
                break;
294
        case PTP_OC_PS_FocusLock:                              
295
                msg = msgPS_FocusLock;
296
                break;
297
        case PTP_OC_PS_FocusUnlock:                            
298
                msg = msgPS_FocusUnlock;
299
                break;
300
        case PTP_OC_PS_InitiateCaptureInMemory:
301
                msg = msgPS_InitiateCaptureInMemory;
302
                break;
303
        case PTP_OC_PS_GetPartialObject:                       
304
                msg = msgPS_GetPartialObject;
305
                break;
306
        case PTP_OC_PS_GetViewfinderImage:             
307
                msg = msgPS_GetViewfinderImage;
308
                break;
309
        case PTP_OC_PS_GetChanges:             
310
                msg = msgPS_GetChanges;
311
                break;
312
        case PTP_OC_PS_GetFolderEntries:
313
                msg = msgPS_GetFolderEntries;
314
                break;
315
        default:
316
                return false;
317
        }
318
        Notify(msg);
319
        return true;
320
}
321
 
322
bool DevInfoParser::PrintEOSOperation(uint16_t op)
323
{
324
        const char *msg;
325
        switch (op)
326
        {
327
        case PTP_OC_EOS_GetStorageIDs:
328
                msg = msgEOS_GetStorageIDs;
329
                break;
330
        case PTP_OC_EOS_GetStorageInfo:                
331
                msg = msgEOS_GetStorageInfo;
332
                break;
333
        case PTP_OC_EOS_GetObject:                             
334
                msg = msgEOS_GetObject;
335
                break;
336
        case PTP_OC_EOS_GetDeviceInfo:                 
337
                msg = msgEOS_GetDeviceInfo;
338
                break;
339
        case PTP_OC_EOS_GetObjectIDs:                  
340
                msg = msgEOS_GetObjectIDs;
341
                break;
342
        case PTP_OC_EOS_Capture:                                       
343
                msg = msgEOS_Capture;
344
                break;
345
        case PTP_OC_EOS_SetDevicePropValue:            
346
                msg = msgEOS_SetDevicePropValue;
347
                break;
348
        case PTP_OC_EOS_SetPCConnectMode:              
349
                msg = msgEOS_SetPCConnectMode;
350
                break;
351
        case PTP_OC_EOS_SetExtendedEventInfo:  
352
                msg = msgEOS_SetExtendedEventInfo;
353
                break;
354
        case PTP_OC_EOS_GetEvent:                              
355
                msg = msgEOS_GetEvent;
356
                break;
357
        case PTP_OC_EOS_GetLiveViewPicture:            
358
                msg = msgEOS_GetLiveViewPicture;
359
                break;
360
        case PTP_OC_EOS_MoveFocus:
361
                msg = msgEOS_MoveFocus;
362
                break;
363
        default:
364
                return false;
365
        }
366
        Notify(msg);
367
        return true;
368
}
369
 
370
void DevInfoParser::PrintEvent(uint16_t op)
371
{
372
        Serial.print(op, HEX);
373
        Notify(msgTab);
374
 
375
        if ((((op >> 8) & 0xFF) == 0x40) && ((op & 0xFF) <= (PTP_EC_UnreportedStatus & 0xFF)))
376
                Notify((char*)pgm_read_word(&ptpevNames[(op & 0xFF)]));
377
        else
378
                if ((((op >> 8) & 0xFF) == 0xC8) && ((op & 0xFF) <= (MTP_EC_ObjectReferencesChanged & 0xFF)))
379
                        Notify((char*)pgm_read_word(&mtpevNames[(op & 0xFF)]));
380
                else
381
                        Notify(msgVendorDefined);
382
        Notify(msgCRLF);
383
}
384
 
385
void DevInfoParser::PrintDevProp(uint16_t op)
386
{
387
        Serial.print(op, HEX);
388
        Notify(msgTab);
389
 
390
        if ((((op >> 8) & 0xFF) == 0x50) && ((op & 0xFF) <= (PTP_DPC_CopyrightInfo & 0xFF)))
391
                Notify((char*)pgm_read_word(&ptpprNames[(op & 0xFF)]));
392
        else
393
                if (((op >> 8) & 0xFF) == 0xD4)
394
                {
395
                        if ( (op & 0xFF) <= (MTP_DPC_Perceived_Device_Type & 0xFF) )
396
                                Notify((char*)pgm_read_word(&mtpprNames[(op & 0xFF)]));
397
                        else
398
                        {
399
                                switch (op)
400
                                {
401
                                case MTP_DPC_Playback_Rate:
402
                                        Notify(msgPlayback_Rate);
403
                                        break;
404
                                case MTP_DPC_Playback_Object:
405
                                        Notify(msgPlayback_Object);
406
                                        break;
407
                                case MTP_DPC_Playback_Container:
408
                                        Notify(msgPlayback_Container);
409
                                        break;
410
                                default:
411
                                        Notify(msgVendorDefined);
412
                                }
413
                        }
414
                }
415
                else
416
                        Notify(msgVendorDefined);
417
 
418
        Notify(msgCRLF);
419
}
420
 
421
void DevInfoParser::PrintFormat(uint16_t op)
422
{
423
        Serial.print(op, HEX);
424
        Notify(msgTab);
425
 
426
        if ((((op >> 8) & 0xFF) == 0x30) && ((op & 0xFF) <= (PTP_OFC_QT & 0xFF)))
427
                Notify((char*)pgm_read_word(&acNames[(op & 0xFF)]));
428
        else
429
                if ((((op >> 8) & 0xFF) == 0x38) && ((op & 0xFF) <= (PTP_OFC_JPX & 0xFF)))
430
                        Notify((char*)pgm_read_word(&imNames[(op & 0xFF)]));
431
                else
432
                {
433
                        switch (op)
434
                        {
435
                        case MTP_OFC_Undefined_Firmware:
436
                                Notify(msgUndefined_Firmware);
437
                                break;
438
                        case MTP_OFC_Windows_Image_Format:     
439
                                Notify(msgWindows_Image_Format);
440
                                break;
441
                        case MTP_OFC_Undefined_Audio:                  
442
                                Notify(msgUndefined_Audio);
443
                                break;
444
                        case MTP_OFC_WMA:                                              
445
                                Notify(msgWMA);
446
                                break;
447
                        case MTP_OFC_OGG:                                              
448
                                Notify(msgOGG);
449
                                break;
450
                        case MTP_OFC_AAC:                                              
451
                                Notify(msgAAC);
452
                                break;
453
                        case MTP_OFC_Audible:                                  
454
                                Notify(msgAudible);
455
                                break;
456
                        case MTP_OFC_FLAC:                                     
457
                                Notify(msgFLAC);
458
                                break;
459
                        case MTP_OFC_Undefined_Video:                  
460
                                Notify(msgUndefined_Video);
461
                                break;
462
                        case MTP_OFC_WMV:                                              
463
                                Notify(msgWMV);
464
                                break;
465
                        case MTP_OFC_MP4_Container:                    
466
                                Notify(msgMP4_Container);
467
                                break;
468
                        case MTP_OFC_MP2:                                              
469
                                Notify(msgMP2);
470
                                break;
471
                        case MTP_OFC_3GP_Container:
472
                                Notify(msg3GP_Container);
473
                                break;
474
                        default:
475
                                Notify(msgVendorDefined);
476
                        }
477
                }
478
        Notify(msgCRLF);
479
}
480
 
481
bool DevInfoParser::PrintVendor(uint8_t **pp, uint16_t &count)
482
{
483
        Notify(PSTR("Vendor Ext. ID:\t0x"));
484
        Serial.print(*((uint32_t*)*pp),HEX);
485
 
486
        switch (*((uint32_t*)*pp))
487
        {
488
        case PTP_VENDOR_EASTMAN_KODAK:
489
                Notify(PSTR("(Eastman Kodak)"));
490
                break;
491
        case PTP_VENDOR_SEIKO_EPSON:           
492
                Notify(PSTR("(Seiko Epson)"));
493
                break;
494
        case PTP_VENDOR_AGILENT:               
495
                Notify(PSTR("(Agilent)"));
496
                break;
497
        case PTP_VENDOR_POLAROID:                      
498
                Notify(PSTR("(Polaroid)"));
499
                break;
500
        case PTP_VENDOR_AGFA_GEVAERT:                  
501
                Notify(PSTR("(AGFA)"));
502
                break;
503
        case PTP_VENDOR_MICROSOFT:             
504
                Notify(PSTR("(Microsoft)"));
505
                break;
506
        case PTP_VENDOR_EQUINOX:               
507
                Notify(PSTR("(Equinox)"));
508
                break;
509
        case PTP_VENDOR_VIEWQUEST:             
510
                Notify(PSTR("(ViewQuest)"));
511
                break;
512
        case PTP_VENDOR_STMICROELECTRONICS:
513
                Notify(PSTR("(StMicroelectronics)"));
514
                break;
515
        case PTP_VENDOR_NIKON:
516
                Notify(PSTR("(Nikon)"));
517
                break;
518
        case PTP_VENDOR_CANON:
519
                Notify(PSTR("(Canon)"));
520
                break;
521
        case PTP_VENDOR_FOTONATION:
522
                Notify(PSTR("(FotoNation)"));
523
                break;
524
        case PTP_VENDOR_PENTAX:
525
                Notify(PSTR("(Pentax)"));
526
                break;
527
        case PTP_VENDOR_FUJI:
528
                Notify(PSTR("(Fuji)"));
529
                break;
530
        default:
531
                Notify(PSTR("(Unknown)"));
532
        }
533
        Notify(msgCRLF);
534
        *pp += 4; count -= 4;
535
        return true;
536
}
537
 
538
bool DevInfoParser::PrintString(uint8_t **pp, uint16_t &count)
539
{
540
        if (!count)
541
                return true;
542
 
543
        if ( !strByteCountDown )
544
        {
545
                if ( !(**pp) )
546
                {
547
                        (*pp) ++;
548
                        count --;
549
                        return true;
550
                }
551
                strByteCountDown = ((**pp) << 1);
552
                (*pp) ++;
553
                count --;
554
        }
555
 
556
        for (; strByteCountDown && count; strByteCountDown--, count--, (*pp)++)
557
        {
558
                if ( !(strByteCountDown & 1) && ((**pp) > 0))
559
                        Serial.print((unsigned char)(**pp));
560
        }
561
        return (strByteCountDown == 0);
562
}
563
 
564
bool DevInfoParser::PrintWordArray(uint8_t **pp, uint16_t &count, PRINTFUNC pf = NULL)
565
{
566
        switch (waStage)
567
        {
568
        case 0:
569
                if (!waLenCountDown)
570
                        waLenCountDown = 4;
571
 
572
                for (; waLenCountDown && count; waLenCountDown--, count--, (*pp)++)
573
                        waLen[4-waLenCountDown] = (**pp);
574
 
575
                if (waLenCountDown)
576
                        return false;
577
 
578
                waStage ++;
579
 
580
        case 1:
581
                for (waByteCountDown = (waByteCountDown) ? waByteCountDown : ((*((uint32_t*)waLen) << 1));
582
                         waByteCountDown && count; waByteCountDown--, count--, (*pp)++)
583
                {
584
                        if (waByteCountDown & 1)
585
                        {
586
                                waWord.bytes[1] = (**pp);
587
 
588
                                if ( pf )
589
                                        (this->*pf)(waWord.word);
590
                                else
591
                                        Serial.println (waWord.word, HEX);
592
                        }
593
                        else
594
                                waWord.bytes[0] = (**pp);
595
                }
596
                if (waByteCountDown)
597
                        return false;
598
        }
599
        waStage = 0;
600
        return true;
601
}
602
 
603
void DevInfoParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint32_t &offset)
604
{
605
        uint16_t        count   = (uint16_t)len;
606
        uint8_t         *p              = (uint8_t*)pbuf;
607
 
608
        switch (nStage)
609
        {
610
        case 0:
611
                // Skip PTP container header
612
                p += 12;        count -=12;
613
                nStage ++;
614
        case 1:
615
                Notify(PSTR("\r\nStd.Ver.:\t0x"));                      Serial.println(*(uint16_t*)p, DEC);    
616
                p += 2;         count -= 2;
617
 
618
                idVendor = *((uint32_t*)p);
619
                PrintVendor(&p, count);
620
 
621
                Notify(PSTR("\r\nVend.Ext.Ver.:\t0x"));         Serial.println(*((uint16_t*)p), HEX);
622
                p += 2;         count -=2;
623
 
624
                nStage ++;
625
        case 2:
626
                // Vendor extension description
627
                //if (*p)
628
                {
629
                        if (!PrintString(&p, count))
630
                                return;
631
 
632
                        Notify(msgCRLF);
633
                }
634
                nStage ++;
635
        case 3:
636
                // Functional mode
637
                if (!PrintFunctMode(&p, count))
638
                        return;
639
                nStage ++;
640
        case 4:
641
                // Operations Supported
642
                Notify(PSTR("\r\nOperations supported:\r\n"));
643
                nStage++;
644
        case 5:
645
                if (!PrintWordArray(&p, count, &DevInfoParser::PrintOperation))
646
                        return;
647
                nStage ++;
648
        case 6:
649
                // Events Supported
650
                Notify(PSTR("\r\nEvents supported:\r\n"));
651
                nStage ++;
652
        case 7:
653
                if (!PrintWordArray(&p, count, &DevInfoParser::PrintEvent))
654
                        return;
655
                nStage ++;
656
        case 8:
657
                // Device Properties Supported
658
                Notify(PSTR("\r\nDevice properties supported:\r\n"));
659
                nStage ++;
660
        case 9:
661
                if (!PrintWordArray(&p, count, &DevInfoParser::PrintDevProp))
662
                        return;
663
                nStage ++;
664
        case 10:
665
                // Capture formats
666
                Notify(PSTR("\r\nCapture formats:\r\n"));
667
                nStage ++;
668
        case 11:
669
                if (!PrintWordArray(&p, count, &DevInfoParser::PrintFormat))
670
                        return;
671
                nStage ++;
672
        case 12:
673
                // Image Formats
674
                Notify(PSTR("\r\nImage Formats:\r\n"));
675
                nStage ++;
676
        case 13:
677
                if (!PrintWordArray(&p, count, &DevInfoParser::PrintFormat))
678
                        return;
679
                nStage ++;
680
        case 14:
681
                // Manufacturer
682
                Notify(PSTR("\r\nManufacturer:\t"));
683
                nStage ++;
684
        case 15:
685
                if (!PrintString(&p, count))
686
                        return;
687
                nStage ++;
688
        case 16:
689
                // Model
690
                Notify(PSTR("\r\nModel:\t\t"));
691
                nStage ++;
692
        case 17:
693
                if (!PrintString(&p, count))
694
                        return;
695
                nStage ++;
696
        case 18:
697
                // Device version
698
                Notify(PSTR("\r\nDevice ver.:\t"));
699
                nStage ++;
700
        case 19:
701
                if (!PrintString(&p, count))
702
                        return;
703
                nStage ++;
704
        case 20:
705
                // Serial number
706
                Notify(PSTR("\r\nSerial num.:\t"));
707
                nStage ++;
708
        case 21:
709
                if (!PrintString(&p, count))
710
                        return;
711
                Notify(PSTR("\r\n\r\n"));
712
                //nStage = 0;
713
        }
714
}