Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,22 @@ USB:
- {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3}
```

每一项可以加上 `interface`,作为这路 CDC 控制接口和数据接口的名字。几路 CDC 的 VID:PID 相同,主机按接口名
区分它们;没有 `interface` 的一路使用 LibXR 的默认名 `XRUSB CDC Control` 和 `XRUSB CDC Data`:

Each item can add `interface`, the name of the control and data interfaces of that CDC. The CDCs
share VID:PID, and the host tells them apart by the interface name; a CDC without `interface`
keeps the LibXR default names `XRUSB CDC Control` and `XRUSB CDC Data`:

```yaml
USB:
usb_otg_hs:
enable: true
cdc:
- {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3, interface: Console}
- {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3, interface: Telemetry}
```

`database.enable` 为 true 时,`app_main()` 生成 `STM32Flash flash(FLASH_REGIONS, FLASH_REGION_NUMBER)`
和 `DatabaseRaw<N> database(flash)`,数据库以 `database` 注册;`FLASH_REGIONS` 来自
`User/flash_map.hpp`,数据库使用 Flash 末尾的两个扇区。模板参数 `N` 是 Flash 的最小写入单元,单位为
Expand Down
32 changes: 24 additions & 8 deletions src/libxr/generator_code_stm32.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,8 @@ def _usb_settings(instance: str) -> tuple[str, dict] | None:

enable 的默认值由 _default_usb_enables() 先行写入,仍然缺少时为 false;未启用的实例不再补其他
设置。已启用的实例按固定顺序补上缺少的设置:包大小、缓冲区和 FIFO 大小、dma_section、cdc 列表
(每路 CDC 一项,含 tx_fifo_size、rx_fifo_size 和 queue_size,默认一路),以及描述符(默认
(每路 CDC 一项,含 tx_fifo_size、rx_fifo_size、queue_size 和可选的 interface,默认一路),
以及描述符(默认
1d50:6199 / 0x0100 / "XRUSB-DEMO-",1d50:6199 的分配记录见
https://github.com/openmoko/openmoko-usb-oui/commit/27f3846d77e0d0d10271b809b831f70040c6197a)。
旧版的 cdc_tx_fifo_size、cdc_rx_fifo_size 和 cdc_queue_size 转换为 cdc 的一项,并在原来的位置
Expand All @@ -1125,7 +1126,8 @@ def _usb_settings(instance: str) -> tuple[str, dict] | None:
_default_usb_enables() writes the default enable first; when it is still missing it is
false, and a disabled instance gets no other setting. An enabled instance gets its missing
settings in a fixed order: packet size, buffer and FIFO sizes, dma_section, the cdc list (one
item per CDC with tx_fifo_size, rx_fifo_size and queue_size, one CDC by default), and the
item per CDC with tx_fifo_size, rx_fifo_size, queue_size and an optional interface, one CDC
by default), and the
descriptor (default 1d50:6199 / 0x0100 / "XRUSB-DEMO-"; see the link above for the
allocation of 1d50:6199). The earlier cdc_tx_fifo_size, cdc_rx_fifo_size and
cdc_queue_size become one item of cdc, written back where they were. An ep0_packet_size
Expand Down Expand Up @@ -1272,6 +1274,9 @@ def _check_cdc(prefix: str, cfg: dict, is_otg: bool) -> None:
Check the cdc list and give each item its defaults: a non-empty list whose items are
mappings with positive integer values.

可选的 interface 是字符串,不补默认值。
The optional interface is a string and gets no default.

CDC 的路数不得超过端点号 EP1 到 EP15 能容纳的路数;OTG 设备的接收 FIFO 为 EP0 和每路 CDC 的
OUT 端点各留 64 字节。
The number of CDCs may not exceed what the endpoint numbers EP1 to EP15 hold; the receive
Expand All @@ -1294,6 +1299,8 @@ def _check_cdc(prefix: str, cfg: dict, is_otg: bool) -> None:
raise _invalid_setting(f"{key}[{index}]", item, "a mapping", "映射")
for name, default in _CDC_DEFAULTS.items():
_integer(f"{key}[{index}].{name}", item.setdefault(name, default))
if "interface" in item:
item["interface"] = _text(f"{key}[{index}].interface", item["interface"])
if len(cdc) > _MAX_CDC:
raise LibXRConfigError(
tr(
Expand Down Expand Up @@ -1500,13 +1507,16 @@ def _usb_buffer_plan(is_otg: bool, cdc_count: int, ep0: int, tx: int, rx: int) -


def _cdc_items(cfg: dict) -> list[dict]:
"""USB 设备的 CDC 串口设置列表:每个 CDC 一个映射,含 tx_fifo_size、rx_fifo_size 和
queue_size,均为整数。
The list of CDC serial port settings of a USB device: one mapping per CDC with
tx_fifo_size, rx_fifo_size and queue_size, all integers.
"""USB 设备的 CDC 串口设置列表:每个 CDC 一个映射,含整数 tx_fifo_size、rx_fifo_size 和
queue_size,以及接口名 interface(未设置时为空字符串)。
The list of CDC serial port settings of a USB device: one mapping per CDC with the integers
tx_fifo_size, rx_fifo_size and queue_size and the interface name interface (an empty string
when it is not set).
"""
return [
{name: _integer(f"cdc.{name}", item[name]) for name in _CDC_DEFAULTS} for item in cfg["cdc"]
{name: _integer(f"cdc.{name}", item[name]) for name in _CDC_DEFAULTS}
| {"interface": _text("cdc.interface", item.get("interface"))}
for item in cfg["cdc"]
]


Expand Down Expand Up @@ -2177,6 +2187,11 @@ def endpoint(number: int) -> str:
cdc_names.append(cdc_name)
data_in = 2 * index + 1
data_out = index + 1 if is_otg else data_in
# 设置了 interface 时它同时作为控制接口和数据接口的名字;主机按它区分 VID:PID 相同的
# 各路 CDC。
# A set interface names both the control and the data interface; the host tells the
# CDCs that share VID:PID apart by it.
interface = cdc["interface"].replace('"', '\\"')
lines += layout(
f"static USB::CDCUart {cdc_name}",
[
Expand All @@ -2186,7 +2201,8 @@ def endpoint(number: int) -> str:
str(cdc["rx_fifo_size"]),
str(cdc["tx_fifo_size"]),
str(cdc["queue_size"]),
],
]
+ ([f'"{interface}"'] * 2 if interface else []),
)

def buffer(suffix: str) -> "str | Braces":
Expand Down
36 changes: 36 additions & 0 deletions tests/test_generator_code_stm32.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,42 @@ def test_each_cdc_takes_its_own_queue_sizes(self):
self.assertIn("USB::Endpoint::EPNumber::EP2, 64, 256, 2);", code)
self.assertIn("USB::Endpoint::EPNumber::EP4, 128, 128, 7);", code)

def test_a_cdc_interface_names_its_control_and_data_interfaces(self):
# interface 接在队列容量之后,作为 CDCUart 的控制接口名和数据接口名;未设置的 CDC
# 使用 LibXR 的默认名,不写 interface 键。
# interface follows the queue sizes as the control and data interface names of
# CDCUart; a CDC without it keeps the LibXR default names, and no interface key is
# written for it.
project = self.usb_otg_hs(cdc=[{"interface": 'Port "A"'}, {}])
code = self.generate(project)
self.assertIn(
" static USB::CDCUart usb_otg_hs_cdc(\n"
" USB::Endpoint::EPNumber::EP1, USB::Endpoint::EPNumber::EP1,\n"
' USB::Endpoint::EPNumber::EP2, 128, 128, 3, "Port \\"A\\"", "Port \\"A\\"");\n'
" static USB::CDCUart usb_otg_hs_cdc2(USB::Endpoint::EPNumber::EP3,\n"
" USB::Endpoint::EPNumber::EP2,\n"
" USB::Endpoint::EPNumber::EP4, 128, 128, 3);\n",
code,
)
self.assertEqual(
generator.libxr_settings["USB"]["usb_otg_hs"]["cdc"],
[
{
"interface": 'Port "A"',
"tx_fifo_size": 128,
"rx_fifo_size": 128,
"queue_size": 3,
},
{"tx_fifo_size": 128, "rx_fifo_size": 128, "queue_size": 3},
],
)

def test_a_cdc_interface_must_be_a_string(self):
project = self.usb_otg_hs(cdc=[{"interface": 7}])
with self.assertRaises(LibXRConfigError) as raised:
self.generate(project)
self.assertIn("USB.usb_otg_hs.cdc[0].interface", str(raised.exception))

def test_on_fsdev_each_cdc_has_a_data_endpoint_and_a_notification_endpoint(
self,
):
Expand Down
Loading