[EN] Try the SoftHost USB library for ESP32.

This article is an example of using nathalis‘s ESP32 Soft Host to try and test it on an OLED display with a resolution of 128×64 dots as shown in Figure 1 to receive data from a keyboard or mouse, it uses only a few GPIO pins but receives data from a keyboard with a large number of keys. Normally, the ESP32 microcontroller does not support a direct USB connection, so it requires programming by using a timer to check the status of the pins D- and D+ to be assembled into data at the byte level and assembled into packs of data for further interpretation.

Figure 1 Connected devices and boards are illustrated in this article

Connection

The part of the connection between USB Port and ESP32 is as shown in Figure 2.

  • GPIO18 connected to D+
  • GPIO19 connected to D-
  • GND connected to GND of USB
  • 5V connected to Vcc of SB
Figure 2 Connection between ESP32 and USB

Library list

The library created by nathalis supports up to 4 USB ports, defined in the code as follows: and if not use it as -1

#define DP_P0  18  // Data+
#define DM_P0  19  // Data-
#define DP_P1  -1  // not used
#define DM_P1  -1  // not used
#define DP_P2  -1  // not used
#define DM_P2  -1  // not used
#define DP_P3  -1  // not used
#define DM_P3  -1  // not used

usb_pins_config_t USB_Pins_Config =
{
  DP_P0, DM_P0,
  DP_P1, DM_P1,
  DP_P2, DM_P2,
  DP_P3, DM_P3
};

The files that come together with ESP32-USB-SOFTHOST1.1-LOWSPEED-KEYBOARD-AND-MOUSE are

What we have corrected is in the code that is defined as inline and thus fails to compile. So change the code of usb_host.c as follows

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>

#include "driver/gpio.h"
#include "sdkconfig.h"
#include "driver/timer.h"
#include "soc/soc.h"
#include "soc/rtc.h"
#include "math.h"
#include "esp_heap_caps.h"

/*******************************
     warning!!!: any copy of this code or his part must include this:
   "The original was written by Dima Samsonov @ Israel [email protected] on 3/2021"
   Copyright (C) 2021  Dmitry Samsonov
********************************/

/*\
   Changes by tobozo (may 2021):
     - Backported calibration at init (last changes from from Samsonov's repo)
   Changes by tobozo (march 2021):
     - Arduino IDE compliance (mostly code regression to esp-idf 3.x)
     - Added callbacks (data and device detection)
  \*/


#include "usb_host.h"

// Arduino IDE complains about volatile at init, but we don't care
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"

extern uint8_t DEBUGEXTRA_VAR;
uint8_t new_device = 0;


#define T_START   0b00000001
#define T_ACK     0b01001011
#define T_NACK    0b01011010
#define T_SOF    0b10100101
#define T_SETUP  0b10110100
#define T_DATA0  0b11000011
#define T_DATA1  0b11010010
#define T_DATA2  0b11100001
#define T_OUT    0b10000111
#define T_IN    0b10010110

#define T_ERR    0b00111100
#define T_PRE    0b00111100
#define T_NYET  0b01101001
#define T_STALL  0b01111000

// local non std
#define T_NEED_ACK   0b01111011
#define T_CHK_ERR    0b01111111

#define USB_LS_K  0
#define USB_LS_J  1
#define USB_LS_S  2

//most counters- uint_8t :  so  prevents overflow...

#define DEF_BUFF_SIZE 0x100

// somethins short  like ACK
#define SMALL_NO_DATA 36


///cpufreq (must be 240) /8 count = 30MHz  convinient number for measure 1.5MHz  of  low speed USB
static inline uint8_t _getCycleCount8d8(void)
{
  uint32_t ccount;
  __asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
  return ccount >> 3;
}

static inline uint32_t _getCycleCount32(void)
{
  uint32_t ccount;
  __asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
  return ccount;
}

int TRANSMIT_TIME_DELAY = 110;  //delay each bit transmit
int TIME_MULT           = 25;    //received time factor delta clocks* TIME_MULT/TIME_SCALE
int TM_OUT              = 64;    //receive time out no activity on bus
#define  TIME_SCALE       1024

//#define TEST
#ifdef TEST
#define TOUT  1000
#else
#define TOUT  (TM_OUT)
#endif

#define SET_I { PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[DP_PIN]); PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[DM_PIN]); GPIO.enable_w1tc = (1 << DP_PIN) | (1 << DM_PIN);  }
#define SET_O { GPIO.enable_w1ts = (1 << DP_PIN) | (1 << DM_PIN);  PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[DP_PIN]); PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[DM_PIN]);  }
#define SE_J  { *snd[1][0] = (1 << DM_PIN);*snd[1][1] = (1 << DP_PIN); }
#define SE_0  { *snd[2][0] = (1 << DM_PIN);*snd[2][1] = (1 << DP_PIN); }

#define READ_BOTH_PINS ((GPIO.in&RD_MASK)>>RD_SHIFT)

//must be setup ech time with setPins
uint32_t DP_PIN;
uint32_t DM_PIN;

uint32_t DM_PIN_M;
uint32_t DP_PIN_M;
uint16_t M_ONE;
uint16_t P_ONE;
uint32_t RD_MASK;
uint32_t RD_SHIFT;
//end must be setup ech time with setPins

// temporary used insize lowlevel
volatile   uint8_t received_NRZI_buffer_bytesCnt;
uint16_t   received_NRZI_buffer[DEF_BUFF_SIZE];

volatile uint8_t transmit_bits_buffer_store_cnt;
//uint8_t transmit_bits_buffer_store[DEF_BUFF_SIZE];
uint8_t* transmit_bits_buffer_store = (uint8_t*)&received_NRZI_buffer[0];

volatile uint8_t transmit_NRZI_buffer_cnt;
uint8_t  transmit_NRZI_buffer[DEF_BUFF_SIZE];

volatile uint8_t decoded_receive_buffer_head;
volatile uint8_t decoded_receive_buffer_tail;
uint8_t decoded_receive_buffer[DEF_BUFF_SIZE];
// end temporary used insize lowlevel


void (*delay_pntA)() = NULL;
#define cpuDelay(x) {(*delay_pntA)();}
void setDelay(uint8_t ticks)
{
  // opcodes of void test_delay() {__asm__ (" nop"); __asm__ (" nop"); __asm__ (" nop"); ...}
  //36 41 00 3d f0 1d f0 00 // one  nop
  //36 41 00 3d f0 3d f0 3d f0 3d f0 3d f0 1d f0 00  // five  nops
  //36 41 00 3d f0 3d f0 3d f0 3d f0 3d f0 3d f0 1d  f0 00 00 00 //
  int    MAX_DELAY_CODE_SIZE = 0x280;
  uint8_t*     pntS;
  // it can't execute but can read & write
  if (!delay_pntA) {
    pntS = malloc(MAX_DELAY_CODE_SIZE);
  } else {
    pntS = heap_caps_realloc(delay_pntA, MAX_DELAY_CODE_SIZE, MALLOC_CAP_8BIT);
  }
  uint8_t* pnt = (uint8_t*)pntS;
  //put head of delay procedure
  *pnt++ = 0x36;
  *pnt++ = 0x41;
  *pnt++ = 0;
  for (int k = 0; k < ticks; k++) {
    //put NOPs
    *pnt++ = 0x3d;
    *pnt++ = 0xf0;
  }
  //put tail of delay procedure
  *pnt++ = 0x1d;
  *pnt++ = 0xf0;
  *pnt++ = 0x00;
  *pnt++ = 0x00;
  // move it to executable memory segment
  // it can't  write  but can read & execute
  delay_pntA = heap_caps_realloc(pntS, MAX_DELAY_CODE_SIZE, MALLOC_CAP_EXEC);
}


typedef struct
{
  uint8_t cmd;
  uint8_t addr;
  uint8_t eop;

  uint8_t  dataCmd;
  uint8_t  bmRequestType;
  uint8_t  bmRequest;
  uint16_t wValue;
  uint16_t wIndex;
  uint16_t wLen;
} Req;



enum DeviceState
{
  NOT_ATTACHED,
  ATTACHED,
  POWERED,
  DEFAULT,
  ADDRESS,
  PARSE_CONFIG,
  PARSE_CONFIG1,
  PARSE_CONFIG2,
  PARSE_CONFIG3,
  POST_ATTACHED,
  RESET_COMPLETE,
  POWERED_COMPLETE,
  DEFAULT_COMPL
};



enum CallbackCmd
{
  CB_CHECK,
  CB_RESET,
  CB_WAIT0,
  CB_POWER,
  CB_TICK,
  CB_2,
  CB_2Ack,
  CB_3,
  CB_4,
  CB_5,
  CB_6,
  CB_7,
  CB_8,
  CB_9,
  CB_WAIT1
};



//Req rq;
typedef struct
{
  int isValid;
  int selfNum;
  int epCount;
  int cnt;

  uint32_t DP;
  uint32_t DM;

  volatile enum CallbackCmd cb_Cmd;
  volatile enum DeviceState fsm_state;
  volatile uint16_t wires_last_state;

  sDevDesc desc;
  sCfgDesc cfg;
  Req rq;

  int counterNAck;
  int counterAck;

  uint8_t descrBuffer[DEF_BUFF_SIZE];
  uint8_t descrBufferLen;

  volatile int bComplete;
  volatile int in_data_flip_flop;

  int cmdTimeOut;

  uint32_t ufPrintDesc;
  int numb_reps_errors_allowed;

  uint8_t acc_decoded_resp[DEF_BUFF_SIZE];
  uint8_t acc_decoded_resp_counter;

  int asckedReceiveBytes;
  int transmitL1Bytes;
  uint8_t transmitL1[DEF_BUFF_SIZE];

  uint8_t Resp0[DEF_BUFF_SIZE];
  uint8_t R0Bytes;
  uint8_t Resp1[DEF_BUFF_SIZE];
  uint8_t R1Bytes;

} sUsbContStruct;

sUsbContStruct * current;


uint32_t* snd[4][2]  =
{
  { &GPIO.out_w1tc, &GPIO.out_w1ts },
  { &GPIO.out_w1ts, &GPIO.out_w1tc },
  { &GPIO.out_w1tc, &GPIO.out_w1tc },
  { &GPIO.out_w1tc, &GPIO.out_w1tc }
} ;


#ifdef WR_SIMULTA
uint32_t sndA[4]  = {0, 0, 0, 0};
#endif



void restart()
{
  transmit_NRZI_buffer_cnt = 0;
}



void decoded_receive_buffer_clear()
{
  decoded_receive_buffer_tail = decoded_receive_buffer_head;
}



