' =========== HID INJECTOR FOR PICOMITE - QUICK HELP V 0.0.1 ==============

' Pico RP2040 USB HID injector. Turns SERIAL/I2C/IR input into USB
' keyboard, mouse, consumer, absolute mouse, system control and MIDI.
' In addition control/monitoring of GPIOs, WS2812 LEDs and audio
' is possible.
'
' ---------------------------- INPUT CHANNELS -----------------------------

' I2C  : slave 0x20, GP4=SDA GP5=SCL, 400kHz. Raw [CMD][DATA] (no frame).
' UART : GP0=TX GP1=RX, 8N1, default 9600 baud(adaptable). Framed protocol.
' CDC  : USB virtual COM port. Same framed protocol as UART. Always on.
' IR   : GP18 receiver. Sony SIRC 12-bit (5-bit device, 7-bit key).

' ---------------------------- INPUTS/OUTPUTS -----------------------------

' Audio: GP22 output for a passive piezo buzzer.
' GPIOs: GP2 6 7 8 9 10 11 12 13 14 15 17 20 21 26 27 28 programmable I/Os.
' Reset: GP3 factory reset if connected to ground during startup.
' Test:  GP19 output of system data to USB/audio if connected to GND.
' WS2812: Output via GP16. Control of 256 LEDs and/or status display.
'
'
'                         +.......USB.......+
'       GP0 TX            |1              40|     VBUS
'       GP1 RX            |2              39|     VSYS
'       GND               |3              38|     GND
'       GP2 (free)        |4              37|     3V3_EN
'       GP3 Factory Reset |5              36|     3V3
'       GP4 I2C SDA       |6              35|     ADC_VREF
'       GP5 I2C SCL       |7              34|     GP28 (ADC2/free)
'       GND               |8              33|     GND
'       GP6 (free)        |9              32|     GP27 (ADC1/free)
'       GP7 (free)        |10             31|     GP26 (ADC0/free)
'       GP8 (free)        |11             30|     RUN
'       GP9 (free)        |12             29|     GP22 passive piezo
'       GND               |13             28|     GND
'       GP10 PWM Ch0      |14             27|     GP21 (free)
'       GP11 PWM Ch1      |15             26|     GP20 (free)
'       GP12 PWM Ch2      |16             25|     GP19 Test
'       GP13 PWM Ch3      |17             24|     GP18 IR Receiver
'       GND               |18             23|     GND
'       GP14 PWM Ch4      |19             22|     GP17 (free)
'       GP15 (free)       |20             21|     GP16 WS2812
'                         +.................+
'
' 
' ---------------------- SERIAL FRAME (UART / CDC) ------------------------

' Format: 0xAA LEN CMD DATA... 0x0D.
' LEN = number of bytes from CMD to last DATA (1..62).
' Status reply: 0xAA 0x01 STATUS 0x0D  (0x00=OK, 0x02=queue full).

' ------------------------- I2C COMMAND FORMAT ----------------------------

' MMBasic write: I2C WRITE addr, option, sendlen, data...
' addr    = &H20 (slave address)
' option  = 0 (always 0 = send stop condition)
' sendlen = number of bytes (CMD + DATA), same as frame LEN
' data    = CMD, DATA... (no sync 0xAA, no CR)

' MMBasic read:  I2C READ addr, option, rcvlen, buffer
' For read commands: first I2C WRITE the command, then I2C READ.
' I2C read length: status=1, digital read=2, adc read=3.

' -------------- HOW TO: SELECT USB DEVICES (INTERFACE MASK) --------------

' Send CMD 0x0A with mask_lo, mask_hi. Mask is stored in flash and the
' device reconnects. Combine bits by adding them.

' Bits:
' 0x0001 Keyboard
' 0x0002 Mouse
' 0x0004 Consumer
' 0x0010 AbsMouse
' 0x0020 SysCtrl
' 0x0040 MIDI

' Example: keyboard + mouse = 0x0003
' UART/CDC Format:0xAA LEN CMD DATA... 0x0D
' Frame: 0xAA 0x03 0x0A 0x03 0x00 0x0D
' 
' I2C Format: ADR,0,LEN,CMD,DATA
' I2C WRITE &H20, 0, 3, &H0A, &H03, &H00

' Example: keyboard only (default) = 0x0001
' UART/CDC: 0xAA 0x03 0x0A 0x01 0x00 0x0D
' I2C: I2C WRITE &H20, 0, 3, &H0A, &H01, &H00

' CDC stays active even with mask 0x0000.

' ------------------ HOW TO: TYPE ASCII-TEXT (CMD 0x01) -----------------
'
'       Type one character (CMD 0x01), mapped via active layout

' UART/CDC:
' Character 'A' -> 0xAA 0x02 0x01 0x41 0x0D
' Enter-key     -> 0xAA 0x02 0x01 0x0D 0x0D

' I2C:
' Character 'A' -> I2C WRITE &H20, 0, 2, &H01, &H41
' Enter-key     -> I2C WRITE &H20, 0, 2, &H01, &H0D

' IR (quick channel 19, key = ASCII code):
' Character 'A' -> 0x41
' Enter-key     -> 0x0D

' Codes according to ASCII - character table

' Implemented control keys:
' key    function
' 0x08   Backspace
' 0x09   Tab
' 0x0A   Enter
' 0x0D   Enter
' 0x1B   Escape
' 0x7F   Delete
' Other codes as <0x20 and >0x7E are not implemented

' The character codes are mapped according to selected keyboard layout DE/US.
' Default layout is DE. Change with CMD 0x09 if US is needed.

' -------------- ASCII-TEXT + SPECIAL FUNCTIONS (CMD 0x02) ------------------

