source: avrstuff/starkadroid/code/main.c@ 4b06930

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

Copie de ak2usbpour faire starkadroid: usb hid pour borne d'arcade (jusqu'à 36 boutons)

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

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