void decoded_receive_buffer_put(uint8_t val)
{
  decoded_receive_buffer[decoded_receive_buffer_head] = val;
  decoded_receive_buffer_head++;
}



uint8_t decoded_receive_buffer_get()
{
  return decoded_receive_buffer[decoded_receive_buffer_tail++];
}



uint8_t decoded_receive_buffer_size()
{
  return (uint8_t )(decoded_receive_buffer_head - decoded_receive_buffer_tail);
}



uint8_t cal5()
{
  uint8_t   crcb;
  uint8_t   rem;

  crcb = 0b00101;
  rem =  0b11111;

  for (int k = 16; k < transmit_bits_buffer_store_cnt; k++) {
    int rb = (rem >> 4) & 1;
    rem   =  (rem << 1) & 0b11111;

    if (rb ^ (transmit_bits_buffer_store[k] & 1)) {
      rem ^= crcb;
    }
  }
  return (~rem) & 0b11111;
}



uint32_t cal16()
{
  uint32_t   crcb;
  uint32_t   rem;

  crcb = 0b1000000000000101;
  rem =  0b1111111111111111;

  for (int k = 16; k < transmit_bits_buffer_store_cnt; k++) {
    int rb = (rem >> 15) & 1;
    rem   =  (rem << 1) & 0b1111111111111111;

    if (rb ^ (transmit_bits_buffer_store[k] & 1)) {
      rem ^= crcb;
    }
  }
  return (~rem) & 0b1111111111111111;
}



void seB(int bit)
{
  transmit_bits_buffer_store[transmit_bits_buffer_store_cnt++] = bit;
}



void pu_MSB(uint16_t msg, int N)
{
  for (int k = 0; k < N; k++) {
    seB(msg & (1 << (N - 1 - k)) ? 1 : 0);
  }
}



void pu_LSB(uint16_t msg, int N)
{
  for (int k = 0; k < N; k++) {
    seB(msg & (1 << (k)) ? 1 : 0);
  }
}



void repack()
{
  int last = USB_LS_J;
  int cntOnes = 0;
  transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_J;
  for (int k = 0; k < transmit_bits_buffer_store_cnt; k++) {
    if (transmit_bits_buffer_store[k] == 0) {
      if (last == USB_LS_J || last == USB_LS_S) {
        last = USB_LS_K;
      } else {
        last = USB_LS_J;
      }
      cntOnes = 0;
    } else if (transmit_bits_buffer_store[k] == 1) {
      cntOnes++;
      if (cntOnes == 6) {
        transmit_NRZI_buffer[transmit_NRZI_buffer_cnt] = last;
        transmit_NRZI_buffer_cnt++;
        if (last == USB_LS_J) {
          last = USB_LS_K;
        } else {
          last = USB_LS_J;
        }
        cntOnes = 0;
      }
      if (last == USB_LS_S) {
        last = USB_LS_J;
      }
    }
    transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = last;
  }

  transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_S;
  transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_S;

  transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_J;
  transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_J;
  transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_J;
  transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_J;

  transmit_bits_buffer_store_cnt = 0;
}



uint8_t rev8(uint8_t j)
{
  uint8_t res = 0;
  for (int i = 0; i < 8; i++) {
    res <<= 1;
    res |= (j >> i) & 1;
  }
  return res;
}



uint16_t rev16(uint16_t j) {
  uint16_t res = 0;
  for (int i = 0; i < 16; i++) {
    res <<= 1;
    res |= (j >> i) & 1;
  }
  return res;
}



#ifdef DEBUG_ALL
uint16_t debug_buff[0x100];
#endif



int parse_received_NRZI_buffer()
{

  if (!received_NRZI_buffer_bytesCnt) return 0;

  uint32_t   crcb;
  uint32_t   rem;

  crcb = 0b1000000000000101;
  rem =  0b1111111111111111;

  int  res = 0;
  int  cntOnes = 0;

  int terr  = 0;
  uint8_t  current_res = 0xfe;
  uint16_t prev = received_NRZI_buffer[0];
  int      start = -1;
  uint8_t  prev_smb = M_ONE;
#ifdef DEBUG_ALL
  debug_buff[0] = received_NRZI_buffer_bytesCnt;
  uint8_t rcnt = 1;
  debug_buff[received_NRZI_buffer_bytesCnt] = 0xff;
#endif
  for (int i = 1; i < received_NRZI_buffer_bytesCnt; i++) {
    //define 2.5
    uint16_t curr = (prev & 0xff00) + (((received_NRZI_buffer[i] - prev)) & 0xff);
    prev          = received_NRZI_buffer[i];

    uint8_t smb = curr >> 8;
    int tm = (curr & 0xff);
    //debug_buff[i] = tm | (smb<<8);
    if ( tm < 2  || (smb == 0) ) {
      //terr+=tm<4?tm : 4;
      terr += tm;
    } else {
      //terr = 0;
      int delta = ((((curr + terr) & 0xff)) * TIME_MULT + TIME_SCALE / 2) / TIME_SCALE;

      for (int k = 0; k < delta; k++) {
        int incc = 1;

        if (prev_smb != smb) {
          if (cntOnes != 6) {
            current_res = current_res * 2 + 0;
          } else {
            incc = 0;
          }
          cntOnes = 0;
        } else {
          current_res = current_res * 2 + 1;
          cntOnes++;
        }
        if (start >= 0) {
          start += incc;
        }
        if (current_res == 0x1 && start < 0 ) {
          start = 0;
        }
        if ( (start & 0x7) == 0 && incc) {
          if (start == 8) {
            res = current_res;
          }
#ifdef DEBUG_ALL
          debug_buff[rcnt++] = current_res;
#endif
          decoded_receive_buffer_put(current_res);
          if (start > 8) {
            for (int bt = 0; bt < 8; bt++) {
              int rb = (rem >> 15) & 1;
              rem   =  (rem << 1) & 0b1111111111111111;
              if (rb ^ ((current_res >> (7 - bt)) & 1)) {
                rem ^= crcb;
              }
            }
          }
        }

        prev_smb = smb;
      }
      terr = 0;
    }
  }
#ifdef DEBUG_ALL
  debug_buff[rcnt++] = 0xff;
#endif
  rem &= 0b1111111111111111;
  if (rem == 0b1111111111111111) {
    return res;
  }
  if (rem == 0x800d) {
    return  T_NEED_ACK;
  } else {
    return  T_CHK_ERR;
  }
}



//#define WR_SIMULTA
void sendOnly()
{
  uint8_t k;
  SET_O;
#ifdef WR_SIMULTA
  uint32_t out_base = GPIO.out;
  sndA[0] = (out_base | DP) & ~DM;
  sndA[1] = (out_base | DM) & ~DP;
  sndA[2] = (out_base ) & ~(DP | DM);
  sndA[3] = out_base | (DM | DP);
#endif
  for (k = 0; k < transmit_NRZI_buffer_cnt; k++) {
    //usb_transmit_delay(10);
    cpuDelay(TRANSMIT_TIME_DELAY);
#ifdef WR_SIMULTA
    GPIO.out = sndA[transmit_NRZI_buffer[k]];
#else
    *snd[transmit_NRZI_buffer[k]][0] = DM_PIN_M;
    *snd[transmit_NRZI_buffer[k]][1] = DP_PIN_M;
#endif
  }
  restart();
  SET_I;
}


void sendRecieveNParse()
{
  register uint32_t R3;
  register uint16_t *STORE = received_NRZI_buffer;
  //__disable_irq();
  sendOnly();
  register uint32_t R4;// = READ_BOTH_PINS;

START:
  R4 = READ_BOTH_PINS;
  *STORE = R4 | _getCycleCount8d8();
  STORE++;
  R3 = R4;
  //R4 = READ_BOTH_PINS;
  //if(R4!=R3)  goto START;
  if ( R3 ) {
    for (int k = 0; k < TOUT; k++) {
      R4   = READ_BOTH_PINS;
      if (R4 != R3)  goto START;
    }
  }
  //__enable_irq();
  received_NRZI_buffer_bytesCnt = STORE - received_NRZI_buffer;
}



int sendRecieve()
{
  sendRecieveNParse();
  return parse_received_NRZI_buffer();
}



void SOF()
{
  if (1) {
    repack();
  }
  sendOnly();
}



void pu_Addr(uint8_t cmd, uint8_t addr, uint8_t eop)
{
  pu_MSB(T_START, 8);
  pu_MSB(cmd, 8); //setup
  pu_LSB(addr, 7);
  pu_LSB(eop, 4);
  pu_MSB(cal5(), 5);
  repack();
}



void pu_ShortCmd(uint8_t cmd)
{
  pu_MSB(T_START, 8);
  pu_MSB(cmd, 8); //setup
  pu_MSB(0, 16);
  repack();
}



void pu_Cmd(uint8_t cmd, uint8_t bmRequestType, uint8_t bmRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLen)
{
  pu_MSB(T_START, 8);
  pu_MSB(cmd, 8); //setup
  pu_LSB(bmRequestType, 8);
  pu_LSB(bmRequest, 8);
  pu_LSB(wValue, 16);
  pu_LSB(wIndex, 16);
  pu_LSB(wLen, 16);
  pu_MSB(cal16(), 16);
  repack();
}



uint8_t ACK_BUFF[0x20];
int    ACK_BUFF_CNT = 0;


void ACK()
{
  transmit_NRZI_buffer_cnt = 0;
  if (ACK_BUFF_CNT == 0) {
    pu_MSB(T_START, 8);
    pu_MSB(T_ACK, 8); // ack
    repack();
    memcpy(ACK_BUFF, transmit_NRZI_buffer, transmit_NRZI_buffer_cnt);
    ACK_BUFF_CNT = transmit_NRZI_buffer_cnt;
  } else {
    memcpy(transmit_NRZI_buffer, ACK_BUFF, ACK_BUFF_CNT);
    transmit_NRZI_buffer_cnt = ACK_BUFF_CNT;
  }
  sendOnly();
}