' key       Device      Description
' 0-127    Keyboard   ASCII-Characters as CMD 0x01
' 128      Keyboard         F1
' 129      Keyboard         F2
' 130      Keyboard         F3
' 131      Keyboard         F4
' 132      Keyboard         F5
' 133      Keyboard         F6
' 134      Keyboard         F7
' 135      Keyboard         F8
' 136      Keyboard         F9
' 137      Keyboard         F10
' 138      Keyboard         F11
' 139      Keyboard         F12
' 140      Keyboard         PrtSc
' 141      Keyboard         ScrLk
' 142      Keyboard         Pause
' 143      Keyboard         Insert
' 144      Keyboard         Home
' 145      Keyboard         PgUp
' 146      Keyboard         End
' 147      Keyboard         PgDn
' 148      Keyboard         Arrow Right
' 149      Keyboard         Arrow Left
' 150      Keyboard         Arrow Down
' 151      Keyboard         Arrow Up
' 152-177  Keyboard         Ctrl+A...Ctrl+Z
' 178      GPIO 22          Audio C6  (1047 Hz)
' 179      GPIO 22          Audio C#6 (1109 Hz)
' 180      GPIO 22          Audio D6  (1175 Hz)
' 181      GPIO 22          Audio D#6 (1245 Hz)
' 182      GPIO 22          Audio E6  (1319 Hz)
' 183	   GPIO 22          Audio F6  (1397 Hz)
' 184-191  Keyboard         Alt+F1... Alt+F8
' 192      Media            Play/Pause
' 193      Media            Volume +
' 194      Media            Volume -
' 195      Media            Mute
' 196      Media            Next Track
' 197      Media      	    Prev Track
' 198      Media	    Stop
' 199      Media	    Eject
' 200      Media	    Bass+
' 201      Media            Bass-
' 202      Media            WWW Home
' 203      Media            WWW Search
' 204      Media            WWW Back
' 205      Media            WWW Fwd
' 206      Media            WWW Stop
' 207      System           Power
' 208      System           Sleep
' 209      System           Wake
' 210-217  Mouse            small move 1px up,ru,r,rd,d,ld,l,lu
' 218-225  Mouse            medium move 5px up,ru,r,rd,d,ld,l,lu
' 226-233  Mouse            large move  20px up,ru,r,rd,d,ld,l,lu
' 234      Mouse            L-Down button 1
' 235      Mouse            M-Down button 2
' 236      Mouse            R-down button 3
' 237      Mouse            L-Up button 1
' 238      Mouse            M-Up button 2
' 239      Mouse            R-Up button 3 
' 240      Mouse            Scroll up    wheel +1
' 241      Mouse            Scroll down  wheel -1
' 242      Mouse            Scroll left  wheel -1
' 243      Mouse            Scroll right wheel +1
' 244      GPIO 22          Audio F#6 (1480 Hz)
' 245      GPIO 22          Audio G6  (1568 Hz)
' 246      GPIO 22          Audio G#6 (1661 Hz)
' 247      GPIO 22          Audio A6  (1760 Hz)
' 248      GPIO 22          Audio A#6 (1865 Hz)
' 249      GPIO 22          Audio B6  (1976 Hz)
' 250      GPIO 22          Audio C7  (2093 Hz)
' 251      GPIO 22          Audio C#7 (2217 Hz)
' 252      GPIO 22          Audio D7  (2349 Hz)
' 253      GPIO 22          Audio D#7 (2489 Hz)
' 254      GPIO 22          Audio E7  (2637 Hz)
' 255      GPIO 22          Audio F7  (2794 Hz)

' ------------------- HOW TO: ENTER A RAW KEY (CMD 0x03) --------------------
'
'      Press a raw key without release (CMD 0x03): modifier, keycode

' UART/CDC:
' Ctrl+C  -> 0xAA 0x03 0x03 0x01 0x06 0x0D

' Release all keys and buttons (CMD 0x04):
' Release -> 0xAA 0x01 0x04 0x0D

' I2C:
' Ctrl+C  -> I2C WRITE &H20, 0, 3, &H03, &H01, &H06
' Release -> I2C WRITE &H20, 0, 1, &H04

' IR:
' Special keys via quick channel 20(see table quick channel 20(Ctrl+C->26)
' Or raw keys via channel 26.

' Short overview on modifiers and keycodes:

' Modifier (Byte 4): bit values, add them

' 0x01 Ctrl, 0x02 Shift, 0x04 Alt, 0x08 GUI (left)
' 0x10 Ctrl, 0x20 Shift, 0x40 AltGr, 0x80 GUI (right)

' Keycode (Byte 5): USB HID Usage IDs (standard table)
'
' a-z = 0x04-0x1D, 1-9 = 0x1E-0x26, 0 = 0x27
' Enter 0x28, Esc 0x29, Backspace 0x2A, Tab 0x2B, Space 0x2C
' F1-F12 = 0x3A-0x45, arrows 0x4F-0x52

' So Ctrl+C = modifier 0x01, keycode 0x06 ('c')

' Further details raw keys, modifiers and keycodes see 'USB HID Usage
' Tables Keyboard'(Usage page 0x07).

' ------------------- HOW TO: USE RELATIVE MOUSE (CMD 0x07) ----------------

'                              Move mouse

' First activate keyboard and/or mouse (if not already done):
' Interface mask keyboard + mouse = 0x0003
' UART/CDC: 0xAA 0x03 0x0A 0x03 0x00 0x0D
' I2C: I2C WRITE &H20, 0, 3, &H0A, &H03, &H00

