Mouse.c (10256B)
1 /* 2 LUFA Library 3 Copyright (C) Dean Camera, 2018. 4 5 dean [at] fourwalledcubicle [dot] com 6 www.lufa-lib.org 7 */ 8 9 /* 10 Copyright 2018 Dean Camera (dean [at] fourwalledcubicle [dot] com) 11 12 Permission to use, copy, modify, distribute, and sell this 13 software and its documentation for any purpose is hereby granted 14 without fee, provided that the above copyright notice appear in 15 all copies and that both that the copyright notice and this 16 permission notice and warranty disclaimer appear in supporting 17 documentation, and that the name of the author not be used in 18 advertising or publicity pertaining to distribution of the 19 software without specific, written prior permission. 20 21 The author disclaims all warranties with regard to this 22 software, including all implied warranties of merchantability 23 and fitness. In no event shall the author be liable for any 24 special, indirect or consequential damages or any damages 25 whatsoever resulting from loss of use, data or profits, whether 26 in an action of contract, negligence or other tortious action, 27 arising out of or in connection with the use or performance of 28 this software. 29 */ 30 31 #include <avr/pgmspace.h> 32 #include <avr/io.h> 33 #include <stdlib.h> 34 35 #include "i2cmaster/i2cmaster.h" 36 #include "azoteq.h" 37 38 #include "Mouse.h" 39 40 /** Buffer to hold the previously generated Mouse HID report, for comparison purposes inside the HID class driver. */ 41 static uint8_t PrevMouseHIDReportBuffer[sizeof(USB_WheelMouseReport_Data_t)]; 42 43 /** LUFA HID Class driver interface configuration and state information. This structure is 44 * passed to all HID Class driver functions, so that multiple instances of the same class 45 * within a device can be differentiated from one another. 46 */ 47 USB_ClassInfo_HID_Device_t Mouse_HID_Interface = 48 { 49 .Config = 50 { 51 .InterfaceNumber = INTERFACE_ID_Mouse, 52 .ReportINEndpoint = 53 { 54 .Address = MOUSE_EPADDR, 55 .Size = MOUSE_EPSIZE, 56 .Banks = 1, 57 }, 58 .PrevReportINBuffer = PrevMouseHIDReportBuffer, 59 .PrevReportINBufferSize = sizeof(PrevMouseHIDReportBuffer), 60 }, 61 }; 62 63 uint8_t twi_write_reg[1]; 64 uint8_t twi_write_buf[10]; 65 uint8_t twi_read_buf[10]; 66 67 void SetupHardware(void) 68 { 69 /* Disable watchdog if enabled by bootloader/fuses */ 70 MCUSR &= ~(1 << WDRF); 71 wdt_disable(); 72 73 // Disable clock division 74 // this should yield 8Mhz with internal osc 75 clock_prescale_set(clock_div_1); 76 77 DDRD = 0b00000000; 78 DDRB = 0b00000100; 79 DDRC = 0b00000000; 80 81 i2c_init(); 82 USB_Init(); 83 84 Delay_MS(100); 85 86 i2c_start_wait(ADDR_SENSOR|I2C_WRITE); 87 i2c_write(0x04); 88 i2c_write(0x32); 89 i2c_write(2); // reset 90 i2c_stop(); 91 92 i2c_start_wait(ADDR_SENSOR|I2C_WRITE); 93 i2c_write(0x04); 94 i2c_write(0x32); 95 i2c_write(0); // reset 96 i2c_stop(); 97 98 // Disable idle mode timeout, so we never enter LP1 99 i2c_start_wait(ADDR_SENSOR|I2C_WRITE); 100 i2c_write(0x05); 101 i2c_write(0x86); 102 i2c_write(0xff); // Idle mode, 255s = never timeout 103 i2c_stop(); 104 105 Delay_MS(100); 106 } 107 108 /** Event handler for the library USB Connection event. */ 109 void EVENT_USB_Device_Connect(void) 110 { 111 } 112 113 /** Event handler for the library USB Disconnection event. */ 114 void EVENT_USB_Device_Disconnect(void) 115 { 116 } 117 118 /** Event handler for the library USB Configuration Changed event. */ 119 void EVENT_USB_Device_ConfigurationChanged(void) 120 { 121 bool ConfigSuccess = true; 122 123 ConfigSuccess &= HID_Device_ConfigureEndpoints(&Mouse_HID_Interface); 124 125 USB_Device_EnableSOFEvents(); 126 } 127 128 /** Event handler for the library USB Control Request reception event. */ 129 void EVENT_USB_Device_ControlRequest(void) 130 { 131 HID_Device_ProcessControlRequest(&Mouse_HID_Interface); 132 } 133 134 /** Event handler for the USB device Start Of Frame event. */ 135 void EVENT_USB_Device_StartOfFrame(void) 136 { 137 HID_Device_MillisecondElapsed(&Mouse_HID_Interface); 138 } 139 140 float dx = 0, dy = 0; 141 int16_t lastx = 0, lasty = 0; 142 int16_t lastx2 = 0, lasty2 = 0; 143 unsigned int cycle = 0; 144 int wheeling = 0; 145 int touched_time = 0; 146 int last_num_fingers = 0; 147 int start_num_fingers = 0; 148 int report_lift = 0; 149 bool g_want_bootloader = false; 150 151 #define PRESS_TIME 6 152 #define MOTION_CLIP 127 153 154 /** HID class driver callback function for the creation of HID reports to the host. 155 * 156 * \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced 157 * \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID 158 * \param[in] ReportType Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature 159 * \param[out] ReportData Pointer to a buffer where the created report should be stored 160 * \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent) 161 * 162 * \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent 163 */ 164 bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, 165 uint8_t* const ReportID, 166 const uint8_t ReportType, 167 void* ReportData, 168 uint16_t* const ReportSize) 169 { 170 if (ReportType==HID_REPORT_ITEM_Feature) { 171 if (*ReportID==0) { 172 *ReportID=2; 173 } 174 175 if (*ReportID==2) { 176 USB_WheelMouseFeatureReport_Data_t* FeatureReport = (USB_WheelMouseFeatureReport_Data_t*)ReportData; 177 FeatureReport->Multiplier = 2; 178 *ReportSize = sizeof(USB_WheelMouseFeatureReport_Data_t); 179 return true; 180 } else { 181 return false; 182 } 183 } 184 185 if (*ReportID==0) { 186 *ReportID=1; 187 } 188 189 if (*ReportID!=1) { 190 return false; 191 } 192 193 USB_WheelMouseReport_Data_t* MouseReport = (USB_WheelMouseReport_Data_t*)ReportData; 194 195 // note: look for IQS550 196 197 MouseReport->Button = 0; 198 MouseReport->Pan = 0; 199 MouseReport->Wheel = 0; 200 MouseReport->X = 0; 201 MouseReport->Y = 0; 202 203 // sensor ready? 204 uint8_t rdy = PINB&(1<<5); 205 if (!rdy) { 206 if (report_lift) { 207 // we still have to end a short click event 208 report_lift = 0; 209 *ReportSize = sizeof(USB_WheelMouseReport_Data_t); 210 return true; 211 } 212 return false; 213 } 214 215 struct azoteq_data sensor = { 0 }; 216 read_azoteq_data(&sensor); 217 218 // touched? 219 if (sensor.num_fingers) { 220 touched_time++; 221 wheeling = 0; 222 223 if (sensor.num_fingers != last_num_fingers) { 224 lastx2 = 0; 225 lasty2 = 0; 226 lastx = 0; 227 lasty = 0; 228 } 229 230 if (start_num_fingers < sensor.num_fingers) { 231 start_num_fingers = sensor.num_fingers; 232 } 233 234 if (start_num_fingers == 2) { 235 // wheel 236 wheeling = 1; 237 } else if (start_num_fingers == 3) { 238 MouseReport->Button |= 1; 239 } else if (start_num_fingers == 4) { 240 // right mouse button 241 //MouseReport->Button |= 2; 242 } 243 244 if (sensor.num_fingers >= 2) { 245 dx = lastx && lastx2 ? ((float)sensor.fingers[1].abs_x + (float)sensor.fingers[0].abs_x) / 2.0f - ((float)lastx2 + (float)lastx) / 2.0f : 0.0f; 246 dy = lasty && lasty2 ? ((float)sensor.fingers[1].abs_y + (float)sensor.fingers[0].abs_y) / 2.0f - ((float)lasty2 + (float)lasty) / 2.0f : 0.0f; 247 } else { 248 dx = (float)sensor.relative_x; 249 dy = (float)sensor.relative_y; 250 } 251 252 if (wheeling) { 253 // horizontal and vertical scrolling 254 MouseReport->Pan = dx / 4.0f; 255 MouseReport->Wheel = -dy / 4.0f; 256 } else { 257 // normal movement 258 MouseReport->X = dx; 259 MouseReport->Y = dy; 260 } 261 262 lastx = sensor.fingers[0].abs_x; lasty = sensor.fingers[0].abs_y; 263 if (sensor.num_fingers > 1) lastx2 = sensor.fingers[1].abs_x; lasty2 = sensor.fingers[1].abs_y; 264 } else { 265 // no (more) touches 266 267 if (start_num_fingers == 1 && touched_time > 0 && touched_time <= PRESS_TIME) { 268 // tapped for a short time with 1 finger? left click 269 MouseReport->Button |= 1; 270 } else if (start_num_fingers == 2 && touched_time > 0 && touched_time <= PRESS_TIME) { 271 // tapped for a short time with 2 fingers? right click 272 MouseReport->Button |= 2; 273 } else if (start_num_fingers == 3 && touched_time > 0 && touched_time <= PRESS_TIME) { 274 // tapped for a short time with 3 fingers? middle click 275 MouseReport->Button |= 4; 276 } 277 touched_time = 0; 278 start_num_fingers = 0; 279 report_lift = 1; 280 dx = 0; 281 dy = 0; 282 lastx = 0; 283 lasty = 0; 284 lastx2 = 0; 285 lasty2 = 0; 286 } 287 288 last_num_fingers = sensor.num_fingers; 289 290 *ReportSize = sizeof(USB_WheelMouseReport_Data_t); 291 292 return true; 293 } 294 295 #define BOOTLOADER_START_ADDRESS ((0x8000 - 0x1000) >> 1) 296 void jump_to_bootloader(void) { 297 ((void (*)(void))BOOTLOADER_START_ADDRESS)(); 298 } 299 300 #define cmd(_s) (*(uint32_t *)(_s)) 301 #define CMD_JUMP_TO_BOOTLOADER cmd("JTBL") 302 /** HID class driver callback function for the processing of HID reports from the host. 303 * 304 * \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced 305 * \param[in] ReportID Report ID of the received report from the host 306 * \param[in] ReportType The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature 307 * \param[in] ReportData Pointer to a buffer where the received report has been stored 308 * \param[in] ReportSize Size in bytes of the received HID report 309 */ 310 void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, 311 const uint8_t ReportID, 312 const uint8_t ReportType, 313 const void* ReportData, 314 const uint16_t ReportSize) 315 { 316 // Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports 317 // if (ReportSize < 4) return; 318 const uint32_t command = *(uint32_t *)ReportData; 319 if (command == CMD_JUMP_TO_BOOTLOADER) { 320 g_want_bootloader = true; 321 } 322 } 323 324 325 int main(void) 326 { 327 SetupHardware(); 328 GlobalInterruptEnable(); 329 330 for (;;) 331 { 332 HID_Device_USBTask(&Mouse_HID_Interface); 333 USB_USBTask(); 334 if (g_want_bootloader) jump_to_bootloader(); 335 } 336 }