Initial bring up USB HID interface

This commit is contained in:
Wenting Zhang 2024-06-23 21:36:42 -07:00
parent 3a16b26ec2
commit 3bf4096d43
10 changed files with 249 additions and 27 deletions

View file

@ -28,10 +28,12 @@ add_executable(fw
bitstream.c
button.c
caster.c
crc16.c
edid.c
fpga.c
fusb302.c
fw.c
iap.c
power.c
ptn3460.c
tcpm_driver.c

View file

@ -95,4 +95,3 @@ uint8_t caster_load_waveform(uint8_t *waveform, uint8_t frames);
uint8_t caster_redraw(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
uint8_t caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
UPDATE_MODE mode);
uint8_t caster_setinput(uint8_t input_src);

60
fw/crc16.c Normal file
View file

@ -0,0 +1,60 @@
#include "crc16.h"
/*
* The crc32 is licensed under the Apache License, Version 2.0
* CRC16 implementation according to CCITT standards.
*
* The XMODEM CRC 16 algorithm, using the following parameters:
*
* Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
* Width : 16 bit
* Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1)
* Initialization : 0000
* Reflect Input byte : False
* Reflect Output CRC : False
* Xor constant to output CRC : 0000
* Output for "123456789" : 31C3
*/
static const uint16_t crc16tab[256]= {
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
uint16_t crc16(const char *buf, int len) {
int counter;
uint16_t crc = 0;
for (counter = 0; counter < len; counter++)
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];
return crc;
}

14
fw/crc16.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef _CRC_CRC16_H
#define _CRC_CRC16_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
uint16_t crc16(const char *buf, int len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View file

@ -112,7 +112,7 @@ int main()
}
void osd_task(void) {
#ifdef BOARD_HAS_BUTTON
#ifdef HAS_BUTTON
static int mode_max = 6;
static int mode = 1;
const UPDATE_MODE modes[6] = {

56
fw/iap.c Normal file
View file

@ -0,0 +1,56 @@
//
// Copyright 2024 Wenting Zhang <zephray@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "pico/bootrom.h"
#include "iap.h"
void __no_inline_not_in_flash_func(nuke)() {
uint flash_size_bytes;
#ifndef PICO_FLASH_SIZE_BYTES
#warning PICO_FLASH_SIZE_BYTES not set, assuming 16M
flash_size_bytes = 16 * 1024 * 1024;
#else
flash_size_bytes = PICO_FLASH_SIZE_BYTES;
#endif
flash_range_erase(0, flash_size_bytes);
// Pop back up as an MSD drive
reset_usb_boot(0, 0);
}
void iap_usbboot(void) {
reset_usb_boot(0, 0);
__builtin_unreachable();
}
void iap_reset(void) {
(*((volatile uint32_t*)(PPB_BASE + 0x0ED0C))) = 0x5FA0004; // Reset via NVIC
__builtin_unreachable();
}
void iap_nuke(void) {
nuke();
__builtin_unreachable();
}

5
fw/iap.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
void iap_nuke(void);
void iap_usbboot(void);
void iap_reset(void);

View file

@ -25,6 +25,9 @@
#include "caster.h"
#include "tusb.h"
#include "usb_descriptors.h"
#include "usbapp.h"
#include "crc16.h"
#include "iap.h"
void usbapp_init(void) {
tusb_init();
@ -80,11 +83,19 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
uint16_t y1 = (buffer[11] << 8) | buffer[10];
uint16_t id = (buffer[13] << 8) | buffer[12];
uint16_t chksum = (buffer[15] << 8) | buffer[14];
uint8_t retval = 1;
switch (buffer[0]) {
uint8_t retval;
uint16_t exp_chksum = crc16(buffer, 14);
if (chksum != exp_chksum) {
retval = USBRET_CHKSUMFAIL;
goto returnval;
}
retval = 1;
switch (cmd) {
case USBCMD_RESET:
// reset system
(*((volatile uint32_t*)(PPB_BASE + 0x0ED0C))) = 0x5FA0004; // Reset via NVIC
//iap_reset();
break;
case USBCMD_POWERDOWN:
// TODO
@ -93,7 +104,7 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
// TODO
break;
case USBCMD_SETINPUT:
retval = caster_setinput((uint8_t)param);
// TODO
break;
case USBCMD_REDRAW:
retval = caster_redraw(x0, y0, x1, y1);
@ -101,12 +112,27 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
case USBCMD_SETMODE:
retval = caster_setmode(x0, y0, x1, y1, (UPDATE_MODE)param);
break;
case USBCMD_USBBOOT:
//iap_usbboot();
break;
case USBCMD_NUKE:
//iap_nuke();
break;
}
if (retval == 0)
retval = USBRET_SUCCESS;
else
retval = USBRET_GENERALFAIL;
uint8_t txbuf[1];
returnval:
uint8_t txbuf[16] = {0};
txbuf[0] = retval;
txbuf[2] = buffer[14];
txbuf[3] = buffer[15];
txbuf[4] = exp_chksum & 0xff;
txbuf[5] = (exp_chksum >> 8) & 0xff;
tud_hid_report(0, txbuf, 1);
tud_hid_report(0, txbuf, 16);
}
void usbapp_task(void) {

View file

@ -27,6 +27,12 @@
#define USBCMD_SETINPUT 0x03
#define USBCMD_REDRAW 0x04
#define USBCMD_SETMODE 0x05
#define USBCMD_NUKE 0x06
#define USBCMD_USBBOOT 0x07
#define USBRET_GENERALFAIL 0x00
#define USBRET_CHKSUMFAIL 0x01
#define USBRET_SUCCESS 0x55
void usbapp_init(void);
void usbapp_task(void);

View file

@ -1,26 +1,80 @@
# Install python3 HID package https://pypi.org/project/hid/
# Install python3 hidapi package https://pypi.org/project/hidapi/
import hid
import struct
vid = 0xcafe
pid = 0x4004
USBCMD_RESET = 0x00
USBCMD_POWERDOWN = 0x01
USBCMD_POWERUP = 0x02
USBCMD_SETINPUT = 0x03
USBCMD_REDRAW = 0x04
USBCMD_SETMODE = 0x05
USBCMD_NUKE = 0x06
USBCMD_USBBOOT = 0x07
dev = hid.Device(vid, pid)
USBRET_GENERALFAIL = 0x00
USBRET_CHKSUMFAIL = 0x01
USBRET_SUCCESS = 0x55
if not dev:
print("Unable to open device")
exit()
def crc16(data: bytes):
'''
CRC-16 (CCITT) implemented with a precomputed lookup table
'''
table = [
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
]
crc = 0x0
for byte in data:
crc = (crc << 8) ^ table[(crc >> 8) ^ byte]
crc &= 0xFFFF # important, crc must stay 16bits all the way through
return crc
cmd = 0x00
param = 0x00
x0 = 0
y0 = 0
x1 = 1600 - 1
y1 = 1200 - 1
pid = 0
chksum = 0
def send_cmd():
vid = 0xcafe
pid = 0x4004
str_out = struct.pack('>h>h>h>h>h>h>h>h', cmd, param, x0, y0, x1, y1, pid, chksum)
dev.write(str_out)
str_in = dev.read(1)
print("Received from HID Device:", str_in, '\n')
h = hid.device()
h.open(vid, pid)
print("Manufacturer: %s" % h.get_manufacturer_string())
print("Product: %s" % h.get_product_string())
print("Serial No: %s" % h.get_serial_number_string())
#cmd = USBCMD_REDRAW
cmd = USBCMD_SETMODE
param = 0x02
x0 = 0
y0 = 0
x1 = 1200 - 1
y1 = 1200 - 1
pid = 0
byteseq = struct.pack('<hhhhhhh', cmd, param, x0, y0, x1, y1, pid)
chksum = struct.pack('<H', crc16(byteseq))
byteout = byteseq + chksum
print(byteout)
h.write(byteout)
str_in = h.read(16)
print("Received from HID Device:", str_in, '\n')
def main():
send_cmd()
if __name__ == "__main__":
main()