#include <stdint.h>
#include <string.h>
+#include <stdbool.h>
#include <avr/io.h>
#include <avr/wdt.h>
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);
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:{
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 */
}
return 1;
}
memcpy(color.idx, data, 6);
+ keyDidChange = true;
return 1;
case CUSTOM_RQ_WRITE_MEM:
memcpy(uni_buffer.ptr[0], data, len);
* additional hardware initialization.
*/
- init_tmpsensor();
+ init_temperature_sensor();
usbInit();
usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
i = 0;
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;
}
--- /dev/null
+/* 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
#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
* 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.
/* 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.]
* 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
/* -------------------------- 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
* 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
* 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