Changeset 703832c in avrstuff


Ignore:
Timestamp:
Sep 26, 2021, 10:16:19 AM (3 years ago)
Author:
Adrien Destugues <pulkomandy@…>
Branches:
main
Children:
e545350
Parents:
81b8d53
Message:

GrIP2HID: actually do HID (using the LUFA USB stack)

Location:
grip2hid
Files:
6 added
1 deleted
1 edited
1 moved

Legend:

Unmodified
Added
Removed
  • grip2hid/README.md

    r81b8d53 r703832c  
    1111(2 gameports, each allowing to use 2 gamepads thanks to Gravis chaining system).
    1212
     13The gamepads are each reported as a separate USB report, and show up as 4 independant
     14gamepads on both Windows and Haiku. Buttons are assigned in this order:
     15green, yellow, red, blue, L1, R1, start, select, R2, L2. This order is reasonable
     16(but not perfect) while allowing to reuse the bits received from the gamepad almost
     17directly to fill the HID report. The only change needed is inverting the Y axis,
     18because USB wants the up direction to be lowest values.
     19
    1320It is powered by an AT90USB AVR microcontroller, because these implement USB in
    14 hardware and have easily usable external interupts (PCINT) making it much easier
    15 to implement the protocol (this helps because the gamepad is the master and
    16 drives the clock).
     21hardware and make it easy to implement an HID device.
     22
     23You need the LUFA USB stack to compile this project. I am not including it to
     24avoid code duplication. Download and extract it yourself, or set the LUFA_PATH variable
     25to where you already have it when compiling.
    1726
    1827[Further reading on GrIP](http://pulkomandy.tk/_/_Electronique/_Gravis%20Interface%20Protocol)
  • grip2hid/grip.cpp

    r81b8d53 r703832c  
    11#include <avr/io.h>
    2 #include <avr/interrupt.h>
    3 #include <avr/wdt.h>
    4 #include <avr/pgmspace.h>
    5 #include <util/delay.h>
    62
    7 #include <string.h>
    83#include <stdbool.h>
    94
    10 #include "../libs/usart/usart.h"
    11 
     5// The UART is on PD2 (Rx) and PD3 (Tx)
     6// The gamepads are all connected on port B
    127#define GRIP_PORT PORTB
    138#define GRIP_DDR  DDRB
     
    3227        }
    3328
     29        // Push the next bit and returns true if it completes a word.
     30        // The whole 24 bit word is stored in "word" and consists of:
     31        // - One 7-bit sync pattern: always 0111111
     32        // - Three 6-bit blocks starting with a 0 followed by 5 button bits
    3433        bool PushBit(uint32_t bit)
    3534        {
    36                 word = (word << 1) | (bit & 1);
     35                word = (word >> 1) | ((bit & 1) << 31);
    3736                count++;
    3837
    3938                switch (state) {
    4039                        case 0:
    41                                 if ((word & 0x3F) != 0x1F) return false;
    42                                 count = 6;
     40                                if ((word & 0xFE000000) != 0x7C000000) return false;
     41                                count = 7;
    4342                                state = 1;
    4443                                break;
     
    5554        }
    5655
    57         void Dump() {
    58                 USARTWriteHex(word >> 16);
    59                 USARTWriteHex(word >> 8);
    60                 USARTWriteHex(word);
    61         }
    62 
     56public:
     57        uint32_t word;
    6358private:
    64         uint32_t word;
    6559        uint8_t count;
    66         uint8_t state;
     60        uint8_t state; // 0 = looking for sync, 1 = synchronized (we received 0111111)
    6761};
    6862
    6963
    70 int main() {
    71         wdt_enable(WDTO_2S);
    72 
     64extern "C" void GrIP_Init() {
    7365        // GrIP input
    7466        GRIP_PORT = 0xFF; // Enable pull-ups
    7567        GRIP_DDR = 0;  // Port as input
     68}
    7669
    77         USARTInit();
    78         USARTWriteChar('h');
    79         USARTWriteChar('\r');
    80         USARTWriteChar('\n');
    81 
     70extern "C" uint8_t GrIP_Read(uint32_t* v, uint8_t k2) {
    8271        // Initial value of oldv for edge detection
    8372        uint8_t oldv = GRIP_PIN;
     73        static uint8_t k = 0;
     74        if (k2 != 0)
     75                k = k2 - 1;
     76        else {
     77                k++; if (k > 3) k = 0;
     78        }
    8479
    85         for (;;) {
    8680                // Because the CPU is too slow, if we try to scan all pads at once we
    8781                // don't manage to decode them (missed transitions). So we scan them
     
    9589                // also fixes the problem mentionned below that when less pads are
    9690                // connected, it will not slowdown waiting for one of them to timeout.
     91                //
     92                // When a gamepad is plugged, the loop seems to complete in around 1000 iterations.
     93                // When no gamepad is plugged, that's a timeout.
    9794
    98                 // FIXME the loop to 255 here to wait for a bit isn't too nice. We
    99                 // should rather use a timer with a known period?
    10095                // Process pad1
    10196                GrIP pad;
    102                 uint8_t i;
    103                 for (i = 0; i < 255; i++) {
    104                         wdt_reset();
     97                uint16_t i;
    10598
     99                if (k == 0)
     100                for (i = 0; i < 2048; i++) {
    106101                        uint8_t newv = GRIP_PIN;
    107 
    108102                        if (!(newv & GRIP_CLK_A)) { // clock is down
    109103                                if (oldv & GRIP_CLK_A) { // and it was up at previous read
     
    111105                                        uint32_t bit = (newv & GRIP_DAT_A) != 0;
    112106                                        if (pad.PushBit(bit)) {
     107                                                *v = pad.word;
    113108                                                break;
    114109                                        }
     
    118113                }
    119114
    120                 pad.Dump();
    121                 USARTWriteChar(' ');
    122 
    123115                // Process pad 2
    124                 for (i = 0; i < 255; i++) {
    125                         wdt_reset();
    126 
     116                if (k == 1)
     117                for (i = 0; i < 2048; i++) {
    127118                        uint8_t newv = GRIP_PIN;
    128119                        if (!(newv & GRIP_CLK_B)) { // clock is down
     
    131122                                        uint32_t bit = (newv & GRIP_DAT_B) != 0;
    132123                                        if (pad.PushBit(bit)) {
     124                                                *v = pad.word;
    133125                                                break;
    134126                                        }
     
    138130                }
    139131
    140                 pad.Dump();
    141                 USARTWriteChar(' ');
    142 
    143132                // Process pad 3
    144                 for (i = 0; i < 255; i++) {
    145                         wdt_reset();
    146 
     133                if (k == 2)
     134                for (i = 0; i < 2048; i++) {
    147135                        uint8_t newv = GRIP_PIN;
    148136                        if (!(newv & GRIP_CLK_C)) { // clock is down
     
    151139                                        uint32_t bit = (newv & GRIP_DAT_C) != 0;
    152140                                        if (pad.PushBit(bit)) {
     141                                                *v = pad.word;
    153142                                                break;
    154143                                        }
     
    158147                }
    159148
    160                 pad.Dump();
    161                 USARTWriteChar(' ');
    162 
    163149                // Process pad 4
    164                 for (i = 0; i < 255; i++) {
    165                         wdt_reset();
    166 
     150                if (k == 3)
     151                for (i = 0; i < 2048; i++) {
    167152                        uint8_t newv = GRIP_PIN;
    168153                        if (!(newv & GRIP_CLK_D)) { // clock is down
     
    171156                                        uint32_t bit = (newv & GRIP_DAT_D) != 0;
    172157                                        if (pad.PushBit(bit)) {
     158                                                *v = pad.word;
    173159                                                break;
    174160                                        }
     
    178164                }
    179165
    180                 pad.Dump();
    181                 USARTWriteChar('\r');
    182                 USARTWriteChar('\n');
    183         }
    184 
    185         return 0;
     166                return k;
    186167}
    187168
Note: See TracChangeset for help on using the changeset viewer.