defmodule FarmbotCore.FirmwareSideEffects do @moduledoc "Handles firmware data and syncing it with BotState." @behaviour FarmbotFirmware.SideEffects require Logger require FarmbotCore.Logger alias FarmbotCore.{Asset, BotState, DepTracker, FirmwareEstopTimer, Leds} @impl FarmbotFirmware.SideEffects def handle_position(x: x, y: y, z: z) do :ok = BotState.set_position(x, y, z) end @impl FarmbotFirmware.SideEffects def handle_load(x: x, y: y, z: z) do :ok = BotState.set_load(x, y, z) end @impl FarmbotFirmware.SideEffects def handle_position_change([{_axis, _value}]) do :noop end @impl FarmbotFirmware.SideEffects def handle_axis_state([{axis, state}]) do BotState.set_axis_state(axis, state) end @impl FarmbotFirmware.SideEffects def handle_axis_timeout(axis) do FarmbotCore.Logger.error 1, "Axis #{axis} timed out waiting for movement to complete" :noop end @impl FarmbotFirmware.SideEffects def handle_home_complete(_) do :noop end @impl FarmbotFirmware.SideEffects def handle_calibration_state([{_axis, _state}]) do :noop end @impl FarmbotFirmware.SideEffects def handle_encoders_scaled(x: x, y: y, z: z) do :ok = BotState.set_encoders_scaled(x, y, z) end # this is a bug in the firmware code i think def handle_encoders_scaled([]), do: :noop @impl FarmbotFirmware.SideEffects def handle_encoders_raw(x: x, y: y, z: z) do :ok = BotState.set_encoders_raw(x, y, z) end @impl FarmbotFirmware.SideEffects def handle_parameter_value([{param, value}]) do :ok = BotState.set_firmware_config(param, value) end @impl FarmbotFirmware.SideEffects def handle_parameter_calibration_value([{param, value}]) do %{param => value} |> Asset.update_firmware_config!() |> Asset.Private.mark_dirty!(%{}) :ok end @impl FarmbotFirmware.SideEffects def handle_pin_value(p: pin, v: value) do :ok = BotState.set_pin_value(pin, value) end @impl FarmbotFirmware.SideEffects def handle_software_version([version]) do :ok = BotState.set_firmware_version(version) case String.split(version, ".") do # Ramps [_, _, _, "R"] -> _ = Leds.red(:solid) :ok = BotState.set_firmware_hardware("arduino") # Farmduino [_, _, _, "F"] -> _ = Leds.red(:solid) :ok = BotState.set_firmware_hardware("farmduino") # Farmduino V14 [_, _, _, "G"] -> _ = Leds.red(:solid) :ok = BotState.set_firmware_hardware("farmduino_k14") # Farmduino V15 [_, _, _, "H"] -> _ = Leds.red(:solid) :ok = BotState.set_firmware_hardware("farmduino_k15") # Express V10 [_, _, _, "E"] -> _ = Leds.red(:solid) :ok = BotState.set_firmware_hardware("express_k10") [_, _, _, "S"] -> _ = Leds.red(:slow_blink) :ok = BotState.set_firmware_version("none") :ok = BotState.set_firmware_hardware("none") end end @impl FarmbotFirmware.SideEffects def handle_end_stops(_) do :noop end @impl FarmbotFirmware.SideEffects def handle_busy(busy) do :ok = BotState.set_firmware_busy(busy) DepTracker.register_service(:firmware, :busy) end @impl FarmbotFirmware.SideEffects def handle_idle(idle) do _ = FirmwareEstopTimer.cancel_timer() :ok = BotState.set_firmware_unlocked() :ok = BotState.set_firmware_idle(idle) DepTracker.register_service(:firmware, :idle) end @impl FarmbotFirmware.SideEffects def handle_emergency_lock() do _ = FirmwareEstopTimer.start_timer() _ = Leds.yellow(:slow_blink) :ok = BotState.set_firmware_locked() DepTracker.register_service(:firmware, :locked) end @impl FarmbotFirmware.SideEffects def handle_emergency_unlock() do _ = FirmwareEstopTimer.cancel_timer() _ = Leds.yellow(:off) :ok = BotState.set_firmware_unlocked() end @impl FarmbotFirmware.SideEffects def handle_input_gcode({_, {:unknown, _}}) do :ok end def handle_input_gcode({:unknown, _}) do :ok end def handle_input_gcode(code) do string_code = FarmbotFirmware.GCODE.encode(code) should_log? = Asset.fbos_config().firmware_input_log should_log? && FarmbotCore.Logger.debug(3, "Firmware input: " <> string_code) end @impl FarmbotFirmware.SideEffects def handle_output_gcode(code) do string_code = FarmbotFirmware.GCODE.encode(code) should_log? = Asset.fbos_config().firmware_output_log should_log? && FarmbotCore.Logger.debug(3, "Firmware output: " <> string_code) end @impl FarmbotFirmware.SideEffects def handle_debug_message([message]) do fbos_config = Asset.fbos_config() should_log? = fbos_config.firmware_debug_log || fbos_config.arduino_debug_messages should_log? && FarmbotCore.Logger.debug(3, "Firmware debug message: " <> message) end @impl FarmbotFirmware.SideEffects def handle_configuration_status(status) do :ok = BotState.set_firmware_configured(status) DepTracker.register_service(:firmware, :configured) end @impl FarmbotFirmware.SideEffects def load_params do conf = Asset.firmware_config() known_params(conf) end def known_params(conf) do Map.take(conf, [ :param_e_stop_on_mov_err, :param_mov_nr_retry, :movement_timeout_x, :movement_timeout_y, :movement_timeout_z, :movement_keep_active_x, :movement_keep_active_y, :movement_keep_active_z, :movement_home_at_boot_x, :movement_home_at_boot_y, :movement_home_at_boot_z, :movement_invert_endpoints_x, :movement_invert_endpoints_y, :movement_invert_endpoints_z, :movement_enable_endpoints_x, :movement_enable_endpoints_y, :movement_enable_endpoints_z, :movement_invert_motor_x, :movement_invert_motor_y, :movement_invert_motor_z, :movement_secondary_motor_x, :movement_secondary_motor_invert_x, :movement_steps_acc_dec_x, :movement_steps_acc_dec_y, :movement_steps_acc_dec_z, :movement_stop_at_home_x, :movement_stop_at_home_y, :movement_stop_at_home_z, :movement_home_up_x, :movement_home_up_y, :movement_home_up_z, :movement_step_per_mm_x, :movement_step_per_mm_y, :movement_step_per_mm_z, :movement_min_spd_x, :movement_min_spd_y, :movement_min_spd_z, :movement_home_spd_x, :movement_home_spd_y, :movement_home_spd_z, :movement_max_spd_x, :movement_max_spd_y, :movement_max_spd_z, :movement_invert_2_endpoints_x, :movement_invert_2_endpoints_y, :movement_invert_2_endpoints_z, :movement_motor_current_x, :movement_motor_current_y, :movement_motor_current_z, :movement_stall_sensitivity_x, :movement_stall_sensitivity_y, :movement_stall_sensitivity_z, :movement_microsteps_x, :movement_microsteps_y, :movement_microsteps_z, :encoder_enabled_x, :encoder_enabled_y, :encoder_enabled_z, :encoder_type_x, :encoder_type_y, :encoder_type_z, :encoder_missed_steps_max_x, :encoder_missed_steps_max_y, :encoder_missed_steps_max_z, :encoder_scaling_x, :encoder_scaling_y, :encoder_scaling_z, :encoder_missed_steps_decay_x, :encoder_missed_steps_decay_y, :encoder_missed_steps_decay_z, :encoder_use_for_pos_x, :encoder_use_for_pos_y, :encoder_use_for_pos_z, :encoder_invert_x, :encoder_invert_y, :encoder_invert_z, :movement_axis_nr_steps_x, :movement_axis_nr_steps_y, :movement_axis_nr_steps_z, :movement_stop_at_max_x, :movement_stop_at_max_y, :movement_stop_at_max_z, :pin_guard_1_pin_nr, :pin_guard_1_time_out, :pin_guard_1_active_state, :pin_guard_2_pin_nr, :pin_guard_2_time_out, :pin_guard_2_active_state, :pin_guard_3_pin_nr, :pin_guard_3_time_out, :pin_guard_3_active_state, :pin_guard_4_pin_nr, :pin_guard_4_time_out, :pin_guard_4_active_state, :pin_guard_5_pin_nr, :pin_guard_5_time_out, :pin_guard_5_active_state ]) end end