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.
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
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
- ESP32USBHOST.ino Examples provided by the developer
- ESP32-USBSoftHost.hpp
- usb_host.c
- usb_host.h
- usbkbd.h
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(¤t->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(¤t->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 = ¤t_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 = ¤t_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 = ¤t_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.
- 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.
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