void timerCallBack()
{
  decoded_receive_buffer_clear();

  if (current->cb_Cmd == CB_CHECK) {
    SET_I;
    current->wires_last_state = READ_BOTH_PINS >> 8;
    if (current->wires_last_state == M_ONE) {
      // low speed

    } else if (current->wires_last_state == P_ONE) {
      //high speed

    } else if (current->wires_last_state == 0x00) {
      // not connected
    } else if (current->wires_last_state == (M_ONE + P_ONE) ) {
      //????
    }

    new_device = 1;

    current->bComplete = 1;
  } else if (current->cb_Cmd == CB_RESET) {
    SOF();
    sendRecieveNParse();
    SET_O;
    SE_0;
    current->cmdTimeOut  =   31;
    current->cb_Cmd         =   CB_WAIT0;
  } else if (current->cb_Cmd == CB_WAIT0) {
    if (current->cmdTimeOut > 0) {
      current->cmdTimeOut--;
    } else {
      //sendRecieveNParse();
      current->bComplete     = 1;
    }
  } else if (current->cb_Cmd == CB_WAIT1) {
    SOF();
    if (current->cmdTimeOut > 0) {
      current->cmdTimeOut--;
    } else {
      sendRecieveNParse();
      current->wires_last_state = READ_BOTH_PINS >> 8;
      current->bComplete     = 1;
    }
  } else if (current->cb_Cmd == CB_POWER) {

    // for TEST
#ifdef TEST
    SOF();
    sendRecieve();
    SOF();
    SOF();
#else
    SET_O;
    SE_J;
    SET_I;
    current->cmdTimeOut  =    2;
    current->cb_Cmd  = CB_WAIT1;
#endif
  } else if (current->cb_Cmd == CB_TICK) {
    SOF();
    current->bComplete     =         1;
  } else if (current->cb_Cmd == CB_3) {
    SOF();
    pu_Addr(current->rq.cmd, current->rq.addr, current->rq.eop);
    pu_Cmd(current->rq.dataCmd, current->rq.bmRequestType, current->rq.bmRequest, current->rq.wValue, current->rq.wIndex, current->rq.wLen);
    int res = sendRecieve();
    if (res == T_ACK) {
      current->cb_Cmd = CB_4;
      current->numb_reps_errors_allowed = 8;
      return ;
    } else {
      current->numb_reps_errors_allowed--;
      if (current->numb_reps_errors_allowed > 0) {
        return ;
      } else {
        current->cb_Cmd = CB_TICK;
        current->bComplete = 1;
      }
    }
  } else if (current->cb_Cmd == CB_4) {
    SOF();
    pu_Addr(T_OUT, current->rq.addr, current->rq.eop);
    //reB();
    pu_MSB(T_START, 8);
    pu_MSB(T_DATA1, 8); //setup
    for (int k = 0; k < current->transmitL1Bytes; k++) {
      pu_LSB(current->transmitL1[k], 8);
    }
    pu_MSB(cal16(), 16);
    repack();
    sendRecieveNParse();
    pu_Addr(T_IN, current->rq.addr, current->rq.eop);
    //setup
    sendRecieveNParse();
    ACK();
    current->cb_Cmd = CB_TICK;
    current->bComplete = 1;
  } else if (current->cb_Cmd == CB_5) {
    SOF();
    pu_Addr(current->rq.cmd, current->rq.addr, current->rq.eop);
    pu_Cmd(current->rq.dataCmd, current->rq.bmRequestType, current->rq.bmRequest, current->rq.wValue, current->rq.wIndex, current->rq.wLen);
    sendRecieveNParse();

    int res = parse_received_NRZI_buffer();
    if (res == T_ACK) {
      current->cb_Cmd = CB_6;
      current->in_data_flip_flop = 1;
      current->numb_reps_errors_allowed = 4;
      current->counterAck ++;
      return ;
    } else {
      //SOF();
      current->counterNAck ++;
      current->numb_reps_errors_allowed--;
      if (current->numb_reps_errors_allowed > 0) {
        // current->cb_Cmd = CB_TICK;
        current->acc_decoded_resp_counter = 0;
        return ;
      } else {
        current->cb_Cmd = CB_TICK;
        current->bComplete       =  1;
      }
    }
  } else if (current->cb_Cmd == CB_6) {
    SOF();
    pu_Addr(T_IN, current->rq.addr, current->rq.eop);
    //setup
    sendRecieveNParse();
    // if receive something ??
    if (current->asckedReceiveBytes == 0 && current->acc_decoded_resp_counter == 0 && received_NRZI_buffer_bytesCnt < SMALL_NO_DATA &&  received_NRZI_buffer_bytesCnt > SMALL_NO_DATA / 4 ) {
      ACK();

      current->cb_Cmd = CB_TICK;
      current->bComplete       =  1;
      return ;
    }
    int res = parse_received_NRZI_buffer();
    if (res == T_NEED_ACK) {
      //SOF();
      if (decoded_receive_buffer_size() > 2) {
        decoded_receive_buffer_get();
        uint8_t sval = decoded_receive_buffer_get();
        if ((current->in_data_flip_flop & 1) == 1) {
          if (sval == T_DATA1) {

          } else {
            current->cb_Cmd = CB_7;
            return ;
          }
        } else {
          if (sval == T_DATA0) {

          } else {
            current->cb_Cmd = CB_7;
            return ;
          }
        }
        current->in_data_flip_flop++;
        int bytes = decoded_receive_buffer_size() - 2;
        for (int kk = 0; kk < bytes; kk++) {
          current->acc_decoded_resp[current->acc_decoded_resp_counter] = rev8(decoded_receive_buffer_get());
          current->acc_decoded_resp_counter++;
          current->asckedReceiveBytes--;
        }

        if (bytes <= 0) {

          current->acc_decoded_resp_counter = 0;
          current->asckedReceiveBytes = 0;
          current->cb_Cmd = CB_TICK;
          current->bComplete = 1;
        } else {
          current->cb_Cmd = CB_7;
          return ;
        }
      } else {
        current->acc_decoded_resp_counter = 0;
        current->asckedReceiveBytes = 0;
        current->cb_Cmd = CB_TICK;
        current->bComplete = 1;
        return ;
      }
    } else {
      current->numb_reps_errors_allowed--;
      if (current->numb_reps_errors_allowed > 0) {
        return ;
      } else {
        current->cb_Cmd = CB_TICK;
        current->bComplete = 1;
      }
    }
  } else if (current->cb_Cmd == CB_7) {
    SOF();
    pu_Addr(T_IN, current->rq.addr, current->rq.eop);
    //setup
    sendRecieveNParse();
    ACK();
    if (current->asckedReceiveBytes > 0) {
      current->cb_Cmd = CB_6;
      return ;
    }
    current->cb_Cmd = CB_8;
  } else if (current->cb_Cmd == CB_8) {
    SOF();
    pu_Addr(T_OUT, current->rq.addr, current->rq.eop);
    pu_ShortCmd(T_DATA1);
    sendOnly();
    current->cb_Cmd = CB_TICK;
    current->bComplete = 1;
  } else if (current->cb_Cmd == CB_2Ack) {
    SOF();
    pu_Addr(T_IN, current->rq.addr, current->rq.eop);
    //setup
    sendRecieveNParse();
    if (received_NRZI_buffer_bytesCnt < SMALL_NO_DATA / 2) {
      // no data , seems NAK or something like this
      current->cb_Cmd = CB_TICK;
      current->bComplete = 1;
      return ;
    }
    ACK();
    current->cb_Cmd = CB_TICK;
    current->bComplete = 1;
  } else if (current->cb_Cmd == CB_2) {
    SOF();
    pu_Addr(T_IN, current->rq.addr, current->rq.eop);
    //setup
    sendRecieveNParse();
    if (received_NRZI_buffer_bytesCnt < SMALL_NO_DATA / 2) {
      // no data , seems NAK or something like this
      current->cb_Cmd = CB_TICK;
      current->bComplete = 1;
      return ;
    }
    int res = parse_received_NRZI_buffer();
    if (res == T_NEED_ACK) {
      if (decoded_receive_buffer_size() > 2) {
        decoded_receive_buffer_get();
        decoded_receive_buffer_get();
        int bytes = decoded_receive_buffer_size() - 2;
        for (int kk = 0; kk < bytes; kk++) {
          current->acc_decoded_resp[current->acc_decoded_resp_counter] = rev8(decoded_receive_buffer_get());
          current->acc_decoded_resp_counter++;
          current->asckedReceiveBytes--;
        }
      }
      current->asckedReceiveBytes = 0;
      current->cb_Cmd = CB_2Ack;
      return ;
    } else {
      current->numb_reps_errors_allowed--;
      if (current->numb_reps_errors_allowed > 0) {
        return ;
      } else {
        current->cb_Cmd = CB_TICK;
        current->bComplete = 1;
      }
    }
    current->cb_Cmd = CB_TICK;
    current->bComplete = 1;
    current->asckedReceiveBytes = 0;
  }
}



void Request( uint8_t cmd, uint8_t addr, uint8_t eop, uint8_t dataCmd, uint8_t bmRequestType, uint8_t bmRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLen, uint16_t waitForBytes)
{
  current->rq.cmd  = cmd;
  current->rq.addr = addr;
  current->rq.eop  = eop;
  current->rq.dataCmd = dataCmd;
  current->rq.bmRequestType = bmRequestType;
  current->rq.bmRequest = bmRequest;
  current->rq.wValue = wValue;
  current->rq.wIndex = wIndex;
  current->rq.wLen = wLen;

  current->numb_reps_errors_allowed = 4;
  current->asckedReceiveBytes = waitForBytes;
  current->acc_decoded_resp_counter    = 0;
  current->cb_Cmd = CB_5;
}



void RequestSend(uint8_t cmd,   uint8_t addr, uint8_t eop,
                 uint8_t  dataCmd, uint8_t bmRequestType, uint8_t bmRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLen, uint16_t transmitL1Bytes, uint8_t* data)
{
  current->rq.cmd  = cmd;
  current->rq.addr = addr;
  current->rq.eop  = eop;
  current->rq.dataCmd = dataCmd;
  current->rq.bmRequestType = bmRequestType;
  current->rq.bmRequest = bmRequest;
  current->rq.wValue = wValue;
  current->rq.wIndex = wIndex;
  current->rq.wLen = wLen;
  current->transmitL1Bytes = transmitL1Bytes;
  for (int k = 0; k < current->transmitL1Bytes; k++) {
    current->transmitL1[k] = data[k];
  }
  current->numb_reps_errors_allowed = 4;
  current->acc_decoded_resp_counter    = 0;
  current->cb_Cmd = CB_3;
}


void RequestIn(uint8_t cmd,   uint8_t addr, uint8_t eop, uint16_t waitForBytes)
{
  current->rq.cmd  = cmd;
  current->rq.addr = addr;
  current->rq.eop  = eop;
  current->numb_reps_errors_allowed = 4;
  current->asckedReceiveBytes = waitForBytes;
  current->acc_decoded_resp_counter    = 0;
  current->cb_Cmd = CB_2;
}


void (*printDataCB)(uint8_t usbNum, uint8_t byte_depth, uint8_t* data, uint8_t data_len) = NULL;

void set_print_cb( printcb_t cb )
{
  printDataCB = cb;
};



void (*onDetectCB)(uint8_t usbNum, void *device) = NULL;

