4cbf58f8dc
Signed-off-by: fly <merspieler@alwaysdata.net>
328 lines
8.6 KiB
Python
Executable file
328 lines
8.6 KiB
Python
Executable file
#! /usr/bin/env python3
|
|
|
|
from dataclasses import dataclass
|
|
import time
|
|
import os
|
|
import sys
|
|
import socket
|
|
|
|
from enum import Enum
|
|
|
|
import hid
|
|
|
|
hidraw_path = ""
|
|
for device in hid.enumerate():
|
|
if device["vendor_id"] == 0x4098 and device["product_id"] == 0xbb10:
|
|
hidraw_path = device["path"]
|
|
|
|
if hidraw_path == "":
|
|
print("Unable to find FCU device")
|
|
sys.exit(1)
|
|
|
|
class Leds(Enum):
|
|
BACKLIGHT = 0 # 0 .. 255
|
|
SCREEN_BACKLIGHT = 1 # 0 .. 255
|
|
LOC_GREEN = 3 # all on/off
|
|
AP1_GREEN = 5
|
|
AP2_GREEN = 7
|
|
ATHR_GREEN = 9
|
|
EXPED_GREEN = 11
|
|
APPR_GREEN = 13
|
|
FLAG_GREEN = 17 # 0 .. 255
|
|
EXPED_YELLOW = 30 # 0 .. 255
|
|
|
|
# A
|
|
# ---
|
|
# F | G | B
|
|
# ---
|
|
# E | | C
|
|
# ---
|
|
# D
|
|
# A=0x80, B=0x40, C=0x20, D=0x10, E=0x02, F=0x08, G=0x04
|
|
# Bits are valid for Speed display only, all other share bits in 2 databyte per lcd 7-segment display.
|
|
# Use function data_from_string_swapped to recalculate values
|
|
representations = {
|
|
'0' : 0xfa,
|
|
'1' : 0x60,
|
|
'2' : 0xd6,
|
|
'3' : 0xf4,
|
|
'4' : 0x6c,
|
|
'5' : 0xbc,
|
|
'6' : 0xbe,
|
|
'7' : 0xe0,
|
|
'8' : 0xfe,
|
|
'9' : 0xfc,
|
|
'A' : 0xee,
|
|
'B' : 0xfe,
|
|
'C' : 0x9a,
|
|
'D' : 0x76,
|
|
'E' : 0x9e,
|
|
'F' : 0x8e,
|
|
'G' : 0xbe,
|
|
'H' : 0x6e,
|
|
'I' : 0x60,
|
|
'J' : 0x70,
|
|
'K' : 0x0e,
|
|
'L' : 0x1a,
|
|
'M' : 0xa6,
|
|
'N' : 0x26,
|
|
'O' : 0xfa,
|
|
'P' : 0xce,
|
|
'Q' : 0xec,
|
|
'R' : 0x06,
|
|
'S' : 0xbc,
|
|
'T' : 0x1e,
|
|
'U' : 0x7a,
|
|
'V' : 0x32,
|
|
'W' : 0x58,
|
|
'X' : 0x6e,
|
|
'Y' : 0x7c,
|
|
'Z' : 0xd6,
|
|
'-' : 0x04,
|
|
'#' : 0x36,
|
|
'/' : 0x60,
|
|
'\\' : 0xa0,
|
|
' ' : 0x00,
|
|
}
|
|
|
|
class Byte(Enum):
|
|
H0 = 0
|
|
H3 = 1
|
|
A0 = 2
|
|
A1 = 3
|
|
A2 = 4
|
|
A3 = 5
|
|
A4 = 6
|
|
A5 = 7
|
|
V2 = 8
|
|
V3 = 9
|
|
V0 = 10
|
|
V1 = 11
|
|
S1 = 12
|
|
|
|
|
|
|
|
@dataclass
|
|
class Flag:
|
|
name : str
|
|
byte : Byte
|
|
mask : int
|
|
value : bool = False
|
|
|
|
|
|
flags = dict([("spd", Flag('spd-mach_spd', Byte.H3, 0x08, True)),
|
|
("mach", Flag('spd-mach_mach', Byte.H3, 0x04)),
|
|
("hdg", Flag('hdg-trk-lat_hdg', Byte.H0, 0x80)),
|
|
("trk", Flag('hdg-trk-lat_trk', Byte.H0, 0x40)),
|
|
("lat", Flag('hdg-trk-lat_lat', Byte.H0, 0x20, True)),
|
|
("vshdg", Flag('hdg-v/s_hdg', Byte.A5, 0x08, True)),
|
|
("vs", Flag('hdg-v/s_v/s', Byte.A5, 0x04, True)),
|
|
("ftrk", Flag('trk-fpa_trk', Byte.A5, 0x02)),
|
|
("ffpa", Flag('trk-fpa_fpa', Byte.A5, 0x01)),
|
|
("alt", Flag('alt', Byte.A4, 0x10, True)),
|
|
("hdg_managed", Flag('hdg managed', Byte.H0, 0x10)),
|
|
("spd_managed", Flag('spd managed', Byte.H3, 0x02)),
|
|
("alt_managed", Flag('alt_managed', Byte.V1, 0x10)),
|
|
("vs_horz", Flag('v/s plus horizontal', Byte.A0, 0x10, True)),
|
|
("vs_vert", Flag('v/s plus vertical', Byte.V2, 0x10)),
|
|
("lvl", Flag('lvl change', Byte.A2, 0x10, True)),
|
|
("lvl_left", Flag('lvl change left', Byte.A3, 0x10, True)),
|
|
("lvl_right", Flag('lvl change right', Byte.A1, 0x10, True)),
|
|
("fvs", Flag('v/s-fpa_v/s', Byte.V0, 0x40, True)),
|
|
("ffpa2", Flag('v/s-fpa_fpa', Byte.V0, 0x80)),
|
|
("fpa_comma", Flag('fpa_comma', Byte.V3, 0x10)),
|
|
("mach_comma", Flag('mach_comma', Byte.S1, 0x01)),
|
|
])
|
|
|
|
|
|
def swap_nibbles(x):
|
|
return ( (x & 0x0F)<<4 | (x & 0xF0)>>4 )
|
|
|
|
|
|
def winwing_fcu_set_led(led, brightness):
|
|
data = [0x02, 0x10, 0xbb, 0, 0, 3, 0x49, led.value, brightness, 0,0,0,0,0]
|
|
cmd = bytes(data)
|
|
send_data_to_hidraw(cmd)
|
|
|
|
|
|
def lcd_init():
|
|
data = [0xf0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] # init packet
|
|
cmd = bytes(data)
|
|
send_data_to_hidraw(cmd)
|
|
|
|
|
|
def data_from_string(num_7segments, string):
|
|
|
|
l = num_7segments
|
|
d = [0] * (l)
|
|
for i in range(min(l, len(string))):
|
|
r = representations.get(string.upper()[i])
|
|
if r == None:
|
|
r = 0xef
|
|
print("ERROR: char '{string.upper()[i]}' not found")
|
|
d[l-1-i] = r
|
|
return d
|
|
|
|
|
|
def data_from_string_swapped(num_7segments, string): # some 7-segemnts have wired mapping, correct ist here
|
|
# return array with one byte more than lcd chars
|
|
|
|
l = num_7segments
|
|
|
|
d = data_from_string(l, string)
|
|
d.append(0)
|
|
|
|
# fix wired segment mapping special elements such at the bars at the LVL/CH
|
|
for i in range(len(d)):
|
|
d[i] = swap_nibbles(d[i])
|
|
for i in range(0, len(d) - 1):
|
|
d[l-i] = (d[l-i] & 0x0f) | (d[l-1-i] & 0xf0)
|
|
d[l-1-i] = d[l-1-i] & 0x0f
|
|
|
|
return d
|
|
|
|
|
|
def winwing_fcu_lcd_set(speed, heading, alt,vs, new):
|
|
s = data_from_string( 3, str(speed))
|
|
h = data_from_string_swapped(3, str(heading))
|
|
a = data_from_string_swapped(5, str(alt))
|
|
v = data_from_string_swapped(4, str(vs))
|
|
|
|
bl = [0] * len(Byte)
|
|
for f in flags:
|
|
bl[flags[f].byte.value] |= (flags[f].mask * flags[f].value)
|
|
|
|
pkg_nr = 1
|
|
data = [0xf0, 0x0, pkg_nr, 0x31, 0x10, 0xbb, 0x0, 0x0, 0x2, 0x1, 0x0, 0x0, 0xff, 0xff, 0x2, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, s[2], s[1], s[0], h[3] | bl[Byte.H3.value], h[2], h[1], h[0] | bl[Byte.H0.value], a[5] | bl[Byte.A5.value], a[4] | bl[Byte.A4.value], a[3] | bl[Byte.A3.value], a[2] | bl[Byte.A2.value], a[1] | bl[Byte.A1.value], a[0] | v[4] | bl[Byte.A0.value], v[3] | bl[Byte.V3.value], v[2] | bl[Byte.V2.value], v[1] | bl[Byte.V1.value], v[0] | bl[Byte.V0.value], 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
|
|
cmd = bytes(data)
|
|
send_data_to_hidraw(cmd)
|
|
|
|
data = [0xf0, 0x0, pkg_nr, 0x11, 0x10, 0xbb, 0x0, 0x0, 0x3, 0x1, 0x0, 0x0, 0xff, 0xff, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
|
|
cmd = bytes(data)
|
|
send_data_to_hidraw(cmd)
|
|
|
|
def send_data_to_hidraw(data):
|
|
global hidraw_path
|
|
try:
|
|
# Open the HIDRAW device
|
|
hidraw = os.open(hidraw_path, os.O_RDWR | os.O_NONBLOCK)
|
|
|
|
# Write data to the HIDRAW device
|
|
os.write(hidraw, bytes(data))
|
|
|
|
# print("Data sent successfully to HIDRAW device.")
|
|
|
|
# Close the HIDRAW device
|
|
os.close(hidraw)
|
|
except Exception as e:
|
|
print("Error:", e)
|
|
|
|
|
|
lcd_init()
|
|
|
|
speed = 100
|
|
heading = 360
|
|
alt = 10000
|
|
vs = '----'
|
|
|
|
|
|
winwing_fcu_set_led(Leds.BACKLIGHT, 70)
|
|
winwing_fcu_set_led(Leds.EXPED_YELLOW, 70)
|
|
winwing_fcu_set_led(Leds.SCREEN_BACKLIGHT, 200)
|
|
winwing_fcu_lcd_set(speed, heading, alt, vs, 0x0)
|
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM | socket.SOCK_NONBLOCK)
|
|
s.bind(('', 12000))
|
|
try:
|
|
message = "d,100,360,10000,----,0.0,0.0,d"
|
|
while True:
|
|
time.sleep(0.1)
|
|
try:
|
|
while True:
|
|
message, address = s.recvfrom(1024)
|
|
except BlockingIOError:
|
|
pass
|
|
print(message)
|
|
items = str(message).split(",")
|
|
winwing_fcu_lcd_set(items[1], items[2], items[3], items[4], 0x0)
|
|
winwing_fcu_set_led(Leds.BACKLIGHT, int(float(items[5]) * 255))
|
|
winwing_fcu_set_led(Leds.EXPED_YELLOW, int(float(items[5]) * 255))
|
|
winwing_fcu_set_led(Leds.SCREEN_BACKLIGHT, int(float(items[6]) * 255))
|
|
|
|
if "spd" in items:
|
|
flags["spd"].value = True
|
|
else:
|
|
flags["spd"].value = False
|
|
if "mach" in items:
|
|
flags["mach"].value = True
|
|
flags["mach_comma"].value = True
|
|
else:
|
|
flags["mach"].value = False
|
|
flags["mach_comma"].value = False
|
|
if "spd-mgt" in items:
|
|
flags["spd_managed"].value = True
|
|
else:
|
|
flags["spd_managed"].value = False
|
|
|
|
if "lat" in items:
|
|
flags["lat"].value = True
|
|
flags["hdg_managed"].value = True
|
|
else:
|
|
flags["lat"].value = False
|
|
flags["hdg_managed"].value = False
|
|
|
|
if "hdg-vs" in items:
|
|
flags["hdg"].value = True
|
|
flags["vshdg"].value = True
|
|
flags["vs"].value = True
|
|
flags["fvs"].value = True
|
|
else:
|
|
flags["hdg"].value = False
|
|
flags["vshdg"].value = False
|
|
flags["vs"].value = False
|
|
flags["fvs"].value = False
|
|
if "trk-fpa" in items:
|
|
flags["trk"].value = True
|
|
flags["ftrk"].value = True
|
|
flags["ffpa"].value = True
|
|
flags["ffpa2"].value = True
|
|
if items[4] != "----":
|
|
flags["fpa_comma"].value = True
|
|
else:
|
|
flags["fpa_comma"].value = False
|
|
else:
|
|
flags["trk"].value = False
|
|
flags["ftrk"].value = False
|
|
flags["ffpa"].value = False
|
|
flags["ffpa2"].value = False
|
|
flags["fpa_comma"].value = False
|
|
|
|
if "plus" in items:
|
|
flags["vs_vert"].value = True
|
|
else:
|
|
flags["vs_vert"].value = False
|
|
|
|
if "ap1" in items:
|
|
winwing_fcu_set_led(Leds.AP1_GREEN, 1)
|
|
else:
|
|
winwing_fcu_set_led(Leds.AP1_GREEN, 0)
|
|
if "ap2" in items:
|
|
winwing_fcu_set_led(Leds.AP2_GREEN, 1)
|
|
else:
|
|
winwing_fcu_set_led(Leds.AP2_GREEN, 0)
|
|
if "athr" in items:
|
|
winwing_fcu_set_led(Leds.ATHR_GREEN, 1)
|
|
else:
|
|
winwing_fcu_set_led(Leds.ATHR_GREEN, 0)
|
|
if "loc" in items:
|
|
winwing_fcu_set_led(Leds.LOC_GREEN, 1)
|
|
else:
|
|
winwing_fcu_set_led(Leds.LOC_GREEN, 0)
|
|
if "appr" in items:
|
|
winwing_fcu_set_led(Leds.APPR_GREEN, 1)
|
|
else:
|
|
winwing_fcu_set_led(Leds.APPR_GREEN, 0)
|
|
|
|
|
|
except KeyboardInterrupt:
|
|
s.close()
|