' Move mouse (CMD 0x07): btn, dx, dy, scroll_v, scroll_h
'
' Values for dx/dy, scroll_v, scroll_h with sign: -127..+127
' dx: +right, dy: +down, scroll_v: + up, scroll_h: + right
'
' Buttons: left: &H01, right: &H02, middle: &H04
' 
' Release buttons with:
' UART/CDC: AA 01 04 0D
' I2C: I2C WRITE &H20,0,1,&H04

' UART/CDC:
' Move right 10, down 5 -> 0xAA 0x06 0x07 0x00 0x0A 0x05 0x00 0x00 0x0D

' I2C:
' Move right 10, down 5 ->I2C WRITE &H20,0,6,&H07,&H00,&H0A,&H05,&H00,&H00

' IR: relative mouse via quick channel 23
' Move right 10:send two times key 2 (key 2 = 5px right)
' Move down 5: send key 5 (key 5 = 5px down)

' Further details see table IR-quick channel 23: Relative Mouse

' --------- HOW TO: READ ANALOG / DIGITAL INPUTS CMD 0x1D)-------------------
'
'                Understanding the GPIO command structure

' GPIO uses CMD 0x1D. The first DATA byte is always the SUB-command,
' followed by that sub-command's own arguments.

' Example: set GP26 to ADC mode
' UART/CDC: 0xAA 0x04 0x1D 0x00 0x1A 0x03 0x0D

' Byte  Value  Meaning
'  1    0xAA   Sync (frame start)
'  2    0x04   LEN = 4 (CMD + SUB + pin + mode)
'  3    0x1D   CMD  = GPIO
'  4    0x00   SUB  = Pin Mode
'  5    0x1A   pin  = 0x1A = 26 -> GP26
'  6    0x03   mode = 3 = ADC
'  7    0x0D   CR (frame end)

' The SUB-command decides which arguments follow. For SUB 0x00
' (Pin Mode) they are: pin, then mode. LEN counts CMD plus all DATA
' bytes (SUB and its arguments), but not sync or CR.

' -------------------------------------------------------------------------
'
'                      Read an analog value (ADC)

' Step 1: set pin to ADC (mode 3). SUB 0x00: pin, mode
' UART/CDC: 0xAA 0x04 0x1D 0x00 0x1A 0x03 0x0D
' I2C: I2C WRITE &H20, 0, 4, &H1D, &H00, &H1A, &H03

' Step 2: read ADC channel(SUB 0x03): channel 0..2,(GP26=0, GP27=1, GP28=2,
' GP29=3(Voltage),on chip temperature=4)
'
' Example for GP26:
' UART/CDC:
' Send:  0xAA 0x03 0x1D 0x03 0x00 0x0D
' Reply: 0xAA 0x04 0x1D 0x03 val_lo val_hi 0x0D  (12-bit, 0..4095)

' I2C (write command, then read 3 bytes: status, val_lo, val_hi):
' I2C WRITE &H20, 0, 3, &H1D, &H03, &H00
' I2C READ  &H20, 0, 3, ARRAY()

' IR: No read functionality implemented

' -------------------------------------------------------------------------
'
'                     Read a digital input (0/1)

' Step 1: set pin mode. mode 0 = input, mode 2 = input with pullup
' Example set GP02 to input (no pull up):
' UART/CDC: 0xAA 0x04 0x1D 0x00 0x02 0x00 0x0D
' I2C: I2C WRITE &H20, 0, 4, &H1D, &H00, &H02, &H00

' Step 2: digital read (SUB 0x02): pin
' Example for GP02:
' UART/CDC:
' Send:     0xAA 0x03 0x1D 0x02 0x02 0x0D
' Reply:    0xAA 0x03 0x1D 0x02 value 0x0D

' I2C (write command, then read 2 bytes: status, value):
' I2C WRITE &H20, 0, 3, &H1D, &H02, &H02
' I2C READ  &H20, 0, 2, ARRAY()

' IR: No read functionality implemented

' -------------------------------------------------------------------------
'
'                      Write a digital output (0/1)

' Step 1: set pin to output (mode 1)
' Example set GP2 to output:
' UART/CDC: 0xAA 0x04 0x1D 0x00 0x02 0x01 0x0D
' I2C: I2C WRITE &H20, 0, 4, &H1D, &H00, &H02, &H01

' Step 2: digital write (SUB 0x01): pin, value
' Example set GP2 high:
' UART/CDC: 0xAA 0x04 0x1D 0x01 0x02 0x01 0x0D
' I2C: I2C WRITE &H20, 0, 4, &H1D, &H01, &H02, &H01

' IR: digital output via quick channels 30/31 (universal channel)
' Send each frame byte in turn. Frame = [LEN][CMD][DATA...],
' no sync 0xAA, no CR. Bytes 0x00-0x7F: send device 30, key=byte.
' Then device 31 key=0x02 (commit) to push the byte.
' Bytes > 0x7F: device 30 key=low 7 bits, device 31 key=0x03
' (bit0=high bit, bit1=commit).

' Example: set GP2 to output = frame 04 1D 00 02 01
'   byte 0x04 (LEN=4): dev 30 key 0x04, then dev 31 key 0x02
'   byte 0x1D (CMD):   dev 30 key 0x1D, then dev 31 key 0x02
'   byte 0x00 (SUB):   dev 30 key 0x00, then dev 31 key 0x02
'   byte 0x02 (pin):   dev 30 key 0x02, then dev 31 key 0x02
'   byte 0x01 (mode):  dev 30 key 0x01, then dev 31 key 0x02
' Parser assembles [04 1D 00 02 01] and runs the command.

' Then set GP2 high = frame 04 1D 01 02 01
' 0x04, 0x1D, 0x01, 0x02, 0x01 (each: dev 30 value, dev 31 commit)