void set_ondetect_cb( ondetectcb_t cb )
{
  onDetectCB = cb;
}

void (*onLedBlinkCB)(int on_off) = NULL;

void set_onled_blink_cb( onledblinkcb_t cb )
{
  onLedBlinkCB = cb;
}


void fsm_Mashine()
{
  if (!current->bComplete) return;
  current->bComplete = 0;

  if (current->fsm_state == 0) {
    current->epCount = 0;
    current->cb_Cmd     = CB_CHECK;
    current->fsm_state   = 1;
  }
  if (current->fsm_state == 1) {
    if (current->wires_last_state == M_ONE) { // if(1)
      current->cmdTimeOut = 100 + current->selfNum * 73;
      current->cb_Cmd      = CB_WAIT0;
      current->fsm_state   = 2;
    } else {
      current->fsm_state   = 0;
      current->cb_Cmd      = CB_CHECK;
    }
  } else if (current->fsm_state == 2) {
    current->cb_Cmd       = CB_RESET;
    current->fsm_state    = 3;
  } else if (current->fsm_state == 3) {
    current->cb_Cmd       = CB_POWER;
#ifdef TEST
    current->fsm_state    =  3;
#else
    current->fsm_state    =  4;
#endif
  } else if (current->fsm_state == 4) {
    Request(T_SETUP, ZERO_USB_ADDRESS, 0b0000, T_DATA0, 0x80, 0x6, 0x0100, 0x0000, 0x0012, 0x0012);
    current->fsm_state    = 5;
  } else if (current->fsm_state == 5) {
    if (current->acc_decoded_resp_counter == 0x12) {
      memcpy(&current->desc, current->acc_decoded_resp, 0x12);
      current->ufPrintDesc |= 1;
    } else {
      if (current->numb_reps_errors_allowed <= 0) {
        current->fsm_state    =  0;
        return;
      }
    }

    Request(T_SETUP, ZERO_USB_ADDRESS, 0b0000, T_DATA0, 0x00, 0x5, 0x0000 + ASSIGNED_USB_ADDRESS, 0x0000, 0x0000, 0x0000);
    current->fsm_state    =  6;

  } else if (current->fsm_state == 6) {
    current->cmdTimeOut = 5;
    current->cb_Cmd       = CB_WAIT1;
    current->fsm_state    = 7;
  } else if (current->fsm_state == 7) {
    Request(T_SETUP, ASSIGNED_USB_ADDRESS, 0b0000, T_DATA0, 0x80, 0x6, 0x0200, 0x0000, 0x0009, 0x0009);
    current->fsm_state    = 8;
  } else if (current->fsm_state == 8) {
    if (current->acc_decoded_resp_counter == 0x9) {
      memcpy(&current->cfg, current->acc_decoded_resp, 0x9);
      current->ufPrintDesc |= 2;
      Request(T_SETUP, ASSIGNED_USB_ADDRESS, 0b0000, T_DATA0, 0x80, 0x6, 0x0200, 0x0000, current->cfg.wLength, current->cfg.wLength);
      current->fsm_state    = 9;
    } else {
      current->fsm_state    = 0;
      return;
    }
  } else if (current->fsm_state == 9) {
    if (current->acc_decoded_resp_counter == current->cfg.wLength) {
      current->ufPrintDesc |= 4;
      current->descrBufferLen = current->acc_decoded_resp_counter;
      memcpy(current->descrBuffer, current->acc_decoded_resp, current->descrBufferLen);
      current->fsm_state    = 97;
    } else {
      current->cmdTimeOut = 5;
      current->cb_Cmd       = CB_WAIT1;
      current->fsm_state    = 7;
    }
  } else if (current->fsm_state == 97) {
    Request(T_SETUP, ASSIGNED_USB_ADDRESS, 0b0000, T_DATA0, 0x00, 0x9, 0x0001, 0x0000, 0x0000, 0x0000);
    current->fsm_state    = 98;
  } else if (current->fsm_state == 98) {
    // config interfaces??
    Request(T_SETUP, ASSIGNED_USB_ADDRESS, 0b0000, T_DATA0, 0x21, 0xa, 0x0000, 0x0000, 0x0000, 0x0000);
    current->fsm_state    = 99;
  } else if (current->fsm_state == 99) {
    uint8_t cmd1 = 0;
    RequestSend(T_SETUP, ASSIGNED_USB_ADDRESS, 0b0000, T_DATA0, 0x21, 0x9, 0x0200, 0x0000, 0x0001, 0x0001, &cmd1);
    current->fsm_state    = 100;
  } else if (current->fsm_state == 100) {
    if ( onLedBlinkCB ) onLedBlinkCB(0);
    RequestIn(T_IN,  ASSIGNED_USB_ADDRESS, 1, 8);
    current->fsm_state    = 101;
  } else if (current->fsm_state == 101) {
    if (current->acc_decoded_resp_counter >= 1) {
      current->ufPrintDesc |= 8;
      current->R0Bytes = current->acc_decoded_resp_counter;
      memcpy(current->Resp0, current->acc_decoded_resp, current->R0Bytes);
      if ( onLedBlinkCB ) onLedBlinkCB(1);
    }
    if (current->epCount >= 2) {
      RequestIn(T_IN,  ASSIGNED_USB_ADDRESS, 2, 8);
      current->fsm_state    = 102;
    } else {
      current->cmdTimeOut = 3;
      current->cb_Cmd        = CB_WAIT1;
      current->fsm_state      = 104;
    }
  } else if (current->fsm_state == 102) {
    if (current->acc_decoded_resp_counter >= 1) {
      current->ufPrintDesc |= 16;
      current->R1Bytes = current->acc_decoded_resp_counter;
      memcpy(current->Resp1, current->acc_decoded_resp, current->R0Bytes);
    }
    current->cmdTimeOut = 2;
    current->cb_Cmd        = CB_WAIT1;
    current->fsm_state      = 104;
  } else if (current->fsm_state == 104) {
    current->cmdTimeOut = 4;
    current->cb_Cmd        = CB_WAIT1;
#ifdef  DEBUG_REPEAT
    static int rcnt = 0;
    rcnt++;  //
    if (  (rcnt & 0xff) == 0 ||  (current->wires_last_state != M_ONE))
#else
    if (current->wires_last_state != M_ONE)
#endif
    {
      current->fsm_state      = 0;
      return ;
    }
    current->fsm_state      = 100;
  } else {
    current->cmdTimeOut = 2;
    current->cb_Cmd        = CB_WAIT1;
    current->fsm_state      = 0;
  }
}



void setPins(int DPPin, int DMPin)
{
  DP_PIN = DPPin;
  DM_PIN = DMPin;
  int diff = DPPin - DMPin;
  if (abs(diff) > 7) {
    printf("PIN DIFFERENCE MUST BE LESS 8!\n");
    return;
  }
  int MIN_PIN = (DPPin < DMPin) ? DPPin : DMPin;

  DM_PIN_M   = (1 << DMPin);
  DP_PIN_M    = (1 << DPPin);
  RD_MASK    = (1 << DPPin) | (1 << DMPin);
  int DIFF = MIN_PIN - 8;
  if (DIFF >= 0) {
    RD_SHIFT = DIFF;
    M_ONE = 1 << (DM_PIN - MIN_PIN);
    P_ONE = 1 << (DP_PIN - MIN_PIN);
  } else {
    RD_SHIFT = -DIFF;
    M_ONE = 2;
    P_ONE = 1;
  }
}


sUsbContStruct  current_usb[NUM_USB];


int checkPins(int dp, int dm)
{
  int diff = abs(dp - dm);
  if (diff > 7 || diff == 0) {
    return 0;
  }
  if ( dp < 8 || dp > 31) return 0;
  if ( dm < 8 || dm > 31) return 0;

  return 1;
}


float testDelay6(float freq_MHz)
{
  // 6 bits must take 4.0 uSec
#define SEND_BITS  120
  float res = 1;
  transmit_NRZI_buffer_cnt = 0;

  for (int k = 0; k < SEND_BITS / 2; k++) {
    transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_K;
    transmit_NRZI_buffer[transmit_NRZI_buffer_cnt++] = USB_LS_J;
  }
  uint32_t stim = _getCycleCount32();
  sendOnly();
  stim =  _getCycleCount32() - stim;
  res = stim * 6.0 / freq_MHz / SEND_BITS;
  printf("%d bits in %f uSec %f MHz  6 ticks in %f uS\n", SEND_BITS, stim / (float)freq_MHz, SEND_BITS * freq_MHz / stim, stim * 6.0 / freq_MHz / SEND_BITS);

  return res;
}

uint8_t arr[0x200];


void initStates(int DP0, int DM0, int DP1, int DM1, int DP2, int DM2, int DP3, int DM3)
{
  decoded_receive_buffer_head = 0;
  decoded_receive_buffer_tail = 0;
  transmit_bits_buffer_store_cnt = 0;

  int calibrated = 0;

  for (int k = 0; k < NUM_USB; k++) {
    current = &current_usb[k];
    if (k == 0) {
      current->DP = DP0;
      current->DM = DM0;
    } else if (k == 1) {
      current->DP = DP1;
      current->DM = DM1;
    } else if (k == 2) {
      current->DP = DP2;
      current->DM = DM2;
    } else if (k == 3) {
      current->DP = DP3;
      current->DM = DM3;
    }
    current->isValid = 0;
    if (checkPins(current->DP, current->DM)) {
      printf("USB#%d (pins %d %d) is OK!\n", k, current->DP, current->DM );
      current->selfNum = k;
      current->in_data_flip_flop       = 0;
      current->bComplete  = 1;
      current->cmdTimeOut = 0;
      current->ufPrintDesc = 0;
      current->cb_Cmd     = CB_CHECK;
      current->fsm_state  = 0;
      current->wires_last_state = 0;
      current->counterNAck = 0;
      current->counterAck = 0;
      current->epCount = 0;
      gpio_pad_select_gpio(current->DP);
      gpio_set_direction(current->DP, GPIO_MODE_INPUT);
      gpio_pulldown_en(current->DP);

      gpio_pad_select_gpio(current->DM);
      gpio_set_direction(current->DM, GPIO_MODE_INPUT);
      gpio_pulldown_en(current->DM);
      current->isValid = 1;

      // TEST
      setPins(current->DP, current->DM);

      if (!calibrated) {
        //calibrate delay divide 2
        int  uTime = 254;
        int  dTime = 0;

        rtc_cpu_freq_config_t  out_config;

        rtc_clk_cpu_freq_get_config(&out_config);
        printf("cpu freq = %d MHz\n", out_config.freq_mhz);

        TM_OUT = out_config.freq_mhz / 2;

        // 8  - func divided clock to 8, 1.5 - MHz USB LS
        TIME_MULT = (int)(TIME_SCALE / (out_config.freq_mhz / 8 / 1.5) + 0.5);
        printf("TIME_MULT = %d \n", TIME_MULT);

        int     TRANSMIT_TIME_DELAY_OPT = 0;
        TRANSMIT_TIME_DELAY = TRANSMIT_TIME_DELAY_OPT;
        setDelay(TRANSMIT_TIME_DELAY);
        float  cS_opt = testDelay6(out_config.freq_mhz);
#define OPT_TIME (4.00f)
        for (int p = 0; p < 9; p++) {
          TRANSMIT_TIME_DELAY = (uTime + dTime) / 2;
          setDelay(TRANSMIT_TIME_DELAY);
          float cS = testDelay6(out_config.freq_mhz);
          if (fabsf(OPT_TIME - cS) < fabsf(OPT_TIME - cS_opt)) {
            cS_opt = cS;
            TRANSMIT_TIME_DELAY_OPT = TRANSMIT_TIME_DELAY;
          }
          if (cS < OPT_TIME) {
            dTime = TRANSMIT_TIME_DELAY;
          } else {
            uTime = TRANSMIT_TIME_DELAY;
          }
        }
        TRANSMIT_TIME_DELAY = TRANSMIT_TIME_DELAY_OPT;
        setDelay(TRANSMIT_TIME_DELAY);
        printf("TRANSMIT_TIME_DELAY = %d time = %f error = %f%% \n", TRANSMIT_TIME_DELAY, cS_opt, (cS_opt - OPT_TIME) / OPT_TIME * 100);
      }
    } else {
      if ( current->DP == -1 && current->DM == -1 ) {
        printf("USB#%d is disabled by user configuration\n", k);
      } else {
        printf("USB#%d (pins %d %d) has errors and will be disabled !\n", k, current->DP, current->DM );
      }
    }
  }
}



