Fork of Smoothie to port to mbed non-LPC targets.

Dependencies:   mbed

Fork of Smoothie by Stéphane Cachat

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBSerial.cpp Source File

USBSerial.cpp

00001 /* Copyright (c) 2010-2011 mbed.org, MIT License
00002 *
00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004 * and associated documentation files (the "Software"), to deal in the Software without
00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00007 * Software is furnished to do so, subject to the following conditions:
00008 *
00009 * The above copyright notice and this permission notice shall be included in all copies or
00010 * substantial portions of the Software.
00011 *
00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 */
00018 
00019 #include <cstdint>
00020 #include <cstdio>
00021 
00022 #include "USBSerial.h"
00023 
00024 #include "libs/Kernel.h"
00025 #include "libs/SerialMessage.h"
00026 
00027 // extern void setled(int, bool);
00028 #define setled(a, b) do {} while (0)
00029 
00030 #define iprintf(...) do { } while (0)
00031 
00032 USBSerial::USBSerial(USB *u): USBCDC(u), rxbuf(256 + 8), txbuf(128 + 8)
00033 {
00034     usb = u;
00035     nl_in_rx = 0;
00036     attach = attached = false;
00037     flush_to_nl = false;
00038 }
00039 
00040 void USBSerial::ensure_tx_space(int space)
00041 {
00042     while (txbuf.free() < space)
00043     {
00044         usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
00045         usb->usbisr();
00046     }
00047 }
00048 
00049 int USBSerial::_putc(int c)
00050 {
00051     if (!attached)
00052         return 1;
00053     ensure_tx_space(1);
00054     txbuf.queue(c);
00055 
00056     usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
00057     return 1;
00058 }
00059 
00060 int USBSerial::_getc()
00061 {
00062     if (!attached)
00063         return 0;
00064     uint8_t c = 0;
00065     setled(4, 1); while (rxbuf.isEmpty()); setled(4, 0);
00066     rxbuf.dequeue(&c);
00067     if (rxbuf.free() == MAX_PACKET_SIZE_EPBULK)
00068     {
00069         usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);
00070         iprintf("rxbuf has room for another packet, interrupt enabled\n");
00071     }
00072     else if ((rxbuf.free() < MAX_PACKET_SIZE_EPBULK) && (nl_in_rx == 0))
00073     {
00074         // handle potential deadlock where a short line, and the beginning of a very long line are bundled in one usb packet
00075         rxbuf.flush();
00076         flush_to_nl = true;
00077 
00078         usb->endpointSetInterrupt(CDC_BulkOut.bEndpointAddress, true);
00079         iprintf("rxbuf has room for another packet, interrupt enabled\n");
00080     }
00081     if (nl_in_rx > 0)
00082         if (c == '\n' || c == '\r')
00083             nl_in_rx--;
00084 
00085     return c;
00086 }
00087 
00088 int USBSerial::puts(const char *str)
00089 {
00090     if (!attached)
00091         return strlen(str);
00092     int i = 0;
00093     while (*str)
00094     {
00095         ensure_tx_space(1);
00096         txbuf.queue(*str);
00097         if ((txbuf.available() % 64) == 0)
00098             usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
00099         i++;
00100         str++;
00101     }
00102     usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
00103     return i;
00104 }
00105 
00106 uint16_t USBSerial::writeBlock(const uint8_t * buf, uint16_t size)
00107 {
00108     if (!attached)
00109         return size;
00110     if (size > txbuf.free())
00111     {
00112         size = txbuf.free();
00113     }
00114     if (size > 0)
00115     {
00116         for (uint8_t i = 0; i < size; i++)
00117         {
00118             txbuf.queue(buf[i]);
00119         }
00120         usb->endpointSetInterrupt(CDC_BulkIn.bEndpointAddress, true);
00121     }
00122     return size;
00123 }
00124 
00125 bool USBSerial::USBEvent_EPIn(uint8_t bEP, uint8_t bEPStatus)
00126 {
00127     /*
00128      * Called in ISR context
00129      */
00130 
00131 //     static bool needToSendNull = false;
00132 
00133     bool r = true;
00134 
00135     if (bEP != CDC_BulkIn.bEndpointAddress)
00136         return false;
00137 
00138     iprintf("USBSerial:EpIn: 0x%02X\n", bEPStatus);
00139 
00140     uint8_t b[MAX_PACKET_SIZE_EPBULK];
00141 
00142     int l = txbuf.available();
00143     iprintf("%d bytes queued\n", l);
00144     if (l > 0)
00145     {
00146         if (l > MAX_PACKET_SIZE_EPBULK)
00147             l = MAX_PACKET_SIZE_EPBULK;
00148         iprintf("Sending %d bytes:\n\t", l);
00149         int i;
00150         for (i = 0; i < l; i++) {
00151             txbuf.dequeue(&b[i]);
00152             if (b[i] >= 32 && b[i] < 128)
00153                 iprintf("%c", b[i]);
00154             else {
00155                 iprintf("\\x%02X", b[i]);
00156             }
00157         }
00158         iprintf("\nSending...\n");
00159         send(b, l);
00160         iprintf("Sent\n");
00161         if (txbuf.available() == 0)
00162             r = false;
00163     }
00164     else
00165     {
00166         r = false;
00167     }
00168     iprintf("USBSerial:EpIn Complete\n");
00169     return r;
00170 }
00171 
00172 bool USBSerial::USBEvent_EPOut(uint8_t bEP, uint8_t bEPStatus)
00173 {
00174     /*
00175      * Called in ISR context
00176      */
00177 
00178     bool r = true;
00179 
00180     iprintf("USBSerial:EpOut\n");
00181     if (bEP != CDC_BulkOut.bEndpointAddress)
00182         return false;
00183 
00184     if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)
00185     {
00186 //         usb->endpointSetInterrupt(bEP, false);
00187         return false;
00188     }
00189 
00190     uint8_t c[MAX_PACKET_SIZE_EPBULK];
00191     uint32_t size = 64;
00192 
00193     //we read the packet received and put it on the circular buffer
00194     readEP(c, &size);
00195     iprintf("Read %ld bytes:\n\t", size);
00196     for (uint8_t i = 0; i < size; i++) {
00197 
00198         if (flush_to_nl == false)
00199             rxbuf.queue(c[i]);
00200 
00201         if (c[i] >= 32 && c[i] < 128)
00202         {
00203             iprintf("%c", c[i]);
00204         }
00205         else
00206         {
00207             iprintf("\\x%02X", c[i]);
00208         }
00209 
00210         if (c[i] == '\n' || c[i] == '\r')
00211         {
00212             if (flush_to_nl)
00213                 flush_to_nl = false;
00214             else
00215                 nl_in_rx++;
00216         }
00217         else if (rxbuf.isFull() && (nl_in_rx == 0))
00218         {
00219             // to avoid a deadlock with very long lines, we must dump the buffer
00220             // and continue flushing to the next newline
00221             rxbuf.flush();
00222             flush_to_nl = true;
00223         }
00224     }
00225     iprintf("\nQueued, %d empty\n", rxbuf.free());
00226 
00227     if (rxbuf.free() < MAX_PACKET_SIZE_EPBULK)
00228     {
00229         // if buffer is full, stall endpoint, do not accept more data
00230         r = false;
00231 
00232         if (nl_in_rx == 0)
00233         {
00234             // we have to check for long line deadlock here too
00235             flush_to_nl = true;
00236             rxbuf.flush();
00237 
00238             // and since our buffer is empty, we can accept more data
00239             r = true;
00240         }
00241     }
00242 
00243     usb->readStart(CDC_BulkOut.bEndpointAddress, MAX_PACKET_SIZE_EPBULK);
00244     iprintf("USBSerial:EpOut Complete\n");
00245     return r;
00246 }
00247 
00248 uint8_t USBSerial::available()
00249 {
00250     return rxbuf.available();
00251 }
00252 
00253 void USBSerial::on_module_loaded()
00254 {
00255     this->register_for_event(ON_MAIN_LOOP);
00256 }
00257 
00258 void USBSerial::on_main_loop(void *argument)
00259 {
00260     // apparently some OSes don't assert DTR when a program opens the port
00261     if (available() && !attach)
00262         attach = true;
00263 
00264     if (attach != attached)
00265     {
00266         if (attach)
00267         {
00268             attached = true;
00269             THEKERNEL->streams->append_stream(this);
00270             writeBlock((const uint8_t *) "Smoothie\nok\n", 12);
00271         }
00272         else
00273         {
00274             attached = false;
00275             THEKERNEL->streams->remove_stream(this);
00276             txbuf.flush();
00277             rxbuf.flush();
00278             nl_in_rx = 0;
00279         }
00280     }
00281     if (nl_in_rx)
00282     {
00283         string received;
00284         while (available())
00285         {
00286             char c = _getc();
00287             if( c == '\n' || c == '\r')
00288             {
00289                 struct SerialMessage message;
00290                 message.message = received;
00291                 message.stream = this;
00292                 iprintf("USBSerial Received: %s\n", message.message.c_str());
00293                 THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );
00294                 return;
00295             }
00296             else
00297             {
00298                 received += c;
00299             }
00300         }
00301     }
00302 }
00303 
00304 void USBSerial::on_attach()
00305 {
00306     attach = true;
00307 }
00308 
00309 void USBSerial::on_detach()
00310 {
00311     attach = false;
00312 }