+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <termios.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "tohit_fn.h"
+#include <boot_fn.h>
+
+#define DEBUG 0
+#define DEBUG_COUNT 0
+
+int tohit_verbosity;
+
+#define verbose(level, ...) \
+ do { if (tohit_verbosity >= (level)) { printf("tohit: " __VA_ARGS__); } } while (0)
+
+//#define WITHOUT_CFSETSPEED
+
+#ifdef WITHOUT_CFSETSPEED
+
+
+struct rs232_speed_struct
+{
+ speed_t value;
+ speed_t internal;
+};
+
+static const struct rs232_speed_struct rs232_speeds[] =
+ {
+#ifdef B0
+ { 0, B0 },
+#endif
+#ifdef B50
+ { 50, B50 },
+#endif
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B76800
+ { 76800, B76800 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+#ifdef B153600
+ { 153600, B153600 },
+#endif
+#ifdef B230400
+ { 230400, B230400 },
+#endif
+#ifdef B307200
+ { 307200, B307200 },
+#endif
+#ifdef B460800
+ { 460800, B460800 },
+#endif
+ };
+
+/* Set both the input and output baud rates stored in *TERMIOS_P to SPEED. */
+int
+rs232_cfsetspeed (struct termios *termios_p, speed_t speed)
+{
+ size_t cnt;
+
+ for (cnt = 0; cnt < sizeof (rs232_speeds) / sizeof (rs232_speeds[0]); ++cnt)
+ if (speed == rs232_speeds[cnt].internal)
+ {
+ cfsetispeed (termios_p, speed);
+ cfsetospeed (termios_p, speed);
+ return 0;
+ }
+ else if (speed == rs232_speeds[cnt].value)
+ {
+ cfsetispeed (termios_p, rs232_speeds[cnt].internal);
+ cfsetospeed (termios_p, rs232_speeds[cnt].internal);
+ return 0;
+ }
+ /*__set_errno (EINVAL);*/
+
+ return -1;
+}
+
+#endif /* WITHOUT_CFSETSPEED */
+
+/* Set right mode and speed for RS232 interface */
+/* baud can be either speed in character per second or special Bxxxx constant */
+int rs232_setmode(int fd, int baud, int mode, int flowc)
+{
+ struct termios ts;
+
+ /* Flush input and output queues. */
+ if (tcflush(fd, TCIOFLUSH) != 0) {
+ fprintf(stderr,"Error in tcflush\n");
+ return -1;
+ }
+
+ /* Fetch the current terminal parameters. */
+ if (tcgetattr(fd, &ts) != 0) {
+ fprintf(stderr,"Error in tcgetattr\n");
+ return -1;
+ }
+
+ /* Sets hardware control flags: */
+ /* 8 data bits */
+ /* Enable receiver */
+ /* Ignore CD (local connection) */
+ ts.c_cflag = CS8 | CREAD | CLOCAL;
+ if(flowc&1){
+ /* Use RTS/CTS flow control */
+ ts.c_cflag |= CRTSCTS; /* CCTS_OFLOW | CRTS_IFLOW */
+ }
+ ts.c_iflag = 0;
+ ts.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
+ ts.c_lflag = 0;
+
+ /* set right ispeed and ospeed */
+ #ifdef WITHOUT_CFSETSPEED
+ if(rs232_cfsetspeed(&ts,baud)<0){
+ fprintf(stderr,"Error in rs232_cfsetspeed\n");
+ return -1;
+ }
+ #else /* WITHOUT_CFSETSPEED */
+ if(cfsetspeed(&ts,baud)<0){
+ fprintf(stderr,"Error in cfsetspeed\n");
+ return -1;
+ }
+ #endif /* WITHOUT_CFSETSPEED */
+
+ ts.c_cc[VINTR] = '\0';
+ ts.c_cc[VQUIT] = '\0';
+ ts.c_cc[VERASE] = '\0';
+ ts.c_cc[VKILL] = '\0';
+ ts.c_cc[VEOF] = '\0';
+ ts.c_cc[VTIME] = '\0';
+ ts.c_cc[VMIN] = 1;
+ ts.c_cc[VSWTC] = '\0';
+ ts.c_cc[VSTART] = '\0';
+ ts.c_cc[VSTOP] = '\0';
+ ts.c_cc[VSUSP] = '\0';
+ ts.c_cc[VEOL] = '\0';
+ ts.c_cc[VREPRINT] = '\0';
+ ts.c_cc[VDISCARD] = '\0';
+ ts.c_cc[VWERASE] = '\0';
+ ts.c_cc[VLNEXT] = '\0';
+ ts.c_cc[VEOL2] = '\0';
+
+ /* Sets the new terminal parameters. */
+ if (tcsetattr(fd, TCSANOW, &ts) != 0) {
+ fprintf(stderr,"Error in tcsetattr\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int rs232_sendch(int fd,unsigned char c)
+{
+ verbose(3, " > sending 0x%02X\n", c);
+ if(write(fd, &c, 1) != 1){
+ fprintf(stderr,"Error in rs232_sendch\n");
+ return -1;
+ }
+
+ return c;
+}
+
+int rs232_recch(int fd)
+{
+ unsigned char c;
+ int trycount=10;
+/* const char *message; */
+ int recieved;
+ do{
+ recieved=read(fd, &c, 1);
+
+ }while(trycount-- && (recieved==-1) && ((errno==EINTR)||(errno==EAGAIN)));
+
+ if (trycount <= 0){
+ fprintf(stderr,"Timeout in rs232_recch\n");
+ return -1;
+ }
+ if (recieved != 1){
+ fprintf(stderr,"Error in rs232_recch errno = %d\n", errno);
+ perror("rs232_recch");
+ printf("Read 0x%02X a recieved:%d \n",c,recieved);
+ return -1;
+ }
+
+ verbose(3, " < read 0x%02X \n",c);
+
+ return c;
+}
+
+int rs232_test(int fd,int time)
+{
+ struct timeval tv;
+ fd_set rfds;
+ int x;
+
+ if(time<tohit_waitrep)
+ time=tohit_waitrep;
+ tv.tv_sec = 0;
+ tv.tv_usec = time;
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ x=select(fd + 1, &rfds, NULL, NULL, &tv);
+ #if DEBUG
+ printf("rs232_test %d ",x);
+ #endif
+ return x;
+}
+
+void tohit_sendi(int fd,long a, int bytes)
+{
+ while(bytes--){
+ rs232_sendch(fd,(a>>(8*bytes)) & 0xFF);
+ }
+}
+
+long tohit_reci(int fd, int bytes)
+{
+ unsigned long x=0;
+ unsigned long c;
+ while(bytes--){
+ rs232_test(fd,500000);
+ c=rs232_recch(fd);
+ if(c==-1) return -1;
+ x|=c<<(8*bytes);
+ }
+ return x;
+}
+
+int tohit_sendichk(int fd,long a, int bytes)
+{
+ tohit_sendi(fd,a,bytes);
+ rs232_test(fd,500000);
+ if(tohit_reci(fd,bytes)!=a)
+ return -1;
+ return 0;
+}
+
+/* Synchronize with target */
+int tohit_synchronize(int fd)
+{
+ int i;
+ unsigned char c;
+ verbose(1, "Synchronizing with target\n");
+ i=10;
+ do{
+ c=0;
+ rs232_sendch(fd,c);
+
+ if(rs232_test(fd,500000)>0){
+ c=rs232_recch(fd);
+ if(c==0) break;
+ }
+ i--;
+ #if DEBUG
+ printf("\n");
+ #endif
+ }while (i>0);
+
+ if (i==0){
+ printf("Error timeout\n");
+ return -3;
+ }
+
+ /* Run 55=>AA synchronization */
+ #if DEBUG
+ printf("\n");
+ #endif
+ rs232_sendch(fd,0x55);
+ rs232_test(fd,500000);
+ c=rs232_recch(fd);
+ #if DEBUG
+ printf("\n");
+ #endif
+ if (c!=0xAA) {
+ printf("Error in AA reply\n");
+ return -4;
+ }
+ return 0;
+}
+
+const char *cmd_name[] = {
+ [1+TOHIT_WRITEBB] = "WRITEBB",
+ [1+TOHIT_WRITE] = "WRITE",
+ [1+TOHIT_WRITEFL] = "WRITEFL",
+ [1+TOHIT_READ] = "READ",
+ [1+TOHIT_ERASEBL] = "ERASEBL",
+ [1+TOHIT_ERASEREG] = "ERASEREG",
+ [1+TOHIT_GOTO] = "GOTO",
+ [1+TOHIT_RESET] = "RESET"
+};
+
+const char *boot_err[] = {
+ [EBOOT_PROG_FAILURE] = "Flash programming failure (damaged flash?)",
+ [EBOOT_EXT_FLASH_VERIFY] = "External flash verify failed",
+ [EBOOT_FLASH_VERIFY] = "Flash verify failed",
+ [EBOOT_ROW_NOT_ERASED] = "Flash row was not erased",
+ [EBOOT_NO_FWE] = "Flash write not enabled (FWE pin)",
+ [EBOOT_ROW_BEGIN] = "Programming starts in the middle of a row",
+ [EBOOT_BLOCKADDR] = "Wrong flash block start/end address",
+ [EBOOT_BLNUM_HIGH] = "Flash block number to high",
+ [EBOOT_BLNUM_LOW] = "Flash block number to low (negative)",
+ [EBOOT_FLASH_ERROR] = "Flash error indicated",
+ [EBOOT_ERASE_FAILURE] = "Flash erase failure"
+};
+
+#define ARR_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+
+int tohit_open4cmd(char *sdev, int baud, int cmd)
+{
+ int fd;
+ int c;
+
+ /* Open RS232 device */
+ if ((fd = open(sdev, O_RDWR | O_NONBLOCK)) == -1) {
+ printf("Error openning %s\n",sdev);
+ return -1;
+ }
+
+ /* Set RS232 device mode and speed */
+ if(rs232_setmode(fd,baud,0,0)<0){
+ printf("Error in rs232_setmode\n");
+ return -1;
+ }
+
+ /* Synchronize with target */
+ if(tohit_synchronize(fd)<0){
+ printf("Error in tohit_synchronize\n");
+ return -1;
+ }
+
+ if(cmd!=-1){
+ /* send cmd */
+ verbose(1, "Sending command 0x%02X (%s)\n", cmd, cmd_name[1+cmd]);
+ c=cmd | ((cmd ^ 7) << 3);
+ rs232_sendch(fd,c);
+ rs232_test(fd,500000);
+ if ((c | 0x80)!=rs232_recch(fd)) {
+ printf("Error in cmd reply\n");
+ return -4;
+ }
+ }
+ return fd;
+}
+
+int tohit_cmdrepchk(int fd)
+{
+ int res;
+ verbose(2, "Waiting for end reply\n");
+ rs232_test(fd,2000000);
+ res=rs232_recch(fd);
+ if(res<0){
+ printf("Error no end reply\n");
+ return -6;
+ }
+ if (res!=0xAA && res!=0x5a) {
+ int err = (int)(signed char)res;
+ printf("Error in end reply - received 0x%02X == %d (%s)\n",
+ res, err,
+ (err < 0 && -err < ARR_SIZE(boot_err)) ? boot_err[-err] : NULL);
+ return -6;
+ }
+ return 0;
+}
+
+#define BLEN 0x40000
+
+char *tohit_sdev="/dev/ttyS1";
+int tohit_baud=4800;
+
+
+int tohit_goto(unsigned long adr)
+{
+ int fd;
+ if((fd=tohit_open4cmd(tohit_sdev, tohit_baud, TOHIT_GOTO))<0)
+ {
+ printf("Error in tohit_open4cmd\n");
+ close(fd);
+ return -1;
+ }
+
+ verbose(2, "Sending go address 0x%08lx\n", adr);
+ if (tohit_sendichk(fd,adr,4)<0) {
+ printf("Error in goto adr send and reply\n");
+ close(fd);
+ return -4;
+ }
+
+ close(fd);
+ return 1;
+}
+
+void print_flash_error(int err)
+{
+ printf("Flash error: %s\n",
+ (err >= 0 && err < ARR_SIZE(boot_err)) ? boot_err[err] : "unknown error");
+}
+
+int tohit_writemem(int cmd, const unsigned char *buf,
+ unsigned long adr, unsigned long size, int blockmode)
+{
+ int fd;
+ int count;
+ unsigned long i;
+ int j, k;
+ int c;
+ unsigned char rbuf[128];
+
+ if((blockmode==1)||(blockmode>128)) blockmode=128;
+
+ if((fd=tohit_open4cmd(tohit_sdev, tohit_baud, cmd))<0)
+ {
+ printf("Error in tohit_open4cmd\n");
+ close(fd);
+ return -1;
+ }
+ if(cmd==TOHIT_WRITEBB){
+ verbose(2, "Sending size 0x%04lx\n", size);
+ if (tohit_sendichk(fd,size,2)<0) {
+ printf("Error in start adr send and reply\n");
+ close(fd);
+ return -4;
+ }
+ }else{
+ verbose(2, "Sending address 0x%08lx\n", adr);
+ if (tohit_sendichk(fd,adr,4)<0) {
+ printf("Error in start adr send and reply\n");
+ close(fd);
+ return -4;
+ }
+ verbose(2, "Sending size 0x%08lx\n", size);
+ if (tohit_sendichk(fd,size,4)<0) {
+ printf("Error in size send and reply\n");
+ close(fd);
+ return -4;
+ }
+ }
+
+ #if DEBUG
+ printf("Data send\n");
+ #endif /* DEBUG */
+ if(!blockmode){
+ verbose(2, "Writing in single byte mode\n");
+ for(i=0;i<size;i++){
+ rs232_sendch(fd,buf[i]);
+ rs232_test(fd,500000);
+ c=rs232_recch(fd);
+ if (c!=buf[i]) {
+ if (i % FLASH_ROW == FLASH_ROW-1) {
+ print_flash_error(rbuf[i]);
+ } else {
+ printf("Error in data reply (expected 0x%02x, received 0x%02x)\n", buf[i], c);
+ }
+ close(fd);
+ return -5;
+ }
+ if((i%128)==0){
+ printf(".");
+ fflush(stdout);
+ }
+ #if DEBUG
+ printf("\n");
+ #endif
+ }
+ }else{ /*TOHIT_WRITEFL*/
+ i=0;
+ verbose(2, "Writing in block mode (block size=%d)\n", blockmode);
+ count=blockmode-(adr&(blockmode-1));
+ while(i<size){
+ if(count>(size-i)) count=size-i;
+
+ verbose(3, " writing %d bytes\n",count);
+
+ j=0;
+ while(j<count){
+ k=write(fd, buf+i+j, count-j);
+ j+=k;
+ if((k<=0)||(j>count)){
+ perror("write");
+ printf("Error in blk write (%d,%d)\n",j,k);
+ close(fd);
+ return -2;
+ }
+ }
+
+ verbose(3, " reading %d bytes\n",count);
+ j=0;
+ do{
+ if ((i+j) % FLASH_ROW == FLASH_ROW - 1) {
+ verbose(3, " waiting for flashing a row\n");
+ rs232_test(fd,2/*sec*/*1000000);
+ } else {
+ rs232_test(fd,500000);
+ }
+ k=read(fd, rbuf+j, count-j);
+ if(k>=0) {
+ j+=k;
+ } else {
+ perror("read");
+ printf("Error in blk write - no reply (%d,%d)\n",j,k);
+ close(fd);
+ return -2;
+ }
+ }while(j<count);
+ if (tohit_verbosity < 3) {
+ printf(".");
+ fflush(stdout);
+ }
+ for(j=0;j<count;j++){
+ if (rbuf[j]!=buf[i+j]) {
+ if (i+j % FLASH_ROW == FLASH_ROW-1) {
+ print_flash_error(rbuf[j]);
+ } else {
+ printf("Error in data reply at position %d\n", j);
+
+ printf("Sent: ");
+ for (k=j; k < count && k < j+8; k++)
+ printf(" 0x%02x", rbuf[j+k]);
+ printf("\nReceived:");
+ for (k=j; k < count && k < j+8; k++)
+ printf(" 0x%02x", buf[i+j+k]);
+ printf("\n");
+ }
+ close(fd);
+ return -5;
+ }
+ }
+ i+=count;
+ count=blockmode;
+ }
+ printf("\n");
+ }
+
+ if(tohit_cmdrepchk(fd)<0){
+ printf("Error no end reply\n");
+ close(fd);
+ return -4;
+ }
+ close(fd);
+ return 1;
+}
+
+int tohit_readmem(int cmd, unsigned char *buf,
+ unsigned long adr, unsigned long size, int blockmode)
+{
+ int fd;
+ unsigned long i;
+ int c,k,ret;
+
+ if((fd=tohit_open4cmd(tohit_sdev, tohit_baud, cmd))<0)
+ {
+ printf("Error in tohit_open4cmd\n");
+ close(fd);
+ return -1;
+ }
+ verbose(2, "Sending address 0x%08lx\n", adr);
+ if (tohit_sendichk(fd,adr,4)<0) {
+ printf("Error in start adr send and reply\n");
+ close(fd);
+ return -4;
+ }
+ verbose(2, "Sending size 0x%08lx\n", size);
+ if (tohit_sendichk(fd,size,4)<0) {
+ printf("Error in size send and reply\n");
+ close(fd);
+ return -4;
+ }
+ if(!blockmode){
+ /* Read memory by single byte */
+ for(i=0;i<size;i++){
+ rs232_test(fd,500000);
+ if((c=rs232_recch(fd))<0){
+ printf("Error in receive char\n");
+ close(fd);
+ return -4;
+ }
+ buf[i]=c;
+ rs232_sendch(fd,c);
+ if((i%128)==0){
+ printf(".");
+ fflush(stdout);
+ }
+ #if DEBUG
+ printf("\n");
+ #endif
+ }
+ printf("\n");
+
+ if(tohit_cmdrepchk(fd)<0){
+ printf("Error no end reply\n");
+ close(fd);
+ return -4;
+ }
+ }else{
+ /* Read memory by blocks */
+ for(i=0;i<size;){
+ if(size-i>blockmode) c=blockmode;
+ else c=size-i;
+ for(k=0;k<c;k++)
+ while(rs232_sendch(fd,0)<0);
+ for(k=0;k<c;){
+ rs232_test(fd,500000);
+ ret=read(fd,buf+i+k,c-k);
+ if(ret<0){
+ printf("Error in block receive\n");
+ close(fd);
+ return -4;
+ }
+ k+=ret;
+ }
+ printf(".");
+ fflush(stdout);
+ i+=c;
+ }
+ if(rs232_recch(fd)!=0xff){
+ printf("Error no end reply\n");
+ close(fd);
+ return -4;
+ }
+ }
+ close(fd);
+ return 1;
+}
+
+int tohit_blockerase(int block)
+{
+ int fd;
+
+ if((fd=tohit_open4cmd(tohit_sdev, tohit_baud, TOHIT_ERASEBL))<0)
+ {
+ printf("Error in tohit_open4cmd\n");
+ close(fd);
+ return -1;
+ }
+
+ verbose(2, "Sending block number: %d\n", block);
+ rs232_sendch(fd,block);
+ rs232_test(fd,2000000);
+ rs232_test(fd,2000000);
+
+ if(tohit_cmdrepchk(fd)<0){
+ printf("Error no end reply\n");
+ close(fd);
+ return -4;
+ }
+ close(fd);
+ return 1;
+}
+
+int tohit_regerase(unsigned long adr, unsigned long size)
+{
+ int fd;
+
+ if((fd=tohit_open4cmd(tohit_sdev, tohit_baud, TOHIT_ERASEREG))<0)
+ {
+ printf("Error in tohit_open4cmd\n");
+ close(fd);
+ return -1;
+ }
+ verbose(2, "Sending start address 0x%08lx\n", adr);
+ if (tohit_sendichk(fd,adr,4)<0) {
+ printf("Error in start adr send and reply\n");
+ close(fd);
+ return -4;
+ }
+ verbose(2, "Sending size 0x%08lx\n", size);
+ if (tohit_sendichk(fd,size,4)<0) {
+ printf("Error in size send and reply\n");
+ close(fd);
+ return -4;
+ }
+
+ printf("\n");
+
+ if(tohit_cmdrepchk(fd)<0){
+ printf("Error no end reply\n");
+ close(fd);
+ return -4;
+ }
+ close(fd);
+ return 1;
+}
+
+int tohit_reset(void)
+{
+ int fd;
+ if((fd=tohit_open4cmd(tohit_sdev, tohit_baud, TOHIT_RESET))<0)
+ {
+ printf("Error in tohit_open4cmd\n");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 1;
+}
+
+int tohit_break(void)
+{
+ int fd;
+ int i;
+ char c=0;
+
+ /* Open RS232 device */
+ if ((fd = open(tohit_sdev, O_RDWR | O_NONBLOCK)) == -1) {
+ printf("Error openning %s\n",tohit_sdev);
+ return -1;
+ }
+
+ if(rs232_setmode(fd,tohit_baud/2,0,0)<0)
+ {
+ close(fd);
+ return -1;
+ }
+
+ verbose(1, "Sending break chars \n");
+
+ for(i=100;i--;)
+ write(fd,&c,1);
+
+ close(fd);
+ return 1;
+}