lwgpio_protocol = Proto("LW-GPIO", "Livewire GPIO Protocol") rudp = ProtoField.uint32("lwgpio.rudp", "R/UDP Header", base.HEX) message = ProtoField.string("lwgpio.message", "Message ID") count = ProtoField.uint16("lwgpio.count", "Item Count") lcid = ProtoField.uint32("lwgpio.lcid", "Logic Circuit ID", base.HEX) lpid = ProtoField.uint16("lwgpio.lpid", "Logic Port ID") circuit = ProtoField.uint8("lwgpio.circuit", "GPIO Circuit number") attrib_read = ProtoField.uint8("lwgpio.attrib_read", "Circuit Read State", base.HEX) attrib_write = ProtoField.uint8("lwgpio.attrib_write", "Circuit Write State", base.HEX) supmsg = ProtoField.uint32("lwgpio.suppmsg", "Supplementary Message ID", base.HEX) supdata = ProtoField.uint16("lwgpio.supdata", "Supplementary Data", base.HEX) lwgpio_protocol.fields = { rudp, message, count, lpid, circuit, lcid, attrib_read, attrib_write, supmsg, supdata } function lwgpio_protocol.dissector(buffer, pinfo, tree) length = buffer:len() if length == 0 then return end pinfo.cols.protocol = lwgpio_protocol.name --extract items from buffer to show in Packet Details first line local msg_id = buffer(16,4):string() local msg_count = buffer(20,2):uint() local msg_lcid = buffer(22,4):uint() local msg_lpid = buffer(23,2):uint() local msg_circuit = buffer(25,1):uint() local msg_state = buffer(27,1):uint() local msg_description = get_msg_description(msg_id) local msg_lpid_ip_address = get_ip_from_lw(msg_lpid) local msg_circuit_number = get_cct_number(msg_circuit) local msg_gpio_ident = msg_lpid .. "." .. msg_circuit_number local msg_state_active = (bit.band(msg_state and 64))/64 local msg_ckt_state = get_ckt_state(msg_state) local msg_state_active_binary = "False" if msg_state_active == 1 then msg_state_active_binary = "True" end local msg_gpio_state = msg_gpio_ident .. "=" .. msg_state_active local summary ="Unknown Command" if msg_id == "READ" then summary = msg_id .. " " .. msg_gpio_ident .. "=?" .. ", " elseif msg_id == "WRNI" then summary = msg_id .. ", Livewire chan:" .. msg_lpid .. " GPO pin " .. msg_circuit_number .. " " .. msg_ckt_state elseif msg_id == "INDI" then summary = msg_id .. ", Livewire chan:" .. msg_lpid .. " GPI pin " .. msg_circuit_number .. " " .. msg_ckt_state end pinfo.cols.protocol = lwgpio_protocol.name pinfo.cols.info = summary local subtree = tree:add(lwgpio_protocol, buffer(), "Livewire GPIO Protocol Data, " .. summary) subtree:add(rudp, buffer(0,4)) subtree:add(message, buffer(16,4)):append_text(" [" .. msg_description .. "]") subtree:add(count, buffer(20,2)) subtree:add(lcid, buffer(22,4)):append_text(" [" .. msg_gpio_ident .. "]") subtree:add(lpid, buffer(23,2)):append_text(" [Corresponding to audio stream " .. msg_lpid_ip_address .. "]") subtree:add(circuit, buffer(25,1)):append_text(" [Corresponding to GPIO channel " .. msg_circuit_number .. "]") subtree:add(attrib_read, buffer(26,1)) subtree:add(attrib_write, buffer(27,1)) if msg_count == 1 then return end subtree:add(supmsg, buffer(28,4)) subtree:add(supdata, buffer(32,2)) end function get_msg_description(msg_id) local msg_result = "Unknown" if msg_id == "WRNI" then msg_result = "Write value - returning the value indication is not requested" elseif msg_id == "WRIN" then msg_result = "Write value - returning the value indication is requested" elseif msg_id == "READ" then msg_result = "Read value" elseif msg_id == "INDI" then msg_result = "Value indication" elseif msg_id == "STAT" then msg_result = "Status indication" elseif msg_id == "NEST" then msg_result = "No operation - container for nested messages" end return msg_result end function get_ckt_state(msg_state) local msg_result = msg_state .. " is undefined in script: get_ckt_state" if msg_state > 192 then msg_result = "Pulse Low for " .. (msg_state - 192)*10 .. " ms" elseif msg_state == 192 then msg_result = "Latch Low" elseif (192 > msg_state and msg_state > 128) then msg_result = "Pulse High for " .. (msg_state - 128)*10 .. " ms" elseif msg_state == 128 then msg_result = "Latch High" elseif (96 > msg_state and msg_state > 64) then msg_result = "Pulse Low for " .. (msg_state - 64)*250 .. " ms" elseif msg_state == 64 then msg_result = "Pulse Low for 250ms" elseif (32 > msg_state and msg_state > 1) then msg_result = "Pulse High for " .. (msg_state)*250 .. " ms" elseif msg_state == 1 then msg_result = "Pin Low" -- this only covers GPI states and not GPO **TBD elseif msg_state == 0 then msg_result = "Pin High" -- this only covers GPI states and not GPO **TBD end return msg_result end function get_lcid_display(msg_lcid) local result = "Unknown" local lpid_ip_address = math.floor(msg_lcid / 256) local lpid_circuit = msg_lcid % 256 local gpio_seq = 0 if lpid_circuit < 9 then result = lpid_ip_address .. "." .. 9-lpid_circuit .. " = " .. msg_state_active else result = lpid_ip_address .. "." .. 14-lpid_circuit .. " = " .. msg_state_active end return result end function get_ip_from_lw(msg_lpid) local result = "239.192." .. math.floor(msg_lpid/256) .. "." .. msg_lpid%256 return result end function get_cct_number(msg_circuit) local result = "Unknown" if msg_circuit < 9 then result = 9-msg_circuit else result = 14-msg_circuit end return result end local udp_port = DissectorTable.get("udp.port") udp_port:add(2055, lwgpio_protocol) udp_port:add(2060, lwgpio_protocol) --[[ R/UDP header (Bytes 1-4 = 0x03000207, ignore Bytes 5-16) Message ID (four Bytes - WRNI,WRIN,READ,INDI,STAT,NEST) Item Count (two Bytes) LCID (Logic Circuit ID) - Byte 1 = 0 - Byte 2,3 = LPID (Logic Port ID = Livewire Channel) - Byte 4 = GPIO Circuit - GPO has values 4-8 - subtract from 9 for GPO circuit number - GPI has values 9-13 - subtract from 14 for GPI circuit number Attribute - Read (ignore?) Attribute - Write - ]]