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

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

Some fixes and improvements to akusb and lib amiga_keyboard to try not losing that much keypresses.
It's not perfect yet, but it's better.

git-svn-id: svn://pulkomandy.tk/avrstuff@49 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 int j = 0;
81 for (i = 2; i < reportIndex; i++) {
82 if (reportBuffer[i] == key) {
83 j++;
84 reportIndex--;
85 }
86 reportBuffer[i] = reportBuffer[i+j];
87 }
88
89 for (i = reportIndex; i < 8; i++)
90 {
91 reportBuffer[i] = 0;
92 }
93 }
94 reportBuffer[0] &= ~modifier;
95}
96
97
98/*
99void usbSendReport(uint8_t mode, uint8_t key) {
100 // buffer for HID reports. we use a private one, so nobody gets disturbed
101 uint8_t repBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
102 repBuffer[0] = mode;
103 repBuffer[2] = key;
104 while (!usbInterruptIsReady()); // wait
105 usbSetInterrupt(repBuffer, sizeof(repBuffer)); // send
106}
107*/
108
109int main() {
110 uint8_t idleCounter = 0;
111 uint8_t updateNeeded = 0;
112 int capsDelay = 16;
113
114 wdt_enable(WDTO_2S);
115 // configure timer 0 for a rate of 16M/(256 * 256) = ~244Hz
116 TCCR0 = 4; // timer 0 prescaler: 256
117
118 //debug LED - output
119 DDRD |= (1<<PD6);
120
121 // Keyboard
122 uint8_t key_code = 255;
123 memset(reportBuffer, 0, sizeof(reportBuffer)); // clear report buffer
124
125 // USB
126 usbInit();
127 ak_init_keyboard();
128 sei();
129 bool doReport = false;
130 bool doRelease = false;
131
132 while(1) {
133 wdt_reset();
134 usbPoll();
135
136 updateNeeded = char_waiting;
137
138 while (char_waiting) {
139 key_code = ak_read_scancode();
140 // if an update is needed, send the report
141 if ((key_code & 1) == 0) {
142 fillReportBuffer(key_code>>1);
143 LEDON;
144 doReport = true;
145 } else {
146 emptyReportBuffer(key_code>>1);
147 doRelease = true;
148 }
149 }
150
151 if (doReport && usbInterruptIsReady()) {
152 usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
153 LEDOFF;
154 doReport = false;
155 }
156
157
158 // check timer if we need periodic reports
159 if (TIFR & (1 << TOV0)) {
160 TIFR = (1 << TOV0); // reset flag
161
162 if (pressingCaps) {
163 if (--capsDelay == 0) {
164 capsDelay = 16;
165 pressingCaps = 0;
166
167 int i;
168 for (i = 2; i < reportIndex; i++) {
169 if (reportBuffer[i] == KEY_capslock) {
170 for (; i < 7; i++)
171 reportBuffer[i] = reportBuffer[i+1];
172 reportBuffer[7] = 0;
173 reportIndex--;
174 }
175 }
176 }
177 }
178
179 ++idleCounter;
180 if(idleCounter > 4){ // yes, but not yet
181 idleCounter -= 5; // 22ms in units of 4ms
182 } else { // yes, it is time now
183 idleCounter = idleRate;
184 /*
185 if (pressingCaps) {
186 emptyReportBuffer(0x62);
187 pressingCaps = 0;
188 }
189 */
190 if (doRelease && usbInterruptIsReady()) {
191 usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
192 doRelease = false;
193 }
194 }
195 }
196 }
197
198 return 0;
199}
200
201static uint8_t protocolVer = 1;
202uint8_t expectReport = 0;
203
204#define LED_NUM 0x01 ///< num LED on a boot-protocol keyboard
205#define LED_CAPS 0x02 ///< caps LED on a boot-protocol keyboard
206#define LED_SCROLL 0x04 ///< scroll LED on a boot-protocol keyboard
207#define LED_COMPOSE 0x08 ///< compose LED on a boot-protocol keyboard
208#define LED_KANA 0x10 ///< kana LED on a boot-protocol keyboard
209uint8_t LEDstate = 0; ///< current state of the LEDs
210
211
212char PROGMEM usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
213 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
214 0x09, 0x06, // USAGE (Keyboard)
215 0xa1, 0x01, // COLLECTION (Application)
216 0x05, 0x07, // USAGE_PAGE (Keyboard)
217 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
218 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
219 0x15, 0x00, // LOGICAL_MINIMUM (0)
220 0x25, 0x01, // LOGICAL_MAXIMUM (1)
221 0x75, 0x01, // REPORT_SIZE (1)
222 0x95, 0x08, // REPORT_COUNT (8)
223 0x81, 0x02, // INPUT (Data,Var,Abs)
224 0x95, 0x01, // REPORT_COUNT (1)
225 0x75, 0x08, // REPORT_SIZE (8)
226 0x81, 0x03, // INPUT (Cnst,Var,Abs)
227 0x95, 0x05, // REPORT_COUNT (5)
228 0x75, 0x01, // REPORT_SIZE (1)
229 0x05, 0x08, // USAGE_PAGE (LEDs)
230 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
231 0x29, 0x05, // USAGE_MAXIMUM (Kana)
232 0x91, 0x02, // OUTPUT (Data,Var,Abs)
233 0x95, 0x01, // REPORT_COUNT (1)
234 0x75, 0x03, // REPORT_SIZE (3)
235 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
236 0x95, 0x06, // REPORT_COUNT (6)
237 0x75, 0x08, // REPORT_SIZE (8)
238 0x15, 0x00, // LOGICAL_MINIMUM (0)
239 0x25, 0x65, // LOGICAL_MAXIMUM (101)
240 0x05, 0x07, // USAGE_PAGE (Keyboard)
241 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
242 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
243 0x81, 0x00, // INPUT (Data,Ary,Abs)
244 0xc0 // END_COLLECTION
245};
246
247
248
249
250uint8_t usbFunctionSetup(uint8_t data[8]) {
251 usbRequest_t *rq = (void *)data;
252 usbMsgPtr = reportBuffer;
253 if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
254 // class request type
255 if (rq->bRequest == USBRQ_HID_GET_REPORT) {
256 // wValue: ReportType (highbyte), ReportID (lowbyte)
257 // we only have one report type, so don't look at wValue
258 return sizeof(reportBuffer);
259 } else if (rq->bRequest == USBRQ_HID_SET_REPORT) {
260 if (rq->wLength.word == 1) {
261 // We expect one byte reports
262 expectReport = 1;
263 return 0xff; // Call usbFunctionWrite with data
264 }
265 } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
266 usbMsgPtr = &idleRate;
267 return 1;
268 } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
269 idleRate = rq->wValue.bytes[1];
270 } else if (rq->bRequest == USBRQ_HID_GET_PROTOCOL) {
271 if (rq->wValue.bytes[1] < 1) {
272 protocolVer = rq->wValue.bytes[1];
273 }
274 } else if(rq->bRequest == USBRQ_HID_SET_PROTOCOL) {
275 usbMsgPtr = &protocolVer;
276 return 1;
277 }
278 } else {
279 // no vendor specific requests implemented
280 }
281 return 0;
282}
283
284/**
285 * The write function is called when LEDs should be set. Normally, we get only
286 * one byte that contains info about the LED states.
287 * \param data pointer to received data
288 * \param len number ob bytes received
289 * \return 0x01
290 */
291uint8_t usbFunctionWrite(uchar *data, uchar len) {
292 if (expectReport && (len == 1)) {
293 LEDstate = data[0]; // Get the state of all 5 LEDs
294 /* TODO
295 if (LEDstate & LED_NUM) { // light up caps lock
296 PORTLEDS &= ~(1 << LEDNUM);
297 } else {
298 PORTLEDS |= (1 << LEDNUM);
299 }
300 if (LEDstate & LED_CAPS) { // light up caps lock
301 PORTLEDS &= ~(1 << LEDCAPS);
302 } else {
303 PORTLEDS |= (1 << LEDCAPS);
304 }
305 if (LEDstate & LED_SCROLL) { // light up caps lock
306 PORTLEDS &= ~(1 << LEDSCROLL);
307 } else {
308 PORTLEDS |= (1 << LEDSCROLL);
309 }
310 */
311 }
312 expectReport = 0;
313 return 0x01;
314}
315
Note: See TracBrowser for help on using the repository browser.