WinWingFCUSync/fcuSync.py

329 lines
8.6 KiB
Python
Raw Permalink Normal View History

#! /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()