brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 1 | /* |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 2 | LPCUSB, an USB device driver for LPC microcontrollers |
| 3 | Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 4 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 5 | Redistribution and use in source and binary forms, with or without |
| 6 | modification, are permitted provided that the following conditions are met: |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 7 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 8 | 1. Redistributions of source code must retain the above copyright |
| 9 | notice, this list of conditions and the following disclaimer. |
| 10 | 2. Redistributions in binary form must reproduce the above copyright |
| 11 | notice, this list of conditions and the following disclaimer in the |
| 12 | documentation and/or other materials provided with the distribution. |
| 13 | 3. The name of the author may not be used to endorse or promote products |
| 14 | derived from this software without specific prior written permission. |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 15 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 17 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 19 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 21 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 26 | */ |
| 27 | |
| 28 | #include "FreeRTOS.h" |
| 29 | #include "queue.h" |
| 30 | #include "task.h" |
| 31 | |
| 32 | #include <stdio.h> |
| 33 | #include <string.h> |
| 34 | |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 35 | #include "LPCUSB/usbapi.h" |
| 36 | #include "LPCUSB/usbdebug.h" |
| 37 | #include "LPCUSB/usbstruct.h" |
| 38 | |
| 39 | // This file is marked private and most of the functions in its associated .c |
| 40 | // file started out static, but we want to use some of them to do frame handling |
| 41 | // stuff because we do special stuff with it (handle it ourselves for reduced |
| 42 | // jitter and actually deal with the frame number correctly), so it's nice to |
| 43 | // have the utility functions for accessing the hardware available instead of |
| 44 | // having to rewrite them. |
| 45 | #include "LPCUSB/usbhw_lpc.h" |
| 46 | unsigned char USBHwCmdRead(unsigned char bCmd); |
| 47 | void Wait4DevInt(unsigned long dwIntr); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 48 | |
| 49 | #include "LPC17xx.h" |
| 50 | |
Brian Silverman | f92396c | 2013-09-12 20:13:13 -0700 | [diff] [blame] | 51 | #include "fill_packet.h" |
Brian Silverman | c554a8f | 2013-03-31 19:07:49 -0700 | [diff] [blame] | 52 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 53 | #define usbMAX_SEND_BLOCK ( 20 / portTICK_RATE_MS ) |
| 54 | #define usbRXBUFFER_LEN ( 80 ) |
| 55 | #define usbTXBUFFER_LEN ( 600 ) |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 56 | |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 57 | // Read the processor manual for picking these. |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 58 | #define BULK_IN_EP 0x82 |
Brian Silverman | c554a8f | 2013-03-31 19:07:49 -0700 | [diff] [blame] | 59 | #define BULK_OUT_EP 0x05 |
| 60 | #define ISOC_IN_EP 0x83 |
Brian Silverman | 2d21bb2 | 2013-10-25 15:52:42 -0700 | [diff] [blame] | 61 | #define NUM_ENDPOINTS 3 |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 62 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 63 | #define MAX_PACKET_SIZE 64 |
Brian Silverman | 2d21bb2 | 2013-10-25 15:52:42 -0700 | [diff] [blame] | 64 | #define DATA_PACKET_SIZE DATA_STRUCT_SEND_SIZE |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 65 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 66 | #define LE_WORD(x) ((x)&0xFF),((x)>>8) |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 67 | |
| 68 | static xQueueHandle xRxedChars = NULL, xCharsForTx = NULL; |
| 69 | |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 70 | // This gets cleared each time the ISR is entered and then checked as it's |
| 71 | // returning so that we can still yield from the ISR to a woken task but not |
| 72 | // from the middle of the ISR like it would be if this was checked in each |
| 73 | // endpoint handler that needs it. |
| 74 | static portBASE_TYPE higher_priority_task_woken; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 75 | |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 76 | static const unsigned char abDescriptors[] = { |
Austin Schuh | 63d0e9b | 2013-03-27 04:43:14 +0000 | [diff] [blame] | 77 | // Device descriptor |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 78 | 0x12, |
| 79 | DESC_DEVICE, |
| 80 | LE_WORD(0x0200), // bcdUSB |
| 81 | 0xFF, // bDeviceClass |
| 82 | 0x00, // bDeviceSubClass |
| 83 | 0x00, // bDeviceProtocol |
| 84 | MAX_PACKET_SIZE0, // bMaxPacketSize |
| 85 | LE_WORD(0x1424), // idVendor |
| 86 | LE_WORD(0xd243), // idProduct |
| 87 | LE_WORD(0x0153), // bcdDevice |
| 88 | 0x03, // iManufacturer |
| 89 | 0x02, // iProduct |
| 90 | 0x01, // iSerialNumber |
| 91 | 0x01, // bNumConfigurations |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 92 | |
Austin Schuh | 63d0e9b | 2013-03-27 04:43:14 +0000 | [diff] [blame] | 93 | // Configuration descriptor |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 94 | 0x09, |
| 95 | DESC_CONFIGURATION, |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 96 | LE_WORD(9 + 9 + 7 * NUM_ENDPOINTS), // wTotalLength |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 97 | 0x01, // bNumInterfaces |
| 98 | 0x01, // bConfigurationValue |
| 99 | 0x00, // iConfiguration |
| 100 | 0xC0, // bmAttributes |
| 101 | 0x32, // bMaxPower |
Austin Schuh | 63d0e9b | 2013-03-27 04:43:14 +0000 | [diff] [blame] | 102 | // Data class interface descriptor |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 103 | 0x09, |
| 104 | DESC_INTERFACE, |
| 105 | 0x00, // bInterfaceNumber |
| 106 | 0x00, // bAlternateSetting |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 107 | NUM_ENDPOINTS, // bNumEndPoints |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 108 | 0x0A, // bInterfaceClass = data |
| 109 | 0x00, // bInterfaceSubClass |
| 110 | 0x00, // bInterfaceProtocol |
| 111 | 0x00, // iInterface |
Austin Schuh | 63d0e9b | 2013-03-27 04:43:14 +0000 | [diff] [blame] | 112 | // Debug EP OUT |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 113 | 0x07, |
| 114 | DESC_ENDPOINT, |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 115 | BULK_OUT_EP, // bEndpointAddress |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 116 | 0x02, // bmAttributes = bulk |
| 117 | LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize |
| 118 | 0x00, // bInterval |
Austin Schuh | 63d0e9b | 2013-03-27 04:43:14 +0000 | [diff] [blame] | 119 | // Debug EP in |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 120 | 0x07, |
| 121 | DESC_ENDPOINT, |
| 122 | BULK_IN_EP, // bEndpointAddress |
| 123 | 0x02, // bmAttributes = bulk |
| 124 | LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize |
| 125 | 0x00, // bInterval |
Brian Silverman | c554a8f | 2013-03-31 19:07:49 -0700 | [diff] [blame] | 126 | // isoc data EP IN |
| 127 | 0x07, |
| 128 | DESC_ENDPOINT, |
| 129 | ISOC_IN_EP, // bEndpointAddress |
| 130 | 0x0D, // bmAttributes = isoc, synchronous, data endpoint |
Brian Silverman | 2d21bb2 | 2013-10-25 15:52:42 -0700 | [diff] [blame] | 131 | LE_WORD(DATA_PACKET_SIZE), // wMaxPacketSize |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 132 | 0x01, // bInterval |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 133 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 134 | // string descriptors |
| 135 | 0x04, |
| 136 | DESC_STRING, |
| 137 | LE_WORD(0x0409), |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 138 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 139 | 0x0E, |
| 140 | DESC_STRING, |
| 141 | 'A', 0, 'S', 0, 'C', 0, 'H', 0, 'U', 0, 'H', 0, |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 142 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 143 | 0x14, |
| 144 | DESC_STRING, |
| 145 | 'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'n', 0, 's', 0, 'o', 0, 'r', 0, |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 146 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 147 | 0x12, |
| 148 | DESC_STRING, |
| 149 | 'A', 0, 'O', 0, 'S', 0, '_', 0, 'G', 0, 'y', 0, 'r', 0, 'o', 0, |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 150 | |
| 151 | // terminating zero |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 152 | 0 |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 153 | }; |
| 154 | |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 155 | // Enables interrupts to write data instead of NAKing on the bulk in endpoints. |
| 156 | // This is in a centralized place so that other NAK interrupts can be enabled |
| 157 | // all of the time easily in the future. |
| 158 | static void bulk_in_nak_int(int have_data) { |
| 159 | USBHwNakIntEnable(have_data ? INACK_BI : 0); |
| 160 | } |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 161 | |
| 162 | /** |
| 163 | * Local function to handle incoming bulk data |
| 164 | * |
| 165 | * @param [in] bEP |
| 166 | * @param [in] bEPStatus |
| 167 | */ |
| 168 | static void DebugOut(unsigned char bEP, unsigned char bEPStatus) { |
| 169 | int i, iLen; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 170 | unsigned char abBulkBuf[64]; |
| 171 | |
| 172 | (void) bEPStatus; |
| 173 | |
| 174 | // get data from USB into intermediate buffer |
| 175 | iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf)); |
| 176 | for (i = 0; i < iLen; i++) { |
| 177 | // put into queue |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 178 | xQueueSendFromISR(xRxedChars, &abBulkBuf[i], &higher_priority_task_woken); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 179 | } |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | |
| 183 | /** |
| 184 | * Local function to handle outgoing bulk data |
| 185 | * |
| 186 | * @param [in] bEP |
| 187 | * @param [in] bEPStatus |
| 188 | */ |
| 189 | static void DebugIn(unsigned char bEP, unsigned char bEPStatus) { |
| 190 | int i, iLen; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 191 | unsigned char abBulkBuf[64]; |
| 192 | |
| 193 | (void) bEPStatus; |
| 194 | |
| 195 | if (uxQueueMessagesWaitingFromISR(xCharsForTx) == 0) { |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 196 | // no more data |
| 197 | bulk_in_nak_int(0); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 198 | return; |
| 199 | } |
| 200 | |
| 201 | // get bytes from transmit FIFO into intermediate buffer |
| 202 | for (i = 0; i < MAX_PACKET_SIZE; i++) { |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 203 | if (xQueueReceiveFromISR(xCharsForTx, &abBulkBuf[i], |
| 204 | &higher_priority_task_woken) != pdPASS) { |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 205 | break; |
| 206 | } |
| 207 | } |
| 208 | iLen = i; |
| 209 | |
| 210 | // send over USB |
| 211 | if (iLen > 0) { |
| 212 | USBHwEPWrite(bEP, abBulkBuf, iLen); |
| 213 | } |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 214 | } |
| 215 | |
Austin Schuh | 63d0e9b | 2013-03-27 04:43:14 +0000 | [diff] [blame] | 216 | |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 217 | /** |
| 218 | * Writes one character to VCOM port |
| 219 | * |
| 220 | * @param [in] c character to write |
| 221 | * @returns character written, or EOF if character could not be written |
| 222 | */ |
| 223 | int VCOM_putcharFromISR(int c, long *lHigherPriorityTaskWoken) { |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 224 | char cc = (char) c; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 225 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 226 | if (xQueueSendFromISR(xCharsForTx, &cc, |
| 227 | lHigherPriorityTaskWoken) == pdPASS) { |
| 228 | return c; |
| 229 | } else { |
| 230 | return EOF; |
| 231 | } |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | int VCOM_putchar(int c) { |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 235 | char cc = (char) c; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 236 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 237 | // Don't block if not connected to USB. |
| 238 | if (xQueueSend(xCharsForTx, &cc, |
Brian Silverman | c554a8f | 2013-03-31 19:07:49 -0700 | [diff] [blame] | 239 | USBIsConnected() ? usbMAX_SEND_BLOCK : 0) == pdPASS) { |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 240 | return c; |
| 241 | } else { |
| 242 | return EOF; |
| 243 | } |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | |
| 247 | /** |
| 248 | * Reads one character from VCOM port |
| 249 | * |
| 250 | * @returns character read, or EOF if character could not be read |
| 251 | */ |
| 252 | int VCOM_getchar(void) { |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 253 | unsigned char c; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 254 | |
Brian Silverman | 6ad00b8 | 2013-03-27 19:02:38 -0700 | [diff] [blame] | 255 | /* Block the task until a character is available. */ |
| 256 | if(xQueueReceive(xRxedChars, &c, 0) == pdTRUE){ //portMAX_DELAY); |
| 257 | return c; |
| 258 | } |
| 259 | return -1; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 260 | } |
| 261 | |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 262 | // Instead of registering an lpcusb handler for this, we do it ourself so that |
| 263 | // we can get the timing jitter down. |
| 264 | static void HandleFrame(void) { |
| 265 | USB->USBDevIntClr = FRAME; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 266 | |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 267 | static struct DataStruct sensor_values; |
| 268 | fillSensorPacket(&sensor_values); |
| 269 | |
| 270 | static int32_t current_frame = -1; |
| 271 | static int guessed_frames = 0; |
| 272 | |
| 273 | uint8_t error_status = USBHwCmdRead(CMD_DEV_READ_ERROR_STATUS); |
| 274 | if (error_status & PID_ERR) { |
| 275 | ++guessed_frames; |
Brian Silverman | c554a8f | 2013-03-31 19:07:49 -0700 | [diff] [blame] | 276 | } else { |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 277 | int16_t read_frame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR); |
| 278 | USB->USBCmdCode = 0x00000200 | (CMD_DEV_READ_CUR_FRAME_NR << 16); |
| 279 | Wait4DevInt(CDFULL); |
| 280 | read_frame |= USB->USBCmdData << 8; |
| 281 | |
| 282 | if (current_frame < 0) { |
| 283 | current_frame = read_frame; |
| 284 | guessed_frames = 0; |
| 285 | } else { |
| 286 | static const uint32_t kMaxReadFrame = 0x800; |
| 287 | static const uint32_t kReadMask = kMaxReadFrame - 1; |
| 288 | if ((current_frame & kReadMask) == read_frame) { |
| 289 | // This seems like it must mean that we didn't receive the SOF token. |
| 290 | ++guessed_frames; |
| 291 | } else { |
| 292 | guessed_frames = 0; |
| 293 | int16_t difference = |
| 294 | read_frame - (int16_t)((current_frame + 1) & kReadMask); |
| 295 | // If we're off by only a little. |
| 296 | if (difference > -10 && difference < 10) { |
| 297 | current_frame = ((current_frame + 1) & ~kReadMask) | read_frame; |
| 298 | // If we're ahead by only a little but we wrapped. |
| 299 | } else if (difference > kMaxReadFrame - 10) { |
| 300 | current_frame = |
| 301 | ((current_frame & ~kReadMask) - kMaxReadFrame) | read_frame; |
| 302 | // If we're behind by only a little but the packet counter wrapped. |
| 303 | } else if (difference < -(kMaxReadFrame - 10)) { |
| 304 | current_frame = |
| 305 | ((current_frame & ~kReadMask) + kMaxReadFrame) | read_frame; |
| 306 | } else { |
| 307 | // Give up and reset. |
| 308 | current_frame = -1; |
| 309 | } |
| 310 | } |
| 311 | } |
Austin Schuh | 63d0e9b | 2013-03-27 04:43:14 +0000 | [diff] [blame] | 312 | } |
Brian Silverman | c554a8f | 2013-03-31 19:07:49 -0700 | [diff] [blame] | 313 | |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 314 | sensor_values.frame_number = current_frame + guessed_frames; |
| 315 | sensor_values.unknown_frame = guessed_frames > 10; |
| 316 | |
| 317 | USBHwEPWrite(ISOC_IN_EP, (unsigned char *)&sensor_values, DATA_PACKET_SIZE); |
| 318 | |
| 319 | if (uxQueueMessagesWaitingFromISR(xCharsForTx) > 0) { |
| 320 | // Data to send is available so enable interrupt instead of NAK. |
| 321 | bulk_in_nak_int(1); |
| 322 | } else { |
| 323 | bulk_in_nak_int(0); |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | void USB_IRQHandler(void) { |
| 328 | higher_priority_task_woken = pdFALSE; |
| 329 | uint32_t status = SC->USBIntSt; |
| 330 | if (status & USB_INT_REQ_HP) { |
| 331 | // We set the frame interrupt to get routed to the high priority line. |
| 332 | HandleFrame(); |
| 333 | } |
| 334 | //if (status & USB_INT_REQ_LP) { |
| 335 | // Call lpcusb to let it handle all of the other interrupts. |
| 336 | USBHwISR(); |
| 337 | //} |
| 338 | portEND_SWITCHING_ISR(higher_priority_task_woken); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 339 | } |
| 340 | |
Brian Silverman | d36b7d3 | 2013-10-24 15:56:47 -0700 | [diff] [blame] | 341 | void usb_init(void) { |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 342 | DBG("Initialising USB stack\n"); |
| 343 | |
| 344 | xRxedChars = xQueueCreate(usbRXBUFFER_LEN, sizeof(char)); |
| 345 | xCharsForTx = xQueueCreate(usbTXBUFFER_LEN, sizeof(char)); |
| 346 | |
| 347 | if ((xRxedChars == NULL) || (xCharsForTx == NULL)) { |
| 348 | /* Not enough heap available to create the buffer queues, can't do |
| 349 | anything so just delete ourselves. */ |
| 350 | vTaskDelete(NULL); |
| 351 | } |
| 352 | |
Brian Silverman | 70478d1 | 2013-10-11 17:54:58 -0700 | [diff] [blame] | 353 | // Initialise the USB stack. |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 354 | USBInit(); |
| 355 | |
| 356 | // register descriptors |
| 357 | USBRegisterDescriptors(abDescriptors); |
| 358 | |
| 359 | // register class request handler |
| 360 | //USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, |
| 361 | // HandleClassRequest, abClassReqData); |
| 362 | |
| 363 | // register endpoint handlers |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 364 | USBHwRegisterEPIntHandler(BULK_IN_EP, DebugIn); |
| 365 | USBHwRegisterEPIntHandler(BULK_OUT_EP, DebugOut); |
| 366 | |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 367 | USB->USBDevIntPri = 1; // route frame interrupt to high priority line |
| 368 | USB->USBDevIntEn |= FRAME; // enable frame interrupt |
| 369 | |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 370 | // register frame handler |
Brian Silverman | 89e8636 | 2013-10-30 17:50:50 -0700 | [diff] [blame] | 371 | //USBHwRegisterFrameHandler(USBFrameHandler); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 372 | |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 373 | DBG("Starting USB communication\n"); |
| 374 | |
| 375 | NVIC_SetPriority(USB_IRQn, configUSB_INTERRUPT_PRIORITY); |
| 376 | NVIC_EnableIRQ(USB_IRQn); |
| 377 | |
| 378 | // connect to bus |
| 379 | |
| 380 | DBG("Connecting to USB bus\n"); |
| 381 | USBHwConnect(TRUE); |
| 382 | |
Brian Silverman | d36b7d3 | 2013-10-24 15:56:47 -0700 | [diff] [blame] | 383 | // Enable USB. The PC has probably disconnected it now. |
| 384 | USBHwAllowConnect(); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 385 | } |