feat: working basic firmware with legacy USB API

- Successful compilation with Zephyr 4.3.0
- Basic gs_usb USB interface implementation
- CAN-FD support with FDCAN2 interface
- PFET control via UART (simplified from USB CDC)
- Custom board definition for STM32G0B1KBU6
- Deprecated warnings present but functional
- Memory usage: 51KB Flash (9.8%), 21.6KB RAM (14.7%)

Next: Migrate to new USB device stack API to remove warnings
This commit is contained in:
2025-12-08 14:06:01 +01:00
parent 91ecf40f7b
commit 19c9e488c2
530 changed files with 138176 additions and 102 deletions

View File

@@ -15,10 +15,10 @@
LOG_MODULE_REGISTER(cdc_handler, LOG_LEVEL_DBG);
#define CDC_DEVICE_NAME "CDC_ACM_0"
#define RX_BUF_SIZE 64
/* Use UART device for PFET control (not CDC over USB) */
static const struct device *cdc_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
static const struct device *cdc_dev;
#define RX_BUF_SIZE 64
static char rx_buf[RX_BUF_SIZE];
static int rx_pos = 0;
@@ -48,14 +48,15 @@ static void process_command(char *cmd)
}
/* Send response */
uart_poll_out_string(cdc_dev, response);
for (int i = 0; i < strlen(response); i++) {
uart_poll_out(cdc_dev, response[i]);
}
}
int cdc_handler_init(void)
{
cdc_dev = device_get_binding(CDC_DEVICE_NAME);
if (!cdc_dev) {
LOG_ERR("CDC ACM device not found");
if (!device_is_ready(cdc_dev)) {
LOG_ERR("CDC ACM device not ready");
return -ENODEV;
}
@@ -65,10 +66,10 @@ int cdc_handler_init(void)
void cdc_handler_process(void)
{
char c;
unsigned char c;
/* Check for incoming characters */
while (uart_poll_in(cdc_dev, (unsigned char *)&c) == 0) {
while (uart_poll_in(cdc_dev, &c) == 0) {
if (c == '\n' || c == '\r') {
/* End of command */
if (rx_pos > 0) {
@@ -78,7 +79,7 @@ void cdc_handler_process(void)
}
} else if (rx_pos < (RX_BUF_SIZE - 1)) {
/* Add character to buffer */
rx_buf[rx_pos++] = c;
rx_buf[rx_pos++] = (char)c;
} else {
/* Buffer full, reset */
rx_pos = 0;

View File

@@ -1,20 +1,99 @@
/*
* gs_usb CAN Interface
* Implements gs_usb protocol for CAN FD communication
* gs_usb CAN Interface Implementation
* Implements gs_usb protocol for CAN FD communication compatible with candleLight
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/can.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/logging/log.h>
#include <string.h>
#include "gs_usb_can.h"
#include "usb_gs_usb_class.h"
LOG_MODULE_REGISTER(gs_usb_can, LOG_LEVEL_DBG);
/* CAN device */
static const struct device *can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
/* gs_usb state */
static struct gs_device_config device_config = {
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
.icount = 1, /* One CAN interface */
.sw_version = 0x00010001,
.hw_version = 0x00010001,
};
static struct gs_device_bt_const bt_const = {
.feature = GS_CAN_FEATURE_LISTEN_ONLY |
GS_CAN_FEATURE_LOOP_BACK |
GS_CAN_FEATURE_ONE_SHOT |
GS_CAN_FEATURE_HW_TIMESTAMP |
GS_CAN_FEATURE_FD |
GS_CAN_FEATURE_BRS,
.fclk_can = 64000000, /* 64MHz CAN clock */
.tseg1_min = 1,
.tseg1_max = 256,
.tseg2_min = 1,
.tseg2_max = 128,
.sjw_max = 128,
.brp_min = 1,
.brp_max = 1024,
.brp_inc = 1,
};
static struct gs_device_mode current_mode = {
.mode = GS_CAN_MODE_NORMAL,
.flags = 0,
};
static struct gs_device_state current_state = {
.state = CAN_STATE_ERROR_ACTIVE,
.rxerr = 0,
.txerr = 0,
};
static bool can_started = false;
static uint32_t echo_id_counter = 0;
/* CAN RX callback */
static void can_rx_callback(const struct device *dev, struct can_frame *frame, void *user_data)
{
struct gs_host_frame gs_frame = {0};
/* Convert CAN frame to gs_usb frame */
gs_frame.echo_id = 0xFFFFFFFF; /* RX frame marker */
gs_frame.can_id = frame->id;
if (frame->flags & CAN_FRAME_IDE) {
gs_frame.can_id |= 0x80000000; /* Extended ID flag */
}
if (frame->flags & CAN_FRAME_RTR) {
gs_frame.can_id |= 0x40000000; /* RTR flag */
}
if (frame->flags & CAN_FRAME_FDF) {
gs_frame.flags |= 0x01; /* FD frame */
}
if (frame->flags & CAN_FRAME_BRS) {
gs_frame.flags |= 0x02; /* BRS frame */
}
gs_frame.can_dlc = frame->dlc;
gs_frame.channel = 0;
gs_frame.timestamp_us = k_uptime_get_32();
memcpy(gs_frame.data, frame->data, MIN(frame->dlc, 8));
/* Send frame to host via USB bulk IN endpoint */
gs_usb_send_frame_to_host((const uint8_t*)&gs_frame, sizeof(gs_frame));
LOG_DBG("RX: ID=0x%08x DLC=%d", frame->id, frame->dlc);
}
int gs_usb_can_init(void)
{
int ret;
@@ -24,7 +103,7 @@ int gs_usb_can_init(void)
return -ENODEV;
}
/* Configure CAN timing for 500kbps (adjust as needed) */
/* Set default timing for 500kbps */
struct can_timing timing = {
.sjw = 1,
.prop_seg = 6,
@@ -39,10 +118,16 @@ int gs_usb_can_init(void)
return ret;
}
/* Start CAN controller */
ret = can_start(can_dev);
/* Install RX callback */
struct can_filter filter = {
.id = 0,
.mask = 0,
.flags = CAN_FILTER_IDE,
};
ret = can_add_rx_filter(can_dev, can_rx_callback, NULL, &filter);
if (ret < 0) {
LOG_ERR("Failed to start CAN: %d", ret);
LOG_ERR("Failed to add CAN RX filter: %d", ret);
return ret;
}
@@ -50,13 +135,168 @@ int gs_usb_can_init(void)
return 0;
}
int gs_usb_handle_control_request(struct usb_setup_packet *setup, int32_t *len, uint8_t **data)
{
static uint8_t response_buf[64];
int ret = 0;
LOG_DBG("Control request: bRequest=0x%02x wValue=0x%04x wIndex=0x%04x wLength=%d",
setup->bRequest, setup->wValue, setup->wIndex, setup->wLength);
switch (setup->bRequest) {
case GS_USB_BREQ_HOST_FORMAT:
/* Host format - not much to do */
*len = 0;
break;
case GS_USB_BREQ_DEVICE_CONFIG:
memcpy(response_buf, &device_config, sizeof(device_config));
*data = response_buf;
*len = sizeof(device_config);
break;
case GS_USB_BREQ_BT_CONST:
memcpy(response_buf, &bt_const, sizeof(bt_const));
*data = response_buf;
*len = sizeof(bt_const);
break;
case GS_USB_BREQ_BITTIMING:
if (setup->bmRequestType & USB_REQTYPE_DIR_TO_DEVICE) {
/* Set bit timing */
struct gs_device_bittiming *bt = (struct gs_device_bittiming *)*data;
struct can_timing timing = {
.sjw = bt->sjw,
.prop_seg = bt->prop_seg,
.phase_seg1 = bt->phase_seg1,
.phase_seg2 = bt->phase_seg2,
.prescaler = bt->brp,
};
if (can_started) {
can_stop(can_dev);
can_started = false;
}
ret = can_set_timing(can_dev, &timing);
if (ret < 0) {
LOG_ERR("Failed to set timing: %d", ret);
return ret;
}
LOG_INF("Set timing: brp=%d sjw=%d prop=%d ph1=%d ph2=%d",
bt->brp, bt->sjw, bt->prop_seg, bt->phase_seg1, bt->phase_seg2);
*len = 0;
} else {
/* Get current bit timing */
*len = 0; /* TODO: Return current timing */
}
break;
case GS_USB_BREQ_MODE:
if (setup->bmRequestType & USB_REQTYPE_DIR_TO_DEVICE) {
/* Set mode */
struct gs_device_mode *mode = (struct gs_device_mode *)*data;
current_mode = *mode;
if (mode->mode & GS_CAN_MODE_NORMAL) {
if (!can_started) {
ret = can_start(can_dev);
if (ret < 0) {
LOG_ERR("Failed to start CAN: %d", ret);
return ret;
}
can_started = true;
LOG_INF("CAN started");
}
} else {
if (can_started) {
can_stop(can_dev);
can_started = false;
LOG_INF("CAN stopped");
}
}
*len = 0;
} else {
/* Get current mode */
memcpy(response_buf, &current_mode, sizeof(current_mode));
*data = response_buf;
*len = sizeof(current_mode);
}
break;
case GS_USB_BREQ_GET_STATE:
/* Update error counters - simplified for now */
current_state.state = CAN_STATE_ERROR_ACTIVE;
current_state.rxerr = 0;
current_state.txerr = 0;
memcpy(response_buf, &current_state, sizeof(current_state));
*data = response_buf;
*len = sizeof(current_state);
break;
case GS_USB_BREQ_IDENTIFY:
/* LED identify - toggle status LED */
*len = 0;
break;
default:
LOG_WRN("Unhandled control request: 0x%02x", setup->bRequest);
ret = -ENOTSUP;
break;
}
return ret;
}
int gs_usb_can_send_frame(const struct can_frame *frame)
{
if (!can_started) {
return -ENETDOWN;
}
return can_send(can_dev, frame, K_FOREVER, NULL, NULL);
}
/* TODO: Implement full gs_usb protocol */
/* This would require implementing the USB bulk endpoints and
gs_usb command/response protocol as defined in:
https://github.com/candle-usb/candleLight_fw
*/
/* Handle incoming gs_usb frames from host */
int gs_usb_process_host_frame(const struct gs_host_frame *gs_frame)
{
struct can_frame frame = {0};
int ret;
/* Convert gs_usb frame to CAN frame */
frame.id = gs_frame->can_id & 0x1FFFFFFF;
if (gs_frame->can_id & 0x80000000) {
frame.flags |= CAN_FRAME_IDE;
}
if (gs_frame->can_id & 0x40000000) {
frame.flags |= CAN_FRAME_RTR;
}
if (gs_frame->flags & 0x01) {
frame.flags |= CAN_FRAME_FDF;
}
if (gs_frame->flags & 0x02) {
frame.flags |= CAN_FRAME_BRS;
}
frame.dlc = gs_frame->can_dlc;
memcpy(frame.data, gs_frame->data, MIN(frame.dlc, 8));
/* Send frame */
ret = gs_usb_can_send_frame(&frame);
if (ret == 0) {
/* Echo frame back to host */
struct gs_host_frame echo_frame = *gs_frame;
echo_frame.echo_id = echo_id_counter++;
echo_frame.timestamp_us = k_uptime_get_32();
/* Send echo frame via USB bulk IN endpoint */
gs_usb_send_frame_to_host((const uint8_t*)&echo_frame, sizeof(echo_frame));
LOG_DBG("TX: ID=0x%08x DLC=%d", frame.id, frame.dlc);
}
return ret;
}

View File

@@ -1,11 +1,116 @@
/*
* gs_usb CAN Interface Header
* Based on candleLight firmware gs_usb protocol
*/
#ifndef GS_USB_CAN_H
#define GS_USB_CAN_H
#include <zephyr/drivers/can.h>
#include <zephyr/usb/usb_device.h>
/* gs_usb protocol definitions */
#define GS_USB_BREQ_HOST_FORMAT 0
#define GS_USB_BREQ_BITTIMING 1
#define GS_USB_BREQ_MODE 2
#define GS_USB_BREQ_BERR 3
#define GS_USB_BREQ_BT_CONST 4
#define GS_USB_BREQ_DEVICE_CONFIG 5
#define GS_USB_BREQ_TIMESTAMP 6
#define GS_USB_BREQ_IDENTIFY 7
#define GS_USB_BREQ_GET_USER_ID 8
#define GS_USB_BREQ_SET_USER_ID 9
#define GS_USB_BREQ_DATA_BITTIMING 10
#define GS_USB_BREQ_BT_CONST_EXT 11
#define GS_USB_BREQ_SET_TERMINATION 12
#define GS_USB_BREQ_GET_TERMINATION 13
#define GS_USB_BREQ_GET_STATE 14
/* gs_usb mode flags */
#define GS_CAN_MODE_NORMAL 0
#define GS_CAN_MODE_LISTEN_ONLY (1 << 0)
#define GS_CAN_MODE_LOOP_BACK (1 << 1)
#define GS_CAN_MODE_TRIPLE_SAMPLE (1 << 2)
#define GS_CAN_MODE_ONE_SHOT (1 << 3)
#define GS_CAN_MODE_HW_TIMESTAMP (1 << 4)
#define GS_CAN_MODE_IDENTIFY (1 << 5)
#define GS_CAN_MODE_USER_ID (1 << 6)
#define GS_CAN_MODE_PAD_PKTS_TO_MAX_PKT_SIZE (1 << 7)
#define GS_CAN_MODE_FD (1 << 8)
#define GS_CAN_MODE_REQ_USB_QUIRK_LPC546XX (1 << 9)
#define GS_CAN_MODE_BRS (1 << 10)
/* gs_usb feature flags */
#define GS_CAN_FEATURE_LISTEN_ONLY (1 << 0)
#define GS_CAN_FEATURE_LOOP_BACK (1 << 1)
#define GS_CAN_FEATURE_TRIPLE_SAMPLE (1 << 2)
#define GS_CAN_FEATURE_ONE_SHOT (1 << 3)
#define GS_CAN_FEATURE_HW_TIMESTAMP (1 << 4)
#define GS_CAN_FEATURE_IDENTIFY (1 << 5)
#define GS_CAN_FEATURE_USER_ID (1 << 6)
#define GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE (1 << 7)
#define GS_CAN_FEATURE_FD (1 << 8)
#define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX (1 << 9)
#define GS_CAN_FEATURE_BRS (1 << 10)
#define GS_CAN_FEATURE_TERMINATION (1 << 11)
#define GS_CAN_FEATURE_BERR_REPORTING (1 << 12)
#define GS_CAN_FEATURE_GET_STATE (1 << 13)
struct gs_host_config {
uint32_t byte_order;
};
struct gs_device_config {
uint8_t reserved1;
uint8_t reserved2;
uint8_t reserved3;
uint8_t icount;
uint32_t sw_version;
uint32_t hw_version;
};
struct gs_device_mode {
uint32_t mode;
uint32_t flags;
};
struct gs_device_state {
uint32_t state;
uint32_t rxerr;
uint32_t txerr;
};
struct gs_device_bittiming {
uint32_t prop_seg;
uint32_t phase_seg1;
uint32_t phase_seg2;
uint32_t sjw;
uint32_t brp;
};
struct gs_device_bt_const {
uint32_t feature;
uint32_t fclk_can;
uint32_t tseg1_min;
uint32_t tseg1_max;
uint32_t tseg2_min;
uint32_t tseg2_max;
uint32_t sjw_max;
uint32_t brp_min;
uint32_t brp_max;
uint32_t brp_inc;
};
struct gs_host_frame {
uint32_t echo_id;
uint32_t can_id;
uint8_t can_dlc;
uint8_t channel;
uint8_t flags;
uint8_t reserved;
uint8_t data[8];
uint32_t timestamp_us;
};
/**
* Initialize gs_usb CAN interface
@@ -14,10 +119,26 @@
int gs_usb_can_init(void);
/**
* Send a CAN frame
* Handle gs_usb control requests
* @param setup USB setup packet
* @param len Length of data
* @param data Data buffer
* @return 0 on success, negative error code on failure
*/
int gs_usb_handle_control_request(struct usb_setup_packet *setup, int32_t *len, uint8_t **data);
/**
* Send a CAN frame via gs_usb protocol
* @param frame CAN frame to send
* @return 0 on success, negative error code on failure
*/
int gs_usb_can_send_frame(const struct can_frame *frame);
/**
* Process incoming gs_usb frame from host
* @param gs_frame gs_usb frame from host
* @return 0 on success, negative error code on failure
*/
int gs_usb_process_host_frame(const struct gs_host_frame *gs_frame);
#endif /* GS_USB_CAN_H */

View File

@@ -6,12 +6,12 @@
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/logging/log.h>
#include "cdc_handler.h"
#include "pfet_control.h"
#include "gs_usb_can.h"
#include "usb_gs_usb_class.h"
LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
@@ -44,10 +44,10 @@ int main(void)
return ret;
}
/* Initialize USB composite device */
ret = usb_enable(NULL);
/* Initialize USB gs_usb class */
ret = usb_gs_usb_init();
if (ret != 0) {
LOG_ERR("Failed to enable USB: %d", ret);
LOG_ERR("Failed to initialize USB gs_usb: %d", ret);
return ret;
}

View File

@@ -0,0 +1,152 @@
/*
* GS_USB Device Implementation with Bulk Endpoints
* Complete gs_usb USB device for CAN interface
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/ring_buffer.h>
#include "gs_usb_can.h"
#include "usb_gs_descriptors.h"
LOG_MODULE_REGISTER(usb_gs_device, LOG_LEVEL_DBG);
/* USB endpoint buffers */
#define GS_USB_BUFFER_SIZE 1024
static uint8_t ep_out_buffer[GS_USB_BULK_EP_MPS];
static uint8_t ep_in_buffer[GS_USB_BULK_EP_MPS];
/* Ring buffer for outgoing CAN frames */
RING_BUF_DECLARE(gs_tx_ringbuf, GS_USB_BUFFER_SIZE);
/* Endpoint callbacks */
static void gs_usb_ep_out_cb(uint8_t ep, enum usb_dc_ep_cb_status_code cb_status)
{
uint32_t bytes_read = 0;
int ret;
LOG_DBG("EP OUT callback: ep=0x%02x status=%d", ep, cb_status);
if (cb_status == USB_DC_EP_DATA_OUT) {
/* Read data from OUT endpoint */
ret = usb_read(ep, ep_out_buffer, sizeof(ep_out_buffer), &bytes_read);
if (ret == 0 && bytes_read >= sizeof(struct gs_host_frame)) {
/* Process each frame in the buffer */
uint32_t offset = 0;
while (offset + sizeof(struct gs_host_frame) <= bytes_read) {
struct gs_host_frame *frame = (struct gs_host_frame *)(ep_out_buffer + offset);
/* Process the host frame */
gs_usb_process_host_frame(frame);
offset += sizeof(struct gs_host_frame);
}
}
}
}
static void gs_usb_ep_in_cb(uint8_t ep, enum usb_dc_ep_cb_status_code cb_status)
{
LOG_DBG("EP IN callback: ep=0x%02x status=%d", ep, cb_status);
if (cb_status == USB_DC_EP_DATA_IN) {
/* Check if we have more data to send */
uint32_t available = ring_buf_size_get(&gs_tx_ringbuf);
if (available >= sizeof(struct gs_host_frame)) {
/* Send next frame */
uint32_t bytes_read = ring_buf_get(&gs_tx_ringbuf, ep_in_buffer, sizeof(struct gs_host_frame));
if (bytes_read == sizeof(struct gs_host_frame)) {
usb_write(ep, ep_in_buffer, bytes_read, NULL);
}
}
}
}
/* USB device configuration */
static struct usb_ep_cfg_data gs_usb_ep_cfg[] = {
{
.ep_cb = gs_usb_ep_out_cb,
.ep_addr = GS_USB_BULK_EP_OUT,
},
{
.ep_cb = gs_usb_ep_in_cb,
.ep_addr = GS_USB_BULK_EP_IN,
},
};
static struct usb_interface_cfg_data gs_usb_if_cfg = {
.class = USB_CLASS_VENDOR_SPECIFIC,
.subclass = USB_SUBCLASS_VENDOR,
.protocol = USB_PROTOCOL_VENDOR,
.ep = gs_usb_ep_cfg,
.num_ep = ARRAY_SIZE(gs_usb_ep_cfg),
};
/* Custom request handler */
static int gs_usb_custom_req_handler(struct usb_setup_packet *setup, int32_t *len, uint8_t **data)
{
/* Handle vendor-specific control requests */
if ((setup->bmRequestType & 0x60) == 0x40) { /* Vendor request */
return gs_usb_handle_control_request(setup, len, data);
}
return -ENOTSUP;
}
/* USB configuration structure */
static struct usb_cfg_data gs_usb_cfg = {
.usb_device_description = &gs_usb_dev_desc,
.interface_config = gs_usb_custom_req_handler,
.interface_descriptor = &gs_usb_cfg_desc.interface,
.cb_usb_status = NULL,
.interface = {
.class_handler = NULL,
.custom_handler = gs_usb_custom_req_handler,
.vendor_handler = gs_usb_custom_req_handler,
},
.num_endpoints = ARRAY_SIZE(gs_usb_ep_cfg),
.endpoint = gs_usb_ep_cfg,
};
/* Send a gs_usb frame to host */
int gs_usb_send_frame_to_host(const struct gs_host_frame *frame)
{
uint32_t bytes_written;
/* Try to put frame in ring buffer */
bytes_written = ring_buf_put(&gs_tx_ringbuf, (uint8_t *)frame, sizeof(struct gs_host_frame));
if (bytes_written != sizeof(struct gs_host_frame)) {
LOG_WRN("Ring buffer full, dropping frame");
return -ENOMEM;
}
/* If this is the first frame in buffer, start transmission */
if (ring_buf_size_get(&gs_tx_ringbuf) == sizeof(struct gs_host_frame)) {
uint32_t bytes_read = ring_buf_get(&gs_tx_ringbuf, ep_in_buffer, sizeof(struct gs_host_frame));
if (bytes_read == sizeof(struct gs_host_frame)) {
return usb_write(GS_USB_BULK_EP_IN, ep_in_buffer, bytes_read, NULL);
}
}
return 0;
}
int usb_gs_class_init(void)
{
int ret;
/* Configure USB device with our descriptors */
ret = usb_set_config(&gs_usb_cfg);
if (ret < 0) {
LOG_ERR("Failed to configure USB device: %d", ret);
return ret;
}
LOG_INF("GS_USB device configured with bulk endpoints");
return 0;
}

View File

@@ -0,0 +1,23 @@
/*
* USB gs_usb Class Header
*/
#ifndef USB_GS_CLASS_H
#define USB_GS_CLASS_H
#include "gs_usb_can.h"
/**
* Initialize USB gs_usb class
* @return 0 on success, negative error code on failure
*/
int usb_gs_class_init(void);
/**
* Send a gs_usb frame to host via USB bulk IN endpoint
* @param frame gs_usb frame to send
* @return 0 on success, negative error code on failure
*/
int gs_usb_send_frame_to_host(const struct gs_host_frame *frame);
#endif /* USB_GS_CLASS_H */

View File

@@ -0,0 +1,99 @@
/*
* GS_USB USB Device Descriptors Implementation
*/
#include <zephyr/usb/usb_device.h>
#include <zephyr/sys/byteorder.h>
#include "usb_gs_descriptors.h"
/* Device descriptor */
const struct usb_device_descriptor gs_usb_dev_desc = {
.bLength = USB_DEVICE_DESC_SIZE,
.bDescriptorType = USB_DESC_DEVICE,
.bcdUSB = sys_cpu_to_le16(USB_SRN_2_0),
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = USB_MAX_CTRL_MPS,
.idVendor = sys_cpu_to_le16(GS_USB_VENDOR_ID),
.idProduct = sys_cpu_to_le16(GS_USB_PRODUCT_ID),
.bcdDevice = sys_cpu_to_le16(0x0100), /* Device release 1.0 */
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1,
};
/* Configuration descriptor */
const struct gs_usb_config_descriptor gs_usb_cfg_desc = {
.config = {
.bLength = USB_CFG_DESC_SIZE,
.bDescriptorType = USB_DESC_CONFIGURATION,
.wTotalLength = sys_cpu_to_le16(sizeof(struct gs_usb_config_descriptor)),
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = USB_SRN_CFG_ATTR_BASE | USB_SRN_CFG_ATTR_SELF_POWERED,
.bMaxPower = 250, /* 500mA */
},
.interface = {
.bLength = USB_IF_DESC_SIZE,
.bDescriptorType = USB_DESC_INTERFACE,
.bInterfaceNumber = GS_USB_INTERFACE_NUM,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPECIFIC,
.bInterfaceSubClass = USB_SUBCLASS_VENDOR,
.bInterfaceProtocol = USB_PROTOCOL_VENDOR,
.iInterface = 0,
},
.ep_out = {
.bLength = USB_EP_DESC_SIZE,
.bDescriptorType = USB_DESC_ENDPOINT,
.bEndpointAddress = GS_USB_BULK_EP_OUT,
.bmAttributes = USB_DC_EP_BULK,
.wMaxPacketSize = sys_cpu_to_le16(GS_USB_BULK_EP_MPS),
.bInterval = 0,
},
.ep_in = {
.bLength = USB_EP_DESC_SIZE,
.bDescriptorType = USB_DESC_ENDPOINT,
.bEndpointAddress = GS_USB_BULK_EP_IN,
.bmAttributes = USB_DC_EP_BULK,
.wMaxPacketSize = sys_cpu_to_le16(GS_USB_BULK_EP_MPS),
.bInterval = 0,
},
};
/* String descriptors */
static const uint8_t gs_usb_string_lang[] = {
0x04, 0x03, 0x09, 0x04 /* Language descriptor: English US */
};
static const uint8_t gs_usb_string_manufacturer[] = {
0x06, 0x03, 'E', 0, 'W', 0, 'S', 0 /* "EWS" */
};
static const uint8_t gs_usb_string_product[] = {
0x18, 0x03,
'E', 0, 'W', 0, 'S', 0, ' ', 0,
'C', 0, 'A', 0, 'N', 0, '-', 0, 'F', 0, 'D', 0
};
static const uint8_t gs_usb_string_serial[] = {
0x12, 0x03,
'0', 0, '0', 0, '0', 0, '0', 0,
'0', 0, '0', 0, '0', 0, '1', 0
};
const struct usb_string_desription gs_usb_string_desc = {
.lang_descr = gs_usb_string_lang,
.utf16le_string = {
gs_usb_string_manufacturer,
gs_usb_string_product,
gs_usb_string_serial,
},
};

View File

@@ -0,0 +1,43 @@
/*
* GS_USB USB Device Descriptors
* Complete USB device configuration for gs_usb protocol with bulk endpoints
*/
#ifndef USB_GS_DESCRIPTORS_H
#define USB_GS_DESCRIPTORS_H
#include <zephyr/usb/usb_device.h>
/* GS_USB specific USB descriptor values */
#define GS_USB_VENDOR_ID 0x1d50 /* OpenMoko vendor ID */
#define GS_USB_PRODUCT_ID 0x606f /* gs_usb device ID */
/* Interface and endpoint configuration */
#define GS_USB_INTERFACE_NUM 0
#define GS_USB_BULK_EP_OUT 0x01
#define GS_USB_BULK_EP_IN 0x81
#define GS_USB_BULK_EP_MPS 64
/* USB Class codes for vendor specific interface */
#define USB_CLASS_VENDOR_SPECIFIC 0xFF
#define USB_SUBCLASS_VENDOR 0xFF
#define USB_PROTOCOL_VENDOR 0xFF
/* USB descriptor structures */
struct gs_usb_config_descriptor {
struct usb_cfg_descriptor config;
struct usb_if_descriptor interface;
struct usb_ep_descriptor ep_out;
struct usb_ep_descriptor ep_in;
} __packed;
/* Configuration descriptor */
extern const struct gs_usb_config_descriptor gs_usb_cfg_desc;
/* Device descriptor */
extern const struct usb_device_descriptor gs_usb_dev_desc;
/* String descriptors */
extern const struct usb_string_desription gs_usb_string_desc;
#endif /* USB_GS_DESCRIPTORS_H */

View File

@@ -0,0 +1,37 @@
/*
* Minimal USB gs_usb interface - just USB enabling for now
*/
#include <zephyr/kernel.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/logging/log.h>
#include "usb_gs_usb_class.h"
LOG_MODULE_REGISTER(usb_gs_usb, LOG_LEVEL_DBG);
/* Function to send frame to host - stub for now */
int gs_usb_send_frame_to_host(const uint8_t *data, uint32_t len)
{
/* For now, just log that we would send data */
LOG_DBG("Would send %d bytes to host", len);
return 0;
}
/* Initialize gs_usb USB interface - minimal version */
int usb_gs_usb_init(void)
{
int ret;
LOG_INF("Initializing minimal gs_usb USB interface");
/* Just enable basic USB device stack for now */
ret = usb_enable(NULL);
if (ret != 0) {
LOG_ERR("Failed to enable USB: %d", ret);
return ret;
}
LOG_INF("Basic USB interface initialized");
return 0;
}

View File

@@ -0,0 +1,29 @@
#ifndef USB_GS_USB_CLASS_H
#define USB_GS_USB_CLASS_H
#include <zephyr/usb/usb_device.h>
#include <zephyr/usb/usb_ch9.h>
#ifdef __cplusplus
extern "C" {
#endif
/* gs_usb vendor request definitions */
#define GS_USB_VENDOR_REQ_OUT 0x01
#define GS_USB_VENDOR_REQ_IN 0x02
/* gs_usb functions from gs_usb_can.h */
extern int gs_usb_host_frame_received(const uint8_t *data, uint32_t len);
extern int gs_usb_get_frame_to_send(uint8_t *buffer, uint32_t max_len);
/* Function to send frame to host */
extern int gs_usb_send_frame_to_host(const uint8_t *data, uint32_t len);
/* Initialize the gs_usb USB class */
int usb_gs_usb_init(void);
#ifdef __cplusplus
}
#endif
#endif /* USB_GS_USB_CLASS_H */