Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TivaUsbKeyboardDev.cxx
Go to the documentation of this file.
1
35
36//****************************************************************************
37//
38// The languages supported by this device.
39//
40//****************************************************************************
41static const uint8_t g_pui8LangDescriptor[] = {
42 4, USB_DTYPE_STRING, USBShort(USB_LANG_EN_US)};
43
44//****************************************************************************
45//
46// The manufacturer string.
47//
48//****************************************************************************
49static const uint8_t g_pui8ManufacturerString[] = {
50 (17 + 1) * 2, USB_DTYPE_STRING, 'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ',
51 0, 'I', 0, 'n', 0, 's', 0, 't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0,
52 't', 0, 's', 0,
53};
54
55//****************************************************************************
56//
57// The product string.
58//
59//****************************************************************************
60static const uint8_t g_pui8ProductString[] = {(16 + 1) * 2, USB_DTYPE_STRING,
61 'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, 'E',
62 0, 'x', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0};
63
64//****************************************************************************
65//
66// The serial number string.
67//
68//****************************************************************************
69static const uint8_t g_pui8SeriailNumberString[] = {(8 + 1) * 2,
70 USB_DTYPE_STRING, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0,
71 '8', 0};
72
73//*****************************************************************************
74//
75// The interface description string.
76//
77//*****************************************************************************
78static const uint8_t g_pui8HIDInterfaceString[] = {(22 + 1) * 2,
79 USB_DTYPE_STRING, 'H', 0, 'I', 0, 'D', 0, ' ', 0, 'K', 0, 'e', 0, 'y', 0,
80 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, 'I', 0, 'n', 0, 't', 0, 'e',
81 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0};
82
83//*****************************************************************************
84//
85// The configuration description string.
86//
87//*****************************************************************************
88static const uint8_t g_pui8ConfigString[] = {(26 + 1) * 2, USB_DTYPE_STRING,
89 'H', 0, 'I', 0, 'D', 0, ' ', 0, 'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a',
90 0, 'r', 0, 'd', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0, 'f', 0, 'i', 0, 'g', 0,
91 'u', 0, 'r', 0, 'a', 0, 't', 0, 'i', 0, 'o', 0, 'n', 0};
92
93//*****************************************************************************
94//
95// The descriptor string table.
96//
97//*****************************************************************************
98static const uint8_t *const g_ppui8StringDescriptors[] = {g_pui8LangDescriptor,
99 g_pui8ManufacturerString, g_pui8ProductString, g_pui8SeriailNumberString,
100 g_pui8HIDInterfaceString, g_pui8ConfigString};
101
102#define NUM_STRING_DESCRIPTORS \
103 (sizeof(g_ppui8StringDescriptors) / sizeof(uint8_t *))
104
105//*****************************************************************************
106//
107// A mapping from the ASCII value received from the UART to the corresponding
108// USB HID usage code.
109//
110//*****************************************************************************
111static const int8_t g_ppi8KeyUsageCodes[][2] = {
112 {0, 0}, // 0x00
113 {0, 0}, // 0x01
114 {0, 0}, // 0x02
115 {0, 0}, // 0x03
116 {0, 0}, // 0x04
117 {0, 0}, // 0x05
118 {0, 0}, // 0x06
119 {0, 0}, // 0x07
120 {0, HID_KEYB_USAGE_BACKSPACE}, // 0x08 '\b'
121 {0, 0}, // 0x09
122 {0, HID_KEYB_USAGE_ENTER}, // 0x0a '\n'
123 {0, 0}, // 0x0b
124 {0, 0}, // 0x0c
125 {0, 0}, // 0x0d
126 {0, 0}, // 0x0e
127 {0, 0}, // 0x0f
128 {0, 0}, // 0x10
129 {0, 0}, // 0x11
130 {0, 0}, // 0x12
131 {0, 0}, // 0x13
132 {0, 0}, // 0x14
133 {0, 0}, // 0x15
134 {0, 0}, // 0x16
135 {0, 0}, // 0x17
136 {0, 0}, // 0x18
137 {0, 0}, // 0x19
138 {0, 0}, // 0x1a
139 {0, 0}, // 0x1b
140 {0, 0}, // 0x1c
141 {0, 0}, // 0x1d
142 {0, 0}, // 0x1e
143 {0, 0}, // 0x1f
144 {0, HID_KEYB_USAGE_SPACE}, // 0x20
145 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_1}, // ! 0x21
146 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_FQUOTE}, // " 0x22
147 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_3}, // # 0x23
148 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_4}, // $ 0x24
149 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_5}, // % 0x25
150 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_7}, // & 0x26
151 {0, HID_KEYB_USAGE_FQUOTE}, // ' 0x27
152 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_9}, // ( 0x28
153 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_0}, // ) 0x29
154 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_8}, // * 0x2a
155 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_EQUAL}, // + 0x2b
156 {0, HID_KEYB_USAGE_COMMA}, // , 0x2c
157 {0, HID_KEYB_USAGE_MINUS}, // - 0x2d
158 {0, HID_KEYB_USAGE_PERIOD}, // . 0x2e
159 {0, HID_KEYB_USAGE_FSLASH}, // / 0x2f
160 {0, HID_KEYB_USAGE_0}, // 0 0x30
161 {0, HID_KEYB_USAGE_1}, // 1 0x31
162 {0, HID_KEYB_USAGE_2}, // 2 0x32
163 {0, HID_KEYB_USAGE_3}, // 3 0x33
164 {0, HID_KEYB_USAGE_4}, // 4 0x34
165 {0, HID_KEYB_USAGE_5}, // 5 0x35
166 {0, HID_KEYB_USAGE_6}, // 6 0x36
167 {0, HID_KEYB_USAGE_7}, // 7 0x37
168 {0, HID_KEYB_USAGE_8}, // 8 0x38
169 {0, HID_KEYB_USAGE_9}, // 9 0x39
170 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_SEMICOLON}, // : 0x3a
171 {0, HID_KEYB_USAGE_SEMICOLON}, // ; 0x3b
172 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_COMMA}, // < 0x3c
173 {0, HID_KEYB_USAGE_EQUAL}, // = 0x3d
174 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_PERIOD}, // > 0x3e
175 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_FSLASH}, // ? 0x3f
176 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_2}, // @ 0x40
177 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_A}, // A 0x41
178 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_B}, // B 0x42
179 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_C}, // C 0x43
180 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_D}, // D 0x44
181 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_E}, // E 0x45
182 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_F}, // F 0x46
183 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_G}, // G 0x47
184 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_H}, // H 0x48
185 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_I}, // I 0x49
186 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_J}, // J 0x4a
187 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_K}, // K 0x4b
188 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_L}, // L 0x4c
189 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_M}, // M 0x4d
190 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_N}, // N 0x4e
191 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_O}, // O 0x4f
192 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_P}, // P 0x50
193 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_Q}, // Q 0x51
194 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_R}, // R 0x52
195 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_S}, // S 0x53
196 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_T}, // T 0x54
197 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_U}, // U 0x55
198 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_V}, // V 0x56
199 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_W}, // W 0x57
200 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_X}, // X 0x58
201 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_Y}, // Y 0x59
202 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_Z}, // Z 0x5a
203 {0, HID_KEYB_USAGE_LBRACKET}, // [ 0x5b
204 {0, HID_KEYB_USAGE_BSLASH}, // \ 0x5c
205 {0, HID_KEYB_USAGE_RBRACKET}, // ] 0x5d
206 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_6}, // ^ 0x5e
207 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_MINUS}, // _ 0x5f
208 {0, HID_KEYB_USAGE_BQUOTE}, // ` 0x60
209 {0, HID_KEYB_USAGE_A}, // a 0x61
210 {0, HID_KEYB_USAGE_B}, // b 0x62
211 {0, HID_KEYB_USAGE_C}, // c 0x63
212 {0, HID_KEYB_USAGE_D}, // d 0x64
213 {0, HID_KEYB_USAGE_E}, // e 0x65
214 {0, HID_KEYB_USAGE_F}, // f 0x66
215 {0, HID_KEYB_USAGE_G}, // g 0x67
216 {0, HID_KEYB_USAGE_H}, // h 0x68
217 {0, HID_KEYB_USAGE_I}, // i 0x69
218 {0, HID_KEYB_USAGE_J}, // j 0x6a
219 {0, HID_KEYB_USAGE_K}, // k 0x6b
220 {0, HID_KEYB_USAGE_L}, // l 0x6c
221 {0, HID_KEYB_USAGE_M}, // m 0x6d
222 {0, HID_KEYB_USAGE_N}, // n 0x6e
223 {0, HID_KEYB_USAGE_O}, // o 0x6f
224 {0, HID_KEYB_USAGE_P}, // p 0x70
225 {0, HID_KEYB_USAGE_Q}, // q 0x71
226 {0, HID_KEYB_USAGE_R}, // r 0x72
227 {0, HID_KEYB_USAGE_S}, // s 0x73
228 {0, HID_KEYB_USAGE_T}, // t 0x74
229 {0, HID_KEYB_USAGE_U}, // u 0x75
230 {0, HID_KEYB_USAGE_V}, // v 0x76
231 {0, HID_KEYB_USAGE_W}, // w 0x77
232 {0, HID_KEYB_USAGE_X}, // x 0x78
233 {0, HID_KEYB_USAGE_Y}, // y 0x79
234 {0, HID_KEYB_USAGE_Z}, // z 0x7a
235 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_LBRACKET}, // { 0x7b
236 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_BSLASH}, // | 0x7c
237 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_RBRACKET}, // } 0x7d
238 {HID_KEYB_LEFT_SHIFT, HID_KEYB_USAGE_BQUOTE}, // ~ 0x7e
239};
240
241static uint32_t static_keyboard_handler(
242 void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData, void *pvMsgData)
243{
245 ui32Event, ui32MsgData, pvMsgData);
246}
247
248TivaUsbKeyboardDev::TivaUsbKeyboardDev(const char *name, uint32_t interrupt)
249 : Serial(name, 32, 1)
250 , tivaKeyboardDevice_{USB_VID_TI_1CBE, USB_PID_KEYBOARD, 500,
251 USB_CONF_ATTR_SELF_PWR | USB_CONF_ATTR_RWAKE, static_keyboard_handler,
252 (void *)&tivaKeyboardDevice_, g_ppui8StringDescriptors,
254 , isConnected_(0)
255 , isSuspended_(0)
256 , txPending_(0)
257 , keyUpPending_(0)
258{
259 /* USB interrupt low priority. We make this a low priority because
260 * USB interrupts perform a decent amount of processing and we want
261 * to maintain the overall determinism of our system.
262 */
263 MAP_IntPrioritySet(interrupt, 0xff);
264
265 USBStackModeSet(0, eUSBModeDevice, 0);
266 USBDHIDKeyboardInit(0, &tivaKeyboardDevice_);
267}
268
270{
271 if (!isConnected_)
272 {
273 return;
274 }
275 if (isSuspended_)
276 {
277 USBDHIDKeyboardRemoteWakeupRequest((void *)&tivaKeyboardDevice_);
278 txPending_ = true;
279 return;
280 }
281 if (!txPending_)
282 {
284 }
285}
286
288{
289 if (txBuf->pending() == 0)
290 {
291 return true;
292 }
294 txPending_ = true;
295 uint8_t *data;
296 txBuf->data_read_pointer(&data);
297 uint32_t ui32Char = (*data);
298 if (keyUpPending_)
299 {
300 if (USBDHIDKeyboardKeyStateChange((void *)&tivaKeyboardDevice_, 0,
301 g_ppi8KeyUsageCodes[ui32Char][1], false) != KEYB_SUCCESS)
302 {
303 ++errorCount_;
304 }
305 keyUpPending_ = 0;
306 txBuf->consume(1);
307 return true;
308 }
309 else
310 {
311 if (USBDHIDKeyboardKeyStateChange((void *)&tivaKeyboardDevice_,
312 g_ppi8KeyUsageCodes[ui32Char][0],
313 g_ppi8KeyUsageCodes[ui32Char][1], true) != KEYB_SUCCESS)
314 {
315 ++errorCount_;
316 }
317 keyUpPending_ = 1;
318 return false;
319 }
320}
321
323 uint32_t ui32Event, uint32_t ui32MsgData, void *pvMsgData)
324{
325 switch (ui32Event)
326 {
327 //
328 // The host has connected to us and configured the device.
329 //
330 case USB_EVENT_CONNECTED:
331 {
332 isConnected_ = true;
333 isSuspended_ = false;
335 break;
336 }
337
338 //
339 // The host has disconnected from us.
340 //
341 case USB_EVENT_DISCONNECTED:
342 {
343 isConnected_ = false;
344 txPending_ = false;
345 break;
346 }
347
348 //
349 // We receive this event every time the host acknowledges transmission
350 // of a report.
351 //
352 case USB_EVENT_TX_COMPLETE:
353 {
354 txPending_ = false;
355 if (send_next_event())
356 {
358 }
359 break;
360 }
361
362 //
363 // This event indicates that the host has suspended the USB bus.
364 //
365 case USB_EVENT_SUSPEND:
366 {
367 isSuspended_ = true;
368 break;
369 }
370
371 //
372 // This event signals that the host has resumed signalling on the bus.
373 //
374 case USB_EVENT_RESUME:
375 {
376 isSuspended_ = false;
377 txPending_ = false;
378 if (send_next_event())
379 {
381 }
382 break;
383 }
384
385 //
386 // This event indicates that the host has sent us an Output or
387 // Feature report and that the report is now in the buffer we provided
388 // on the previous USBD_HID_EVENT_GET_REPORT_BUFFER callback.
389 //
390 case USBD_HID_KEYB_EVENT_SET_LEDS:
391 {
392 uint8_t response = ui32MsgData & 0xff;
393 if (!rxBuf->put(&response, 1))
394 {
395 overrunCount++;
396 }
397 else
398 {
400 }
401 break;
402 }
403 }
404 return 0;
405}
406
407extern "C" {
411{
412 USB0DeviceIntHandler();
413}
414
415} // extern "C"
#define NUM_STRING_DESCRIPTORS
number of string descriptors
void usb0_interrupt_handler(void)
Handle interrupts for USB0.
size_t pending()
Return the number of items in the queue.
size_t consume(size_t items)
Remove a number of items from the buffer by advancing the readIndex.
void signal_condition_from_isr()
Signal the wakeup condition from an ISR context.
size_t put(const T *buf, size_t items)
Insert a number of items to the buffer.
size_t data_read_pointer(T **buf)
Get a reference to the current location in the buffer for read.
Private data for a serial device.
Definition Serial.hxx:46
DeviceBuffer< uint8_t > * rxBuf
receive buffer
Definition Serial.hxx:85
DeviceBuffer< uint8_t > * txBuf
transmit buffer
Definition Serial.hxx:84
unsigned int overrunCount
overrun count
Definition Serial.hxx:86
static TivaUsbKeyboardDev * instance()
Definition Singleton.hxx:77
tUSBDHIDKeyboardDevice tivaKeyboardDevice_
Keyboard driver structure.
uint8_t isConnected_
Whether the USB host has connected to this device.
uint8_t isSuspended_
Whether the USB bus is suspended.
void tx_char() override
Function to try and transmit a character.
bool send_next_event()
Internal implementation that sends a single keyboard event, from a critical section or in an interrup...
unsigned errorCount_
Number of transmission errors. These occur in the USB device stack.
uint8_t txPending_
Whether we have a pending unfinished send.
uint8_t keyUpPending_
Whether we need to send a key up command still.
uint32_t keyboard_handler(uint32_t ui32Event, uint32_t ui32MsgData, void *pvMsgData)
Callback from the keyboard driver. Called in an interrupt context.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138