I am developing a driver for a device communicating over half duplex uart. An example dataframe is shown below (request from pixhawk and respond from device). The problem is that pixhawk does not read the respond. In fact it reads it sometimes, rarely and randomly.
I have developed the following lua script which in the case of full duplex uart works perfectly (used an extra board to convert half to full duplex). My understanding is that due to the delay between request and respond, port:available() does not find any data and the script exits. How can I add a delay to synchronize it? Or maybe any other better ideas?
local port = serial:find_serial(0)
assert(port, 'No scripting serial port found!')
port:begin(1000000)
port:set_flow_control(0)
function update ()
port:write(0xFF)
port:write(0xFF)
port:write(0x01)
port:write(0x04)
port:write(0x02)
port:write(0x38)
port:write(0x02)
port:write(0xBE)
local n_bytes = port:available()
while n_bytes > 0 do
local byte = port:read()
gcs:send_text(0, 'received ' .. byte)
n_bytes = n_bytes - 1
end
gcs:send_text(0, "Exiting!")
return update, 1000
end
return update, 100
local SEND_INTERVAL_MS = 1000 -- how often to send a message
local POLL_INTERVAL_MS = 20 -- how fast to poll for a response
local TIMEOUT_MS = 100 -- how long to wait for a response
local MESSAGE = { 0xFF, 0xFF, 0x01, 0x04, 0x02, 0x38, 0x02, 0xBE }
local port = serial:find_serial(0)
assert(port, 'No scripting serial port found!')
port:begin(uint32_t(1000000))
port:set_flow_control(0)
local message_timeout = uint32_t(0)
local message_count = 0
local response_count = 0
local error_count = 0
function send_message ()
-- send all bytes in the message table
for _, b in ipairs(MESSAGE) do
port:write(b)
end
-- report number of messages sent
message_count = message_count + 1
gcs:send_named_float('SENT', message_count)
-- set a timeout for perihpheral response
message_timeout = millis() + TIMEOUT_MS
-- schedule the receiver function
return receive_message, POLL_INTERVAL_MS
end
function receive_message()
-- read all available bytes
local received = {}
while port:available() > 0 do
received[#received + 1] = port:read()
end
-- report packet size and response count upon receipt
if #received > 0 then
response_count = response_count + 1
gcs:send_named_float('RCVD', response_count)
gcs:send_named_float('BYTES', #received)
return send_message, SEND_INTERVAL_MS
end
-- check for timeout rather than polling forever
if millis() > message_timeout then
error_count = error_count + 1
gcs:send_named_float('ERRS', error_count)
return send_message, SEND_INTERVAL_MS
end
-- continue to poll for a response until timeout
return receive_message, POLL_INTERVAL_MS
end
return send_message, SEND_INTERVAL_MS
thanks for your response. I tried your script and works perfectly in the case of full duplex UART. Unfortunately with half duplex it does not. In fact it does not read any bytes though I can see them with a logic analyzer. This is exactly the situation I faced with my script. So i am thinking of the the following possible scenarios:
Wrong configuration for half duplex??
I have configured serialx_protocol = 28 and serialx_options = 4.
I tried serial port 1 to 4.
Voltage levels not enough for pixhawk 4??
The actual voltage is seen below and logic analyzer reads it correctly.
(2v/div)
by the way, is it possible to visualize in the Graph Log Tool the various named float variable of your script? I only can see just one. If not, is there any other way? Perhaps some tlog file parser?
The named float binding is a way for you to get a scripted value sent across the telemetry link. Anything that happens after that is up to the GCS software (Mission Planner, in this case).