source: avrstuff/aktousb/code/main.c@ 49fd394

main
Last change on this file since 49fd394 was 49fd394, checked in by Adrien Destugues <pulkomandy@…>, 14 years ago
  • Add aktousb

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

  • Property mode set to 100644
File size: 9.4 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 if (key != KEY_Reserved && reportIndex < 8) {
48 reportBuffer[reportIndex] = key; // set next available entry
49 reportIndex++;
50 if (key == KEY_capslock)
51 pressingCaps = 1;
52 }
53 reportBuffer[0] |= modifier;
54}
55
56
57void emptyReportBuffer(uint8_t key_code) {
58
59 uint8_t key, modifier;
60 uint8_t i;
61 key = pgm_read_byte(&keymatrix[key_code]);
62 if (key_code >= 0x60 && key_code < 0x68)
63 modifier = pgm_read_byte(&modmatrix[key_code - 0x60]);
64 else
65 modifier = MOD_NONE;
66 if (key != KEY_Reserved) {
67 for (i = 2; i < reportIndex; i++) {
68 if (reportBuffer[i] == key) {
69 for (; i < 7; i++)
70 reportBuffer[i] = reportBuffer[i+1];
71 reportBuffer[7] = 0;
72 reportIndex--;
73 }
74 }
75 }
76 reportBuffer[0] &= ~modifier;
77}
78
79
80void usbSendReport(uint8_t mode, uint8_t key) {
81 // buffer for HID reports. we use a private one, so nobody gets disturbed
82 uint8_t repBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
83 repBuffer[0] = mode;
84 repBuffer[2] = key;
85 while (!usbInterruptIsReady()); // wait
86 usbSetInterrupt(repBuffer, sizeof(repBuffer)); // send
87}
88
89
90int main() {
91 uint8_t idleCounter = 0;
92 uint8_t updateNeeded = 0;
93
94 wdt_enable(WDTO_2S);
95 // configure timer 0 for a rate of 12M/(1024 * 256) = 45.78Hz (~22ms)
96 TCCR0 = 5; // timer 0 prescaler: 1024
97
98 //debug LED - output
99 DDRC |= (1<<PC5);
100 DDRC |= (1<<PC4);
101
102 // Keyboard
103 uint8_t key_code = 255;
104 memset(reportBuffer, 0, sizeof(reportBuffer)); // clear report buffer
105
106 // USB
107 usbInit();
108 ak_init_keyboard();
109 sei();
110
111 while(1) {
112 wdt_reset();
113 usbPoll();
114
115 updateNeeded = char_waiting;
116
117 if (char_waiting) {
118 key_code = ak_read_scancode();
119 PORTC ^= (1<<PC4);
120 PORTC ^= (1<<PC5);
121 // if an update is needed, send the report
122 if ((key_code & 1) == 0)
123 fillReportBuffer(key_code>>1);
124 else
125 emptyReportBuffer(key_code>>1);
126 if (usbInterruptIsReady())
127 usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
128 }
129
130 // check timer if we need periodic reports
131 if (TIFR & (1 << TOV0)) {
132 TIFR = (1 << TOV0); // reset flag
133 if (idleRate != 0) { // do we need periodic reports?
134 if(idleCounter > 4){ // yes, but not yet
135 idleCounter -= 5; // 22ms in units of 4ms
136 } else { // yes, it is time now
137 idleCounter = idleRate;
138 if (pressingCaps) {
139 emptyReportBuffer(0x62);
140 pressingCaps = 0;
141 }
142 if (usbInterruptIsReady())
143 usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
144 }
145 }
146
147 }
148 }
149
150 return 0;
151}
152
153static uint8_t protocolVer = 1;
154uint8_t expectReport = 0;
155
156#define LED_NUM 0x01 ///< num LED on a boot-protocol keyboard
157#define LED_CAPS 0x02 ///< caps LED on a boot-protocol keyboard
158#define LED_SCROLL 0x04 ///< scroll LED on a boot-protocol keyboard
159#define LED_COMPOSE 0x08 ///< compose LED on a boot-protocol keyboard
160#define LED_KANA 0x10 ///< kana LED on a boot-protocol keyboard
161uint8_t LEDstate = 0; ///< current state of the LEDs
162
163
164char PROGMEM usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
165 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
166 0x09, 0x06, // USAGE (Keyboard)
167 0xa1, 0x01, // COLLECTION (Application)
168 0x05, 0x07, // USAGE_PAGE (Keyboard)
169 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
170 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
171 0x15, 0x00, // LOGICAL_MINIMUM (0)
172 0x25, 0x01, // LOGICAL_MAXIMUM (1)
173 0x75, 0x01, // REPORT_SIZE (1)
174 0x95, 0x08, // REPORT_COUNT (8)
175 0x81, 0x02, // INPUT (Data,Var,Abs)
176 0x95, 0x01, // REPORT_COUNT (1)
177 0x75, 0x08, // REPORT_SIZE (8)
178 0x81, 0x03, // INPUT (Cnst,Var,Abs)
179 0x95, 0x05, // REPORT_COUNT (5)
180 0x75, 0x01, // REPORT_SIZE (1)
181 0x05, 0x08, // USAGE_PAGE (LEDs)
182 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
183 0x29, 0x05, // USAGE_MAXIMUM (Kana)
184 0x91, 0x02, // OUTPUT (Data,Var,Abs)
185 0x95, 0x01, // REPORT_COUNT (1)
186 0x75, 0x03, // REPORT_SIZE (3)
187 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
188 0x95, 0x06, // REPORT_COUNT (6)
189 0x75, 0x08, // REPORT_SIZE (8)
190 0x15, 0x00, // LOGICAL_MINIMUM (0)
191 0x25, 0x65, // LOGICAL_MAXIMUM (101)
192 0x05, 0x07, // USAGE_PAGE (Keyboard)
193 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
194 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
195 0x81, 0x00, // INPUT (Data,Ary,Abs)
196 0xc0 // END_COLLECTION
197};
198
199
200
201
202uint8_t usbFunctionSetup(uint8_t data[8]) {
203 usbRequest_t *rq = (void *)data;
204 usbMsgPtr = reportBuffer;
205 if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
206 // class request type
207 if (rq->bRequest == USBRQ_HID_GET_REPORT) {
208 // wValue: ReportType (highbyte), ReportID (lowbyte)
209 // we only have one report type, so don't look at wValue
210 return sizeof(reportBuffer);
211 } else if (rq->bRequest == USBRQ_HID_SET_REPORT) {
212 if (rq->wLength.word == 1) {
213 // We expect one byte reports
214 expectReport = 1;
215 return 0xff; // Call usbFunctionWrite with data
216 }
217 } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
218 usbMsgPtr = &idleRate;
219 return 1;
220 } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
221 idleRate = rq->wValue.bytes[1];
222 } else if (rq->bRequest == USBRQ_HID_GET_PROTOCOL) {
223 if (rq->wValue.bytes[1] < 1) {
224 protocolVer = rq->wValue.bytes[1];
225 }
226 } else if(rq->bRequest == USBRQ_HID_SET_PROTOCOL) {
227 usbMsgPtr = &protocolVer;
228 return 1;
229 }
230 } else {
231 // no vendor specific requests implemented
232 }
233 return 0;
234}
235
236/**
237 * The write function is called when LEDs should be set. Normally, we get only
238 * one byte that contains info about the LED states.
239 * \param data pointer to received data
240 * \param len number ob bytes received
241 * \return 0x01
242 */
243uint8_t usbFunctionWrite(uchar *data, uchar len) {
244 if (expectReport && (len == 1)) {
245 LEDstate = data[0]; // Get the state of all 5 LEDs
246 /* TODO
247 if (LEDstate & LED_NUM) { // light up caps lock
248 PORTLEDS &= ~(1 << LEDNUM);
249 } else {
250 PORTLEDS |= (1 << LEDNUM);
251 }
252 if (LEDstate & LED_CAPS) { // light up caps lock
253 PORTLEDS &= ~(1 << LEDCAPS);
254 } else {
255 PORTLEDS |= (1 << LEDCAPS);
256 }
257 if (LEDstate & LED_SCROLL) { // light up caps lock
258 PORTLEDS &= ~(1 << LEDSCROLL);
259 } else {
260 PORTLEDS |= (1 << LEDSCROLL);
261 }
262 */
263 }
264 expectReport = 0;
265 return 0x01;
266}
267
Note: See TracBrowser for help on using the repository browser.