1 /* Copyright (c) 2010-2011 mbed.org, MIT License
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4 * and associated documentation files (the "Software"), to deal in the Software without
5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7 * Software is furnished to do so, subject to the following conditions:
9 * The above copyright notice and this permission notice shall be included in all copies or
10 * substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #include "USBSerial.h"
24 #include "libs/Kernel.h"
25 #include "libs/SerialMessage.h"
26 #include "StreamOutputPool.h"
28 // extern void setled(int, bool);
29 #define setled(a, b) do {} while (0)
31 #define iprintf(...) do { } while (0)
33 USBSerial::USBSerial(USB
*u
): USBCDC(u
), rxbuf(256 + 8), txbuf(128 + 8)
37 attach
= attached
= false;
41 last_char_was_dollar
= false;
44 void USBSerial::ensure_tx_space(int space
)
46 while (txbuf
.free() < space
) {
47 usb
->endpointSetInterrupt(CDC_BulkIn
.bEndpointAddress
, true);
52 int USBSerial::_putc(int c
)
59 usb
->endpointSetInterrupt(CDC_BulkIn
.bEndpointAddress
, true);
63 int USBSerial::_getc()
68 setled(4, 1); while (rxbuf
.isEmpty()); setled(4, 0);
70 if (rxbuf
.free() == MAX_PACKET_SIZE_EPBULK
) {
71 usb
->endpointSetInterrupt(CDC_BulkOut
.bEndpointAddress
, true);
72 iprintf("rxbuf has room for another packet, interrupt enabled\n");
73 } else if ((rxbuf
.free() < MAX_PACKET_SIZE_EPBULK
) && (nl_in_rx
== 0)) {
74 // handle potential deadlock where a short line, and the beginning of a very long line are bundled in one usb packet
78 usb
->endpointSetInterrupt(CDC_BulkOut
.bEndpointAddress
, true);
79 iprintf("rxbuf has room for another packet, interrupt enabled\n");
82 if (c
== '\n' || c
== '\r')
88 int USBSerial::puts(const char *str
)
96 if ((txbuf
.available() % 64) == 0)
97 usb
->endpointSetInterrupt(CDC_BulkIn
.bEndpointAddress
, true);
101 usb
->endpointSetInterrupt(CDC_BulkIn
.bEndpointAddress
, true);
105 uint16_t USBSerial::writeBlock(const uint8_t * buf
, uint16_t size
)
109 if (size
> txbuf
.free()) {
113 for (uint8_t i
= 0; i
< size
; i
++) {
116 usb
->endpointSetInterrupt(CDC_BulkIn
.bEndpointAddress
, true);
121 bool USBSerial::USBEvent_EPIn(uint8_t bEP
, uint8_t bEPStatus
)
124 * Called in ISR context
127 // static bool needToSendNull = false;
131 if (bEP
!= CDC_BulkIn
.bEndpointAddress
)
134 iprintf("USBSerial:EpIn: 0x%02X\n", bEPStatus
);
136 uint8_t b
[MAX_PACKET_SIZE_EPBULK
];
138 int l
= txbuf
.available();
140 // Use MAX_PACKET_SIZE_EPBULK-1 below instead of MAX_PACKET_SIZE_EPBULK
141 // to work around a problem sending packets that are exactly MAX_PACKET_SIZE_EPBULK
142 // bytes in length. The problem is that these packets don't flush properly.
143 if (l
> MAX_PACKET_SIZE_EPBULK
-1)
144 l
= MAX_PACKET_SIZE_EPBULK
-1;
146 for (i
= 0; i
< l
; i
++) {
147 txbuf
.dequeue(&b
[i
]);
150 if (txbuf
.available() == 0)
155 iprintf("USBSerial:EpIn Complete\n");
159 bool USBSerial::USBEvent_EPOut(uint8_t bEP
, uint8_t bEPStatus
)
162 * Called in ISR context
167 iprintf("USBSerial:EpOut\n");
168 if (bEP
!= CDC_BulkOut
.bEndpointAddress
)
171 if (rxbuf
.free() < MAX_PACKET_SIZE_EPBULK
) {
172 // usb->endpointSetInterrupt(bEP, false);
176 uint8_t c
[MAX_PACKET_SIZE_EPBULK
];
179 //we read the packet received and put it on the circular buffer
181 iprintf("Read %ld bytes:\n\t", size
);
182 for (uint8_t i
= 0; i
< size
; i
++) {
184 // handle backspace and delete by deleting the last character in the buffer if there is one
185 if(c
[i
] == 0x08 || c
[i
] == 0x7F) {
186 if(!rxbuf
.isEmpty()) rxbuf
.pop();
190 if(c
[i
] == 'X' - 'A' + 1) { // ^X
191 //THEKERNEL->set_feed_hold(false); // required to free stuff up
196 if(c
[i
] == '?') { // ?
201 if(THEKERNEL
->is_grbl_mode()) {
202 if(c
[i
] == '!') { // safe pause
203 //THEKERNEL->set_feed_hold(true);
207 if(c
[i
] == '~') { // safe resume
208 //THEKERNEL->set_feed_hold(false);
211 // if(last_char_was_dollar && (c[i] == 'X' || c[i] == 'H')) {
212 // // we need to do this otherwise $X/$H won't work if there was a feed hold like when stop is clicked in bCNC
213 // THEKERNEL->set_feed_hold(false);
217 last_char_was_dollar
= (c
[i
] == '$');
219 if (flush_to_nl
== false)
222 // if (c[i] >= 32 && c[i] < 128)
224 // iprintf("%c", c[i]);
228 // iprintf("\\x%02X", c[i]);
231 if (c
[i
] == '\n' || c
[i
] == '\r') {
236 } else if (rxbuf
.isFull() && (nl_in_rx
== 0)) {
237 // to avoid a deadlock with very long lines, we must dump the buffer
238 // and continue flushing to the next newline
243 iprintf("\nQueued, %d empty\n", rxbuf
.free());
245 if (rxbuf
.free() < MAX_PACKET_SIZE_EPBULK
) {
246 // if buffer is full, stall endpoint, do not accept more data
250 // we have to check for long line deadlock here too
254 // and since our buffer is empty, we can accept more data
259 usb
->readStart(CDC_BulkOut
.bEndpointAddress
, MAX_PACKET_SIZE_EPBULK
);
260 iprintf("USBSerial:EpOut Complete\n");
264 uint8_t USBSerial::available()
266 return rxbuf
.available();
269 bool USBSerial::ready()
271 return rxbuf
.available();
274 void USBSerial::on_module_loaded()
276 this->register_for_event(ON_MAIN_LOOP
);
277 this->register_for_event(ON_IDLE
);
280 void USBSerial::on_idle(void *argument
)
284 THEKERNEL
->call_event(ON_HALT
, nullptr);
285 if(THEKERNEL
->is_grbl_mode()) {
286 puts("ALARM:Abort during cycle\r\n");
288 puts("HALTED, M999 or $X to exit HALT state\r\n");
290 rxbuf
.flush(); // flush the recieve buffer, hopefully upstream has stopped sending
296 puts(THEKERNEL
->get_query_string().c_str());
301 void USBSerial::on_main_loop(void *argument
)
303 // apparently some OSes don't assert DTR when a program opens the port
304 if (available() && !attach
)
307 if (attach
!= attached
) {
310 THEKERNEL
->streams
->append_stream(this);
311 puts("Smoothie\r\nok\r\n");
314 THEKERNEL
->streams
->remove_stream(this);
321 // if we are in feed hold we do not process anything
322 //if(THEKERNEL->get_feed_hold()) return;
326 while (available()) {
328 if( c
== '\n' || c
== '\r') {
329 struct SerialMessage message
;
330 message
.message
= received
;
331 message
.stream
= this;
332 iprintf("USBSerial Received: %s\n", message
.message
.c_str());
333 THEKERNEL
->call_event(ON_CONSOLE_LINE_RECEIVED
, &message
);
342 void USBSerial::on_attach()
347 void USBSerial::on_detach()