' --------------------- HOW TO: PWM AND SERVO OUTPUT ----------------------
'
'                           PWM output (mode 4)

' Step 1: set pin to PWM (mode 4). SUB 0x00: pin, mode
' UART/CDC: 0xAA 0x04 0x1D 0x00 0x0A 0x04 0x0D
' I2C: I2C WRITE &H20, 0, 4, &H1D, &H00, &H0A, &H04

' Step 2 (optional): set frequency (SUB 0x06): pin, freq_hi, freq_lo
' Example set GP10 to 1000 Hz:
' UART/CDC: 0xAA 0x05 0x1D 0x06 0x0A 0x03 0xE8 0x0D
' I2C: I2C WRITE &H20, 0, 5, &H1D, &H06, &H0A, &H03, &HE8

' Step 3: set duty (SUB 0x04): pin, duty_hi, duty_lo (0..65535)
' Example set GP10 to 50% (0x8000)
' UART/CDC: 0xAA 0x05 0x1D 0x04 0x0A 0x80 0x00 0x0D
' I2C: I2C WRITE &H20, 0, 5, &H1D, &H04, &H0A, &H80, &H00

' IR: PWM output possible via quick channels 30/31 (universal channel)

' -------------------------------------------------------------------------
'
'                         Servo output (mode 5)

' Step 1: set pin to PWM-Servo (mode 5)
' Example set GP10 to servo mode:
' UART/CDC: 0xAA 0x04 0x1D 0x00 0x0A 0x05 0x0D
' I2C: I2C WRITE &H20, 0, 4, &H1D, &H00, &H0A, &H05

' Step 2: set pulse width (SUB 0x05): pin, us_hi, us_lo (500..2500)
' Example set GP10 1500us (center)
' UART/CDC: 0xAA 0x05 0x1D 0x05 0x0A 0x05 0xDC 0x0D
' I2C: I2C WRITE &H20, 0, 5, &H1D, &H05, &H0A, &H05, &HDC

' Servo frequency is clamped to 50..300Hz (change via SUB 0x06):
' pin, freq_hi, freq_lo
' Example set GP10 to 50 Hz:
' UART/CDC: 0xAA 0x05 0x1D 0x06 0x0A 0x00 0x32 0x0D
' I2C: I2C WRITE &H20, 0, 5, &H1D, &H06, &H0A, &H00, &H32

' Enable/disable a pin (SUB 0x07): pin, value(1=on, 0=off)
' Example enable GP10:
' UART/CDC: 0xAA 0x04 0x1D 0x07 0x0A 0x01 0x0D
' I2C: I2C WRITE &H20, 0, 4, &H1D, &H07, &H0A, &H01

' Save GPIO config to flash (SUB 0x08):
' UART/CDC: 0xAA 0x02 0x1D 0x08 0x0D
' I2C: I2C WRITE &H20, 0, 2, &H1D, &H08

' IR: Servo output possible via quick channels 30/31 (universal channel)

' ------------------ HOW TO: WS2812 LEDS (CMD 0x1C) ------------------------
'
'                     Addressable RGB LEDs on GP16

' Two modes: 0 -> control of all LEDs including LED 0
'            1 -> LED 0 is status display

' Set mode (SUB 0x02): mode
' Manual -> UART/CDC: 0xAA 0x03 0x1C 0x02 0x00 0x0D
'        -> I2C: I2C WRITE &H20, 0, 3, &H1C, &H02, &H00

' Set LED count (SUB 0x03): count_lo, count_hi (1..256, saved)
' 8 LEDs -> UART/CDC: 0xAA 0x04 0x1C 0x03 0x08 0x00 0x0D
'        -> I2C: I2C WRITE &H20, 0, 4, &H1C, &H03, &H08, &H00

' Set one LED and show (SUB 0x00): index, r, g, b
' LED0 red -> UART/CDC: 0xAA 0x06 0x1C 0x00 0x00 0xFF 0x00 0x00 0x0D
'          -> I2C: I2C WRITE &H20,0,6,&H1C,&H00,&H00,&HFF,&H00,&H00

' Set all LEDs and show (SUB 0x01): r, g, b
' All blue -> UART/CDC: 0xAA 0x05 0x1C 0x01 0x00 0x00 0xFF 0x0D
'          -> I2C: I2C WRITE &H20, 0, 5, &H1C, &H01, &H00, &H00, &HFF

' Set brightness (SUB 0x04): 0..255
' Half -> UART/CDC: 0xAA 0x03 0x1C 0x04 0x80 0x0D
'      -> I2C: I2C WRITE &H20, 0, 3, &H1C, &H04, &H80

' Set one LED into buffer (SUB 0x06): index, r, g, b
' LED0 red -> UART/CDC: 0xAA 0x06 0x1C 0x06 0x00 0xFF 0x00 0x00 0x0D
'          -> I2C: I2C WRITE &H20,0,6,&H1C,&H06,&H00,&HFF,&H00,&H00

' Show all LEDs of buffer (Sub 0x05)
' Show LEDs->UART/CDC: 0xAA 0x02 0x1C 0x05 0x0D
'          -> I2C: I2C WRITE &H20,0,2,&H1C,&H05 

' --------------------------- HOW TO: MIDI (CMD 0x0C)  ---------------------
'
'                Enable MIDI first via interface mask

' Select USB-device: Keyboard + MIDI = 0x0041
' UART/CDC: 0xAA 0x03 0x0A 0x41 0x00 0x0D
' I2C: I2C WRITE &H20, 0, 3, &H0A, &H41, &H00

