From 57640a10a66a97a07b954a25e976ff0d3a5d28b0 Mon Sep 17 00:00:00 2001
From: Nao Pross <naopross@thearcway.org>
Date: Thu, 19 Oct 2017 17:56:29 +0200
Subject: Got a real rom programmer, this code is still broken but I don't care

---
 sw/programmer/linux/src/flash.c  |  12 ++++++--
 sw/programmer/linux/src/serial.c |  63 ++++++++++++++++++++++++++++++++++-----
 sw/programmer/linux/src/serial.h |   4 +++
 sw/programmer/linux/src/z80prog  | Bin 49856 -> 52072 bytes
 4 files changed, 68 insertions(+), 11 deletions(-)

(limited to 'sw/programmer/linux')

diff --git a/sw/programmer/linux/src/flash.c b/sw/programmer/linux/src/flash.c
index 24d5269..3527de8 100644
--- a/sw/programmer/linux/src/flash.c
+++ b/sw/programmer/linux/src/flash.c
@@ -15,6 +15,7 @@ int flash_open(const char *path, unsigned long baudrate)
 int flash_write(const char *romfile, void (*log)(const char *))
 {
 	int romfd;
+    int v;
 	ssize_t written;
 
 	struct stat romst;
@@ -33,7 +34,11 @@ int flash_write(const char *romfile, void (*log)(const char *))
             break;
         }
 
-		head.addr = (uint16_t) lseek(romfd, 0, SEEK_CUR);
+		head.addr = (uint16_t) lseek(romfd, 0, SEEK_CUR) - head.size;
+
+        char logbuf[64];
+        sprintf(logbuf, "[@] Writing a block of size %d at addr %d\n", head.size, head.addr);
+        log(logbuf);
 
 		written = write(flash_serial_fd, &head, sizeof(struct flash_blk));
 		if (written != sizeof(struct flash_blk)) {
@@ -45,8 +50,9 @@ int flash_write(const char *romfile, void (*log)(const char *))
             log("[#] Some bytes might not have been written\n");
 		}
 
-        char logbuf[64];
-		sprintf(logbuf, "[@] Written %d bytes at address %d\n", head.size, head.addr);
+        while (!read(flash_serial_fd, &v, 1));
+
+        sprintf(logbuf, "[@] Written %d bytes at address %d\n", head.size, head.addr);
 		log(logbuf);
 	}
 
diff --git a/sw/programmer/linux/src/serial.c b/sw/programmer/linux/src/serial.c
index e2544be..42f021e 100644
--- a/sw/programmer/linux/src/serial.c
+++ b/sw/programmer/linux/src/serial.c
@@ -1,9 +1,23 @@
 #include "serial.h"
 
+static int rate_to_constant(int baudrate) {
+#define B(x) case x: return B##x
+    switch(baudrate) {
+        B(50);     B(75);     B(110);    B(134);    B(150);
+        B(200);    B(300);    B(600);    B(1200);   B(1800);
+        B(2400);   B(4800);   B(9600);   B(19200);  B(38400);
+        B(57600);  B(115200); B(230400); B(460800); B(500000); 
+        B(576000); B(921600); B(1000000);B(1152000);B(1500000); 
+    default: return 0;
+    }
+#undef B
+}
+
 int serial_open(const char *devpath, unsigned long baudrate)
 {
-    int fd;
+    int fd, speed;
     struct termios tty;
+    struct serial_struct serinfo;
     // struct termios tty_old;
     
     // open device
@@ -11,14 +25,44 @@ int serial_open(const char *devpath, unsigned long baudrate)
         return -1;
     }
 
+    speed = rate_to_constant(baudrate);
+    if (speed == 0) {
+        /* custom divisor */
+        serinfo.reserved_char[0] = 0;
+        if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
+            return -1;
+        serinfo.flags &= ~ASYNC_SPD_MASK;
+        serinfo.flags |= ASYNC_SPD_CUST;
+        serinfo.custom_divisor = (serinfo.baud_base + (baudrate / 2)) / baudrate;
+
+        if (serinfo.custom_divisor < 1) 
+            serinfo.custom_divisor = 1;
+        if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
+            return -1;
+        if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
+            return -1;
+        if (serinfo.custom_divisor * baudrate != serinfo.baud_base) {
+            warnx("actual baudrate is %d / %d = %f",
+                  serinfo.baud_base, serinfo.custom_divisor,
+                  (float)serinfo.baud_base / serinfo.custom_divisor);
+        }
+    }
+
+    // set custom baudrate
+    ioctl(fd, TIOCGSERIAL, &serinfo);
+    serinfo.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY; 
+    serinfo.custom_divisor = serinfo.baud_base / baudrate; 
+    ioctl(fd, TIOCSSERIAL, &serinfo);
+
     // set parameters
     if (tcgetattr(fd, &tty) != 0) {
+        // perror("failed tcgetattr");
         return -1;
     }
 
-    // TODO: update UI or add support for custom baudrate
-    // cfsetospeed(&tty, 
-    // cfsetispeed(&tty, 
+    cfsetispeed(&tty, speed ?: B38400);
+    cfsetospeed(&tty, speed ?: B38400);
+    cfmakeraw(&tty);
 
     tty.c_cflag &= ~PARENB;  // no parity
     tty.c_cflag &= ~CSTOPB;  // no stop bit
@@ -28,16 +72,19 @@ int serial_open(const char *devpath, unsigned long baudrate)
     tty.c_lflag     =  0;  // no signaling chars, no echo, no canonical processing
     tty.c_oflag     =  0;  // no remapping, no delays
     tty.c_cc[VMIN]  =  0;  // no block read
-    tty.c_cc[VTIME] = .5;  // .5 seconds read timeout
+    tty.c_cc[VTIME] =  5;  // .5 seconds read timeout
 
     tty.c_cflag |= CREAD | CLOCAL;      // turn on read and ignore ctrl lines
     tty.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
     tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
     tty.c_oflag &= ~OPOST; // make raw
 
-    tcflush(fd , TCIFLUSH);
-    // if (tcsetaddr(
+    tcflush(fd , TCIFLUSH); // ?
+
+    if (tcsetattr (fd, TCSANOW, &tty) != 0) {
+        // perror("failed tcsetattr to set serial port.\n");
+        return -1;
+    }
 
     return fd;
 }
-
diff --git a/sw/programmer/linux/src/serial.h b/sw/programmer/linux/src/serial.h
index fe21524..dd70756 100644
--- a/sw/programmer/linux/src/serial.h
+++ b/sw/programmer/linux/src/serial.h
@@ -7,6 +7,10 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <termios.h>
+#include <sys/ioctl.h>
+#include <termio.h>
+#include <err.h>
+#include <linux/serial.h>
 
 int serial_open(const char *devpath, unsigned long baudrate);
 
diff --git a/sw/programmer/linux/src/z80prog b/sw/programmer/linux/src/z80prog
index 9787e67..e2876ee 100755
Binary files a/sw/programmer/linux/src/z80prog and b/sw/programmer/linux/src/z80prog differ
-- 
cgit v1.2.1