Allow TABS in config
[clinton/Smoothieware.git] / src / libs / USBDevice / USBSerial / USBSerial.cpp
index 99bfbeb..f01c151 100644 (file)
 \r
 #include "libs/Kernel.h"\r
 #include "libs/SerialMessage.h"\r
+#include "StreamOutputPool.h"\r
 \r
 // extern void setled(int, bool);\r
 #define setled(a, b) do {} while (0)\r
 \r
 #define iprintf(...) do { } while (0)\r
 \r
-USBSerial::USBSerial(USB *u): USBCDC(u), rxbuf(128 + 8), txbuf(128 + 8)\r
+USBSerial::USBSerial(USB *u): USBCDC(u), rxbuf(256 + 8), txbuf(128 + 8)\r
 {\r
     usb = u;\r
     nl_in_rx = 0;\r
     attach = attached = false;\r
+    flush_to_nl = false;\r
 }\r
 \r
 void USBSerial::ensure_tx_space(int space)\r
@@ -49,8 +51,6 @@ int USBSerial::_putc(int c)
 {\r
     if (!attached)\r
         return 1;\r
-    if (c == '\r')\r
-        return 1;\r
     ensure_tx_space(1);\r
     txbuf.queue(c);\r
 \r
@@ -70,8 +70,17 @@ int USBSerial::_getc()
         usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);\r
         iprintf("rxbuf has room for another packet, interrupt enabled\n");\r
     }\r
+    else if ((rxbuf.free() < MAX_PACKET_SIZE_EPBULK) && (nl_in_rx == 0))\r
+    {\r
+        // handle potential deadlock where a short line, and the beginning of a very long line are bundled in one usb packet\r
+        rxbuf.flush();\r
+        flush_to_nl = true;\r
+\r
+        usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);\r
+        iprintf("rxbuf has room for another packet, interrupt enabled\n");\r
+    }\r
     if (nl_in_rx > 0)\r
-        if (c == '\n')\r
+        if (c == '\n' || c == '\r')\r
             nl_in_rx--;\r
 \r
     return c;\r
@@ -85,8 +94,7 @@ int USBSerial::puts(const char *str)
     while (*str)\r
     {\r
         ensure_tx_space(1);\r
-        if ((*str != '\r'))\r
-            txbuf.queue(*str);\r
+        txbuf.queue(*str);\r
         if ((txbuf.available() % 64) == 0)\r
             usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);\r
         i++;\r
@@ -96,7 +104,7 @@ int USBSerial::puts(const char *str)
     return i;\r
 }\r
 \r
-uint16_t USBSerial::writeBlock(uint8_t * buf, uint16_t size)\r
+uint16_t USBSerial::writeBlock(const uint8_t * buf, uint16_t size)\r
 {\r
     if (!attached)\r
         return size;\r
@@ -187,7 +195,10 @@ bool USBSerial::USBEvent_EPOut(uint8_t bEP, uint8_t bEPStatus)
     readEP(c, &size);\r
     iprintf("Read %ld bytes:\n\t", size);\r
     for (uint8_t i = 0; i < size; i++) {\r
-        rxbuf.queue(c[i]);\r
+\r
+        if (flush_to_nl == false)\r
+            rxbuf.queue(c[i]);\r
+\r
         if (c[i] >= 32 && c[i] < 128)\r
         {\r
             iprintf("%c", c[i]);\r
@@ -196,14 +207,38 @@ bool USBSerial::USBEvent_EPOut(uint8_t bEP, uint8_t bEPStatus)
         {\r
             iprintf("\\x%02X", c[i]);\r
         }\r
-        if (c[i] == '\n')\r
-            nl_in_rx++;\r
+\r
+        if (c[i] == '\n' || c[i] == '\r')\r
+        {\r
+            if (flush_to_nl)\r
+                flush_to_nl = false;\r
+            else\r
+                nl_in_rx++;\r
+        }\r
+        else if (rxbuf.isFull() && (nl_in_rx == 0))\r
+        {\r
+            // to avoid a deadlock with very long lines, we must dump the buffer\r
+            // and continue flushing to the next newline\r
+            rxbuf.flush();\r
+            flush_to_nl = true;\r
+        }\r
     }\r
     iprintf("\nQueued, %d empty\n", rxbuf.free());\r
 \r
     if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)\r
     {\r
+        // if buffer is full, stall endpoint, do not accept more data\r
         r = false;\r
+\r
+        if (nl_in_rx == 0)\r
+        {\r
+            // we have to check for long line deadlock here too\r
+            flush_to_nl = true;\r
+            rxbuf.flush();\r
+\r
+            // and since our buffer is empty, we can accept more data\r
+            r = true;\r
+        }\r
     }\r
 \r
     usb->readStart(CDC_BulkOut.bEndpointAddress, MAX_PACKET_SIZE_EPBULK);\r
@@ -223,18 +258,22 @@ void USBSerial::on_module_loaded()
 \r
 void USBSerial::on_main_loop(void *argument)\r
 {\r
+    // apparently some OSes don't assert DTR when a program opens the port\r
+    if (available() && !attach)\r
+        attach = true;\r
+\r
     if (attach != attached)\r
     {\r
         if (attach)\r
         {\r
             attached = true;\r
-            kernel->streams->append_stream(this);\r
-            writeBlock((uint8_t *) "Smoothie\nok\n", 12);\r
+            THEKERNEL->streams->append_stream(this);\r
+            writeBlock((const uint8_t *) "Smoothie\nok\n", 12);\r
         }\r
         else\r
         {\r
             attached = false;\r
-            kernel->streams->remove_stream(this);\r
+            THEKERNEL->streams->remove_stream(this);\r
             txbuf.flush();\r
             rxbuf.flush();\r
             nl_in_rx = 0;\r
@@ -246,13 +285,13 @@ void USBSerial::on_main_loop(void *argument)
         while (available())\r
         {\r
             char c = _getc();\r
-            if( c == '\n' )\r
+            if( c == '\n' || c == '\r')\r
             {\r
                 struct SerialMessage message;\r
                 message.message = received;\r
                 message.stream = this;\r
                 iprintf("USBSerial Received: %s\n", message.message.c_str());\r
-                this->kernel->call_event(ON_CONSOLE_LINE_RECEIVED, &message );\r
+                THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );\r
                 return;\r
             }\r
             else\r