void usb_process()
{
  for (int k = 0; k < NUM_USB; k++) {
    current = &current_usb[k];
    if (current->isValid) {
      setPins(current->DP, current->DM);
      timerCallBack();
      fsm_Mashine();
    }
  }
}


void printState()
{
  static int cntl = 0;
  cntl++;
  int ref = cntl % NUM_USB;
  sUsbContStruct * pcurrent = &current_usb[ref];
  if (!pcurrent->isValid) return ;
  if ((cntl % 200) < NUM_USB) {

    //--------------------------------------------------------------------------------
    if (DEBUGEXTRA_VAR == 1)
      printf("USB%d: Ack = %d Nack = %d %02x pcurrent->cb_Cmd = %d  state = %d epCount = %d \n",
             cntl % NUM_USB, pcurrent->counterAck,
             pcurrent->counterNAck,
             pcurrent->wires_last_state,
             pcurrent->cb_Cmd,
             pcurrent->fsm_state,
             pcurrent->epCount
            );
    if (pcurrent->wires_last_state == M_ONE &&  new_device == 1) {
      printf("USB 1.1 LOW SPEED (1.5Mbit/s) DEVICE DETECTED... supported. \n\n");
      new_device = 0;
    }
    if (pcurrent->wires_last_state == P_ONE &&  new_device == 1) {
      printf("USB 1.1 FULL SPEED (12Mbit/s) DEVICE DETECTED... not suported. \n\n");
      new_device = 0;
    }

    //--------------------------------------------------------------------------------

#ifdef DEBUG_ALL
    for (int k = 0; k < 20; k++) {
      printf("%04x ", debug_buff[k]);
    }
    printf("\n");
#endif

  }

  if (pcurrent->ufPrintDesc & 1) {
    pcurrent->ufPrintDesc &= ~(uint32_t)1;
    if ( onDetectCB ) {
      onDetectCB( ref, (void*)&pcurrent->desc );
    } else {
      printf("desc.bcdDevice       = %02x\n", pcurrent->desc.bcdDevice);
      printf("desc.iManufacturer   = %02x\n", pcurrent->desc.iManufacturer);
      printf("desc.iProduct        = %02x\n", pcurrent->desc.iProduct);
      printf("desc.iSerialNumber   = %02x\n", pcurrent->desc.iSerialNumber);
      printf("desc.bNumConfigurations = %02x\n", pcurrent->desc.bNumConfigurations);
    }

  }

  if (pcurrent->ufPrintDesc & 2) {
    pcurrent->ufPrintDesc &= ~(uint32_t)2;
  }

  if (pcurrent->ufPrintDesc & 8) {
    pcurrent->ufPrintDesc &= ~(uint32_t)8;

    if ( printDataCB ) {
      printDataCB( ref, 8, pcurrent->Resp0, pcurrent->R0Bytes );
    } else {
      printf("in0 :");
      for (int k = 0; k < pcurrent->R0Bytes; k++) {
        printf("%02x ", pcurrent->Resp0[k]);
      }
      printf("\n");
    }
  }

  if (pcurrent->ufPrintDesc & 16) {
    pcurrent->ufPrintDesc &= ~(uint32_t)16;

    if ( printDataCB ) {
      printDataCB( ref, 16, pcurrent->Resp1, pcurrent->R1Bytes );
    } else {
      printf("in1 :");
      for (int k = 0; k < pcurrent->R1Bytes; k++) {
        printf("%02x ", pcurrent->Resp1[k]);
      }
      printf("\n");
    }
  }

  if (pcurrent->ufPrintDesc & 4) {
    pcurrent->ufPrintDesc &= ~(uint32_t)4;
    sCfgDesc lcfg;
    sIntfDesc sIntf;
    HIDDescriptor hid[4];
    sEPDesc epd;
    int cfgCount   = 0;
    int sIntfCount   = 0;
    int hidCount   = 0;
    int pos = 0;
#define STDCLASS        0x00
#define HIDCLASS        0x03
#define HUBCLASS     0x09      /* bDeviceClass, bInterfaceClass */
#ifdef DEBUG_ALL
    printf("clear epCount %d self = %d\n", pcurrent->epCount, pcurrent->selfNum);
#endif
    pcurrent->epCount     = 0;
    while (pos < pcurrent->descrBufferLen - 2) {
      uint8_t len  =  pcurrent->descrBuffer[pos];
      uint8_t type =  pcurrent->descrBuffer[pos + 1];
      if (len == 0) {
        pos = pcurrent->descrBufferLen;
      }
      if (pos + len <= pcurrent->descrBufferLen) {
        //printf("\n");
        if (type == 0x2) {
          sCfgDesc cfg;
          memcpy(&cfg, &pcurrent->descrBuffer[pos], len);
          printf("cfg.wLength         = %02x\n", cfg.wLength);
          printf("cfg.bNumIntf        = %02x\n", cfg.bNumIntf);
          printf("cfg.bCV             = %02x\n", cfg.bCV);
          printf("cfg.bMaxPower       = %d\n", cfg.bMaxPower);
        } else if (type == 0x4) {
          sIntfDesc sIntf;
          memcpy(&sIntf, &pcurrent->descrBuffer[pos], len);
        } else if (type == 0x21) {
          hidCount++;
          int i = hidCount - 1;
          memcpy(&hid[i], &pcurrent->descrBuffer[pos], len);
        } else if (type == 0x5) {
          pcurrent->epCount++;
          sEPDesc epd;
          memcpy(&epd, &pcurrent->descrBuffer[pos], len);
#ifdef DEBUG_ALL
          printf("pcurrent->epCount = %d\n", pcurrent->epCount);
          printf("epd.bLength       = %02x\n", epd.bLength);
          printf("epd.bType         = %02x\n", epd.bType);
          printf("epd.bEPAdd        = %02x\n", epd.bEPAdd);
          printf("epd.bAttr         = %02x\n", epd.bAttr);
          printf("epd.wPayLoad      = %02x\n", epd.wPayLoad);
          printf("epd.bInterval     = %02x\n", epd.bInterval);
#endif
        }
      }
      pos += len;
    }
  }
}


#pragma GCC diagnostic pop

Additional writing can be found in the sample file that the author of the library has attached. we summarize the principles in a nutshell as follows:

  • The USH.init() call must be specified to specify a function to respond to initializing the device plugged into the port and a function that is used to respond when a connected device fails.
  • Responsive function for plugging the device into the port. The original name is used herein my_USB_DetectCB() is called when a device is plugged into the port. In which example, when the device is not plugged in, we have set to display the results as shown in Figure 3 and when this function is called to order to change the display, the result is as shown in Figure 4.
Figure 3 Display at startup and no device found on USB port
Figure 4 An example of the result after finding a device plugged into a USB port
  • The function that responds to receiving data from the device is  my_USB_PrintCB(), where data length is checked, if the data is 8 bytes long, it’s a keyboard device, but 4 is the mouse. In the written example, a CTRL key state check was added and a Shift on the left whether it is pressed or not. If pressed, the message as shown in Figures 5 and 6 will be displayed, but if not pressed, the message will not appear as in the 4th example. In the case of pressing any other letter keys, it will show the status that the key has been pressed and released as in Figure 7.
Figure 5 When the left CTRL is pressed
Figure 6 When the left shift is pressed
Figure 7 When other button is pressed

The improved sample code is as follows.

#define U8G2_WITH_UNICODE
//#define DEBUG
//#define DEBUGEXTRA


#include <Arduino.h>
#include <U8g2lib.h>

extern "C" {
#ifdef DEBUGEXTRA
  uint8_t DEBUGEXTRA_VAR = 1;
#else
  uint8_t DEBUGEXTRA_VAR = 0;
#endif
}



#include "ESP32-USBSoftHost.hpp"
#include "usbkbd.h"                 // KeyboardReportParser

//================================================================================

#define DP_P0  18  // Data+
#define DM_P0  19  // Data-
#define DP_P1  -1  // not used
#define DM_P1  -1  // not used
#define DP_P2  -1  // not used
#define DM_P2  -1  // not used
#define DP_P3  -1  // not used
#define DM_P3  -1  // not used

usb_pins_config_t USB_Pins_Config =
{
  DP_P0, DM_P0,
  DP_P1, DM_P1,
  DP_P2, DM_P2,
  DP_P3, DM_P3
};


