MHVLib
20111011
An efficiency oriented runtime library for AVR microcontrollers
|
00001 /* 00002 * Copyright (c) 2011, Make, Hack, Void Inc 00003 * All rights reserved. 00004 * 00005 * License: GNU GPL v2 (see mhvlib-Vusb-Keyboard/vusb/License.txt) 00006 * 00007 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00008 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00009 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00010 * DISCLAIMED. IN NO EVENT SHALL MAKE, HACK, VOID BE LIABLE FOR ANY 00011 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00012 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00013 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00014 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00015 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00016 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00017 */ 00018 00019 extern "C" { 00020 #include <vusb/usbdrv.h> 00021 } 00022 00023 #include <MHV_VusbKeyboard.h> 00024 #include <avr/pgmspace.h> 00025 #include <util/delay.h> 00026 00027 #define MHV_OSCCAL_EEPROM_ADDRESS 0 00028 00029 /* We use a simplifed keyboard report descriptor which does not support the 00030 * boot protocol. We don't allow setting status LEDs and but we do allow 00031 * simultaneous key presses. 00032 * The report descriptor has been created with usb.org's "HID Descriptor Tool" 00033 * which can be downloaded from http://www.usb.org/developers/hidpage/. 00034 * Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted 00035 * for the second INPUT item. 00036 */ 00037 PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */ 00038 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 00039 0x09, 0x06, // USAGE (Keyboard) 00040 0xa1, 0x01, // COLLECTION (Application) 00041 0x05, 0x07, // USAGE_PAGE (Keyboard) 00042 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 00043 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 00044 0x15, 0x00, // LOGICAL_MINIMUM (0) 00045 0x25, 0x01, // LOGICAL_MAXIMUM (1) 00046 0x75, 0x01, // REPORT_SIZE (1) 00047 0x95, 0x08, // REPORT_COUNT (8) 00048 0x81, 0x02, // INPUT (Data,Var,Abs) 00049 0x95, 0x01, // REPORT_COUNT (1) 00050 0x75, 0x08, // REPORT_SIZE (8) 00051 0x25, 0x65, // LOGICAL_MAXIMUM (101) 00052 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 00053 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 00054 0x81, 0x00, // INPUT (Data,Ary,Abs) 00055 0xc0 // END_COLLECTION 00056 }; 00057 00058 /* This code has been borrowed from Sparkfun's AVR Stick firmware 00059 * See: http://www.sparkfun.com/products/9147 00060 */ 00061 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH 00062 #include <avr/eeprom.h> 00063 /* ------------------------------------------------------------------------- */ 00064 /* ------------------------ Oscillator Calibration ------------------------- */ 00065 /* ------------------------------------------------------------------------- */ 00066 00067 /* Calibrate the RC oscillator to 8.25 MHz. The core clock of 16.5 MHz is 00068 * derived from the 66 MHz peripheral clock by dividing. Our timing reference 00069 * is the Start Of Frame signal (a single SE0 bit) available immediately after 00070 * a USB RESET. We first do a binary search for the OSCCAL value and then 00071 * optimize this value with a neighboorhod search. 00072 * This algorithm may also be used to calibrate the RC oscillator directly to 00073 * 12 MHz (no PLL involved, can therefore be used on almost ALL AVRs), but this 00074 * is wide outside the spec for the OSCCAL value and the required precision for 00075 * the 12 MHz clock! Use the RC oscillator calibrated to 12 MHz for 00076 * experimental purposes only! 00077 */ 00078 static void calibrateOscillator(void) 00079 { 00080 uchar step = 128; 00081 uchar trialValue = 0, optimumValue; 00082 int x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5); 00083 00084 /* do a binary search: */ 00085 do{ 00086 OSCCAL = trialValue + step; 00087 x = usbMeasureFrameLength(); /* proportional to current real frequency */ 00088 if(x < targetValue) /* frequency still too low */ 00089 trialValue += step; 00090 step >>= 1; 00091 }while(step > 0); 00092 /* We have a precision of +/- 1 for optimum OSCCAL here */ 00093 /* now do a neighborhood search for optimum value */ 00094 optimumValue = trialValue; 00095 optimumDev = x; /* this is certainly far away from optimum */ 00096 for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){ 00097 x = usbMeasureFrameLength() - targetValue; 00098 if(x < 0) 00099 x = -x; 00100 if(x < optimumDev){ 00101 optimumDev = x; 00102 optimumValue = OSCCAL; 00103 } 00104 } 00105 OSCCAL = optimumValue; 00106 } 00107 /* 00108 Note: This calibration algorithm may try OSCCAL values of up to 192 even if 00109 the optimum value is far below 192. It may therefore exceed the allowed clock 00110 frequency of the CPU in low voltage designs! 00111 You may replace this search algorithm with any other algorithm you like if 00112 you have additional constraints such as a maximum CPU clock. 00113 For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g. 00114 ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in 00115 both regions. 00116 */ 00117 00118 void usbEventResetReady(void) 00119 { 00120 calibrateOscillator(); 00121 uchar calibrationValue = eeprom_read_byte(MHV_OSCCAL_EEPROM_ADDRESS); 00122 if (calibrationValue != OSCCAL) { 00123 eeprom_write_byte(MHV_OSCCAL_EEPROM_ADDRESS, OSCCAL); 00124 } 00125 } 00126 #endif 00127 00128 static unsigned char mhv_vusbReportBuffer[2]; /* buffer for HID reports */ 00129 static unsigned char mhv_vusbIdleRate = 1; /* in 4 ms units */ 00130 00131 unsigned char usbFunctionSetup(uchar data[8]) { 00132 usbRequest_t *rq = (usbRequest_t *) ((void *) data); 00133 00134 usbMsgPtr = mhv_vusbReportBuffer; 00135 if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) { /* class request type */ 00136 if (rq->bRequest == USBRQ_HID_GET_REPORT) { /* wValue: ReportType (highbyte), ReportID (lowbyte) */ 00137 /* we only have one report type, so don't look at wValue */ 00138 return sizeof(mhv_vusbReportBuffer); 00139 } else if (rq->bRequest == USBRQ_HID_GET_IDLE) { 00140 usbMsgPtr = &mhv_vusbIdleRate; 00141 return 1; 00142 } else if (rq->bRequest == USBRQ_HID_SET_IDLE) { 00143 mhv_vusbIdleRate = rq->wValue.bytes[1]; 00144 } 00145 } else { 00146 /* no vendor specific requests implemented */ 00147 } 00148 return 0; 00149 } 00150 00151 00158 MHV_VusbKeyboard::MHV_VusbKeyboard(MHV_RTC *rtc) { 00159 _rtc = rtc; 00160 00161 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH 00162 uchar calibrationValue; 00163 00164 calibrationValue = eeprom_read_byte(MHV_OSCCAL_EEPROM_ADDRESS); /* calibration value from last time */ 00165 if (calibrationValue != 0xff) { 00166 OSCCAL = calibrationValue; 00167 } 00168 #endif 00169 00170 mhv_setInput(mhv_make_pin(USB_CFG_IOPORTNAME, USB_CFG_DPLUS_BIT)); 00171 mhv_setInput(mhv_make_pin(USB_CFG_IOPORTNAME, USB_CFG_DMINUS_BIT)); 00172 00173 usbDeviceDisconnect(); 00174 for(uint8_t i=0;i<20;i++){ /* 300 ms disconnect */ 00175 _delay_ms(15); 00176 } 00177 usbDeviceConnect(); 00178 00179 usbInit(); 00180 00181 MHV_ALARM newAlarm; 00182 00183 _rtc->current(&(newAlarm.when)); 00184 mhv_timestampIncrement(&(newAlarm.when), 0, 5); 00185 newAlarm.repeat.milliseconds = 5; 00186 newAlarm.repeat.timestamp = 0; 00187 newAlarm.listener = this; 00188 00189 _rtc->addAlarm(&newAlarm); 00190 } 00191 00199 void MHV_VusbKeyboard::keyStroke(MHV_VUSB_KEYBOARD_KEY key, uint8_t modifiers) { 00200 keyDown(key, modifiers); 00201 keysUp(0); 00202 } 00203 00210 void MHV_VusbKeyboard::keyStroke(MHV_VUSB_KEYBOARD_KEY key) { 00211 return keyStroke(key, 0); 00212 } 00213 00219 void MHV_VusbKeyboard::keyDown(MHV_VUSB_KEYBOARD_KEY key, uint8_t modifiers) { 00220 mhv_vusbReportBuffer[0] = modifiers; 00221 mhv_vusbReportBuffer[1] = key; 00222 00223 while (!usbInterruptIsReady()) {} 00224 usbSetInterrupt(mhv_vusbReportBuffer, sizeof(mhv_vusbReportBuffer)); 00225 } 00226 00231 void MHV_VusbKeyboard::keysUp(uint8_t modifiers) { 00232 while (!usbInterruptIsReady()) {} 00233 00234 mhv_vusbReportBuffer[0] = modifiers; 00235 mhv_vusbReportBuffer[1] = 0; 00236 usbSetInterrupt(mhv_vusbReportBuffer, sizeof(mhv_vusbReportBuffer)); 00237 } 00238 00242 void MHV_VusbKeyboard::keysUp() { 00243 keysUp(0); 00244 } 00245 00249 void MHV_VusbKeyboard::alarm(MHV_ALARM *alarm) { 00250 usbPoll(); 00251 }