บทความนี้เป็นตัวอย่างการนำ ESP32 Soft Host ของ nathalis มาทดลองใช้งานและทดลองแสดงผลที่จอแสดงผล OLED ที่มีความละเอียด 128×64 จุด ดังภาพที่ 1 เพื่อรับข้อมูลจากแป้นพิมพ์ หรือเมาส์ ทำให้ใช้ GPIO เพียงไม่กี่ขาแต่สามารถรับข้อมูลจากแป้นพิมพ์ที่มีจำนวนปุ่มที่เยอะได้ ซึ่งโดยปกติแล้วตัวไมโครคอนโทรลเลอร์ ESP32 ไม่รองรับการทำเชื่อมต่อกับ USB โดยตรงจึงต้องอาศัยการเขียนโปรแกรมด้วยการใช้ตัวตั้งเวลาหรือ Timer มาตรวจสอบสถานะของสายสัญญาณขา D- และ D+ เพื่อนำมาประกอบกันเป็นข้อมูลในระดับไบต์และนำมาประกอบกันเป็นแพ็คของข้อมูลเพื่อทำการตีความต่อไป
การเชื่อมต่อ
ส่วนของการเชื่อมต่อระหว่าง USB Port กับ ESP32 เป็นดังภาพที่ 2 คือ
- GPIO18 ต่อเข้ากับ D+
- GPIO19 ต่อเข้ากับ D-
- GND ต่อเข้ากับ GND ของพอร์ต USB
- 5V ต่อเข้ากับ Vcc ของพอร์ต SB
รายการไลบรารี
ไลบรารีที่ nathalis สร้างมานั้นรองรับพอร์ต USB ได้ 4 พอร์ต โดยกำหนดในโค้ดดังเช่นต่อไปนี้ และถ้าไม่ใช้ให้ใส่เป็น -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
};
ส่วนของไฟล์ที่มากับ ESP32-USB-SOFTHOST1.1-LOWSPEED-KEYBOARD-AND-MOUSE ได้แก่
- ESP32USBHOST.ino ตัวอย่างที่ผู้พัฒนาเตรียมการไว้ให้
- ESP32-USBSoftHost.hpp
- usb_host.c
- usb_host.h
- usbkbd.h
สิ่งที่พวกเราปรับแก้คือ ในโค้ดที่กำหนดไว้เป็น inline และทำให้คอมไพล์ไม่ผ่าน จึงเปลี่ยนโค้ดของ usb_host.c ดังนี้
#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
ส่วนที่เขียนเพิ่มสามารถศึกษาได้จากไฟล์ตัวอย่างที่ผู้เขียนไลบรารีได้แนบมาด้วย ซึ่งทีมเราสรุปหลักการคร่าว ๆ ได้ดังนี้
- ต้องเรียก USH.init() เพื่อระบุฟังก์ชันสำหรับตอบสนองต่อการเริ่มต้นทำงานตรวจสอบอุปกรณ์ที่เสียบเข้ากับพอร์ต และฟังก์ชันที่ใช้ในการตอบสนองเมื่อเกิดเหตุการณ์อับอุปกรณ์ที่เชื่อมต่อ
- ฟังก์ชันที่ตอบสนองต่อการเสียบอุปกรณ์เข้ากับพอร์ต ในที่นี้ใช้ชื่อตามต้นฉบับคือ my_USB_DetectCB() จะถูกเรียกเมื่อมีการเสียบอุปกรณ์เข้ากับพอร์ต ซึ่งตัวอย่างเมื่อยังไม่ได้เสียบอุปรกรณ์ทางทีมงานเราได้กำหนดให้แสดงผลดังภาพที่ 3 และเมื่อฟังก์ชันนี้ถูกเรียกใช้ได้สั่งให้เปลี่ยนการแสดงผลจึงได้ผลลัพธ์ดังภาพที่ 4
- ฟังก์ชันตอบสนองการรับข้อมูลจากอุปกรณ์ ในที่นี้ใช้ชื่อฟังก์ชันเป็น my_USB_PrintCB() ตามต้นฉบับ โดยในฟังก์ชันนี้มีการตรวจสอบความยาวของข้อมูลโดยถ้าข้อมูลยาว 8 ไบต์ นั่นเป็นอุปกรณ์แป้นพิมพ์ แต่ถ้ายาว 4 เป็นของเมาส์ ในตัวอย่างที่เขียขึ้นได้เพิ่มการตรวจสอบสถานะของแป้น CTRL และ Shift ด้านซ้ายว่าถูกกดอยู่หรือไม่ ถ้ากดจะแสดงข้อความดังภาพที่ 5 และ 6 แต่ถ้าไม่ได้กดจะไม่ปรากฏข้อความดังในตัวอย่างที่ 4 ส่วนกรณีที่กดแป้นอื่น ๆ ที่เป็นตัวอักษรจะให้แสดงสถานะว่าแป้นนั้นถูกกดและถูกปล่อยดังภาพที่ 7
โค้ดตัวอย่างที่ปรับปรุงแล้วเป็นดังนี้
#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;
}
}
สรุป
จากบทความนี้จะพบว่า การนำไลบรารีมาใช้ทำให้ลดการเขียนโค้ดไปได้เยอะ แต่ต้องมีการแก้ไขบางส่วนเพื่อให้คอมไพล์ผ่าน และต้อทำความเข้าใจกับหลักการทำงานของไลบรารีเพื่อให้สามารถนำมาใช้งานได้ตรงกับความต้องการของผู้นำมาใช้ต่อ ดังนั้น การเข้าใจหลักภาษา และทักษะในการไล่โค้ดเพื่อทำความเข้าใจจึงเป็นสิ่งที่สำคัญ ซึ่งต้องใช้ความอดทนและมานะในการพัฒนาทักษะนี้ … ขอให้สนุกกับการเขียนโปรแกรมครับ
(C) 2020-2022, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-11-24, 2022-01-26