1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
|
//*****************************************************************************
//
// usb_dev_mouse.c - Main routines for the mouse device.
//
// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "driverlib/systick.h"
#include "grlib/grlib.h"
#include "grlib/widget.h"
#include "usblib/usblib.h"
#include "usblib/usbhid.h"
#include "usblib/device/usbdevice.h"
#include "usblib/device/usbdhid.h"
#include "usblib/device/usbdhidmouse.h"
#include "utils/uartstdio.h"
#include "usb_mouse_structs.h"
#include "drivers/touch.h"
#include "usb_otg_mouse.h"
//*****************************************************************************
//
// The GPIO pin which is connected to the select button.
//
//*****************************************************************************
#define SEL_BTN_PORT GPIO_PORTP_BASE
#define SEL_BTN_PIN GPIO_PIN_1
//*****************************************************************************
//
// The defines used with the g_ui32Commands variable.
//
//*****************************************************************************
#define UPDATE_TICK_EVENT 0x80000000
//*****************************************************************************
//
// The incremental update for the mouse.
//
//*****************************************************************************
#define MOUSE_MOVE_INC ((char)4)
#define MOUSE_MOVE_DEC ((char)-4)
//*****************************************************************************
//
// The HID mouse report offsets for this mouse application.
//
//*****************************************************************************
#define HID_REPORT_BUTTONS 0
#define HID_REPORT_X 1
#define HID_REPORT_Y 2
//*****************************************************************************
//
// Holds command bits used to signal the main loop to perform various tasks.
//
//*****************************************************************************
volatile uint32_t g_ui32Commands;
//*****************************************************************************
//
// Holds the current state of the touchscreen - pressed or not.
//
//*****************************************************************************
volatile bool g_bScreenPressed;
//*****************************************************************************
//
// Holds the current state of the user button - pressed or not.
//
//*****************************************************************************
volatile bool g_bButtonPressed;
//*****************************************************************************
//
// A flag used to indicate whether or not we are currently connected to the USB
// host.
//
//*****************************************************************************
volatile bool g_bConnected;
//*****************************************************************************
//
// Holds the previous press position for the touchscreen.
//
//*****************************************************************************
volatile int32_t g_i32ScreenStartX;
volatile int32_t g_i32ScreenStartY;
//*****************************************************************************
//
// Holds the current press position for the touchscreen.
//
//*****************************************************************************
volatile int32_t g_i32ScreenX;
volatile int32_t g_i32ScreenY;
//*****************************************************************************
//
// The system tick timer rate.
//
//*****************************************************************************
#define SYSTICKS_PER_SECOND 100
#define MS_PER_SYSTICK (1000 / SYSTICKS_PER_SECOND)
//*****************************************************************************
//
// Global system tick counter holds elapsed time since the application started
// expressed in 100ths of a second.
//
//*****************************************************************************
volatile uint32_t g_ui32SysTickCount;
//*****************************************************************************
//
// Global system tick counter hold the g_ui32SysTickCount the last time
// GetTickms() was called.
//
//*****************************************************************************
static uint32_t g_ui32LastTick;
//*****************************************************************************
//
// The number of system ticks to wait for each USB packet to be sent before
// we assume the host has disconnected. The value 50 equates to half a second.
//
//*****************************************************************************
#define MAX_SEND_DELAY 50
//*****************************************************************************
//
// This enumeration holds the various states that the mouse can be in during
// normal operation.
//
//*****************************************************************************
volatile enum
{
//
// Unconfigured.
//
eMouseStateUnconfigured,
//
// No keys to send and not waiting on data.
//
eMouseStateIdle,
//
// Waiting on data to be sent out.
//
eMouseStateSend
}
g_iMouseState = eMouseStateUnconfigured;
uint32_t
MouseHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData,
void *pvMsgData)
{
switch(ui32Event)
{
//
// The USB host has connected to and configured the device.
//
case USB_EVENT_CONNECTED:
{
UARTprintf("Host connected.\n");
g_iMouseState = eMouseStateIdle;
g_bConnected = true;
break;
}
//
// The USB host has disconnected from the device.
//
case USB_EVENT_DISCONNECTED:
{
UARTprintf("Host disconnected.\n");
g_bConnected = false;
g_iMouseState = eMouseStateUnconfigured;
break;
}
//
// A report was sent to the host. We are now free to send another.
//
case USB_EVENT_TX_COMPLETE:
{
g_iMouseState = eMouseStateIdle;
break;
}
}
return(0);
}
//***************************************************************************
//
// Wait for a period of time for the state to become idle or unconfigured.
//
// \param ui32TimeoutTick is the number of system ticks to wait before
// declaring a timeout and returning \b false.
//
// This function polls the current mouse state for ui32TimeoutTicks system
// ticks waiting for it to either become idle or unconfigured. If the state
// becomes one of these, the function returns true. If ui32TimeoutTicks
// occur prior to the state becoming idle or unconfigured, false is returned
// to indicate a timeout.
//
// \return Returns \b true on success or \b false on timeout.
//
//***************************************************************************
bool
WaitForSendIdle(uint32_t ui32TimeoutTicks)
{
uint32_t ui32Start, ui32Now, ui32Elapsed;
ui32Start = g_ui32SysTickCount;
ui32Elapsed = 0;
while(ui32Elapsed < ui32TimeoutTicks)
{
//
// Is the mouse is idle or we have disconnected, return immediately.
//
if((g_iMouseState == eMouseStateIdle) ||
(g_iMouseState == eMouseStateUnconfigured))
{
return(true);
}
//
// Determine how much time has elapsed since we started waiting. This
// should be safe across a wrap of g_ui32SysTickCount. I suspect you
// won't likely leave the app running for the 497.1 days it will take
// for this to occur but you never know...
//
ui32Now = g_ui32SysTickCount;
ui32Elapsed = (ui32Start < ui32Now) ? (ui32Now - ui32Start) :
(((uint32_t)0xFFFFFFFF - ui32Start) + ui32Now + 1);
}
//
// If we get here, we timed out so return a bad return code to let the
// caller know.
//
return(false);
}
//*****************************************************************************
//
// This is the interrupt handler for the SysTick interrupt. It is called
// periodically and updates a global tick counter then sets a flag to tell the
// main loop to check to see if a new HID report should be sent to the host.
//
//*****************************************************************************
void
SysTickHandler(void)
{
g_ui32SysTickCount++;
g_ui32Commands |= UPDATE_TICK_EVENT;
}
//*****************************************************************************
//
// This function handles updates due to the touchscreen and buttons.
//
// This function is called from the main loop each time the touchscreen state
// needs to be checked. If it detects an update it will schedule an transfer
// to the host.
//
// Returns Returns \b true on success or \b false if an error is detected.
//
//*****************************************************************************
bool
TouchEventHandler(void)
{
uint32_t ui32Retcode;
int32_t i32DeltaX, i32DeltaY;
bool bSuccess;
bool bBtnPressed;
//
// Assume all is well until we determine otherwise.
//
bSuccess = true;
//
// Get the current state of the select button.
//
bBtnPressed = (ROM_GPIOPinRead(SEL_BTN_PORT, SEL_BTN_PIN) & SEL_BTN_PIN) ?
false : true;
//
// Is someone pressing the screen or has the button changed state? If so,
// we determine how far they have dragged their finger/stylus and use this
// to calculate mouse position changes to send to the host.
//
if(g_bScreenPressed || (bBtnPressed != g_bButtonPressed))
{
//
// Calculate how far we moved since the last time we checked. This
// rather odd layout prevents a compiler warning about undefined order
// of volatile accesses.
//
i32DeltaX = g_i32ScreenX;
i32DeltaX -= g_i32ScreenStartX;
i32DeltaY = g_i32ScreenY;
i32DeltaY -= g_i32ScreenStartY;
//
// Reset our start position.
//
g_i32ScreenStartX = g_i32ScreenX;
g_i32ScreenStartY = g_i32ScreenY;
//
// Was there any movement or change in button state?
//
if(i32DeltaX || i32DeltaY || (bBtnPressed != g_bButtonPressed))
{
//
// Yes - send a report back to the host after clipping the deltas
// to the maximum we can support.
//
i32DeltaX = (i32DeltaX > 127) ? 127 : i32DeltaX;
i32DeltaX = (i32DeltaX < -128) ? -128 : i32DeltaX;
i32DeltaY = (i32DeltaY > 127) ? 127 : i32DeltaY;
i32DeltaY = (i32DeltaY < -128) ? -128 : i32DeltaY;
//
// Remember the current button state.
//
g_bButtonPressed = bBtnPressed;
//
// Send the report back to the host.
//
g_iMouseState = eMouseStateSend;
ui32Retcode = USBDHIDMouseStateChange((void *)&g_sMouseDevice,
(char)i32DeltaX, (char)i32DeltaY,
(bBtnPressed ?
MOUSE_REPORT_BUTTON_1 : 0));
//
// Did we schedule the report for transmission?
//
if(ui32Retcode == MOUSE_SUCCESS)
{
//
// Wait for the host to acknowledge the transmission if all went
// well.
//
bSuccess = WaitForSendIdle(MAX_SEND_DELAY);
//
// Did we time out waiting for the packet to be sent?
//
if (!bSuccess)
{
//
// Yes - assume the host disconnected and go back to
// waiting for a new connection.
//
UARTprintf("Send timed out!\n");
g_bConnected = 0;
}
}
else
{
//
// An error was reported when trying to send the report. This
// may be due to host disconnection but could also be due to a
// clash between our attempt to send a report and the driver
// sending the last report in response to an idle timer timeout
// so we don't jump to the conclusion that we were disconnected
// in this case.
//
UARTprintf("Can't send report.\n");
bSuccess = false;
}
}
}
return(bSuccess);
}
//*****************************************************************************
//
// This function is called by the touchscreen driver whenever there is a
// change in press state or position.
//
//*****************************************************************************
int32_t
DeviceMouseTouchCallback(uint32_t ui32Message, int32_t i32X, int32_t i32Y)
{
switch(ui32Message)
{
//
// The touchscreen has been pressed. Remember where we are so that
// we can determine how far the pointer moves later.
//
case WIDGET_MSG_PTR_DOWN:
g_i32ScreenStartX = i32X;
g_i32ScreenStartY = i32Y;
g_i32ScreenX = i32X;
g_i32ScreenY = i32Y;
g_bScreenPressed = true;
break;
//
// The touchscreen is no longer being pressed.
//
case WIDGET_MSG_PTR_UP:
g_bScreenPressed = false;
break;
//
// The user is dragging his/her finger/stylus over the touchscreen.
//
case WIDGET_MSG_PTR_MOVE:
g_i32ScreenX = i32X;
g_i32ScreenY = i32Y;
break;
}
//
// Tell the mouse driver we handled the message.
//
return(1);
}
//*****************************************************************************
//
// This function initializes the mouse in device mode.
//
//*****************************************************************************
void
DeviceInit(void)
{
//
// Initialize the touchscreen driver and install our event handler.
//
TouchScreenInit(g_ui32SysClock);
TouchScreenCallbackSet(DeviceMouseTouchCallback);
//
// Set the system tick to fire 100 times per second.
//
ROM_SysTickPeriodSet(g_ui32SysClock / SYSTICKS_PER_SECOND);
ROM_SysTickIntEnable();
ROM_SysTickEnable();
//
// Pass the USB library our device information, initialize the USB
// controller and connect the device to the bus.
//
USBDHIDMouseInit(0, (tUSBDHIDMouseDevice *)&g_sMouseDevice);
}
//*****************************************************************************
//
// This is the main loop that runs the mouse device application.
//
//*****************************************************************************
void
DeviceMain(void)
{
bool bRetcode;
if(g_iMouseState == eMouseStateUnconfigured)
{
return;
}
//
// If it is time to check the touchscreen state then do so.
//
if(g_ui32Commands & UPDATE_TICK_EVENT)
{
g_ui32Commands &= ~UPDATE_TICK_EVENT;
TouchEventHandler();
//
// Wait for the last data to go out before sending more data. Also
// ensure that we drop out if the device is disconnected.
//
bRetcode = WaitForSendIdle(MAX_SEND_DELAY);
//
// If we timed out, assume the host disconnected and start looking
// for a new connection.
//
if(!bRetcode)
{
g_iMouseState = eMouseStateUnconfigured;
}
}
}
//*****************************************************************************
//
// This function returns the number of ticks since the last time this function
// was called.
//
//*****************************************************************************
uint32_t
GetTickms(void)
{
uint32_t ui32RetVal, ui32Saved;
ui32RetVal = g_ui32SysTickCount;
ui32Saved = ui32RetVal;
if(ui32Saved > g_ui32LastTick)
{
ui32RetVal = ui32Saved - g_ui32LastTick;
}
else
{
ui32RetVal = g_ui32LastTick - ui32Saved;
}
//
// This could miss a few milliseconds but the timings here are on a
// much larger scale.
//
g_ui32LastTick = ui32Saved;
//
// Return the number of milliseconds since the last time this was called.
//
return(ui32RetVal * MS_PER_SYSTICK);
}
|