source: avrstuff/aktousb/code/main.c@ ff4dbfd

main
Last change on this file since ff4dbfd was ff4dbfd, checked in by Adrien Destugues <pulkomandy@…>, 14 years ago

Gestion correcte de la touche capslock.

git-svn-id: svn://pulkomandy.tk/avrstuff@15 c6672c3c-f6b6-47f9-9001-1fd6b12fecbe

  • Property mode set to 100644
File size: 10.1 KB
Line 
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include <avr/wdt.h>
4#include <avr/pgmspace.h>
5#include <util/delay.h>
6
7#include <string.h>
8
9#include "amiga_keyboard/amiga_keyboard.h"
10#include "usbdrv/usbdrv.h"
11#include "keycodes.h"
12
13static uint8_t pressingCaps = 0;
14
15const uint8_t PROGMEM keymatrix[0x70] = {
16// 0 1 2 3 4 5 6 7 8 9 A B C D E F
17KEY_grave, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_minus, KEY_equals, KEY_F11, KEY_Reserved, KEY_KP0, //0
18KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_lbracket, KEY_rbracket, KEY_Reserved, KEY_KP1, KEY_KP2, KEY_KP3, //1
19KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_semicolon, KEY_apostroph,KEY_hash, KEY_Reserved, KEY_KP4, KEY_KP5, KEY_KP6, //2
20KEY_Euro, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_comma, KEY_dot, KEY_slash, KEY_Reserved, KEY_KPcomma, KEY_KP7, KEY_KP8, KEY_KP9, //3
21KEY_Spacebar,KEY_DELETE, KEY_Tab, KEY_KPenter, KEY_Return,KEY_ESCAPE,KEY_DeleteForward,KEY_Reserved,KEY_Reserved,KEY_Reserved, KEY_KPminus, KEY_Reserved, KEY_UpArrow, KEY_DownArrow, KEY_RightArrow,KEY_LeftArrow,//4
22KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_Home, KEY_End, KEY_KPslash, KEY_KPasterisk,KEY_KPplus, KEY_F12, //5
23KEY_Reserved,KEY_Reserved,KEY_capslock,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved,KEY_Reserved, KEY_Reserved, KEY_Reserved, //6
24};
25
26/**
27 * The modmatrix-array contains positions of the modifier-keys in the matrix.
28 * It is built in the same way as the keymatrix-array.
29 * \sa keymatrix
30 */
31const uint8_t PROGMEM modmatrix[8] = { // contains positions of modifiers in the matrix
32 // 0 1 2 3 4 5 6 7
33MOD_SHIFT_LEFT,MOD_SHIFT_RIGHT,MOD_NONE,MOD_CONTROL_LEFT,MOD_ALT_LEFT,MOD_ALT_RIGHT, MOD_GUI_LEFT, MOD_GUI_RIGHT,
34};
35
36static uint8_t idleRate;
37static uint8_t reportIndex = 2;
38static uint8_t reportBuffer[8];
39
40void fillReportBuffer(uint8_t key_code) {
41 uint8_t key, modifier;
42 key = pgm_read_byte(&keymatrix[key_code]);
43 if (key_code >= 0x60 && key_code < 0x68)
44 modifier = pgm_read_byte(&modmatrix[key_code - 0x60]);
45 else
46 modifier = MOD_NONE;
47
48 if (key != KEY_Reserved && reportIndex < 8) {
49 reportBuffer[reportIndex] = key; // set next available entry
50 reportIndex++;
51 if (key == KEY_capslock)
52 pressingCaps = 1;
53 }
54 reportBuffer[0] |= modifier;
55}
56
57
58void emptyReportBuffer(uint8_t key_code) {
59
60 uint8_t key, modifier;
61 uint8_t i;
62 key = pgm_read_byte(&keymatrix[key_code]);
63 if (key_code >= 0x60 && key_code < 0x68)
64 modifier = pgm_read_byte(&modmatrix[key_code - 0x60]);
65 else
66 modifier = MOD_NONE;
67
68 if (key == KEY_capslock) {
69 if (reportIndex < 8) {
70 reportBuffer[reportIndex] = key; // set next available entry
71 reportIndex++;
72 pressingCaps = 1;
73 }
74 } else if (key != KEY_Reserved) {
75 for (i = 2; i < reportIndex; i++) {
76 if (reportBuffer[i] == key) {
77 for (; i < 7; i++)
78 reportBuffer[i] = reportBuffer[i+1];
79 reportBuffer[7] = 0;
80 reportIndex--;
81 }
82 }
83 }
84 reportBuffer[0] &= ~modifier;
85}
86
87
88void usbSendReport(uint8_t mode, uint8_t key) {
89 // buffer for HID reports. we use a private one, so nobody gets disturbed
90 uint8_t repBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
91 repBuffer[0] = mode;
92 repBuffer[2] = key;
93 while (!usbInterruptIsReady()); // wait
94 usbSetInterrupt(repBuffer, sizeof(repBuffer)); // send
95}
96
97
98int main() {
99 uint8_t idleCounter = 0;
100 uint8_t updateNeeded = 0;
101 int capsDelay = 16;
102
103 wdt_enable(WDTO_2S);
104 // configure timer 0 for a rate of 12M/(1024 * 256) = 45.78Hz (~22ms)
105 TCCR0 = 5; // timer 0 prescaler: 1024
106
107 //debug LED - output
108 DDRD |= (1<<PD6);
109
110 // Keyboard
111 uint8_t key_code = 255;
112 memset(reportBuffer, 0, sizeof(reportBuffer)); // clear report buffer
113
114 // USB
115 usbInit();
116 ak_init_keyboard();
117 sei();
118
119 while(1) {
120 wdt_reset();
121 usbPoll();
122
123 updateNeeded = char_waiting;
124
125 if (char_waiting) {
126 key_code = ak_read_scancode();
127 // if an update is needed, send the report
128 if ((key_code & 1) == 0)
129 fillReportBuffer(key_code>>1);
130 else
131 emptyReportBuffer(key_code>>1);
132 if (usbInterruptIsReady())
133 usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
134 }
135
136
137 // check timer if we need periodic reports
138 if (TIFR & (1 << TOV0)) {
139 TIFR = (1 << TOV0); // reset flag
140
141 // PORTD ^= (1<<PD6); // blink del : we are alive !
142 if (pressingCaps)
143 PORTD |= 1<<PD6;
144 else
145 PORTD &= ~(1<<PD6);
146
147 if (pressingCaps) {
148 if (--capsDelay == 0) {
149 capsDelay = 16;
150 pressingCaps = 0;
151
152 int i;
153 for (i = 2; i < reportIndex; i++) {
154 if (reportBuffer[i] == KEY_capslock) {
155 for (; i < 7; i++)
156 reportBuffer[i] = reportBuffer[i+1];
157 reportBuffer[7] = 0;
158 reportIndex--;
159 }
160 }
161 }
162 }
163
164 if (idleRate != 0) { // do we need periodic reports?
165 if(idleCounter > 4){ // yes, but not yet
166 idleCounter -= 5; // 22ms in units of 4ms
167 } else { // yes, it is time now
168 idleCounter = idleRate;
169 if (pressingCaps) {
170 emptyReportBuffer(0x62);
171 pressingCaps = 0;
172 }
173 if (usbInterruptIsReady())
174 usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
175 }
176 }
177
178 }
179 }
180
181 return 0;
182}
183
184static uint8_t protocolVer = 1;
185uint8_t expectReport = 0;
186
187#define LED_NUM 0x01 ///< num LED on a boot-protocol keyboard
188#define LED_CAPS 0x02 ///< caps LED on a boot-protocol keyboard
189#define LED_SCROLL 0x04 ///< scroll LED on a boot-protocol keyboard
190#define LED_COMPOSE 0x08 ///< compose LED on a boot-protocol keyboard
191#define LED_KANA 0x10 ///< kana LED on a boot-protocol keyboard
192uint8_t LEDstate = 0; ///< current state of the LEDs
193
194
195char PROGMEM usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
196 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
197 0x09, 0x06, // USAGE (Keyboard)
198 0xa1, 0x01, // COLLECTION (Application)
199 0x05, 0x07, // USAGE_PAGE (Keyboard)
200 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
201 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
202 0x15, 0x00, // LOGICAL_MINIMUM (0)
203 0x25, 0x01, // LOGICAL_MAXIMUM (1)
204 0x75, 0x01, // REPORT_SIZE (1)
205 0x95, 0x08, // REPORT_COUNT (8)
206 0x81, 0x02, // INPUT (Data,Var,Abs)
207 0x95, 0x01, // REPORT_COUNT (1)
208 0x75, 0x08, // REPORT_SIZE (8)
209 0x81, 0x03, // INPUT (Cnst,Var,Abs)
210 0x95, 0x05, // REPORT_COUNT (5)
211 0x75, 0x01, // REPORT_SIZE (1)
212 0x05, 0x08, // USAGE_PAGE (LEDs)
213 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
214 0x29, 0x05, // USAGE_MAXIMUM (Kana)
215 0x91, 0x02, // OUTPUT (Data,Var,Abs)
216 0x95, 0x01, // REPORT_COUNT (1)
217 0x75, 0x03, // REPORT_SIZE (3)
218 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
219 0x95, 0x06, // REPORT_COUNT (6)
220 0x75, 0x08, // REPORT_SIZE (8)
221 0x15, 0x00, // LOGICAL_MINIMUM (0)
222 0x25, 0x65, // LOGICAL_MAXIMUM (101)
223 0x05, 0x07, // USAGE_PAGE (Keyboard)
224 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
225 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
226 0x81, 0x00, // INPUT (Data,Ary,Abs)
227 0xc0 // END_COLLECTION
228};
229
230
231
232
233uint8_t usbFunctionSetup(uint8_t data[8]) {
234 usbRequest_t *rq = (void *)data;
235 usbMsgPtr = reportBuffer;
236 if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
237 // class request type
238 if (rq->bRequest == USBRQ_HID_GET_REPORT) {
239 // wValue: ReportType (highbyte), ReportID (lowbyte)
240 // we only have one report type, so don't look at wValue
241 return sizeof(reportBuffer);
242 } else if (rq->bRequest == USBRQ_HID_SET_REPORT) {
243 if (rq->wLength.word == 1) {
244 // We expect one byte reports
245 expectReport = 1;
246 return 0xff; // Call usbFunctionWrite with data
247 }
248 } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
249 usbMsgPtr = &idleRate;
250 return 1;
251 } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
252 idleRate = rq->wValue.bytes[1];
253 } else if (rq->bRequest == USBRQ_HID_GET_PROTOCOL) {
254 if (rq->wValue.bytes[1] < 1) {
255 protocolVer = rq->wValue.bytes[1];
256 }
257 } else if(rq->bRequest == USBRQ_HID_SET_PROTOCOL) {
258 usbMsgPtr = &protocolVer;
259 return 1;
260 }
261 } else {
262 // no vendor specific requests implemented
263 }
264 return 0;
265}
266
267/**
268 * The write function is called when LEDs should be set. Normally, we get only
269 * one byte that contains info about the LED states.
270 * \param data pointer to received data
271 * \param len number ob bytes received
272 * \return 0x01
273 */
274uint8_t usbFunctionWrite(uchar *data, uchar len) {
275 if (expectReport && (len == 1)) {
276 LEDstate = data[0]; // Get the state of all 5 LEDs
277 /* TODO
278 if (LEDstate & LED_NUM) { // light up caps lock
279 PORTLEDS &= ~(1 << LEDNUM);
280 } else {
281 PORTLEDS |= (1 << LEDNUM);
282 }
283 if (LEDstate & LED_CAPS) { // light up caps lock
284 PORTLEDS &= ~(1 << LEDCAPS);
285 } else {
286 PORTLEDS |= (1 << LEDCAPS);
287 }
288 if (LEDstate & LED_SCROLL) { // light up caps lock
289 PORTLEDS &= ~(1 << LEDSCROLL);
290 } else {
291 PORTLEDS |= (1 << LEDSCROLL);
292 }
293 */
294 }
295 expectReport = 0;
296 return 0x01;
297}
298
Note: See TracBrowser for help on using the repository browser.