reform

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

main.c (8224B)


      1 /*
      2  * The MIT License (MIT)
      3  *
      4  * Copyright 2019 Ha Thach (tinyusb.org)
      5  * Copyright 2023 MNT Research GmbH (mntre.com)
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23  * THE SOFTWARE.
     24  *
     25  */
     26 
     27 #include <stdlib.h>
     28 #include <stdio.h>
     29 #include <string.h>
     30 
     31 #include "bsp/board_api.h"
     32 #include "tusb.h"
     33 
     34 #include "pico/stdlib.h"
     35 #include "pico/binary_info.h"
     36 #include "hardware/gpio.h"
     37 #include "hardware/i2c.h"
     38 
     39 #define PIN_SDA 0
     40 #define PIN_SCL 1
     41 
     42 #define PIN_BTN1 20
     43 #define PIN_BTN2 21
     44 #define PIN_BTN3 19
     45 #define PIN_BTN4 18
     46 #define PIN_BTN5 17
     47 
     48 #define PIN_LEDS 24
     49 
     50 #define ADDR_SENSOR (0x79)
     51 
     52 //--------------------------------------------------------------------+
     53 // MACRO CONSTANT TYPEDEF PROTYPES
     54 //--------------------------------------------------------------------+
     55 
     56 // Interface index depends on the order in configuration descriptor
     57 enum {
     58   ITF_MOUSE = 0
     59 };
     60 
     61 void hid_task(void);
     62 
     63 /*------------- MAIN -------------*/
     64 int main(void)
     65 {
     66   board_init();
     67   tusb_init();
     68 
     69   gpio_pull_up(PIN_BTN1);
     70   gpio_pull_up(PIN_BTN2);
     71   gpio_pull_up(PIN_BTN3);
     72   gpio_pull_up(PIN_BTN4);
     73   gpio_pull_up(PIN_BTN5);
     74 
     75   gpio_init(PIN_LEDS);
     76   gpio_set_dir(PIN_LEDS, true); // output
     77 
     78   i2c_init(i2c0, 100 * 1000);
     79   gpio_set_function(PIN_SDA, GPIO_FUNC_I2C);
     80   gpio_set_function(PIN_SCL, GPIO_FUNC_I2C);
     81 
     82   bi_decl(bi_2pins_with_func(PIN_SDA, PIN_SCL, GPIO_FUNC_I2C));
     83 
     84   uint8_t buf[] = {0x7f, 0x00, 0x00, 0x00};
     85   i2c_write_blocking(i2c0, ADDR_SENSOR, buf, 2, false);
     86 
     87   buf[0] = 0x05;
     88   buf[1] = 0x01;
     89   i2c_write_blocking(i2c0, ADDR_SENSOR, buf, 2, false);
     90 
     91   while (1)
     92   {
     93     tud_task(); // tinyusb device task
     94 
     95     hid_task();
     96   }
     97 
     98   return 0;
     99 }
    100 
    101 //--------------------------------------------------------------------+
    102 // Device callbacks
    103 //--------------------------------------------------------------------+
    104 
    105 // Invoked when device is mounted
    106 void tud_mount_cb(void)
    107 {
    108 }
    109 
    110 // Invoked when device is unmounted
    111 void tud_umount_cb(void)
    112 {
    113 }
    114 
    115 // Invoked when usb bus is suspended
    116 // remote_wakeup_en : if host allow us  to perform remote wakeup
    117 // Within 7ms, device must draw an average of current less than 2.5 mA from bus
    118 void tud_suspend_cb(bool remote_wakeup_en)
    119 {
    120   (void) remote_wakeup_en;
    121 }
    122 
    123 // Invoked when usb bus is resumed
    124 void tud_resume_cb(void)
    125 {
    126 }
    127 
    128 //--------------------------------------------------------------------+
    129 // USB HID
    130 //--------------------------------------------------------------------+
    131 
    132 typedef struct TU_ATTR_PACKED
    133 {
    134   uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
    135   int8_t  x;       /**< Current delta x movement of the mouse. */
    136   int8_t  y;       /**< Current delta y movement on the mouse. */
    137   int8_t  wheel;   /**< Current delta wheel movement on the mouse. */
    138   int8_t  pan;     // using AC Pan
    139 } hid_trackball_report_t;
    140 
    141 bool tud_hid_n_trackball_report(uint8_t instance, uint8_t report_id,
    142                             uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
    143 {
    144   hid_trackball_report_t report =
    145   {
    146     .buttons = buttons,
    147     .x       = x,
    148     .y       = y,
    149     .wheel   = vertical,
    150     .pan     = horizontal
    151   };
    152 
    153   return tud_hid_n_report(instance, report_id, &report, sizeof(report));
    154 }
    155 
    156 uint8_t prev_buttons = 0;
    157 uint8_t scroll_toggle = 0;
    158 
    159 int __attribute__((optimize("Os"))) delay300ns() {
    160   // ~300ns
    161   asm volatile(
    162                "mov  r0, #10\n"    		// 1 cycle
    163                "loop1: sub  r0, r0, #1\n"	// 1 cycle
    164                "bne   loop1\n"          	// 2 cycles if loop taken, 1 if not
    165                );
    166   return 0;
    167 }
    168 
    169 // TODO to use LEDs, rather implement PIOs like in Pocket Reform's pocket-hid
    170 void led_test(uint32_t rgb) {
    171   for (int y=0; y<5; y++) {
    172     for (int i=23; i>=0; i--) {
    173       uint32_t bit = !!(rgb & (1<<i));
    174       if (bit) {
    175         // one
    176         gpio_put(PIN_LEDS, 1);
    177         delay300ns();
    178         delay300ns();
    179         delay300ns();
    180         gpio_put(PIN_LEDS, 0);
    181         // ~600ms delay
    182         delay300ns();
    183         delay300ns();
    184       } else {
    185         // zero
    186         gpio_put(PIN_LEDS, 1);
    187         delay300ns();
    188         gpio_put(PIN_LEDS, 0);
    189         // ~1.2ms delay
    190         delay300ns();
    191         delay300ns();
    192         delay300ns();
    193         delay300ns();
    194         //delay300ns();
    195       }
    196     }
    197   }
    198 }
    199 
    200 int rgb_channel = 0;
    201 int rgb_val = 0;
    202 
    203 void hid_task(void)
    204 {
    205   // Poll every 10ms
    206   const uint32_t interval_ms = 10;
    207   static uint32_t start_ms = 0;
    208 
    209   uint8_t buf[] = {0x7f, 0x00, 0x00, 0x00};
    210 
    211   if ( board_millis() - start_ms < interval_ms) return; // not enough time
    212 
    213   start_ms += interval_ms;
    214 
    215   int btn = !gpio_get(PIN_BTN1);
    216 
    217   // Remote wakeup
    218   if ( tud_suspended() && btn )
    219   {
    220     // Wake up host if we are in suspend mode
    221     // and REMOTE_WAKEUP feature is enabled by host
    222     tud_remote_wakeup();
    223   }
    224 
    225   // LED test
    226   /*led_test(rgb_val<<rgb_channel);
    227   rgb_val++;
    228   if (rgb_val > 0xff) {
    229     rgb_val = 0;
    230     rgb_channel += 8;
    231     if (rgb_channel > 16) {
    232       rgb_channel = 0;
    233     }
    234   }*/
    235 
    236   /*------------- Mouse -------------*/
    237   if ( tud_hid_n_ready(ITF_MOUSE) )
    238   {
    239     buf[0] = 0x02;
    240     i2c_write_blocking(i2c0, ADDR_SENSOR, buf, 1, true);
    241     i2c_read_blocking(i2c0, ADDR_SENSOR, buf, 1, false);
    242 
    243     uint8_t btn1 = !gpio_get(PIN_BTN1);
    244     uint8_t btn2 = !gpio_get(PIN_BTN2);
    245     uint8_t btn3 = !gpio_get(PIN_BTN3);
    246     uint8_t btn4 = !gpio_get(PIN_BTN4);
    247     uint8_t btn5 = !gpio_get(PIN_BTN5);
    248 
    249     // pressing both wheel buttons together turns on sticky wheel mode
    250     if (btn1 || btn2 || btn4) {
    251       scroll_toggle = 0;
    252     } else if (btn5 && btn3) {
    253       scroll_toggle = 1;
    254     }
    255 
    256     uint8_t buttons = btn1 | (btn2<<1) | (btn4<<2);
    257 
    258     if (buf[0] & 0xf0) {
    259       buf[0] = 0x03;
    260       i2c_write_blocking(i2c0, ADDR_SENSOR, buf, 1, true);
    261       i2c_read_blocking(i2c0, ADDR_SENSOR, buf, 2, false);
    262 
    263       int8_t nx = (int8_t)buf[0];
    264       int8_t ny = (int8_t)buf[1];
    265 
    266       // no button, right + down, no scroll pan
    267       if (btn3 || btn5 || scroll_toggle) {
    268         tud_hid_n_trackball_report(ITF_MOUSE, 1, buttons, 0, 0, -2*ny, 2*nx);
    269       } else {
    270         tud_hid_n_trackball_report(ITF_MOUSE, 1, buttons, 2*nx, 2*ny, 0, 0);
    271       }
    272     } else {
    273       if (buttons != prev_buttons) {
    274         tud_hid_n_mouse_report(ITF_MOUSE, 1, buttons, 0, 0, 0, 0);
    275       }
    276     }
    277 
    278     prev_buttons = buttons;
    279   }
    280 }
    281 
    282 
    283 // Invoked when received GET_REPORT control request
    284 // Application must fill buffer report's content and return its length.
    285 // Return zero will cause the stack to STALL request
    286 uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
    287 {
    288   // TODO not Implemented
    289   (void) itf;
    290   (void) buffer;
    291   (void) reqlen;
    292 
    293   if (report_type != HID_REPORT_TYPE_FEATURE) return 0;
    294 
    295   if (report_id == 2) {
    296     //buffer[0] = 2; // multiplier
    297     //return 1;
    298   }
    299 
    300   return 0;
    301 }
    302 
    303 // Invoked when received SET_REPORT control request or
    304 // received data on OUT endpoint ( Report ID = 0, Type = 0 )
    305 void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
    306 {
    307   // TODO set LED based on CAPLOCK, NUMLOCK etc...
    308   (void) itf;
    309   (void) report_id;
    310   (void) report_type;
    311   (void) buffer;
    312   (void) bufsize;
    313 }