--[[
   Pelco-D control implementation for antennatracker.
   Implemented by using knowledge from the excellent python implementation in https://gist.github.com/jn0/cc5c78f4a0f447a6fb2e45a5d9efa13d.
--]]

local SERVO_PAN = 71
local SERVO_TILT = 72
local SERIAL_BAUD = 9600

-- Antennattracker modes
local MODE_STOP = 1
local MODE_SCAN = 2
local MODE_SERVOTEST = 3
local MODE_GUIDED = 4

gcs:send_text(0, "Starting Pelco-D Control")

local port = assert(serial:find_serial(0), "Pelco-D: No Scripting Serial Port")
port:begin(SERIAL_BAUD)
port:set_flow_control(0)

function set_bit(value, n)
  return value | (0x01 << n)
end

function PelcoD_msg_addchecksum(msg)
  local sum = 0
  for i = 2, #msg-1 do
      sum = sum + msg[i]
  end
  checksum =  sum % 256
  msg[7] = checksum
end

function PelcoD_move(panspeed, tiltspeed)
  local command = 0x00
  local scale = 63 -- max pelcod speed
  if panspeed < 0 then -- left
      command = set_bit(command, 2)
  elseif panspeed > 0 then -- right
      command = set_bit(command, 1)
  end
  if tiltspeed < 0 then -- down
      command = set_bit(command, 4)
  elseif tiltspeed > 0 then -- up
      command = set_bit(command, 3)
  end
  local msg = {0xFF, 0x01, 0x00, command, math.floor(math.abs(panspeed) * scale), math.floor(math.abs(tiltspeed) * scale), 0x00}
  PelcoD_msg_addchecksum(msg)
  return msg
end

-- write msg to the serial port
function send_message(msg)
  for _, v in ipairs(msg) do
    port:write(v)
  end
end

function update()
  tilt_norm = SRV_Channels:get_output_scaled(SERVO_TILT)
  pan_norm = SRV_Channels:get_output_scaled(SERVO_PAN)
  if (vehicle:get_mode() == MODE_SCAN or vehicle:get_mode() == MODE_SERVOTEST or vehicle:get_mode() == MODE_GUIDED) then
    -- Limit pan and tilt to -1...+1
    pan_norm=math.max(pan_norm,-1.0)
    pan_norm=math.min(pan_norm,1.0)
    tilt_norm=math.max(tilt_norm,-1.0)
    tilt_norm=math.min(tilt_norm,1.0)
    local msg=PelcoD_move(-pan_norm,tilt_norm)
    send_message(msg)
  elseif (vehicle:get_mode() == MODE_STOP) then
    local msg=PelcoD_move(0,0)
    send_message(msg)
  end

  return update, 20 -- 50 hz
end

PelcoD_move(0,0)
return update()


--[[
function PelcoD_pan_absolute_position(degrees)
  centidegrees = degrees*100
  local msg = {0xFF, 0x01, 0x00, 0x4b, (centidegrees >> 8) & 255 , centidegrees & 255, 0x00}
  PelcoD_msg_addchecksum(msg)
  return msg
end

function PelcoD_tilt_absolute_position(degrees)
  centidegrees = degrees*100
  local msg = {0xFF, 0x01, 0x00, 0x4d, (centidegrees >> 8) & 255 , centidegrees & 255, 0x00}
  PelcoD_msg_addchecksum(msg)
  return msg
end

function PelcoD_zoom_absolute_position(position)
  local msg = {0xFF, 0x01, 0x00, 0x4f, (position >> 8) & 255 , position & 255, 0x00}
  PelcoD_msg_addchecksum(msg)
  return msg
end

function PelcoD_zero_absolute_position(degrees)
  centidegrees = degrees*100
  local msg = {0xFF, 0x01, 0x00, 0x49, 0x00, 0x00, 0x00}
  PelcoD_msg_addchecksum(msg)
  return msg
end
--]]
