reform

MNT Reform: Open Source Portable Computer
Log (Feed) | Files | Refs (Tags) | README

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 }