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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions lib/ext/ap_trigger.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
defmodule FarmbotOS.APTrigger do
@moduledoc """
通过 GPIO 引脚触发进入 AP 模式。

- 默认使用 GPIO26 (BCM 编号),可在 @gpio_pin 修改。
- 检测到按键低电平(falling edge)时,进入 AP 模式。
- LED 闪烁表示触发。
- 防止重复触发。
"""

use GenServer
require FarmbotOS.Logger

@gpio_pin 26
@led_flash_ms 500

# 启动 GenServer
def start_link(_args) do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
end

@impl true
def init(_state) do
# 打开 GPIO 输入模式
{:ok, gpio} = Circuits.GPIO.open(@gpio_pin, :input)
# 设置上拉
:ok = Circuits.GPIO.set_pull_mode(gpio, :pullup)
# 设置下降沿触发
Circuits.GPIO.set_interrupts(gpio, :falling)

IO.puts("APTrigger: 监听 GPIO#{@gpio_pin},低电平触发进入 AP 模式。")
FarmbotOS.Logger.debug(1, "APTrigger: 监听 GPIO#{@gpio_pin},低电平触发进入 AP 模式。")

# first 表示第一次触发
# processing 表示正在处理
{:ok, %{gpio: gpio, first: true, processing: false}}
end

# 防止重复触发:如果正在处理,忽略新消息
@impl true
def handle_info({:circuits_gpio, pin, ts, 0}, %{processing: true} = state) do
IO.puts("GPIO #{pin} 触发被忽略,正在处理上一条触发,ts=#{ts}")
{:noreply, state}
end

# 第一次正常触发
@impl true
def handle_info({:circuits_gpio, pin, ts, 0}, %{first: true} = state) do
IO.puts("GPIO #{pin} 触发消息到达 APTrigger, 第一次!, ts=#{ts}")
FarmbotOS.Logger.debug(1, "APTrigger: GPIO #{pin} 触发 → 进入 AP 模式。")

# 设置正在处理标记
new_state = %{state | first: false, processing: true}

# 异步执行 factory_reset,同时闪烁 LED
Task.start(fn ->
# LED 闪烁一次
FarmbotOS.SystemLed.on()
Process.sleep(@led_flash_ms)
FarmbotOS.SystemLed.off()

# 执行出厂重置
FarmbotOS.System.factory_reset("GPIO trigger", true)

# 通知 GenServer 完成处理
GenServer.cast(__MODULE__, :done)
end)

{:noreply, new_state}
end

# 处理完成后,清除 processing 标记
@impl true
def handle_cast(:done, state) do
{:noreply, %{state | processing: false}}
end

# 其他 GPIO 消息
# @impl true
# def handle_info(msg, state) do
# IO.inspect(msg, label: "APTrigger 收到其他消息")
# {:noreply, state}
# end
end
17 changes: 17 additions & 0 deletions lib/ext/system_led.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 定义 LED 控制模块
defmodule FarmbotOS.SystemLed do
@led_path "/sys/class/leds/ACT/brightness"

# 点亮
def on, do: File.write!(@led_path, "1")

# 熄灭
def off, do: File.write!(@led_path, "0")

# 闪烁
def blink(ms \\ 500) do
on()
Process.sleep(ms)
off()
end
end
4 changes: 3 additions & 1 deletion lib/farmbot_os.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ defmodule FarmbotOS do
{FarmbotOS.Platform.Supervisor, []},
FarmbotOS.Asset.Supervisor,
FarmbotOS.Firmware.UARTObserver,
{Task.Supervisor, name: FarmbotOS.Task.Supervisor}
{Task.Supervisor, name: FarmbotOS.Task.Supervisor},
# GPIO Trigger
{FarmbotOS.APTrigger, []}
]

Supervisor.start_link(children, strategy: :one_for_one, name: __MODULE__)
Expand Down