' Note On (CMD 0x0C): channel, note, velocity
' Middle C on -> UART/CDC: 0xAA 0x04 0x0C 0x00 0x3C 0x64 0x0D
'             -> I2C: I2C WRITE &H20, 0, 4, &H0C, &H00, &H3C, &H64

' Note Off (CMD 0x0D): channel, note, velocity
' Middle C off -> UART/CDC: 0xAA 0x04 0x0D 0x00 0x3C 0x00 0x0D
'              -> I2C: I2C WRITE &H20, 0, 4, &H0D, &H00, &H3C, &H00

' Control Change (CMD 0x0E): channel, controller, value
' Program Change (CMD 0x0F): channel, program
' Pitch Bend (CMD 0x10): channel, lsb, msb
' Raw MIDI (CMD 0x11): len, bytes...

' ------------------ HOW TO: MEDIA / CONSUMER KEYS (CMD 0x05)  ---------------
'
'                        Volume, play/pause etc.

' Select USB-device: 0x07 Keyboard+Mouse+Consumer
' Media (CMD 0x05): usage_hi, usage_lo (16-bit consumer usage)
' Volume Up (0x00E9) -> UART/CDC: 0xAA 0x03 0x05 0x00 0xE9 0x0D
'                    -> I2C: I2C WRITE &H20, 0, 3, &H05, &H00, &HE9

' IR: quick channel 21 (media control).
' Common usages: Play/Pause 0x00CD, Vol+ 0x00E9, Vol- 0x00EA,
' Mute 0x00E2, Next 0x00B5, Prev 0x00B6, Stop 0x00B7.

' --------------------- HOW TO: SYSTEM CONTROL (CMD 0x0B) -------------------
'
'                         Power / Sleep / Wake

' Select USB-device: 0x23 Keyboard+Mouse+SysCtrl
' SysControl (CMD 0x0B): usage (0x81 power, 0x82 sleep, 0x83 wake)
' Sleep -> UART/CDC: 0xAA 0x02 0x0B 0x82 0x0D
'       -> I2C: I2C WRITE &H20, 0, 2, &H0B, &H82

' IR: quick channel 22 (system control).

' --------------- HOW TO: ABSOLUTE MOUSE / TOUCHSCREEN (CMD 0x08) -----------
'
'              Point to an absolute screen position

' Select USB-device: AbsMouse
' Touch (CMD 0x08): btn, x_lo, x_hi, y_lo, y_hi (range 0..32767)
' Center, no button -> X=16384 (0x4000), Y=16384 (0x4000)

' Generate touch on Center(btn=0x01):
' 
' Press/touch (button):
' UART/CDC: 0xAA 0x06 0x08 0x01 0x00 0x40 0x00 0x40 0x0D
' Release touch (button(s)):
' UART/CDC: 0xAA 0x01 0x04 0x0D
' 
' I2C Write &H20,0,6,&H08,&H01,&H00,&H040,&H00,&H04
' I2C: I2C WRITE &H20,0,1,&H04

' Depend on pauses between press - release single finger gestures may be
' simulated

' IR: quick channels 24/25 (set X/Y), then 27 (trigger).

' -------------------- HOW TO: LAYOUT / BAUD / CONFIG ---------------------
'
'                Keyboard layout, baud rate, config

' Set layout (CMD 0x09): layout_id (0=US, 1=DE). Saved to flash.
' DE -> UART/CDC: 0xAA 0x02 0x09 0x01 0x0D
'    -> I2C: I2C WRITE &H20, 0, 2, &H09, &H01

' Set UART baud (CMD 0x12): b3, b2, b1, b0 (MSB first). Saved.
' 115200 (0x0001C200) ->
' UART/CDC: 0xAA 0x05 0x12 0x00 0x01 0xC2 0x00 0x0D
' I2C: I2C WRITE &H20, 0, 5, &H12, &H00, &H01, &HC2, &H00

' Config dump (CMD 0x1A, CDC only): 0xAA 0x01 0x1A 0x0D
' Reply: 0xAA 0x08 0x1A layout mask_lo mask_hi b3 b2 b1 b0 0x0D

' ========================== COMMAND REFERENCE ============================

' CMD   Name          LEN    Payload
' 0x01  Char          2      ascii
' 0x02  Char+         2      ascii+ quick-keys + MTMF/ alarm audio
' 0x03  Key           3      modifier, keycode
' 0x04  Release       1      (none)
' 0x05  Media         3      usage_hi, usage_lo
' 0x07  Mouse         6      btn, dx, dy, scroll_v, scroll_h
' 0x08  Touch         6      btn, x_lo, x_hi, y_lo, y_hi
' 0x09  Layout        2      layout_id (0=US, 1=DE)
' 0x0A  InterfaceCfg  3      mask_lo, mask_hi
' 0x0B  SysControl    2      usage (0x81/0x82/0x83)
' 0x0C  NoteOn        4      channel, note, velocity
' 0x0D  NoteOff       4      channel, note, velocity
' 0x0E  CtrlChange    4      channel, controller, value
' 0x0F  ProgChange    3      channel, program
' 0x10  PitchBend     4      channel, lsb, msb
' 0x11  RawMIDI       2-4    len, bytes...
' 0x12  BaudRate      5      b3, b2, b1, b0 (MSB first)
' 0x1A  ConfigDump    1      (CDC only)
' 0x1C  WS2812        3-6    sub, data...
' 0x1D  GPIO          3-5    sub, data...

' Note: LEN counts CMD + all DATA bytes (incl. SUB). No sync, no CR.
' for I2C, LEN is the MMBasic 'sendlen' argument.

' ----------------------- GPIO SUB-COMMANDS (0x1D) ------------------------

