|
MHVLib
20111227
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 1022 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 #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH 00161 uchar calibrationValue; 00162 00163 calibrationValue = eeprom_read_byte(MHV_OSCCAL_EEPROM_ADDRESS); /* calibration value from last time */ 00164 if (calibrationValue != 0xff) { 00165 OSCCAL = calibrationValue; 00166 } 00167 #endif 00168 00169 mhv_setInput(MHV_MAKE_PIN(USB_CFG_IOPORTNAME, USB_CFG_DPLUS_BIT)); 00170 mhv_setInput(MHV_MAKE_PIN(USB_CFG_IOPORTNAME, USB_CFG_DMINUS_BIT)); 00171 00172 usbDeviceDisconnect(); 00173 for(uint8_t i=0;i<20;i++){ /* 300 ms disconnect */ 00174 _delay_ms(15); 00175 } 00176 usbDeviceConnect(); 00177 00178 usbInit(); 00179 00180 MHV_ALARM newAlarm; 00181 00182 _rtc.current(&(newAlarm.when)); 00183 mhv_timestampIncrement(&(newAlarm.when), 0, 5); 00184 newAlarm.repeat.milliseconds = 5; 00185 newAlarm.repeat.timestamp = 0; 00186 newAlarm.listener = this; 00187 00188 _rtc.addAlarm(&newAlarm); 00189 } 00190 00198 void MHV_VusbKeyboard::keyStroke(MHV_VUSB_KEYBOARD_KEY key, uint8_t modifiers) { 00199 keyDown(key, modifiers); 00200 keysUp(0); 00201 } 00202 00209 void MHV_VusbKeyboard::keyStroke(MHV_VUSB_KEYBOARD_KEY key) { 00210 return keyStroke(key, 0); 00211 } 00212 00218 void MHV_VusbKeyboard::keyDown(MHV_VUSB_KEYBOARD_KEY key, uint8_t modifiers) { 00219 while (!usbInterruptIsReady()) {} 00220 00221 mhv_vusbReportBuffer[0] = modifiers; 00222 mhv_vusbReportBuffer[1] = key; 00223 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(const MHV_ALARM &alarm) { 00250 usbPoll(); 00251 }