//********************************************************************************
uint8_t essential_key = 0;
uint8_t lastkey[6] = {0}; ///max 6 keys can be pressed
byte* keymap;
//********************************************************************************
//EMULATE JOYSTICK BY KEYBOARDS:
uint8_t KEY_UP = 0;      /// ↑
uint8_t KEY_DOWN = 0;    /// ↓
uint8_t KEY_LEFT = 0;    /// ←
uint8_t KEY_RIGHT = 0;   /// →
uint8_t KEY_CROSS = 0;   /// X
uint8_t KEY_SQUARE = 0;  /// □
uint8_t KEY_SHARE = 0;   /// START
uint8_t KEY_OPTIONS = 0; /// SELECT
uint8_t KEY_CIRCLE = 0;  /// O
uint8_t KEY_TRIANGLE = 0; /// Δ
//********************************************************************************
const char keycharmap[256][6] = {
  " ", "ESC", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "PRINT", "SCRLL", "PAUSE",
  "~", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "BACKS", "INSER", "HOME", "PUP", "NUMLC", "NUM /", "NUM *", "NUM -",
  "TAB", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "DEL", "END", "PDOWN", "NUM 7", "NUM 8", "NUM 9", "NUM +",
  "CAPS", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "ENTER", "NUM 4", "NUM 5", "NUM 6",
  "SHIFT", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "SHIFT", "UP", "NUM 1", "NUM 2", "NUM 3", "ENTER",
  "CTRL", "ALT", "SPACE", "ALT", "CTRL", "LEFT", "DOWN", "RIGHT", "NUM 0", "NUM .", "GUI", "GUI", "MENU"
};
//********************************************************************************
uint8_t mouse_button = 0;
uint8_t mouse_left_button = 0;
uint8_t mouse_right_button = 0;
uint8_t mouse_middle_button = 0;
int16_t mouse_X_POSITION = 0;
int16_t mouse_Y_POSITION = 0;
int16_t mouse_Z_POSITION = 0;
//********************************************************************************

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);


//================================================================================

bool usbActived = false;
void setup() {


  u8g2.begin();

  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_etl14thai_t );
  u8g2.drawUTF8(10, 10, "ESP32-USB-KB");
  u8g2.drawUTF8(4, 30, "> USB init");
  u8g2.sendBuffer();

  Serial.begin(115200);
  keymap = (byte*)malloc(256); ///malloc array !
  for (int idx = 0; idx < 256; idx++) {
    keymap[idx] = 0;
  }
  delay(200);
  Serial.println("USB init: ");
  delay(1000);

  USH.init( USB_Pins_Config, my_USB_DetectCB, my_USB_PrintCB);
}

void clrScr() {
  u8g2.setDrawColor(0);
  u8g2.drawBox(4, 30, 120, 20);
  u8g2.setDrawColor(1);
}

void loop() {
  clrScr();
  if (keymap[0x5c]) {
    u8g2.drawUTF8(4, 50, ">KB.L-CTRL");
  }
  if (keymap[0x4b]) {
    u8g2.drawUTF8(4, 50, ">KB.L-SHIFT");
  }
  u8g2.sendBuffer();
}



//================================================================================
static void my_USB_DetectCB( uint8_t usbNum, void * dev )
{
  sDevDesc *device = (sDevDesc*)dev;

  u8g2.setDrawColor(0);
  u8g2.drawBox(4, 10, 120, 20);
  u8g2.setDrawColor(1);
  u8g2.drawUTF8(4, 30, "> USB Ready");
  u8g2.sendBuffer();


#ifdef DEBUG
  printf("New device detected on USB#%d\n", usbNum);
  printf("desc.bcdUSB             = 0x%04x\n", device->bcdUSB);
  printf("desc.bDeviceClass       = 0x%02x\n", device->bDeviceClass);
  printf("desc.bDeviceSubClass    = 0x%02x\n", device->bDeviceSubClass);
  printf("desc.bDeviceProtocol    = 0x%02x\n", device->bDeviceProtocol);
  printf("desc.bMaxPacketSize0    = 0x%02x\n", device->bMaxPacketSize0);
  printf("desc.idVendor           = 0x%04x\n", device->idVendor);
  printf("desc.idProduct          = 0x%04x\n", device->idProduct);
  printf("desc.bcdDevice          = 0x%04x\n", device->bcdDevice);
  printf("desc.iManufacturer      = 0x%02x\n", device->iManufacturer);
  printf("desc.iProduct           = 0x%02x\n", device->iProduct);
  printf("desc.iSerialNumber      = 0x%02x\n", device->iSerialNumber);
  printf("desc.bNumConfigurations = 0x%02x\n", device->bNumConfigurations);
  // if( device->iProduct == mySupportedIdProduct && device->iManufacturer == mySupportedManufacturer ) {
  //   myListenUSBPort = usbNum;
  // }
#endif
}

char msg[32];

static void my_USB_PrintCB(uint8_t usbNum, uint8_t byte_depth, uint8_t* data, uint8_t data_len)
{
  //--------------------------------------------------------------------------------
  if (data_len == 8) { //it is keyboard
    //--------------------------------------------------------------------------------
    if ((data[0] & 1) == 1 && (essential_key & 1) != 1) {
      essential_key = data[0];
      keymap[0x5c] = 1; // LEFT CTRL

    } else if ((essential_key & 1) == 1 && (data[0] & 1) != 1) {
      essential_key = data[0];
      keymap[0x5c] = 0; // LEFT CTRL
    }
    if ((data[0] & 2) == 2 && (essential_key & 2) != 2) {
      essential_key = data[0];
      keymap[0x4b] = 1; // LEFT SHIFT
    } else if ((essential_key & 2) == 2 && (data[0] & 2) != 2) {
      essential_key = data[0];
      keymap[0x4b] = 0; // LEFT SHIFT
    }
    if ((data[0] & 4) == 4 && (essential_key & 4) != 4) {
      essential_key = data[0];
      keymap[0x5d] = 1; // LEFT ALT
    } else if ((essential_key & 4) == 4 && (data[0] & 4) != 4) {
      essential_key = data[0];
      keymap[0x5d] = 0; // LEFT ALT
    }
    if ((data[0] & 8) == 8 && (essential_key & 8) != 8) {
      essential_key = data[0];
      keymap[0x66] = 1; // LEFT GUI
    } else if ((essential_key & 8) == 8 && (data[0] & 8) != 8) {
      essential_key = data[0];
      keymap[0x66] = 0; // LEFT GUI
    }
    if ((data[0] & 0x10) == 0x10 && (essential_key & 0x10) != 0x10) {
      essential_key = data[0];
      keymap[0x60] = 1; // RIGHT CTRL
    } else if ((essential_key & 0x10) == 0x10 && (data[0] & 0x10) != 0x10) {
      essential_key = data[0];
      keymap[0x60] = 0; // RIGHT CTRL
    }
    if ((data[0] & 0x20) == 0x20 && (essential_key & 0x20) != 0x20) {
      essential_key = data[0];
      keymap[0x56] = 1; // RIGHT SHIFT
    } else if ((essential_key & 0x20) == 0x20 && (data[0] & 0x20) != 0x20) {
      essential_key = data[0];
      keymap[0x56] = 0; // RIGHT SHIFT
    }
    if ((data[0] & 0x40) == 0x40 && (essential_key & 0x40) != 0x40) {
      essential_key = data[0];
      keymap[0x5f] = 1; // RIGHT ALT
    } else if ((essential_key & 0x40) == 0x40 && (data[0] & 0x40) != 0x40) {
      essential_key = data[0];
      keymap[0x5f] = 0; // RIGHT ALT
    }
    if ((data[0] & 0x80) == 0x80 && (essential_key & 0x80) != 0x80) {
      essential_key = data[0];
      keymap[0x67] = 1; // RIGHT GUI
    } else if ((essential_key & 0x80) == 0x80 && (data[0] & 0x80) != 0x80) {
      essential_key = data[0];
      keymap[0x67] = 0; // RIGHT GUI

    }
    //--------------------------------------------------------------------------------
    for (int8_t tmp = 0; tmp < sizeof(lastkey); tmp++) {

      if (data[tmp + 2] != 1) {
        if (lastkey[tmp] != data[tmp + 2] && lastkey[tmp] == 0) {
          //pressed key
          lastkey[tmp] = data[tmp + 2];
          keypress(lastkey[tmp]); // <----PRESSED KEY
          printf("pressed --> %s\n", keycharmap[keypress(lastkey[tmp])]);
        } else if (lastkey[tmp] != data[tmp + 2] && data[tmp + 2] != 0) {
          if (lastkey[tmp + 1] == data[tmp + 2]) {
            keyrelease(lastkey[tmp]); // RELEASED KEY
            printf("released --> %s\n", keycharmap[keypress(lastkey[tmp])]);
            for (int8_t i = tmp; i < sizeof(lastkey) - 1; i++) lastkey[i] = lastkey[i + 1];
          }
        } else if (data[tmp + 2] == 0 && lastkey[tmp] != 0) {
          //released key
          keyrelease(lastkey[tmp]); // RELEASED KEY
          printf("released --> %s\n", keycharmap[keypress(lastkey[tmp])]);
          lastkey[tmp] = 0;
        }
      } else {

        for (uint16_t tmp = 0; tmp < 256; tmp++) keymap[tmp] = 0; // RELEASE ALL KEYS!
      }
    }
    //--------------------------------------------------------------------------------
  } else if (data_len == 4) { //it is mouse
    if ((data[0] & 1) == 1 && (mouse_button & 1) != 1) {
      mouse_button = data[0];
      mouse_left_button = 1;
#ifdef DEBUG
      printf("LEFT MOUSE BUTTON PRESSED\n");
#endif
    } else if ((mouse_button & 1) == 0 && (data[0] & 1) != 0) {
      mouse_button = data[0];
      mouse_left_button = 0;
#ifdef DEBUG
      printf("LEFT MOUSE BUTTON RELEASED\n");
#endif
    }
    if ((data[0] & 2) == 2 && (mouse_button & 2) != 2) {
      mouse_button = data[0];
      mouse_right_button = 1;
#ifdef DEBUG
      printf("RIGHT MOUSE BUTTON PRESSED\n");
#endif
    } else if ((mouse_button & 2) == 0 && (data[0] & 2) != 0) {
      mouse_button = data[0];
      mouse_right_button = 0;
#ifdef DEBUG
      printf("RIGHT MOUSE BUTTON RELEASED\n");
#endif
    }
    if ((data[0] & 4) == 4 && (mouse_button & 4) != 4) {
      mouse_button = data[0];
      mouse_middle_button = 1;
#ifdef DEBUG
      printf("MIDDLE MOUSE BUTTON PRESSED\n");
#endif
    } else if ((mouse_button & 4) == 0 && (data[0] & 4) != 0) {
      mouse_button = data[0];
      mouse_middle_button = 0;
#ifdef DEBUG
      printf("MIDDLE MOUSE BUTTON RELEASED\n");
#endif
    }
    //--------------------------------------------------------------------------------
    if (data[1] != 0) { //X POSITION
      if ((uint8_t)data[1] > 0 && (uint8_t)data[1] < 128 ) { // +X
        mouse_X_POSITION += (uint8_t)data[1];
#ifdef DEBUG
        printf("MOUSE X POSITION: %d [+%d]\n", mouse_X_POSITION, data[1]);
#endif
      } else if ((uint8_t)data[1] > 127 && (uint8_t)data[1] < 256 ) { // -X
        mouse_X_POSITION -= (256 - (uint8_t)data[1]);
#ifdef DEBUG
        printf("MOUSE X POSITION: %d [-%d]\n", mouse_X_POSITION, (256 - data[1]));
#endif
      }
    }
    //--------------------------------------------------------------------------------
    if (data[2] != 0) { //Y POSITION
      if ((uint8_t)data[2] > 0 && (uint8_t)data[2] < 128 ) { // +Y
        mouse_Y_POSITION += (uint8_t)data[2];
#ifdef DEBUG
        printf("MOUSE Y POSITION: %d [+%d]\n", mouse_Y_POSITION, data[2]);
#endif
      } else if ((uint8_t)data[2] > 127 && (uint8_t)data[2] < 256 ) { // -Y
        mouse_Y_POSITION -= (256 - (uint8_t)data[2]);
#ifdef DEBUG
        printf("MOUSE Y POSITION: %d [-%d]\n", mouse_Y_POSITION, (256 - data[2]));
#endif
      }
    }
    //--------------------------------------------------------------------------------
    if (data[3] != 0) { //Z POSITION
      if ((uint8_t)data[3] > 0 && (uint8_t)data[3] < 128 ) { // +Z
        mouse_Z_POSITION += (uint8_t)data[3];
#ifdef DEBUG
        printf("MOUSE Z POSITION: %d [+%d]\n", mouse_Z_POSITION, data[3]);
#endif
      } else if ((uint8_t)data[3] > 127 && (uint8_t)data[3] < 256 ) { // -Z
        mouse_Z_POSITION -= (256 - (uint8_t)data[3]);
#ifdef DEBUG
        printf("MOUSE Z POSITION: %d [-%d]\n", mouse_Z_POSITION, (256 - data[3]));
#endif
      }
      //--------------------------------------------------------------------------------
    }
    //--------------------------------------------------------------------------------
  } else { //I do not know what is it, this device?

  }
  //--------------------------------------------------------------------------------
#ifdef DEBUG
  printf("\n");
#endif
}

