keyboard functionality still not working
authorbg <daniel.otte@rub.de>
Wed, 16 Oct 2013 00:06:13 +0000 (02:06 +0200)
committerbg <daniel.otte@rub.de>
Wed, 16 Oct 2013 00:06:13 +0000 (02:06 +0200)
firmware/Makefile
firmware/main.c
firmware/special_functions.S [new file with mode: 0644]
firmware/special_functions.h [new file with mode: 0644]
firmware/usbconfig.h

index 9bd5f9d..2172ea9 100644 (file)
@@ -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)
index b9fa41f..20bf8c0 100644 (file)
@@ -25,6 +25,7 @@ different port or bit, change the macros below:
 
 #include <stdint.h>
 #include <string.h>
+#include <stdbool.h>
 
 #include <avr/io.h>
 #include <avr/wdt.h>
@@ -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<<BUTTON_PIN);
        PORTB |= 1<<BUTTON_PIN;
        PORTB &= ~(1<<BUTTON_PIN);
@@ -174,36 +179,68 @@ uint8_t read_button(void){
        return v;
 }
 
-void init_tmpsensor(void){
+void init_temperature_sensor(void){
        ADMUX = 0x8F;
        ADCSRA = 0x87;
 }
 
-uint16_t read_tmpsensor(void){
+uint16_t read_temperture_sensor(void){
        ADCSRA |= 0x40;
        while(ADCSRA & 0x40)
                ;
        return ADC;
 }
 
+#if 0
+uchar   usbFunctionSetup(uchar data[8])
+{
+usbRequest_t    *rq = (void *)data;
+
+    usbMsgPtr = reportBuffer;
+    if((rq->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 (file)
index 0000000..88ae6dc
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <avr/io.h>
+#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 (file)
index 0000000..a970e14
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SPECIAL_FUNCTIONS_H_
+#define SPECIAL_FUNCTIONS_H_
+
+#include <stdint.h>
+
+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_ */
index 7be2b84..341fc71 100644 (file)
@@ -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