/****************************************************/ /* TransHex (Windows/Linux) */ /* Version 1.3 */ /****************************************************/ /* Author: Michael Kapp */ /* History: 02.07.2001 Linux version */ /* 12.10.2001 Windows version added */ /* 04.06.2003 Upload for Windows added */ /****************************************************/ #ifdef _WIN32 #include #include #include #include #include #define SYSTEM_NAME "Windows" #define DEFAULT_DEVICE "COM1" #define RTS 1 #define DTR 2 static void configure_terminal(void) {} #else #include #include #include #include #include #include #include #include #define SYSTEM_NAME "Linux" #define DEFAULT_DEVICE "/dev/ttyS0" #define RTS TIOCM_RTS #define DTR TIOCM_DTR #define HANDLE int static struct termios termios1; static char ch1 = 0; /* Restore terminal configuration. Called from exit() * automatically. */ static void restore_terminal(void) { tcsetattr(fileno(stdin), TCSANOW, &termios1); } /* Configure terminal for non-blocking input. */ static void configure_terminal(void) { struct termios termios2; tcgetattr(fileno(stdin), &termios1); memcpy(&termios2, &termios1, sizeof(struct termios)); termios2.c_lflag &= ~(ICANON | ECHO); termios2.c_cc[VMIN] = 0; termios2.c_cc[VTIME] = 0; tcsetattr(fileno(stdin), TCSANOW, &termios2); atexit(restore_terminal); } /* Poll keyboard. Return non-zero if a key has been pressed, or zero * otherwise. */ static int kbhit(void) { return read(fileno(stdin), &ch1, sizeof(char)); } /* Read keyboard. Return ASCII character for key that was * pressed. */ static int getch(void) { int ch2; /* If necessary, wait for a key to be pressed. */ if(ch1 == 0) while(!kbhit()) {} /* Return the most recent key read by kbhit(). */ ch2 = ch1; ch1 = 0; return ch2; } #endif /* Verzoegerung (< 1000 ms!) */ void Delay(int ms) { #ifdef _WIN32 Sleep(ms); #else usleep(ms*1000); #endif } /* Serielle Schnittstelle oeffnen */ HANDLE OpenSerial(const char *device) { HANDLE h; int error = 0; #ifdef _WIN32 h = CreateFile(device, // pointer to name of the file GENERIC_READ|GENERIC_WRITE, // access mode 0, // comm devices must be opened w/exclusive-access NULL, // no security attributs OPEN_EXISTING, // comm devices must use OPEN_EXISTING 0, // flags NULL); // hTemplate must be NULL for comm devices if (h==INVALID_HANDLE_VALUE) error = 1; #else h = open(device, O_RDWR | O_NOCTTY); if (h<0) error = 1; #endif if (error) { fprintf(stderr, "Could not open device %s\n", device); exit(1); } return h; } /* Serielle Schnittstelle schliessen */ void CloseSerial(HANDLE h) { #ifdef _WIN32 CloseHandle(h); #else close(h); #endif } /* Serielle Schnittstelle konfigurieren */ void SetSerial(HANDLE h, long baud, int handshake) { int error = 0; #ifdef _WIN32 DCB dcb; if (baud!=2400 && baud!=9600 && baud!=19200 && baud!=38400 && baud!=57600 && baud!=115200) { fprintf(stderr, "Illegal baud rate (%ld)\n", baud); exit(1); } GetCommState(h, &dcb); dcb.BaudRate = baud; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fOutxCtsFlow = handshake? TRUE : FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_ENABLE; // IRmate benötigt ENABLE dcb.fDsrSensitivity = FALSE; dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.fNull = FALSE; dcb.fRtsControl = RTS_CONTROL_ENABLE; // IRmate benötigt ENABLE dcb.fAbortOnError = FALSE; //dc.b.EofChar = ?? if (!SetCommState(h, &dcb)) error = 1; #else int baudcode; struct termios tio; /* aktuelle Einstellungen lesen */ tcgetattr(h, &tio); switch (baud) { case 2400: baudcode = B2400; break; case 9600: baudcode = B9600; break; case 19200: baudcode = B19200; break; case 38400: baudcode = B38400; break; case 57600: baudcode = B57600; break; case 115200: baudcode = B115200; break; default: fprintf(stderr, "Illegal baud rate (%ld)\n", baud); exit(1); } /* Baudrate, 8N1, Steuerleitungen ignorieren, Empfang ermoeglichen, Flusskontrolle */ tio.c_cflag = baudcode | CS8 | CLOCAL | CREAD; if (handshake) tio.c_cflag |= CRTSCTS; /* Frame/Parity-Fehler ignorieren */ tio.c_iflag = IGNPAR; /* Raw output */ tio.c_oflag = 0; /* Kein Echo */ tio.c_lflag = 0; /* Control chars */ tio.c_cc[VINTR] = 0; /* Ctrl-c */ tio.c_cc[VQUIT] = 0; /* Ctrl-\ */ tio.c_cc[VERASE] = 0; /* del */ tio.c_cc[VKILL] = 0; /* @ */ tio.c_cc[VEOF] = 0; /* Ctrl-d */ tio.c_cc[VSWTC] = 0; /* '\0' */ tio.c_cc[VSTART] = 0; /* Ctrl-q */ tio.c_cc[VSTOP] = 0; /* Ctrl-s */ tio.c_cc[VSUSP] = 0; /* Ctrl-z */ tio.c_cc[VEOL] = 0; /* '\0' */ tio.c_cc[VREPRINT] = 0; /* Ctrl-r */ tio.c_cc[VDISCARD] = 0; /* Ctrl-u */ tio.c_cc[VWERASE] = 0; /* Ctrl-w */ tio.c_cc[VLNEXT] = 0; /* Ctrl-v */ tio.c_cc[VEOL2] = 0; /* '\0' */ /* Use non-blocking input. This is necessary to allow the * keyboard to be polled while uploading. */ tio.c_cc[VMIN] = 0; tio.c_cc[VTIME] = 0; /* Einstellungen setzen */ if (tcsetattr(h, TCSADRAIN, &tio) < 0) error = 1; #endif if (error) { fprintf(stderr, "Serial initialization failed\n"); exit(1); } } /* Timeout für den blockierenden Empfang von Daten setzen */ void SetTimeout(HANDLE h, int seconds) { #ifdef _WIN32 COMMTIMEOUTS Timeouts; char res; res = GetCommTimeouts(h, &Timeouts); if(res) { Timeouts.ReadTotalTimeoutConstant = 1000*seconds; res = SetCommTimeouts(h, &Timeouts); if(res) return; } fprintf(stderr, "Serial timeout could not be set\n"); exit(1); #endif } /* Byte ueber serielle Schnittstelle ausgeben */ void WriteSerial(HANDLE h, unsigned char c) { int error = 0; #ifdef _WIN32 DWORD written; WriteFile(h, &c, 1, &written, NULL); if (written != 1) error = 1; #else if (write(h, &c, 1) != 1) error = 1; #endif if (error) { fprintf(stderr, "Serial write failed\n"); exit(1); } } /* Byte ueber serielle Schnittstelle einlesen */ /* Return 1, wenn 1 Zeichen empgangen wurde, 0 wenn ein Timeour auftrat (KEIN FEHLER!!) */ int ReadSerial(HANDLE h, unsigned char *c) { int error = 0; #ifdef _WIN32 DWORD read; if(!ReadFile(h, c, 1, &read, NULL)) error = 1; else if(read == 1) return 1; #else if (read(h, c, 1) == 1) return 1; // Todo errordetection // if(errno != 0) error = 1; #endif if (error) { fprintf(stderr, "Serial read failed\n"); exit(1); } return 0; } /* RTS/DTR setzen */ void SetLines(HANDLE h, int rtsdtr) { int error = 0; #ifdef _WIN32 if (rtsdtr & RTS) if (!EscapeCommFunction(h, SETRTS)) error = 1; if (rtsdtr & DTR) if (!EscapeCommFunction(h, SETDTR)) error = 1; #else if (ioctl(h, TIOCMBIS, &rtsdtr) < 0) error = 1; #endif if (error) { fprintf(stderr, "Could not access RTS/DTR lines\n"); exit(1); } } /* RTS/DTR loeschen */ void ClrLines(HANDLE h, int rtsdtr) { int error = 0; #ifdef _WIN32 if (rtsdtr & RTS) if (!EscapeCommFunction(h, CLRRTS)) error = 1; if (rtsdtr & DTR) if (!EscapeCommFunction(h, CLRDTR)) error = 1; #else if (ioctl(h, TIOCMBIC, &rtsdtr) < 0) error = 1; #endif if (error) { fprintf(stderr, "Could not access RTS/DTR lines\n"); exit(1); } } /* IRmate zuruecksetzen */ void ResetIRmate(HANDLE h) { SetLines(h, RTS | DTR); Delay(100); ClrLines(h, DTR); Delay(2); SetLines(h, DTR); Delay(2); } /* IRmate-Baudrate setzen */ void SetIRmateSpeed(HANDLE h, long baud) { unsigned char ctrlbyte; switch (baud) { case 2400: ctrlbyte = 8; break; case 9600: ctrlbyte = 4; break; case 19200: ctrlbyte = 3; break; case 38400: ctrlbyte = 2; break; case 57600: ctrlbyte = 1; break; case 115200: ctrlbyte = 0; break; default: fprintf(stderr, "Illegal baud rate (%ld)\n", baud); exit(1); } /* ctrlbyte |= 16 fuer kurze Pulse */ ClrLines(h, RTS); Delay(2); WriteSerial(h, ctrlbyte); Delay(100); SetLines(h, RTS); } /* Hauptprogramm */ int main(int argc, char *argv[]) { char *DeviceName = DEFAULT_DEVICE; long BaudRate = 115200; int NoHandshake = 0; int IRmate = 0; char *FileName = NULL; int ReceiveMode = 0; HANDLE h; FILE *hexfile; long size; long count; int percent, old_percent; int i; unsigned char c; configure_terminal(); /* Parameter parsen */ i = 1; while (i\n\n" "Available OPTIONS:\n" "-c Serial device to use\n" "-b Transmission speed. Must be one of the following values:\n" " 2400, 9600, 19200, 38400, 57600, 115200\n" "-r [MODE] Receive file. The reception will allways stop upon key press\n" " MODE='NULL' stops receiving upon reception of an 0x0-character\n" "-nohandshake Don't use RTS/CTS handshaking\n" "-irmate Enable transmission via IRmate (includes -nohandshake)\n\n" "Default values: -c " DEFAULT_DEVICE " -b 115200\n", argv[0]); exit(1); } /* Schnittstelle initialisieren */ h = OpenSerial(DeviceName); if (IRmate) { printf("Initializing IRmate...\n"); SetSerial(h, 9600, 0); ResetIRmate(h); SetIRmateSpeed(h, BaudRate); } SetSerial(h, BaudRate, !NoHandshake); // Soll eine Datei gesendet oder empfangen werden? if(ReceiveMode) { // Damit nicht unendlich gewartet wird bis Daten kommen (Lesen ist blockierend!!) kehre immer wieder zurück SetTimeout(h,1); /* File empfangen */ hexfile = fopen(FileName, "wb"); if (hexfile==NULL) { fprintf(stderr, "Could not open file %s\n", FileName); exit(1); } errno = 0; count = 0; setbuf(stdout, NULL); /* ungepufferte Ausgabe fuer Fortschrittsanzeige */ printf("Press key to stop upload.\n"); printf("Starting upload: 0 Bytes\r"); while(!kbhit()) { if(ReadSerial(h, &c)) { if((ReceiveMode == 2) && (c==0)) { printf("\nEOF detected, closing file...\n"); break; } fputc(c, hexfile); count++; printf("Starting upload: %ld Bytes\r", count); } } if(kbhit()) getch(); printf("\n"); fclose(hexfile); } // Datei versenden else { /* File uebertragen */ hexfile = fopen(FileName, "rb"); if (hexfile==NULL) { fprintf(stderr, "Could not open file %s\n", FileName); exit(1); } errno = 0; fseek(hexfile, 0, SEEK_END); size = ftell(hexfile); fseek(hexfile, 0, SEEK_SET); if (errno!=0) { fprintf(stderr, "Could not determine size of file %s\n", FileName); exit(1); } old_percent = -1; count = 0; setbuf(stdout, NULL); /* ungepufferte Ausgabe fuer Fortschrittsanzeige */ while ((i=fgetc(hexfile))!=EOF) { c = i; WriteSerial(h, c); count++; percent = count*100/size; if (percent!=old_percent) { printf("Starting download: %ld%%\r", (long int)percent); old_percent = percent; } } printf("\n"); fclose(hexfile); } CloseSerial(h); return 0; }