1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - tools - loadrun
3   File:     loadrun.c
4 
5   Copyright 2005-2007 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-05-23#$
14   $Rev: 6187 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 #include <windows.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/fcntl.h>
23 #include <sys/stat.h>
24 #include <getopt.h>
25 #include <signal.h>
26 #include <time.h>
27 
28 #include "ISNITRODLL.h"
29 #include "isd_api.h"
30 
31 #define  SDK_BOOL_ALREADY_DEFINED_
32 #include <nitro_win32.h>
33 #include <nitro/os/common/system.h>
34 
35 extern const unsigned long SDK_DATE_OF_LATEST_FILE;
36 
37 //---- Version string
38 #define VERSION_STRING     " 1.13  Copyright 2005-2008 Nintendo. All right reserved."
39 // 1.13  Fixed print callback bug
40 // 1.12 Corrected help display
41 // 1.11 Deleted device type
42 // 1.10 Displayed latest time stamp of source file
43 // 1.9 Changed exit status of loadrun itself
44 // 1.8 Supported terminating character string from OS_EXIT()
45 // 1.7 Allowed data to be read from standard input
46 // 1.6 Disabled buffering of standard output
47 // 1.5 Allowed character string termination even in Quiet Mode
48 // 1.4 Implemented wrap display
49 // 1.3 Implemented execution timeout
50 // 1.2 Changed processing when execution is stopped using ctrl-c
51 // 1.1 Made it so the slot is turned off when execution is stopped using ctrl-c
52 // 1.0 Published
53 
54 //---- exit number
55 #define EXIT_NUM_NO_ERROR               207     // Successful exit (however, this will not result next time)
56 #define EXIT_NUM_USER_SIGNAL            206     // Forced exit by user (ctrl-C)
57 #define EXIT_NUM_EXEC_TIME_OUT          205     // Forced exit due to execution timeout
58 #define EXIT_NUM_TIME_OUT               204     // Forced exit due to display timeout
59 #define EXIT_NUM_SHOW_DEVICES           203     // Exit on device list display
60 #define EXIT_NUM_SHOW_USAGE             202     // Exit on help display
61 #define EXIT_NUM_SHOW_VERSION           201     // Exit on version display
62 #define EXIT_NUM_STRING_ABORT           200     // Forced exit by character string
63 
64 #define EXIT_NUM_NO_DEVICE              -1      // There are no available devices
65 #define EXIT_NUM_UNKNOWN_OPTION         -2      // An unknown option was specified
66 #define EXIT_NUM_ILLEGAL_OPTION         -3      // Illegal use of option
67 #define EXIT_NUM_NO_INPUT_FILE          -4      // The specified file does not exist or cannot be opened
68 #define EXIT_NUM_NOT_CONNECT            -5      // Failed to connect to device
69 #define EXIT_NUM_CANNOT_USE_CARTRIDGE   -6      // Failed to lock cartridge
70 #define EXIT_NUM_CANNOT_USE_CARD        -7      // Failed to lock card
71 #define EXIT_NUM_PRINTF_ERROR           -8      // Error while handling printf data
72 #define EXIT_NUM_LOADING_ERROR          -9      // Error during loading
73 
74 //---- For device specification
75 char   *gDeviceName[] = {
76     "CGBUSB", "CGBSCSI", "NITROUSB", "NITROUIC", NULL
77 };
78 int     gDeviceTypeArray[] = {
79     ISNTD_DEVICE_CGB_EMULATOR_USB,
80     ISNTD_DEVICE_CGB_EMULATOR_SCSI,
81     ISNTD_DEVICE_IS_NITRO_EMULATOR,
82     ISNTD_DEVICE_IS_NITRO_UIC
83 };
84 
85 //---- Operating mode
86 BOOL    gQuietMode = FALSE;            // Quiet mode
87 BOOL    gVerboseMode = FALSE;          // verbose mode
88 BOOL    gDebugMode = FALSE;            // Debug mode
89 
90 BOOL    gStdinMode = FALSE;            // stdin mode
91 
92 BOOL    gIsTypeSpecified = FALSE;      // Is there a device type specification?
93 int     gSpecifiedType;                // Device type if one is specified
94 
95 BOOL    gIsSerialSpecified = FALSE;    // Is there a serial number specification?
96 int     gSpecifiedSerial;              // Serial number if one was specified
97 
98 BOOL    gIsCartridgeLocked = FALSE;    // Should the cartridge slot be locked?
99 BOOL    gIsCardLocked = FALSE;         // Should the card slot be locked?
100 
101 int     gTimeOutTime = 0;              // Timeout interval in sec (0 indicates no timeout)
102 BOOL    gTimeOutOccured = FALSE;       // Has a timeout occurred?
103 
104 int     gExecTimeOutTime = 0;          // Execution timeout interval in sec (0 indicates no timeout)
105 int     gExecTimeOutOccured = FALSE;   // Has an execution timeout occurred?
106 
107 char   *gAbortString = NULL;           // Abort string
108 BOOL    gStringAborted = FALSE;        // Has execution terminated due to the abort string?
109 
110 BOOL    gExitAborted = FALSE;          // Exit from OS_Exit()
111 int     gExitStatusNum = EXIT_NUM_STRING_ABORT; // Return value when terminated by OS_Exit()
112 int     gExitStrLength;                // Length of exit string
113 
114 //---- For NITRO library
115 HINSTANCE gDllInstance;
116 NITRODEVICEHANDLE gDeviceHandle;
117 NITRODEVICEID gDeviceId;
118 
119 //Connected to the device? (for slot switch)
120 BOOL    gDeviceConnected = FALSE;
121 
122 
123 //---- Device list
124 #define DEVICE_MAX_NUM      256
125 #define DEVICE_SERIAL_NONE  0x7fffffff // means no specified
126 ISNTDDevice gDeviceList[DEVICE_MAX_NUM];
127 int     gCurrentDevice = -1;
128 int     gConnectedDeviceNum = 0;
129 
130 int     gDeviceTypeSpecified = ISNTD_DEVICE_NONE;
131 int     gDeviceSerialSpecified = DEVICE_SERIAL_NONE;    // means no specified
132 
133 //---- Input file
134 #define FILE_NAME_MAX_SIZE  1024
135 FILE   *gInputFile;
136 char    gInputFileNameString[FILE_NAME_MAX_SIZE];
137 BOOL    gIsInputFileOpened = FALSE;
138 
139 //---- Time
140 time_t  gStartTime = 0;                // Start time
141 BOOL    gIsLineHead = TRUE;            // Start of line?
142 BOOL    gShowLapTime = FALSE;
143 
144 //---- Signal
145 BOOL    gStoppedByUser = FALSE;        // Indicates whether execution was stopped by the user.
146 
147 
148 #define printfIfNotQuiet(str)    do{if(!gQuietMode){fputs(str,stdout);}}while(0)
149 
150 void    displayErrorAndExit(int exitNum, char *message);
151 BOOL    outputString(char *buf, int bufSize);
152 
153 /*---------------------------------------------------------------------------*
154   Name:         myExit
155 
156   Description:  similar to exit()
157 
158   Arguments:    exitNum: exit() number
159 
160   Returns:      None.
161  *---------------------------------------------------------------------------*/
myExit(int exitNum)162 void myExit(int exitNum)
163 {
164     //---- Turns off the slot for the cartridge and card
165     if (gDeviceConnected)
166     {
167         (void)ISNTD_CartridgeSlotPower(gDeviceHandle, FALSE);
168         (void)ISNTD_CardSlotPower(gDeviceHandle, FALSE);
169     }
170 
171     //---- Deallocate DLL memory
172     ISNTD_FreeDll();
173 
174     if (!gQuietMode)
175     {
176         if (exitNum == EXIT_NUM_USER_SIGNAL)
177         {
178             printf("\n*** loadrun: stopped by user.\n");
179         }
180         else if (exitNum == EXIT_NUM_TIME_OUT)
181         {
182             printf("\n*** loadrun: stopped by print timeout.\n");
183         }
184         else if (exitNum == EXIT_NUM_EXEC_TIME_OUT)
185         {
186             printf("\n*** loadrun: stopped by exec timeout.\n");
187         }
188         else if (gStringAborted)
189         {
190             printf("\n*** loadrun: stopped by aborting string.\n");
191         }
192         else if (gExitAborted)
193         {
194             exitNum = gExitStatusNum;
195         }
196     }
197 
198     exit(exitNum);
199 }
200 
201 /*---------------------------------------------------------------------------*
202   Name:         listDevice
203 
204   Description:  Displays a list of devices and terminates
205 
206   Arguments:    None.
207 
208   Returns:      None.
209  *---------------------------------------------------------------------------*/
listDevice(void)210 void listDevice(void)
211 {
212     int     n;
213 
214     //---- Device read
215     gConnectedDeviceNum = ISNTD_GetDeviceList(&gDeviceList[0], DEVICE_MAX_NUM);
216     if (gConnectedDeviceNum < 0)
217     {
218         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "Cannot access devices.");
219     }
220 
221     printf("---- Connected devices:\n");
222 
223     for (n = 0; n < gConnectedDeviceNum; n++)
224     {
225         switch (gDeviceList[n].type)
226         {
227         case ISNTD_DEVICE_CGB_EMULATOR_USB:
228             printf("%3d: [CGBUSB]  IS-CGB-EMU(USB) serial:%8d\n", n, gDeviceList[n].serial);
229             break;
230         case ISNTD_DEVICE_CGB_EMULATOR_SCSI:
231             printf("%3d: [CGBSCSI]  IS-CGB-EMULATOR serial(host-id):%02d%02d\n", n,
232                    gDeviceList[n].host, gDeviceList[n].serial);
233             break;
234         case ISNTD_DEVICE_IS_NITRO_EMULATOR:
235             printf("%3d: [NITROUSB]  IS-NITRO-EMULATOR serial:%08d\n", n, gDeviceList[n].serial);
236             break;
237         case ISNTD_DEVICE_IS_NITRO_UIC:
238             printf("%3d: [NITROUIC]  IS-NITRO-UIC serial: %08d\n", n, gDeviceList[n].serial);
239             break;
240         case ISNTD_DEVICE_UNKNOWN:
241             printf("%3d: unknown device %x\n", n, (int)gDeviceList[n].ntdId);
242             break;
243         default:
244             printf("Illegal device\n");
245             break;
246         }
247     }
248 
249     //---- Search result
250     printf("%d device(s) found.\n", gConnectedDeviceNum);
251 
252     myExit(EXIT_NUM_SHOW_DEVICES);
253 }
254 
255 /*---------------------------------------------------------------------------*
256   Name:         searchDevice
257 
258   Description:  search device
259 
260   Arguments:    None.
261 
262   Returns:      None.
263  *---------------------------------------------------------------------------*/
searchDevice(void)264 void searchDevice(void)
265 {
266     //---- If there is no device
267     if (gConnectedDeviceNum <= 0)
268     {
269         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "found no device.");
270     }
271 
272     //---- If there was some kind of specification
273     if (gDeviceTypeSpecified != ISNTD_DEVICE_NONE || gDeviceSerialSpecified != DEVICE_SERIAL_NONE)
274     {
275         int     n;
276         gCurrentDevice = -1;
277         for (n = 0; n < gConnectedDeviceNum; n++)
278         {
279             //---- Matching with specified device
280             if (gDeviceTypeSpecified != ISNTD_DEVICE_NONE
281                 && gDeviceTypeSpecified != gDeviceList[n].type)
282             {
283                 continue;
284             }
285 
286             //---- Matching with specified serial
287             if (gDeviceSerialSpecified != DEVICE_SERIAL_NONE
288                 && gDeviceSerialSpecified != gDeviceList[n].serial)
289             {
290                 continue;
291             }
292 
293             gCurrentDevice = n;
294             break;
295         }
296     }
297     //---- First one if there is no specification
298     else
299     {
300         gCurrentDevice = 0;
301     }
302 
303     //---- The specified device does not exist or is incorrect
304     if (gCurrentDevice < 0
305         || gDeviceList[gCurrentDevice].type == ISNTD_DEVICE_NONE
306         || gDeviceList[gCurrentDevice].type == ISNTD_DEVICE_UNKNOWN)
307     {
308         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "illegal device.");
309     }
310 }
311 
312 /*---------------------------------------------------------------------------*
313   Name:         displayUsage
314 
315   Description:  Displays the usage
316 
317   Arguments:    None.
318 
319   Returns:      None.
320  *---------------------------------------------------------------------------*/
displayUsage(void)321 void displayUsage(void)
322 {
323     fprintf(stderr,
324             "NITRO-SDK Development Tool - loadrun - Execute NITRO ROM image\n"
325             "Build %lu\n\n"
326             "Usage: loadrun [OPTION] <SrlFile>\n"
327             "\t\tdownload Nitro srl file to debugger and execute.\n\n"
328             "Options:\n"
329             "  --version                   : Show version.\n"
330             "  -h, --help                  : Show this help.\n"
331             "  -q, --quiet                 : Quiet mode.\n"
332             "  -v, --verbose               : Verbose mode.\n"
333             "  -L, --list                  : List connecting device.\n"
334             "  -l, --lap                   : Show lap time at each line.\n"
335 //            "  -d, --type=DEVICE          : Specify device type.\n"
336 //            "                                DEVICE=CGBUSB|CGBSCSI|NITROUSB|NITROUIC.\n"
337             "  -s, --serial=SERIAL         : Specify serial number.\n"
338             "  -t, --timeout=SECOND        : Specify quit time after last print.\n"
339             "  -T, --exec-timeout=SECOND   : Specify quit time after execute program.\n"
340             "  -a, --abort-string=STRING   : Specify aborting string.\n"
341             "  -c, --card-slot=SWITCH      : Card      slot SWITCH=ON|OFF, default OFF.\n"
342             "  -C, --cartridge-slot=SWITCH : Cartridge slot SWITCH=ON|OFF, default OFF.\n"
343             "  --stdin, --standard-input   : Read data from stdin instead of <SrlFile>.\n\n",
344             SDK_DATE_OF_LATEST_FILE);
345 }
346 
347 /*---------------------------------------------------------------------------*
348   Name:         displayVersion
349 
350   Description:  Displays the version
351 
352   Arguments:    None.
353 
354   Returns:      None.
355  *---------------------------------------------------------------------------*/
displayVersion(void)356 void displayVersion(void)
357 {
358     printf("*** loadrun: %s\n", VERSION_STRING);
359 }
360 
361 /*---------------------------------------------------------------------------*
362   Name:         displayErrorAndExit
363 
364   Description:  Displays errors.
365 
366   Arguments:    None.
367 
368   Returns:      None.
369  *---------------------------------------------------------------------------*/
displayErrorAndExit(int exitNum,char * message)370 void displayErrorAndExit(int exitNum, char *message)
371 {
372     printf("*** loadrun: Error: %s\n", message);
373 
374     //---- Deallocate DLL memory
375     ISNTD_FreeDll();
376 
377     exit(exitNum);
378 }
379 
380 /*---------------------------------------------------------------------------*
381   Name:         parseOption
382 
383   Description:  parses the option line
384 
385   Arguments:    argc : argument count
386                 argv: argument vector
387 
388   Returns:      result. less than 0 if error.
389  *---------------------------------------------------------------------------*/
parseOption(int argc,char * argv[])390 void parseOption(int argc, char *argv[])
391 {
392     int     n;
393     int     c;
394     BOOL    helpFlag = FALSE;
395 
396     struct option optionInfo[] = {
397         {"help", no_argument, NULL, 'h'},
398         {"quiet", no_argument, NULL, 'q'},
399         {"verbose", no_argument, NULL, 'v'},
400         {"list", no_argument, NULL, 'L'},
401         {"lap", no_argument, NULL, 'l'},
402         {"debug", no_argument, NULL, 'D'},      //Hidden options
403         {"version", no_argument, NULL, '1'},
404         {"stdin", no_argument, NULL, 'I'},
405         {"standard-input", no_argument, NULL, 'I'},
406         {"type", required_argument, 0, 'd'},    //Hidden options
407         {"serial", required_argument, 0, 's'},
408         {"timeout", required_argument, 0, 't'},
409         {"exec-timeout", required_argument, 0, 'T'},
410         {"abort-string", required_argument, 0, 'a'},
411         {"card-slot", required_argument, 0, 'c'},
412         {"cartridge-slot", required_argument, 0, 'C'},
413         {NULL, 0, 0, 0}
414     };
415     int     optionIndex;
416 
417     char   *optionStr = NULL;
418 
419     //---- suppress error string of getopt_long()
420     opterr = 0;
421 
422     while (1)
423     {
424         c = getopt_long(argc, argv, "+hqvlLDd:s:t:T:a:c:C:", &optionInfo[0], &optionIndex);
425 
426         //printf("optind=%d optopt=%d  %x(%c) \n", optind, optopt, c,c );
427 
428         if (c == -1)
429         {
430             break;
431         }
432 
433         switch (c)
434         {
435         case 'I':                     //---- Standard input
436             gStdinMode = TRUE;
437             break;
438         case 'h':                     //---- Help display
439             helpFlag = TRUE;
440             break;
441         case 'q':                     //---- Quiet mode
442             gQuietMode = TRUE;
443             break;
444         case 'v':                     //---- Verbose mode
445             gVerboseMode = TRUE;
446             break;
447         case 'D':                     //---- Debug mode
448             gDebugMode = TRUE;
449             break;
450         case '1':                     //---- Version display
451             displayVersion();
452             myExit(EXIT_NUM_SHOW_VERSION);
453             break;
454         case 'L':                     //---- Device list
455             listDevice();
456             break;
457         case 'l':                     //---- Lap time
458             gShowLapTime = TRUE;
459             break;
460         case 'd':                     //---- Device
461             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
462             {
463                 int     n;
464                 for (n = 0; gDeviceName[n]; n++)
465                 {
466                     if (!strcmp(optionStr, gDeviceName[n]))
467                     {
468                         gDeviceTypeSpecified = gDeviceTypeArray[n];
469                         break;
470                     }
471                 }
472 
473                 if (gDeviceTypeSpecified == ISNTD_DEVICE_NONE)
474                 {
475                     displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION, "illegal device type.");
476                 }
477             }
478             break;
479         case 's':                     //---- Serial specification
480             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
481             gDeviceSerialSpecified = atoi(optionStr);
482             break;
483         case 'c':                     //---- Card slot lock
484             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
485             if (!strcmp(optionStr, "ON") || !strcmp(optionStr, "on"))
486             {
487                 gIsCardLocked = TRUE;
488             }
489             else if (!strcmp(optionStr, "OFF") || !strcmp(optionStr, "off"))
490             {
491                 gIsCardLocked = FALSE;
492             }
493             else
494             {
495                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION, "illegal value for card slot option.");
496             }
497             break;
498         case 'C':                     //---- Cartridge slot lock
499             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
500             if (!strcmp(optionStr, "ON") || !strcmp(optionStr, "on"))
501             {
502                 gIsCartridgeLocked = TRUE;
503             }
504             else if (!strcmp(optionStr, "OFF") || !strcmp(optionStr, "off"))
505             {
506                 gIsCartridgeLocked = FALSE;
507             }
508             else
509             {
510                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
511                                     "illegal value for cartridge slot option.");
512             }
513             break;
514         case 't':                     //---- Timeout interval beginning from final display
515             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
516             gTimeOutTime = atoi(optionStr);
517             if (gTimeOutTime <= 0)
518             {
519                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
520                                     "illegal value for abort timeout option.");
521             }
522             break;
523         case 'T':                     //---- Execution timeout interval
524             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
525             gExecTimeOutTime = atoi(optionStr);
526             if (gExecTimeOutTime <= 0)
527             {
528                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
529                                     "illegal value for abort exec timeout option.");
530             }
531             break;
532         case 'a':                     //---- Abort string
533             gAbortString = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
534             {
535                 int     length = strlen(gAbortString);
536                 if (length <= 0 || length > 256)
537                 {
538                     displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
539                                         "illegal value for abort string option.");
540                 }
541             }
542             break;
543         default:
544             displayErrorAndExit(EXIT_NUM_UNKNOWN_OPTION, "unknown option.");
545         }
546     }
547 
548     //---- Help display
549     {
550         BOOL    isDisplayHelp = FALSE;
551 
552         if (helpFlag)
553         {
554             isDisplayHelp = TRUE;
555         }
556         else if (argc <= optind && !gStdinMode)
557         {
558             isDisplayHelp = TRUE;
559         }
560         else if (argc > optind && gStdinMode)
561         {
562             isDisplayHelp = TRUE;
563         }
564 
565         if (isDisplayHelp)
566         {
567             displayUsage();
568             exit(EXIT_NUM_SHOW_USAGE);
569         }
570     }
571 
572     //---- Input file name
573     if (!gStdinMode)
574     {
575         strncpy(gInputFileNameString, argv[optind], FILE_NAME_MAX_SIZE);
576     }
577 
578     if (gVerboseMode)
579     {
580         if (!gStdinMode)
581         {
582             printf("Input file is [%s]\n", gInputFileNameString);
583         }
584         else
585         {
586             printf("Input file is stdin\n");
587         }
588     }
589 
590     //---- Information display
591     if (gVerboseMode)
592     {
593         printf("Print time out : %d sec.\n", gTimeOutTime);
594         printf("Execute time out : %d sec.\n", gExecTimeOutTime);
595         printf("Card lock : %s.\n", (gIsCardLocked) ? "ON" : "OFF");
596         printf("Cartridge lock : %s.\n", (gIsCartridgeLocked) ? "ON" : "OFF");
597 
598         if (gAbortString)
599         {
600             printf("Abort string : [%s]\n", gAbortString);
601         }
602     }
603 }
604 
605 /*---------------------------------------------------------------------------*
606   Name:         loadFile
607 
608   Description:  loads file
609 
610   Arguments:    None.
611 
612   Returns:      None.
613  *---------------------------------------------------------------------------*/
loadFile(void)614 void loadFile(void)
615 {
616     unsigned int address = 0;
617     //int fileSize;
618 
619     //---- File open
620     if (gStdinMode)
621     {
622         gInputFile = stdin;
623         _setmode(_fileno(gInputFile), O_BINARY);
624     }
625     else
626     {
627         if ((gInputFile = fopen(gInputFileNameString, "rb")) == NULL)
628         {
629             displayErrorAndExit(EXIT_NUM_NO_INPUT_FILE, "cannot open input file.");
630         }
631     }
632     gIsInputFileOpened = TRUE;
633 
634     //---- Connected to device
635     if ((gDeviceHandle = ISNTD_DeviceOpen(gDeviceList[gCurrentDevice].ntdId)) == NULL)
636     {
637         displayErrorAndExit(EXIT_NUM_NOT_CONNECT, "cannot connect device.");
638     }
639     gDeviceConnected = TRUE;
640 
641     //---- Issue reset
642     ISNTD_Reset(gDeviceHandle, TRUE);
643     Sleep(1000);
644 
645     //---- Get file size
646     //fseek( gInputFile, 0L, SEEK_END );
647     //fileSize = ftell( gInputFile );
648     //fseek( gInputFile, 0L, SEEK_SET );
649 
650     //---- Transfer every 16KB
651     while (1)
652     {
653         char    buf[16384];
654         size_t  size = fread(buf, 1, sizeof(buf), gInputFile);
655         static int progressCount = 0;
656 
657         if (!size)
658         {
659             break;
660         }
661 
662         //---- Transfer
663         if (!ISNTD_WriteROM(gDeviceHandle, buf, address, size))
664         {
665             displayErrorAndExit(EXIT_NUM_LOADING_ERROR, "troubled while loading input file.");
666         }
667 
668         address += size;
669 
670         if (gVerboseMode)
671         {
672             if (!(progressCount++ % 32))
673             {
674                 printf("*");
675             }
676         }
677     }
678 
679     //---- File close
680     if (gStdinMode)
681     {
682         _setmode(_fileno(gInputFile), O_TEXT);
683     }
684     else
685     {
686         fclose(gInputFile);
687     }
688     gIsInputFileOpened = FALSE;
689 
690     if (gVerboseMode)
691     {
692         printf("\nInput file size: %d (0x%x) byte\n", address, address);
693     }
694 }
695 
696 /*---------------------------------------------------------------------------*
697   Name:         setSlopPower
698 
699   Description:  Slot power process
700 
701   Arguments:    None.
702 
703   Returns:      None.
704  *---------------------------------------------------------------------------*/
setSlotPower(void)705 void setSlotPower(void)
706 {
707     //---- Should the cartridge slot be locked?
708     if (gIsCartridgeLocked)
709     {
710         if (!ISNTD_CartridgeSlotPower(gDeviceHandle, TRUE))
711         {
712             displayErrorAndExit(EXIT_NUM_CANNOT_USE_CARTRIDGE, "cannot use cartridge slot.");
713         }
714     }
715 
716     //---- Should the card slot be locked?
717     if (gIsCardLocked)
718     {
719         if (!ISNTD_CardSlotPower(gDeviceHandle, TRUE))
720         {
721             displayErrorAndExit(EXIT_NUM_CANNOT_USE_CARD, "cannot use card slot.");
722         }
723     }
724 
725     //---- Cancel reset
726     Sleep(1000);
727     ISNTD_Reset(gDeviceHandle, FALSE);
728 }
729 
730 /*---------------------------------------------------------------------------*
731   Name:         procPrint
732 
733   Description:  printf process
734 
735   Arguments:    None.
736 
737   Returns:      None.
738  *---------------------------------------------------------------------------*/
739 NITROArch archNum[] = {
740     NITROArchARM9,
741     NITROArchARM7
742 };
743 
744 #define PRINT_ONETIME_SIZE  512
745 //#define PRINT_ONETIME_SIZE    16
746 
747 //---- Buffer for joint display
748 static char gConbineBuf[PRINT_ONETIME_SIZE * 2 + 2] = "\0";
749 static char *gConbineBufPtr = &gConbineBuf[0];
750 
751 //---- Buffer for joining and comparing character strings
752 static char gLineBuf[PRINT_ONETIME_SIZE + 1];
753 
754 
procPrintf(void)755 void procPrintf(void)
756 {
757     int     blankTime = 0;
758 
759     //---- Size of exit string
760     gExitStrLength = strlen(OS_EXIT_STRING_1);
761 
762     while (1)
763     {
764         BOOL    isOutputString = FALSE;
765 
766         //---- When stopped by the user
767         if (gStoppedByUser)
768         {
769             myExit(EXIT_NUM_USER_SIGNAL);
770         }
771 
772         //printf("[######]\n" );
773         {
774             int     n;
775             int     dataSize;
776             char    tmpBuf[PRINT_ONETIME_SIZE + 1];
777 
778             for (n = 0; n < 2; n++)
779             {
780                 //---- Get display data
781                 if (!ISNTD_GetDebugPrint
782                     (gDeviceHandle, archNum[n], tmpBuf, &dataSize, PRINT_ONETIME_SIZE))
783                 {
784                     ISNTD_DeviceClose(gDeviceHandle);
785                     displayErrorAndExit(EXIT_NUM_PRINTF_ERROR,
786                                         "troubled while receiving print data.");
787                 }
788                 tmpBuf[dataSize] = '\0';
789 
790                 //---- If there is data to be displayed, display it
791                 if (dataSize)
792                 {
793                     //---- Record that data was displayed
794                     isOutputString = TRUE;
795 
796                     //---- Output
797                     if (!outputString(tmpBuf, dataSize))
798                     {
799                         break;
800                     }
801                 }
802             }
803         }
804 
805         //---- Exit?
806         if (gStringAborted || gExitAborted)
807         {
808             break;
809         }
810 
811         //---- If text is not being displayed
812         if (!isOutputString)
813         {
814             Sleep(100);
815             blankTime += 100;
816 
817             //---- Timeout decision
818             if (gTimeOutTime && blankTime > gTimeOutTime * 1000)
819             {
820                 gTimeOutOccured = TRUE;
821                 break;
822             }
823         }
824         //---- If text has been displayed
825         else
826         {
827             blankTime = 0;
828         }
829 
830         //---- Timeout check
831         if (gExecTimeOutTime > 0)
832         {
833             time_t  currentTime;
834             (void)time(&currentTime);
835 
836             if (currentTime - gStartTime >= gExecTimeOutTime)
837             {
838                 gExecTimeOutOccured = TRUE;
839                 break;
840             }
841         }
842     }
843 }
844 
845 
846 /*---------------------------------------------------------------------------*
847   Name:         showLapTime
848 
849   Description:  displays lap time at line head
850 
851   Arguments:    None.
852 
853   Returns:      None.
854  *---------------------------------------------------------------------------*/
showLapTime(void)855 void showLapTime(void)
856 {
857     int     lap;
858     time_t  currentTime;
859 
860     (void)time(&currentTime);
861     lap = currentTime - gStartTime;
862 
863     printf("{%d:%02d}", lap / 60, lap % 60);
864 }
865 
866 /*---------------------------------------------------------------------------*
867   Name:         outputString
868 
869   Description:  outputs string to stdout
870 
871   Arguments:    buf: buffer
872                 bufSize: data size in buffer
873 
874   Returns:      FALSE if to do quit.
875  *---------------------------------------------------------------------------*/
outputString(char * buf,int bufSize)876 BOOL outputString(char *buf, int bufSize)
877 {
878     char   *bufEnd = buf + bufSize;
879     char   *p = buf;
880 
881     int     abortStrLength = gAbortString ? strlen(gAbortString) : 0;
882 
883     while (p < bufEnd)
884     {
885         char   *crPtr = strchr(p, '\n');
886 
887         //---- \n missing
888         if (!crPtr)
889         {
890             //---- Save for comparison
891             strcat(gConbineBufPtr, p);
892             gConbineBufPtr += strlen(p);
893 
894             //---- Time display
895             if (!gQuietMode && gIsLineHead && gShowLapTime)
896             {
897                 showLapTime();
898             }
899             gIsLineHead = FALSE;
900 
901             //---- Display
902             printfIfNotQuiet(p);
903 
904             //---- Destroy if buffer overflows (the responsibility is on the output side to insert \n)
905             if (gConbineBufPtr - &gConbineBuf[0] > PRINT_ONETIME_SIZE)
906             {
907                 gConbineBufPtr = &gConbineBuf[0];
908                 *gConbineBufPtr = '\0';
909             }
910 
911             break;
912         }
913 
914         //---- copy up to \n
915         {
916             int     n = crPtr - p + 1;
917 
918             //---- Combine for comparison
919             strncpy(gConbineBufPtr, p, n);
920             gConbineBufPtr[n] = '\0';
921 
922             //---- For display
923             strncpy(&gLineBuf[0], p, n);
924             gLineBuf[n] = '\0';
925         }
926 
927         //---- Time display
928         if (!gQuietMode && gIsLineHead && gShowLapTime)
929         {
930             showLapTime();
931         }
932         gIsLineHead = TRUE;
933 
934         //---- Line display
935         printfIfNotQuiet(gLineBuf);
936 
937         //---- Compare with abort string
938         if (gAbortString && !strncmp(gConbineBuf, gAbortString, abortStrLength))
939         {
940             gStringAborted = TRUE;
941             return FALSE;
942         }
943 
944         //---- Exit using OS_Exit
945         if (!strncmp(gConbineBuf, OS_EXIT_STRING_1, gExitStrLength))
946         {
947             gExitAborted = TRUE;
948             gExitStatusNum = atoi(gConbineBuf + gExitStrLength);
949             return FALSE;
950         }
951 
952         gConbineBufPtr = &gConbineBuf[0];
953         *gConbineBufPtr = '\0';
954 
955         p = crPtr + 1;
956     }
957 
958     return TRUE;
959 }
960 
961 /*---------------------------------------------------------------------------*
962   Name:         signalHandler
963 
964   Description:  signal handler
965 
966   Arguments:    sig
967                 argv: argument vector
968 
969   Returns:      ---
970  *---------------------------------------------------------------------------*/
signalHandler(int sig)971 void signalHandler(int sig)
972 {
973     gStoppedByUser = TRUE;
974 }
975 
976 /*---------------------------------------------------------------------------*
977   Name:         Main
978 
979   Description:  main proc
980 
981   Arguments:    argc : argument count
982                 argv: argument vector
983 
984   Returns:      ---
985  *---------------------------------------------------------------------------*/
main(int argc,char * argv[])986 int main(int argc, char *argv[])
987 {
988     //---- Initialize DLL
989     ISNTD_InitDll();
990 
991     //---- Disable buffering of standard output
992     setvbuf(stdout, NULL, _IONBF, 0);
993 
994     //---- Option parsing
995     parseOption(argc, argv);
996 
997     //---- Device read
998     gConnectedDeviceNum = ISNTD_GetDeviceList(&gDeviceList[0], DEVICE_MAX_NUM);
999     if (gConnectedDeviceNum < 0)
1000     {
1001         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "Cannot access devices.");
1002     }
1003 
1004     //---- Search for device
1005     searchDevice();
1006 
1007     //---- Read
1008     loadFile();
1009 
1010     //---- Signal setting
1011     (void)signal(SIGINT, signalHandler);
1012 
1013     //---- Slot
1014     setSlotPower();
1015 
1016     //---- Get start time
1017     (void)time(&gStartTime);
1018 
1019     //---- printf process
1020     procPrintf();
1021 
1022     //---- End
1023     if (gExitAborted)                  //---- Exit from OS_Exit()
1024     {
1025         myExit(gExitStatusNum);
1026     }
1027     else if (gStringAborted)           //---- Abort string
1028     {
1029         myExit(EXIT_NUM_STRING_ABORT);
1030     }
1031     else if (gTimeOutOccured)          //---- Timeout
1032     {
1033         myExit(EXIT_NUM_TIME_OUT);
1034     }
1035     else if (gExecTimeOutOccured)
1036     {
1037         myExit(EXIT_NUM_EXEC_TIME_OUT);
1038     }
1039     else                               //---- Normal end
1040     {
1041         myExit(EXIT_NUM_NO_ERROR);
1042     }
1043     //---- never reached here
1044 
1045     //---- dummy to avoid warning
1046     return 0;
1047 }
1048