From fdff8599457302351e026b2c0fac82ac4e012225 Mon Sep 17 00:00:00 2001
From: Markus Hitter <mah@jump-ing.de>
Date: Tue, 19 Nov 2013 21:07:50 +0100
Subject: ui/serialtx: implement SerialTxFile.

Just like the Rx counterpart, this is for communications between
a file/special file/console and the actually simulated UART. Works
beautifully.
---
 src/ui/serialtx.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/ui/serialtx.h   | 17 +++++++++++++++
 2 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/src/ui/serialtx.cpp b/src/ui/serialtx.cpp
index c13e580..cdf8652 100644
--- a/src/ui/serialtx.cpp
+++ b/src/ui/serialtx.cpp
@@ -107,7 +107,7 @@ void SerialTxBuffered::Send(unsigned char data)
 {
     inputBuffer.push_back(data); //write new char to input buffer
 
-    cerr << "TX: " << hex << data << " ";
+    // cerr << "TX: " << hex << data << endl;
     //if we not active, activate tx machine now
     if (txState==TX_DISABLED) {
         txState=TX_SEND_STARTBIT;
@@ -115,6 +115,10 @@ void SerialTxBuffered::Send(unsigned char data)
     }
 }
 
+bool SerialTxBuffered::Sending(void) {
+    return (txState != TX_DISABLED);
+}
+
 void SerialTxBuffered::SetBaudRate(SystemClockOffset baud){
     baudrate = baud;
 }
@@ -124,6 +128,60 @@ void SerialTxBuffered::SetHexInput(bool newValue){
 }
 
 
+// ===========================================================================
+// ===========================================================================
+// ===========================================================================
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+
+SerialTxFile::SerialTxFile(const char *filename) {
+    if (std::string(filename) == "-")
+        fd = fileno(stdin);
+    else
+        fd = open(filename, O_RDONLY, O_CREAT);
+    if (fd < 0)
+        avr_error("open input file failed");
+    Reset();
+
+    SystemClock::Instance().Add(this);
+}
+
+SerialTxFile::~SerialTxFile() {
+    if (fd != fileno(stdin))
+        close(fd);
+}
+
+int SerialTxFile::Step(bool &trueHwStep,
+                       SystemClockOffset *timeToNextStepIn_ns) {
+
+    if (Sending()) {
+        SerialTxBuffered::Step(trueHwStep, timeToNextStepIn_ns);
+    }
+    
+#ifndef WIN32
+    pollfd cinfd[1];
+    cinfd[0].fd = fd;
+    cinfd[0].events = POLLIN;
+    if (poll(cinfd, 1, 0) > 0) {
+#else
+    HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
+    if (WaitForSingleObject(h, 0) == WAIT_OBJECT_0) {
+#endif
+        unsigned char c;
+        if (read(fd, &c, 1)) {
+            Send((unsigned char)c);
+        }
+    }
+
+    if ( ! Sending()) // may have changed with Step() or Send()
+        // Polling for new data every millisecond should be enough. If there's
+        // more than one byte waiting, they're accepted at every serial clock
+        // tick, which means, ten times faster than they can be sent.
+        *timeToNextStepIn_ns = (SystemClockOffset)1000000;
+}
 
 // ===========================================================================
 // ===========================================================================
diff --git a/src/ui/serialtx.h b/src/ui/serialtx.h
index 7ce2ac4..9f92b0d 100644
--- a/src/ui/serialtx.h
+++ b/src/ui/serialtx.h
@@ -61,10 +61,27 @@ class SerialTxBuffered: public SimulationMember {
         virtual int Step(bool &trueHwStep, SystemClockOffset *timeToNextStepIn_ns=0);
         /// Add byte from UI to be sent to device's UART.
         virtual void Send(unsigned char data);
+        bool Sending(void);
         virtual void SetBaudRate(SystemClockOffset baud);
         virtual Pin* GetPin(const char *name); 
 };
 
+#include <stdio.h>
+#include <unistd.h>
+
+/** Reads  bytes from a file, a special file/com port or the console
+ *  and sends them to the device's UART. */
+class SerialTxFile: public SerialTxBuffered {
+    private:
+        // Use a classic file descriptor to have better
+        // control over buffers (and their avoidance).
+        int fd;
+    public:
+        SerialTxFile(const char *filename);
+        ~SerialTxFile();
+        virtual int Step(bool &trueHwStep, SystemClockOffset *timeToNextStepIn_ns=0);
+};
+
 
 /** Buffers byte from UI to be sent to device's UART. */
 class SerialTx: public SerialTxBuffered, public ExternalType {
-- 
1.8.3.2

