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.
20 #include "USBCDCMSC.h"
21 #include "USBBusInterface.h"
22 #include "libs/SerialMessage.h"
24 #include "libs/RingBuffer.h"
26 static uint8_t cdc_line_coding
[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08};
28 #define DEFAULT_CONFIGURATION (1)
30 #define CDC_SET_LINE_CODING 0x20
31 #define CDC_GET_LINE_CODING 0x21
32 #define CDC_SET_CONTROL_LINE_STATE 0x22
33 #define CDC_SEND_BREAK 0x23
35 #define MAX_CDC_REPORT_SIZE MAX_PACKET_SIZE_EPBULK
42 #define WRITE_PROTECT 0x04
44 #define CBW_Signature 0x43425355
45 #define CSW_Signature 0x53425355
48 #define TEST_UNIT_READY 0x00
49 #define REQUEST_SENSE 0x03
50 #define FORMAT_UNIT 0x04
52 #define MODE_SELECT6 0x15
53 #define MODE_SENSE6 0x1A
54 #define START_STOP_UNIT 0x1B
55 #define MEDIA_REMOVAL 0x1E
56 #define READ_FORMAT_CAPACITIES 0x23
57 #define READ_CAPACITY 0x25
63 #define MODE_SELECT10 0x55
64 #define MODE_SENSE10 0x5A
66 // MSC class specific requests
67 #define MSC_REQUEST_RESET 0xFF
68 #define MSC_REQUEST_GET_MAX_LUN 0xFE
70 #define DEFAULT_CONFIGURATION (1)
73 #define MAX_PACKET MAX_PACKET_SIZE_EPBULK
83 USBCDCMSC::USBCDCMSC(SDFileSystem
*sd
, uint16_t vendor_id
, uint16_t product_id
, uint16_t product_release
): USBDevice(vendor_id
, product_id
, product_release
), cdcbuf(128), _sd(sd
) {
87 // USBDevice::connect();
91 bool USBCDCMSC::USBCallback_request(void) {
92 /* Called in ISR context */
95 CONTROL_TRANSFER
* transfer
= getTransferPtr();
96 static uint8_t maxLUN
[1] = {0};
98 /* Process class-specific requests */
100 if (transfer
->setup
.bmRequestType
.Type
== CLASS_TYPE
) {
101 switch (transfer
->setup
.bRequest
) {
102 case CDC_GET_LINE_CODING
:
103 transfer
->remaining
= 7;
104 transfer
->ptr
= cdc_line_coding
;
105 transfer
->direction
= DEVICE_TO_HOST
;
108 case CDC_SET_LINE_CODING
:
109 transfer
->remaining
= 7;
112 case CDC_SET_CONTROL_LINE_STATE
:
119 case MSC_REQUEST_RESET
:
123 case MSC_REQUEST_GET_MAX_LUN
:
124 transfer
->remaining
= 1;
125 transfer
->ptr
= maxLUN
;
126 transfer
->direction
= DEVICE_TO_HOST
;
138 // Called in ISR context
139 // Set configuration. Return false if the
140 // configuration is not supported.
141 bool USBCDCMSC::USBCallback_setConfiguration(uint8_t configuration
) {
142 if (configuration
!= DEFAULT_CONFIGURATION
) {
146 // Configure endpoints > 0
147 addEndpoint(EPINT_IN
, MAX_PACKET_SIZE_EPINT
);
148 addEndpoint(EPBULK_IN
, MAX_PACKET_SIZE_EPBULK
);
149 addEndpoint(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
151 // Configure endpoints > 0
152 addEndpoint(MSDBULK_IN
, MAX_PACKET_SIZE_MSDBULK
);
153 addEndpoint(MSDBULK_OUT
, MAX_PACKET_SIZE_MSDBULK
);
155 // We activate the endpoint to be able to recceive data
156 readStart(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
159 readStart(MSDBULK_OUT
, MAX_PACKET_SIZE_MSDBULK
);
163 bool USBCDCMSC::send(uint8_t * buffer
, uint16_t size
) {
164 return USBDevice::write(EPBULK_IN
, buffer
, size
, MAX_CDC_REPORT_SIZE
);
167 bool USBCDCMSC::readEP(uint8_t * buffer
, uint16_t * size
) {
168 if (!USBDevice::readEP(EPBULK_OUT
, buffer
, size
, MAX_CDC_REPORT_SIZE
))
170 if (!readStart(EPBULK_OUT
, MAX_CDC_REPORT_SIZE
))
175 bool USBCDCMSC::readEP_NB(uint8_t * buffer
, uint16_t * size
) {
176 if (!USBDevice::readEP_NB(EPBULK_OUT
, buffer
, size
, MAX_CDC_REPORT_SIZE
))
178 if (!readStart(EPBULK_OUT
, MAX_CDC_REPORT_SIZE
))
184 uint8_t * USBCDCMSC::deviceDesc() {
185 static uint8_t deviceDescriptor
[] = {
187 1, // bDescriptorType
188 0x10, 0x01, // bcdUSB
189 0xef, // bDeviceClass
190 0x02, // bDeviceSubClass
191 0x01, // bDeviceProtocol
192 MAX_PACKET_SIZE_EP0
, // bMaxPacketSize0
193 LSB(VENDOR_ID
), MSB(VENDOR_ID
), // idVendor
194 LSB(PRODUCT_ID
), MSB(PRODUCT_ID
),// idProduct
195 0x00, 0x01, // bcdDevice
199 1 // bNumConfigurations
201 return deviceDescriptor
;
204 uint8_t * USBCDCMSC::stringIinterfaceDesc() {
205 static uint8_t stringIinterfaceDescriptor
[] = {
208 'C',0,'D',0,'C',0,'M',0,'S',0,'C',0,
210 return stringIinterfaceDescriptor
;
213 uint8_t * USBCDCMSC::stringIproductDesc() {
214 static uint8_t stringIproductDescriptor
[] = {
217 'C',0,'D',0,'C',0,'M',0,'S',0,'C',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0
219 return stringIproductDescriptor
;
223 uint8_t * USBCDCMSC::configurationDesc() {
224 static uint8_t configDescriptor
[] = {
226 2, // bDescriptorType;
227 LSB(0x62), // wTotalLength
230 1, // bConfigurationValue
232 0xc0, // bmAttributes
236 // 0x08, 0x0B, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00,
237 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x01, 0x00,
239 // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
241 4, // bDescriptorType
242 0, // bInterfaceNumber
243 0, // bAlternateSetting
245 0x02, // bInterfaceClass
246 0x02, // bInterfaceSubClass
247 0x01, // bInterfaceProtocol
250 // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26
251 5, // bFunctionLength
252 0x24, // bDescriptorType
253 0x00, // bDescriptorSubtype
254 0x10, 0x01, // bcdCDC
256 // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27
257 5, // bFunctionLength
258 0x24, // bDescriptorType
259 0x01, // bDescriptorSubtype
260 0x03, // bmCapabilities
263 // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28
264 4, // bFunctionLength
265 0x24, // bDescriptorType
266 0x02, // bDescriptorSubtype
267 0x06, // bmCapabilities
269 // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33
270 5, // bFunctionLength
271 0x24, // bDescriptorType
272 0x06, // bDescriptorSubtype
273 0, // bMasterInterface
274 1, // bSlaveInterface0
276 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
277 ENDPOINT_DESCRIPTOR_LENGTH
, // bLength
278 ENDPOINT_DESCRIPTOR
, // bDescriptorType
279 PHY_TO_DESC(EPINT_IN
), // bEndpointAddress
280 E_INTERRUPT
, // bmAttributes (0x03=intr)
281 LSB(MAX_PACKET_SIZE_EPINT
), // wMaxPacketSize (LSB)
282 MSB(MAX_PACKET_SIZE_EPINT
), // wMaxPacketSize (MSB)
288 // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
290 4, // bDescriptorType
291 1, // bInterfaceNumber
292 0, // bAlternateSetting
294 0x0A, // bInterfaceClass
295 0x00, // bInterfaceSubClass
296 0x00, // bInterfaceProtocol
299 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
301 5, // bDescriptorType
302 PHY_TO_DESC(EPBULK_IN
), // bEndpointAddress
303 0x02, // bmAttributes (0x02=bulk)
304 LSB(MAX_PACKET_SIZE_EPBULK
), // wMaxPacketSize (LSB)
305 MSB(MAX_PACKET_SIZE_EPBULK
), // wMaxPacketSize (MSB)
308 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
310 5, // bDescriptorType
311 PHY_TO_DESC(EPBULK_OUT
),// bEndpointAddress
312 0x02, // bmAttributes (0x02=bulk)
313 LSB(MAX_PACKET_SIZE_EPBULK
), // wMaxPacketSize (LSB)
314 MSB(MAX_PACKET_SIZE_EPBULK
), // wMaxPacketSize (MSB)
317 // Interface 2, Alternate Setting 0, MSC Class
319 4, // bDescriptorType
320 0x02, // bInterfaceNumber
321 0x00, // bAlternateSetting
322 0x02, // bNumEndpoints
323 0x08, // bInterfaceClass
324 0x06, // bInterfaceSubClass
325 0x50, // bInterfaceProtocol
328 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
330 5, // bDescriptorType
331 PHY_TO_DESC(MSDBULK_IN
), // bEndpointAddress
332 0x02, // bmAttributes (0x02=bulk)
333 LSB(MAX_PACKET_SIZE_EPBULK
),// wMaxPacketSize (LSB)
334 MSB(MAX_PACKET_SIZE_EPBULK
),// wMaxPacketSize (MSB)
337 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
339 5, // bDescriptorType
340 PHY_TO_DESC(MSDBULK_OUT
), // bEndpointAddress
341 0x02, // bmAttributes (0x02=bulk)
342 LSB(MAX_PACKET_SIZE_EPBULK
),// wMaxPacketSize (LSB)
343 MSB(MAX_PACKET_SIZE_EPBULK
),// wMaxPacketSize (MSB)
346 return configDescriptor
;
349 int USBCDCMSC::_putc(int c
) {
350 send((uint8_t *)&c
, 1);
354 int USBCDCMSC::_getc() {
356 while (cdcbuf
.isEmpty());
362 bool USBCDCMSC::writeBlock(uint8_t * buf
, uint16_t size
) {
363 if(size
> MAX_PACKET_SIZE_EPBULK
) {
366 if(!send(buf
, size
)) {
374 bool USBCDCMSC::EP2_OUT_callback() {
378 //we read the packet received and put it on the circular buffer
380 for (int i
= 0; i
< size
; i
++) {
384 //call a potential handler
387 // We reactivate the endpoint to receive next characters
388 readStart(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
392 uint8_t USBCDCMSC::available() {
393 return cdcbuf
.available();
397 bool USBCDCMSC::connect() {
399 //disk initialization
400 if (disk_status() & NO_INIT
) {
401 if (disk_initialize()) {
406 // get number of blocks
407 BlockCount
= disk_sectors();
410 MemorySize
= disk_size();
412 if (BlockCount
>= 0) {
413 BlockSize
= MemorySize
/ BlockCount
;
414 if (BlockSize
!= 0) {
415 page
= (uint8_t *)malloc(BlockSize
* sizeof(uint8_t));
424 // USBDevice::connect();
429 void USBCDCMSC::reset() {
434 // Called in ISR context called when a data is received
435 bool USBCDCMSC::EP5_OUT_callback() {
437 uint8_t buf
[MAX_PACKET_SIZE_EPBULK
];
438 USBDevice::readEP(MSDBULK_OUT
, buf
, &size
, MAX_PACKET_SIZE_EPBULK
);
440 // the device has to decode the CBW received
442 CBWDecode(buf
, size
);
445 // the device has to receive data from the host
450 memoryWrite(buf
, size
);
453 memoryVerify(buf
, size
);
458 // an error has occured: stall endpoint and send CSW
460 stallEndpoint(MSDBULK_OUT
);
461 csw
.Status
= CSW_ERROR
;
466 //reactivate readings on the OUT bulk endpoint
467 readStart(MSDBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
471 // Called in ISR context when a data has been transferred
472 bool USBCDCMSC::EP5_IN_callback() {
475 // the device has to send data to the host
485 //the device has to send a CSW
490 // an error has occured
492 stallEndpoint(MSDBULK_IN
);
496 // the host has received the CSW -> we wait a CBW
505 void USBCDCMSC::memoryWrite (uint8_t * buf
, uint16_t size
) {
507 if ((addr
+ size
) > MemorySize
) {
508 size
= MemorySize
- addr
;
510 stallEndpoint(MSDBULK_OUT
);
513 // we fill an array in RAM of 1 block before writing it in memory
514 for (int i
= 0; i
< size
; i
++)
515 page
[addr
%BlockSize
+ i
] = buf
[i
];
517 // if the array is filled, write it in memory
518 if (!((addr
+ size
)%BlockSize
)) {
519 if (!(disk_status() & WRITE_PROTECT
)) {
520 disk_write((const char *)page
, addr
/BlockSize
);
526 csw
.DataResidue
-= size
;
528 if ((!length
) || (stage
!= PROCESS_CBW
)) {
529 csw
.Status
= (stage
== ERROR
) ? CSW_FAILED
: CSW_PASSED
;
534 void USBCDCMSC::memoryVerify (uint8_t * buf
, uint16_t size
) {
537 if ((addr
+ size
) > MemorySize
) {
538 size
= MemorySize
- addr
;
540 stallEndpoint(MSDBULK_OUT
);
543 // beginning of a new block -> load a whole block in RAM
544 if (!(addr
%BlockSize
))
545 disk_read((char *)page
, addr
/BlockSize
);
547 // info are in RAM -> no need to re-read memory
548 for (n
= 0; n
< size
; n
++) {
549 if (page
[addr
%BlockSize
+ n
] != buf
[n
]) {
557 csw
.DataResidue
-= size
;
559 if ( !length
|| (stage
!= PROCESS_CBW
)) {
560 csw
.Status
= (memOK
&& (stage
== PROCESS_CBW
)) ? CSW_PASSED
: CSW_FAILED
;
566 bool USBCDCMSC::inquiryRequest (void) {
567 uint8_t inquiry
[] = { 0x00, 0x80, 0x00, 0x01,
568 36 - 4, 0x80, 0x00, 0x00,
569 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G',
570 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ',
573 if (!msd_write(inquiry
, sizeof(inquiry
))) {
580 bool USBCDCMSC::readFormatCapacity() {
581 uint8_t capacity
[] = { 0x00, 0x00, 0x00, 0x08,
582 (BlockCount
>> 24) & 0xff,
583 (BlockCount
>> 16) & 0xff,
584 (BlockCount
>> 8) & 0xff,
585 (BlockCount
>> 0) & 0xff,
588 (BlockSize
>> 16) & 0xff,
589 (BlockSize
>> 8) & 0xff,
590 (BlockSize
>> 0) & 0xff,
592 if (!msd_write(capacity
, sizeof(capacity
))) {
599 bool USBCDCMSC::readCapacity (void) {
600 uint8_t capacity
[] = {
601 ((BlockCount
- 1) >> 24) & 0xff,
602 ((BlockCount
- 1) >> 16) & 0xff,
603 ((BlockCount
- 1) >> 8) & 0xff,
604 ((BlockCount
- 1) >> 0) & 0xff,
606 (BlockSize
>> 24) & 0xff,
607 (BlockSize
>> 16) & 0xff,
608 (BlockSize
>> 8) & 0xff,
609 (BlockSize
>> 0) & 0xff,
611 if (!msd_write(capacity
, sizeof(capacity
))) {
617 bool USBCDCMSC::msd_write (uint8_t * buf
, uint16_t size
) {
619 if (size
>= cbw
.DataLength
) {
620 size
= cbw
.DataLength
;
624 if (!writeNB(MSDBULK_IN
, buf
, size
, MAX_PACKET_SIZE_EPBULK
)) {
628 csw
.DataResidue
-= size
;
629 csw
.Status
= CSW_PASSED
;
634 bool USBCDCMSC::modeSense6 (void) {
635 uint8_t sense6
[] = { 0x03, 0x00, 0x00, 0x00 };
636 if (!msd_write(sense6
, sizeof(sense6
))) {
642 void USBCDCMSC::sendCSW() {
643 csw
.Signature
= CSW_Signature
;
644 writeNB(MSDBULK_IN
, (uint8_t *)&csw
, sizeof(CSW
), MAX_PACKET_SIZE_EPBULK
);
648 bool USBCDCMSC::requestSense (void) {
649 uint8_t request_sense
[] = {
652 0x05, // Sense Key: illegal request
670 if (!msd_write(request_sense
, sizeof(request_sense
))) {
677 void USBCDCMSC::fail() {
678 csw
.Status
= CSW_FAILED
;
683 void USBCDCMSC::CBWDecode(uint8_t * buf
, uint16_t size
) {
684 if (size
== sizeof(cbw
)) {
685 memcpy((uint8_t *)&cbw
, buf
, size
);
686 if (cbw
.Signature
== CBW_Signature
) {
688 csw
.DataResidue
= cbw
.DataLength
;
689 if ((cbw
.CBLength
< 1) || (cbw
.CBLength
> 16) ) {
693 case TEST_UNIT_READY
:
705 case READ_FORMAT_CAPACITIES
:
706 readFormatCapacity();
713 if (infoTransfer()) {
714 if ((cbw
.Flags
& 0x80)) {
718 stallEndpoint(MSDBULK_OUT
);
719 csw
.Status
= CSW_ERROR
;
726 if (infoTransfer()) {
727 if (!(cbw
.Flags
& 0x80)) {
730 stallEndpoint(MSDBULK_IN
);
731 csw
.Status
= CSW_ERROR
;
737 if (!(cbw
.CB
[1] & 0x02)) {
738 csw
.Status
= CSW_PASSED
;
742 if (infoTransfer()) {
743 if (!(cbw
.Flags
& 0x80)) {
747 stallEndpoint(MSDBULK_IN
);
748 csw
.Status
= CSW_ERROR
;
762 void USBCDCMSC::testUnitReady (void) {
764 if (cbw
.DataLength
!= 0) {
765 if ((cbw
.Flags
& 0x80) != 0) {
766 stallEndpoint(MSDBULK_IN
);
768 stallEndpoint(MSDBULK_OUT
);
772 csw
.Status
= CSW_PASSED
;
777 void USBCDCMSC::memoryRead (void) {
780 n
= (length
> MAX_PACKET
) ? MAX_PACKET
: length
;
782 if ((addr
+ n
) > MemorySize
) {
783 n
= MemorySize
- addr
;
787 // we read an entire block
788 if (!(addr
%BlockSize
))
789 disk_read((char *)page
, addr
/BlockSize
);
791 // write data which are in RAM
792 writeNB(MSDBULK_IN
, &page
[addr
%BlockSize
], n
, MAX_PACKET_SIZE_EPBULK
);
797 csw
.DataResidue
-= n
;
799 if ( !length
|| (stage
!= PROCESS_CBW
)) {
800 csw
.Status
= (stage
== PROCESS_CBW
) ? CSW_PASSED
: CSW_FAILED
;
801 stage
= (stage
== PROCESS_CBW
) ? SEND_CSW
: stage
;
806 bool USBCDCMSC::infoTransfer (void) {
809 // Logical Block Address of First Block
810 n
= (cbw
.CB
[2] << 24) | (cbw
.CB
[3] << 16) | (cbw
.CB
[4] << 8) | (cbw
.CB
[5] << 0);
812 addr
= n
* BlockSize
;
814 // Number of Blocks to transfer
819 n
= (cbw
.CB
[7] << 8) | (cbw
.CB
[8] << 0);
824 n
= (cbw
.CB
[6] << 24) | (cbw
.CB
[7] << 16) | (cbw
.CB
[8] << 8) | (cbw
.CB
[9] << 0);
828 length
= n
* BlockSize
;
830 if (!cbw
.DataLength
) { // host requests no data
831 csw
.Status
= CSW_FAILED
;
836 if (cbw
.DataLength
!= length
) {
837 if ((cbw
.Flags
& 0x80) != 0) {
838 stallEndpoint(MSDBULK_IN
);
840 stallEndpoint(MSDBULK_OUT
);
843 csw
.Status
= CSW_FAILED
;
851 int USBCDCMSC::isBreak () {
857 int USBCDCMSC::disk_initialize() {
858 if (_sd
->disk_initialize()) {
867 int USBCDCMSC::disk_write(const char *buffer
, int block_number
) {
868 return _sd
->disk_write(buffer
, block_number
);
871 int USBCDCMSC::disk_read(char *buffer
, int block_number
) {
872 return _sd
->disk_read(buffer
, block_number
);
875 int USBCDCMSC::disk_status() {
879 int USBCDCMSC::disk_sectors() {
880 return _sd
->disk_sectors();
882 int USBCDCMSC::disk_size() {
883 return _sd
->disk_sectors() * 512;
887 void USBCDCMSC::on_module_loaded(){
888 // We want to be called every time a new char is received
889 this->attach(this, &USBCDCMSC::on_serial_char_received
);
891 // We only call the command dispatcher in the main loop, nowhere else
892 this->register_for_event(ON_MAIN_LOOP
);
895 void USBCDCMSC::on_main_loop(void* argument
){
896 //if( this->configured() ){
897 // this->kernel->serial->printf("a:%d\r\n", this->buffer.size());
899 if( this->has_char('\n') ){
904 this->buffer
.pop_front(c
);
906 struct SerialMessage message
;
907 message
.message
= received
;
908 message
.stream
= this;
909 this->kernel
->call_event(ON_CONSOLE_LINE_RECEIVED
, &message
);
910 //this->kernel->serial->printf("received: %s \r\n", received.c_str() );
911 //this->printf("received: %s\r\n", received.c_str() );
922 void USBCDCMSC::on_serial_char_received(){
923 if(this->available()){
924 char received
= this->getc();
925 //On newline, we have received a line, else concatenate in buffer
926 if( received
== '\r' ){ return; }
927 //if( this->kernel != NULL ){
928 // this->kernel->serial->printf("received:%c\r\n", received);
930 this->buffer
.push_back(received
);
938 bool USBCDCMSC::has_char(char letter
){
939 int index
= this->buffer
.head
;
940 while( index
!= this->buffer
.tail
){
941 if( this->buffer
.buffer
[index
] == letter
){
944 index
= this->buffer
.next_block_index(index
);