diff --git a/bsp/rp2040/m_default/bsp-feature.h b/bsp/rp2040/m_default/bsp-feature.h index 7feecac..e059f85 100644 --- a/bsp/rp2040/m_default/bsp-feature.h +++ b/bsp/rp2040/m_default/bsp-feature.h @@ -4,11 +4,10 @@ #define DBOARD_HAS_UART #define DBOARD_HAS_CMSISDAP +// TODO: rename to _SPI #define DBOARD_HAS_SERPROG -// FIXME: this one doesn't work yet!!!!! (kernel usb device cfg fails) -// "usb 1-1: can't set config #1, error -32" -/*#define DBOARD_HAS_I2C*/ -/*#define DBOARD_HAS_TEMPSENSOR*/ +#define DBOARD_HAS_I2C +#define DBOARD_HAS_TEMPSENSOR #include "bsp-info.h" diff --git a/bsp/rp2040/m_default/i2c_tinyusb.c b/bsp/rp2040/m_default/i2c_tinyusb.c index d8b78e0..d7f207b 100644 --- a/bsp/rp2040/m_default/i2c_tinyusb.c +++ b/bsp/rp2040/m_default/i2c_tinyusb.c @@ -381,7 +381,7 @@ static inline int i2cex_read_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10 return i2cex_read_blocking_until(i2c, addr, a10bit, dst, len, nostop, t); } -__attribute__((__const__)) enum ki2c_funcs i2ctu_get_func(void) { +__attribute__((__const__)) enum ki2c_funcs i2ctu_dev_get_func(void) { // TODO: SMBUS_EMUL_ALL => I2C_M_RECV_LEN // TODO: maybe also PROTOCOL_MANGLING, NOSTART return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; diff --git a/src/m_default/_default.c b/src/m_default/_default.c index f6f3bd2..b01ac38 100644 --- a/src/m_default/_default.c +++ b/src/m_default/_default.c @@ -21,6 +21,26 @@ /* CDC-Serprog */ #include "m_default/serprog.h" +/* temperature sensor */ +#include "m_default/tempsensor.h" + +// FIXME: this one doesn't work yet!!!!! (kernel usb device cfg fails) +// "usb 1-1: can't set config #1, error -32" +/*#define MODE_ENABLE_I2CTINYUSB*/ + +enum m_default_cmds { + mdef_cmd_spi = mode_cmd__specific, + mdef_cmd_i2c, + mdef_cmd_tempsense +}; +enum m_default_feature { + mdef_feat_uart = 1<<0, + mdef_feat_cmsisdap = 1<<1, + mdef_feat_spi = 1<<2, + mdef_feat_i2c = 1<<3, + mdef_feat_tempsense = 1<<4, +}; + #ifdef DBOARD_HAS_UART static cothread_t uartthread; static uint8_t uartstack[THREAD_STACK_SIZE]; @@ -94,11 +114,46 @@ static void task_cb(void) { static void handle_cmd_cb(uint8_t cmd) { uint8_t resp = 0; - // TODO: tempsensor control commands! switch (cmd) { case mode_cmd_get_features: +#ifdef DBOARD_HAS_UART + resp |= mdef_feat_uart; +#endif +#ifdef DBOARD_HAS_CMSISDAP + resp |= mdef_feat_cmsisdap; +#endif +#ifdef DBOARD_HAS_SERPROG + resp |= mdef_feat_spi; +#endif +#ifdef DBOARD_HAS_I2C + resp |= mdef_feat_i2c; +#endif +#ifdef DBOARD_HAS_TEMPSENSOR + resp |= mdef_feat_tempsense; +#endif vnd_cfg_write_resp(cfg_resp_ok, 1, &resp); break; + case mdef_cmd_spi: +#ifdef DBOARD_HAS_SERPROG + sp_spi_bulk_cmd(); +#else + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); +#endif + break; + case mdef_cmd_i2c: +#ifdef DBOARD_HAS_I2C + i2ctu_bulk_cmd(); +#else + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); +#endif + break; + case mdef_cmd_tempsense: +#ifdef DBOARD_HAS_TEMPSENSOR + tempsense_bulk_cmd(); +#else + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); +#endif + break; default: vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); break; @@ -129,7 +184,7 @@ enum { #if CFG_TUD_VENDOR > 0 ITF_NUM_VND_CFG, #endif -#ifdef DBOARD_HAS_I2C +#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB) ITF_NUM_VND_I2CTINYUSB, #endif #ifdef DBOARD_HAS_CMSISDAP @@ -156,7 +211,7 @@ enum { #if CFG_TUD_VENDOR > 0 + TUD_VENDOR_DESC_LEN #endif -#ifdef DBOARD_HAS_I2C +#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB) + TUD_I2CTINYUSB_LEN #endif #ifdef DBOARD_HAS_CMSISDAP @@ -213,7 +268,7 @@ static const uint8_t desc_configuration[] = { EPNUM_VND_CFG_IN, 64), #endif -#ifdef DBOARD_HAS_I2C +#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB) TUD_I2CTINYUSB_DESCRIPTOR(ITF_NUM_VND_I2CTINYUSB, STRID_IF_VND_I2CTINYUSB), #endif @@ -288,7 +343,7 @@ static void my_hid_set_report_cb(uint8_t instance, uint8_t report_id, } #endif -#ifdef DBOARD_HAS_I2CTINYUSB +#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB) static bool my_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_control_request_t const* req) { return i2ctu_ctl_req(rhport, ep_addr, req); @@ -318,7 +373,7 @@ struct mode m_01_default = { .tud_hid_descriptor_report_cb = my_hid_descriptor_report_cb, #endif -#if defined(DBOARD_HAS_I2CTINYUSB) +#if defined(DBOARD_HAS_I2C) && defined(MODE_ENABLE_I2CTINYUSB) .tud_vendor_control_xfer_cb = i2ctu_ctl_req, #endif }; diff --git a/src/m_default/cdc_serprog.c b/src/m_default/cdc_serprog.c index ccd481d..ff90598 100644 --- a/src/m_default/cdc_serprog.c +++ b/src/m_default/cdc_serprog.c @@ -11,6 +11,7 @@ #include "info.h" #include "util.h" #include "thread.h" +#include "vnd_cfg.h" #include "serprog.h" @@ -219,5 +220,10 @@ static void handle_cmd(void) { void cdc_serprog_task(void) { handle_cmd(); } +void sp_spi_bulk_cmd(void) { + // TODO + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); +} + #endif /* DBOARD_HAS_SERPROG */ diff --git a/src/m_default/i2ctinyusb.h b/src/m_default/i2ctinyusb.h index fe2fd53..18f7b1b 100644 --- a/src/m_default/i2ctinyusb.h +++ b/src/m_default/i2ctinyusb.h @@ -105,6 +105,7 @@ enum itu_status i2ctu_dev_read(enum ki2c_flags flags, enum itu_command startstop void i2ctu_init(void); void i2ctu_deinit(void); bool i2ctu_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req); +void i2ctu_bulk_cmd(void); /* uses data in/out from vnd_cfg.h */ #endif #endif diff --git a/src/m_default/serprog.h b/src/m_default/serprog.h index dea36f3..7c06bd0 100644 --- a/src/m_default/serprog.h +++ b/src/m_default/serprog.h @@ -59,6 +59,7 @@ static inline void sp_spi_op_do( void cdc_serprog_init(void); void cdc_serprog_deinit(void); void cdc_serprog_task(void); +void sp_spi_bulk_cmd(void); #endif #endif diff --git a/src/m_default/tempsensor.c b/src/m_default/tempsensor.c index 7076f2e..f7230c1 100644 --- a/src/m_default/tempsensor.c +++ b/src/m_default/tempsensor.c @@ -13,6 +13,8 @@ // clang-format on #endif +#include "vnd_cfg.h" + #ifdef DBOARD_HAS_TEMPSENSOR #include "tempsensor.h" @@ -251,5 +253,46 @@ int tempsense_do_write(int length, const uint8_t* buf) { return i; } +void tempsense_bulk_cmd(void) { + uint16_t temp; + uint8_t resp[2]; + + switch (vnd_cfg_read_byte()) { + case tcmd_get_addr: + resp[0] = tempsense_get_addr(); + vnd_cfg_write_resp(cfg_resp_ok, 1, resp); + break; + case tcmd_set_addr: + resp[0] = tempsense_get_addr(); + tempsense_set_addr(vnd_cfg_read_byte()); + resp[1] = tempsense_get_addr(); + vnd_cfg_write_resp(cfg_resp_ok, 2, resp); + break; + case tcmd_get_temp: + temp = tempsense_dev_get_temp(); + resp[0] = temp & 0xff; + resp[1] = (temp >> 8) & 0xff; + vnd_cfg_write_resp(cfg_resp_ok, 2, resp); + case tcmd_get_lower: + temp = tempsense_dev_get_lower(); + resp[0] = temp & 0xff; + resp[1] = (temp >> 8) & 0xff; + vnd_cfg_write_resp(cfg_resp_ok, 2, resp); + case tcmd_get_upper: + temp = tempsense_dev_get_upper(); + resp[0] = temp & 0xff; + resp[1] = (temp >> 8) & 0xff; + vnd_cfg_write_resp(cfg_resp_ok, 2, resp); + case tcmd_get_crit: + temp = tempsense_dev_get_crit(); + resp[0] = temp & 0xff; + resp[1] = (temp >> 8) & 0xff; + vnd_cfg_write_resp(cfg_resp_ok, 2, resp); + default: + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); + break; + } +} + #endif diff --git a/src/m_default/tempsensor.h b/src/m_default/tempsensor.h index 70c0bac..b9127b7 100644 --- a/src/m_default/tempsensor.h +++ b/src/m_default/tempsensor.h @@ -6,6 +6,15 @@ #include #include +enum tempsense_cmd { + tcmd_get_addr, + tcmd_set_addr, + tcmd_get_temp, + tcmd_get_lower, + tcmd_get_upper, + tcmd_get_crit +}; + void tempsense_init(void); void tempsense_deinit(void); @@ -19,6 +28,8 @@ int tempsense_do_read(int length, uint8_t* buf); int tempsense_do_write(int length, const uint8_t* buf); void tempsense_do_stop(void); // stop cond +void tempsense_bulk_cmd(void); + #ifdef DBOARD_HAS_TEMPSENSOR void tempsense_dev_init(void); void tempsense_dev_deinit(void); diff --git a/src/m_default/vnd_i2ctinyusb.c b/src/m_default/vnd_i2ctinyusb.c index 4d27103..4661b28 100644 --- a/src/m_default/vnd_i2ctinyusb.c +++ b/src/m_default/vnd_i2ctinyusb.c @@ -1,3 +1,4 @@ +// vim: set et: #include "m_default/bsp-feature.h" @@ -13,7 +14,7 @@ #include #include -#include "m_default/bsp-feature.h" +#include "vnd_cfg.h" #include "i2ctinyusb.h" @@ -46,6 +47,61 @@ void i2ctu_deinit(void) { #endif } +static void handle_probe(struct itu_cmd* cmd) { + uint8_t bleh = 0; +#ifdef DBOARD_HAS_TEMPSENSOR + if (tempsense_get_active() && tempsense_get_addr() == cmd->addr) { + if (cmd->cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); + int rv = tempsense_do_write(0, &bleh); + if (rv < 0 || rv != cmd->len) + status = ITU_STATUS_ADDR_NAK; + else + status = ITU_STATUS_ADDR_ACK; + if (cmd->cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); + } else +#endif + { + status = i2ctu_dev_write(cmd->flags, cmd->cmd & ITU_CMD_I2C_IO_DIR_MASK, + cmd->addr, &bleh, 0); + } +} +static void handle_read(struct itu_cmd* cmd) { +#ifdef DBOARD_HAS_TEMPSENSOR + if (tempsense_get_active() && tempsense_get_addr() == cmd->addr) { + if (cmd->cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); + int rv = tempsense_do_read( + cmd->len > sizeof txbuf ? sizeof txbuf : cmd->len, txbuf); + if (rv < 0 || rv != cmd->len) + status = ITU_STATUS_ADDR_NAK; + else + status = ITU_STATUS_ADDR_ACK; + if (cmd->cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); + } else +#endif + { + status = i2ctu_dev_read(cmd->flags, cmd->cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd->addr, + txbuf, cmd->len > sizeof txbuf ? sizeof txbuf : cmd->len); + } +} +static void handle_write(struct itu_cmd* cmd) { +#ifdef DBOARD_HAS_TEMPSENSOR + if (tempsense_get_active() && tempsense_get_addr() == cmd->addr) { + if (cmd->cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); + // FIXME: fix status handling + int rv = tempsense_do_write(cmd->len > sizeof rxbuf ? sizeof rxbuf : cmd->len, rxbuf); + if (rv < 0 || rv != cmd->len) + status = ITU_STATUS_ADDR_NAK; + else + status = ITU_STATUS_ADDR_ACK; + if (cmd->cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); + } else +#endif + { + status = i2ctu_dev_write(cmd->flags, cmd->cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd->addr, rxbuf, + cmd->len > sizeof rxbuf ? sizeof rxbuf : cmd->len); + } +} + bool i2ctu_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req) { (void)rhport; @@ -67,22 +123,7 @@ bool i2ctu_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* // printf("WDATA a=%04hx l=%04hx ", cmd.addr, cmd.len); // printf("data=%02x %02x...\n", rxbuf[0], rxbuf[1]); -#ifdef DBOARD_HAS_TEMPSENSOR - if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) { - if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); - // FIXME: fix status handling - int rv = tempsense_do_write(cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len, rxbuf); - if (rv < 0 || rv != cmd.len) - status = ITU_STATUS_ADDR_NAK; - else - status = ITU_STATUS_ADDR_ACK; - if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); - } else -#endif - { - status = i2ctu_dev_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr, rxbuf, - cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len); - } + handle_write(&cmd); // cancel curcmd curcmd.cmd = 0xff; @@ -140,44 +181,14 @@ bool i2ctu_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* if (cmd.flags & I2C_M_RD) { // read from I2C device // printf("read addr=%04hx len=%04hx ", cmd.addr, cmd.len); -#ifdef DBOARD_HAS_TEMPSENSOR - if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) { - if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); - int rv = tempsense_do_read( - cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len, txbuf); - if (rv < 0 || rv != cmd.len) - status = ITU_STATUS_ADDR_NAK; - else - status = ITU_STATUS_ADDR_ACK; - if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); - } else -#endif - { - status = i2ctu_dev_read(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr, - txbuf, cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len); - } + handle_read(&cmd); // printf("data=%02x %02x...\n", txbuf[0], txbuf[1]); return tud_control_xfer( rhport, req, txbuf, cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len); } else { // write // printf("write addr=%04hx len=%04hx ", cmd.addr, cmd.len); if (cmd.len == 0) { // address probe -> do this here - uint8_t bleh = 0; -#ifdef DBOARD_HAS_TEMPSENSOR - if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) { - if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); - int rv = tempsense_do_write(0, &bleh); - if (rv < 0 || rv != cmd.len) - status = ITU_STATUS_ADDR_NAK; - else - status = ITU_STATUS_ADDR_ACK; - if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); - } else -#endif - { - status = i2ctu_dev_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, - cmd.addr, &bleh, 0); - } + handle_probe(&cmd); // printf("probe -> %d\n", status); return tud_control_status(rhport, req); } else { @@ -197,5 +208,77 @@ bool i2ctu_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* return true; // other stage... } +void i2ctu_bulk_cmd(void) { + uint16_t us; + uint32_t func, freq; + + switch (vnd_cfg_read_byte()) { + case ITU_CMD_ECHO: + txbuf[0] = vnd_cfg_read_byte(); + vnd_cfg_write_resp(cfg_resp_ok, 1, txbuf); + break; + case ITU_CMD_GET_FUNC: + func = i2ctu_dev_get_func(); + + txbuf[0] = func & 0xff; + txbuf[1] = (func >> 8) & 0xff; + txbuf[2] = (func >> 16) & 0xff; + txbuf[3] = (func >> 24) & 0xff; + vnd_cfg_write_resp(cfg_resp_ok, 4, txbuf); + break; + case ITU_CMD_SET_DELAY: + us = (uint16_t)vnd_cfg_read_byte(); + us |= ((uint16_t)vnd_cfg_read_byte() << 8); + + if (us == 0) us = 1; + freq = 1000 * 1000 / (uint32_t)us; + + if (i2ctu_dev_set_freq(freq, us) != 0) + vnd_cfg_write_resp(cfg_resp_ok, 0, NULL); + else + vnd_cfg_write_resp(cfg_resp_badarg, 0, NULL); + break; + case ITU_CMD_GET_STATUS: + txbuf[0] = status; + vnd_cfg_write_resp(cfg_resp_ok, 1, txbuf); + break; + case ITU_CMD_I2C_IO: + case ITU_CMD_I2C_IO_BEGIN: + case ITU_CMD_I2C_IO_END: + case ITU_CMD_I2C_IO_BEGINEND: { + struct itu_cmd cmd; + cmd.cmd = vnd_cfg_read_byte(); + cmd.flags = (uint16_t)vnd_cfg_read_byte(); + cmd.flags |= (uint16_t)vnd_cfg_read_byte() << 8; + cmd.addr = (uint16_t)vnd_cfg_read_byte(); + cmd.addr |= (uint16_t)vnd_cfg_read_byte() << 8; + cmd.len = (uint16_t)vnd_cfg_read_byte(); + cmd.len |= (uint16_t)vnd_cfg_read_byte() << 8; + + if (cmd.flags & I2C_M_RD) { + handle_read(&cmd); + us = cmd.len; + if (us > sizeof txbuf) us = sizeof txbuf; + vnd_cfg_write_resp(cfg_resp_ok, us, txbuf); + } else if (cmd.len == 0) { + handle_probe(&cmd); + txbuf[0] = status; + vnd_cfg_write_resp(cfg_resp_ok, 1, txbuf); + } else { + us = cmd.len; + if (us > sizeof rxbuf) us = sizeof rxbuf; + for (size_t i = 0; i < us; ++i) + rxbuf[i] = vnd_cfg_read_byte(); + + handle_write(&cmd); + } + } break; + + default: + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); + break; + } +} + #endif /* DBOARD_HAS_I2C */ diff --git a/src/tusb_plt.S b/src/tusb_plt.S index a90d72c..3c88f51 100644 --- a/src/tusb_plt.S +++ b/src/tusb_plt.S @@ -7,7 +7,7 @@ .global tusb_plt tusb_plt: - @ sigh, thumb... + @ sigh, thumb... (cant do `ldr r12, ...`) .type tud_hid_get_report_cb, %function .global tud_hid_get_report_cb tud_hid_get_report_cb: diff --git a/src/vnd_cfg.h b/src/vnd_cfg.h index 3769a2f..b39a751 100644 --- a/src/vnd_cfg.h +++ b/src/vnd_cfg.h @@ -28,6 +28,8 @@ enum mode_cmd { mode_cmd_get_name = 0x00, mode_cmd_get_version = 0x01, mode_cmd_get_features = 0x02, + + mode_cmd__specific = 0x03 }; enum cfg_resp { @@ -35,6 +37,7 @@ enum cfg_resp { cfg_resp_illcmd = 0x01, cfg_resp_badmode = 0x02, cfg_resp_nosuchmode = 0x03, + cfg_resp_badarg = 0x04 }; uint8_t vnd_cfg_read_byte (void);