//********************************************************************************
uint8_t keypress(uint8_t scancode) {
  switch (scancode) {
    case 0x29: // ESC
      keymap[1] = 1;
      return (1);
      break;
    case 0x3a: // F1
      keymap[2] = 1;
      return (2);
      break;
    case 0x3b: // F2
      keymap[3] = 1;
      return (3);
      break;
    case 0x3c: // F3
      keymap[4] = 1;
      return (4);
      break;
    case 0x3d: // F4
      keymap[5] = 1;
      return (5);
      break;
    case 0x3e: // F5
      keymap[6] = 1;
      return (6);
      break;
    case 0x3f: // F6
      keymap[7] = 1;
      return (7);
      break;
    case 0x40: // F7
      keymap[8] = 1;
      return (8);
      break;
    case 0x41: // F8
      keymap[9] = 1;
      return (9);
      break;
    case 0x42: // F9
      keymap[0x0a] = 1;
      return (0x0a);
      break;
    case 0x43: // F10
      keymap[0x0b] = 1;
      return (0x0b);
      break;
    case 0x44: // F11
      keymap[0x0c] = 1;
      return (0x0c);
      break;
    case 0x45: // F12
      keymap[0x0d] = 1;
      return (0x0d);
      break;
    case 0x46: // PrintScreen
      keymap[0x0e] = 1;
      return (0x0e);
      break;
    case 0x47: // ScrollLock
      keymap[0x0f] = 1;
      return (0x0f);
      break;
    case 0x48: // Pause/Break
      keymap[0x10] = 1;
      return (0x10);
      break;
    case 0x35: // ~
      keymap[0x11] = 1;
      return (0x11);
      break;
    case 0x1e: // 1
      keymap[0x12] = 1;
      return (0x12);
      break;
    case 0x1f: // 2
      keymap[0x13] = 1;
      return (0x13);
      break;
    case 0x20: // 3
      keymap[0x14] = 1;
      return (0x14);
      break;
    case 0x21: // 4
      keymap[0x15] = 1;
      return (0x15);
      break;
    case 0x22: // 5
      keymap[0x16] = 1;
      return (0x16);
      break;
    case 0x23: // 6
      keymap[0x17] = 1;
      return (0x17);
      break;
    case 0x24: // 7
      keymap[0x18] = 1;
      return (0x18);
      break;
    case 0x25: // 8
      keymap[0x19] = 1;
      return (0x19);
      break;
    case 0x26: // 9
      keymap[0x1a] = 1;
      return (0x1a);
      break;
    case 0x27: // 0
      keymap[0x1b] = 1;
      return (0x1b);
      break;
    case 0x2d: // -
      keymap[0x1c] = 1;
      return (0x1c);
      break;
    case 0x2e: // =
      keymap[0x1d] = 1;
      return (0x1d);
      break;
    case 0x2a: // BACKSPACE
      keymap[0x1e] = 1;
      return (0x1e);
      break;
    case 0x2b: // TAB
      keymap[0x26] = 1;
      return (0x26);
      break;
    case 0x14: // Q
      keymap[0x27] = 1;
      return (0x27);
      break;
    case 0x1a: // W
      keymap[0x28] = 1;
      return (0x28);
      break;
    case 0x08: // E
      keymap[0x29] = 1;
      return (0x29);
      break;
    case 0x15: // R
      keymap[0x2a] = 1;
      return (0x2a);
      break;
    case 0x17: // T
      keymap[0x2b] = 1;
      return (0x2b);
      break;
    case 0x1c: // Y
      keymap[0x2c] = 1;
      return (0x2c);
      break;
    case 0x18: // U
      keymap[0x2d] = 1;
      return (0x2d);
      break;
    case 0x0c: // I
      keymap[0x2e] = 1;
      return (0x2e);
      break;
    case 0x12: // O
      keymap[0x2f] = 1;
      return (0x2f);
      break;
    case 0x13: // P
      keymap[0x30] = 1;
      return (0x30);
      break;
    case 0x2f: // {
      keymap[0x31] = 1;
      return (0x31);
      break;
    case 0x30: // }
      keymap[0x32] = 1;
      return (0x32);
      break;
    case 0x32: // \\
      keymap[0x33] = 1;
      return (0x33);
      break;
    case 0x39: // CAPSLOCK
      keymap[0x3b] = 1;
      return (0x3b);
      break;
    case 0x04: // A
      keymap[0x3c] = 1;
      return (0x3c);
      break;
    case 0x16: // S
      keymap[0x3d] = 1;
      return (0x3d);
      break;
    case 0x07: // D
      keymap[0x3e] = 1;
      return (0x3e);
      break;
    case 0x09: // F
      keymap[0x3f] = 1;
      return (0x3f);
      break;
    case 0x0a: // G
      keymap[0x40] = 1;
      return (0x40);
      break;
    case 0x0b: // H
      keymap[0x41] = 1;
      return (0x41);
      break;
    case 0x0d: // J
      keymap[0x42] = 1;
      return (0x42);
      break;
    case 0x0e: // K
      keymap[0x43] = 1;
      return (0x43);
      break;
    case 0x0f: // L
      keymap[0x44] = 1;
      return (0x44);
      break;
    case 0x33: // ;
      keymap[0x45] = 1;
      return (0x45);
      break;
    case 0x34: // '
      keymap[0x46] = 1;
      return (0x46);
      break;
    case 0x28: // ENTER
      keymap[0x47] = 1;
      return (0x47);
      break;
    case 0x1d: // Z
      keymap[0x4c] = 1;
      return (0x4c);
      break;
    case 0x1b: // X
      keymap[0x4d] = 1;
      return (0x4d);
      break;
    case 0x06: // C
      keymap[0x4e] = 1;
      return (0x4e);
      break;
    case 0x19: // V
      keymap[0x4f] = 1;
      return (0x4f);
      break;
    case 0x05: // B
      keymap[0x50] = 1;
      return (0x50);
      break;
    case 0x11: // N
      keymap[0x51] = 1;
      return (0x51);
      break;
    case 0x10: // M
      keymap[0x52] = 1;
      return (0x52);
      break;
    case 0x36: // ,
      keymap[0x53] = 1;
      return (0x53);
      break;
    case 0x37: // .
      keymap[0x54] = 1;
      return (0x54);
      break;
    case 0x38: // /
      keymap[0x55] = 1;
      return (0x55);
      break;
    case 0x2c: // SPACEBAR
      keymap[0x5e] = 1;
      return (0x5e);
      break;
    case 0x65: // CONTEXT BUTTON
      keymap[0x68] = 1;
      return (0x68);
      break;
    case 0x49: // INSERT
      keymap[0x1f] = 1;
      return (0x1f);
      break;
    case 0x4a: // HOME
      keymap[0x20] = 1;
      return (0x20);
      break;
    case 0x4b: // PAGEUP
      keymap[0x21] = 1;
      return (0x21);
      break;
    case 0x4c: // DELETE
      keymap[0x34] = 1;
      return (0x34);
      break;
    case 0x4d: // END
      keymap[0x35] = 1;
      return (0x35);
      break;
    case 0x4e: // PAGEDOWN
      keymap[0x36] = 1;
      return (0x36);
      break;
    case 0x52: // UP
      keymap[0x57] = 1;
      return (0x57);
      break;
    case 0x50: // LEFT
      keymap[0x61] = 1;
      return (0x61);
      break;
    case 0x51: // DOWN
      keymap[0x62] = 1;
      return (0x62);
      break;
    case 0x4f: // RIGHT
      keymap[0x63] = 1;
      return (0x63);
      break;
    case 0x53: // NUMLOCK
      keymap[0x22] = 1;
      return (0x22);
      break;
    case 0x54: // NUM /
      keymap[0x23] = 1;
      return (0x23);
      break;
    case 0x55: // NUM *
      keymap[0x24] = 1;
      return (0x24);
      break;
    case 0x56: // NUM -
      keymap[0x25] = 1;
      return (0x25);
      break;
    case 0x57: // NUM +
      keymap[0x3a] = 1;
      return (0x3a);
      break;
    case 0x58: // NUM ENTER
      keymap[0x5b] = 1;
      return (0x5b);
      break;
    case 0x63: // NUM .
      keymap[0x65] = 1;
      return (0x65);
      break;
    case 0x62: // NUM 0
      keymap[0x64] = 1;
      return (0x64);
      break;
    case 0x59: // NUM 1
      keymap[0x58] = 1;
      return (0x58);
      break;
    case 0x5a: // NUM 2
      keymap[0x59] = 1;
      return (0x59);
      break;
    case 0x5b: // NUM 3
      keymap[0x5a] = 1;
      return (0x5a);
      break;
    case 0x5c: // NUM 4
      keymap[0x48] = 1;
      return (0x48);
      break;
    case 0x5d: // NUM 5
      keymap[0x49] = 1;
      return (0x49);
      break;
    case 0x5e: // NUM 6
      keymap[0x4a] = 1;
      return (0x4a);
      break;
    case 0x5f: // NUM 7
      keymap[0x37] = 1;
      return (0x37);
      break;
    case 0x60: // NUM 8
      keymap[0x38] = 1;
      return (0x38);
      break;
    case 0x61: // NUM 9
      keymap[0x39] = 1;
      return (0x39);
      break;
    default:
      return (0);
      break;
  }
}
//********************************************************************************
uint8_t keyrelease(uint8_t scancode) {
  switch (scancode) {
    case 0x29: // ESC
      keymap[1] = 0;
      return (1);
      break;
    case 0x3a: // F1
      keymap[2] = 0;
      return (2);
      break;
    case 0x3b: // F2
      keymap[3] = 0;
      return (3);
      break;
    case 0x3c: // F3
      keymap[4] = 0;
      return (4);
      break;
    case 0x3d: // F4
      keymap[5] = 0;
      return (5);
      break;
    case 0x3e: // F5
      keymap[6] = 0;
      return (6);
      break;
    case 0x3f: // F6
      keymap[7] = 0;
      return (7);
      break;
    case 0x40: // F7
      keymap[8] = 0;
      return (8);
      break;
    case 0x41: // F8
      keymap[9] = 0;
      return (9);
      break;
    case 0x42: // F9
      keymap[0x0a] = 0;
      return (0x0a);
      break;
    case 0x43: // F10
      keymap[0x0b] = 0;
      return (0x0b);
      break;
    case 0x44: // F11
      keymap[0x0c] = 0;
      return (0x0c);
      break;
    case 0x45: // F12
      keymap[0x0d] = 0;
      return (0x0d);
      break;
    case 0x46: // PrintScreen
      keymap[0x0e] = 0;
      return (0x0e);
      break;
    case 0x47: // ScrollLock
      keymap[0x0f] = 0;
      return (0x0f);
      break;
    case 0x48: // Pause/Break
      keymap[0x10] = 0;
      return (0x10);
      break;
    case 0x35: // ~
      keymap[0x11] = 0;
      return (0x11);
      break;
    case 0x1e: // 1
      keymap[0x12] = 0;
      return (0x12);
      break;
    case 0x1f: // 2
      keymap[0x13] = 0;
      return (0x13);
      break;
    case 0x20: // 3
      keymap[0x14] = 0;
      return (0x14);
      break;
    case 0x21: // 4
      keymap[0x15] = 0;
      return (0x15);
      break;
    case 0x22: // 5
      keymap[0x16] = 0;
      return (0x16);
      break;
    case 0x23: // 6
      keymap[0x17] = 0;
      return (0x17);
      break;
    case 0x24: // 7
      keymap[0x18] = 0;
      return (0x18);
      break;
    case 0x25: // 8
      keymap[0x19] = 0;
      return (0x19);
      break;
    case 0x26: // 9
      keymap[0x1a] = 0;
      return (0x1a);
      break;
    case 0x27: // 0
      keymap[0x1b] = 0;
      return (0x1b);
      break;
    case 0x2d: // -
      keymap[0x1c] = 0;
      return (0x1c);
      break;
    case 0x2e: // =
      keymap[0x1d] = 0;
      return (0x1d);
      break;
    case 0x2a: // BACKSPACE
      keymap[0x1e] = 0;
      return (0x1e);
      break;
    case 0x2b: // TAB
      keymap[0x26] = 0;
      return (0x26);
      break;
    case 0x14: // Q
      keymap[0x27] = 0;
      return (0x27);
      break;
    case 0x1a: // W
      keymap[0x28] = 0;
      return (0x28);
      break;
    case 0x08: // E
      keymap[0x29] = 0;
      return (0x29);
      break;
    case 0x15: // R
      keymap[0x2a] = 0;
      return (0x2a);
      break;
    case 0x17: // T
      keymap[0x2b] = 0;
      return (0x2b);
      break;
    case 0x1c: // Y
      keymap[0x2c] = 0;
      return (0x2c);
      break;
    case 0x18: // U
      keymap[0x2d] = 0;
      return (0x2d);
      break;
    case 0x0c: // I
      keymap[0x2e] = 0;
      return (0x2e);
      break;
    case 0x12: // O
      keymap[0x2f] = 0;
      return (0x2f);
      break;
    case 0x13: // P
      keymap[0x30] = 0;
      return (0x30);
      break;
    case 0x2f: // {
      keymap[0x31] = 0;
      return (0x31);
      break;
    case 0x30: // }
      keymap[0x32] = 0;
      return (0x32);
      break;
    case 0x32: // \\
      keymap[0x33] = 0;
      return (0x33);
      break;
    case 0x39: // CAPSLOCK
      keymap[0x3b] = 0;
      return (0x3b);
      break;
    case 0x04: // A
      keymap[0x3c] = 0;
      return (0x3c);
      break;
    case 0x16: // S
      keymap[0x3d] = 0;
      return (0x3d);
      break;
    case 0x07: // D
      keymap[0x3e] = 0;
      return (0x3e);
      break;
    case 0x09: // F
      keymap[0x3f] = 0;
      return (0x3f);
      break;
    case 0x0a: // G
      keymap[0x40] = 0;
      return (0x40);
      break;
    case 0x0b: // H
      keymap[0x41] = 0;
      return (0x41);
      break;
    case 0x0d: // J
      keymap[0x42] = 0;
      return (0x42);
      break;
    case 0x0e: // K
      keymap[0x43] = 0;
      return (0x43);
      break;
    case 0x0f: // L
      keymap[0x44] = 0;
      return (0x44);
      break;
    case 0x33: // ;
      keymap[0x45] = 0;
      return (0x45);
      break;
    case 0x34: // '
      keymap[0x46] = 0;
      return (0x46);
      break;
    case 0x28: // ENTER
      keymap[0x47] = 0;
      return (0x47);
      break;
    case 0x1d: // Z
      keymap[0x4c] = 0;
      return (0x4c);
      break;
    case 0x1b: // X
      keymap[0x4d] = 0;
      return (0x4d);
      break;
    case 0x06: // C
      keymap[0x4e] = 0;
      return (0x4e);
      break;
    case 0x19: // V
      keymap[0x4f] = 0;
      return (0x4f);
      break;
    case 0x05: // B
      keymap[0x50] = 0;
      return (0x50);
      break;
    case 0x11: // N
      keymap[0x51] = 0;
      return (0x51);
      break;
    case 0x10: // M
      keymap[0x52] = 0;
      return (0x52);
      break;
    case 0x36: // ,
      keymap[0x53] = 0;
      return (0x53);
      break;
    case 0x37: // .
      keymap[0x54] = 0;
      return (0x54);
      break;
    case 0x38: // /
      keymap[0x55] = 0;
      return (0x55);
      break;
    case 0x2c: // SPACEBAR
      keymap[0x5e] = 0;
      return (0x5e);
      break;
    case 0x65: // CONTEXT BUTTON
      keymap[0x68] = 0;
      return (0x68);
      break;
    case 0x49: // INSERT
      keymap[0x1f] = 0;
      return (0x1f);
      break;
    case 0x4a: // HOME
      keymap[0x20] = 0;
      return (0x20);
      break;
    case 0x4b: // PAGEUP
      keymap[0x21] = 0;
      return (0x21);
      break;
    case 0x4c: // DELETE
      keymap[0x34] = 0;
      return (0x34);
      break;
    case 0x4d: // END
      keymap[0x35] = 0;
      return (0x35);
      break;
    case 0x4e: // PAGEDOWN
      keymap[0x36] = 0;
      return (0x36);
      break;
    case 0x52: // UP
      keymap[0x57] = 0;
      return (0x57);
      break;
    case 0x50: // LEFT
      keymap[0x61] = 0;
      return (0x61);
      break;
    case 0x51: // DOWN
      keymap[0x62] = 0;
      return (0x62);
      break;
    case 0x4f: // RIGHT
      keymap[0x63] = 0;
      return (0x63);
      break;
    case 0x53: // NUMLOCK
      keymap[0x22] = 0;
      return (0x22);
      break;
    case 0x54: // NUM /
      keymap[0x23] = 0;
      return (0x23);
      break;
    case 0x55: // NUM *
      keymap[0x24] = 0;
      return (0x24);
      break;
    case 0x56: // NUM -
      keymap[0x25] = 0;
      return (0x25);
      break;
    case 0x57: // NUM +
      keymap[0x3a] = 0;
      return (0x3a);
      break;
    case 0x58: // NUM ENTER
      keymap[0x5b] = 0;
      return (0x5b);
      break;
    case 0x63: // NUM .
      keymap[0x65] = 0;
      return (0x65);
      break;
    case 0x62: // NUM 0
      keymap[0x64] = 0;
      return (0x64);
      break;
    case 0x59: // NUM 1
      keymap[0x58] = 0;
      return (0x58);
      break;
    case 0x5a: // NUM 2
      keymap[0x59] = 0;
      return (0x59);
      break;
    case 0x5b: // NUM 3
      keymap[0x5a] = 0;
      return (0x5a);
      break;
    case 0x5c: // NUM 4
      keymap[0x48] = 0;
      return (0x48);
      break;
    case 0x5d: // NUM 5
      keymap[0x49] = 0;
      return (0x49);
      break;
    case 0x5e: // NUM 6
      keymap[0x4a] = 0;
      return (0x4a);
      break;
    case 0x5f: // NUM 7
      keymap[0x37] = 0;
      return (0x37);
      break;
    case 0x60: // NUM 8
      keymap[0x38] = 0;
      return (0x38);
      break;
    case 0x61: // NUM 9
      keymap[0x39] = 0;
      return (0x39);
      break;
    default:
      return (0);
      break;
  }
}

Conclusion

From this article, you will find that by adopting a library, there is a significant reduction in coding. But some modifications have to be made for it to compile through and one must understand the working principle of the library to be able to use it to meet the needs of others and coding skills to understand it is essential. It takes patience and persistence to develop this skill … Have fun with programming.

(C) 2020-2022, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2022-01-28