From d33d633ba22dc5dfcab005e91e6497d5785a11e9 Mon Sep 17 00:00:00 2001 From: liangliangit <248593893@qq.com> Date: Fri, 21 Aug 2026 15:09:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BB=8F=E7=BA=AC=E5=BA=A6?= =?UTF-8?q?=20=E6=97=A5=E5=87=BA=E6=97=A5=E8=90=BD=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 37 ++++- apps/m9zCtrlTty/build.sh | 135 +++++++++++++++++++ internal/module/m9zTtyApi/read.go | 4 +- internal/module/m9zTtyApi/set.go | 18 ++- internal/module/m9zTtyApi/solar_task.go | 17 +++ internal/module/m9zTtyApi/solar_task_test.go | 49 +++++++ 7 files changed, 253 insertions(+), 8 deletions(-) create mode 100755 apps/m9zCtrlTty/build.sh create mode 100644 internal/module/m9zTtyApi/solar_task.go create mode 100644 internal/module/m9zTtyApi/solar_task_test.go diff --git a/.gitignore b/.gitignore index 9ac25ef..6e4c07d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ *.idea* *logs **.DS_Store** +/dist/ diff --git a/README.md b/README.md index 74cba43..47f625f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,36 @@ # 明九洲触摸屏 - 打包 - ``` - cd apps/m9zCtrlTty - sh build.sh m9zCtrlTty.go linux arm64 - ``` + +## 编译 m9zCtrlTty + +构建机需要 Go 1.26.2 或更高版本。 + +编译 Linux ARM 32 位(默认采用 ARMv7): + +```bash +./apps/m9zCtrlTty/build.sh linux arm 7 +``` + +输出文件:`dist/linux-armv7/m9zCtrlTty` + +脚本按 Go 的 `GOOS/GOARCH` 目标进行交叉编译,例如: + +```bash +./apps/m9zCtrlTty/build.sh linux arm64 +./apps/m9zCtrlTty/build.sh linux amd64 +./apps/m9zCtrlTty/build.sh windows amd64 +./apps/m9zCtrlTty/build.sh darwin arm64 +``` + +可运行 `go tool dist list` 查看当前 Go 工具链支持的操作系统和 CPU 架构组合。脚本默认设置 `CGO_ENABLED=0`,并编译整个 `apps/m9zCtrlTty` 包,确保同目录的所有 Go 源文件都被包含。 + +ARM 型号对应关系:`armv7l` 使用 `7`,`armv6l` 使用 `6`,ARMv5 使用 `5`,`aarch64` 则应使用 `arm64`。默认 ARMv7 使用硬浮点;采用软浮点 ABI 的设备可使用例如 `linux arm 7,softfloat`。 + +Windows 和 macOS 目标可以交叉编译,但当前程序运行期依赖 Linux 的串口设备、`systemd`、`dpkg` 和 X11,因此完整功能部署仍以 Linux 为目标。 + +脚本默认用 `-s -w` 移除调试符号以减小嵌入式产物体积;如需保留符号,可设置空值:`BUILD_LDFLAGS= ./apps/m9zCtrlTty/build.sh linux arm 7`。 + +二进制没有嵌入运行资源。部署时还需要在程序目录中配套提供 `config/config.json`、`wwwroot/` 和 `firefox/firefox-deb.tar.gz` 等实际运行资源。 + 前端分绿盟版和普通版 git clone https://gitee.com/lufaneng/central-control.git diff --git a/apps/m9zCtrlTty/build.sh b/apps/m9zCtrlTty/build.sh new file mode 100755 index 0000000..105730c --- /dev/null +++ b/apps/m9zCtrlTty/build.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +app_name="m9zCtrlTty" +app_package="./apps/m9zCtrlTty" +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/../.." && pwd)" + +usage() { + cat <<'EOF' +Usage: + ./apps/m9zCtrlTty/build.sh [goarm] + +Examples: + ./apps/m9zCtrlTty/build.sh linux arm 7 + ./apps/m9zCtrlTty/build.sh linux arm64 + ./apps/m9zCtrlTty/build.sh windows amd64 + ./apps/m9zCtrlTty/build.sh darwin arm64 + +Arguments: + goos Target operating system accepted by "go tool dist list". + goarch Target CPU architecture accepted by "go tool dist list". + goarm ARM generation for 32-bit GOARCH=arm: 5, 6, or 7 (default: 7). + Soft-float targets may use 5,softfloat, 6,softfloat, or 7,softfloat. + +Environment variables: + OUTPUT_ROOT Output root directory (default: dist). + CGO_ENABLED CGO mode (default: 0 for cross-compilation). + BUILD_TAGS Optional Go build tags. + BUILD_LDFLAGS Go linker flags (default: -s -w; set to an empty value to keep symbols). +EOF +} + +if [[ $# -lt 2 || $# -gt 3 ]]; then + usage >&2 + exit 2 +fi + +if ! command -v go >/dev/null 2>&1; then + printf 'Go toolchain was not found in PATH.\n' >&2 + exit 127 +fi + +target_os="$1" +target_arch="$2" +target_pair="${target_os}/${target_arch}" + +supported_target=false +while IFS= read -r candidate; do + if [[ "$candidate" == "$target_pair" ]]; then + supported_target=true + break + fi +done < <(go tool dist list) + +if [[ "$supported_target" != true ]]; then + printf 'Unsupported Go build target: %s\n' "$target_pair" >&2 + printf 'Run "go tool dist list" to see supported targets.\n' >&2 + exit 2 +fi + +arch_label="$target_arch" +if [[ "$target_arch" == "arm" ]]; then + target_goarm="${3:-${GOARM:-7}}" + case "$target_goarm" in + 5|6|7|5,softfloat|6,softfloat|7,softfloat) ;; + *) + printf 'Invalid GOARM value: %s\n' "$target_goarm" >&2 + exit 2 + ;; + esac + export GOARM="$target_goarm" + arm_generation="${target_goarm%%,*}" + arch_label="armv${arm_generation}" + if [[ "$target_goarm" == *,softfloat ]]; then + arch_label="${arch_label}-softfloat" + fi +elif [[ $# -eq 3 ]]; then + printf 'The third argument (goarm) is only valid when GOARCH=arm.\n' >&2 + exit 2 +fi + +output_root="${OUTPUT_ROOT:-dist}" +if [[ "$output_root" != /* ]]; then + output_root="${repo_root}/${output_root}" +fi +output_dir="${output_root}/${target_os}-${arch_label}" + +extension="" +case "$target_os" in + windows) extension=".exe" ;; + js|wasip1) + if [[ "$target_arch" == "wasm" ]]; then + extension=".wasm" + fi + ;; +esac + +output_path="${output_dir}/${app_name}${extension}" +mkdir -p "$output_dir" + +export GOOS="$target_os" +export GOARCH="$target_arch" +export CGO_ENABLED="${CGO_ENABLED:-0}" + +if [[ "${BUILD_LDFLAGS+x}" == "x" ]]; then + build_ldflags="$BUILD_LDFLAGS" +else + build_ldflags="-s -w" +fi + +build_args=(build -mod=readonly -trimpath -o "$output_path") +if [[ -n "${BUILD_TAGS:-}" ]]; then + build_args+=(-tags "$BUILD_TAGS") +fi +if [[ -n "$build_ldflags" ]]; then + build_args+=(-ldflags "$build_ldflags") +fi +build_args+=("$app_package") + +printf 'Building %s for %s (CGO_ENABLED=%s)\n' "$app_name" "$target_pair" "$CGO_ENABLED" +if [[ "$target_arch" == "arm" ]]; then + printf 'Using GOARM=%s\n' "$GOARM" +fi + +( + cd "$repo_root" + go "${build_args[@]}" +) + +printf 'Build complete: %s\n' "$output_path" +if command -v file >/dev/null 2>&1; then + file "$output_path" +fi diff --git a/internal/module/m9zTtyApi/read.go b/internal/module/m9zTtyApi/read.go index 8777029..670c98b 100644 --- a/internal/module/m9zTtyApi/read.go +++ b/internal/module/m9zTtyApi/read.go @@ -384,7 +384,7 @@ func getStartTask2(rpc towgo.JsonRpcConnection) { if err != nil { panic(err) } - task.ExecTime = timeRead.Sunrise + applyStartTaskSolarTime(task, timeRead) } rpc.WriteResult(task) @@ -412,7 +412,7 @@ func getStopTask2(rpc towgo.JsonRpcConnection) { if err != nil { panic(err) } - task.ExecTime = timeRead.Sunset + applyStopTaskSolarTime(task, timeRead) } rpc.WriteResult(task) diff --git a/internal/module/m9zTtyApi/set.go b/internal/module/m9zTtyApi/set.go index 013f582..bf00298 100644 --- a/internal/module/m9zTtyApi/set.go +++ b/internal/module/m9zTtyApi/set.go @@ -290,7 +290,7 @@ func setStopTaskWrite(rpc towgo.JsonRpcConnection) { rpc.WriteResult("ok") } -// 写入开始任务 (优化指令 CMD=0x15) +// 写入开始任务 (优化指令 CMD=0x13,经纬度模式使用日落时间) func setStartTask2(rpc towgo.JsonRpcConnection) { var p struct { ExecTime string `json:"execTime"` @@ -307,6 +307,13 @@ func setStartTask2(rpc towgo.JsonRpcConnection) { panic(err) } p.ControlTask.ExecTime = parse + if p.ControlTask.TimeType == 1 { + sunTimes, err := m9z.SunRiseTimeRead(p.CommUid) + if err != nil { + panic(err) + } + applyStartTaskSolarTime(&p.ControlTask, sunTimes) + } program, err := m9z.ControlTaskToTaskProgram(p.ControlTask, p.Mode) if err != nil { panic(err) @@ -321,6 +328,8 @@ func setStartTask2(rpc towgo.JsonRpcConnection) { } rpc.WriteResult("ok") } + +// 写入结束任务 (优化指令 CMD=0x15,经纬度模式使用日出时间) func setStopTask2(rpc towgo.JsonRpcConnection) { var p struct { ExecTime string `json:"execTime"` @@ -337,6 +346,13 @@ func setStopTask2(rpc towgo.JsonRpcConnection) { if p.CommUid == "" { panic(gerror.New("comm_uid is empty")) } + if p.ControlTask.TimeType == 1 { + sunTimes, err := m9z.SunRiseTimeRead(p.CommUid) + if err != nil { + panic(err) + } + applyStopTaskSolarTime(&p.ControlTask, sunTimes) + } program, err := m9z.ControlTaskToTaskProgram(p.ControlTask, p.Mode) if err != nil { diff --git a/internal/module/m9zTtyApi/solar_task.go b/internal/module/m9zTtyApi/solar_task.go new file mode 100644 index 0000000..891870b --- /dev/null +++ b/internal/module/m9zTtyApi/solar_task.go @@ -0,0 +1,17 @@ +package m9zApi + +import "tgk-touch/internal/library/m9z" + +// 开始任务用于日落开灯,结束任务用于日出关灯。 +// rise/set 的协议语义保持不变:rise 始终是日出,set 始终是日落。 +func applyStartTaskSolarTime(task *m9z.ControlTask, sunTimes *m9z.SunTimes) { + if task.TimeType == 1 { + task.ExecTime = sunTimes.Sunset + } +} + +func applyStopTaskSolarTime(task *m9z.ControlTask, sunTimes *m9z.SunTimes) { + if task.TimeType == 1 { + task.ExecTime = sunTimes.Sunrise + } +} diff --git a/internal/module/m9zTtyApi/solar_task_test.go b/internal/module/m9zTtyApi/solar_task_test.go new file mode 100644 index 0000000..49d8c4a --- /dev/null +++ b/internal/module/m9zTtyApi/solar_task_test.go @@ -0,0 +1,49 @@ +package m9zApi + +import ( + "testing" + "time" + + "tgk-touch/internal/library/m9z" +) + +func TestApplySolarTaskTime(t *testing.T) { + sunrise := time.Date(2026, 8, 21, 5, 32, 0, 0, time.Local) + sunset := time.Date(2026, 8, 21, 18, 41, 0, 0, time.Local) + sunTimes := &m9z.SunTimes{Sunrise: sunrise, Sunset: sunset} + + tests := []struct { + name string + apply func(*m9z.ControlTask, *m9z.SunTimes) + want time.Time + }{ + {name: "start task uses sunset", apply: applyStartTaskSolarTime, want: sunset}, + {name: "stop task uses sunrise", apply: applyStopTaskSolarTime, want: sunrise}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + task := &m9z.ControlTask{TimeType: 1} + tt.apply(task, sunTimes) + if !task.ExecTime.Equal(tt.want) { + t.Fatalf("ExecTime = %v, want %v", task.ExecTime, tt.want) + } + }) + } +} + +func TestApplySolarTaskTimeKeepsScheduledTime(t *testing.T) { + scheduled := time.Date(2026, 8, 21, 20, 0, 0, 0, time.Local) + task := &m9z.ControlTask{TimeType: 0, ExecTime: scheduled} + sunTimes := &m9z.SunTimes{ + Sunrise: scheduled.Add(-14 * time.Hour), + Sunset: scheduled.Add(-time.Hour), + } + + applyStartTaskSolarTime(task, sunTimes) + applyStopTaskSolarTime(task, sunTimes) + + if !task.ExecTime.Equal(scheduled) { + t.Fatalf("ExecTime = %v, want scheduled time %v", task.ExecTime, scheduled) + } +}