' sub   name          payload           valid mode
' 0x00  Pin Mode      pin, mode(0-5)     any
' 0x01  Digital Write pin, value(0/1)    mode 1
' 0x02  Digital Read  pin                mode 0/1/2
' 0x03  ADC Read      channel(0-2)       mode 3
' 0x04  PWM Duty      pin, hi, lo        mode 4
' 0x05  PWM Servo     pin, hi, lo (us)   mode 5
' 0x06  PWM Freq      pin, hi, lo (Hz)   mode 4/5
' 0x07  PWM Enable    pin, value(0/1)    mode 4/5
' 0x08  Save Config   (none)             any

' Pin modes: 0=In 1=Out 2=InPullup 3=ADC 4=PWM 5=PWM-Servo
' PWM pins: GP2 6 7 8 9 10 11 12 13 14 15 17 20 21
' ADC pins: GP26(0) GP27(1) GP28(2). Locked: GP3 GP16 GP18 GP19 GP22.
' Internal: GP29(3) ADC supply voltage, on chip temperature (4)
' Wrong pin or mode returns status 0xFF.

' ----------------------- WS2812 SUB-COMMANDS (0x1C) ----------------------

' sub   name              payload
' 0x00  Set LED + Show    index, r, g, b
' 0x01  Set All + Show    r, g, b
' 0x02  Set Mode          0=Manual, 1=Status (stored in flash)
' 0x03  Set Count         lo, hi (1..256), (stored in flash)
' 0x04  Set Brightness    0..255
' 0x05  Show              (none)
' 0x06  Set LED No-Show   index, r, g, b

' Data on GP16, max 256 LEDs. Status mode uses LED0 only.

' =================== ASCII+ QUICK-KEYS (CMD 0x02) ========================

' Char+ --> ascii-code (0-127) expanded (128-255) with often used features

' 128      Keyboard         F1
' 129      Keyboard         F2
' 130      Keyboard         F3
' 131      Keyboard         F4
' 132      Keyboard         F5
' 133      Keyboard         F6
' 134      Keyboard         F7
' 135      Keyboard         F8
' 136      Keyboard         F9
' 137      Keyboard         F10
' 138      Keyboard         F11
' 139      Keyboard         F12
' 140      Keyboard         PrtSc
' 141      Keyboard         ScrLk
' 142      Keyboard         Pause
' 143      Keyboard         Insert
' 144      Keyboard         Home
' 145      Keyboard         PgUp
' 146      Keyboard         End
' 147      Keyboard         PgDn
' 148      Keyboard         Arrow Right
' 149      Keyboard         Arrow Left
' 150      Keyboard         Arrow Down
' 151      Keyboard         Arrow Up
' 152-177  Keyboard         Ctrl+A...Ctrl+Z
' 178      GPIO 22          Audio C6  (1047 Hz)
' 179      GPIO 22          Audio C#6 (1109 Hz)
' 180      GPIO 22          Audio D6  (1175 Hz)
' 181      GPIO 22          Audio D#6 (1245 Hz)
' 182      GPIO 22          Audio E6  (1319 Hz)
' 183	   GPIO 22          Audio F6  (1397 Hz)
' 184-191  Keyboard         Alt+F1...Alt+F8
' 192      Media            Play/Pause
' 193      Media            Volume +
' 194      Media            Volume -
' 195      Media            Mute
' 196      Media            Next Track
' 197      Media	    Prev Track
' 198      Media	    Stop
' 199      Media	    Eject
' 200      Media	    Bass+
' 201      Media            Bass-
' 202      Media            WWW Home
' 203      Media            WWW Search
' 204      Media            WWW Back
' 205      Media            WWW Fwd
' 206      Media            WWW Stop
' 207      System           Power
' 208      System           Sleep
' 209      System           Wake
' 210-217  Mouse            small move 1px up,ru,r,rd,d,ld,l,lu
' 218-225  Mouse            medium move 5px up,ru,r,rd,d,ld,l,lu
' 226-233  Mouse            large move  20px up,ru,r,rd,d,ld,l,lu
' 234      Mouse            L-Down button 1
' 235      Mouse            M-Down button 2
' 236      Mouse            R-down button 3
' 237      Mouse            L-Up button 1
' 238      Mouse            M-Up button 2
' 239      Mouse            R-Up button 3 
' 240      Mouse            Scroll up    wheel +1
' 241      Mouse            Scroll down  wheel -1
' 242      Mouse            Scroll left  wheel -1
' 243      Mouse            Scroll right wheel +1
' 244      GPIO 22          Audio F#6 (1480 Hz)
' 245      GPIO 22          Audio G6  (1568 Hz)
' 246      GPIO 22          Audio G#6 (1661 Hz)
' 247      GPIO 22          Audio A6  (1760 Hz)
' 248      GPIO 22          Audio A#6 (1865 Hz)
' 249      GPIO 22          Audio B6  (1976 Hz)
' 250      GPIO 22          Audio C7  (2093 Hz)
' 251      GPIO 22          Audio C#7 (2217 Hz)
' 252      GPIO 22          Audio D7  (2349 Hz)
' 253      GPIO 22          Audio D#7 (2489 Hz)
' 254      GPIO 22          Audio E7  (2637 Hz)
' 255      GPIO 22          Audio F7  (2794 Hz)

' =================== IR QUICK CHANNELS - OVERVIEW ========================

' Sony SIRC 12-bit: 5-bit device + 7-bit key. Debounce 60ms, no repeat.

