ISP example program.
Dependencies: SLCD mbed USBLocalFileSystem
FRDM-KL46Z | LPC810 | |
---|---|---|
UART RXD | PTE23 | p2(P0_4) |
UART TXD | PTE22 | p8(P0_0) |
nRESET | D6 | p1(P0_5) |
nISP | D8 | p5(P0_1) |
GND | GND | p7 |
3.3V | P3V3 | p6 |
Copy binary image to the disk called LPC81ISP.
Push sw1 or sw3, start write to LPC810 flash.
Revision 1:cccfc461c61f, committed 2014-02-16
- Comitter:
- va009039
- Date:
- Sun Feb 16 12:56:12 2014 +0000
- Parent:
- 0:ad2b1fc04955
- Child:
- 2:eafc1c6787c7
- Commit message:
- add virtual COM.
Changed in this revision
--- a/USBDevice.lib Sat Feb 15 10:15:42 2014 +0000 +++ b/USBDevice.lib Sun Feb 16 12:56:12 2014 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/va009039/code/USBDevice/#1ad500eb1e69 +http://mbed.org/users/va009039/code/USBDevice/#6dcb8023e437
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/DiskInterface.h Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,49 @@ +// DiskInterface.h 2013/9/21 +#pragma once + +class DiskInterface { +public: + /* + * read a block on a storage chip + * + * @param data pointer where will be stored read data + * @param block block number + * @returns 0 if successful + */ + virtual int disk_read(uint8_t * data, uint64_t block) = 0; + + /* + * write a block on a storage chip + * + * @param data data to write + * @param block block number + * @returns 0 if successful + */ + virtual int disk_write(const uint8_t * data, uint64_t block) = 0; + + /* + * Disk initilization + */ + virtual int disk_initialize() = 0; + + /* + * Return the number of blocks + * + * @returns number of blocks + */ + virtual uint64_t disk_sectors() = 0; + + /* + * Return memory size + * + * @returns memory size + */ + virtual uint64_t disk_size() = 0; + + /* + * To check the status of the storage chip + * + * @returns status: 0: OK, 1: disk not initialized, 2: no medium in the drive, 4: write protected + */ + virtual int disk_status() = 0; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/SerialInterface.h Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,15 @@ +// SerialInterface.h 2013/9/22 +#pragma once + +class SerialInterface { +public: + /** virtual COM to target + */ + virtual void serial_send_to_target(int c) = 0; + + /** target to virtual COM + */ + virtual int serial_send_to_virtual_com(int c); + + virtual void serial_break(); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USBMSD2.cpp Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,349 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "stdint.h" +#include "USBMSD2.h" +#include "USB_MSD.h" +#include "USB_CDC.h" +#include "USB_HID.h" + +#if (DEBUG2 > 3) +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +#else +#define USB_DBG(...) while(0) +#endif + +#define DEFAULT_CONFIGURATION (1) + +USBMSD2::USBMSD2(uint16_t vendor_id, uint16_t product_id, uint16_t product_release) + : USBDevice(vendor_id, product_id, product_release) +{ + USB_DBG("%p vid=%04x pid=%04x", this, vendor_id, product_id); + + _msd = new USB_MSD(this, this); + _cdc = new USB_CDC(this); + _hid = new USB_HID(this); +} + +USBMSD2::~USBMSD2() { + _msd->disconnect(); + USBDevice::disconnect(); +} + +void USBMSD2::putc(int c) +{ + _cdc->putc(c); +} + +int USBMSD2::getc() +{ + return _cdc->getc(); +} + +int USBMSD2::readable() +{ + return _cdc->readable(); +} + +int USBMSD2::writeable() +{ + return _cdc->writeable(); +} + +bool USBMSD2::readNB(HID_REPORT* report) +{ + return _hid->readNB(report); +} + +bool USBMSD2::send(HID_REPORT* report) +{ + return _hid->send(report); +} + +bool USBMSD2::connect() +{ + if (_msd->connect()) { + USBDevice::connect(); + return true; + } + return false; +} + +// Called in ISR context to process a class specific request +bool USBMSD2::USBCallback_request(void) { + CONTROL_TRANSFER* transfer = getTransferPtr(); + if (_msd->Request_callback(transfer)) { + return true; + } + if (_cdc->Request_callback(transfer)) { + return true; + } + // Find the HID descriptor, after the configuration descriptor + uint8_t* hidDescriptor = findDescriptor(HID_DESCRIPTOR); + if (_hid->Request_callback(transfer, hidDescriptor)) { + return true; + } + return false; +} + +/* virtual */ void USBMSD2::USBCallback_requestCompleted(uint8_t* buf, uint32_t length) +{ + CONTROL_TRANSFER* transfer = getTransferPtr(); + if (_cdc->RequestCompleted_callback(transfer, buf, length)) { + return; + } +} + +// Called in ISR context +// Set configuration. Return false if the +// configuration is not supported. +bool USBMSD2::USBCallback_setConfiguration(uint8_t configuration) { + if (configuration != DEFAULT_CONFIGURATION) { + return false; + } + + // Configure endpoints > 0 + addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK); + addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + + addEndpoint(CDC_EPINT_IN, MAX_PACKET_SIZE_EPINT); + addEndpoint(CDC_EPBULK_IN, MAX_PACKET_SIZE_EPBULK); + addEndpoint(CDC_EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + addEndpoint(HID_EPINT_IN, MAX_PACKET_SIZE_EPINT); + addEndpoint(HID_EPINT_OUT, MAX_PACKET_SIZE_EPINT); + + //activate readings + readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + readStart(CDC_EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + readStart(HID_EPINT_OUT, MAX_PACKET_SIZE_EPINT); + + return true; +} + +/* virtual */ bool USBMSD2::EP2_OUT_callback() +{ + return _msd->EPBULK_OUT_callback(); +} + +/* virtual */ bool USBMSD2::EP2_IN_callback() { + return _msd->EPBULK_IN_callback(); +} + +/* virtual */ bool USBMSD2::EP3_OUT_callback() +{ + return _cdc->EPBULK_OUT_callback(); +} + +/* virtual */ bool USBMSD2::EP5_OUT_callback() +{ + return _cdc->EPBULK_OUT_callback(); +} + +uint8_t * USBMSD2::deviceDesc() { + static uint8_t deviceDescriptor[] = { + 18, // bLength + 1, // bDescriptorType + 0x10, 0x01, // bcdUSB + 2, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol + MAX_PACKET_SIZE_EP0, // bMaxPacketSize0 + (uint8_t)(LSB(VENDOR_ID)), (uint8_t)(MSB(VENDOR_ID)), // idVendor + (uint8_t)(LSB(PRODUCT_ID)), (uint8_t)(MSB(PRODUCT_ID)),// idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 3, // iSerialNumber + 1 // bNumConfigurations + }; + return deviceDescriptor; +} + +uint8_t * USBMSD2::stringIinterfaceDesc() { + static uint8_t stringIinterfaceDescriptor[] = { + 0x08, //bLength + STRING_DESCRIPTOR, //bDescriptorType 0x03 + 'H',0,'I',0,'D',0, //bString iInterface - HID + }; + return stringIinterfaceDescriptor; +} + +uint8_t * USBMSD2::stringIproductDesc() { + static uint8_t stringIproductDescriptor[] = { + 32, //bLength + STRING_DESCRIPTOR, //bDescriptorType 0x03 + 'K',0,'L',0,'2',0,'5',0,'Z',0,' ',0,'C',0,'M',0,'S',0,'I',0,'S',0,'-',0,'D',0,'A',0,'P',0 // KL25Z CMSIS-DAP + }; + return stringIproductDescriptor; +} + +uint8_t * USBMSD2::configurationDesc() { + static uint8_t configDescriptor[] = { + // Configuration 1 + 9, // bLength + 2, // bDescriptorType + LSB(122), // wTotalLength + MSB(122), + 4, // bNumInterfaces + 1, // bConfigurationValue: 0x01 is used to select this configuration + 0x00, // iConfiguration: no string to describe this configuration + 0x80, // bmAttributes + 250, // bMaxPower, device power consumption is 100 mA + + // Interface 0, Alternate Setting 0, MSC Class + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 0, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x08, // bInterfaceClass + 0x06, // bInterfaceSubClass + 0x50, // bInterfaceProtocol + 0x04, // iInterface + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPBULK_IN), // bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPBULK_OUT), // bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 1, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0, // iInterface + + // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x00, // bDescriptorSubtype + 0x10, 0x01, // bcdCDC + + // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x01, // bDescriptorSubtype + 0x03, // bmCapabilities + 2, // bDataInterface + + // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 + 4, // bFunctionLength + 0x24, // bDescriptorType + 0x02, // bDescriptorSubtype + 0x06, // bmCapabilities + + // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x06, // bDescriptorSubtype + 1, // bMasterInterface + 2, // bSlaveInterface0 + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(CDC_EPINT_IN), // bEndpointAddress + E_INTERRUPT, // bmAttributes (0x03=intr) + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 2, // bInterval + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 2, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(CDC_EPBULK_IN), // bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(CDC_EPBULK_OUT),// bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 3, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + HID_CLASS, // bInterfaceClass + HID_SUBCLASS_NONE, // bInterfaceSubClass + HID_PROTOCOL_NONE, // bInterfaceProtocol + 0, // iInterface + + HID_DESCRIPTOR_LENGTH, // bLength + HID_DESCRIPTOR, // bDescriptorType + LSB(HID_VERSION_1_11), // bcdHID (LSB) + MSB(HID_VERSION_1_11), // bcdHID (MSB) + 0x00, // bCountryCode + 1, // bNumDescriptors + REPORT_DESCRIPTOR, // bDescriptorType + LSB(_hid->reportDescLength()), // wDescriptorLength (LSB) + MSB(_hid->reportDescLength()), // wDescriptorLength (MSB) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(HID_EPINT_IN), // bEndpointAddress + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(HID_EPINT_OUT), // bEndpointAddress + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + }; + return configDescriptor; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USBMSD2.h Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,175 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +/* These headers are included for child class. */ +#include "USBDescriptor.h" +#include "USBDevice_Types.h" +#include "USBHID_Types.h" +#include "USBDevice.h" +#include "DiskInterface.h" + +/** + * USBMSD2 class: generic class in order to use all kinds of blocks storage chip + * + * Introduction + * + * The USBMSD implements the MSD protocol. It permits to access a memory chip (flash, sdcard,...) + * from a computer over USB. But this class doesn't work standalone, you need to subclass this class + * and define virtual functions which are called in USBMSD. + * + * How to use this class with your chip ? + * + * You have to inherit and define some pure virtual functions (mandatory step): + * - virtual int disk_read(char * data, int block): function to read a block + * - virtual int disk_write(const char * data, int block): function to write a block + * - virtual int disk_initialize(): function to initialize the memory + * - virtual int disk_sectors(): return the number of blocks + * - virtual int disk_size(): return the memory size + * - virtual int disk_status(): return the status of the storage chip (0: OK, 1: not initialized, 2: no medium in the drive, 4: write protection) + * + * All functions names are compatible with the fat filesystem library. So you can imagine using your own class with + * USBMSD and the fat filesystem library in the same program. Just be careful because there are two different parts which + * will access the sd card. You can do a master/slave system using the disk_status method. + * + * Once these functions defined, you can call connect() (at the end of the constructor of your class for instance) + * of USBMSD to connect your mass storage device. connect() will first call disk_status() to test the status of the disk. + * If disk_status() returns 1 (disk not initialized), then disk_initialize() is called. After this step, connect() will collect information + * such as the number of blocks and the memory size. + */ +class USB_MSD; +class USB_CDC; +class USB_HID; + +class USBMSD2: public DiskInterface, public USBDevice { +public: + /** + * Constructor + * + * @param vendor_id Your vendor_id + * @param product_id Your product_id + * @param product_release Your preoduct_release + */ + USBMSD2(uint16_t vendor_id = 0x0d28, uint16_t product_id = 0x0204, uint16_t product_release = 0x0001); + + /** + * Connect the USB MSD device. Establish disk initialization before really connect the device. + * + * @returns true if successful + */ + bool connect(); + + /** + * Disconnect the USB MSD device. + */ + void disconnect(); + + /** + * Destructor + */ + ~USBMSD2(); + + /** target to virtual COM + */ + void putc(int c); + + /** virtial COM to target + */ + int getc(); + int readable(); + int writeable(); + + + /** + * Read a report: non blocking + * + * @param report pointer to the report to fill + * @returns true if successful + */ + bool readNB(HID_REPORT* report); + + /** + * Send a Report. warning: blocking + * + * @param report Report which will be sent (a report is defined by all data and the length) + * @returns true if successful + */ + bool send(HID_REPORT* report); + +protected: + /* + * Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength. + * + * @returns pointer to the device descriptor + */ + virtual uint8_t * deviceDesc(); + + /* + * Get string product descriptor + * + * @returns pointer to the string product descriptor + */ + virtual uint8_t * stringIproductDesc(); + + /* + * Get string interface descriptor + * + * @returns pointer to the string interface descriptor + */ + virtual uint8_t * stringIinterfaceDesc(); + + /* + * Get configuration descriptor + * + * @returns pointer to the configuration descriptor + */ + virtual uint8_t * configurationDesc(); + + virtual bool EP2_OUT_callback(); // MSC Callback called when a packet is received + virtual bool EP2_IN_callback(); // MSC Callback called when a packet has been sent + virtual bool EP3_OUT_callback(); // CDC Callback called when a packet is received + virtual bool EP5_OUT_callback(); // CDC Callback called when a packet is received + + /* + * Set configuration of device. Add endpoints + */ + virtual bool USBCallback_setConfiguration(uint8_t configuration); + + /* + * Callback called to process class specific requests + */ + virtual bool USBCallback_request(); + + /* + * Called by USBDevice on Endpoint0 request completion + * if the 'notify' flag has been set to true. Warning: Called in ISR context + * + * In this case it is used to indicate that a HID report has + * been received from the host on endpoint 0 + * + * @param buf buffer received on endpoint 0 + * @param length length of this buffer + */ + virtual void USBCallback_requestCompleted(uint8_t * buf, uint32_t length); + +private: + USB_MSD* _msd; + USB_CDC* _cdc; + USB_HID* _hid; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USB_CDC.cpp Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,172 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "USB_CDC.h" + +#if (DEBUG2 > 3) +#define CDC_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +#define CDC_DBG_HEX(A,B) while(0); +#else +#define CDC_DBG(...) while(0) +#define CDC_DBG_HEX(A,B) while(0) +#endif + +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 +#define CDC_SEND_BREAK 0x23 + +#define MAX_CDC_REPORT_SIZE MAX_PACKET_SIZE_EPBULK + +USB_CDC::USB_CDC(USBDevice* device) : _device(device), _rx_buf(128) +{ + CDC_DBG("device=%p", device); + + terminal_connected = false; + //USBDevice::connect(); +} + +void USB_CDC::putc(int c) +{ + if (terminal_connected) { + uint8_t buf[1]; + buf[0] = c; + _device->write(CDC_EPBULK_IN, buf, sizeof(buf), MAX_CDC_REPORT_SIZE); + } +} + +int USB_CDC::getc() +{ + uint8_t c = 0; + while (_rx_buf.isEmpty()); + _rx_buf.dequeue(&c); + return c; +} + +int USB_CDC::readable() +{ + return _rx_buf.available() > 0 ? 1 : 0; +} + +int USB_CDC::writeable() +{ + return 1; +} + +void USB_CDC::baud_callback(int baudrate) +{ + CDC_DBG("baudrate=%d", baudrate); +} + +void USB_CDC::send_break_callback(uint16_t duration) +{ + CDC_DBG("duration=%04x", duration); +} + +void USB_CDC::control_line_callback(int rts, int dtr) +{ + CDC_DBG("rts=%d, dtr=%d", rts, dtr); +} + +bool USB_CDC::send(uint8_t * buffer, uint32_t size) { + return _device->write(CDC_EPBULK_IN, buffer, size, MAX_CDC_REPORT_SIZE); +} + +bool USB_CDC::readEP(uint8_t * buffer, uint32_t * size) { + if (!_device->readEP(CDC_EPBULK_OUT, buffer, size, MAX_CDC_REPORT_SIZE)) + return false; + if (!_device->readStart(CDC_EPBULK_OUT, MAX_CDC_REPORT_SIZE)) + return false; + return true; +} + +bool USB_CDC::readEP_NB(uint8_t * buffer, uint32_t * size) { + if (!_device->readEP_NB(CDC_EPBULK_OUT, buffer, size, MAX_CDC_REPORT_SIZE)) + return false; + if (!_device->readStart(CDC_EPBULK_OUT, MAX_CDC_REPORT_SIZE)) + return false; + return true; +} + +bool USB_CDC::Request_callback(CONTROL_TRANSFER* transfer) +{ + static uint8_t cdc_line_coding[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08}; + + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { + switch (transfer->setup.bRequest) { + case CDC_SET_LINE_CODING: // 0x20 + transfer->remaining = 7; + transfer->notify = true; + terminal_connected = true; + return true; + + case CDC_GET_LINE_CODING: // x021 + transfer->remaining = 7; + transfer->ptr = cdc_line_coding; + transfer->direction = DEVICE_TO_HOST; + return true; + + case CDC_SET_CONTROL_LINE_STATE: // 0x22 + control_line_callback((transfer->setup.wValue>>1) & 1, (transfer->setup.wValue) & 1); + terminal_connected = false; + return true; + + case CDC_SEND_BREAK: // 0x23 + send_break_callback(transfer->setup.wValue); + return true; + } + } + return false; +} + +static uint32_t LD32(uint8_t* buf) +{ + return buf[0]|(buf[1]<<8)|(buf[2]<<16)|(buf[3]<<24); +} + +bool USB_CDC::RequestCompleted_callback(CONTROL_TRANSFER* transfer, uint8_t* buf, int length) +{ + CDC_DBG("transer=%p", transfer); + int baudrate; + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { + switch (transfer->setup.bRequest) { + case CDC_SET_LINE_CODING: // 0x20 + baudrate = LD32(buf); + baud_callback(baudrate); + return true; + } + } + CDC_DBG_HEX((uint8_t*)transfer, sizeof(CONTROL_TRANSFER)); + return false; +} + +bool USB_CDC::EPBULK_OUT_callback() // virtual COM to target +{ + uint8_t buf[MAX_CDC_REPORT_SIZE]; + uint32_t size = 0; + //we read the packet received and put it on the circular buffer + _device->readEP(CDC_EPBULK_OUT, buf, &size, MAX_CDC_REPORT_SIZE); + CDC_DBG("size=%d", size); + for(int i = 0; i < size; i++) { + _rx_buf.queue(buf[i]); + } + + // We reactivate the endpoint to receive next characters + _device->readStart(CDC_EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USB_CDC.h Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,100 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include "USBDevice.h" +#include "CircBuffer.h" + +#if defined(TARGET_LPC1768) +#define CDC_EPINT_IN EP1IN +#define CDC_EPBULK_IN EP5IN +#define CDC_EPBULK_OUT EP5OUT +#elif defined(TARGET_LPC1347) +#define CDC_EPINT_IN EP1IN +#define CDC_EPBULK_IN EP3IN +#define CDC_EPBULK_OUT EP3OUT +#elif defined(TARGET_KL25Z)||defined(TARGET_KL46Z) +#define CDC_EPINT_IN EP1IN +#define CDC_EPBULK_IN EP5IN +#define CDC_EPBULK_OUT EP5OUT +#else +#error "target type error" +#endif + +class USB_CDC { +public: + USB_CDC(USBDevice* device); + + /** target to virtual COM + */ + void putc(int c); + + /** virtial COM to target + */ + int getc(); + + int readable(); + + int writeable(); + + void baud_callback(int baudrate); + void send_break_callback(uint16_t duration); + void control_line_callback(int rts, int dtr); + + /* + * Send a buffer + * + * @param endpoint endpoint which will be sent the buffer + * @param buffer buffer to be sent + * @param size length of the buffer + * @returns true if successful + */ + bool send(uint8_t * buffer, uint32_t size); + + /* + * Read a buffer from a certain endpoint. Warning: blocking + * + * @param endpoint endpoint to read + * @param buffer buffer where will be stored bytes + * @param size the number of bytes read will be stored in *size + * @param maxSize the maximum length that can be read + * @returns true if successful + */ + bool readEP(uint8_t * buffer, uint32_t * size); + + /* + * Read a buffer from a certain endpoint. Warning: non blocking + * + * @param endpoint endpoint to read + * @param buffer buffer where will be stored bytes + * @param size the number of bytes read will be stored in *size + * @param maxSize the maximum length that can be read + * @returns true if successful + */ + bool readEP_NB(uint8_t * buffer, uint32_t * size); + + bool Request_callback(CONTROL_TRANSFER* transfer); + bool RequestCompleted_callback(CONTROL_TRANSFER* transfer, uint8_t* buf, int length); + bool EPBULK_OUT_callback(); + +private: + USBDevice* _device; + CircBuffer<uint8_t> _rx_buf; + volatile bool terminal_connected; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USB_HID.cpp Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,142 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "USB_HID.h" + +#if (DEBUG2 > 3) +#define HID_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +#else +#define HID_DBG(...) while(0) +#endif + +USB_HID::USB_HID(USBDevice* device, uint8_t output_report_length, uint8_t input_report_length) : _device(device) +{ + HID_DBG("device=%p", device); + + output_length = output_report_length; + input_length = input_report_length; +} + +bool USB_HID::send(HID_REPORT *report) +{ + return _device->write(HID_EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE); +} + +bool USB_HID::sendNB(HID_REPORT *report) +{ + return _device->writeNB(HID_EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE); +} + +bool USB_HID::read(HID_REPORT *report) +{ + uint32_t bytesRead = 0; + bool result; + result = _device->readEP(HID_EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE); + if(!_device->readStart(HID_EPINT_OUT, MAX_HID_REPORT_SIZE)) + return false; + report->length = bytesRead; + return result; +} + +bool USB_HID::readNB(HID_REPORT *report) +{ + uint32_t bytesRead = 0; + bool result; + result = _device->readEP_NB(HID_EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE); + report->length = bytesRead; + if(!_device->readStart(HID_EPINT_OUT, MAX_HID_REPORT_SIZE)) + return false; + return result; +} + +/* virtual */ uint8_t * USB_HID::reportDesc() { + static uint8_t reportDescriptor[] = { + 0x06, 0x00, 0xff, + 0x09, 0x01, // usage + 0xA1, 0x01, // Collection 0x01 + 0x15, 0x00, // logical minimum = 0 + 0x26, 0xFF, 0x00, // logical maximum = 255 + 0x75, 0x08, // report size = 8 bits + 0x95, 0x40, // report count + 0x09, 0x01, // usage + 0x81, 0x02, // Input (array) + 0x95, 0x40, // report count + 0x09, 0x01, // usage + 0x91, 0x02, // Output (array) + 0x95, 0x01, // report count + 0x09, 0x01, // usage + 0xb1, 0x02, + 0xC0 // end collection + }; + reportLength = sizeof(reportDescriptor); + return reportDescriptor; +} + +/* virtual */ uint16_t USB_HID::reportDescLength() { + reportDesc(); + return reportLength; +} + +bool USB_HID::Request_callback(CONTROL_TRANSFER* transfer, uint8_t* hidDescriptor) +{ + // Process additional standard requests + if (transfer->setup.bmRequestType.Type == STANDARD_TYPE) { + switch (transfer->setup.bRequest) { + case GET_DESCRIPTOR: + switch (DESCRIPTOR_TYPE(transfer->setup.wValue)) { + case REPORT_DESCRIPTOR: + if ((reportDesc() != NULL) && (reportDescLength() != 0)) { + transfer->remaining = reportDescLength(); + transfer->ptr = reportDesc(); + transfer->direction = DEVICE_TO_HOST; + return true; + } + break; + case HID_DESCRIPTOR: + if (hidDescriptor != NULL) { + transfer->remaining = HID_DESCRIPTOR_LENGTH; + transfer->ptr = hidDescriptor; + transfer->direction = DEVICE_TO_HOST; + return true; + } + break; + default: + break; + } + break; + default: + break; + } + } + + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { + switch (transfer->setup.bRequest) { + case SET_REPORT: + // First byte will be used for report ID + outputReport.data[0] = transfer->setup.wValue & 0xff; + outputReport.length = transfer->setup.wLength + 1; + + transfer->remaining = sizeof(outputReport.data) - 1; + transfer->ptr = &outputReport.data[1]; + transfer->direction = HOST_TO_DEVICE; + transfer->notify = true; + return true; + } + } + return false; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USB_HID.h Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,97 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include "USBHID_Types.h" +#include "USBDevice.h" + +#define HID_EPINT_IN EP4IN +#define HID_EPINT_OUT EP4OUT + +/** USB HID device for CMSIS-DAP + */ +class USB_HID { +public: + + /** + * Constructor + * + * @param output_report_length Maximum length of a sent report (up to 64 bytes) (default: 64 bytes) + * @param input_report_length Maximum length of a received report (up to 64 bytes) (default: 64 bytes) + */ + USB_HID(USBDevice* device, uint8_t output_report_length = 64, uint8_t input_report_length = 64); + + + /** + * Send a Report. warning: blocking + * + * @param report Report which will be sent (a report is defined by all data and the length) + * @returns true if successful + */ + bool send(HID_REPORT *report); + + + /** + * Send a Report. warning: non blocking + * + * @param report Report which will be sent (a report is defined by all data and the length) + * @returns true if successful + */ + bool sendNB(HID_REPORT *report); + + /** + * Read a report: blocking + * + * @param report pointer to the report to fill + * @returns true if successful + */ + bool read(HID_REPORT * report); + + /** + * Read a report: non blocking + * + * @param report pointer to the report to fill + * @returns true if successful + */ + bool readNB(HID_REPORT * report); + + /* + * Get the length of the report descriptor + * + * @returns the length of the report descriptor + */ + virtual uint16_t reportDescLength(); + + bool Request_callback(CONTROL_TRANSFER* transfer, uint8_t* hidDescriptor); +protected: + /* + * Get the Report descriptor + * + * @returns pointer to the report descriptor + */ + virtual uint8_t * reportDesc(); + + uint16_t reportLength; + +private: + USBDevice* _device; + HID_REPORT outputReport; + uint8_t output_length; + uint8_t input_length; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USB_MSD.cpp Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,550 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "USB_MSD.h" + +#if (DEBUG2 > 3) +#define MSD_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +#else +#define MSD_DBG(...) while(0) +#endif + +#define DISK_OK 0x00 +#define NO_INIT 0x01 +#define NO_DISK 0x02 +#define WRITE_PROTECT 0x04 + +#define CBW_Signature 0x43425355 +#define CSW_Signature 0x53425355 + +// SCSI Commands +#define TEST_UNIT_READY 0x00 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define INQUIRY 0x12 +#define MODE_SELECT6 0x15 +#define MODE_SENSE6 0x1A +#define START_STOP_UNIT 0x1B +#define MEDIA_REMOVAL 0x1E +#define READ_FORMAT_CAPACITIES 0x23 +#define READ_CAPACITY 0x25 +#define READ10 0x28 +#define WRITE10 0x2A +#define VERIFY10 0x2F +#define READ12 0xA8 +#define WRITE12 0xAA +#define MODE_SELECT10 0x55 +#define MODE_SENSE10 0x5A + +// MSC class specific requests +#define MSC_REQUEST_RESET 0xFF +#define MSC_REQUEST_GET_MAX_LUN 0xFE + +#define DEFAULT_CONFIGURATION (1) + +// max packet size +#define MAX_PACKET MAX_PACKET_SIZE_EPBULK + +// CSW Status +enum Status { + CSW_PASSED, + CSW_FAILED, + CSW_ERROR, +}; + +USB_MSD::USB_MSD(USBDevice* device, DiskInterface* disk) : _device(device),_disk(disk) +{ + MSD_DBG("device=%p", device); + + stage = READ_CBW; + memset((void *)&cbw, 0, sizeof(CBW)); + memset((void *)&csw, 0, sizeof(CSW)); + page = NULL; +} + +bool USB_MSD::connect() { + + //disk initialization + if (_disk->disk_status() & NO_INIT) { + if (_disk->disk_initialize()) { + return false; + } + } + + // get number of blocks + BlockCount = _disk->disk_sectors(); + + // get memory size + MemorySize = _disk->disk_size(); + + if (BlockCount > 0) { + BlockSize = MemorySize / BlockCount; + if (BlockSize != 0) { + free(page); + page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t)); + if (page == NULL) + return false; + } + } else { + return false; + } + return true; +} + +void USB_MSD::disconnect() { + //De-allocate MSD page size: + free(page); + page = NULL; +} + +void USB_MSD::reset() { + stage = READ_CBW; +} + +bool USB_MSD::Request_callback(CONTROL_TRANSFER* transfer) +{ + static uint8_t msc_maxLUN[1] = {0}; + + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { + switch (transfer->setup.bRequest) { + case MSC_REQUEST_RESET: + reset(); + return true; + + case MSC_REQUEST_GET_MAX_LUN: + transfer->remaining = 1; + transfer->ptr = msc_maxLUN; + transfer->direction = DEVICE_TO_HOST; + return true; + } + } + return false; +} + +// Called in ISR context called when a data is received +bool USB_MSD::EPBULK_OUT_callback() { + uint32_t size = 0; + uint8_t buf[MAX_PACKET_SIZE_EPBULK]; + _device->readEP(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK); + switch (stage) { + // the device has to decode the CBW received + case READ_CBW: + CBWDecode(buf, size); + break; + + // the device has to receive data from the host + case PROCESS_CBW: + switch (cbw.CB[0]) { + case WRITE10: + case WRITE12: + memoryWrite(buf, size); + break; + case VERIFY10: + memoryVerify(buf, size); + break; + } + break; + + // an error has occured: stall endpoint and send CSW + default: + _device->stallEndpoint(EPBULK_OUT); + csw.Status = CSW_ERROR; + sendCSW(); + break; + } + + //reactivate readings on the OUT bulk endpoint + _device->readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + return true; +} + +// Called in ISR context when a data has been transferred +bool USB_MSD::EPBULK_IN_callback() { + switch (stage) { + + // the device has to send data to the host + case PROCESS_CBW: + switch (cbw.CB[0]) { + case READ10: + case READ12: + memoryRead(); + break; + } + break; + + //the device has to send a CSW + case SEND_CSW: + sendCSW(); + break; + + // the host has received the CSW -> we wait a CBW + case WAIT_CSW: + stage = READ_CBW; + break; + + // an error has occured + default: + _device->stallEndpoint(EPBULK_IN); + sendCSW(); + break; + } + return true; +} + +void USB_MSD::memoryWrite (uint8_t * buf, uint16_t size) { + + if ((addr + size) > MemorySize) { + size = MemorySize - addr; + stage = ERROR; + _device->stallEndpoint(EPBULK_OUT); + } + + // we fill an array in RAM of 1 block before writing it in memory + for (int i = 0; i < size; i++) + page[addr%BlockSize + i] = buf[i]; + + // if the array is filled, write it in memory + if (!((addr + size)%BlockSize)) { + if (!(_disk->disk_status() & WRITE_PROTECT)) { + _disk->disk_write(page, addr/BlockSize); + } + } + + addr += size; + length -= size; + csw.DataResidue -= size; + + if ((!length) || (stage != PROCESS_CBW)) { + csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED; + sendCSW(); + } +} + +void USB_MSD::memoryVerify (uint8_t * buf, uint16_t size) { + uint32_t n; + + if ((addr + size) > MemorySize) { + size = MemorySize - addr; + stage = ERROR; + _device->stallEndpoint(EPBULK_OUT); + } + + // beginning of a new block -> load a whole block in RAM + if (!(addr%BlockSize)) + _disk->disk_read(page, addr/BlockSize); + + // info are in RAM -> no need to re-read memory + for (n = 0; n < size; n++) { + if (page[addr%BlockSize + n] != buf[n]) { + memOK = false; + break; + } + } + + addr += size; + length -= size; + csw.DataResidue -= size; + + if ( !length || (stage != PROCESS_CBW)) { + csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED; + sendCSW(); + } +} + +bool USB_MSD::inquiryRequest (void) { + uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01, + 36 - 4, 0x80, 0x00, 0x00, + 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G', + 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ', + '1', '.', '0', ' ', + }; + if (!write(inquiry, sizeof(inquiry))) { + return false; + } + return true; +} + +bool USB_MSD::readFormatCapacity() { + uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08, + (uint8_t)((BlockCount >> 24) & 0xff), + (uint8_t)((BlockCount >> 16) & 0xff), + (uint8_t)((BlockCount >> 8) & 0xff), + (uint8_t)((BlockCount >> 0) & 0xff), + + 0x02, + (uint8_t)((BlockSize >> 16) & 0xff), + (uint8_t)((BlockSize >> 8) & 0xff), + (uint8_t)((BlockSize >> 0) & 0xff), + }; + if (!write(capacity, sizeof(capacity))) { + return false; + } + return true; +} + +bool USB_MSD::readCapacity (void) { + uint8_t capacity[] = { + (uint8_t)(((BlockCount - 1) >> 24) & 0xff), + (uint8_t)(((BlockCount - 1) >> 16) & 0xff), + (uint8_t)(((BlockCount - 1) >> 8) & 0xff), + (uint8_t)(((BlockCount - 1) >> 0) & 0xff), + + (uint8_t)((BlockSize >> 24) & 0xff), + (uint8_t)((BlockSize >> 16) & 0xff), + (uint8_t)((BlockSize >> 8) & 0xff), + (uint8_t)((BlockSize >> 0) & 0xff), + }; + if (!write(capacity, sizeof(capacity))) { + return false; + } + return true; +} + +bool USB_MSD::write (uint8_t * buf, uint16_t size) { + + if (size >= cbw.DataLength) { + size = cbw.DataLength; + } + stage = SEND_CSW; + + if (!_device->writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) { + return false; + } + + csw.DataResidue -= size; + csw.Status = CSW_PASSED; + return true; +} + +bool USB_MSD::modeSense6 (void) { + uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 }; + if (!write(sense6, sizeof(sense6))) { + return false; + } + return true; +} + +void USB_MSD::sendCSW() { + csw.Signature = CSW_Signature; + _device->writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK); + stage = WAIT_CSW; +} + +bool USB_MSD::requestSense (void) { + uint8_t request_sense[] = { + 0x70, + 0x00, + 0x05, // Sense Key: illegal request + 0x00, + 0x00, + 0x00, + 0x00, + 0x0A, + 0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + }; + + if (!write(request_sense, sizeof(request_sense))) { + return false; + } + + return true; +} + +void USB_MSD::fail() { + csw.Status = CSW_FAILED; + sendCSW(); +} + +void USB_MSD::CBWDecode(uint8_t * buf, uint16_t size) { + if (size == sizeof(cbw)) { + memcpy((uint8_t *)&cbw, buf, size); + if (cbw.Signature == CBW_Signature) { + csw.Tag = cbw.Tag; + csw.DataResidue = cbw.DataLength; + if ((cbw.CBLength < 1) || (cbw.CBLength > 16) ) { + fail(); + } else { + switch (cbw.CB[0]) { + case TEST_UNIT_READY: + testUnitReady(); + break; + case REQUEST_SENSE: + requestSense(); + break; + case INQUIRY: + inquiryRequest(); + break; + case MODE_SENSE6: + modeSense6(); + break; + case READ_FORMAT_CAPACITIES: + readFormatCapacity(); + break; + case READ_CAPACITY: + readCapacity(); + break; + case READ10: + case READ12: + if (infoTransfer()) { + if ((cbw.Flags & 0x80)) { + stage = PROCESS_CBW; + memoryRead(); + } else { + _device->stallEndpoint(EPBULK_OUT); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + case WRITE10: + case WRITE12: + if (infoTransfer()) { + if (!(cbw.Flags & 0x80)) { + stage = PROCESS_CBW; + } else { + _device->stallEndpoint(EPBULK_IN); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + case VERIFY10: + if (!(cbw.CB[1] & 0x02)) { + csw.Status = CSW_PASSED; + sendCSW(); + break; + } + if (infoTransfer()) { + if (!(cbw.Flags & 0x80)) { + stage = PROCESS_CBW; + memOK = true; + } else { + _device->stallEndpoint(EPBULK_IN); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + case MEDIA_REMOVAL: + csw.Status = CSW_PASSED; + sendCSW(); + break; + default: + fail(); + break; + } + } + } + } +} + +void USB_MSD::testUnitReady (void) { + + if (cbw.DataLength != 0) { + if ((cbw.Flags & 0x80) != 0) { + _device->stallEndpoint(EPBULK_IN); + } else { + _device->stallEndpoint(EPBULK_OUT); + } + } + + csw.Status = CSW_PASSED; + sendCSW(); +} + +void USB_MSD::memoryRead (void) { + uint32_t n; + + n = (length > MAX_PACKET) ? MAX_PACKET : length; + + if ((addr + n) > MemorySize) { + n = MemorySize - addr; + stage = ERROR; + } + + // we read an entire block + if (!(addr%BlockSize)) + _disk->disk_read(page, addr/BlockSize); + + // write data which are in RAM + _device->writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK); + + addr += n; + length -= n; + + csw.DataResidue -= n; + + if ( !length || (stage != PROCESS_CBW)) { + csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED; + stage = (stage == PROCESS_CBW) ? SEND_CSW : stage; + } +} + +bool USB_MSD::infoTransfer (void) { + uint32_t n; + + // Logical Block Address of First Block + n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] << 8) | (cbw.CB[5] << 0); + + addr = n * BlockSize; + + // Number of Blocks to transfer + switch (cbw.CB[0]) { + case READ10: + case WRITE10: + case VERIFY10: + n = (cbw.CB[7] << 8) | (cbw.CB[8] << 0); + break; + + case READ12: + case WRITE12: + n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] << 8) | (cbw.CB[9] << 0); + break; + } + + length = n * BlockSize; + + if (!cbw.DataLength) { // host requests no data + csw.Status = CSW_FAILED; + sendCSW(); + return false; + } + + if (cbw.DataLength != length) { + if ((cbw.Flags & 0x80) != 0) { + _device->stallEndpoint(EPBULK_IN); + } else { + _device->stallEndpoint(EPBULK_OUT); + } + + csw.Status = CSW_FAILED; + sendCSW(); + return false; + } + + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD2/USB_MSD.h Sun Feb 16 12:56:12 2014 +0000 @@ -0,0 +1,153 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include "USBDevice.h" +#include "DiskInterface.h" + +// MSC class specific requests +#define MSC_REQUEST_RESET 0xFF +#define MSC_REQUEST_GET_MAX_LUN 0xFE + +/** + * USBMSD2 class: generic class in order to use all kinds of blocks storage chip + * + * Introduction + * + * The USBMSD implements the MSD protocol. It permits to access a memory chip (flash, sdcard,...) + * from a computer over USB. But this class doesn't work standalone, you need to subclass this class + * and define virtual functions which are called in USBMSD. + * + * How to use this class with your chip ? + * + * You have to inherit and define some pure virtual functions (mandatory step): + * - virtual int disk_read(char * data, int block): function to read a block + * - virtual int disk_write(const char * data, int block): function to write a block + * - virtual int disk_initialize(): function to initialize the memory + * - virtual int disk_sectors(): return the number of blocks + * - virtual int disk_size(): return the memory size + * - virtual int disk_status(): return the status of the storage chip (0: OK, 1: not initialized, 2: no medium in the drive, 4: write protection) + * + * All functions names are compatible with the fat filesystem library. So you can imagine using your own class with + * USBMSD and the fat filesystem library in the same program. Just be careful because there are two different parts which + * will access the sd card. You can do a master/slave system using the disk_status method. + * + * Once these functions defined, you can call connect() (at the end of the constructor of your class for instance) + * of USBMSD to connect your mass storage device. connect() will first call disk_status() to test the status of the disk. + * If disk_status() returns 1 (disk not initialized), then disk_initialize() is called. After this step, connect() will collect information + * such as the number of blocks and the memory size. + */ +class USB_MSD { +public: + USB_MSD(USBDevice* device, DiskInterface* disk); + + /** + * Connect the USB MSD device. Establish disk initialization before really connect the device. + * + * @returns true if successful + */ + bool connect(); + + /** + * Disconnect the USB MSD device. + */ + void disconnect(); + + /** + * Destructor + */ + ~USB_MSD(); + + bool Request_callback(CONTROL_TRANSFER* transfer); + bool EPBULK_OUT_callback(); + bool EPBULK_IN_callback(); + +private: + USBDevice* _device; + DiskInterface* _disk; + + // MSC Bulk-only Stage + enum Stage { + READ_CBW, // wait a CBW + ERROR, // error + PROCESS_CBW, // process a CBW request + SEND_CSW, // send a CSW + WAIT_CSW, // wait that a CSW has been effectively sent + }; + + // Bulk-only CBW + typedef struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataLength; + uint8_t Flags; + uint8_t LUN; + uint8_t CBLength; + uint8_t CB[16]; + } PACKED CBW; + + // Bulk-only CSW + typedef struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataResidue; + uint8_t Status; + } PACKED CSW; + + //state of the bulk-only state machine + Stage stage; + + // current CBW + CBW cbw; + + // CSW which will be sent + CSW csw; + + // addr where will be read or written data + uint32_t addr; + + // length of a reading or writing + uint32_t length; + + // memory OK (after a memoryVerify) + bool memOK; + + // cache in RAM before writing in memory. Useful also to read a block. + uint8_t * page; + + int BlockSize; + uint64_t MemorySize; + uint64_t BlockCount; + + void reset(); + void CBWDecode(uint8_t * buf, uint16_t size); + void sendCSW (void); + bool inquiryRequest (void); + bool write (uint8_t * buf, uint16_t size); + bool readFormatCapacity(); + bool readCapacity (void); + bool infoTransfer (void); + void memoryRead (void); + bool modeSense6 (void); + void testUnitReady (void); + bool requestSense (void); + void memoryVerify (uint8_t * buf, uint16_t size); + void memoryWrite (uint8_t * buf, uint16_t size); + void fail(); +};
--- a/main.cpp Sat Feb 15 10:15:42 2014 +0000 +++ b/main.cpp Sun Feb 16 12:56:12 2014 +0000 @@ -1,3 +1,4 @@ +#ifdef TARGET_KL46Z #include "RamDisk.h" #include "Storage.h" #include "BaseLpcIsp.h" @@ -42,7 +43,7 @@ sw3.rise(swIRQ); RamDisk* ramdisk = new RamDisk; - USBStorage* usb = new USBStorage(ramdisk); + USBStorage2* usb = new USBStorage2(ramdisk); LocalStorage* local = NULL; slcd.puts("REDY"); write_start = false; @@ -63,6 +64,12 @@ } write_start = false; } + if (usb->readable()) { + lpc.putc(usb->getc()); + } + if (lpc.readable()) { + usb->putc(lpc.getc()); + } if (pc.readable()) { switch(pc.getc()) { case 'd': ramdisk->dump(0); break; @@ -72,3 +79,4 @@ } } } +#endif
--- a/src/Storage.h Sat Feb 15 10:15:42 2014 +0000 +++ b/src/Storage.h Sun Feb 16 12:56:12 2014 +0000 @@ -2,6 +2,7 @@ #include "mbed.h" #include "FATFileSystem.h" #include "USBMSD.h" +#include "USBMSD2.h" #include "StorageInterface.h" #include "mystring.h" @@ -42,3 +43,22 @@ StorageInterface* _storage; }; +class USBStorage2 : public USBMSD2 { +public: + USBStorage2(StorageInterface* storage): _storage(storage) { + connect(); + } + virtual int disk_read(uint8_t * data, uint64_t block) { + return _storage->storage_read(data, block); + } + virtual int disk_write(const uint8_t * data, uint64_t block) { + return _storage->storage_write(data, block); + } + virtual int disk_initialize() { return _storage->storage_initialize(); } + virtual uint64_t disk_sectors() { return _storage->storage_sectors(); } + virtual uint64_t disk_size() { return _storage->storage_size(); } + virtual int disk_status() { return _storage->storage_status(); } + +private: + StorageInterface* _storage; +};
--- a/src/myqueue.h Sat Feb 15 10:15:42 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -#pragma once - -template<class T> -class myqueue { -public: - myqueue() { - m_wpos = m_rpos = 0; - m_size = 0; - m_capacity = 0; - } - void push(T v) { - if (m_size >= m_capacity) { // resize - int new_capacity = m_capacity + 1; - T* new_buf = new T[new_capacity]; - if (m_capacity > 0) { - for(int i = 0; i < m_size; i++) { - new_buf[i] = m_buf[m_rpos++]; - if (m_rpos >= m_capacity) { - m_rpos = 0; - } - } - delete[] m_buf; - } - m_rpos = 0; - m_wpos = m_size; - m_buf = new_buf; - m_capacity = new_capacity; - } - m_buf[m_wpos++] = v; - if (m_wpos >= m_capacity) { - m_wpos = 0; - } - m_size++; - } - T pop() { - T v = m_buf[m_rpos++]; - if (m_rpos >= m_capacity) { - m_rpos = 0; - } - m_size--; - return v; - } - bool empty() { return m_size == 0; } - int size() { return m_size; } - -private: - int m_capacity; - int m_size; - int m_wpos; - int m_rpos; - T *m_buf; -};