Compare commits
1 commit
main
...
feat/usbse
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
202d874dee |
32 changed files with 730 additions and 27541 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -24,7 +24,3 @@ target/
|
||||||
|
|
||||||
# Ignore .DS_Store file in mac
|
# Ignore .DS_Store file in mac
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
|
|
||||||
# Ignore KiCad backups and lock files
|
|
||||||
hardware/c_its-companion/c_its-companion-backups/
|
|
||||||
*.kicad_pro.lck
|
|
||||||
|
|
|
||||||
41
Cargo.lock
generated
41
Cargo.lock
generated
|
|
@ -192,9 +192,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "c-its-parser"
|
name = "c-its-parser"
|
||||||
version = "2.4.1"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e94d9990b20498f621f164f23ae198c4365115eb4191ae106352ec74d4a4110"
|
checksum = "cd4db66f495280ec88eef8712dd9ab7d1aacc590f62485e3e03a89b3ce4f8b14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"etherparse",
|
"etherparse",
|
||||||
|
|
@ -1171,7 +1171,6 @@ dependencies = [
|
||||||
"esp-println",
|
"esp-println",
|
||||||
"esp-radio",
|
"esp-radio",
|
||||||
"esp-rtos",
|
"esp-rtos",
|
||||||
"esp32-cits-core",
|
|
||||||
"geo-types",
|
"geo-types",
|
||||||
"log",
|
"log",
|
||||||
"mipidsi",
|
"mipidsi",
|
||||||
|
|
@ -1179,19 +1178,6 @@ dependencies = [
|
||||||
"profont",
|
"profont",
|
||||||
"prost",
|
"prost",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
"ublox",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "esp32-cits-core"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "git+https://git.hamburg.ccc.de/jtbx/esp32-cits-core?branch=main#a6d0ea6ca2da130fde2b84060a34ef45e772a459"
|
|
||||||
dependencies = [
|
|
||||||
"c-its-parser",
|
|
||||||
"chrono",
|
|
||||||
"esp-hal",
|
|
||||||
"esp-radio",
|
|
||||||
"geo-types",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2504,29 +2490,6 @@ version = "1.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ublox"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5bcc96bd937066775fb87034e1dbf6d7165a8975c74ddec1105e31b4a050538b"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"chrono",
|
|
||||||
"num-traits",
|
|
||||||
"ublox_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ublox_derive"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f5eda7d1c1151a40ae85c7c065a19959909573535034e18e1015b738993cd2c0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ufmt-write"
|
name = "ufmt-write"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
||||||
18
Cargo.toml
18
Cargo.toml
|
|
@ -14,8 +14,14 @@ name = "test"
|
||||||
path = "./src/test.rs"
|
path = "./src/test.rs"
|
||||||
required-features = ["std", "cam"]
|
required-features = ["std", "cam"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
## run with cargo run --target host-tuple --bin test-proto --no-default-features -F std,uart
|
||||||
|
name = "test-proto"
|
||||||
|
path = "./src/test-proto.rs"
|
||||||
|
required-features = ["std", "uart", "cam"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["esp", "spat", "gnss_ubx", "screen"]
|
default = ["esp", "spat", "gnss", "screen"]
|
||||||
|
|
||||||
# build for ESP (needed to build test for `host-tuple`)
|
# build for ESP (needed to build test for `host-tuple`)
|
||||||
esp = [
|
esp = [
|
||||||
|
|
@ -30,15 +36,11 @@ esp = [
|
||||||
"dep:esp-backtrace",
|
"dep:esp-backtrace",
|
||||||
"dep:esp-println",
|
"dep:esp-println",
|
||||||
"dep:esp-radio",
|
"dep:esp-radio",
|
||||||
"esp32-cits-core/esp32c5",
|
|
||||||
"esp32-cits-core/log-04",
|
|
||||||
]
|
]
|
||||||
std = ["c-its-parser/std", "esp32-cits-core/std"]
|
std = ["c-its-parser/std"]
|
||||||
|
|
||||||
# enable u-blox GNSS module
|
|
||||||
gnss_ubx = ["_gnss", "_uart", "dep:ublox"]
|
|
||||||
# enable L67K GNSS module
|
# enable L67K GNSS module
|
||||||
gnss_l67k = ["_gnss", "dep:embassy_gps"]
|
gnss = ["_gnss", "dep:embassy_gps"]
|
||||||
# echo CAM data on serial
|
# echo CAM data on serial
|
||||||
cam = ["c-its-parser/cam"]
|
cam = ["c-its-parser/cam"]
|
||||||
# send CAM autonomously
|
# send CAM autonomously
|
||||||
|
|
@ -95,7 +97,6 @@ esp-radio = { version = "0.18.0", optional = true, features = [
|
||||||
] }
|
] }
|
||||||
|
|
||||||
embassy_gps = { version = "0.1.0", optional = true, default-features = false, features = ["esp", "log-04"], git = "https://github.com/jbeyerstedt/embassy_gps.git", branch = "feat/rework-gpsfix" }
|
embassy_gps = { version = "0.1.0", optional = true, default-features = false, features = ["esp", "log-04"], git = "https://github.com/jbeyerstedt/embassy_gps.git", branch = "feat/rework-gpsfix" }
|
||||||
esp32-cits-core = { version = "0.1.0", default-features = false, git = "https://git.hamburg.ccc.de/jtbx/esp32-cits-core", branch = "main" }
|
|
||||||
embedded-hal-bus = { version = "0.3.0", optional = true }
|
embedded-hal-bus = { version = "0.3.0", optional = true }
|
||||||
embedded-graphics = { version = "0.8.2", optional = true }
|
embedded-graphics = { version = "0.8.2", optional = true }
|
||||||
# needs newer GN with removed bitvec dependency
|
# needs newer GN with removed bitvec dependency
|
||||||
|
|
@ -112,7 +113,6 @@ mipidsi = { version = "0.10.0", optional = true }
|
||||||
num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }
|
num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }
|
||||||
profont = { version = "0.7.0", optional = true }
|
profont = { version = "0.7.0", optional = true }
|
||||||
prost = { version = "0.14", optional = true, default-features = false, features = ["derive"] }
|
prost = { version = "0.14", optional = true, default-features = false, features = ["derive"] }
|
||||||
ublox = { version = "0.10", optional = true, default-features = false, features = ["alloc", "ubx_proto27"] }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_float_eq = "1.2.0"
|
assert_float_eq = "1.2.0"
|
||||||
|
|
|
||||||
34
Readme.md
34
Readme.md
|
|
@ -5,16 +5,15 @@ Displays different C-ITS receive-only use cases for cheap.
|
||||||
## Hardware Requirements
|
## Hardware Requirements
|
||||||
The code is currently tailored to:
|
The code is currently tailored to:
|
||||||
- Seeed XIAO ESP32-C5 (8MB PSRAM)
|
- Seeed XIAO ESP32-C5 (8MB PSRAM)
|
||||||
- U-Blox M10Q GNSS (connected on GPIO12 (RX), GPIO11 (TX), and GPIO25 (reset))
|
- Seeed XIAO L67K (connected on GPIO12 (RX), GPIO11 (TX), GPIO1 (wakeup) and GPIO25 (reset))
|
||||||
or Seeed XIAO L67K (connected on GPIO12 (RX), GPIO11 (TX), GPIO1 (wakeup) and GPIO25 (reset))
|
only available with `gnss` feature (which is included in `spat` feature)
|
||||||
only available with `gnss_ubx` or `gnss_l67k` feature (which is included in `spat` feature)
|
|
||||||
- Some ST7789 172*320px screen (connected on GPIO8 (SCL/ SCK), GPIO10 (SDA/ MOSI), GPIO7 (reset), GPIO23 (DC), GPIO24 (CS), TODO GPIO0 (BL))
|
- Some ST7789 172*320px screen (connected on GPIO8 (SCL/ SCK), GPIO10 (SDA/ MOSI), GPIO7 (reset), GPIO23 (DC), GPIO24 (CS), TODO GPIO0 (BL))
|
||||||
only available with `screen` feature (which is included in `spat` feature)
|
only available with `screen` feature (which is included in `spat` feature)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### GNSS
|
### GNSS
|
||||||
Enable u-blox or L67K GNSS module and in main application logic/ state.
|
Enable L67K GNSS module and in main application logic/ state.
|
||||||
|
|
||||||
### SPAT
|
### SPAT
|
||||||
Takes the current position and heading from the GNSS receiver and displays the signal phases of the upcoming intersection.
|
Takes the current position and heading from the GNSS receiver and displays the signal phases of the upcoming intersection.
|
||||||
|
|
@ -33,25 +32,6 @@ Just prints a line for each received CAM.
|
||||||
Generates and transmits a CAM when a GNSS update was received.
|
Generates and transmits a CAM when a GNSS update was received.
|
||||||
Depends on the `gnss` feature.
|
Depends on the `gnss` feature.
|
||||||
|
|
||||||
Note: In germany, using the 5875 to 5915 MHz frequency band is only permitted for C-ITS use cases which implement transmit power reduction measures with at least 30 dB reduction range (or equivalent measures) and have a maximum EIRP of 33 dBm.
|
|
||||||
This is based on EU regulation 2014/53/EU, so it applies to other EU countries in similar ways.
|
|
||||||
The relevant harmonized standard is ETSI EN 302 571 which mandates (excerpt of most relevant points):
|
|
||||||
|
|
||||||
- a maximum power spectral density of 23 dBm/Mhz EIRP
|
|
||||||
- transmit power control (TCP) in a range from 3 dBm up to the maximum output power of the equipment
|
|
||||||
* used for CEN DSRC and HDR DSRC interference mitigation by implementing measures from ETSI TS 102 792
|
|
||||||
+ Mode A or B: Output power less than 10 dBm EIRP and less than -65 or -45 dBm/MHz EIRP in CEN DSRC band -> **needs to be measured**
|
|
||||||
+ Mode C: Maximum transmission time of less than 1 ms and at least a few 100 ms between transmission (realistically) -> **can't be ensured with big messages**
|
|
||||||
+ Mode D: "any" realistically possible transmission time, but at least 500 ms between transmissions for ~5 ITS stations/ 1000ms for 10 ITS stations -> **safe to assume when we only send CAMs at 1 Hz**
|
|
||||||
+ But modes C and D also need to:
|
|
||||||
- use protected zone information from CAM messages
|
|
||||||
- use a protected zone database, e.g. from www.asecap-pzdb.com
|
|
||||||
* used for dynamic congestion control (DCC)
|
|
||||||
+ mandatory mechanism described in ETSI EN 302 571, chapter 4.2.10
|
|
||||||
|
|
||||||
This is **not** implemented in this application!
|
|
||||||
**So legally, you're not allowed to send with this.**
|
|
||||||
|
|
||||||
### UART
|
### UART
|
||||||
Enable UART I/O protocol according to [docs/uart-protocol.md](./docs/uart-protocol.md).
|
Enable UART I/O protocol according to [docs/uart-protocol.md](./docs/uart-protocol.md).
|
||||||
|
|
||||||
|
|
@ -90,10 +70,10 @@ Additional features are available through feature flags:
|
||||||
- `cam_tx`: Enable CAM generation and transmission (needs time and position source)
|
- `cam_tx`: Enable CAM generation and transmission (needs time and position source)
|
||||||
|
|
||||||
Officially supported feature combinations are:
|
Officially supported feature combinations are:
|
||||||
- `esp,spat,gnss_ubx,screen` (default features, "standalone")
|
- `esp,spat,gnss,screen` (default features)
|
||||||
- `esp,spat,gnss_ubx,screen,cam_tx` ("standalone with CAM")
|
- `esp,spat,gnss,screen,cam_tx`
|
||||||
- `esp,spat,gnss_ubx,screen,cam_tx,cam,denm`
|
- `esp,spat,gnss,screen,cam_tx,cam,denm`
|
||||||
- `esp,uart,cam,denm` ("smartphone companion")
|
- `esp,uart,cam,denm`
|
||||||
|
|
||||||
Connect your ESP32-C5 and run:
|
Connect your ESP32-C5 and run:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ extended=${2:-false}
|
||||||
|
|
||||||
features_base=(
|
features_base=(
|
||||||
uart,cam,denm
|
uart,cam,denm
|
||||||
spat,gnss_ubx,screen
|
spat,gnss,screen
|
||||||
spat,gnss_ubx,screen,cam_tx
|
spat,gnss,screen,cam_tx
|
||||||
)
|
)
|
||||||
features_more=(
|
features_more=(
|
||||||
spat,gnss_ubx,screen,cam,denm
|
spat,gnss,screen,cam,denm
|
||||||
spat,gnss_ubx,screen,cam_tx,cam,denm
|
spat,gnss,screen,cam_tx,cam,denm
|
||||||
)
|
)
|
||||||
features_test=(
|
features_test=(
|
||||||
spat,cam,denm,uart
|
spat,cam,denm,uart
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 145 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 142 KiB |
File diff suppressed because it is too large
Load diff
|
|
@ -1,138 +0,0 @@
|
||||||
{
|
|
||||||
"board": {
|
|
||||||
"active_layer": 0,
|
|
||||||
"active_layer_preset": "",
|
|
||||||
"auto_track_width": true,
|
|
||||||
"hidden_netclasses": [],
|
|
||||||
"hidden_nets": [],
|
|
||||||
"high_contrast_mode": 0,
|
|
||||||
"net_color_mode": 1,
|
|
||||||
"opacity": {
|
|
||||||
"images": 0.6,
|
|
||||||
"pads": 1.0,
|
|
||||||
"shapes": 1.0,
|
|
||||||
"tracks": 1.0,
|
|
||||||
"vias": 1.0,
|
|
||||||
"zones": 0.6
|
|
||||||
},
|
|
||||||
"prototype_zone_fills": false,
|
|
||||||
"selection_filter": {
|
|
||||||
"dimensions": true,
|
|
||||||
"footprints": true,
|
|
||||||
"graphics": true,
|
|
||||||
"keepouts": true,
|
|
||||||
"lockedItems": false,
|
|
||||||
"otherItems": true,
|
|
||||||
"pads": true,
|
|
||||||
"text": true,
|
|
||||||
"tracks": true,
|
|
||||||
"vias": true,
|
|
||||||
"zones": true
|
|
||||||
},
|
|
||||||
"visible_items": [
|
|
||||||
"vias",
|
|
||||||
"footprint_text",
|
|
||||||
"footprint_anchors",
|
|
||||||
"ratsnest",
|
|
||||||
"grid",
|
|
||||||
"footprints_front",
|
|
||||||
"footprints_back",
|
|
||||||
"footprint_values",
|
|
||||||
"footprint_references",
|
|
||||||
"tracks",
|
|
||||||
"drc_errors",
|
|
||||||
"drawing_sheet",
|
|
||||||
"bitmaps",
|
|
||||||
"pads",
|
|
||||||
"zones",
|
|
||||||
"drc_warnings",
|
|
||||||
"drc_exclusions",
|
|
||||||
"locked_item_shadows",
|
|
||||||
"conflict_shadows",
|
|
||||||
"shapes",
|
|
||||||
"board_outline_area",
|
|
||||||
"ly_points"
|
|
||||||
],
|
|
||||||
"visible_layers": "ffffffff_ffffffff_ffffffff_ffffffff",
|
|
||||||
"zone_display_mode": 0
|
|
||||||
},
|
|
||||||
"git": {
|
|
||||||
"integration_disabled": false,
|
|
||||||
"repo_type": "",
|
|
||||||
"repo_username": "",
|
|
||||||
"ssh_key": ""
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"filename": "c_its-companion.kicad_prl",
|
|
||||||
"version": 5
|
|
||||||
},
|
|
||||||
"net_inspector_panel": {
|
|
||||||
"col_hidden": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"col_order": [
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
6,
|
|
||||||
7,
|
|
||||||
8,
|
|
||||||
9
|
|
||||||
],
|
|
||||||
"col_widths": [
|
|
||||||
156,
|
|
||||||
141,
|
|
||||||
103,
|
|
||||||
71,
|
|
||||||
103,
|
|
||||||
103,
|
|
||||||
103,
|
|
||||||
74,
|
|
||||||
103,
|
|
||||||
103
|
|
||||||
],
|
|
||||||
"custom_group_rules": [],
|
|
||||||
"expanded_rows": [],
|
|
||||||
"filter_by_net_name": true,
|
|
||||||
"filter_by_netclass": true,
|
|
||||||
"filter_text": "",
|
|
||||||
"group_by_constraint": false,
|
|
||||||
"group_by_netclass": false,
|
|
||||||
"show_time_domain_details": false,
|
|
||||||
"show_unconnected_nets": false,
|
|
||||||
"show_zero_pad_nets": false,
|
|
||||||
"sort_ascending": true,
|
|
||||||
"sorting_column": 0
|
|
||||||
},
|
|
||||||
"open_jobsets": [],
|
|
||||||
"project": {
|
|
||||||
"files": []
|
|
||||||
},
|
|
||||||
"schematic": {
|
|
||||||
"hierarchy_collapsed": [],
|
|
||||||
"selection_filter": {
|
|
||||||
"graphics": true,
|
|
||||||
"images": true,
|
|
||||||
"labels": true,
|
|
||||||
"lockedItems": false,
|
|
||||||
"otherItems": true,
|
|
||||||
"pins": true,
|
|
||||||
"ruleAreas": true,
|
|
||||||
"symbols": true,
|
|
||||||
"text": true,
|
|
||||||
"wires": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,744 +0,0 @@
|
||||||
{
|
|
||||||
"board": {
|
|
||||||
"3dviewports": [
|
|
||||||
{
|
|
||||||
"name": "ISO-back",
|
|
||||||
"ww": 1.0,
|
|
||||||
"wx": 23.768348693847656,
|
|
||||||
"wy": 1.82621169090271,
|
|
||||||
"wz": -13.010103225708008,
|
|
||||||
"xw": 0.0,
|
|
||||||
"xx": -0.6424655318260193,
|
|
||||||
"xy": 0.5901128053665161,
|
|
||||||
"xz": -0.4888812303543091,
|
|
||||||
"yw": 0.0,
|
|
||||||
"yx": 0.7663145065307617,
|
|
||||||
"yy": 0.49455612897872925,
|
|
||||||
"yz": -0.41009292006492615,
|
|
||||||
"zw": 0.0,
|
|
||||||
"zx": -0.00022190232994034886,
|
|
||||||
"zy": -0.638107419013977,
|
|
||||||
"zz": -0.7699472904205322
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ISO-front",
|
|
||||||
"ww": 1.0,
|
|
||||||
"wx": 4.608643054962158,
|
|
||||||
"wy": 18.730253219604492,
|
|
||||||
"wz": -27.170215606689453,
|
|
||||||
"xw": 0.0,
|
|
||||||
"xx": 0.6427879333496094,
|
|
||||||
"xy": -0.5868241190910339,
|
|
||||||
"xz": 0.49240362644195557,
|
|
||||||
"yw": 0.0,
|
|
||||||
"yx": 0.7660443186759949,
|
|
||||||
"yy": 0.4924042820930481,
|
|
||||||
"yz": -0.4131760001182556,
|
|
||||||
"zw": 0.0,
|
|
||||||
"zx": -2.1759660739917308e-08,
|
|
||||||
"zy": 0.6427874565124512,
|
|
||||||
"zz": 0.7660446763038635
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"design_settings": {
|
|
||||||
"defaults": {
|
|
||||||
"apply_defaults_to_fp_barcodes": false,
|
|
||||||
"apply_defaults_to_fp_dimensions": false,
|
|
||||||
"apply_defaults_to_fp_fields": false,
|
|
||||||
"apply_defaults_to_fp_shapes": false,
|
|
||||||
"apply_defaults_to_fp_text": false,
|
|
||||||
"board_outline_line_width": 0.05,
|
|
||||||
"copper_line_width": 0.2,
|
|
||||||
"copper_text_italic": false,
|
|
||||||
"copper_text_size_h": 1.5,
|
|
||||||
"copper_text_size_v": 1.5,
|
|
||||||
"copper_text_thickness": 0.3,
|
|
||||||
"copper_text_upright": false,
|
|
||||||
"courtyard_line_width": 0.05,
|
|
||||||
"dimension_precision": 4,
|
|
||||||
"dimension_units": 3,
|
|
||||||
"dimensions": {
|
|
||||||
"arrow_length": 1270000,
|
|
||||||
"extension_offset": 500000,
|
|
||||||
"keep_text_aligned": true,
|
|
||||||
"suppress_zeroes": true,
|
|
||||||
"text_position": 0,
|
|
||||||
"units_format": 0
|
|
||||||
},
|
|
||||||
"fab_line_width": 0.1,
|
|
||||||
"fab_text_italic": false,
|
|
||||||
"fab_text_size_h": 1.0,
|
|
||||||
"fab_text_size_v": 1.0,
|
|
||||||
"fab_text_thickness": 0.15,
|
|
||||||
"fab_text_upright": false,
|
|
||||||
"other_line_width": 0.1,
|
|
||||||
"other_text_italic": false,
|
|
||||||
"other_text_size_h": 1.0,
|
|
||||||
"other_text_size_v": 1.0,
|
|
||||||
"other_text_thickness": 0.15,
|
|
||||||
"other_text_upright": false,
|
|
||||||
"pads": {
|
|
||||||
"drill": 0.8,
|
|
||||||
"height": 1.27,
|
|
||||||
"width": 1.27
|
|
||||||
},
|
|
||||||
"silk_line_width": 0.1,
|
|
||||||
"silk_text_italic": false,
|
|
||||||
"silk_text_size_h": 1.0,
|
|
||||||
"silk_text_size_v": 1.0,
|
|
||||||
"silk_text_thickness": 0.1,
|
|
||||||
"silk_text_upright": false,
|
|
||||||
"zones": {
|
|
||||||
"border_display_style": 2,
|
|
||||||
"border_hatch_pitch": 0.5,
|
|
||||||
"corner_radius": 0.0,
|
|
||||||
"corner_smoothing": 0,
|
|
||||||
"fill_mode": 0,
|
|
||||||
"hatch_gap": 1.5,
|
|
||||||
"hatch_orientation": 0.0,
|
|
||||||
"hatch_smoothing_level": 0,
|
|
||||||
"hatch_smoothing_value": 0.1,
|
|
||||||
"hatch_thickness": 1.0,
|
|
||||||
"min_clearance": 0.5,
|
|
||||||
"min_island_area": 10.0,
|
|
||||||
"min_thickness": 0.25,
|
|
||||||
"pad_connection": 1,
|
|
||||||
"remove_islands": 0,
|
|
||||||
"thermal_relief_gap": 0.5,
|
|
||||||
"thermal_relief_spoke_width": 0.5
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"diff_pair_dimensions": [
|
|
||||||
{
|
|
||||||
"gap": 0.0,
|
|
||||||
"via_gap": 0.0,
|
|
||||||
"width": 0.0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"drc_exclusions": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 2
|
|
||||||
},
|
|
||||||
"rule_severities": {
|
|
||||||
"annular_width": "error",
|
|
||||||
"clearance": "error",
|
|
||||||
"connection_width": "warning",
|
|
||||||
"copper_edge_clearance": "error",
|
|
||||||
"copper_sliver": "warning",
|
|
||||||
"courtyards_overlap": "error",
|
|
||||||
"creepage": "error",
|
|
||||||
"diff_pair_gap_out_of_range": "error",
|
|
||||||
"diff_pair_uncoupled_length_too_long": "error",
|
|
||||||
"drill_out_of_range": "error",
|
|
||||||
"duplicate_footprints": "warning",
|
|
||||||
"extra_footprint": "warning",
|
|
||||||
"footprint": "error",
|
|
||||||
"footprint_filters_mismatch": "ignore",
|
|
||||||
"footprint_symbol_field_mismatch": "warning",
|
|
||||||
"footprint_symbol_mismatch": "warning",
|
|
||||||
"footprint_type_mismatch": "ignore",
|
|
||||||
"hole_clearance": "error",
|
|
||||||
"hole_to_hole": "warning",
|
|
||||||
"holes_co_located": "warning",
|
|
||||||
"invalid_outline": "error",
|
|
||||||
"isolated_copper": "warning",
|
|
||||||
"item_on_disabled_layer": "error",
|
|
||||||
"items_not_allowed": "error",
|
|
||||||
"length_out_of_range": "error",
|
|
||||||
"lib_footprint_issues": "warning",
|
|
||||||
"lib_footprint_mismatch": "warning",
|
|
||||||
"malformed_courtyard": "error",
|
|
||||||
"microvia_drill_out_of_range": "error",
|
|
||||||
"mirrored_text_on_front_layer": "warning",
|
|
||||||
"missing_courtyard": "ignore",
|
|
||||||
"missing_footprint": "warning",
|
|
||||||
"missing_tuning_profile": "warning",
|
|
||||||
"net_conflict": "warning",
|
|
||||||
"nonmirrored_text_on_back_layer": "warning",
|
|
||||||
"npth_inside_courtyard": "error",
|
|
||||||
"padstack": "warning",
|
|
||||||
"pth_inside_courtyard": "error",
|
|
||||||
"shorting_items": "error",
|
|
||||||
"silk_edge_clearance": "warning",
|
|
||||||
"silk_over_copper": "warning",
|
|
||||||
"silk_overlap": "warning",
|
|
||||||
"skew_out_of_range": "error",
|
|
||||||
"solder_mask_bridge": "error",
|
|
||||||
"starved_thermal": "error",
|
|
||||||
"text_height": "warning",
|
|
||||||
"text_on_edge_cuts": "error",
|
|
||||||
"text_thickness": "warning",
|
|
||||||
"through_hole_pad_without_hole": "error",
|
|
||||||
"too_many_vias": "error",
|
|
||||||
"track_angle": "error",
|
|
||||||
"track_dangling": "warning",
|
|
||||||
"track_not_centered_on_via": "ignore",
|
|
||||||
"track_on_post_machined_layer": "error",
|
|
||||||
"track_segment_length": "error",
|
|
||||||
"track_width": "error",
|
|
||||||
"tracks_crossing": "error",
|
|
||||||
"tuning_profile_track_geometries": "ignore",
|
|
||||||
"unconnected_items": "error",
|
|
||||||
"unresolved_variable": "error",
|
|
||||||
"via_dangling": "warning",
|
|
||||||
"zones_intersect": "error"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"max_error": 0.005,
|
|
||||||
"min_clearance": 0.0,
|
|
||||||
"min_connection": 0.0,
|
|
||||||
"min_copper_edge_clearance": 0.5,
|
|
||||||
"min_groove_width": 0.0,
|
|
||||||
"min_hole_clearance": 0.25,
|
|
||||||
"min_hole_to_hole": 0.25,
|
|
||||||
"min_microvia_diameter": 0.2,
|
|
||||||
"min_microvia_drill": 0.1,
|
|
||||||
"min_resolved_spokes": 2,
|
|
||||||
"min_silk_clearance": 0.0,
|
|
||||||
"min_text_height": 0.8,
|
|
||||||
"min_text_thickness": 0.08,
|
|
||||||
"min_through_hole_diameter": 0.3,
|
|
||||||
"min_track_width": 0.2,
|
|
||||||
"min_via_annular_width": 0.1,
|
|
||||||
"min_via_diameter": 0.5,
|
|
||||||
"solder_mask_to_copper_clearance": 0.005,
|
|
||||||
"use_height_for_length_calcs": true
|
|
||||||
},
|
|
||||||
"teardrop_options": [
|
|
||||||
{
|
|
||||||
"td_onpthpad": true,
|
|
||||||
"td_onroundshapesonly": false,
|
|
||||||
"td_onsmdpad": true,
|
|
||||||
"td_ontrackend": false,
|
|
||||||
"td_onvia": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"teardrop_parameters": [
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_round_shape",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_rect_shape",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_track_end",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"track_widths": [
|
|
||||||
0.0
|
|
||||||
],
|
|
||||||
"tuning_pattern_settings": {
|
|
||||||
"diff_pair_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 1.0
|
|
||||||
},
|
|
||||||
"diff_pair_skew_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 0.6
|
|
||||||
},
|
|
||||||
"single_track_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 0.6
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"via_dimensions": [
|
|
||||||
{
|
|
||||||
"diameter": 0.0,
|
|
||||||
"drill": 0.0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"zones_allow_external_fillets": false
|
|
||||||
},
|
|
||||||
"ipc2581": {
|
|
||||||
"bom_rev": "",
|
|
||||||
"dist": "",
|
|
||||||
"distpn": "",
|
|
||||||
"internal_id": "",
|
|
||||||
"mfg": "",
|
|
||||||
"mpn": "",
|
|
||||||
"sch_revision": "v0.1"
|
|
||||||
},
|
|
||||||
"layer_pairs": [],
|
|
||||||
"layer_presets": [],
|
|
||||||
"viewports": []
|
|
||||||
},
|
|
||||||
"boards": [],
|
|
||||||
"component_class_settings": {
|
|
||||||
"assignments": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 0
|
|
||||||
},
|
|
||||||
"sheet_component_classes": {
|
|
||||||
"enabled": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cvpcb": {
|
|
||||||
"equivalence_files": []
|
|
||||||
},
|
|
||||||
"erc": {
|
|
||||||
"erc_exclusions": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 0
|
|
||||||
},
|
|
||||||
"pin_map": [
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"rule_severities": {
|
|
||||||
"bus_definition_conflict": "error",
|
|
||||||
"bus_entry_needed": "error",
|
|
||||||
"bus_to_bus_conflict": "error",
|
|
||||||
"bus_to_net_conflict": "error",
|
|
||||||
"different_unit_footprint": "error",
|
|
||||||
"different_unit_net": "error",
|
|
||||||
"duplicate_reference": "error",
|
|
||||||
"duplicate_sheet_names": "error",
|
|
||||||
"endpoint_off_grid": "warning",
|
|
||||||
"extra_units": "error",
|
|
||||||
"field_name_whitespace": "warning",
|
|
||||||
"footprint_filter": "ignore",
|
|
||||||
"footprint_link_issues": "warning",
|
|
||||||
"four_way_junction": "ignore",
|
|
||||||
"ground_pin_not_ground": "warning",
|
|
||||||
"hier_label_mismatch": "error",
|
|
||||||
"isolated_pin_label": "warning",
|
|
||||||
"label_dangling": "error",
|
|
||||||
"label_multiple_wires": "warning",
|
|
||||||
"lib_symbol_issues": "warning",
|
|
||||||
"lib_symbol_mismatch": "warning",
|
|
||||||
"missing_bidi_pin": "warning",
|
|
||||||
"missing_input_pin": "warning",
|
|
||||||
"missing_power_pin": "error",
|
|
||||||
"missing_unit": "warning",
|
|
||||||
"multiple_net_names": "warning",
|
|
||||||
"net_not_bus_member": "warning",
|
|
||||||
"no_connect_connected": "warning",
|
|
||||||
"no_connect_dangling": "warning",
|
|
||||||
"pin_not_connected": "error",
|
|
||||||
"pin_not_driven": "error",
|
|
||||||
"pin_to_pin": "warning",
|
|
||||||
"power_pin_not_driven": "error",
|
|
||||||
"same_local_global_label": "warning",
|
|
||||||
"similar_label_and_power": "warning",
|
|
||||||
"similar_labels": "warning",
|
|
||||||
"similar_power": "warning",
|
|
||||||
"simulation_model_issue": "ignore",
|
|
||||||
"single_global_label": "ignore",
|
|
||||||
"stacked_pin_name": "warning",
|
|
||||||
"unannotated": "error",
|
|
||||||
"unconnected_wire_endpoint": "warning",
|
|
||||||
"undefined_netclass": "error",
|
|
||||||
"unit_value_mismatch": "error",
|
|
||||||
"unresolved_variable": "error",
|
|
||||||
"wire_dangling": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libraries": {
|
|
||||||
"pinned_footprint_libs": [],
|
|
||||||
"pinned_symbol_libs": []
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"filename": "c_its-companion.kicad_pro",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"net_settings": {
|
|
||||||
"classes": [
|
|
||||||
{
|
|
||||||
"bus_width": 12,
|
|
||||||
"clearance": 0.2,
|
|
||||||
"diff_pair_gap": 0.25,
|
|
||||||
"diff_pair_via_gap": 0.25,
|
|
||||||
"diff_pair_width": 0.2,
|
|
||||||
"line_style": 0,
|
|
||||||
"microvia_diameter": 0.3,
|
|
||||||
"microvia_drill": 0.1,
|
|
||||||
"name": "Default",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"priority": 2147483647,
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.2,
|
|
||||||
"tuning_profile": "",
|
|
||||||
"via_diameter": 0.6,
|
|
||||||
"via_drill": 0.3,
|
|
||||||
"wire_width": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Power",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"priority": 0,
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.5,
|
|
||||||
"tuning_profile": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"version": 5
|
|
||||||
},
|
|
||||||
"net_colors": null,
|
|
||||||
"netclass_assignments": null,
|
|
||||||
"netclass_patterns": [
|
|
||||||
{
|
|
||||||
"netclass": "Power",
|
|
||||||
"pattern": "GND"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"netclass": "Power",
|
|
||||||
"pattern": "+3V3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"netclass": "Power",
|
|
||||||
"pattern": "/BAT*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"netclass": "Power",
|
|
||||||
"pattern": "/V_*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pcbnew": {
|
|
||||||
"last_paths": {
|
|
||||||
"idf": "",
|
|
||||||
"netlist": "",
|
|
||||||
"plot": "",
|
|
||||||
"specctra_dsn": "",
|
|
||||||
"vrml": ""
|
|
||||||
},
|
|
||||||
"page_layout_descr_file": ""
|
|
||||||
},
|
|
||||||
"schematic": {
|
|
||||||
"annotate_start_num": 0,
|
|
||||||
"annotation": {
|
|
||||||
"method": 0,
|
|
||||||
"sort_order": 0
|
|
||||||
},
|
|
||||||
"bom_export_filename": "${PROJECTNAME}.csv",
|
|
||||||
"bom_fmt_presets": [],
|
|
||||||
"bom_fmt_settings": {
|
|
||||||
"field_delimiter": ",",
|
|
||||||
"keep_line_breaks": false,
|
|
||||||
"keep_tabs": false,
|
|
||||||
"name": "CSV",
|
|
||||||
"ref_delimiter": ",",
|
|
||||||
"ref_range_delimiter": "",
|
|
||||||
"string_delimiter": "\""
|
|
||||||
},
|
|
||||||
"bom_presets": [],
|
|
||||||
"bom_settings": {
|
|
||||||
"exclude_dnp": false,
|
|
||||||
"fields_ordered": [
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Reference",
|
|
||||||
"name": "Reference",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Qty",
|
|
||||||
"name": "${QUANTITY}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Value",
|
|
||||||
"name": "Value",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "DNP",
|
|
||||||
"name": "${DNP}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Exclude from BOM",
|
|
||||||
"name": "${EXCLUDE_FROM_BOM}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Exclude from Board",
|
|
||||||
"name": "${EXCLUDE_FROM_BOARD}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Footprint",
|
|
||||||
"name": "Footprint",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Datasheet",
|
|
||||||
"name": "Datasheet",
|
|
||||||
"show": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"filter_string": "",
|
|
||||||
"group_symbols": true,
|
|
||||||
"include_excluded_from_bom": true,
|
|
||||||
"name": "Default Editing",
|
|
||||||
"sort_asc": true,
|
|
||||||
"sort_field": "Reference"
|
|
||||||
},
|
|
||||||
"bus_aliases": {},
|
|
||||||
"connection_grid_size": 50.0,
|
|
||||||
"drawing": {
|
|
||||||
"dashed_lines_dash_length_ratio": 12.0,
|
|
||||||
"dashed_lines_gap_length_ratio": 3.0,
|
|
||||||
"default_line_thickness": 6.0,
|
|
||||||
"default_text_size": 50.0,
|
|
||||||
"field_names": [],
|
|
||||||
"hop_over_size_choice": 0,
|
|
||||||
"intersheets_ref_own_page": false,
|
|
||||||
"intersheets_ref_prefix": "",
|
|
||||||
"intersheets_ref_short": false,
|
|
||||||
"intersheets_ref_show": false,
|
|
||||||
"intersheets_ref_suffix": "",
|
|
||||||
"junction_size_choice": 3,
|
|
||||||
"label_size_ratio": 0.375,
|
|
||||||
"operating_point_overlay_i_precision": 3,
|
|
||||||
"operating_point_overlay_i_range": "~A",
|
|
||||||
"operating_point_overlay_v_precision": 3,
|
|
||||||
"operating_point_overlay_v_range": "~V",
|
|
||||||
"overbar_offset_ratio": 1.23,
|
|
||||||
"pin_symbol_size": 25.0,
|
|
||||||
"text_offset_ratio": 0.15
|
|
||||||
},
|
|
||||||
"legacy_lib_dir": "",
|
|
||||||
"legacy_lib_list": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 1
|
|
||||||
},
|
|
||||||
"page_layout_descr_file": "",
|
|
||||||
"plot_directory": "",
|
|
||||||
"reuse_designators": true,
|
|
||||||
"subpart_first_id": 65,
|
|
||||||
"subpart_id_separator": 0,
|
|
||||||
"top_level_sheets": [
|
|
||||||
{
|
|
||||||
"filename": "c_its-companion.kicad_sch",
|
|
||||||
"name": "Root",
|
|
||||||
"uuid": "9ad468b0-d7e4-4d4a-b652-c4a81a952e30"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"used_designators": "C1,#PWR1-10,J1-2,SW1,TP1,U1-2,#FLG1-3",
|
|
||||||
"variants": []
|
|
||||||
},
|
|
||||||
"sheets": [
|
|
||||||
[
|
|
||||||
"9ad468b0-d7e4-4d4a-b652-c4a81a952e30",
|
|
||||||
"Root"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"text_variables": {},
|
|
||||||
"tuning_profiles": {
|
|
||||||
"meta": {
|
|
||||||
"version": 0
|
|
||||||
},
|
|
||||||
"tuning_profiles_impedance_geometric": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1 +0,0 @@
|
||||||
{"ARCHIVE_NAME": "", "EXTRA_LAYERS": "", "ALL_ACTIVE_LAYERS": false, "EXTEND_EDGE_CUT": false, "ALTERNATIVE_EDGE_CUT": false, "AUTO TRANSLATE": true, "AUTO FILL": true, "EXCLUDE DNP": false, "OPEN BROWSER": true, "BACKUP_OPT": true}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
(fp_lib_table
|
|
||||||
(version 7)
|
|
||||||
(lib (name "library") (type "KiCad") (uri "${KIPRJMOD}/library") (options "") (descr ""))
|
|
||||||
)
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,542 +0,0 @@
|
||||||
(footprint "XIAO-ESP32-C5-DIP"
|
|
||||||
(version 20241229)
|
|
||||||
(generator "pcbnew")
|
|
||||||
(generator_version "9.0")
|
|
||||||
(layer "F.Cu")
|
|
||||||
(property "Reference" "REF**"
|
|
||||||
(at -0.275 -10.275 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "7bab359d-5e5b-4dff-9db4-e7c8562ce635")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 0.635 0.635)
|
|
||||||
(thickness 0.1016)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Value" "XIAO-ESP32-C5-DIP"
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "79cabf23-4ebc-4d37-9172-bb2cf4ea975f")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 0.635 0.635)
|
|
||||||
(thickness 0.1016)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Datasheet" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "663dc686-104e-47e1-9669-e1228477fa6f")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Description" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "a25b2a4a-94ce-41bd-8341-b98204aa9142")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(attr smd)
|
|
||||||
(fp_line
|
|
||||||
(start -10.414 -6.985)
|
|
||||||
(end -10.414 6.985)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "e213e2f5-659f-4cdb-b390-b284746621aa")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -8.509 -8.89)
|
|
||||||
(end 8.636 -8.89)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "f58afa0e-63f9-4096-9d17-7cf8e5de7759")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -8.509 8.89)
|
|
||||||
(end 8.636 8.89)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "9c6409b2-5f1b-4299-85bf-d07c96f13a2a")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 10.541 -4.495)
|
|
||||||
(end 11.551272 -4.491272)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "4c45fdff-98df-401f-bf6d-768af24b67a9")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 10.541 6.985)
|
|
||||||
(end 10.541 -6.985)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "eb7ba2c6-3729-4940-9c6b-4ac369cf3075")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 10.541 6.985)
|
|
||||||
(end 10.541 -6.985)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "6f680559-bbef-46de-9ef5-efda7c2411e9")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 11.551 4.504)
|
|
||||||
(end 10.541 4.504)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "eddbec16-11c2-42ad-90d6-191cfc991c10")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 12.051 -3.991272)
|
|
||||||
(end 12.051 4.004)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "e973f8d1-81df-437d-bffe-4f734e1ac18e")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start -10.414 -6.985)
|
|
||||||
(mid -9.856038 -8.332038)
|
|
||||||
(end -8.509 -8.89)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "88e5d6ea-6b70-4830-9817-980fd2b32f79")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start -8.509 8.89)
|
|
||||||
(mid -9.856038 8.332038)
|
|
||||||
(end -10.414 6.985)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "f108f05c-d5f6-4de1-bc6f-4c31ef53e967")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 8.636 -8.89)
|
|
||||||
(mid 9.983038 -8.332038)
|
|
||||||
(end 10.541 -6.985)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "c6870bc4-897a-485a-b951-3feda1bdd32e")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 10.541 6.985)
|
|
||||||
(mid 9.983038 8.332038)
|
|
||||||
(end 8.636 8.89)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "e1d8f660-1495-43db-8a6b-7fdc7dc42e35")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 11.551272 -4.491272)
|
|
||||||
(mid 11.904644 -4.344724)
|
|
||||||
(end 12.051 -3.991272)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "a9b2ba2a-ad25-4191-9070-ebc0333a9101")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 12.051 4.004)
|
|
||||||
(mid 11.904553 4.357553)
|
|
||||||
(end 11.551 4.504)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "45e349ac-e285-4bed-a05b-ae5a80336af0")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 9.37 -7.857)
|
|
||||||
(end 9.624 -7.857)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "6839324b-c75a-49ba-8c0c-16e2191166eb")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 10.25 -9)
|
|
||||||
(end 10.504 -9)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "6e5f4857-2ad9-4493-8234-6091a6821232")
|
|
||||||
)
|
|
||||||
(fp_rect
|
|
||||||
(start -10.425 -8.9)
|
|
||||||
(end 10.55 8.9)
|
|
||||||
(stroke
|
|
||||||
(width 0.05)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(fill no)
|
|
||||||
(layer "F.CrtYd")
|
|
||||||
(uuid "b53697bc-d105-40e2-af66-708b16a7f26c")
|
|
||||||
)
|
|
||||||
(fp_rect
|
|
||||||
(start -10.425 -8.9)
|
|
||||||
(end 10.55 8.9)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(fill no)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "a45a327e-f036-4877-8d89-39f4f4b0c715")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 9.376 -7.854)
|
|
||||||
(end 9.63 -7.854)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "12a1812e-f866-498e-9d6e-50e427087f34")
|
|
||||||
)
|
|
||||||
(pad "1" smd roundrect
|
|
||||||
(at 7.62 -8.455 90)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "82bbfb55-8baa-4218-ac89-ab07d82ef7f8")
|
|
||||||
)
|
|
||||||
(pad "1" thru_hole circle
|
|
||||||
(at 7.62 -7.62 90)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "f2fffd4f-460c-4b4d-b954-811e935ed1d6")
|
|
||||||
)
|
|
||||||
(pad "2" smd roundrect
|
|
||||||
(at 5.08 -8.455 90)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "18ef9914-2d15-494c-9020-2334abcc1460")
|
|
||||||
)
|
|
||||||
(pad "2" thru_hole circle
|
|
||||||
(at 5.08 -7.62 90)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "4732cc3f-e641-4870-a9b3-ae13729c7bba")
|
|
||||||
)
|
|
||||||
(pad "3" smd roundrect
|
|
||||||
(at 2.54 -8.455 90)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "15338a55-8514-4218-a2c1-2cae003104c3")
|
|
||||||
)
|
|
||||||
(pad "3" thru_hole circle
|
|
||||||
(at 2.54 -7.62 90)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "0cef5e55-d8ff-4394-9cc1-cc318608b0d9")
|
|
||||||
)
|
|
||||||
(pad "4" smd roundrect
|
|
||||||
(at 0 -8.455 90)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "191a259d-5773-4a80-91de-baa69611fab8")
|
|
||||||
)
|
|
||||||
(pad "4" thru_hole circle
|
|
||||||
(at 0 -7.62 90)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "200b8da4-9395-48a5-b7ac-92a6a147c215")
|
|
||||||
)
|
|
||||||
(pad "5" smd roundrect
|
|
||||||
(at -2.54 -8.455 90)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "52012467-1c46-4a8e-aa82-6f6ce69bd2ca")
|
|
||||||
)
|
|
||||||
(pad "5" thru_hole circle
|
|
||||||
(at -2.54 -7.62 90)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "2b50ccce-3634-47d1-bf7d-a3db4f3f9a9f")
|
|
||||||
)
|
|
||||||
(pad "6" smd roundrect
|
|
||||||
(at -5.08 -8.455 90)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "04aeaf95-142a-40f6-97a3-04453fc50824")
|
|
||||||
)
|
|
||||||
(pad "6" thru_hole circle
|
|
||||||
(at -5.08 -7.62 90)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "7636de9d-d8e5-49c9-9fff-0cd76515690d")
|
|
||||||
)
|
|
||||||
(pad "7" smd roundrect
|
|
||||||
(at -7.62 -8.455 90)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "e997fd0b-233a-4656-afad-cb2f8b9d87c9")
|
|
||||||
)
|
|
||||||
(pad "7" thru_hole circle
|
|
||||||
(at -7.62 -7.62 90)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "9d2c0d0c-05dd-477e-8384-b14eec83fc2e")
|
|
||||||
)
|
|
||||||
(pad "8" thru_hole circle
|
|
||||||
(at -7.62 7.62 270)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "1e50c66f-49b8-4b03-9889-8cc6ca45ad8e")
|
|
||||||
)
|
|
||||||
(pad "8" smd roundrect
|
|
||||||
(at -7.62 8.455 270)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "e7b72803-b5f0-433c-8313-83247355fb43")
|
|
||||||
)
|
|
||||||
(pad "9" thru_hole circle
|
|
||||||
(at -5.08 7.62 270)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "808bf9dc-1c26-4a77-93c9-e4c6d5eccbb2")
|
|
||||||
)
|
|
||||||
(pad "9" smd roundrect
|
|
||||||
(at -5.08 8.455 270)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "532de3b6-bd30-47c5-b70e-0bca6abbd997")
|
|
||||||
)
|
|
||||||
(pad "10" thru_hole circle
|
|
||||||
(at -2.54 7.62 270)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "a792a2ac-537b-4136-8f92-b81f7ce8f753")
|
|
||||||
)
|
|
||||||
(pad "10" smd roundrect
|
|
||||||
(at -2.54 8.455 270)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "6e3f5c75-6143-468e-bb07-d89020c03f59")
|
|
||||||
)
|
|
||||||
(pad "11" thru_hole circle
|
|
||||||
(at 0 7.62 270)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "fb78046a-9b91-4893-b010-827957cc07be")
|
|
||||||
)
|
|
||||||
(pad "11" smd roundrect
|
|
||||||
(at 0 8.455 270)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "5249f425-bece-432d-8076-28e1b8b386e3")
|
|
||||||
)
|
|
||||||
(pad "12" thru_hole circle
|
|
||||||
(at 2.54 7.62 270)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "0b8ccc97-5100-4dcf-8500-e99789ee0b4c")
|
|
||||||
)
|
|
||||||
(pad "12" smd roundrect
|
|
||||||
(at 2.54 8.455 270)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "82f1bbd1-708b-4d2d-9113-7ba3c2313670")
|
|
||||||
)
|
|
||||||
(pad "13" thru_hole circle
|
|
||||||
(at 5.08 7.62 270)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "03882061-01af-484b-b620-9e92a3daaf68")
|
|
||||||
)
|
|
||||||
(pad "13" smd roundrect
|
|
||||||
(at 5.08 8.455 270)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "954f51d1-3d75-42fb-a02a-7389b30718d9")
|
|
||||||
)
|
|
||||||
(pad "14" thru_hole circle
|
|
||||||
(at 7.62 7.62 270)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "c6d1af47-da13-4409-9ab1-55d358cc57eb")
|
|
||||||
)
|
|
||||||
(pad "14" smd roundrect
|
|
||||||
(at 7.62 8.455 270)
|
|
||||||
(size 2.432 1.524)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(roundrect_rratio 0.1)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "6b725fd4-d6f0-46bf-b3e0-7ec07cc05622")
|
|
||||||
)
|
|
||||||
(embedded_fonts no)
|
|
||||||
(model "${AMZPATH}/3dmodels/AMz3D.3dshapes/XIAO-nRF52840 v15.step"
|
|
||||||
(hide yes)
|
|
||||||
(offset
|
|
||||||
(xyz -1.778 -6.096 0.381)
|
|
||||||
)
|
|
||||||
(scale
|
|
||||||
(xyz 1 1 1)
|
|
||||||
)
|
|
||||||
(rotate
|
|
||||||
(xyz -90 0 0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(model "${AMZPATH}/3dmodels/AMz3D.3dshapes/Seeeduino XIAO SAMD21 v4.step"
|
|
||||||
(offset
|
|
||||||
(xyz 0 0 0)
|
|
||||||
)
|
|
||||||
(scale
|
|
||||||
(xyz 1 1 1)
|
|
||||||
)
|
|
||||||
(rotate
|
|
||||||
(xyz 0 0 0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(model "${AMZPATH}/3dmodels/AMz3D.3dshapes/Seeed Studio XIAO RP2040 v26.step"
|
|
||||||
(hide yes)
|
|
||||||
(offset
|
|
||||||
(xyz 0 0 0)
|
|
||||||
)
|
|
||||||
(scale
|
|
||||||
(xyz 1 1 1)
|
|
||||||
)
|
|
||||||
(rotate
|
|
||||||
(xyz 0 0 90)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(model "${AMZPATH}/3dmodels/AMz3D.3dshapes/Seeed Studio XIAO-ESP32-C3.step"
|
|
||||||
(hide yes)
|
|
||||||
(offset
|
|
||||||
(xyz -1.7018 -6.096 0)
|
|
||||||
)
|
|
||||||
(scale
|
|
||||||
(xyz 1 1 1)
|
|
||||||
)
|
|
||||||
(rotate
|
|
||||||
(xyz -90 0 0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(model "${AMZPATH}/3dmodels/AMz3D.3dshapes/XIAO-ESP32S3 v2.step"
|
|
||||||
(hide yes)
|
|
||||||
(offset
|
|
||||||
(xyz -1.778 -6.1722 0)
|
|
||||||
)
|
|
||||||
(scale
|
|
||||||
(xyz 1 1 1)
|
|
||||||
)
|
|
||||||
(rotate
|
|
||||||
(xyz -90 0 0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
@ -1,558 +0,0 @@
|
||||||
(footprint "XIAO-ESP32-C5-SMD-DIP"
|
|
||||||
(version 20260206)
|
|
||||||
(generator "pcbnew")
|
|
||||||
(generator_version "10.0")
|
|
||||||
(layer "F.Cu")
|
|
||||||
(property "Reference" "REF**"
|
|
||||||
(at 7.312 -21.336 0)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "95a6896c-2eab-4f28-adc5-7fd64550efd1")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 0.78232 0.78232)
|
|
||||||
(thickness 0.10668)
|
|
||||||
)
|
|
||||||
(justify left bottom)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Value" "Val**"
|
|
||||||
(at 8.89 -10.795 0)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "ead571aa-8f25-4413-9dd8-3ecea3d8b1b5")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 0.536448 0.536448)
|
|
||||||
(thickness 0.073152)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Datasheet" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "e0e614f2-f99b-42a7-87d5-6d40f74c047a")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Description" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "074d8848-2ba7-4146-8c49-a0cf65e2aa82")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(duplicate_pad_numbers_are_jumpers no)
|
|
||||||
(fp_line
|
|
||||||
(start 0 -1.987)
|
|
||||||
(end 0 -19.132)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "e72c3c07-5bc8-4f5f-97cd-36412308e250")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.905 -0.082)
|
|
||||||
(end 15.875 -0.082)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "e3e0ab25-f18a-4068-92e8-92a17b4caf05")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 4.595 -21.037)
|
|
||||||
(end 4.598728 -22.047272)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "4838598f-afa6-445e-b237-7544ae7e9968")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 5.098728 -22.547)
|
|
||||||
(end 13.094 -22.547)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "101b5417-f570-447c-b9f6-42639e5eff3c")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 13.594 -22.047)
|
|
||||||
(end 13.594 -21.037)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "37ee6532-c85a-4899-82db-921e02cce4af")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 15.875 -21.037)
|
|
||||||
(end 1.905 -21.037)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "f94b2798-d11f-47d7-8f2c-02478417b6f1")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 17.78 -1.987)
|
|
||||||
(end 17.78 -19.132)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "8c3282cc-86c2-4cf3-a698-856916df5f40")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 0 -19.136)
|
|
||||||
(mid 0.557962 -20.483038)
|
|
||||||
(end 1.905 -21.041)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "2a1b788b-cdcf-4a49-acac-d187cf344ffc")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 1.905 -0.082)
|
|
||||||
(mid 0.557962 -0.639962)
|
|
||||||
(end 0 -1.987)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "677c2a8e-0212-4651-99b4-af42d29d0bd1")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 4.598728 -22.047272)
|
|
||||||
(mid 4.745276 -22.400644)
|
|
||||||
(end 5.098728 -22.547)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "b38fc005-51b4-4609-b7e3-78320e82da0d")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 13.094 -22.547)
|
|
||||||
(mid 13.447553 -22.400553)
|
|
||||||
(end 13.594 -22.047)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "46a43512-01fe-440e-b1e8-31a50057cbf8")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 15.875 -21.037)
|
|
||||||
(mid 17.222038 -20.479038)
|
|
||||||
(end 17.78 -19.132)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "f77dffb2-d331-43db-9018-069e9fa47c57")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 17.78 -1.987)
|
|
||||||
(mid 17.222038 -0.639962)
|
|
||||||
(end 15.875 -0.082)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "535b0a70-da0d-4557-a5dd-d25a51ee5468")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center -0.21 -20.621)
|
|
||||||
(end -0.21 -20.875)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "c4f8c64e-4c5d-41c1-8b14-aca8fcf77968")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 1.064 -19.904)
|
|
||||||
(end 1.064 -20.158)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "163ea809-1cd6-43c9-968e-14c093715603")
|
|
||||||
)
|
|
||||||
(fp_rect
|
|
||||||
(start 17.8 0)
|
|
||||||
(end 0 -21)
|
|
||||||
(stroke
|
|
||||||
(width 0.05)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(fill no)
|
|
||||||
(layer "F.CrtYd")
|
|
||||||
(uuid "477d102d-f2d0-4f67-ad93-9f60da51bd76")
|
|
||||||
)
|
|
||||||
(fp_rect
|
|
||||||
(start 0 -21)
|
|
||||||
(end 17.8 0)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(fill no)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "e7107e2f-485b-49f6-9f5d-2537ab0ef458")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 1.084 -19.9)
|
|
||||||
(end 1.084 -20.154)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "089122fe-193e-4cef-a9b8-54d37cb7fa99")
|
|
||||||
)
|
|
||||||
(pad "1" smd roundrect
|
|
||||||
(at 0.835 -18.12)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "351f5f05-8bc3-4b53-9daf-3207bd71876b")
|
|
||||||
)
|
|
||||||
(pad "1" thru_hole circle
|
|
||||||
(at 1.26 -18.14 180)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "6a16c3b2-8d4e-4efe-a84e-dbc418c7fe79")
|
|
||||||
)
|
|
||||||
(pad "2" smd roundrect
|
|
||||||
(at 0.835 -15.58)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "cfdee4aa-d600-484f-9a5c-2062a00bde1d")
|
|
||||||
)
|
|
||||||
(pad "2" thru_hole circle
|
|
||||||
(at 1.26 -15.6 180)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "69193d02-4e31-4519-a90d-949c3f48e92c")
|
|
||||||
)
|
|
||||||
(pad "3" smd roundrect
|
|
||||||
(at 0.835 -13.04)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "52a69e1c-edab-4079-a491-6bcb12907f61")
|
|
||||||
)
|
|
||||||
(pad "3" thru_hole circle
|
|
||||||
(at 1.26 -13.06 180)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "a3aed707-7e8b-4b1b-ba96-06cfb9154fcb")
|
|
||||||
)
|
|
||||||
(pad "4" smd roundrect
|
|
||||||
(at 0.835 -10.5)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "1e864c46-432c-460c-af69-13a1c9d0fd2f")
|
|
||||||
)
|
|
||||||
(pad "4" thru_hole circle
|
|
||||||
(at 1.26 -10.52 180)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "eee65312-1942-42a1-a13a-2a28a114ec95")
|
|
||||||
)
|
|
||||||
(pad "5" smd roundrect
|
|
||||||
(at 0.835 -7.96)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "da854e17-c3b3-4a83-9d47-a379e4d7efa5")
|
|
||||||
)
|
|
||||||
(pad "5" thru_hole circle
|
|
||||||
(at 1.26 -7.98 180)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "febdd29f-f361-4b8e-b2b5-7502d3e5fdea")
|
|
||||||
)
|
|
||||||
(pad "6" smd roundrect
|
|
||||||
(at 0.835 -5.42)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "3fde7f90-983d-44c1-939e-47d36175373f")
|
|
||||||
)
|
|
||||||
(pad "6" thru_hole circle
|
|
||||||
(at 1.26 -5.44 180)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "323ef0a5-3407-4ac3-b76f-8ac19e044d1e")
|
|
||||||
)
|
|
||||||
(pad "7" smd roundrect
|
|
||||||
(at 0.835 -2.88)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "ebfd6bef-ea17-4635-877b-58b57c784dec")
|
|
||||||
)
|
|
||||||
(pad "7" thru_hole circle
|
|
||||||
(at 1.26 -2.9 180)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "2b179783-65b0-4d7c-850b-74c9fa3a7a64")
|
|
||||||
)
|
|
||||||
(pad "8" thru_hole circle
|
|
||||||
(at 16.5 -2.9)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "5cbc8aa6-fdfd-49e6-b018-da1d4ff342aa")
|
|
||||||
)
|
|
||||||
(pad "8" smd roundrect
|
|
||||||
(at 17 -2.88)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "19eb14d0-5713-47b7-86f2-4bccede8ba54")
|
|
||||||
)
|
|
||||||
(pad "9" thru_hole circle
|
|
||||||
(at 16.5 -5.44)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "e7f197b5-1fc8-47f6-9f49-60ffd6fa2335")
|
|
||||||
)
|
|
||||||
(pad "9" smd roundrect
|
|
||||||
(at 17 -5.42)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "4c3b83bc-a000-4a70-887c-6b775bc40ee1")
|
|
||||||
)
|
|
||||||
(pad "10" thru_hole circle
|
|
||||||
(at 16.5 -7.98)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "4df7fd17-71d5-4f8f-a3f2-68c6537a767f")
|
|
||||||
)
|
|
||||||
(pad "10" smd roundrect
|
|
||||||
(at 17 -7.96)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "223d5c33-d2a3-4398-8d3f-544bd6345a86")
|
|
||||||
)
|
|
||||||
(pad "11" thru_hole circle
|
|
||||||
(at 16.5 -10.52)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "dad67976-a604-485a-bb37-2d67ea771b2c")
|
|
||||||
)
|
|
||||||
(pad "11" smd roundrect
|
|
||||||
(at 17 -10.5)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "1f04f1d2-ce82-4256-b122-36f63f189efe")
|
|
||||||
)
|
|
||||||
(pad "12" thru_hole circle
|
|
||||||
(at 16.5 -13.06)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "c55d522b-9f8b-4fa4-afaa-880f3b1c9c5f")
|
|
||||||
)
|
|
||||||
(pad "12" smd roundrect
|
|
||||||
(at 17 -13.04)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "31818d88-bbc0-4c22-b4ed-d6884ef71ebb")
|
|
||||||
)
|
|
||||||
(pad "13" thru_hole circle
|
|
||||||
(at 16.5 -15.6)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "e46165bc-b289-44b0-b7f6-6759bba3d4b8")
|
|
||||||
)
|
|
||||||
(pad "13" smd roundrect
|
|
||||||
(at 17 -15.58)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "3fbf02f8-81da-4fba-bc95-9e47b9abaa05")
|
|
||||||
)
|
|
||||||
(pad "14" thru_hole circle
|
|
||||||
(at 16.5 -18.14)
|
|
||||||
(size 1.524 1.524)
|
|
||||||
(drill 0.889)
|
|
||||||
(layers "*.Cu" "*.Mask")
|
|
||||||
(remove_unused_layers no)
|
|
||||||
(uuid "71ca3093-fd4e-46c3-9980-6d986d711719")
|
|
||||||
)
|
|
||||||
(pad "14" smd roundrect
|
|
||||||
(at 17 -18.12)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "ce7a6ff3-5c3a-4077-bf86-beedc24debb3")
|
|
||||||
)
|
|
||||||
(pad "15" smd circle
|
|
||||||
(at 7.6166 -19.1415)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "7273149b-9aea-4a23-9b4e-db1e0d6c76fc")
|
|
||||||
)
|
|
||||||
(pad "16" smd circle
|
|
||||||
(at 10.1566 -19.1415)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "0aef11c3-14ad-4cb5-9b05-95a892988ce8")
|
|
||||||
)
|
|
||||||
(pad "17" smd circle
|
|
||||||
(at 7.6166 -16.6015)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "158a5cbb-af86-4fa6-8d58-6831485085c5")
|
|
||||||
)
|
|
||||||
(pad "18" smd circle
|
|
||||||
(at 10.1566 -16.6015)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "3b7bcd8a-c97c-46f6-9faa-4e525d03d6e8")
|
|
||||||
)
|
|
||||||
(pad "19" smd circle
|
|
||||||
(at 7.6166 -14.0615)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "ad4ba963-211d-4878-a4cb-255a615c14de")
|
|
||||||
)
|
|
||||||
(pad "20" smd circle
|
|
||||||
(at 10.1566 -14.0615)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "8c7e088d-0846-4d7d-9143-5ce3fdb0c4fd")
|
|
||||||
)
|
|
||||||
(pad "21" smd circle
|
|
||||||
(at 7.6166 -11.5215)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "c6bbe198-c8c7-4b83-a36e-6a6fdeb3b94f")
|
|
||||||
)
|
|
||||||
(pad "22" smd circle
|
|
||||||
(at 10.064 -11.5783)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "4f1e574b-3b71-4a23-b765-d779726fd3c6")
|
|
||||||
)
|
|
||||||
(pad "23" smd roundrect
|
|
||||||
(at 7.3086 -4.9683 270)
|
|
||||||
(size 2.5 1.1)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "08d345bf-1b32-499f-94bb-44332eb5115d")
|
|
||||||
)
|
|
||||||
(pad "24" smd roundrect
|
|
||||||
(at 9.8486 -4.9683 270)
|
|
||||||
(size 2.5 1.1)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "8b3ca1bb-eee0-4c3d-8f3b-eefea4a68bbb")
|
|
||||||
)
|
|
||||||
(pad "25" smd roundrect
|
|
||||||
(at 9.949 -8.412 270)
|
|
||||||
(size 3.1 1.9)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "45570478-e499-45ab-bb97-539cabc4e177")
|
|
||||||
)
|
|
||||||
(embedded_fonts no)
|
|
||||||
)
|
|
||||||
|
|
@ -1,445 +0,0 @@
|
||||||
(footprint "XIAO-ESP32-C5-SMD"
|
|
||||||
(version 20241229)
|
|
||||||
(generator "pcbnew")
|
|
||||||
(generator_version "9.0")
|
|
||||||
(layer "F.Cu")
|
|
||||||
(property "Reference" "REF**"
|
|
||||||
(at 7.312 -21.336 0)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "a9f5f5dd-597c-45dd-b31d-a35c3963eed2")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 0.78232 0.78232)
|
|
||||||
(thickness 0.10668)
|
|
||||||
)
|
|
||||||
(justify left bottom)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Value" "Val**"
|
|
||||||
(at 8.89 -10.795 0)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "2d66aca7-e0b3-44df-838e-be285890792c")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 0.536448 0.536448)
|
|
||||||
(thickness 0.073152)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Datasheet" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "5173b428-b87b-497c-9fd1-0d444c2ced85")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Description" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "ea7181c4-fdca-44f1-ad15-d0627f50a68e")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 0 -1.987)
|
|
||||||
(end 0 -19.132)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "df0486b4-d04f-4201-a301-beede6e15862")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.905 -0.082)
|
|
||||||
(end 15.875 -0.082)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "f54abd8d-62ed-4b05-8e37-f29acdadc0f8")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 4.595 -21.037)
|
|
||||||
(end 4.598728 -22.047272)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "fead6daa-b9f4-4bd1-a131-b5d2cd3184de")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 5.098728 -22.547)
|
|
||||||
(end 13.094 -22.547)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "b90ae92d-7c1a-4689-bf64-c3528a3ea3ee")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 13.594 -22.047)
|
|
||||||
(end 13.594 -21.037)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "b540fbcc-8e06-44d7-95f6-8b142e4c90fb")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 15.875 -21.037)
|
|
||||||
(end 1.905 -21.037)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "2b80542c-5088-4f89-ae32-3400cf894ca1")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 17.78 -1.987)
|
|
||||||
(end 17.78 -19.132)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "4cd8add0-8a8c-468d-ba6f-b86787c288af")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 0 -19.136)
|
|
||||||
(mid 0.557962 -20.483038)
|
|
||||||
(end 1.905 -21.041)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "4d9bf7a5-4ab4-48bb-b8ac-0a5ce4523642")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 1.905 -0.082)
|
|
||||||
(mid 0.557962 -0.639962)
|
|
||||||
(end 0 -1.987)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "d09661c8-1ad3-40e9-8323-9dabc8f3f98b")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 4.598728 -22.047272)
|
|
||||||
(mid 4.745276 -22.400644)
|
|
||||||
(end 5.098728 -22.547)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "7a58f637-14d7-4804-b127-f1d029b5d1e6")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 13.094 -22.547)
|
|
||||||
(mid 13.447553 -22.400553)
|
|
||||||
(end 13.594 -22.047)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "d0bc8663-987f-4e2e-b464-096a547b822f")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 15.875 -21.037)
|
|
||||||
(mid 17.222038 -20.479038)
|
|
||||||
(end 17.78 -19.132)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "77004ea5-53a4-40ab-b35c-7bdd22107e34")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 17.78 -1.987)
|
|
||||||
(mid 17.222038 -0.639962)
|
|
||||||
(end 15.875 -0.082)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "94189dc1-14b5-4f17-b9d3-0163ed99e583")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center -0.21 -20.621)
|
|
||||||
(end -0.21 -20.875)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "dc606cc5-10bc-4635-81d1-fa27b1e6b4e2")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 1.064 -19.904)
|
|
||||||
(end 1.064 -20.158)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "2b5e2829-6d01-441f-9983-fc4a273ff483")
|
|
||||||
)
|
|
||||||
(fp_rect
|
|
||||||
(start 17.8 0)
|
|
||||||
(end 0 -21)
|
|
||||||
(stroke
|
|
||||||
(width 0.05)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(fill no)
|
|
||||||
(layer "F.CrtYd")
|
|
||||||
(uuid "e428eb56-00a2-4249-bb91-d2e5823b2899")
|
|
||||||
)
|
|
||||||
(fp_rect
|
|
||||||
(start 0 -21)
|
|
||||||
(end 17.8 0)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(fill no)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "2133d927-559d-4615-ab92-732772c02d94")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 1.084 -19.9)
|
|
||||||
(end 1.084 -20.154)
|
|
||||||
(stroke
|
|
||||||
(width 0.5)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "50e04a65-8ff2-4d1f-be98-2db48101e90a")
|
|
||||||
)
|
|
||||||
(pad "1" smd roundrect
|
|
||||||
(at 0.835 -18.12)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "c68f6b12-dcf5-46b1-b159-2eef9023b0ac")
|
|
||||||
)
|
|
||||||
(pad "2" smd roundrect
|
|
||||||
(at 0.835 -15.58)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "525b09fc-9099-4274-98c3-45f84d0591ab")
|
|
||||||
)
|
|
||||||
(pad "3" smd roundrect
|
|
||||||
(at 0.835 -13.04)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "99cc76a7-0a78-4868-871b-c214ecac5525")
|
|
||||||
)
|
|
||||||
(pad "4" smd roundrect
|
|
||||||
(at 0.835 -10.5)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "8038b67b-b3bf-4a3e-b790-40857963c957")
|
|
||||||
)
|
|
||||||
(pad "5" smd roundrect
|
|
||||||
(at 0.835 -7.96)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "84711cb2-d222-464e-bcd5-f76af75cc612")
|
|
||||||
)
|
|
||||||
(pad "6" smd roundrect
|
|
||||||
(at 0.835 -5.42)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "aabcfc3b-fa72-4e48-95d1-d53474158cc0")
|
|
||||||
)
|
|
||||||
(pad "7" smd roundrect
|
|
||||||
(at 0.835 -2.88)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "3e086061-1f3f-4b1e-9354-920126d40249")
|
|
||||||
)
|
|
||||||
(pad "8" smd roundrect
|
|
||||||
(at 17 -2.88)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "974a7e29-b5d3-475c-b481-2bc14f5b3495")
|
|
||||||
)
|
|
||||||
(pad "9" smd roundrect
|
|
||||||
(at 17 -5.42)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "a553cc0b-22bc-49aa-9fb7-680c812e8abd")
|
|
||||||
)
|
|
||||||
(pad "10" smd roundrect
|
|
||||||
(at 17 -7.96)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "b650936d-c436-4d93-abb7-7957add5cfb1")
|
|
||||||
)
|
|
||||||
(pad "11" smd roundrect
|
|
||||||
(at 17 -10.5)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "177728f1-7b02-41a6-9de4-bdaee546f6d9")
|
|
||||||
)
|
|
||||||
(pad "12" smd roundrect
|
|
||||||
(at 17 -13.04)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "eb6539ef-4d84-4ae5-bc4e-237dae21b9ef")
|
|
||||||
)
|
|
||||||
(pad "13" smd roundrect
|
|
||||||
(at 17 -15.58)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "c8744fbe-93c9-4c54-84bc-435357de679f")
|
|
||||||
)
|
|
||||||
(pad "14" smd roundrect
|
|
||||||
(at 17 -18.12)
|
|
||||||
(size 2.75 2)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(solder_mask_margin 0.0508)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "fd579d63-bbef-4609-9252-aad3f944a314")
|
|
||||||
)
|
|
||||||
(pad "15" smd circle
|
|
||||||
(at 7.6166 -19.1415)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "ad890579-1e55-4b71-9d59-080a59598896")
|
|
||||||
)
|
|
||||||
(pad "16" smd circle
|
|
||||||
(at 10.1566 -19.1415)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "25d6fdae-01ac-4ca4-8702-55badc8bcbc8")
|
|
||||||
)
|
|
||||||
(pad "17" smd circle
|
|
||||||
(at 7.6166 -16.6015)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "e73ae295-736f-4acf-8ee1-0c120ebcebea")
|
|
||||||
)
|
|
||||||
(pad "18" smd circle
|
|
||||||
(at 10.1566 -16.6015)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "7adfba87-f861-42a5-bb73-c3f9fac53180")
|
|
||||||
)
|
|
||||||
(pad "19" smd circle
|
|
||||||
(at 7.6166 -14.0615)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "619dc2a5-519d-48ac-9c78-8c438df2a14d")
|
|
||||||
)
|
|
||||||
(pad "20" smd circle
|
|
||||||
(at 10.1566 -14.0615)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "aa8b72d0-17bf-47d4-94b1-df9199638a29")
|
|
||||||
)
|
|
||||||
(pad "21" smd circle
|
|
||||||
(at 7.6166 -11.5215)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "8539b5cc-db2c-4fa4-9ead-b842a1885293")
|
|
||||||
)
|
|
||||||
(pad "22" smd circle
|
|
||||||
(at 10.064 -11.5783)
|
|
||||||
(size 1.7 1.7)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(uuid "313edcfe-ad25-4ea7-b786-d8290dfb479a")
|
|
||||||
)
|
|
||||||
(pad "23" smd roundrect
|
|
||||||
(at 7.3086 -4.9683 270)
|
|
||||||
(size 2.5 1.1)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "144d3c3d-6207-433c-9e61-4f75722af865")
|
|
||||||
)
|
|
||||||
(pad "24" smd roundrect
|
|
||||||
(at 9.8486 -4.9683 270)
|
|
||||||
(size 2.5 1.1)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "3780a4ef-348c-4241-b04b-2cb4f7127fa2")
|
|
||||||
)
|
|
||||||
(pad "25" smd roundrect
|
|
||||||
(at 9.949 -8.412 270)
|
|
||||||
(size 3.1 1.9)
|
|
||||||
(layers "F.Cu" "F.Mask" "F.Paste")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "00be3957-5a21-4898-8292-59f5f447623f")
|
|
||||||
)
|
|
||||||
(embedded_fonts no)
|
|
||||||
)
|
|
||||||
Binary file not shown.
|
|
@ -1,4 +0,0 @@
|
||||||
(sym_lib_table
|
|
||||||
(version 7)
|
|
||||||
(lib (name "Seeed_Studio_XIAO_Series") (type "KiCad") (uri "${KIPRJMOD}/library/Seeed_Studio_XIAO_Series.kicad_sym") (options "") (descr ""))
|
|
||||||
)
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
## Builds common config for smartphone connected device
|
|
||||||
## -> only receive CAM and DENMs via UART (TODO: and BLE)
|
|
||||||
|
|
||||||
cargo run --release --no-default-features -F esp,cam,denm,uart
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
## Builds common config for standalone device with automatic CAM transmission
|
|
||||||
## -> enable SPAT/ GLOSA with GNSS and a screen + CAM transmission
|
|
||||||
|
|
||||||
cargo run --release -F cam_tx
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
## Builds common config for standalone device
|
|
||||||
## -> enable SPAT/ GLOSA with GNSS and a screen
|
|
||||||
|
|
||||||
cargo run --release
|
|
||||||
|
|
@ -11,45 +11,6 @@ const PH_MAX_LENGHT_M: f32 = 500.;
|
||||||
const PH_MAX_ITEMS: usize = 23;
|
const PH_MAX_ITEMS: usize = 23;
|
||||||
const PH_MIN_DIST_M: f32 = 20.;
|
const PH_MIN_DIST_M: f32 = 20.;
|
||||||
|
|
||||||
/// Stand-alone CAM generator
|
|
||||||
///
|
|
||||||
/// Generates CAM messages from time and [`PosVel`] updates
|
|
||||||
///
|
|
||||||
/// # Send a message
|
|
||||||
/// ```
|
|
||||||
/// use esp32_cits_core::tx::GnItsPayload as _;
|
|
||||||
///
|
|
||||||
/// let (mut seq_no, mac_bytes) = {
|
|
||||||
/// // unwrap is fine since [`esp_hal::efuse::MacAddress`] is just an `[u8; 6]`
|
|
||||||
/// let mac_bytes = mac.as_bytes().try_into().unwrap();
|
|
||||||
///
|
|
||||||
/// (0, mac_bytes)
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// let mut cam = {
|
|
||||||
/// let station_id = make_station_id(mac);
|
|
||||||
/// info!("V2X Station ID: {station_id}");
|
|
||||||
///
|
|
||||||
/// applogic::cam_tx::CamState::new(
|
|
||||||
/// station_id,
|
|
||||||
/// OWN_STATION_TYPE,
|
|
||||||
/// OWN_VEHICLE_LENGTH,
|
|
||||||
/// OWN_VEHICLE_WIDTH,
|
|
||||||
/// )
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// cam.update(time, fix.clone().into());
|
|
||||||
/// match cam.encode_packet(mac_bytes, pos_vel, time, GN_IS_MOBILE, &mut seq_no) {
|
|
||||||
/// Ok(data) => {
|
|
||||||
/// if let Err(err) =
|
|
||||||
/// radio::send_80211_bcast_frame(&mut wlan_iface, &mac_bytes.clone(), &data)
|
|
||||||
/// {
|
|
||||||
/// warn!("Failed to send 802.11 frame: {err}");
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// Err(err) => warn!("Failed to create CAM: {err}"),
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CamState {
|
pub struct CamState {
|
||||||
station_id: u32,
|
station_id: u32,
|
||||||
|
|
@ -59,7 +20,7 @@ pub struct CamState {
|
||||||
vehicle_width_dm: u8, // vehicle width is in 10cm steps
|
vehicle_width_dm: u8, // vehicle width is in 10cm steps
|
||||||
|
|
||||||
time: chrono::DateTime<chrono::Utc>,
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
pos_state: esp32_cits_core::PosVel,
|
pos_state: super::PositionState,
|
||||||
|
|
||||||
/// database for path history, oldest item at the back of the vector
|
/// database for path history, oldest item at the back of the vector
|
||||||
path_history: Vec<PathPoint>,
|
path_history: Vec<PathPoint>,
|
||||||
|
|
@ -74,7 +35,7 @@ struct PathPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathPoint {
|
impl PathPoint {
|
||||||
fn new_from_pos(pos: &esp32_cits_core::PosVel, time: chrono::DateTime<chrono::Utc>) -> Self {
|
fn new_from_pos(pos: &super::PositionState, time: chrono::DateTime<chrono::Utc>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos: pos.position,
|
pos: pos.position,
|
||||||
time,
|
time,
|
||||||
|
|
@ -83,7 +44,7 @@ impl PathPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_from_pos_with_dist(
|
fn new_from_pos_with_dist(
|
||||||
pos: &esp32_cits_core::PosVel,
|
pos: &super::PositionState,
|
||||||
time: chrono::DateTime<chrono::Utc>,
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
dist_m: f32,
|
dist_m: f32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -108,12 +69,12 @@ impl CamState {
|
||||||
vehicle_length_dm,
|
vehicle_length_dm,
|
||||||
vehicle_width_dm,
|
vehicle_width_dm,
|
||||||
time: chrono::DateTime::<chrono::Utc>::default(),
|
time: chrono::DateTime::<chrono::Utc>::default(),
|
||||||
pos_state: esp32_cits_core::PosVel::default(),
|
pos_state: super::PositionState::default(),
|
||||||
path_history: Vec::with_capacity(PH_MAX_ITEMS + 1),
|
path_history: Vec::with_capacity(PH_MAX_ITEMS + 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, time: chrono::DateTime<chrono::Utc>, pos: esp32_cits_core::PosVel) {
|
pub fn update(&mut self, time: chrono::DateTime<chrono::Utc>, pos: super::PositionState) {
|
||||||
self.time = time;
|
self.time = time;
|
||||||
self.pos_state = pos;
|
self.pos_state = pos;
|
||||||
|
|
||||||
|
|
@ -125,7 +86,7 @@ impl CamState {
|
||||||
fn update_ph(
|
fn update_ph(
|
||||||
path_history: &mut Vec<PathPoint>,
|
path_history: &mut Vec<PathPoint>,
|
||||||
time: chrono::DateTime<chrono::Utc>,
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
pos: &esp32_cits_core::PosVel,
|
pos: &super::PositionState,
|
||||||
) {
|
) {
|
||||||
// Update path history
|
// Update path history
|
||||||
if path_history.is_empty() {
|
if path_history.is_empty() {
|
||||||
|
|
@ -332,11 +293,11 @@ impl CamState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl esp32_cits_core::tx::GnItsPayload for CamState {
|
impl crate::v2x_tx::GnItsPayload for CamState {
|
||||||
fn make_eh(
|
fn make_eh(
|
||||||
&self,
|
&self,
|
||||||
address: [u8; 6],
|
address: [u8; 6],
|
||||||
own_position: &esp32_cits_core::PosVel,
|
own_position: &crate::applogic::PositionState,
|
||||||
time: chrono::DateTime<chrono::Utc>,
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
_seq_no: &mut u16,
|
_seq_no: &mut u16,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
|
|
@ -352,7 +313,7 @@ impl esp32_cits_core::tx::GnItsPayload for CamState {
|
||||||
|
|
||||||
// CAM always uses SHB, hop-limit 1
|
// CAM always uses SHB, hop-limit 1
|
||||||
Ok((
|
Ok((
|
||||||
esp32_cits_core::tx::gn::make_shb_eh(address, station_type, own_position, time)?,
|
crate::v2x_tx::gn::make_shb_eh(address, station_type, own_position, time),
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
))
|
))
|
||||||
|
|
@ -375,8 +336,8 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::init_test_env_logger;
|
use crate::init_test_env_logger;
|
||||||
|
|
||||||
fn posstate_from_pos(position: geo_types::Point) -> esp32_cits_core::PosVel {
|
fn posstate_from_pos(position: geo_types::Point) -> crate::applogic::PositionState {
|
||||||
esp32_cits_core::PosVel {
|
crate::applogic::PositionState {
|
||||||
position,
|
position,
|
||||||
heading_deg: None,
|
heading_deg: None,
|
||||||
speed_mps: None,
|
speed_mps: None,
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ pub struct State {
|
||||||
time: chrono::NaiveDateTime,
|
time: chrono::NaiveDateTime,
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pos: esp32_cits_core::PosVel,
|
pos: PositionState,
|
||||||
|
|
||||||
#[cfg(feature = "spat")]
|
#[cfg(feature = "spat")]
|
||||||
last_prune: chrono::NaiveDateTime,
|
last_prune: chrono::NaiveDateTime,
|
||||||
|
|
@ -130,7 +130,15 @@ pub struct GnssFix {
|
||||||
pub speed_mps: Option<f32>,
|
pub speed_mps: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&GnssFix> for esp32_cits_core::PosVel {
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
|
pub struct PositionState {
|
||||||
|
pub position: geo_types::Point,
|
||||||
|
pub heading_deg: Option<f32>,
|
||||||
|
pub speed_mps: Option<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&GnssFix> for PositionState {
|
||||||
fn from(value: &GnssFix) -> Self {
|
fn from(value: &GnssFix) -> Self {
|
||||||
let position = geo_types::Point::new(value.longitude_deg, value.latitude_deg);
|
let position = geo_types::Point::new(value.longitude_deg, value.latitude_deg);
|
||||||
|
|
||||||
|
|
@ -141,7 +149,7 @@ impl From<&GnssFix> for esp32_cits_core::PosVel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<GnssFix> for esp32_cits_core::PosVel {
|
impl From<GnssFix> for PositionState {
|
||||||
fn from(value: GnssFix) -> Self {
|
fn from(value: GnssFix) -> Self {
|
||||||
(&value).into()
|
(&value).into()
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +212,7 @@ impl State {
|
||||||
Self {
|
Self {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
time: chrono::NaiveDateTime::default(),
|
time: chrono::NaiveDateTime::default(),
|
||||||
pos: esp32_cits_core::PosVel::default(),
|
pos: PositionState::default(),
|
||||||
#[cfg(feature = "spat")]
|
#[cfg(feature = "spat")]
|
||||||
last_prune: chrono::NaiveDateTime::default(),
|
last_prune: chrono::NaiveDateTime::default(),
|
||||||
#[cfg(feature = "spat")]
|
#[cfg(feature = "spat")]
|
||||||
|
|
@ -633,7 +641,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn pos(&self) -> &esp32_cits_core::PosVel {
|
pub fn pos(&self) -> &PositionState {
|
||||||
&self.pos
|
&self.pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/io.rs
18
src/io.rs
|
|
@ -169,7 +169,7 @@ impl From<msg::PositionState> for crate::applogic::GnssFix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<msg::PositionState> for esp32_cits_core::PosVel {
|
impl From<msg::PositionState> for crate::applogic::PositionState {
|
||||||
fn from(value: msg::PositionState) -> Self {
|
fn from(value: msg::PositionState) -> Self {
|
||||||
let position = geo_types::Point::new(
|
let position = geo_types::Point::new(
|
||||||
value.position.longitude_deg.into(),
|
value.position.longitude_deg.into(),
|
||||||
|
|
@ -194,7 +194,7 @@ impl From<msg::PositionState> for esp32_cits_core::PosVel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<msg::ItsPosition> for esp32_cits_core::PosVel {
|
impl From<msg::ItsPosition> for crate::applogic::PositionState {
|
||||||
fn from(value: msg::ItsPosition) -> Self {
|
fn from(value: msg::ItsPosition) -> Self {
|
||||||
let latitude_deg = f64::from(value.latitude) / 10_000_000.;
|
let latitude_deg = f64::from(value.latitude) / 10_000_000.;
|
||||||
let longitude_deg = f64::from(value.longitude) / 10_000_000.;
|
let longitude_deg = f64::from(value.longitude) / 10_000_000.;
|
||||||
|
|
@ -208,11 +208,11 @@ impl From<msg::ItsPosition> for esp32_cits_core::PosVel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl esp32_cits_core::tx::GnItsPayload for msg::RawMsgTx {
|
impl crate::v2x_tx::GnItsPayload for msg::RawMsgTx {
|
||||||
fn make_eh(
|
fn make_eh(
|
||||||
&self,
|
&self,
|
||||||
address: [u8; 6],
|
address: [u8; 6],
|
||||||
own_position: &esp32_cits_core::PosVel,
|
own_position: &crate::applogic::PositionState,
|
||||||
time: chrono::DateTime<chrono::Utc>,
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
seq_no: &mut u16,
|
seq_no: &mut u16,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
|
|
@ -275,19 +275,19 @@ impl esp32_cits_core::tx::GnItsPayload for msg::RawMsgTx {
|
||||||
*seq_no += 1;
|
*seq_no += 1;
|
||||||
|
|
||||||
(
|
(
|
||||||
esp32_cits_core::tx::gn::make_tsb_eh(
|
crate::v2x_tx::gn::make_tsb_eh(
|
||||||
address,
|
address,
|
||||||
station_type,
|
station_type,
|
||||||
own_position,
|
own_position,
|
||||||
time,
|
time,
|
||||||
*seq_no,
|
*seq_no,
|
||||||
)?,
|
),
|
||||||
None,
|
None,
|
||||||
hop_limit,
|
hop_limit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
msg::GnTransport::Shb => (
|
msg::GnTransport::Shb => (
|
||||||
esp32_cits_core::tx::gn::make_shb_eh(address, station_type, own_position, time)?,
|
crate::v2x_tx::gn::make_shb_eh(address, station_type, own_position, time),
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
|
|
@ -308,7 +308,7 @@ impl msg::RawMsgTx {
|
||||||
fn make_geobcast(
|
fn make_geobcast(
|
||||||
address: [u8; 6],
|
address: [u8; 6],
|
||||||
station_type: geonetworking::en302636_4_1::StationType,
|
station_type: geonetworking::en302636_4_1::StationType,
|
||||||
own_position: &esp32_cits_core::PosVel,
|
own_position: &crate::applogic::PositionState,
|
||||||
time: chrono::DateTime<chrono::Utc>,
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
gn_area: msg::GnArea,
|
gn_area: msg::GnArea,
|
||||||
sequence_number: u16,
|
sequence_number: u16,
|
||||||
|
|
@ -320,7 +320,7 @@ impl msg::RawMsgTx {
|
||||||
alloc::string::String,
|
alloc::string::String,
|
||||||
> {
|
> {
|
||||||
let source_position_vector =
|
let source_position_vector =
|
||||||
esp32_cits_core::tx::gn::make_lpv(address, station_type, own_position, time)?;
|
crate::v2x_tx::gn::make_lpv(address, station_type, own_position, time);
|
||||||
|
|
||||||
let (atype, dist_a, dist_b, angle) = match gn_area.area() {
|
let (atype, dist_a, dist_b, angle) = match gn_area.area() {
|
||||||
msg::GnAreaShape::EtsiAreashapeCircle => (
|
msg::GnAreaShape::EtsiAreashapeCircle => (
|
||||||
|
|
|
||||||
192
src/main.rs
192
src/main.rs
|
|
@ -8,16 +8,11 @@
|
||||||
// #![deny(clippy::large_stack_frames)]
|
// #![deny(clippy::large_stack_frames)]
|
||||||
|
|
||||||
// we can't use UART I/O and GNSS at the same time
|
// we can't use UART I/O and GNSS at the same time
|
||||||
#[cfg(all(feature = "uart", feature = "gnss_ubx", feature = "gnss_l67k"))]
|
#[cfg(all(feature = "uart", feature = "gnss"))]
|
||||||
compile_error!(
|
compile_error!("feature \"uart\" and feature \"gnss\" cannot be enabled at the same time");
|
||||||
"feature \"uart\" and features \"gnss_ubx\" or \"gnss_l67k\" cannot be enabled at the same time"
|
|
||||||
);
|
|
||||||
// autonomous CAM generation need a time and position source (aka _gnss)
|
// autonomous CAM generation need a time and position source (aka _gnss)
|
||||||
#[cfg(all(feature = "cam_tx", not(feature = "_gnss")))]
|
#[cfg(all(feature = "cam_tx", not(feature = "_gnss")))]
|
||||||
compile_error!("feature \"cam_tx\" needs a time and position source (either GNSS or UART)");
|
compile_error!("feature \"cam_tx\" needs a time and position source (either GNSS or UART)");
|
||||||
// we can't have both GNSS drivers enabled at the same time
|
|
||||||
#[cfg(all(feature = "gnss_ubx", feature = "gnss_l67k"))]
|
|
||||||
compile_error!("feature \"gnss_ubx\" and feature \"gnss_l67k\" cannot be enabled at the same time");
|
|
||||||
|
|
||||||
use alloc::string::ToString as _;
|
use alloc::string::ToString as _;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
@ -31,14 +26,14 @@ use c_its_parser::standards::extensions::ItsStationType;
|
||||||
use critical_section::Mutex;
|
use critical_section::Mutex;
|
||||||
use crossbeam_queue::ArrayQueue;
|
use crossbeam_queue::ArrayQueue;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
#[cfg(feature = "gnss_l67k")]
|
#[cfg(feature = "gnss")]
|
||||||
use embassy_gps::gps::l76k;
|
use embassy_gps::gps::l76k;
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_hal::clock::CpuClock;
|
use esp_hal::clock::CpuClock;
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
#[cfg(all(target_arch = "riscv32", feature = "spat"))]
|
#[cfg(all(target_arch = "riscv32", feature = "spat"))]
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
use esp32_cits_core::radio;
|
use esp_radio::wifi;
|
||||||
use geonetworking::Decode as _;
|
use geonetworking::Decode as _;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
|
||||||
|
|
@ -49,13 +44,13 @@ mod cache;
|
||||||
mod geo_alg;
|
mod geo_alg;
|
||||||
#[cfg(feature = "uart")]
|
#[cfg(feature = "uart")]
|
||||||
mod io;
|
mod io;
|
||||||
|
mod radio;
|
||||||
#[cfg(feature = "screen")]
|
#[cfg(feature = "screen")]
|
||||||
mod screen;
|
mod screen;
|
||||||
#[cfg(feature = "gnss_ubx")]
|
#[cfg(any(feature = "cam_tx", feature = "uart"))]
|
||||||
mod ubx;
|
mod v2x_tx;
|
||||||
|
|
||||||
const WIFI_CHANNEL: radio::Channel = 180;
|
const WIFI_CHANNEL: radio::Channel = 180;
|
||||||
const WIFI_TXPOWER: i8 = 10; // dBm, 2..20
|
|
||||||
#[cfg(feature = "spat")]
|
#[cfg(feature = "spat")]
|
||||||
const SPAT_RATE_LIMIT: u8 = 5; // keep every n-th message
|
const SPAT_RATE_LIMIT: u8 = 5; // keep every n-th message
|
||||||
#[cfg(any(feature = "cam_tx", feature = "uart"))]
|
#[cfg(any(feature = "cam_tx", feature = "uart"))]
|
||||||
|
|
@ -168,13 +163,9 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
esp_radio::wifi::ControllerConfig::default(),
|
esp_radio::wifi::ControllerConfig::default(),
|
||||||
)
|
)
|
||||||
.expect("Failed to initialize Wi-Fi controller");
|
.expect("Failed to initialize Wi-Fi controller");
|
||||||
|
|
||||||
if let Err(err) = wifi_controller.set_band_mode(esp_radio::wifi::BandMode::_5G) {
|
if let Err(err) = wifi_controller.set_band_mode(esp_radio::wifi::BandMode::_5G) {
|
||||||
error!("Failed to set WiFi to 5GHz only: {err}");
|
error!("Failed to set WiFi to 5GHz only: {err}");
|
||||||
}
|
}
|
||||||
if let Err(err) = wifi_controller.set_max_tx_power(WIFI_TXPOWER * 4) {
|
|
||||||
error!("Failed to set WiFi TX power: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
WIFI_RX_QUEUE.borrow(cs).replace(Some(ArrayQueue::new(2)));
|
WIFI_RX_QUEUE.borrow(cs).replace(Some(ArrayQueue::new(2)));
|
||||||
|
|
@ -188,15 +179,14 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
let mac = esp_hal::efuse::base_mac_address();
|
let mac = esp_hal::efuse::base_mac_address();
|
||||||
info!("WiFi MAC: {mac}");
|
info!("WiFi MAC: {mac}");
|
||||||
|
|
||||||
// Setup GNSS:
|
// Setup GNSS: Seeed XIAO L67K:
|
||||||
// Seeed XIAO L67K:
|
|
||||||
// RX: D7/ GPIO12
|
// RX: D7/ GPIO12
|
||||||
// TX: D6/ GPIO11
|
// TX: D6/ GPIO11
|
||||||
// WAKEUP: D0/ GPIO1 -> HIGH for active, LOW for Sleep
|
// WAKEUP: D0/ GPIO1 -> HIGH for active, LOW for Sleep
|
||||||
// RESET: D2/ GPIO25 -> HIGH for normal, LOW for Reset
|
// RESET: D2/ GPIO25 -> HIGH for normal, LOW for Reset
|
||||||
#[cfg(feature = "gnss_l67k")]
|
#[cfg(feature = "gnss")]
|
||||||
spawner.spawn(
|
spawner.spawn(
|
||||||
gnss_l67k_task(
|
gnss_task(
|
||||||
peripherals.GPIO1,
|
peripherals.GPIO1,
|
||||||
peripherals.GPIO25,
|
peripherals.GPIO25,
|
||||||
peripherals.UART0,
|
peripherals.UART0,
|
||||||
|
|
@ -205,29 +195,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
)
|
)
|
||||||
.expect("Failed to spawn GNSS task"),
|
.expect("Failed to spawn GNSS task"),
|
||||||
);
|
);
|
||||||
|
#[cfg(feature = "gnss")]
|
||||||
// U-Blox module:
|
|
||||||
// RX: D7/ GPIO12
|
|
||||||
// TX: D6/ GPIO11
|
|
||||||
// RESET: D2/ GPIO25 -> HIGH for normal, LOW for Reset
|
|
||||||
#[cfg(feature = "gnss_ubx")]
|
|
||||||
{
|
|
||||||
setup_uart0(
|
|
||||||
9600,
|
|
||||||
Some(b'\n'),
|
|
||||||
peripherals.GPIO12,
|
|
||||||
peripherals.GPIO11,
|
|
||||||
peripherals.UART0,
|
|
||||||
serial_handler,
|
|
||||||
)
|
|
||||||
.expect("Failed to initialize UART for GNSS");
|
|
||||||
|
|
||||||
// do some settings (UART receive and parsing runs in main loop)
|
|
||||||
spawner
|
|
||||||
.spawn(gnss_ubx_config(peripherals.GPIO25).expect("Failed to spawn GNSS config task"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "_gnss")]
|
|
||||||
info!("GNSS task started, waiting for GNSS fix...");
|
info!("GNSS task started, waiting for GNSS fix...");
|
||||||
|
|
||||||
#[cfg(any(feature = "cam_tx", feature = "uart"))]
|
#[cfg(any(feature = "cam_tx", feature = "uart"))]
|
||||||
|
|
@ -241,7 +209,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
let mut state = applogic::State::new();
|
let mut state = applogic::State::new();
|
||||||
#[cfg(feature = "cam_tx")]
|
#[cfg(feature = "cam_tx")]
|
||||||
let mut cam = {
|
let mut cam = {
|
||||||
let station_id = make_station_id(mac);
|
let station_id = v2x_tx::make_station_id(mac);
|
||||||
info!("V2X Station ID: {station_id}");
|
info!("V2X Station ID: {station_id}");
|
||||||
|
|
||||||
applogic::cam_tx::CamState::new(
|
applogic::cam_tx::CamState::new(
|
||||||
|
|
@ -253,8 +221,6 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
};
|
};
|
||||||
#[cfg(feature = "uart")]
|
#[cfg(feature = "uart")]
|
||||||
let mut uart_input = io::Parser::default();
|
let mut uart_input = io::Parser::default();
|
||||||
#[cfg(feature = "gnss_ubx")]
|
|
||||||
let mut ubx_parser = ublox::Parser::default();
|
|
||||||
loop {
|
loop {
|
||||||
embassy_time::Timer::after(embassy_time::Duration::from_millis(1)).await;
|
embassy_time::Timer::after(embassy_time::Duration::from_millis(1)).await;
|
||||||
|
|
||||||
|
|
@ -286,7 +252,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(io::msg::serial_input_msg::Payload::TxMsg(tx_request)) => {
|
Some(io::msg::serial_input_msg::Payload::TxMsg(tx_request)) => {
|
||||||
use esp32_cits_core::tx::GnItsPayload as _;
|
use v2x_tx::GnItsPayload as _;
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"UART: Got new TX message: Type {} with {} bytes",
|
"UART: Got new TX message: Type {} with {} bytes",
|
||||||
|
|
@ -319,49 +285,6 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "gnss_ubx")]
|
|
||||||
{
|
|
||||||
let mut it = ubx_parser.consume_ubx(&data);
|
|
||||||
loop {
|
|
||||||
match it.next() {
|
|
||||||
Some(Ok(ublox::UbxPacket::Proto27(packet_ref))) => match &packet_ref {
|
|
||||||
ublox::proto27::PacketRef::MonVer(packet) => {
|
|
||||||
println!("{}", ubx::pretty_print_mon_ver(packet));
|
|
||||||
}
|
|
||||||
ublox::proto27::PacketRef::MonComms(packet) => {
|
|
||||||
println!("{}", ubx::pretty_print_mon_comms(packet));
|
|
||||||
}
|
|
||||||
ublox::proto27::PacketRef::MonRf(packet) => {
|
|
||||||
println!("{}", ubx::pretty_print_mon_rf(packet));
|
|
||||||
}
|
|
||||||
ublox::proto27::PacketRef::NavSat(packet) => {
|
|
||||||
println!("{}", ubx::pretty_print_nav_sat(packet));
|
|
||||||
}
|
|
||||||
ublox::proto27::PacketRef::NavPvt(pvt) => {
|
|
||||||
match applogic::GnssFix::try_from(pvt) {
|
|
||||||
Ok(pos_state) => {
|
|
||||||
critical_section::with(|cs| {
|
|
||||||
let gnss_update_ref = GNSS_UPDATE.borrow(cs);
|
|
||||||
gnss_update_ref.replace(Some(pos_state));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(err) => warn!("{err}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
println!("UBX: {packet_ref:?}");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(Err(_)) => {
|
|
||||||
// Received a malformed packet
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// The internal buffer is now empty
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -377,7 +300,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
|
|
||||||
#[cfg(feature = "cam_tx")]
|
#[cfg(feature = "cam_tx")]
|
||||||
{
|
{
|
||||||
use esp32_cits_core::tx::GnItsPayload as _;
|
use v2x_tx::GnItsPayload;
|
||||||
let time = state.time().and_utc();
|
let time = state.time().and_utc();
|
||||||
|
|
||||||
cam.update(time, fix.clone().into());
|
cam.update(time, fix.clone().into());
|
||||||
|
|
@ -510,7 +433,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
reason = "adhering to callback interface"
|
reason = "adhering to callback interface"
|
||||||
)]
|
)]
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn handle_frame(frame: esp_radio::wifi::sniffer::PromiscuousPkt<'_>) {
|
fn handle_frame(frame: wifi::sniffer::PromiscuousPkt<'_>) {
|
||||||
#[cfg(feature = "spat")]
|
#[cfg(feature = "spat")]
|
||||||
const PRUNE_INTERVAL: chrono::Duration = chrono::Duration::seconds(60);
|
const PRUNE_INTERVAL: chrono::Duration = chrono::Duration::seconds(60);
|
||||||
#[cfg(feature = "spat")]
|
#[cfg(feature = "spat")]
|
||||||
|
|
@ -531,18 +454,27 @@ fn handle_frame(frame: esp_radio::wifi::sniffer::PromiscuousPkt<'_>) {
|
||||||
.naive_utc()
|
.naive_utc()
|
||||||
};
|
};
|
||||||
|
|
||||||
match esp32_cits_core::rx::is_broadcast_frame(&frame) {
|
// Ignore frames with errors and non-data frames
|
||||||
Err(err) => {
|
if frame.rx_cntl.rx_state != 0 {
|
||||||
warn!("{err}");
|
warn!("Received frame has RX error: {}", frame.rx_cntl.rx_state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Ok(false) => {
|
if !radio::PromiscuousPktType::Data.matches(frame.frame_type) {
|
||||||
// drop frame
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
Ok(true) => {
|
// Ignore non-broadcast frames
|
||||||
// continue
|
if frame.len < (4 + 6) {
|
||||||
}
|
warn!(
|
||||||
|
"Received frame too small to be a valid broadcast frame: {} bytes",
|
||||||
|
frame.len
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let dest_mac = &frame.data[4..10];
|
||||||
|
if dest_mac != [0xff; 6] {
|
||||||
|
warn!("Received frame is not broadcast frame: Dest MAC {dest_mac:02x?}");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// info!("Received frame with {} bytes", frame.len);
|
// info!("Received frame with {} bytes", frame.len);
|
||||||
|
|
@ -689,10 +621,10 @@ fn get_its_header<'p>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gnss_l67k")]
|
#[cfg(feature = "gnss")]
|
||||||
#[allow(clippy::large_stack_frames, reason = "GNSS driver needs some space")]
|
#[allow(clippy::large_stack_frames, reason = "GNSS driver needs some space")]
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn gnss_l67k_task(
|
async fn gnss_task(
|
||||||
gps_wakeup: esp_hal::peripherals::GPIO1<'static>,
|
gps_wakeup: esp_hal::peripherals::GPIO1<'static>,
|
||||||
gps_reset: esp_hal::peripherals::GPIO25<'static>,
|
gps_reset: esp_hal::peripherals::GPIO25<'static>,
|
||||||
uart: esp_hal::peripherals::UART0<'static>,
|
uart: esp_hal::peripherals::UART0<'static>,
|
||||||
|
|
@ -742,38 +674,6 @@ async fn gnss_l67k_task(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gnss_ubx")]
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn gnss_ubx_config(reset_pin: esp_hal::peripherals::GPIO25<'static>) {
|
|
||||||
// reset the module
|
|
||||||
let mut gnss_reset = esp_hal::gpio::Output::new(
|
|
||||||
reset_pin,
|
|
||||||
esp_hal::gpio::Level::Low,
|
|
||||||
esp_hal::gpio::OutputConfig::default(),
|
|
||||||
);
|
|
||||||
embassy_time::Timer::after(embassy_time::Duration::from_millis(2)).await;
|
|
||||||
gnss_reset.set_high();
|
|
||||||
|
|
||||||
embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
|
|
||||||
|
|
||||||
info!("UBX: Enabling ubx protocol with NAV-PVT and NAV-SAT");
|
|
||||||
let buffer = ublox::packets::cfg_val::CfgValSetBuilder {
|
|
||||||
version: 1,
|
|
||||||
layers: ublox::packets::cfg_val::CfgLayerSet::RAM,
|
|
||||||
reserved1: 0,
|
|
||||||
cfg_data: &[
|
|
||||||
ublox::cfg_val::CfgVal::Uart1OutProtNmea(false),
|
|
||||||
ublox::cfg_val::CfgVal::Uart1OutProtUbx(true),
|
|
||||||
// CFG-MSGOUT-UBX_NAV_PVT_UART1
|
|
||||||
ublox::cfg_val::CfgVal::MsgOutUbxNavPvtUart1(1),
|
|
||||||
// CFG-MSGOUT-UBX_NAV_SAT_UART1
|
|
||||||
// ublox::cfg_val::CfgVal::MsgOutUbxNavSatUart1(10),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
.into_packet_vec();
|
|
||||||
send_uart0(&buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "screen")]
|
#[cfg(feature = "screen")]
|
||||||
fn log_screen_error<E>(error: &E)
|
fn log_screen_error<E>(error: &E)
|
||||||
where
|
where
|
||||||
|
|
@ -873,19 +773,3 @@ fn send_uart0(data: &[u8]) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "esp", feature = "cam_tx"))]
|
|
||||||
/// Creates a station ID from the WLAN MAC address
|
|
||||||
///
|
|
||||||
/// Will use `0xC173` as static prefix and uses last 16 bit from MAC address for the remainder.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// Won't panic in practive b/c of pre-conditions
|
|
||||||
#[must_use]
|
|
||||||
pub fn make_station_id(mac: esp_hal::efuse::MacAddress) -> u32 {
|
|
||||||
// unwrap is fine here since we can be sure that the MacAddress is 6 byte
|
|
||||||
// and a slice of 2 bytes can be converted to [u8; 2]
|
|
||||||
let mac_last_16bit = u16::from_be_bytes(mac.as_bytes().get(4..6).unwrap().try_into().unwrap());
|
|
||||||
|
|
||||||
0xC173_0000 | u32::from(mac_last_16bit)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
288
src/radio.rs
Normal file
288
src/radio.rs
Normal file
|
|
@ -0,0 +1,288 @@
|
||||||
|
//! IEEE 802.11p C-ITS Capture with ESP32-C5
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// missing interface definitions
|
||||||
|
// -----------------------------
|
||||||
|
|
||||||
|
pub type Channel = core::ffi::c_int;
|
||||||
|
|
||||||
|
unsafe extern "C" {
|
||||||
|
/// Changes the 802.11 PHY channel
|
||||||
|
///
|
||||||
|
/// C function signature: `void phy_change_channel(int,int,int,int)`
|
||||||
|
///
|
||||||
|
/// Options:
|
||||||
|
/// - `primary`: Channel frequency in MHz
|
||||||
|
/// - `ignored1`: Ignored (set to 1)
|
||||||
|
/// - `ignored2`: Ignored (set to 0)
|
||||||
|
/// - `ht_mode`: Probably HT mode
|
||||||
|
unsafe fn phy_change_channel(
|
||||||
|
primary: Channel,
|
||||||
|
ignored1: core::ffi::c_int,
|
||||||
|
ignored2: core::ffi::c_int,
|
||||||
|
ht_mode: core::ffi::c_int,
|
||||||
|
) -> core::ffi::c_int;
|
||||||
|
|
||||||
|
/// Enables 802.11p mode on the ESP32-C5
|
||||||
|
///
|
||||||
|
/// C function signature: `void phy_11p_set(int,int)`
|
||||||
|
///
|
||||||
|
/// Options:
|
||||||
|
/// - `enable`: Boolean option to enable 802.11p mode
|
||||||
|
/// - `half_rate`: 5 MHz mode
|
||||||
|
unsafe fn phy_11p_set(enable: u8, half_rate: u8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enum values for `wifi_promiscuous_pkt_type_t` used in `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type`
|
||||||
|
///
|
||||||
|
/// Original value is actually `core::ffi::c_uint`, but that can't be used in `#[repr()]` attributes,
|
||||||
|
/// so we're using `u8` as the smallest suitable type here that can be casted to a bigger type.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) enum PromiscuousPktType {
|
||||||
|
/// Management frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t`
|
||||||
|
Mgmt = 0,
|
||||||
|
/// Control frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t`
|
||||||
|
Ctrl = 1,
|
||||||
|
/// Data frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t`
|
||||||
|
Data = 2,
|
||||||
|
/// Other type, such as MIMO etc. 'buf' argument is `wifi_promiscuous_pkt_t` but the payload is zero length.
|
||||||
|
Misc = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PromiscuousPktType {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn as_repr(self) -> u8 {
|
||||||
|
self as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts to underlying type of `wifi_promiscuous_pkt_type_t` (used by `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type`)
|
||||||
|
pub fn as_frame_type(self) -> core::ffi::c_uint {
|
||||||
|
core::ffi::c_uint::from(self.as_repr())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if we are the same frame type as `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type`
|
||||||
|
pub fn matches(self, frame_type: core::ffi::c_uint) -> bool {
|
||||||
|
self.as_frame_type() == frame_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "esp")]
|
||||||
|
/// Configure WiFi Sniffer to a certain 802.11p channel
|
||||||
|
pub fn setup_wifi_sniffer(
|
||||||
|
channel: Channel,
|
||||||
|
sniffer: &mut esp_radio::wifi::sniffer::Sniffer,
|
||||||
|
callback: fn(esp_radio::wifi::sniffer::PromiscuousPkt<'_>),
|
||||||
|
) -> Result<(), alloc::string::String> {
|
||||||
|
sniffer
|
||||||
|
.set_promiscuous_mode(true)
|
||||||
|
.map_err(|err| alloc::format!("Failed to enable promiscuous mode: {err:?}"))?;
|
||||||
|
|
||||||
|
sniffer.set_receive_cb(callback);
|
||||||
|
|
||||||
|
// convert channel number to frequency in MHz
|
||||||
|
let primary = 5000 + (channel * 5);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
phy_11p_set(1, 0);
|
||||||
|
match phy_change_channel(primary, 1, 0, 0) {
|
||||||
|
0 => Ok(()),
|
||||||
|
ret => Err(alloc::format!("Failed to change channel: {ret}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "esp")]
|
||||||
|
/// Sends 802.11p broadcast frame
|
||||||
|
///
|
||||||
|
/// Expects `data` to contain GN header (BTP header and ITS payload) to be a valid C-ITS/ ITS-G5 packet/ frame.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Fails when MAC is not the right size or returns frame send error
|
||||||
|
pub fn send_80211_bcast_frame(
|
||||||
|
sniffer: &mut esp_radio::wifi::sniffer::Sniffer,
|
||||||
|
mac_addr: &[u8],
|
||||||
|
data: &[u8],
|
||||||
|
) -> Result<(), alloc::string::String> {
|
||||||
|
const HEADER_SIZE: usize = 24 + 8;
|
||||||
|
|
||||||
|
let mac = mac_addr
|
||||||
|
.try_into()
|
||||||
|
.map_err(|err| alloc::format!("Unexpected MAC address size: {err}"))?;
|
||||||
|
|
||||||
|
// assemble frame
|
||||||
|
let mut frame_buf = alloc::vec::Vec::with_capacity(HEADER_SIZE + data.len());
|
||||||
|
frame_buf.extend_from_slice(&DataFrameHeader::new_80211p(mac).to_binary());
|
||||||
|
frame_buf.extend_from_slice(&LlcHeader::new_80211p().to_binary());
|
||||||
|
frame_buf.extend_from_slice(data);
|
||||||
|
|
||||||
|
// send
|
||||||
|
sniffer
|
||||||
|
.send_raw_frame(true, &frame_buf, true)
|
||||||
|
.map_err(|err| alloc::format!("Failed to send 802.11p frame: {err:?}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IEEE 802.11p frame header
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct DataFrameHeader {
|
||||||
|
/// byte 0: subtype in upper nibble, type in lower nibble
|
||||||
|
/// "normal" data frame: 0x08, QoS data frame: 0x88
|
||||||
|
pub type_and_subtype: u8,
|
||||||
|
/// byte 1: frame contol field, 0x00 for 802.11p
|
||||||
|
pub fcf_flags: u8,
|
||||||
|
/// byte 2..3: duration in micros, usually 0x0000 for 802.11p (toDS = 0, fromDS = 0)
|
||||||
|
pub duration: u16,
|
||||||
|
/// byte 4..9: receiver/ destination for 802.11p
|
||||||
|
pub address_1: [u8; 6],
|
||||||
|
/// byte 10..15: transmitter/ source for 802.11p
|
||||||
|
pub address_2: [u8; 6],
|
||||||
|
/// byte 16..21: BSSID for 802.11p
|
||||||
|
pub address_3: [u8; 6],
|
||||||
|
/// byte 22..24: upper 12 bits: seq. no, lower 4 bits: fragment no
|
||||||
|
pub sequence_control: u16,
|
||||||
|
// Note: address 4 is not used in 802.11p
|
||||||
|
// pub qos: Option<[u8; 2]>, // QoS frames are supported by radio library
|
||||||
|
// Note: 802.11p does not use HT mode(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataFrameHeader {
|
||||||
|
const BCAST_MAC: [u8; 6] = [0xFF; 6];
|
||||||
|
|
||||||
|
/// Create an 802.11p (non-QoS) data frame header with a source MAC address
|
||||||
|
pub(crate) fn new_80211p(source_mac: &[u8; 6]) -> Self {
|
||||||
|
Self {
|
||||||
|
type_and_subtype: 0x08,
|
||||||
|
address_1: Self::BCAST_MAC,
|
||||||
|
address_2: *source_mac,
|
||||||
|
address_3: Self::BCAST_MAC,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_binary(&self) -> [u8; 24] {
|
||||||
|
let mut buf = [0u8; 24];
|
||||||
|
|
||||||
|
buf[0] = self.type_and_subtype;
|
||||||
|
|
||||||
|
buf[1] = self.fcf_flags;
|
||||||
|
|
||||||
|
Self::write_u16(&mut buf, 2, self.duration);
|
||||||
|
Self::write_mac_addr(&mut buf, 4, &self.address_1);
|
||||||
|
Self::write_mac_addr(&mut buf, 10, &self.address_2);
|
||||||
|
Self::write_mac_addr(&mut buf, 16, &self.address_3);
|
||||||
|
Self::write_u16(&mut buf, 22, self.sequence_control);
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_u16(buf: &mut [u8; 24], offset: usize, data: u16) {
|
||||||
|
for (idx, byte) in data.to_be_bytes().iter().enumerate() {
|
||||||
|
buf[idx + offset] = *byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_mac_addr(buf: &mut [u8; 24], offset: usize, data: &[u8; 6]) {
|
||||||
|
for (idx, byte) in data.iter().enumerate() {
|
||||||
|
buf[idx + offset] = *byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IEEE 802.11p LLC header
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct LlcHeader {
|
||||||
|
/// byte 0: SNAP (0xaa) in 802.11p
|
||||||
|
pub dsap: u8, // SNAP in
|
||||||
|
/// byte 1: SNAP (0xaa) in 802.11p
|
||||||
|
pub lsap: u8, // SNAP in
|
||||||
|
/// byte 2: SNAP (0xaa) in 802.11p
|
||||||
|
pub control_1: u8, // 0x03
|
||||||
|
// Note: optional second control byte not used in 802.11p
|
||||||
|
|
||||||
|
// SNAP fields
|
||||||
|
/// set to 0 since ethertype is used for protocol ID in 802.11p
|
||||||
|
pub oui: [u8; 3],
|
||||||
|
/// ethertype GeoNetworking (0x8947) in 802.11p
|
||||||
|
pub protocol_id: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LlcHeader {
|
||||||
|
pub(crate) fn new_80211p() -> Self {
|
||||||
|
Self {
|
||||||
|
dsap: 0xaa,
|
||||||
|
lsap: 0xaa,
|
||||||
|
control_1: 0x03,
|
||||||
|
oui: [0; 3],
|
||||||
|
protocol_id: 0x8947,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_binary(&self) -> [u8; 8] {
|
||||||
|
let mut buf: [u8; 8] = [
|
||||||
|
self.dsap,
|
||||||
|
self.lsap,
|
||||||
|
self.control_1,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
];
|
||||||
|
|
||||||
|
buf[3] = self.oui[0];
|
||||||
|
buf[4] = self.oui[1];
|
||||||
|
buf[5] = self.oui[2];
|
||||||
|
|
||||||
|
buf[6] = self.protocol_id.to_be_bytes()[0];
|
||||||
|
buf[7] = self.protocol_id.to_be_bytes()[1];
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn data_frame_test() {
|
||||||
|
// build a typical IEEE 802.11p frame
|
||||||
|
const OWN_MAC: [u8; 6] = [0x12, 0x34, 0x56, 0x78, 0xab, 0xcd];
|
||||||
|
const REF_HEADER: [u8; 24] = [
|
||||||
|
0x08, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x12, 0x34, 0x56, 0x78,
|
||||||
|
0xab, 0xcd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
];
|
||||||
|
|
||||||
|
let frame = DataFrameHeader::new_80211p(&OWN_MAC);
|
||||||
|
|
||||||
|
assert_eq!(0x08, frame.type_and_subtype); // data frame, subtype 0
|
||||||
|
assert_eq!(0x0000, frame.fcf_flags);
|
||||||
|
assert_eq!(0x0000, frame.duration);
|
||||||
|
assert_eq!([0xFF; 6], frame.address_1);
|
||||||
|
assert_eq!(OWN_MAC, frame.address_2);
|
||||||
|
assert_eq!([0xFF; 6], frame.address_3);
|
||||||
|
assert_eq!(0x0000, frame.sequence_control);
|
||||||
|
|
||||||
|
assert_eq!(REF_HEADER, frame.to_binary());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn llc_test() {
|
||||||
|
// build a typical IEEE 802.11p LLC header
|
||||||
|
const REF_HEADER: [u8; 8] = [0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x89, 0x47];
|
||||||
|
|
||||||
|
let llc = LlcHeader::new_80211p();
|
||||||
|
|
||||||
|
assert_eq!(0xaa, llc.dsap);
|
||||||
|
assert_eq!(0xaa, llc.lsap);
|
||||||
|
assert_eq!(0x03, llc.control_1);
|
||||||
|
assert_eq!([0x00; 3], llc.oui);
|
||||||
|
assert_eq!(0x8947, llc.protocol_id);
|
||||||
|
|
||||||
|
assert_eq!(REF_HEADER, llc.to_binary());
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/test-proto.rs
Normal file
89
src/test-proto.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#![cfg(not(target_arch = "riscv32"))]
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
mod applogic;
|
||||||
|
mod io;
|
||||||
|
mod v2x_tx;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
use prost::Message as _;
|
||||||
|
|
||||||
|
// env_logger::init();
|
||||||
|
|
||||||
|
// generate some test UART messages as hex strings
|
||||||
|
let raw_its = input_from_raw(io::msg::RawMsgTx {
|
||||||
|
payload: [0xaa, 0xbb, 0xcc, 0xdd].to_vec(),
|
||||||
|
message_type: 1,
|
||||||
|
gn_transport: io::msg::GnTransport::Shb.into(),
|
||||||
|
gn_area: io::msg::GnArea {
|
||||||
|
area: None,
|
||||||
|
position: None,
|
||||||
|
dist_a: None,
|
||||||
|
dist_b: None,
|
||||||
|
angle: None,
|
||||||
|
},
|
||||||
|
hop_limit: 2,
|
||||||
|
station_type: None,
|
||||||
|
});
|
||||||
|
println!("{}", serialize_serial_msg_hex(&raw_its));
|
||||||
|
|
||||||
|
let pos = input_from_position(io::msg::PositionState {
|
||||||
|
timestamp_ms: 1785144196000,
|
||||||
|
position: io::msg::Position {
|
||||||
|
latitude_deg: 42.,
|
||||||
|
longitude_deg: 23.,
|
||||||
|
},
|
||||||
|
heading: None,
|
||||||
|
speed: None,
|
||||||
|
});
|
||||||
|
println!("{}", serialize_serial_msg_hex(&pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_from_raw(value: io::msg::RawMsgTx) -> io::msg::SerialInputMsg {
|
||||||
|
use io::msg::serial_input_msg::Payload;
|
||||||
|
|
||||||
|
io::msg::SerialInputMsg {
|
||||||
|
payload: Some(Payload::TxMsg(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn input_from_position(value: io::msg::PositionState) -> io::msg::SerialInputMsg {
|
||||||
|
use io::msg::serial_input_msg::Payload;
|
||||||
|
|
||||||
|
io::msg::SerialInputMsg {
|
||||||
|
payload: Some(Payload::Position(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn serialize_serial_msg_hex(msg: &io::msg::SerialInputMsg) -> alloc::string::String {
|
||||||
|
use prost::Message as _;
|
||||||
|
|
||||||
|
let mut msg_buf = msg.encode_to_vec();
|
||||||
|
|
||||||
|
let sof = [0x56u8, 0x32, 0x58, 0x2B];
|
||||||
|
let eof = [0x0du8, 0x0a];
|
||||||
|
let len: [u8; 2] = (msg_buf.len() as u16).to_be_bytes();
|
||||||
|
|
||||||
|
let mut out = sof.to_vec();
|
||||||
|
out.extend_from_slice(&len);
|
||||||
|
out.append(&mut msg_buf);
|
||||||
|
out.extend_from_slice(&eof);
|
||||||
|
|
||||||
|
// convert to hex string
|
||||||
|
let mut hex_str = alloc::string::String::default();
|
||||||
|
for c in out {
|
||||||
|
hex_str.push_str(format!("{c:02x}").as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
hex_str
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// Initializes the env-logger to be used inside tests
|
||||||
|
// fn init_test_env_logger() {
|
||||||
|
// let _ = env_logger::builder()
|
||||||
|
// .format_timestamp(None)
|
||||||
|
// .filter_level(log::LevelFilter::Debug)
|
||||||
|
// .is_test(true)
|
||||||
|
// .try_init();
|
||||||
|
// }
|
||||||
|
|
@ -7,7 +7,9 @@ mod applogic;
|
||||||
mod cache;
|
mod cache;
|
||||||
mod geo_alg;
|
mod geo_alg;
|
||||||
mod io;
|
mod io;
|
||||||
|
mod radio;
|
||||||
mod testdata;
|
mod testdata;
|
||||||
|
mod v2x_tx;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// env_logger::init();
|
// env_logger::init();
|
||||||
|
|
|
||||||
106
src/ubx.rs
106
src/ubx.rs
|
|
@ -1,106 +0,0 @@
|
||||||
//! u-blox helpers
|
|
||||||
#![allow(unused)]
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
pub fn pretty_print_mon_ver(packet: &ublox::mon_ver::MonVerRef) -> alloc::string::String {
|
|
||||||
alloc::format!(
|
|
||||||
"UBX-MON-VER: SW version: {} HW version: {}; Extensions: {:?}",
|
|
||||||
packet.software_version(),
|
|
||||||
packet.hardware_version(),
|
|
||||||
packet.extension().collect::<Vec<&str>>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pretty_print_mon_comms(packet: &ublox::mon_comms::MonCommsRef) -> alloc::string::String {
|
|
||||||
alloc::format!(
|
|
||||||
"UBX-MON-COMMS: {} ports ({:?}), {} tx err, info {:?}",
|
|
||||||
packet.n_ports(),
|
|
||||||
packet.prot_ids(),
|
|
||||||
packet.tx_errors(),
|
|
||||||
packet
|
|
||||||
.ports()
|
|
||||||
.map(|v| alloc::format!("{v:?}"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pretty_print_mon_rf(packet: &ublox::mon_rf::MonRfRef) -> alloc::string::String {
|
|
||||||
alloc::format!(
|
|
||||||
"UBX-MON-RF: {:?}",
|
|
||||||
packet
|
|
||||||
.blocks()
|
|
||||||
.map(|v| alloc::format!("{v:?}"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pretty_print_nav_sat(packet: &ublox::nav_sat::NavSatRef) -> alloc::string::String {
|
|
||||||
// sort by quality flags
|
|
||||||
let mut sat_infos = packet.svs().collect::<Vec<_>>();
|
|
||||||
sat_infos.sort_unstable_by_key(|v| v.flags_raw() & 0x7);
|
|
||||||
sat_infos.reverse();
|
|
||||||
|
|
||||||
let sat_info_strings = sat_infos
|
|
||||||
.iter()
|
|
||||||
.map(|v| {
|
|
||||||
alloc::format!(
|
|
||||||
"- {}/{:3}: E {:3.0}, A {:3.0}, CNO {:2.1} dBHz, {:?}, {:?}",
|
|
||||||
v.gnss_id(),
|
|
||||||
v.sv_id(),
|
|
||||||
v.elev(),
|
|
||||||
v.azim(),
|
|
||||||
v.cno(),
|
|
||||||
v.flags().quality_ind(),
|
|
||||||
v.flags().health(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
alloc::format!(
|
|
||||||
"UBX-NAV-SAT: num {:?}\n{}",
|
|
||||||
packet.num_svs(),
|
|
||||||
sat_info_strings.join("\n")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&ublox::nav_pvt::proto27::NavPvtRef<'a>> for crate::applogic::GnssFix {
|
|
||||||
type Error = alloc::string::String;
|
|
||||||
|
|
||||||
fn try_from(value: &ublox::nav_pvt::proto27::NavPvtRef<'a>) -> Result<Self, Self::Error> {
|
|
||||||
let has_time = value.fix_type() == ublox::GnssFixType::Fix3D
|
|
||||||
|| value.fix_type() == ublox::GnssFixType::GPSPlusDeadReckoning
|
|
||||||
|| value.fix_type() == ublox::GnssFixType::TimeOnlyFix;
|
|
||||||
let has_posvel = value.fix_type() == ublox::GnssFixType::Fix3D
|
|
||||||
|| value.fix_type() == ublox::GnssFixType::GPSPlusDeadReckoning;
|
|
||||||
|
|
||||||
if !has_posvel || !has_time {
|
|
||||||
return Err(alloc::format!(
|
|
||||||
"NAV-PVT without valid fix: {:?}",
|
|
||||||
value.fix_type()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let pos: ublox::PositionLLA = value.into();
|
|
||||||
let vel: ublox::Velocity = value.into();
|
|
||||||
|
|
||||||
let time: chrono::DateTime<chrono::Utc> = value
|
|
||||||
.try_into()
|
|
||||||
.map_err(|err| alloc::format!("Failed to convert time: {err}"))?;
|
|
||||||
|
|
||||||
let latitude_deg = pos.lat;
|
|
||||||
let longitude_deg = pos.lon;
|
|
||||||
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
|
|
||||||
let heading_deg = vel.heading as f32;
|
|
||||||
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
|
|
||||||
let speed_mps = vel.speed as f32;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
time: Some(time.naive_utc()),
|
|
||||||
latitude_deg,
|
|
||||||
longitude_deg,
|
|
||||||
heading_deg: Some(heading_deg),
|
|
||||||
speed_mps: Some(speed_mps),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
94
src/v2x_tx/gn.rs
Normal file
94
src/v2x_tx/gn.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
//! Geonetworking utilities
|
||||||
|
|
||||||
|
use c_its_parser::gn as geonetworking;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn make_shb_eh(
|
||||||
|
address: [u8; 6],
|
||||||
|
station_type: geonetworking::en302636_4_1::StationType,
|
||||||
|
own_position: &crate::applogic::PositionState,
|
||||||
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
|
) -> geonetworking::en302636_4_1::ExtendedHeader {
|
||||||
|
let source_position_vector = make_lpv(address, station_type, own_position, time);
|
||||||
|
|
||||||
|
geonetworking::en302636_4_1::ExtendedHeader::SHB(
|
||||||
|
geonetworking::en302636_4_1::SingleHopBroadcast {
|
||||||
|
source_position_vector,
|
||||||
|
media_dependent_data: [0; 4],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn make_tsb_eh(
|
||||||
|
address: [u8; 6],
|
||||||
|
station_type: geonetworking::en302636_4_1::StationType,
|
||||||
|
own_position: &crate::applogic::PositionState,
|
||||||
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
|
sequence_number: u16,
|
||||||
|
) -> geonetworking::en302636_4_1::ExtendedHeader {
|
||||||
|
let source_position_vector = make_lpv(address, station_type, own_position, time);
|
||||||
|
|
||||||
|
geonetworking::en302636_4_1::ExtendedHeader::TSB(
|
||||||
|
geonetworking::en302636_4_1::TopologicallyScopedBroadcast::new(
|
||||||
|
sequence_number,
|
||||||
|
source_position_vector,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn make_gbc_eh(
|
||||||
|
address: [u8; 6],
|
||||||
|
station_type: geonetworking::en302636_4_1::StationType,
|
||||||
|
own_position: &crate::applogic::PositionState,
|
||||||
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
|
target_pos: geo_types::Point,
|
||||||
|
radius_m: u16,
|
||||||
|
sequence_number: u16,
|
||||||
|
) -> geonetworking::en302636_4_1::ExtendedHeader {
|
||||||
|
let source_position_vector = make_lpv(address, station_type, own_position, time);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let latitude_deg = target_pos.x() as f32;
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let longitude_deg = target_pos.y() as f32;
|
||||||
|
|
||||||
|
geonetworking::en302636_4_1::ExtendedHeader::GBC(
|
||||||
|
geonetworking::en302636_4_1::GeoBroadcast::try_from_values(
|
||||||
|
sequence_number,
|
||||||
|
source_position_vector,
|
||||||
|
latitude_deg,
|
||||||
|
longitude_deg,
|
||||||
|
radius_m,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.expect("Failed to create circular GBC"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_lpv(
|
||||||
|
address: [u8; 6],
|
||||||
|
station_type: geonetworking::en302636_4_1::StationType,
|
||||||
|
own_position: &crate::applogic::PositionState,
|
||||||
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
|
) -> geonetworking::en302636_4_1::LongPositionVector {
|
||||||
|
let timestamp_its = c_its_parser::time_utils::TimestampIts::from(time);
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let latitude_deg = own_position.position.y() as f32;
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let longitude_deg = own_position.position.x() as f32;
|
||||||
|
let speed_mps = own_position.speed_mps.unwrap_or_default();
|
||||||
|
let heading_deg = own_position.heading_deg.unwrap_or_default();
|
||||||
|
|
||||||
|
geonetworking::en302636_4_1::LongPositionVector::try_from_values(
|
||||||
|
geonetworking::en302636_4_1::Address::new(false, station_type, address),
|
||||||
|
timestamp_its.0,
|
||||||
|
latitude_deg,
|
||||||
|
longitude_deg,
|
||||||
|
true,
|
||||||
|
speed_mps,
|
||||||
|
heading_deg,
|
||||||
|
)
|
||||||
|
.expect("Failed to create LongPositionVector")
|
||||||
|
}
|
||||||
164
src/v2x_tx/mod.rs
Normal file
164
src/v2x_tx/mod.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
//! V2X Transmission
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use c_its_parser::gn::{self as geonetworking, Encode};
|
||||||
|
|
||||||
|
pub mod gn;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "esp", feature = "cam_tx"))]
|
||||||
|
/// Creates a station ID from the WLAN MAC address
|
||||||
|
///
|
||||||
|
/// Will use `0xC173` as static prefix and uses last 16 bit from MAC address for the remainder.
|
||||||
|
pub fn make_station_id(mac: esp_hal::efuse::MacAddress) -> u32 {
|
||||||
|
// unwrap is fine here since we can be sure that the MacAddress is 6 byte
|
||||||
|
// and a slice of 2 bytes can be converted to [u8; 2]
|
||||||
|
let mac_last_16bit = u16::from_be_bytes(mac.as_bytes().get(4..6).unwrap().try_into().unwrap());
|
||||||
|
|
||||||
|
0xC173_0000 | u32::from(mac_last_16bit)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GnItsPayload {
|
||||||
|
// common GN parameters
|
||||||
|
const LIFETIME_MILLIS: u32 = 60_000; // itsGnDefaultPacketLifetime is 60 seconds according to ETSI EN 302 636-4-1 V1.4.1
|
||||||
|
|
||||||
|
// ---------------------------------------------
|
||||||
|
// methods to build a GN packet with ITS payload
|
||||||
|
// ---------------------------------------------
|
||||||
|
|
||||||
|
/// Builds the [`geonetworking::en302636_4_1::ExtendedHeader`] and additional information for the ITS message
|
||||||
|
///
|
||||||
|
/// Output:
|
||||||
|
/// - Extended header
|
||||||
|
/// - Area type (when using GAC or GBC)
|
||||||
|
/// - hop limit
|
||||||
|
///
|
||||||
|
/// Note: Make sure to increase the sequence number on multi-hop packets.
|
||||||
|
fn make_eh(
|
||||||
|
&self,
|
||||||
|
address: [u8; 6],
|
||||||
|
own_position: &crate::applogic::PositionState,
|
||||||
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
|
seq_no: &mut u16,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
geonetworking::en302636_4_1::ExtendedHeader,
|
||||||
|
Option<geonetworking::en302636_4_1::AreaType>,
|
||||||
|
u8,
|
||||||
|
),
|
||||||
|
alloc::string::String,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Creates the ITS payload (without BTP header)
|
||||||
|
fn make_payload(
|
||||||
|
&self,
|
||||||
|
) -> Result<(Vec<u8>, c_its_parser::standards::extensions::ItsMessageId), alloc::string::String>;
|
||||||
|
|
||||||
|
// ---------------------------------------------
|
||||||
|
// common methods (with implementation)
|
||||||
|
// ---------------------------------------------
|
||||||
|
|
||||||
|
/// Encodes the GN packet
|
||||||
|
fn encode_packet(
|
||||||
|
&self,
|
||||||
|
address: [u8; 6],
|
||||||
|
own_position: &crate::applogic::PositionState,
|
||||||
|
time: chrono::DateTime<chrono::Utc>,
|
||||||
|
is_mobile: bool,
|
||||||
|
seq_no: &mut u16,
|
||||||
|
) -> Result<Vec<u8>, alloc::string::String> {
|
||||||
|
// Build payload (including BTP header)
|
||||||
|
let (mut its_payload, msg_type) = self.make_payload()?;
|
||||||
|
let mut payload = make_btp_b(msg_type).encode()?;
|
||||||
|
|
||||||
|
payload.append(&mut its_payload);
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let payload_length = (payload.len()) as u16;
|
||||||
|
|
||||||
|
// get extended header (depending on message type and sometimes content as well)
|
||||||
|
let (eh, area_type, maximum_hop_limit) =
|
||||||
|
self.make_eh(address, own_position, time, seq_no)?;
|
||||||
|
|
||||||
|
// Build GN headers
|
||||||
|
let traffic_class = geonetworking::en302636_4_1::TrafficClass::try_new(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
make_traffic_class(msg_type),
|
||||||
|
)
|
||||||
|
.map_err(|err| alloc::format!("Failed to create TrafficClass: {err:?}"))?;
|
||||||
|
let common = geonetworking::en302636_4_1::CommonHeader::from_values(
|
||||||
|
geonetworking::en302636_4_1::NextAfterCommon::BTPB,
|
||||||
|
geonetworking::en302636_4_1::HeaderType::new_from(&eh, area_type)?,
|
||||||
|
traffic_class,
|
||||||
|
is_mobile,
|
||||||
|
payload_length,
|
||||||
|
maximum_hop_limit,
|
||||||
|
);
|
||||||
|
|
||||||
|
let remaining_hop_limit = maximum_hop_limit;
|
||||||
|
let basic = geonetworking::en302636_4_1::BasicHeader::try_new(
|
||||||
|
1,
|
||||||
|
geonetworking::en302636_4_1::NextAfterBasic::CommonHeader,
|
||||||
|
geonetworking::en302636_4_1::Lifetime::from_milliseconds(Self::LIFETIME_MILLIS),
|
||||||
|
remaining_hop_limit,
|
||||||
|
)
|
||||||
|
.map_err(|err| alloc::format!("Failed to create BasicHeader: {err}"))?;
|
||||||
|
|
||||||
|
// Assemble and encode packet
|
||||||
|
let packet = geonetworking::Packet::Unsecured {
|
||||||
|
basic,
|
||||||
|
common,
|
||||||
|
extended: Some(eh),
|
||||||
|
payload: &payload,
|
||||||
|
};
|
||||||
|
|
||||||
|
packet
|
||||||
|
.encode_to_vec()
|
||||||
|
.map_err(|err| alloc::format!("Failed to encode GN packet: {err:?}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a BTP-B header based on the ITS message ID (message type)
|
||||||
|
///
|
||||||
|
/// Port numbers and destination port info according to ETSI TS 103 248
|
||||||
|
fn make_btp_b(
|
||||||
|
msg_type: c_its_parser::standards::extensions::ItsMessageId,
|
||||||
|
) -> c_its_parser::transport::TransportHeader {
|
||||||
|
let (destination_port, destination_port_info) = match msg_type {
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Denm => (2002, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Cam => (2001, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Mapem => (2003, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Spatem => (2004, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Saem => (2005, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Ivim => (2006, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Srem => (2007, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Ssem => (2008, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Cpm => (2009, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Poi => (2010, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::EvRsr => (2012, 0),
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Rtcmem => (2013, 0),
|
||||||
|
_ => (0, 0), // no information found for the subsequent types
|
||||||
|
};
|
||||||
|
|
||||||
|
c_its_parser::transport::TransportHeader::BtpB(c_its_parser::transport::BasicTransportBHeader {
|
||||||
|
destination_port,
|
||||||
|
destination_port_info,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a traffic class ID based on the ITS message ID (message type)
|
||||||
|
fn make_traffic_class(msg_type: c_its_parser::standards::extensions::ItsMessageId) -> u8 {
|
||||||
|
#[allow(clippy::match_same_arms)]
|
||||||
|
match msg_type {
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Denm => 1,
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Cam => 2,
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Mapem => 3, // from C-Roads RS_RSP_063(1)
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Spatem => 3, // from C-Roads RS_RSP_063(1)
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Ivim => 3, // from C-Roads RS_RSP_063(1)
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Srem => 2, // from C-Roads RS_RSP_063(1)
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Ssem => 2, // from C-Roads RS_RSP_063(1)
|
||||||
|
c_its_parser::standards::extensions::ItsMessageId::Rtcmem => 3, // CSP_MaxPrio=252 -> 3
|
||||||
|
_ => 3, // fall-back to lowest priority
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue