Statistics
| Branch: | Tag: | Revision:

root / Keyboard.c @ 2e93ce57

History | View | Annotate | Download (10.7 KB)

1
/*
2
             LUFA Library
3
     Copyright (C) Dean Camera, 2011.
4

5
  dean [at] fourwalledcubicle [dot] com
6
           www.lufa-lib.org
7
*/
8

    
9
/*
10
  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
  Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)
12

13
  Permission to use, copy, modify, distribute, and sell this
14
  software and its documentation for any purpose is hereby granted
15
  without fee, provided that the above copyright notice appear in
16
  all copies and that both that the copyright notice and this
17
  permission notice and warranty disclaimer appear in supporting
18
  documentation, and that the name of the author not be used in
19
  advertising or publicity pertaining to distribution of the
20
  software without specific, written prior permission.
21

22
  The author disclaim all warranties with regard to this
23
  software, including all implied warranties of merchantability
24
  and fitness.  In no event shall the author be liable for any
25
  special, indirect or consequential damages or any damages
26
  whatsoever resulting from loss of use, data or profits, whether
27
  in an action of contract, negligence or other tortious action,
28
  arising out of or in connection with the use or performance of
29
  this software.
30
*/
31

    
32
/** \file
33
 *
34
 *  Main source file for the Keyboard demo. This file contains the main tasks of the demo and
35
 *  is responsible for the initial application hardware configuration.
36
 */
37

    
38
#include "Keyboard.h"
39
#include "MatrixScan.h"
40

    
41
/** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot
42
 *  protocol reporting mode.
43
 */
44
static bool UsingReportProtocol = true;
45

    
46
/** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports
47
 *  for either the entire idle duration, or until the report status changes (e.g. the user presses a key).
48
 */
49
static uint16_t IdleCount = 500;
50

    
51
/** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
52
 *  milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request
53
 *  the current idle period via a Get Idle HID class request, thus its value must be preserved.
54
 */
55
static uint16_t IdleMSRemaining = 0;
56

    
57
/** Main program entry point. This routine configures the hardware required by the application, then
58
 *  enters a loop to run the application tasks in sequence.
59
 */
60
int main(void)
61
{
62
        SetupHardware();
63

    
64
        //LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
65
        sei();
66

    
67
        for (;;)
68
        {
69
                HID_Task();
70
                USB_USBTask();
71
        }
72
}
73

    
74
/** Configures the board hardware and chip peripherals for the demo's functionality. */
75
void SetupHardware(void)
76
{
77
        /* Disable watchdog if enabled by bootloader/fuses */
78
        MCUSR &= ~(1 << WDRF);
79
        wdt_disable();
80

    
81
        /* Disable clock division */
82
        clock_prescale_set(clock_div_1);
83

    
84
        /* Hardware Initialization */
85
        //LEDs_Init();
86
        USB_Init();
87
        setupMatrix();
88
}
89

    
90
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
91
 *  starts the library USB task to begin the enumeration and USB management process.
92
 */
93
void EVENT_USB_Device_Connect(void)
94
{
95
        /* Indicate USB enumerating */
96
        //LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
97

    
98
        /* Default to report protocol on connect */
99
        UsingReportProtocol = true;
100
}
101

    
102
/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
103
 *  the status LEDs.
104
 */
105
void EVENT_USB_Device_Disconnect(void)
106
{
107
        /* Indicate USB not ready */
108
        //LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
109
}
110

    
111
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration
112
 *  of the USB device after enumeration, and configures the keyboard device endpoints.
113
 */
114
void EVENT_USB_Device_ConfigurationChanged(void)
115
{
116
        bool ConfigSuccess = true;
117

    
118
        /* Setup HID Report Endpoints */
119
        ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
120
                                                    KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
121
        ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
122
                                                    KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
123

    
124
        /* Turn on Start-of-Frame events for tracking HID report period expiry */
125
        USB_Device_EnableSOFEvents();
126

    
127
        /* Indicate endpoint configuration success or failure */
128
        //LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
129
}
130

    
131
/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
132
 *  the device from the USB host before passing along unhandled control requests to the library for processing
133
 *  internally.
134
 */
135
void EVENT_USB_Device_ControlRequest(void)
136
{
137
        /* Handle HID Class specific requests */
138
        switch (USB_ControlRequest.bRequest)
139
        {
140
                case HID_REQ_GetReport:
141
                        if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
142
                        {
143
                                USB_KeyboardReport_Data_t KeyboardReportData;
144

    
145
                                /* Create the next keyboard report for transmission to the host */
146
                                CreateKeyboardReport(&KeyboardReportData);
147

    
148
                                Endpoint_ClearSETUP();
149

    
150
                                /* Write the report data to the control endpoint */
151
                                Endpoint_Write_Control_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));
152
                                Endpoint_ClearOUT();
153
                        }
154

    
155
                        break;
156
                case HID_REQ_SetReport:
157
                        if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
158
                        {
159
                                Endpoint_ClearSETUP();
160

    
161
                                /* Wait until the LED report has been sent by the host */
162
                                while (!(Endpoint_IsOUTReceived()))
163
                                {
164
                                        if (USB_DeviceState == DEVICE_STATE_Unattached)
165
                                          return;
166
                                }
167

    
168
                                /* Read in the LED report from the host */
169
                                uint8_t LEDStatus = Endpoint_Read_8();
170

    
171
                                Endpoint_ClearOUT();
172
                                Endpoint_ClearStatusStage();
173

    
174
                                /* Process the incoming LED report */
175
                                ProcessLEDReport(LEDStatus);
176
                        }
177

    
178
                        break;
179
                case HID_REQ_GetProtocol:
180
                        if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
181
                        {
182
                                Endpoint_ClearSETUP();
183

    
184
                                /* Write the current protocol flag to the host */
185
                                Endpoint_Write_8(UsingReportProtocol);
186

    
187
                                Endpoint_ClearIN();
188
                                Endpoint_ClearStatusStage();
189
                        }
190

    
191
                        break;
192
                case HID_REQ_SetProtocol:
193
                        if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
194
                        {
195
                                Endpoint_ClearSETUP();
196
                                Endpoint_ClearStatusStage();
197

    
198
                                /* Set or clear the flag depending on what the host indicates that the current Protocol should be */
199
                                UsingReportProtocol = (USB_ControlRequest.wValue != 0);
200
                        }
201

    
202
                        break;
203
                case HID_REQ_SetIdle:
204
                        if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
205
                        {
206
                                Endpoint_ClearSETUP();
207
                                Endpoint_ClearStatusStage();
208

    
209
                                /* Get idle period in MSB, IdleCount must be multiplied by 4 to get number of milliseconds */
210
                                IdleCount = ((USB_ControlRequest.wValue & 0xFF00) >> 6);
211
                        }
212

    
213
                        break;
214
                case HID_REQ_GetIdle:
215
                        if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
216
                        {
217
                                Endpoint_ClearSETUP();
218

    
219
                                /* Write the current idle duration to the host, must be divided by 4 before sent to host */
220
                                Endpoint_Write_8(IdleCount >> 2);
221

    
222
                                Endpoint_ClearIN();
223
                                Endpoint_ClearStatusStage();
224
                        }
225

    
226
                        break;
227
        }
228
}
229

    
230
/** Event handler for the USB device Start Of Frame event. */
231
void EVENT_USB_Device_StartOfFrame(void)
232
{
233
        /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */
234
        if (IdleMSRemaining)
235
          IdleMSRemaining--;
236
}
237

    
238
/** Fills the given HID report data structure with the next HID report to send to the host.
239
 *
240
 *  \param[out] ReportData  Pointer to a HID report data structure to be filled
241
 */
242
void CreateKeyboardReport(USB_KeyboardReport_Data_t* const ReportData)
243
{
244
        /* Clear the report contents */
245
        memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t));
246
        /* Make sent key uppercase by indicating that the left shift key is pressed */
247
        //ReportData->Modifier = HID_KEYBOARD_MODIFER_LEFTSHIFT;
248
        setReportData(ReportData);
249
}
250

    
251
/** Processes a received LED report, and updates the board LEDs states to match.
252
 *
253
 *  \param[in] LEDReport  LED status report from the host
254
 */
255
void ProcessLEDReport(const uint8_t LEDReport)
256
{
257
        return;
258
}
259

    
260
/** Sends the next HID report to the host, via the keyboard data endpoint. */
261
void SendNextReport(void)
262
{
263
        static USB_KeyboardReport_Data_t PrevKeyboardReportData;
264
        USB_KeyboardReport_Data_t        KeyboardReportData;
265
        bool                             SendReport = true;
266

    
267
        /* Create the next keyboard report for transmission to the host */
268
        CreateKeyboardReport(&KeyboardReportData);
269

    
270
        /* Check to see if the report data has changed - if so a report MUST be sent */
271
        SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0);
272

    
273
        /* Check if the idle period is set and has elapsed */
274
        if (IdleCount && (!(IdleMSRemaining)))
275
        {
276
                /* Reset the idle time remaining counter */
277
                IdleMSRemaining = IdleCount;
278

    
279
                /* Idle period is set and has elapsed, must send a report to the host */
280
                SendReport = true;
281
        }
282

    
283
        /* Select the Keyboard Report Endpoint */
284
        Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
285

    
286
        /* Check if Keyboard Endpoint Ready for Read/Write and if we should send a new report */
287
        if (Endpoint_IsReadWriteAllowed() && SendReport)
288
        {
289
                /* Save the current report data for later comparison to check for changes */
290
                PrevKeyboardReportData = KeyboardReportData;
291

    
292
                /* Write Keyboard Report Data */
293
                Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData), NULL);
294

    
295
                /* Finalize the stream transfer to send the last packet */
296
                Endpoint_ClearIN();
297
        }
298
}
299

    
300
/** Reads the next LED status report from the host from the LED data endpoint, if one has been sent. */
301
void ReceiveNextReport(void)
302
{
303
        /* Select the Keyboard LED Report Endpoint */
304
        Endpoint_SelectEndpoint(KEYBOARD_OUT_EPNUM);
305

    
306
        /* Check if Keyboard LED Endpoint contains a packet */
307
        if (Endpoint_IsOUTReceived())
308
        {
309
                /* Check to see if the packet contains data */
310
                if (Endpoint_IsReadWriteAllowed())
311
                {
312
                        /* Read in the LED report from the host */
313
                        uint8_t LEDReport = Endpoint_Read_8();
314

    
315
                        /* Process the read LED report from the host */
316
                        ProcessLEDReport(LEDReport);
317
                }
318

    
319
                /* Handshake the OUT Endpoint - clear endpoint and ready for next report */
320
                Endpoint_ClearOUT();
321
        }
322
}
323

    
324
/** Function to manage HID report generation and transmission to the host, when in report mode. */
325
void HID_Task(void)
326
{
327
        /* Device must be connected and configured for the task to run */
328
        if (USB_DeviceState != DEVICE_STATE_Configured)
329
          return;
330

    
331
        /* Send the next keypress report to the host */
332
        SendNextReport();
333

    
334
        /* Process the LED report sent from the host */
335
        ReceiveNextReport();
336
}
337