This commit is contained in:
Your Name
2026-07-27 15:09:32 +03:00
commit fa89c89fbe
21 changed files with 1043 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
build
tmp
boards
+24
View File
@@ -0,0 +1,24 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug with pyOCD (RP2350)",
"type": "cortex-debug",
"request": "launch",
"servertype": "pyocd",
"serverpath": "${workspaceFolder}/../venv/bin/pyocd",
"cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/build/zephyr/zephyr.elf",
"interface": "swd",
"runToEntryPoint": "main",
// "preLaunchTask": "build",
"armToolchainPath": "/usr/bin",
"gdbPath": "/usr/bin/arm-none-eabi-gdb",
"serverArgs": [
"--target=rp2350",
"--core=0"
],
"showDevDebugOutput": "raw"
}
]
}
+10
View File
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(usb_commands)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
+60
View File
@@ -0,0 +1,60 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
source "Kconfig.zephyr"
menu "USB options"
depends on USB_DEVICE_STACK_NEXT
config USBD_MANUFACTURER
string "USB device manufacturer string"
default "Zephyr Project"
help
USB device manufacturer string.
config USBD_PRODUCT
string "USB device product string"
default "USBD"
help
USB device product stringa.
config USBD_VID
hex "USB device Vendor ID"
default 0x2fe3
help
USB device Vendor ID. The default id (0x2fe3) is associated to
Zephyr Project, you must use your own VID and applications
outside of Zephyr Project.
config USBD_PID
hex "USB device Product ID"
default 0x0001
help
USB device Product ID. You must use your own PID
and applications outside of Zephyr Project.
config USBD_SELF_POWERED
bool "USB device Self-powered attribute"
default y
help
Set the Self-powered attribute in the configuration.
config USBD_REMOTE_WAKEUP
bool "USB device Remote Wakeup attribute"
help
Set the Remote Wakeup attribute in the configuration.
config USBD_MAX_POWER
int "USB device bMaxPower value"
default 125
range 0 250
help
bMaxPower value in the configuration in 2 mA units.
config USBD_20_EXTENSION_DESC
bool "Use default USB 2.0 Extension Descriptor"
depends on USBD_BOS_SUPPORT
help
Set bcdUSB value to 0201 and use default USB 2.0 Extension Descriptor.
endmenu
+52
View File
@@ -0,0 +1,52 @@
# Zephyr USB Command Handler
This repository contains the implementation of a USB command handler for the Zephyr RTOS. The system allows devices to communicate via USB using custom command messages.
### Components
1. **command_handler.c/h**: Handles incoming commands, processes them, and performs actions based on the command type.
2. **command_message.c/h**: Manages the creation, validation, and logging of command messages, including CRC calculation.
3. **usb.c/h**: Manages USB initialization, data reception via UART, and sending responses. Includes a USB thread.
4. **usb_conf.c/h**: Configures the USB device.
### Command Structure
```c
struct command_message_t {
uint8_t prefix; // 0x69
uint8_t length;
uint8_t id;
uint8_t command;
uint8_t crc;
uint8_t data[160];
} __attribute__((packed));
```
### CRC Calculation Function
```c
uint8_t calculate_crc(struct command_message_t *msg) {
uint32_t sum = 0;
uint8_t crc = 0;
uint8_t *byte_ptr = (uint8_t *)msg;
for (int i = 0; i < (sizeof(struct command_message_t) - sizeof(msg->data) + msg->length) - 1; i++) {
sum += byte_ptr[i];
}
crc = 0x100 - (sum & 0xff);
return crc;
}
```
### Python test script (AI generated)
**Command Usage:**
```bash
python3 scripts/led_blink.py
```
This script sends LED toggle commands to the device connected via USB.
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
chosen {
zephyr,console = &cdc_acm_uart0;
zephyr,shell-uart = &cdc_acm_uart0;
};
};
&zephyr_udc0 {
cdc_acm_uart0: cdc_acm_uart0 {
compatible = "zephyr,cdc-acm-uart";
};
};
+33
View File
@@ -0,0 +1,33 @@
CONFIG_GPIO=y
CONFIG_PWM=y
# Serial
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_UART_LINE_CTRL=y
# USB
CONFIG_USB_DEVICE_STACK_NEXT=y
CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n
# CONFIG_CDC_ACM_SERIAL_PRODUCT_STRING="USB CDC ACM"
# CONFIG_CDC_ACM_SERIAL_PID=
CONFIG_USBD_VID=0xffff
CONFIG_USBD_PID=0x0420
CONFIG_USBD_MANUFACTURER="Zephyr Project"
CONFIG_USBD_PRODUCT="USBD sample"
CONFIG_USBD_SELF_POWERED=y
# CONFIG_USBD_REMOTE_WAKEUP=
CONFIG_USBD_MAX_POWER=125
# LOG
CONFIG_LOG=y
CONFIG_USBD_CDC_ACM_LOG_LEVEL_OFF=y # This removes a pointless warning
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_LOG_MODE_IMMEDIATE=y
# CONFIG_USBD_LOG_LEVEL_ERR=y
# CONFIG_UDC_DRIVER_LOG_LEVEL_ERR=y
# DEBUG
CONFIG_DEBUG_THREAD_INFO=y
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
import serial
import struct
import threading
import time
PORT = "/dev/ttyACM0"
BAUDRATE = 115200
COMMAND_PREFIX = 0x69
COMMAND_ERROR = 0
COMMAND_ACK = 1
COMMAND_NACK = 2
LED = 3
DEVICE_ID = 0
def calculate_crc(msg: bytes) -> int:
s = sum(msg) & 0xFF
return (-s) & 0xFF
def make_packet(command: int, data: bytes = b"") -> bytes:
length = len(data)
pkt = bytearray()
pkt.append(COMMAND_PREFIX)
pkt.append(length)
pkt.append(DEVICE_ID)
pkt.append(command)
pkt.append(0) # CRC placeholder
pkt.extend(data)
pkt[4] = calculate_crc(pkt[:4] + pkt[5:])
return bytes(pkt)
def verify_crc(packet: bytes) -> bool:
crc = packet[4]
calc = calculate_crc(packet[:4] + packet[5:])
return crc == calc
def packet_size(buf: bytes):
if len(buf) < 2:
return None
return 5 + buf[1]
def reader(ser):
rx = bytearray()
while True:
data = ser.read(64)
if not data:
continue
rx.extend(data)
while rx:
# Binary packet?
if rx[0] == COMMAND_PREFIX:
size = packet_size(rx)
if size is None or len(rx) < size:
break
pkt = bytes(rx[:size])
del rx[:size]
if not verify_crc(pkt):
print("RX: Bad CRC:", pkt.hex())
continue
length = pkt[1]
dev_id = pkt[2]
cmd = pkt[3]
if cmd == COMMAND_ACK:
print(f"<-- ACK (device={dev_id})")
elif cmd == COMMAND_NACK:
print(f"<-- NACK (device={dev_id})")
elif cmd == COMMAND_ERROR:
print(f"<-- ERROR (device={dev_id})")
else:
print(f"<-- Command {cmd} len={length}")
else:
# ASCII log output
idx = rx.find(b'\n')
if idx == -1:
break
line = rx[:idx + 1]
del rx[:idx + 1]
try:
print("[LOG]", line.decode().rstrip())
except UnicodeDecodeError:
print("[RAW]", line.hex())
def main():
ser = serial.Serial(PORT, BAUDRATE, timeout=0.05)
threading.Thread(target=reader, args=(ser,), daemon=True).start()
for i in range(10):
print(f"--> Sending LED command {i + 1}")
ser.write(make_packet(LED))
time.sleep(0.5)
print("Done.")
time.sleep(2)
if __name__ == "__main__":
main()
+35
View File
@@ -0,0 +1,35 @@
#include "command_handler.h"
#include "led.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(command_handler, LOG_LEVEL_INF);
int command_handler(struct command_message_t *msg) {
if (msg == NULL) {
LOG_ERR("Received NULL message pointer");
return -EINVAL;
}
LOG_DBG("Processing command: %d, length: %d", msg->command, msg->length);
switch (msg->command) {
case COMMAND_ERROR: {
LOG_WRN("Received COMMAND_ERROR");
break;
}
case LED: {
// Toggle LED with the LED command
led_toggle();
break;
}
default: {
LOG_WRN("Unknown command received: %d", msg->command);
return -EINVAL;
}
}
return 0;
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef COMMAND_HANDLER_H
#define COMMAND_HANDLER_H
#include "command_message.h"
/**
* @brief Process received command message
*
* @param msg Command message to process
* @return 0 on success, negative errno on failure
*/
int command_handler(struct command_message_t *msg);
#endif // COMMAND_HANDLER_H
+73
View File
@@ -0,0 +1,73 @@
#include "command_message.h"
#include <string.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(command_message, LOG_LEVEL_INF);
void command_message_init(struct command_message_t *msg) {
memset(msg, 0, sizeof(struct command_message_t));
msg->prefix = COMMAND_PREFIX;
msg->id = COMMAND_ID;
}
void command_create_message(struct command_message_t *msg, uint8_t length, commands_e command, uint8_t data[160]) {
// Ensure length doesn't exceed available space
if (length > sizeof(msg->data) - 1) {
return;
}
command_message_init(msg);
msg->length = length;
msg->command = command;
// Copy the data
if (data != NULL) {
for (int i = 0; i < msg->length; i++) {
msg->data[i] = data[i];
}
}
msg->crc = command_calculate_crc(msg);
}
uint8_t command_calculate_crc(struct command_message_t *msg) {
uint32_t sum = 0;
uint8_t crc = 0;
uint8_t *byte_ptr = (uint8_t *)msg;
for (int i = 0; i < (sizeof(struct command_message_t) - sizeof(msg->data) + msg->length) - 1; i++) {
sum += byte_ptr[i];
}
crc = 0x100 - (sum & 0xff);
return crc;
}
void command_create_ack(struct command_message_t *msg) {
command_create_message(msg, 0, COMMAND_ACK, NULL);
}
void command_create_nack(struct command_message_t *msg) {
command_create_message(msg, 0, COMMAND_NACK, NULL);
}
void command_log(struct command_message_t *msg) {
if (msg->length > sizeof(msg->data) - 1) {
LOG_ERR("Message length too long: %d", msg->length);
return;
}
LOG_INF("Prefix: %d\n\r", msg->prefix);
LOG_INF("Length: %d\n\r", msg->length);
LOG_INF("COMMAND_ID: %d\n\r", msg->id);
LOG_INF("Command: %d\n\r", msg->command);
LOG_INF("Data:\n\r");
for (int i = 0; i < msg->length; i++) {
LOG_INF("%d", msg->data[i]);
}
LOG_INF("CRC: %d\n\r", msg->crc);
}
+74
View File
@@ -0,0 +1,74 @@
#ifndef COMMAND_MESSAGE_H
#define COMMAND_MESSAGE_H
#include <stdint.h>
#define COMMAND_PREFIX 0x69
#define COMMAND_ID 0x00
typedef enum {
COMMAND_ERROR,
COMMAND_ACK,
COMMAND_NACK,
LED,
} commands_e;
struct command_message_t {
uint8_t prefix;
uint8_t length;
uint8_t id;
uint8_t command;
uint8_t crc;
uint8_t data[160];
} __attribute__((packed));
/**
* @brief Initialize command message to default state
*
* @param msg Message to initialize
*/
void command_message_init(struct command_message_t *msg);
/**
* @brief Create command message with data and CRC
*
* @param msg Message to populate
* @param length Data length in bytes
* @param command Command type
* @param data Data payload
*/
void command_create_message(struct command_message_t *msg, uint8_t length, commands_e command, uint8_t data[160]);
/**
* @brief Calculate CRC for command message
*
* @param msg Message to calculate CRC for
* @return CRC value
*/
uint8_t command_calculate_crc(struct command_message_t *msg);
/**
* @brief Create ACK command message
*
* @param msg Message to populate
*/
void command_create_ack(struct command_message_t *msg);
/**
* @brief Create NACK command message
*
* @param msg Message to populate
*/
void command_create_nack(struct command_message_t *msg);
/**
* @brief Print the command with LOG
*
* @param msg Message to calculate CRC for
*/
void command_log(struct command_message_t *msg);
#endif // COMMAND_MESSAGE_H
+51
View File
@@ -0,0 +1,51 @@
#include "led.h"
#include <zephyr/logging/log.h>
#include <zephyr/drivers/gpio.h>
LOG_MODULE_REGISTER(led, LOG_LEVEL_INF);
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led0_gpio = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static int led0_state = 0;
int led_init() {
int ret;
if (!device_is_ready(led0_gpio.port)) {
LOG_ERR("LED0 GPIO device not ready");
return -ENODEV;
}
ret = gpio_pin_configure_dt(&led0_gpio, GPIO_OUTPUT_INACTIVE);
if (ret != 0) {
LOG_ERR("Failed to configure LED0 GPIO: %d", ret);
return ret;
}
// Turn it off
ret = gpio_pin_set_dt(&led0_gpio, 0);
if (ret != 0) {
LOG_ERR("Failed to initialize LED");
return ret;
}
LOG_INF("LED driver initialized (LED0: GPIO %d)", led0_gpio.pin);
return 0;
}
int led_set(int state) {
led0_state = state ? 1 : 0;
int ret = gpio_pin_set_dt(&led0_gpio, led0_state);
if (ret != 0) {
LOG_ERR("Failed to set LED0: %d", ret);
}
return ret;
}
int led_toggle() {
return led_set(!led0_state);
}
+10
View File
@@ -0,0 +1,10 @@
#ifndef LED_H
#define LED_H
int led_init();
int led_set(int state);
int led_toggle();
#endif // LED_H
+24
View File
@@ -0,0 +1,24 @@
#include "led.h"
#include "usb.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
int main(void) {
int ret;
ret = usb_init();
if (ret != 0) {
LOG_ERR("Failed to enable USB");
return 0;
}
ret = led_init();
if (ret != 0) {
LOG_ERR("Failed to enable LED");
return 0;
}
return 0;
}
+193
View File
@@ -0,0 +1,193 @@
#include "usb.h"
#include "usb_conf.h"
#include "command_handler.h"
#include <zephyr/logging/log.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/kernel.h>
LOG_MODULE_REGISTER(usb, LOG_LEVEL_DBG);
// DEVICE
const struct device *const uart_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
static struct usbd_context *usb_context;
// THREAD
static struct k_thread usb_thread_data;
static k_tid_t usb_thread_id = NULL;
#define USB_THREAD_STACK_SIZE 2048
K_THREAD_STACK_DEFINE(usb_thread_stack, USB_THREAD_STACK_SIZE);
// RX BUFFER
#define RX_BUF_SIZE 4
struct rx_buffer_t {
int current_read;
int current_write;
struct k_sem semaphore;
struct command_message_t buffer[RX_BUF_SIZE];
};
static struct rx_buffer_t rx_buf;
static void interrupt_handler(const struct device *dev, void *user_data) {
ARG_UNUSED(user_data);
while (true) {
uart_irq_update(dev);
if (uart_irq_is_pending(dev) <= 0) {
break;
}
if (uart_irq_rx_ready(dev)) {
size_t len = sizeof(struct command_message_t);
int recv_len = uart_fifo_read(dev, (uint8_t *)&rx_buf.buffer[rx_buf.current_write], len);
if (recv_len < 0) {
LOG_ERR("Failed to read UART FIFO");
recv_len = 0;
};
rx_buf.current_write += 1;
if (rx_buf.current_write >= RX_BUF_SIZE) {
rx_buf.current_write = 0;
rx_buf.current_read = (RX_BUF_SIZE - 1);
}
else {
rx_buf.current_read = (rx_buf.current_write - 1);
}
// Give semaphore for usb read thread
k_sem_give(&rx_buf.semaphore);
}
}
}
static void usb_thread(void *p1, void *p2, void *p3) {
ARG_UNUSED(p1);
ARG_UNUSED(p2);
ARG_UNUSED(p3);
LOG_INF("USB command processing thread started");
while (1) {
// Wait forever for the rx semaphore
k_sem_take(&rx_buf.semaphore, K_FOREVER);
int read_index = rx_buf.current_read;
// Check the prefix
if (rx_buf.buffer[read_index].prefix != COMMAND_PREFIX) {
LOG_ERR("COMMAND_PREFIX does not match: %d", rx_buf.buffer[read_index].prefix);
// Send NACK
struct command_message_t nack_buf;
command_create_nack(&nack_buf);
usb_send_command(&nack_buf);
continue;
}
// Check the CRC
uint8_t calculated_crc = command_calculate_crc(&rx_buf.buffer[read_index]);
if (calculated_crc != rx_buf.buffer[read_index].crc) {
LOG_ERR("CRC does not match:");
LOG_ERR("Calculated CRC: %d", calculated_crc);
LOG_ERR("Received CRC: %d", rx_buf.buffer[read_index].prefix);
// Send NACK
struct command_message_t nack_buf;
command_create_nack(&nack_buf);
usb_send_command(&nack_buf);
continue;
}
int ret = command_handler(&rx_buf.buffer[read_index]);
if (ret == 0) {
// Send ACK
struct command_message_t ack_buf;
command_create_ack(&ack_buf);
usb_send_command(&ack_buf);
}
else {
// Send NACK
struct command_message_t nack_buf;
command_create_nack(&nack_buf);
usb_send_command(&nack_buf);
}
}
LOG_INF("USB command processing thread exiting");
}
int usb_init() {
rx_buf.current_read = 0;
rx_buf.current_write = 0;
k_sem_init(&rx_buf.semaphore, 1, 1);
memset(rx_buf.buffer, 0, sizeof(rx_buf.buffer));
int ret;
if (!device_is_ready(uart_dev)) {
LOG_ERR("CDC ACM device not ready");
return -ENODEV;
}
usb_context = usb_device_init(NULL);
if (usb_context == NULL) {
LOG_ERR("Failed to initialize USB device");
return -ENODEV;
}
if (!usbd_can_detect_vbus(usb_context)) {
ret = usbd_enable(usb_context);
if (ret) {
LOG_ERR("Failed to enable device support");
return ret;
}
}
k_msleep(100);
uart_irq_callback_set(uart_dev, interrupt_handler);
uart_irq_rx_enable(uart_dev);
usb_thread_id = k_thread_create(
&usb_thread_data,
usb_thread_stack,
K_THREAD_STACK_SIZEOF(usb_thread_stack),
usb_thread,
NULL, NULL, NULL,
5,
0,
K_NO_WAIT
);
if (usb_thread_id == NULL) {
LOG_ERR("Failed to create USB thread");
return -ENOMEM;
}
return ret;
}
int usb_send_command(struct command_message_t *msg) {
int ret = 0;
if (!device_is_ready(uart_dev)) {
return -ENODEV;
}
// Message size: prefix + length + id + command + crc + data
size_t msg_size = 5 + msg->length;
uint8_t *msg_bytes = (uint8_t *)msg;
/* uart_poll_out blocks until sent, ensuring data integrity */
for (size_t i = 0; i < msg_size; i++) {
uart_poll_out(uart_dev, msg_bytes[i]);
}
return ret;
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef USB_H
#define USB_H
#include "command_message.h"
int usb_init();
int usb_send_command(struct command_message_t *msg);
#endif // USB_H
+184
View File
@@ -0,0 +1,184 @@
#include "usb_conf.h"
#include <stdint.h>
#include <zephyr/device.h>
#include <zephyr/usb/usbd.h>
#include <zephyr/usb/bos.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(usb_conf, LOG_LEVEL_DBG);
/* By default, do not register the USB DFU class DFU mode instance. */
static const char *const blocklist[] = {
"dfu_dfu",
NULL,
};
/*
* Instantiate a context named my_usb_context using the default USB device
* controller, the Zephyr project vendor ID, and the sample product ID.
* Zephyr project vendor ID must not be used outside of Zephyr samples.
*/
USBD_DEVICE_DEFINE(my_usb_context,
DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)),
CONFIG_USBD_VID, CONFIG_USBD_PID);
USBD_DESC_LANG_DEFINE(my_usb_lang);
USBD_DESC_MANUFACTURER_DEFINE(my_usb_mfr, CONFIG_USBD_MANUFACTURER);
USBD_DESC_PRODUCT_DEFINE(my_usb_product, CONFIG_USBD_PRODUCT);
IF_ENABLED(CONFIG_HWINFO, (USBD_DESC_SERIAL_NUMBER_DEFINE(my_usb_serial)));
USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration");
USBD_DESC_CONFIG_DEFINE(hs_cfg_desc, "HS Configuration");
static const uint8_t attributes = (IS_ENABLED(CONFIG_USBD_SELF_POWERED) ?
USB_SCD_SELF_POWERED : 0) |
(IS_ENABLED(CONFIG_USBD_REMOTE_WAKEUP) ?
USB_SCD_REMOTE_WAKEUP : 0);
/* Full speed configuration */
USBD_CONFIGURATION_DEFINE(sample_fs_config,
attributes,
CONFIG_USBD_MAX_POWER, &fs_cfg_desc);
/* High speed configuration */
USBD_CONFIGURATION_DEFINE(sample_hs_config,
attributes,
CONFIG_USBD_MAX_POWER, &hs_cfg_desc);
#if CONFIG_SAMPLE_USBD_20_EXTENSION_DESC
/*
* This does not yet provide valuable information, but rather serves as an
* example, and will be improved in the future.
*/
static const struct usb_bos_capability_lpm bos_cap_lpm = {
.bLength = sizeof(struct usb_bos_capability_lpm),
.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_BOS_CAPABILITY_EXTENSION,
.bmAttributes = 0UL,
};
USBD_DESC_BOS_DEFINE(my_usb_usbext, sizeof(bos_cap_lpm), &bos_cap_lpm);
#endif
static void usb_fix_code_triple(struct usbd_context *uds_ctx, const enum usbd_speed speed) {
/* Always use class code information from Interface Descriptors */
if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) ||
IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) ||
IS_ENABLED(CONFIG_USBD_CDC_NCM_CLASS) ||
IS_ENABLED(CONFIG_USBD_MIDI2_CLASS) ||
IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS) ||
IS_ENABLED(CONFIG_USBD_VIDEO_CLASS)) {
/*
* Class with multiple interfaces have an Interface
* Association Descriptor available, use an appropriate triple
* to indicate it.
*/
usbd_device_set_code_triple(uds_ctx, speed,
USB_BCC_MISCELLANEOUS, 0x02, 0x01);
} else {
usbd_device_set_code_triple(uds_ctx, speed, 0, 0, 0);
}
}
struct usbd_context *usb_device_setup(usbd_msg_cb_t msg_cb) {
int err;
err = usbd_add_descriptor(&my_usb_context, &my_usb_lang);
if (err) {
LOG_ERR("Failed to initialize language descriptor (%d)", err);
return NULL;
}
err = usbd_add_descriptor(&my_usb_context, &my_usb_mfr);
if (err) {
LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err);
return NULL;
}
err = usbd_add_descriptor(&my_usb_context, &my_usb_product);
if (err) {
LOG_ERR("Failed to initialize product descriptor (%d)", err);
return NULL;
}
IF_ENABLED(CONFIG_HWINFO, (
err = usbd_add_descriptor(&my_usb_context, &my_usb_serial);
))
if (err) {
LOG_ERR("Failed to initialize SN descriptor (%d)", err);
return NULL;
}
if (USBD_SUPPORTS_HIGH_SPEED &&
usbd_caps_speed(&my_usb_context) == USBD_SPEED_HS) {
err = usbd_add_configuration(&my_usb_context, USBD_SPEED_HS,
&sample_hs_config);
if (err) {
LOG_ERR("Failed to add High-Speed configuration");
return NULL;
}
err = usbd_register_all_classes(&my_usb_context, USBD_SPEED_HS, 1,
blocklist);
if (err) {
LOG_ERR("Failed to add register classes");
return NULL;
}
usb_fix_code_triple(&my_usb_context, USBD_SPEED_HS);
}
err = usbd_add_configuration(&my_usb_context, USBD_SPEED_FS,
&sample_fs_config);
if (err) {
LOG_ERR("Failed to add Full-Speed configuration");
return NULL;
}
err = usbd_register_all_classes(&my_usb_context, USBD_SPEED_FS, 1, blocklist);
if (err) {
LOG_ERR("Failed to add register classes");
return NULL;
}
usb_fix_code_triple(&my_usb_context, USBD_SPEED_FS);
usbd_self_powered(&my_usb_context, attributes & USB_SCD_SELF_POWERED);
if (msg_cb != NULL) {
err = usbd_msg_register_cb(&my_usb_context, msg_cb);
if (err) {
LOG_ERR("Failed to register message callback");
return NULL;
}
}
#if CONFIG_SAMPLE_USBD_20_EXTENSION_DESC
(void)usbd_device_set_bcd_usb(&my_usb_context, USBD_SPEED_FS, 0x0201);
(void)usbd_device_set_bcd_usb(&my_usb_context, USBD_SPEED_HS, 0x0201);
err = usbd_add_descriptor(&my_usb_context, &my_usb_usbext);
if (err) {
LOG_ERR("Failed to add USB 2.0 Extension Descriptor");
return NULL;
}
#endif
return &my_usb_context;
}
struct usbd_context *usb_device_init(usbd_msg_cb_t msg_cb) {
int err;
if (usb_device_setup(msg_cb) == NULL) {
return NULL;
}
err = usbd_init(&my_usb_context);
if (err) {
LOG_ERR("Failed to initialize device support");
return NULL;
}
return &my_usb_context;
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef USB_CONF_H
#define USB_CONF_H
#include <zephyr/usb/usbd.h>
struct usbd_context *usb_device_setup(usbd_msg_cb_t msg_cb);
struct usbd_context *usb_device_init(usbd_msg_cb_t msg_cb);
#endif // USB_CONF_H
+21
View File
@@ -0,0 +1,21 @@
#include "zbus_channels.h"
#include "command_message.h"
ZBUS_CHAN_DEFINE(
in_command_chan,
struct command_message_t,
NULL,
NULL,
ZBUS_OBSERVERS_EMPTY,
ZBUS_MSG_INIT(0)
);
ZBUS_CHAN_DEFINE(
out_command_chan,
struct command_message_t,
NULL,
NULL,
ZBUS_OBSERVERS_EMPTY,
ZBUS_MSG_INIT(0)
);
+15
View File
@@ -0,0 +1,15 @@
#ifndef ZBUS_CHANNELS_H
#define ZBUS_CHANNELS_H
#include <zephyr/kernel.h>
#include <zephyr/zbus/zbus.h>
#include "command_message.h"
ZBUS_CHAN_DECLARE(in_command_chan);
ZBUS_CHAN_DECLARE(out_command_chan);
#endif // ZBUS_CHANNELS_H