Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Smoothie by
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 }
Generated on Tue Jul 12 2022 20:09:03 by
1.7.2
