1 /*-------------------------------------------------------------------------
2 tinitalk.c - A tini utility to download files to TINI and talk to it
4 Written By - Johan Knol johan.knol@iduna.nl
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
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.
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 In other words, you are welcome to use, share and improve this program.
21 You are forbidden to forbid anyone else to use, share and improve
22 what you give them. Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
25 #if defined(_MSC_VER) || defined(__BORLANDC__)
26 #define TINI_PORT "COM2"
30 #define TINI_PORT "/dev/ttyS0"
33 #define TINI_PORT "/dev/term/a"
36 #define TINI_BAUD 115200
37 #define TINI_ESCAPE_CHAR 0x1b
45 #if !defined( _MSC_VER) && !defined(__BORLANDC__)
48 #include <sys/ioctl.h>
52 #define sleep(ms) Sleep((ms*1000))
53 #define usleep(us) Sleep((us/1000))
61 int baud = 0, appBaud = 0;
66 fprintf (stderr, "usage: %s <options> command [args] \n", programName);
67 fprintf (stderr, "\nwhere options are:\n");
68 fprintf (stderr, " <-p port> set the serial port, defaults to %s\n", TINI_PORT);
69 fprintf (stderr, " <-b baud> set the baud rate, defaults to %d\n", TINI_BAUD);
70 fprintf (stderr, " <-B baud> set the baud rate for the application\n");
71 fprintf (stderr, " <-c> connect to tini after command (if any)\n");
72 fprintf (stderr, " <-e #> to set the escape char\n");
73 fprintf (stderr, " <-s> to see some examples.\n");
74 fprintf (stderr, "\nand commands are:\n");
75 fprintf (stderr, " <load file> load a hex file and restart the bootloader\n");
76 fprintf (stderr, " <execute [file]> load a hex file and/or start the program in bank 1\n");
84 printf ("%s -p /dev/ttyS1\n", programName);
85 printf (" now you are talking to the bootloader through serial-1\n");
86 printf ("%s -b 19200\n", programName);
87 printf (" now you are talking to the bootloader at 19200 baud\n");
88 printf ("%s load tini.hex\n", programName);
89 printf (" load tini.hex\n");
90 printf ("%s -c load tini.hex\n", programName);
91 printf (" after loading tini.hex you are talking to the bootloader\n");
92 printf ("%s execute tini.hex\n", programName);
93 printf (" load tini.hex and start the program in bank 1\n");
94 printf ("%s -c execute tini.hex\n", programName);
95 printf (" after loading the file you are talking to the (restarted)\n");
96 printf (" program in bank 1\n");
97 printf ("%s execute\n", programName);
98 printf (" now the program in bank 1 is restarted.\n");
99 printf ("%s -c execute\n", programName);
100 printf (" now you are talking to the (restarted) program in bank 1\n");
101 printf ("%s -b 115200 -B 9600 -c execute tini.hex\n", programName);
102 printf (" download tini.hex at 115200 baud, but talk the program at 9600 baud\n");
107 main (int argc, char **argv)
114 //programName=argv[0];
115 programName = "tinitalk";
118 while (arg < argc && argv[arg][0] == '-')
121 // no arguments required
122 if (argv[arg][1] == 'c')
128 else if (argv[arg][1] == 's')
134 if (arg >= (argc - 1))
138 switch (argv[arg][1])
141 port = argv[arg + 1];
144 baud = atoi (argv[arg + 1]);
147 appBaud = atoi (argv[arg + 1]);
150 escapeChar = atoi (argv[arg + 1]);
160 if ((port = getenv ("TINI_PORT")) == NULL)
167 if (getenv ("TINI_BAUD"))
169 baud = atoi (getenv ("TINI_BAUD"));
178 if (getenv ("TINI_ESCAPE_CHAR"))
180 escapeChar = atoi (getenv ("TINI_ESCAPE_CHAR"));
184 escapeChar = TINI_ESCAPE_CHAR;
191 if (!TiniOpen (port, baud))
198 if (strcmp (argv[arg], "load") == 0)
201 if (arg >= (argc - 1))
205 if (LoadHexFile (argv[arg + 1]))
215 if (strcmp (argv[arg], "execute") == 0)
217 // argument supplied?
218 if (arg < (argc - 1))
220 if (!LoadHexFile (argv[arg + 1]))
228 TiniConnect (appBaud);
232 // unsupported command
236 // no commands, just connect
238 // on my linux box, DTR is always set after opening the port, so:
239 // reset the bootloader
241 strcpy (command, "r");
245 switch (tolower (command[0]))
251 printf ("r - reset, start bootloader and connect to TINI\n");
252 printf ("e - reset, start program in bank 1 and connect to TINI\n");
253 printf ("c - connect to TINI.\n");
254 printf ("l - load file.\n");
255 printf ("s - save file.\n");
256 printf ("q - quit.\n");
260 TiniConnect (appBaud);
267 // leave it as it was
272 char fileName[FILENAME_MAX] = "";
273 printf ("Enter filename: ");
275 fgets (fileName, FILENAME_MAX, stdin);
276 // remove the EOL character
277 fileName[strlen (fileName) - 1] = 0;
278 LoadHexFile (fileName);
282 printf ("Command \"%c\" not implemented yet.\n", command[0]);
288 printf ("Unknown command: \"%c\".\n", command[0]);
291 printf ("\n<%s> ", programName);
293 #if defined(_MSC_VER) || defined(__BORLANDC__)
297 fgets (command, 64, stdin);
303 LoadHexFile (char *path)
310 char c, ctrlC = 0x03;
311 int bytesLoaded = 0, progress = 0;
312 char banksZapped[8] =
313 {0, 0, 0, 0, 0, 0, 0, 0};
314 unsigned int address, bytes, i;
315 unsigned int checksum, chk;
317 if ((hexFile = fopen (path, "r")) == NULL)
324 while (fgets (hexLine, 256, hexFile))
327 if (TiniRead (&c, 1) == 1)
329 // show error messages from TINI
335 while (TiniRead (&c, 1) == 1);
337 printf ("\nInterrupted by loader.\n");
342 if (hexLine[0] != ':' ||
343 sscanf (&hexLine[1], "%02x", &bytes) != 1 ||
344 sscanf (&hexLine[3], "%04x", &address) != 1 ||
345 sscanf (&hexLine[7], "%02x", &type) != 1)
347 printf ("Invalid ihx record: \"%s\"\n", hexLine);
351 // make sure line ends with '\r' or TINI won't swallow it
352 hexLine[strlen (hexLine) - 1] = '\r';
354 address += bank << 16;
358 for (i = 0; i < bytes + 5; i++)
360 sscanf (&hexLine[i * 2 + 1], "%02x", &chk);
365 printf ("\nChecksum error at %06x (0x%02x!=0) in line: %d\n",
366 address, checksum&0xff, line);
373 sscanf (&hexLine[9], "%04x", &bank);
374 address = (address & 0xffff) + (bank << 16);
378 printf ("==> No overwrite of bank 0 <==\n");
384 TiniWriteAndWait (&ctrlC, 1, '>');
391 if (!banksZapped[bank])
394 sprintf (tempString, "z%d\r", bank);
395 TiniWriteAndWait (tempString, 3, '?');
396 TiniWriteAndWait ("y", 1, '\n');
397 printf ("[Zapping bank %d]\n", bank);
399 banksZapped[bank] = 1;
401 //printf ("[Starting loader]\n");
403 TiniWriteAndWait ("l\r", 2, '\n');
404 printf ("[Loading bank %d]\n", bank);
408 if ((type == 0) && (1 || ((bytesLoaded / 1024) > progress)))
410 progress = bytesLoaded / 1024;
411 printf ("[%06x: sent %d bytes]\r", address, bytesLoaded);
414 bytesLoaded += bytes;
416 //printf ("data: %s\n", hexLine);
418 TiniWrite (hexLine, strlen (hexLine));
423 //printf ("skip: %s\n", hexLine);
426 TiniWriteAndWait ("\r", 1, '>');
427 printf ("\n[Load succesfull]\n");
433 SaveFile (char *path)
435 printf ("Saving file: %s\n", path);
443 #if defined(_MSC_VER) || defined(__BORLANDC__)
448 static int tini_status;
449 static struct termios tini_options;
452 static int initflag = 0;
455 TiniOpen (char *port, int baud)
462 printf ("[Opening \"%s\" at \"%d\" baud, escape is 0x%02x]\n",
463 port, baud, escapeChar);
465 #if defined(_MSC_VER) || defined(__BORLANDC__)
466 if ((tiniHandle = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
467 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) ==
468 INVALID_HANDLE_VALUE)
470 if ((tini_fd = open (port, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
473 fprintf (stderr, "%s: unable to open port %s - ",
478 // configure the serial port
479 #if defined(_MSC_VER) || defined(__BORLANDC__)
480 tiniDcb.DCBlength = sizeof (DCB);
481 if (GetCommState (tiniHandle, &tiniDcb) != TRUE)
483 fprintf (stderr, "%s: unable to query port %s\n",
488 tiniDcb.StopBits = 0;
489 tiniDcb.ByteSize = 8;
491 tiniDcb.fDtrControl = DTR_CONTROL_DISABLE;
492 tiniDcb.fRtsControl = RTS_CONTROL_DISABLE;
493 tiniDcb.fOutxCtsFlow = FALSE;
494 tiniDcb.fOutX = FALSE;
495 tiniDcb.fInX = FALSE;
496 if (SetCommState (tiniHandle, &tiniDcb) != TRUE)
498 fprintf (stderr, "%s: unable to configure port %s\n",
504 EscapeCommFunction (tiniHandle, CLRDTR);
506 if (ioctl (tini_fd, TIOCMGET, &tini_status))
508 perror ("0: ioctl(tini_fd, TIOCMGET, &tini_status) - ");
513 tini_status &= ~TIOCM_DTR;
514 if (ioctl (tini_fd, TIOCMSET, &tini_status))
516 perror ("2: ioctl(tini_fd, TIOCMSET, &tini_status) - ");
520 tcgetattr (tini_fd, &tini_options);
521 tini_options.c_cflag |= (CLOCAL | CREAD);
522 tini_options.c_lflag &= ~(ISIG | ICANON | ECHO);
523 tini_options.c_iflag |= (IGNCR);
524 tini_options.c_cc[VMIN] = 0;
525 tini_options.c_cc[VTIME] = 0;
526 tcsetattr (tini_fd, TCSANOW, &tini_options);
529 if (!TiniBaudRate (baud))
538 #if defined(_MSC_VER) || defined(__BORLANDC__)
539 #define B9600 CBR_9600
540 #define B19200 CBR_19200
541 #define B38400 CBR_38400
542 #define B57600 CBR_57600
543 #define B115200 CBR_115200
547 TiniBaudRate (int baud)
569 fprintf (stderr, "%s: illegal baudrate: \"%d\"\n", programName, baud);
573 #if defined(_MSC_VER) || defined(__BORLANDC__)
574 tiniDcb.BaudRate = baudB;
575 SetCommState (tiniHandle, &tiniDcb);
577 cfsetispeed (&tini_options, baudB);
578 cfsetospeed (&tini_options, baudB);
579 tcsetattr (tini_fd, TCSANOW, &tini_options);
586 TiniReset (int toBootLoader)
590 #if defined(_MSC_VER) || defined(__BORLANDC__)
591 EscapeCommFunction (tiniHandle, SETDTR);
593 tini_status |= TIOCM_DTR;
594 if (ioctl (tini_fd, TIOCMSET, &tini_status))
596 perror ("1: ioctl(tini_fd, TIOCMSET, &tini_status) - ");
604 // drain input and output buffers
608 #if defined(_MSC_VER) || defined(__BORLANDC__)
609 EscapeCommFunction (tiniHandle, CLRDTR);
611 tini_status &= ~TIOCM_DTR;
612 if (ioctl (tini_fd, TIOCMSET, &tini_status))
614 perror ("2: ioctl(tini_fd, TIOCMSET, &tini_status) - ");
622 if (TiniWrite ("\r", 1) != 1)
624 fprintf (stderr, "TiniReset: couldn't write to tini\n");
627 // wait for the bootloader prompt
628 // we should build a timeout here
635 TiniWriteAndWait ("E\r", 2, 'E');
639 #if defined(_MSC_VER) || defined(__BORLANDC__)
640 // read as much character as available, at most n
642 TiniRead (char *buffer, int n)
648 ClearCommError (tiniHandle, &status, &tiniComStat);
649 if (tiniComStat.cbInQue < (unsigned int) n)
651 n = tiniComStat.cbInQue;
653 ReadFile (tiniHandle, buffer, n, &count, NULL);
659 TiniWrite (char *buffer, int n)
662 WriteFile (tiniHandle, buffer, n, &count, NULL);
667 TiniRead (char *buffer, int n)
669 return read (tini_fd, buffer, n);
673 TiniWrite (char *buffer, int n)
675 return write (tini_fd, buffer, n);
679 // wait for the prompChar
681 TiniWait (char promptChar)
686 switch (TiniRead (&c, 1))
688 case 0: // no char available
689 // give up our time slice
693 case 1: // one char read
702 default: // some error
704 perror ("TiniWait: ");
711 // send the buffer and wait for the promptChar
713 TiniWriteAndWait (char *buffer, int n, char promptChar)
715 char bytes = TiniWrite (buffer, n);
716 TiniWait (promptChar);
720 // flush input and output buffers (wait for it)
724 #if defined(_MSC_VER) || defined(__BORLANDC__)
725 FlushFileBuffers (tiniHandle);
727 // flush the buffers, isn't there a simpler way?
728 tcsetattr (tini_fd, TCSAFLUSH, &tini_options);
732 // drain input and output buffers (forget it)
736 #if defined(_MSC_VER) || defined(__BORLANDC__)
737 PurgeComm (tiniHandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
739 // drain the buffers, isn't there a simpler way?
740 tcsetattr (tini_fd, TCSADRAIN, &tini_options);
744 #if defined(_MSC_VER) || defined(__BORLANDC__)
746 TiniConnect (int baud)
757 if (TiniRead (&c, 1))
759 // char from TINI, high priority
765 // char from console, low priotity
766 if ((c = getch ()) == escapeChar)
768 // escape from connect?
776 // nothing to do, so give up our timeslice
783 TiniConnect (int baud)
785 struct termios options, consoleOptions;
795 // set stdin to nonblocking IO, noecho
796 fno = fileno (stdin);
797 consoleFlags = fcntl (fno, F_GETFL);
798 fcntl (fno, F_SETFL, consoleFlags | O_NONBLOCK);
800 tcgetattr (fno, &consoleOptions);
801 options = consoleOptions;
802 options.c_lflag &= ~(ISIG | ICANON | ECHO);
803 tcsetattr (fno, TCSANOW, &options);
807 if (TiniRead (&c, 1) == 1)
809 // char from TINI, high priority
812 else if ((c = getchar ()) != EOF)
814 // char from console, low priority
817 // escape from connect?
828 // nothing to do, so give up our timeslice
834 fcntl (fno, F_SETFL, consoleFlags);
835 tcsetattr (fno, TCSANOW, &consoleOptions);
843 #if defined(_MSC_VER) || defined(__BORLANDC__)
844 CloseHandle (tiniHandle);