reform

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

Mouse.c (10691B)


      1 /*
      2   MNT Reform 2.0 Trackball Firmware
      3   Copyright 2019-2021  Lukas F. Hartmann / MNT Research GmbH, Berlin
      4   lukas@mntre.com
      5 */
      6 /*
      7              LUFA Library
      8      Copyright (C) Dean Camera, 2018.
      9 
     10   dean [at] fourwalledcubicle [dot] com
     11            www.lufa-lib.org
     12 */
     13 
     14 /*
     15   Copyright 2018  Dean Camera (dean [at] fourwalledcubicle [dot] com)
     16 
     17   Permission to use, copy, modify, distribute, and sell this
     18   software and its documentation for any purpose is hereby granted
     19   without fee, provided that the above copyright notice appear in
     20   all copies and that both that the copyright notice and this
     21   permission notice and warranty disclaimer appear in supporting
     22   documentation, and that the name of the author not be used in
     23   advertising or publicity pertaining to distribution of the
     24   software without specific, written prior permission.
     25 
     26   The author disclaims all warranties with regard to this
     27   software, including all implied warranties of merchantability
     28   and fitness.  In no event shall the author be liable for any
     29   special, indirect or consequential damages or any damages
     30   whatsoever resulting from loss of use, data or profits, whether
     31   in an action of contract, negligence or other tortious action,
     32   arising out of or in connection with the use or performance of
     33   this software.
     34 */
     35 
     36 #include <avr/pgmspace.h>
     37 #include <avr/io.h>
     38 #include <stdlib.h>
     39 
     40 #include "i2cmaster/i2cmaster.h"
     41 
     42 #define output_low(port,pin) port &= ~(1<<pin)
     43 #define output_high(port,pin) port |= (1<<pin)
     44 #define set_input(portdir,pin) portdir &= ~(1<<pin)
     45 #define set_output(portdir,pin) portdir |= (1<<pin)
     46 
     47 // Registers
     48 #define Product_ID  0x00
     49 #define Revision_ID 0x01
     50 #define Motion  0x02
     51 #define Delta_X_L 0x03
     52 #define Delta_X_H 0x04
     53 #define Delta_Y_L 0x05
     54 #define Delta_Y_H 0x06
     55 #define SQUAL 0x07
     56 #define Raw_Data_Sum  0x08
     57 #define Maximum_Raw_data  0x09
     58 #define Minimum_Raw_data  0x0A
     59 #define Shutter_Lower 0x0B
     60 #define Shutter_Upper 0x0C
     61 #define Control 0x0D
     62 #define Config1 0x0F
     63 #define Config2 0x10
     64 #define Angle_Tune  0x11
     65 #define Frame_Capture 0x12
     66 #define SROM_Enable 0x13
     67 #define Run_Downshift 0x14
     68 #define Rest1_Rate_Lower  0x15
     69 #define Rest1_Rate_Upper  0x16
     70 #define Rest1_Downshift 0x17
     71 #define Rest2_Rate_Lower  0x18
     72 #define Rest2_Rate_Upper  0x19
     73 #define Rest2_Downshift 0x1A
     74 #define Rest3_Rate_Lower  0x1B
     75 #define Rest3_Rate_Upper  0x1C
     76 #define Observation 0x24
     77 #define Data_Out_Lower  0x25
     78 #define Data_Out_Upper  0x26
     79 #define Raw_Data_Dump 0x29
     80 #define SROM_ID 0x2A
     81 #define Min_SQ_Run  0x2B
     82 #define Raw_Data_Threshold  0x2C
     83 #define Config5 0x2F
     84 #define Power_Up_Reset  0x3A
     85 #define Shutdown  0x3B
     86 #define Inverse_Product_ID  0x3F
     87 #define LiftCutoff_Tune3  0x41
     88 #define Angle_Snap  0x42
     89 #define LiftCutoff_Tune1  0x4A
     90 #define Motion_Burst  0x50
     91 #define LiftCutoff_Tune_Timeout 0x58
     92 #define LiftCutoff_Tune_Min_Length  0x5A
     93 #define SROM_Load_Burst 0x62
     94 #define Lift_Config 0x63
     95 #define Raw_Data_Burst  0x64
     96 #define LiftCutoff_Tune2  0x65
     97 
     98 uint8_t adns_init_complete=0;
     99 uint8_t g_want_bootloader = 0;
    100 volatile int xydat[2];
    101 
    102 #include "Mouse.h"
    103 
    104 /** Buffer to hold the previously generated Mouse HID report, for comparison purposes inside the HID class driver. */
    105 static uint8_t PrevMouseHIDReportBuffer[sizeof(USB_WheelMouseReport_Data_t)];
    106 
    107 /** LUFA HID Class driver interface configuration and state information. This structure is
    108  *  passed to all HID Class driver functions, so that multiple instances of the same class
    109  *  within a device can be differentiated from one another.
    110  */
    111 USB_ClassInfo_HID_Device_t Mouse_HID_Interface =
    112   {
    113     .Config =
    114       {
    115         .InterfaceNumber              = INTERFACE_ID_Mouse,
    116         .ReportINEndpoint             =
    117           {
    118             .Address              = MOUSE_EPADDR,
    119             .Size                 = MOUSE_EPSIZE,
    120             .Banks                = 1,
    121           },
    122         .PrevReportINBuffer           = PrevMouseHIDReportBuffer,
    123         .PrevReportINBufferSize       = sizeof(PrevMouseHIDReportBuffer),
    124       },
    125   };
    126 
    127 void led_error(void) {
    128   DDRC = 0b11110100;
    129 }
    130 
    131 void led_ok(void) {
    132   DDRC = 0;
    133 }
    134 
    135 void led_set(uint8_t bits) {
    136   DDRC = ((bits&0b11110)<<3)|((bits&1)<<2);
    137 }
    138 
    139 // FIXME QUESTIONABLE
    140 int convTwosComp(int b) {
    141   //Convert from 2's complement
    142   if (b & 0x80) {
    143     b = -1 * ((b ^ 0xff) + 1);
    144   }
    145   return b;
    146 }
    147 
    148 // LM PD0 input pullup
    149 // RM PD1 input pullup
    150 
    151 #define ADDR_SENSOR (0x79<<1)
    152 
    153 uint8_t twi_write_reg[1];
    154 uint8_t twi_write_buf[10];
    155 uint8_t twi_read_buf[10];
    156 
    157 void SetupHardware(void)
    158 {
    159   /* Disable watchdog if enabled by bootloader/fuses */
    160   MCUSR &= ~(1 << WDRF);
    161   wdt_disable();
    162 
    163   // Disable clock division
    164   // this should yield 8Mhz with internal osc
    165   clock_prescale_set(clock_div_1);
    166 
    167   DDRD = 0b00000000;
    168   //DDRB = 0b11000110;
    169   DDRC = 0b00000000;
    170 
    171   output_high(PORTD, 0); // enable input pullup for LMB
    172   output_high(PORTD, 1); // enable input pullup for RMB
    173   output_high(PORTD, 2); // enable input pullup for RMB
    174   output_high(PORTD, 3); // enable input pullup for RMB
    175   output_high(PORTD, 4); // enable input pullup for RMB
    176 
    177   // no jtag plox
    178   //MCUCR |=(1<<JTD);
    179   //MCUCR |=(1<<JTD);
    180 
    181   USB_Init();
    182 
    183   i2c_init();
    184 }
    185 
    186 void init_sensor(void) {
    187   Delay_MS(100);
    188   led_error();
    189   Delay_MS(100);
    190 
    191   if (!i2c_start(ADDR_SENSOR|I2C_WRITE)) {
    192     i2c_write(0x7f);
    193     i2c_write(0x0);
    194     i2c_stop();
    195 
    196     led_ok();
    197   }
    198   if (!i2c_start(ADDR_SENSOR|I2C_WRITE)) {
    199     i2c_write(0x05);
    200     i2c_write(0x01);
    201     i2c_stop();
    202 
    203     led_ok();
    204   }
    205 }
    206 
    207 /** Event handler for the library USB Connection event. */
    208 void EVENT_USB_Device_Connect(void)
    209 {
    210 }
    211 
    212 /** Event handler for the library USB Disconnection event. */
    213 void EVENT_USB_Device_Disconnect(void)
    214 {
    215 }
    216 
    217 /** Event handler for the library USB Configuration Changed event. */
    218 void EVENT_USB_Device_ConfigurationChanged(void)
    219 {
    220   bool ConfigSuccess = true;
    221 
    222   ConfigSuccess &= HID_Device_ConfigureEndpoints(&Mouse_HID_Interface);
    223 
    224   USB_Device_EnableSOFEvents();
    225 }
    226 
    227 /** Event handler for the library USB Control Request reception event. */
    228 void EVENT_USB_Device_ControlRequest(void)
    229 {
    230   HID_Device_ProcessControlRequest(&Mouse_HID_Interface);
    231 }
    232 
    233 /** Event handler for the USB device Start Of Frame event. */
    234 void EVENT_USB_Device_StartOfFrame(void)
    235 {
    236   HID_Device_MillisecondElapsed(&Mouse_HID_Interface);
    237 }
    238 
    239 /** HID class driver callback function for the creation of HID reports to the host.
    240  *
    241  *  \param[in]     HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
    242  *  \param[in,out] ReportID    Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
    243  *  \param[in]     ReportType  Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
    244  *  \param[out]    ReportData  Pointer to a buffer where the created report should be stored
    245  *  \param[out]    ReportSize  Number of bytes written in the report (or zero if no report is to be sent)
    246  *
    247  *  \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
    248  */
    249 bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
    250                                          uint8_t* const ReportID,
    251                                          const uint8_t ReportType,
    252                                          void* ReportData,
    253                                          uint16_t* const ReportSize)
    254 {
    255   if (ReportType==HID_REPORT_ITEM_Feature) {
    256     if (*ReportID==0) {
    257       *ReportID=2;
    258     }
    259 
    260     if (*ReportID==2) {
    261       USB_WheelMouseFeatureReport_Data_t* FeatureReport = (USB_WheelMouseFeatureReport_Data_t*)ReportData;
    262       FeatureReport->Multiplier = 2;
    263       *ReportSize = sizeof(USB_WheelMouseFeatureReport_Data_t);
    264       return true;
    265     } else {
    266       return false;
    267     }
    268   }
    269 
    270   if (*ReportID==0) {
    271     *ReportID=1;
    272   }
    273 
    274   if (*ReportID!=1) {
    275     return false;
    276   }
    277 
    278   int8_t nx = 0;
    279   int8_t ny = 0;
    280 
    281   i2c_start_wait(ADDR_SENSOR|I2C_WRITE);
    282   i2c_write(0x02);
    283   i2c_rep_start(ADDR_SENSOR|I2C_READ);
    284   uint8_t ret = i2c_readNak();
    285   i2c_stop();
    286   if (ret & 0xf0) {
    287     i2c_start_wait(ADDR_SENSOR|I2C_WRITE);
    288     i2c_write(0x03);
    289     i2c_rep_start(ADDR_SENSOR|I2C_READ);
    290     nx = i2c_readAck();
    291     ny = i2c_readNak();
    292     i2c_stop();
    293   }
    294 
    295   USB_WheelMouseReport_Data_t* MouseReport = (USB_WheelMouseReport_Data_t*)ReportData;
    296 
    297   if (!(PIND&(1<<4))) {
    298     MouseReport->Button |= 1;
    299   }
    300   if (!(PIND&(1<<3))) {
    301     MouseReport->Button |= 2;
    302   }
    303   if (!(PIND&(1<<1))) {
    304     MouseReport->Button |= 4;
    305   }
    306 
    307   MouseReport->Pan = 0;
    308   MouseReport->Wheel = 0;
    309 
    310   if (!(PIND&1) || !(PIND&(1<<2))) {
    311     // wheel
    312     MouseReport->Pan = 2*nx;
    313     MouseReport->Wheel = 2*-ny;
    314   } else {
    315     MouseReport->X = 2*abs(nx)*nx;
    316     MouseReport->Y = 2*abs(ny)*ny;
    317   }
    318 
    319   *ReportSize = sizeof(USB_WheelMouseReport_Data_t);
    320 
    321   return false;
    322 }
    323 
    324 #define BOOTLOADER_START_ADDRESS ((0x8000 - 0x1000) >> 1)
    325 void jump_to_bootloader(void) {
    326   ((void (*)(void))BOOTLOADER_START_ADDRESS)();
    327 }
    328 
    329 #define cmd(_s) (*(uint32_t *)(_s))
    330 #define CMD_SET_LEDS           cmd("LEDS")
    331 #define CMD_JUMP_TO_BOOTLOADER cmd("JTBL")
    332 
    333 /** HID class driver callback function for the processing of HID reports from the host.
    334  *
    335  *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
    336  *  \param[in] ReportID    Report ID of the received report from the host
    337  *  \param[in] ReportType  The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
    338  *  \param[in] ReportData  Pointer to a buffer where the received report has been stored
    339  *  \param[in] ReportSize  Size in bytes of the received HID report
    340  */
    341 void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
    342                                           const uint8_t ReportID,
    343                                           const uint8_t ReportType,
    344                                           const void* ReportData,
    345                                           const uint16_t ReportSize)
    346 {
    347   if (ReportSize < 4) return;
    348   const uint32_t command = *(uint32_t *)ReportData;
    349   if (command == CMD_SET_LEDS) {
    350     char* d = (char *)ReportData;
    351     uint8_t bits = ((d[4]=='1')<<4)|((d[5]=='1')<<3)|((d[6]=='1')<<2)|((d[7]=='1')<<1)|(d[8]=='1');
    352     led_set(bits);
    353   }
    354   if (command == CMD_JUMP_TO_BOOTLOADER) {
    355     g_want_bootloader = 1;
    356   }
    357 }
    358 
    359 int main(void)
    360 {
    361   int sensor_initialized = 0;
    362 
    363   SetupHardware();
    364   GlobalInterruptEnable();
    365 
    366   for (;;) {
    367     HID_Device_USBTask(&Mouse_HID_Interface);
    368     USB_USBTask();
    369 
    370     if (g_want_bootloader) jump_to_bootloader();
    371     if (!sensor_initialized) {
    372       init_sensor();
    373       sensor_initialized = 1;
    374     }
    375   }
    376 }