From 06016b0f48e8407fdc6000735d310b84fd1fd0bc Mon Sep 17 00:00:00 2001 From: bg Date: Wed, 16 Oct 2013 02:06:13 +0200 Subject: [PATCH] keyboard functionality still not working --- firmware/Makefile | 2 +- firmware/main.c | 93 ++++++++++++++++++++++++++---------- firmware/special_functions.S | 70 +++++++++++++++++++++++++++ firmware/special_functions.h | 28 +++++++++++ firmware/usbconfig.h | 58 +++++++++------------- 5 files changed, 188 insertions(+), 63 deletions(-) create mode 100644 firmware/special_functions.S create mode 100644 firmware/special_functions.h diff --git a/firmware/Makefile b/firmware/Makefile index 9bd5f9d..2172ea9 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -16,7 +16,7 @@ AVRDUDE_ISP = avrdude -c jtag2isp -P usb -p $(DEVICE) # edit this line for your AVRDUDE_DW = avrdude -c jtag2dw -P usb -p $(DEVICE) # edit this line for your programmer CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 -OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o pwm-x.o main.o \ +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o \ special_functions.o COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) diff --git a/firmware/main.c b/firmware/main.c index b9fa41f..20bf8c0 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -25,6 +25,7 @@ different port or bit, change the macros below: #include #include +#include #include #include @@ -155,13 +156,17 @@ static union { static uint8_t uni_buffer_fill; static uint8_t current_command; + +static uchar reportBuffer[2]; /* buffer for HID reports */ +static uchar idleRate; /* in 4 ms units */ + +static bool keyDidChange = false; /* ------------------------------------------------------------------------- */ uint8_t read_button(void){ - uint8_t t,u,v=0; + uint8_t t,v=0; t = DDRB; - u = PORTB; DDRB &= ~(1<bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ + if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ + /* we only have one report type, so don't look at wValue */ + buildReport(keyPressed()); + return sizeof(reportBuffer); + }else if(rq->bRequest == USBRQ_HID_GET_IDLE){ + usbMsgPtr = &idleRate; + return 1; + }else if(rq->bRequest == USBRQ_HID_SET_IDLE){ + idleRate = rq->wValue.bytes[1]; + } + }else{ + /* no vendor specific requests implemented */ + } + return 0; +} +#endif + usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (usbRequest_t *)data; - - if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR) - { + if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) { /* class request type */ + color.name.red = 13; + if (rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ + /* we only have one report type, so don't look at wValue */ + if (color.name.red == 133) { + color.name.red = 23; + usbMsgPtr = reportBuffer; + reportBuffer[0] = 0; + reportBuffer[1] = KEY_X; + } + return sizeof(reportBuffer); + } else if (rq->bRequest == USBRQ_HID_GET_IDLE) { + usbMsgPtr = &idleRate; + return 1; + }else if (rq->bRequest == USBRQ_HID_SET_IDLE) { + usbMsgPtr = reportBuffer; + idleRate = rq->wValue.bytes[1]; + } + } + if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR) { current_command = rq->bRequest; switch(rq->bRequest) { - case CUSTOM_RQ_SET_RED: - color.name.red = rq->wValue.bytes[0]; - break; - case CUSTOM_RQ_SET_GREEN: - color.name.green = rq->wValue.bytes[0]; - break; - case CUSTOM_RQ_SET_BLUE: - color.name.blue = rq->wValue.bytes[0]; - break; case CUSTOM_RQ_SET_RGB: return USB_NO_MSG; case CUSTOM_RQ_GET_RGB:{ @@ -235,18 +272,12 @@ usbMsgLen_t usbFunctionSetup(uchar data[8]) usbMsgPtr = uni_buffer.w8; return 1; case CUSTOM_RQ_READ_TMPSENS: - uni_buffer.w16[0] = read_tmpsensor(); + uni_buffer.w16[0] = read_temperture_sensor(); usbMsgPtr = uni_buffer.w8; return 2; } } - else - { - /* calls requests USBRQ_HID_GET_REPORT and USBRQ_HID_SET_REPORT are - * not implemented since we never call them. The operating system - * won't call them either because our descriptor defines no meaning. - */ - } + return 0; /* default for not implemented requests: return no data back to host */ } @@ -258,6 +289,7 @@ uchar usbFunctionWrite(uchar *data, uchar len) return 1; } memcpy(color.idx, data, 6); + keyDidChange = true; return 1; case CUSTOM_RQ_WRITE_MEM: memcpy(uni_buffer.ptr[0], data, len); @@ -357,7 +389,7 @@ int main(void) * additional hardware initialization. */ - init_tmpsensor(); + init_temperature_sensor(); usbInit(); usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ i = 0; @@ -371,10 +403,19 @@ int main(void) sei(); for(;;){ /* main event loop */ - update_pwm(); + // update_pwm(); wdt_reset(); usbPoll(); + if(keyDidChange && usbInterruptIsReady()){ + keyDidChange = 0; + color.name.red = 42; + /* use last key and not current key status in order to avoid lost + changes in key status. */ + reportBuffer[0] = 0; + reportBuffer[1] = KEY_Y; + usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); + } } return 0; } diff --git a/firmware/special_functions.S b/firmware/special_functions.S new file mode 100644 index 0000000..88ae6dc --- /dev/null +++ b/firmware/special_functions.S @@ -0,0 +1,70 @@ +/* special_functions.S */ +/* + This file is part of the Labotage2011_Badge. + Copyright (C) 2011 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "usbconfig.h" + +.global exec_spm +/* void exec_spm(uint16_t z, uint16_t r0r1, void* dest, void* src, uint8_t len); */ +exec_spm: + push r28 + push r29 + movw r30, r24 + movw r0, r22 + movw r28, r20 + movw r26, r18 + movw r24, r16 + in r23, _SFR_IO_ADDR(SREG) + cli + tst r24 + breq spm_cmd + dec r24 + breq last_store +copy_loop: + ld r22, X+ + st Y+, r22 + dec r24 + brne copy_loop +last_store: + ld r22, X+ + st Y+, r22 +spm_cmd: + spm + out _SFR_IO_ADDR(SREG), r23 + clr r1 + pop r29 + pop r28 + ret + +.global soft_reset +soft_reset: + cli + andi r24, 0x0F + cpi r24, 0x0F + breq 1f + bst r24, 3 + bld r24, 5 + ori r24, 0x08 + ldi r25, 0x18 + or r25, r24 + sbi _SFR_IO_ADDR(PORTB), USB_CFG_DMINUS_BIT + out _SFR_IO_ADDR(WDTCR), r25 + out _SFR_IO_ADDR(WDTCR), r24 +1: + rjmp 1b diff --git a/firmware/special_functions.h b/firmware/special_functions.h new file mode 100644 index 0000000..a970e14 --- /dev/null +++ b/firmware/special_functions.h @@ -0,0 +1,28 @@ +/* special_functions.h */ +/* + This file is part of the Labotage2011_Badge. + Copyright (C) 2011 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef SPECIAL_FUNCTIONS_H_ +#define SPECIAL_FUNCTIONS_H_ + +#include + +void exec_spm(uint16_t z, uint16_t r0r1, void* dest, void* src, uint8_t len); +void soft_reset(uint8_t delay); + +#endif /* SPECIAL_FUNCTIONS_H_ */ diff --git a/firmware/usbconfig.h b/firmware/usbconfig.h index 7be2b84..341fc71 100644 --- a/firmware/usbconfig.h +++ b/firmware/usbconfig.h @@ -72,24 +72,12 @@ section at the end of this file). #define USB_CFG_HAVE_INTRIN_ENDPOINT 1 /* Define this to 1 if you want to compile a version with two endpoints: The - * default control endpoint 0 and an interrupt-in endpoint (any other endpoint - * number). + * default control endpoint 0 and an interrupt-in endpoint 1. */ #define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 /* Define this to 1 if you want to compile a version with three endpoints: The - * default control endpoint 0, an interrupt-in endpoint 3 (or the number - * configured below) and a catch-all default interrupt-in endpoint as above. - * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. - */ -#define USB_CFG_EP3_NUMBER 3 -/* If the so-called endpoint 3 is used, it can now be configured to any other - * endpoint number (except 0) with this macro. Default if undefined is 3. - */ -/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */ -/* The above macro defines the startup condition for data toggling on the - * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. - * Since the token is toggled BEFORE sending any data, the first packet is - * sent with the opposite value of this configuration! + * default control endpoint 0, an interrupt-in endpoint 1 and an interrupt-in + * endpoint 3. You must also enable endpoint 1 above. */ #define USB_CFG_IMPLEMENT_HALT 0 /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature @@ -97,15 +85,7 @@ section at the end of this file). * it is required by the standard. We have made it a config option because it * bloats the code considerably. */ -#define USB_CFG_SUPPRESS_INTR_CODE 0 -/* Define this to 1 if you want to declare interrupt-in endpoints, but don't - * want to send any data over them. If this macro is defined to 1, functions - * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if - * you need the interrupt-in endpoints in order to comply to an interface - * (e.g. HID), but never want to send any data. This option saves a couple - * of bytes in flash memory and the transmit buffers in RAM. - */ -#define USB_CFG_INTR_POLL_INTERVAL 100 +#define USB_CFG_INTR_POLL_INTERVAL 10 /* If you compile a version with endpoint 1 (interrupt-in), this is the poll * interval. The value is in milliseconds and must not be less than 10 ms for * low speed devices. @@ -114,7 +94,7 @@ section at the end of this file). /* Define this to 1 if the device has its own power supply. Set it to 0 if the * device is powered from the USB bus. */ -#define USB_CFG_MAX_BUS_POWER 40 +#define USB_CFG_MAX_BUS_POWER 100 /* Set this variable to the maximum USB bus power consumption of your device. * The value is in milliamperes. [It will be divided by two since USB * communicates power requirements in units of 2 mA.] @@ -131,10 +111,9 @@ section at the end of this file). * usbFunctionSetup(). This saves a couple of bytes. */ #define USB_CFG_IMPLEMENT_FN_WRITEOUT 0 -/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints. +/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoint 1. * You must implement the function usbFunctionWriteOut() which receives all - * interrupt/bulk data sent to any endpoint other than 0. The endpoint number - * can be found in 'usbRxToken'. + * interrupt/bulk data sent to endpoint 1. */ #define USB_CFG_HAVE_FLOWCONTROL 0 /* Define this to 1 if you want flowcontrol over USB data. See the definition @@ -201,12 +180,19 @@ section at the end of this file). /* -------------------------- Device Description --------------------------- */ -#define USB_CFG_VENDOR_ID 0xc0, 0x16 +/* We cannot use Obdev's free shared VID/PID pair because this is a HID. + * We use John Hyde's VID (author of the book "USB Design By Example") for + * this example instead. John has offered this VID for use by students for + * non-commercial devices. Well... This example is for demonstration and + * education only... DO NOT LET DEVICES WITH THIS VID ESCAPE YOUR LAB! + * The Product-ID is a random number. + */ +#define USB_CFG_VENDOR_ID 0x42, 0x42 /* USB vendor ID for the device, low byte first. If you have registered your * own Vendor ID, define it here. Otherwise you use one of obdev's free shared * VID/PID pairs. Be sure to read USBID-License.txt for rules! */ -#define USB_CFG_DEVICE_ID 0xdf, 0x05 /* obdev's shared PID for HIDs */ +#define USB_CFG_DEVICE_ID 0x31, 0xe1 /* This is the ID of the product, low byte first. It is interpreted in the * scope of the vendor ID. If you have registered your own VID with usb.org * or if you have licensed a PID from somebody else, define it here. Otherwise @@ -226,7 +212,7 @@ section at the end of this file). * obdev's free shared VID/PID pair. See the file USBID-License.txt for * details. */ -#define USB_CFG_DEVICE_NAME 'l', 'a', 'b', 'o', 'r', 't', 'a', 'g', 'e', '2', '0', '1', '1', ' ', 'b', 'a', 'd', 'g', 'e' +#define USB_CFG_DEVICE_NAME 'l', 'a', 'b', 'o', 'r', 't', 'a', 'g', 'e', '2', '0', '1', '3', ' ', 'b', 'a', 'd', 'g', 'e' #define USB_CFG_DEVICE_NAME_LEN 20 /* Same as above for the device name. If you don't want a device name, undefine * the macros. See the file USBID-License.txt before you assign a name if you @@ -241,20 +227,20 @@ section at the end of this file). * to fine tune control over USB descriptors such as the string descriptor * for the serial number. */ -#define USB_CFG_DEVICE_CLASS 0 +#define USB_CFG_DEVICE_CLASS 0 /* specify the class at the interface level */ #define USB_CFG_DEVICE_SUBCLASS 0 /* See USB specification if you want to conform to an existing device class. * Class 0xff is "vendor specific". */ -#define USB_CFG_INTERFACE_CLASS 3 -#define USB_CFG_INTERFACE_SUBCLASS 0 -#define USB_CFG_INTERFACE_PROTOCOL 0 +#define USB_CFG_INTERFACE_CLASS 0x03 /* HID class */ +#define USB_CFG_INTERFACE_SUBCLASS 0 /* no boot interface */ +#define USB_CFG_INTERFACE_PROTOCOL 1 /* keyboard protocol */ /* See USB specification if you want to conform to an existing device class or * protocol. The following classes must be set at interface level: * HID class is 3, no subclass and protocol required (but may be useful!) * CDC class is 2, use subclass 2 and protocol 1 for ACM */ -#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 22 +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 35 /* total length of report descriptor */ /* Define this to the length of the HID report descriptor, if you implement * an HID device. Otherwise don't define it or define it to 0. * If you use this define, you must add a PROGMEM character array named -- 2.39.5