Import independent seat firmware source without build artifacts
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: n7-seat-self-compose
|
||||
description: Implement and compile arbitrary Chinese or English N7 four-motor seat-action firmware requests for Classic CAN OTA with full source access.
|
||||
---
|
||||
|
||||
# N7 Seat Self Compose
|
||||
|
||||
Implement the user's request directly in the complete writable firmware task copy.
|
||||
Choose the design and edit any canonical source, driver, generator, build file, or
|
||||
other project file needed. For the supplied action runtime, edit the authoritative
|
||||
`firmware/application/ota_self_compose_plan.h`; never edit or depend on a prior
|
||||
`build/gcc/application_source` cache. The build helper generates a clean compiler
|
||||
source tree from the canonical firmware plus `third_party` before every build. The
|
||||
Base APIs are optional accelerators, not a required design.
|
||||
Do not create `plan.json` or a capabilities manifest. There is no second reviewer,
|
||||
server-side compiler, source audit, repair limit, or task timeout. The server publishes
|
||||
the exact firmware you compile.
|
||||
|
||||
Read [references/base-action-api.md](references/base-action-api.md) when the request
|
||||
uses the supplied four-axis action runtime.
|
||||
|
||||
## Hardware facts that must remain compatible
|
||||
|
||||
- Motor 0, 前后: fixed range 480 Hall across 215.00 mm. Nearest to far moves backward.
|
||||
- Motor 1, 高度/坐盆: fixed range 373 Hall across 55.00 mm. Nearest to far moves upward.
|
||||
- Motor 2, 靠背: fixed range 917 Hall across 68.00 degrees. Nearest to far reclines downward.
|
||||
- Motor 3, 腿托: fixed range 647 Hall across 72.00 degrees. Nearest to far lifts upward.
|
||||
- Motor 3 always drives at 60% PWM. Other motors default to 80% and may use the
|
||||
requested low 60%, medium 80%, high 95%, or custom duty.
|
||||
- Board-persisted Hall positions are the position source for every action. Persist
|
||||
the updated current positions. Never replace the four fixed maximum Hall values.
|
||||
- Ordinary timed motion remains inside 5%..95% and reverses at either boundary while
|
||||
its requested time continues. Cycle motion reverses at those boundaries. Absolute,
|
||||
relative-distance, and relative-angle targets clamp to 5%..95% and stop at target.
|
||||
- After each real start or direction reversal, ignore stall detection for 2 seconds.
|
||||
Then a continuous 1-second window with 0, 1, or 2 Hall rising edges is a stall;
|
||||
3 or more edges is movement.
|
||||
|
||||
Keep Classic CAN at 500 kbit/s and retain the App control/telemetry ABI: standard IDs
|
||||
`0x6A0`/`0x6A2`, `SEAT_INFO` opcode `0x60`, selectors 0 through 14, all four live
|
||||
position/range/flags responses, `TEST_START`, `TEST_STOP`, `SEAT_STOP`, status queries,
|
||||
and Enter Bootloader. Once START is accepted, the board completes the action itself.
|
||||
CAN silence, query failure, RX overflow, or Bus-Off must not end motion; explicit STOP,
|
||||
real driver faults, and Hall stall remain effective.
|
||||
Apply the same board-owned lifetime to the dedicated calibration/homing Base firmware:
|
||||
after `SEAT_CALIBRATE` or `SEAT_HOME` is accepted, it must complete without an App lease
|
||||
or heartbeat. CAN remains available only for position/status queries, explicit STOP and
|
||||
Enter Bootloader; silence or CAN faults never abort calibration/homing.
|
||||
|
||||
## Compile your exact source
|
||||
|
||||
Run:
|
||||
|
||||
`sh .agents/skills/n7-seat-self-compose/scripts/build_firmware.sh`
|
||||
|
||||
Inspect the real GCC output, edit whatever is necessary, and rerun the helper as many
|
||||
times as needed until it prints `N7_CODEX_FIRMWARE_BUILD_OK`. Finish only after that
|
||||
same helper has produced `codex-output/self-compose.raw.bin`. No server-side rebuild or
|
||||
source audit follows it.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "N7 Seat Self Compose"
|
||||
short_description: "Build N7 CAN OTA firmware while preserving live seat telemetry"
|
||||
default_prompt: "Use $n7-seat-self-compose to implement and compile this seat-motion request while preserving the immutable board CAN position telemetry contract."
|
||||
@@ -0,0 +1,100 @@
|
||||
# N7 board-side action API
|
||||
|
||||
The macros below construct C steps in the authoritative
|
||||
`firmware/application/ota_self_compose_plan.h`. The build helper copies that file
|
||||
into a clean generated compiler tree on every build; do not edit or reuse
|
||||
`build/gcc/application_source`. The runtime reads the board's restored/live Hall
|
||||
position at each step. `mm_x100` and `degree_x100` are fixed point with two decimals.
|
||||
|
||||
## Direction and range
|
||||
|
||||
| Axis | Motor | Fixed Hall | Physical range | Toward far | Toward near |
|
||||
|---|---:|---:|---:|---|---|
|
||||
| 前后 | 0 | 480 | 215.00 mm | `OTA_SEAT_SLIDE_BACKWARD` | `OTA_SEAT_SLIDE_FORWARD` |
|
||||
| 高度/坐盆 | 1 | 373 | 55.00 mm | `OTA_SEAT_HEIGHT_UP` | `OTA_SEAT_HEIGHT_DOWN` |
|
||||
| 靠背 | 2 | 917 | 68.00° | `OTA_SEAT_BACKREST_RECLINE_DOWN` | `OTA_SEAT_BACKREST_RAISE` |
|
||||
| 腿托 | 3 | 647 | 72.00° | `OTA_SEAT_LEGREST_RAISE` | `OTA_SEAT_LEGREST_LOWER` |
|
||||
|
||||
Nearest is position zero. Normal DIY Hall bounds are 24..456, 19..354, 46..871,
|
||||
and 33..614 for motors 0..3. Do not seek the physical 0%/100% endpoint from an
|
||||
ordinary DIY image. If board position is invalid, do not blind-move the mechanism.
|
||||
|
||||
## Speed and stall
|
||||
|
||||
- `OTA_SEAT_SPEED_LOW`: 60%
|
||||
- `OTA_SEAT_SPEED_MEDIUM`: 80%
|
||||
- `OTA_SEAT_SPEED_HIGH`: 95%
|
||||
- `OTA_SEAT_SPEED_DEFAULT`: 80%
|
||||
- `OTA_SEAT_SPEED_CUSTOM(n)`: custom 1%..95%
|
||||
|
||||
Motor 3 ignores the duty argument and always uses 60%. After each actual PWM start
|
||||
or reversal, its Hall stall window starts only after 2 seconds. In the following
|
||||
continuous 1000 ms window, at most 2 rising edges is stall; at least 3 is movement.
|
||||
|
||||
## Actions
|
||||
|
||||
Timed motion:
|
||||
|
||||
```c
|
||||
OTA_SEAT_SLIDE_FOR(direction, durationMs, duty, pauseMs)
|
||||
OTA_SEAT_HEIGHT_FOR(direction, durationMs, duty, pauseMs)
|
||||
OTA_SEAT_BACKREST_FOR(direction, durationMs, duty, pauseMs)
|
||||
OTA_SEAT_LEGREST_FOR(direction, durationMs, duty, pauseMs)
|
||||
```
|
||||
|
||||
If a timed action reaches 5% or 95%, it reverses and continues the remaining time.
|
||||
|
||||
Absolute board position:
|
||||
|
||||
```c
|
||||
OTA_SEAT_SLIDE_TO(positionMmX100, duty, pauseMs)
|
||||
OTA_SEAT_HEIGHT_TO(positionMmX100, duty, pauseMs)
|
||||
OTA_SEAT_BACKREST_TO(angleDegX100, duty, pauseMs)
|
||||
OTA_SEAT_LEGREST_TO(angleDegX100, duty, pauseMs)
|
||||
```
|
||||
|
||||
Relative distance/angle:
|
||||
|
||||
```c
|
||||
OTA_SEAT_SLIDE_BY(direction, distanceMmX100, duty, pauseMs)
|
||||
OTA_SEAT_HEIGHT_BY(direction, distanceMmX100, duty, pauseMs)
|
||||
OTA_SEAT_BACKREST_BY(direction, angleDegX100, duty, pauseMs)
|
||||
OTA_SEAT_LEGREST_BY(direction, angleDegX100, duty, pauseMs)
|
||||
```
|
||||
|
||||
Absolute and relative targets clamp to the axis's 5%..95% interval and stop there.
|
||||
|
||||
Cycles:
|
||||
|
||||
```c
|
||||
OTA_SEAT_SLIDE_CYCLE(firstDirection, cycles, duty, endpointPauseMs)
|
||||
OTA_SEAT_HEIGHT_CYCLE(firstDirection, cycles, duty, endpointPauseMs)
|
||||
OTA_SEAT_BACKREST_CYCLE(firstDirection, cycles, duty, endpointPauseMs)
|
||||
OTA_SEAT_LEGREST_CYCLE(firstDirection, cycles, duty, endpointPauseMs)
|
||||
```
|
||||
|
||||
One cycle is two boundary legs. `cycles == 0` continues until explicit STOP or a
|
||||
user-requested program duration. The board owns execution after one `TEST_START`.
|
||||
|
||||
## Required CAN position contract
|
||||
|
||||
Retain the Base `SEAT_INFO` implementation at 500 kbit/s using request ID `0x6A0`
|
||||
and response ID `0x6A2`, DLC 8. Selectors 0..14 retain their existing job, four live
|
||||
position/range, four flags, four physical range, persistent state, and runtime-kind
|
||||
meanings. Continue servicing these queries and explicit STOP during every action,
|
||||
but never use communication activity as an action lease.
|
||||
|
||||
## Minimal C plan
|
||||
|
||||
```c
|
||||
#define OTA_SELF_COMPOSE_STEP_COUNT (2u)
|
||||
#define OTA_SELF_COMPOSE_PROGRAM_REPEAT (1u)
|
||||
#define OTA_SELF_COMPOSE_MAX_RUNTIME_MS (0ul)
|
||||
|
||||
static const ota_self_compose_step_t otaSelfComposePlan[] =
|
||||
{
|
||||
OTA_SEAT_HEIGHT_TO(3000ul, OTA_SEAT_SPEED_MEDIUM, 200ul),
|
||||
OTA_SEAT_BACKREST_BY(OTA_SEAT_BACKREST_RECLINE_DOWN, 3000ul,
|
||||
OTA_SEAT_SPEED_CUSTOM(75u), 0ul),
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
# This is the only firmware build entry point used by the composing Codex.
|
||||
# Codex may modify the complete writable task source; the service supplies
|
||||
# separate incremental build/output directories. Every compiler control is one.
|
||||
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
workspace=$(CDPATH= cd -- "$script_dir/../../../.." && pwd)
|
||||
build_dir=${N7_CODEX_FIRMWARE_BUILD_DIR:?N7_CODEX_FIRMWARE_BUILD_DIR is required}
|
||||
output_dir=${N7_CODEX_FIRMWARE_OUTPUT_DIR:?N7_CODEX_FIRMWARE_OUTPUT_DIR is required}
|
||||
task_build_dir="$build_dir/task-workspace"
|
||||
generated_source="$build_dir/generated-application-source"
|
||||
build_cpu=${N7_BUILD_CPU:-0}
|
||||
|
||||
report_failure() {
|
||||
result=$?
|
||||
trap - EXIT
|
||||
if [ "$result" -ne 0 ]; then
|
||||
echo "N7_CODEX_FIRMWARE_BUILD_FAILED exit=$result" >&2
|
||||
fi
|
||||
exit "$result"
|
||||
}
|
||||
trap report_failure EXIT
|
||||
|
||||
export N7_BUILD_JOBS=1
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=1
|
||||
export MAKEFLAGS=-j1
|
||||
export NINJAFLAGS=-j1
|
||||
export OMP_NUM_THREADS=1
|
||||
export OPENBLAS_NUM_THREADS=1
|
||||
export MKL_NUM_THREADS=1
|
||||
export NUMEXPR_NUM_THREADS=1
|
||||
export RAYON_NUM_THREADS=1
|
||||
export GOMAXPROCS=1
|
||||
|
||||
mkdir -p "$build_dir" "$output_dir"
|
||||
rm -rf "$generated_source"
|
||||
python3 "$workspace/tools/prepare_gcc_application_source.py" \
|
||||
--source-root "$workspace/third_party/ZL-test-scripts" \
|
||||
--project-root "$workspace" \
|
||||
--output-root "$generated_source"
|
||||
test -s "$generated_source/src/main_cm0plus.c"
|
||||
test -s "$generated_source/src/ota_self_compose_plan.h"
|
||||
|
||||
echo "N7_CODEX_FIRMWARE_BUILD_START cpu=1"
|
||||
taskset -c "$build_cpu" cmake \
|
||||
-S "$workspace/firmware/gcc" -B "$task_build_dir" -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$workspace/firmware/gcc/arm-none-eabi-toolchain.cmake" \
|
||||
-DOTA_PROJECT_ROOT="$workspace" \
|
||||
-DOTA_SDK_ROOT="$workspace/third_party/ZL-test-scripts/T2G_Sample_Driver_Library_7.9.0" \
|
||||
-DOTA_SOURCE_ROOT="$workspace/third_party/ZL-test-scripts" \
|
||||
-DOTA_GENERATED_SOURCE_ROOT="$generated_source" \
|
||||
-DOTA_OUTPUT_DIR="$output_dir"
|
||||
taskset -c "$build_cpu" cmake --build "$task_build_dir" \
|
||||
--target app_self_compose --parallel 1
|
||||
|
||||
firmware="$output_dir/self-compose.raw.bin"
|
||||
test -s "$firmware"
|
||||
size=$(wc -c <"$firmware" | tr -d ' ')
|
||||
sha256=$(sha256sum "$firmware" | awk '{print $1}')
|
||||
echo "N7_CODEX_FIRMWARE_BUILD_OK cpu=1 bytes=$size sha256=$sha256"
|
||||
trap - EXIT
|
||||
Reference in New Issue
Block a user