' Dev  Function
' 19   Keyboard ASCII (key = ASCII code, like CMD 0x01)
' 20   Keyboard Special (F1-F12, navigation, Ctrl+A..Z, Alt+F1..F8)
' 21   Media Control (play, volume, next, prev ...)
' 22   System Control (power, sleep, wake)
' 23   Relative Mouse (move, click, scroll)
' 24   Absolute Mouse: set X (0..127)
' 25   Absolute Mouse: set Y (0..127)
' 26   Raw Keyboard (modifier + keycode, no auto-release)
' 27   Absolute Mouse: trigger action (uses stored X/Y)
' 30   Universal Channel: byte value (low 7 bits)
' 31   Universal Channel: high bit + commit

' ----------------------- Device 19: Keyboard ASCII -----------------------

' key    function
' 0x08   Backspace
' 0x09   Tab
' 0x0A   Enter
' 0x0D   Enter
' 0x1B   Escape
' 0x7F   Delete
' All other codes as <0x20 und >0x7E are not implemented

' The character codes are mapped according to selected keyboard layout DE/US.
' Default layout is DE. Change with CMD 0x09 if you need US.

' -------------- Device 20: Keyboard Special (auto-release) ---------------

' key    function
' 0-11   F1-F12
' 12     Print Screen      13  Scroll Lock
' 14     Pause             15  Insert
' 16     Home              17  Page Up
' 18     End               19  Page Down
' 20     Arrow Right       21  Arrow Left
' 22     Arrow Down        23  Arrow Up
' 24-49  Ctrl+A .. Ctrl+Z
' 50-55  reserved
' 56-63  Alt+F1 .. Alt+F8
' 64     Audio C6  (1047 Hz)
' 65     Audio C#6 (1109 Hz)
' 66     Audio D6  (1175 Hz)
' 67     Audio D#6 (1245 Hz)
' 68     Audio E6  (1319 Hz)
' 69     Audio F6  (1397 Hz)
' 70     Audio F#6 (1480 Hz)
' 71     Audio G6  (1568 Hz)
' 72     Audio G#6 (1661 Hz)
' 73     Audio A6  (1760 Hz)
' 74     Audio A#6 (1865 Hz)
' 75     Audio B6  (1976 Hz)
' 76     Audio C7  (2093 Hz)
' 77     Audio C#7 (2217 Hz)
' 78     Audio D7  (2349 Hz)
' 79     Audio D#7 (2489 Hz)
' 80     Audio E7  (2637 Hz)
' 81     Audio F7  (2794 Hz)

' ---------------- Device 21: Media Control (auto-release) ----------------

' 0 Play/Pause   1 Vol+   2 Vol-   3 Mute   4 Next   5 Prev
' 6 Stop   7 Eject   8 Bright+   9 Bright-   10 Home
' 11 Search   12 Back   13 Forward   14 Refresh

' --------------------- Device 22: System Control -------------------------

' 0 Power Down   1 Sleep   2 Wake Up

'--------------------- Device 23: Relative Mouse -------------------------

' 0-7  move 1px (8 directions, starting up, clockwise)
' 8-15 move 5px (same 8 directions)
' 16-23 move 20px (same 8 directions)
' 24 Left Down   25 Middle Down   26 Right Down
' 27 Left up     28 Middle Up     29 Right Up
' 30 Scroll Up   31 Scroll Down   32 Scroll Left   33 Scroll Right

' ------------------ Device 24/25/27: Absolute Mouse ----------------------

' Dev 24: X (0..127)   Dev 25: Y (0..127)   default X=64 Y=64
' Mapping: coord = key * 32767 / 127
' Dev 27 actions:
' 0 Move Only   1 Left Click   2 Right Click   3 Middle Click
' 4 Double Click Left   5 Left Down (drag)   6 Left Up (drop)
' 7 Right Down   8 Right Up

' --------------- Device 26: Raw Keyboard (no auto-release) ---------------

' 0 Release (keyboard AND mouse)
' 1 Ctrl   2 Shift   3 Alt   4 GUI
' 5 Ctrl+Shift   6 Ctrl+Alt   7 Ctrl+Alt+Shift
' 8-127 HID keycode sent with active modifier
' Modifier resets after 5s without a key.

' -------------------- Device 30/31: Universal Channel --------------------

' Sends any framed command [LEN][CMD][DATA...].
' Dev 30: byte value (low 7 bits, stored)
' Dev 31: bit0 = high bit of byte, bit1 = commit
' Assembled byte = stored_low OR ((key AND 1) << 7)
' Mask and ready checks apply as with UART/CDC.

' ============================= NOTES / TIPS ==============================

' - Default layout: DE.Change with CMD 0x09 if US is need (stored in flash).
' - Keyboard is the only device active by default (USB-device 0x01).
'   Enable mouse, consumer, etc. via CMD 0x0A before using them.
' - Changing the interface USB-device-code reconnects the USB device.
' - Umlauts are not direct supported (ASCII only).
' - Factory reset: hold GP3 low at boot -> defaults + LED 1s.
' - Audio output 200 ms, changes below 200 ms are performed at once.
' - Self test: Set GP19 low, output of system data via USB.
' - If keyboard is not enabled: Selftest audio output approx. after 30 s.
' - Enter pause of approx. 30 ms between commands if commands/data is lost.
'
' ============================= END OF HELP ===============================

' ======================= MMBasic EXAMPLE PROGRAMS ========================

' Following programs can be used to test some functions of HID-Remapper:

' ----------------- Set keyboard layout US/DE via CDC ---------------------

' Open CDC port:
' Open "COMn:4800" As #1
' Input "Select keyboard layout (0=US,1=DE): ";layout
' Print #1,Chr$(&HAA);Chr$(&H02);Chr$(&H09);Char$(layout);Chr$(&H0D)
' close#1

' ----------- Print ASCII Characters 0x20..0x7E via UART to USB -----------
' 
' SetPin GPx,GPy, COMn
' Open "COMn:9600" As #1
' For ASCII=32 to 126
' Print #1,Chr$(&HAA);Chr$(&H02);Chr$(&H01);Chr$(ASCII);Chr$(&H0D) 
' Pause 75
' Next ASCII
' Close #1

' --- Print ASCII Characters 0x20..0x7E via IR Quick-channel 19 to USB --- 
' For ASCII=32 to 126
' IR send GPn,19,ASCII
' Next ASCII

' -------- Send ctrl-c from a running program via CDC to "break" it ------
'
' Open "COMn:4800" as #1
' For i=1 to 1000
' Print i
' Pause 50
' If  i=500 then
' Print #1,chr$(&HAA);chr$(&H03);chr$(&H03);chr$(&H01),chr$(&H06);chr$(&H0D)
' Pause 10
' Print #1,chr$(&HAA);chr$(&H01);chr$(&H04);chr$(&H0D)
' endif
' Next i
' Close #1
'
' ------- Read analog inputs via CDC (Pico voltage and temperature) ------

' Open "COMn:4800" as #1
' Do
' Print #1,chr$(&HAA);chr$(&H04);chr$(&H1D);chr$(&H00);chr$(&H1C);chr$
' (&H03);chr$(&H0D)
' Print #1,chr$(&HAA);chr$(&H03);chr$(&H1D);chr$(&H03);chr$(&H03);chr$(&H0D)
' Pause 10
' Receive$=Input$(7,#1)
' Print(Asc(Mid$(Receive$,5,5))+Asc(Mid$(Receive$,6,6))*256)*3.3/4096*3,
' Print #1,chr$(&HAA);chr$(&H03);chr$(&H1D);chr$(&H03);chr$(&H04);chr$(&H0D)
' Print 27-(Asc(Mid$(Receive$,5,5))+Asc(Mid$(Receive$,6,6))*256)*3.3/4096
' -0.706)/0.001721
' Pause 1000
' Loop
' Close #1

' ----------------- Read a digital I/O with pull-up (GP 02) ---------------
'
' Dim Receive%(1)
' Do
' I2C write &H20,4,&H1D,&H00,&H02,&H02
' I2C write &H20,0,3,&H02,&H02
' Pause 10
' I2C read &H20,0,2,Receive%()
' Print Receive%(1)
' Pause 50
' Loop
'
'---------------------- Write to a digital I/O (GP 02) -------------------
'
' I2C write &H20,0,4,&H1D,&H00,&H02,&H01
' do
' I2C write &H20,0,4,&H1D,&H01,&H02,&H01
' Pause 500
' I2C write &H20,0,4,&H1D,&H00,&H02,&H01
' Loop
'
' -------------------- PWM output (GP10 - Pulsing LED) -------------------
'
' I2C write &G20,0,4,&H1D,&H00,&H0A,&H04
' Pause 10
' I2C write &H20,0,5,&H1D,&H06,&H0A,&H03,&HE8
' Pause 10
' i%=5
' ud%=5
' Do
' I2C write &H20,0,5,&H1D,&H04,&H0A,i%,&H00
' i%=i%+1
' If I%>254 or I%<5 then ud%=-ud%
' Pause 5
' Loop
'
' --------------- Control a servo via GP02 (min<-->max) ------------------
'
' I2C write &G20,0,4,&H1D,&H00,&H02,&H05
' Pause 10
' I2C write &H20,0,5,&H1D,&H06,&H02,&H00,&HE32
' Pause 10
' Do
' I2C write &H20,0,5,&H1D,&H05,&H02,&H00,&H00
' I2C write &H20,0,4,&H1D,&H07,&H02,&H01
' Pause 1000
' I2C write &H20,0,4,&H1D,&H07,&H02,&H00
' Pause 10
' I2C write &H20,0,5,&H1D,&H05,&H02,&HFF,&HFF
' I2C write &H20,0,4,&H1D,&H07,&H02,&H01
' Pause 1000
' I2C write &H20,0,4,&H1D,&H07,&H02,&H00
' Pause 10
' Loop

'--- Simulate touch events with absolute mouse on a horizontal line) -----
'
' Open "COMn:9600" as #1
' GUI cursor on 0
' GUI cursor link mouse
' For i%=0 to 128
' Print #1,chr$(&HAA);chr$(&H06);chr$(&H08);chr$(&H01);chr$(&H00);chr$
' (i%);chr$&H00);chr$(64);chr$(&H0D)
' Pause 30
' Print #1,chr$(&HAA);chr$(&H01);chr$(&H04)
' GUI cursor Touch(x),Touch(y)
' Pause 100
' Next i%
'
'------------------- Send Audio via IR channel 20 -------------------------
'
' For i%=64 to 81
' IR Send GPxx,20,i%
' Pause 200
' Next I%

'---------------- Send Universal Data via IR channel 30/31-----------------
'
' ' Send "AA 03 1C 02 00 0D" (WS2812 to manual mode (0)->Status LED off)
' IR Send GPxx,30,42:Pause 50:IR Send GPxx,31,03:Pause 50
' IR Send GPxx,30,03:Pause 50:IR Send GPxx,31,02:Pause 50
' IR Send GPxx,30,28:Pause 50:IR Send GPxx,31,02:Pause 50
' IR Send GPxx,30,02:Pause 50:IR Send GPxx,31,02:Pause 50
' IR Send GPxx,30,00:Pause 50:IR Send GPxx,31,02:Pause 50 
' IR Send GPxx,30,13:Pause 50:IR Send GPXX,31,02:Pause 50


' Further details to Picomite/MMBasic see https://geoffg.net/picomite.html.

============================== Have fun ... Arne 2026 ======================

