Sync edgetx to Gitea
This commit is contained in:
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import glob
|
||||
|
||||
|
||||
def addLine(filename, newline, after):
|
||||
print(filename, newline)
|
||||
with open(filename, 'r') as f:
|
||||
lines = f.readlines()
|
||||
for i, line in enumerate(lines):
|
||||
if after in line:
|
||||
lines.insert(i + 1, newline + '\n')
|
||||
break
|
||||
with open(filename, 'w') as f:
|
||||
f.writelines(lines)
|
||||
|
||||
|
||||
def modifyTranslations(constant, translation, after):
|
||||
for filename in glob.glob('translations/*.h'):
|
||||
newline = "#define " + constant + " " * max(1, 31 - len(constant)) + '"' + translation + '"'
|
||||
addLine(filename, newline, after + " ")
|
||||
|
||||
|
||||
def modifyDeclaration(constant, after):
|
||||
newline = "extern const char S" + constant + "[];"
|
||||
filename = "translations.h"
|
||||
addLine(filename, newline, after + "[];")
|
||||
|
||||
|
||||
def modifyDefinition(constant, after):
|
||||
newline = "const char S" + constant + "[] = " + constant + ";"
|
||||
filename = "translations.cpp"
|
||||
addLine(filename, newline, after + "[] ")
|
||||
|
||||
|
||||
after = sys.argv[-1]
|
||||
for arg in sys.argv[1:-1]:
|
||||
constant, translation = arg.split("=")
|
||||
modifyTranslations(constant, translation, after)
|
||||
modifyDeclaration(constant, after)
|
||||
modifyDefinition(constant, after)
|
||||
after = constant
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import division
|
||||
import sys
|
||||
|
||||
filename = sys.argv[1]
|
||||
fileout = sys.argv[2]
|
||||
|
||||
# Read entire file
|
||||
with open(filename, "rb") as fr:
|
||||
sts = fr.read()
|
||||
|
||||
# Parse into chunks of 16 bytes
|
||||
sts = [sts[i:i+16] for i in range(0, len(sts), 16)]
|
||||
|
||||
with open(fileout, "w") as fw:
|
||||
for st in sts:
|
||||
for b in st:
|
||||
fw.write("0x%02x," % (ord(b) if isinstance(b, str) else b))
|
||||
fw.write("\n")
|
||||
fw.write("\n")
|
||||
Executable
+291
@@ -0,0 +1,291 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
|
||||
from fwoptions import *
|
||||
|
||||
# Error codes
|
||||
FIRMWARE_SIZE_TOO_BIG = 1
|
||||
COMPILATION_ERROR = 4
|
||||
INVALID_FIRMWARE = 5
|
||||
INVALID_BOARD = 6
|
||||
INVALID_LANGUAGE = 7
|
||||
|
||||
|
||||
def build_target(target, path, cmake_options):
|
||||
srcdir = os.path.dirname(os.path.realpath(__file__)) + "/../.."
|
||||
outpath = path + ".out"
|
||||
errpath = path + ".err"
|
||||
|
||||
# Launch CMake
|
||||
cmd = ["cmake"]
|
||||
for option, value in cmake_options.items():
|
||||
cmd.append("-D%s=%s" % (option, value))
|
||||
if "EDGETX_VERSION_SUFFIX" in os.environ:
|
||||
suffix = os.environ["EDGETX_VERSION_SUFFIX"]
|
||||
cmd.append('-DVERSION_SUFFIX="%s"' % suffix)
|
||||
# if not suffix.startswith("rel"):
|
||||
# cmd.append('-DTEST_BUILD_WARNING=YES')
|
||||
cmd.append(srcdir)
|
||||
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output, error = proc.communicate()
|
||||
if proc.returncode == 0:
|
||||
open(outpath, "a").write("\n".join(cmd) + output.decode("utf-8") + error.decode("utf-8"))
|
||||
else:
|
||||
open(errpath, "w").write(output.decode("utf-8") + error.decode("utf-8"))
|
||||
return COMPILATION_ERROR
|
||||
|
||||
# Launch make
|
||||
cmd = ["make", "-j3", target]
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output, error = proc.communicate()
|
||||
if proc.returncode == 0:
|
||||
open(outpath, "a").write(output.decode("utf-8") + error.decode("utf-8"))
|
||||
else:
|
||||
open(errpath, "w").write(output.decode("utf-8") + error.decode("utf-8"))
|
||||
return COMPILATION_ERROR
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
return INVALID_FIRMWARE
|
||||
|
||||
target = sys.argv[1]
|
||||
directory, filename = os.path.split(sys.argv[2])
|
||||
root, ext = os.path.splitext(filename)
|
||||
options = root.split("-")
|
||||
|
||||
if len(options) < 2 or options[0] != "opentx":
|
||||
return INVALID_FIRMWARE
|
||||
|
||||
optcount = 1
|
||||
cmake_options = {}
|
||||
board_name = options[optcount]
|
||||
|
||||
if board_name == "x9lite":
|
||||
cmake_options["PCB"] = "X9LITE"
|
||||
firmware_options = options_taranis_x9lite
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "x9lites":
|
||||
cmake_options["PCB"] = "X9LITES"
|
||||
firmware_options = options_taranis_x9lite
|
||||
maxsize = 65536 * 8
|
||||
elif options[optcount] == "x7":
|
||||
cmake_options["PCB"] = "X7"
|
||||
firmware_options = options_taranis_x7
|
||||
maxsize = 65536 * 8
|
||||
elif options[optcount] == "x7access":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "ACCESS"
|
||||
firmware_options = options_taranis_x7
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "xlite":
|
||||
cmake_options["PCB"] = "XLITE"
|
||||
firmware_options = options_taranis_xlite
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "xlites":
|
||||
cmake_options["PCB"] = "XLITES"
|
||||
firmware_options = options_taranis_xlites
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "x9d":
|
||||
cmake_options["PCB"] = "X9D"
|
||||
firmware_options = options_taranis_x9d
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "x9d+":
|
||||
cmake_options["PCB"] = "X9D+"
|
||||
firmware_options = options_taranis_x9dp
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "x9d+2019":
|
||||
cmake_options["PCB"] = "X9D+"
|
||||
cmake_options["PCBREV"] = "2019"
|
||||
firmware_options = options_taranis_x9dp
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "x9e":
|
||||
cmake_options["PCB"] = "X9E"
|
||||
firmware_options = options_taranis_x9e
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "x10":
|
||||
cmake_options["PCB"] = "X10"
|
||||
firmware_options = options_horus_x10
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "x10express":
|
||||
cmake_options["PCB"] = "X10"
|
||||
cmake_options["PCBREV"] = "EXPRESS"
|
||||
firmware_options = options_horus_x10
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "x12s":
|
||||
cmake_options["PCB"] = "X12S"
|
||||
firmware_options = options_horus_x12s
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "lr3pro":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "LR3PRO"
|
||||
firmware_options = options_betafpv_lr3pro
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "tlite":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "TLITE"
|
||||
firmware_options = options_jumper_tlite
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "t12":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "T12"
|
||||
firmware_options = options_jumper_t12
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "tx12":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "TX12"
|
||||
firmware_options = options_radiomaster_tx12
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "zorro":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "ZORRO"
|
||||
firmware_options = options_radiomaster_zorro
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "boxer":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "BOXER"
|
||||
firmware_options = options_radiomaster_boxer
|
||||
maxsize = 65536 * 8 * 2
|
||||
elif board_name == "pocket":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "POCKET"
|
||||
firmware_options = options_radiomaster_pocket
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "mt12":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "MT12"
|
||||
firmware_options = options_radiomaster_mt12
|
||||
maxsize = 65536 * 8 * 2
|
||||
elif board_name == "gx12":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "GX12"
|
||||
firmware_options = options_radiomaster_gx12
|
||||
maxsize = 65536 * 8 * 2
|
||||
elif board_name == "t8":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "T8"
|
||||
firmware_options = options_radiomaster_t8
|
||||
maxsize = 65536 * 8
|
||||
elif board_name == "t15":
|
||||
cmake_options["PCB"] = "X10"
|
||||
cmake_options["PCBREV"] = "T15"
|
||||
firmware_options = options_jumper_t16
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "t16":
|
||||
cmake_options["PCB"] = "X10"
|
||||
cmake_options["PCBREV"] = "T16"
|
||||
firmware_options = options_jumper_t16
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "t18":
|
||||
cmake_options["PCB"] = "X10"
|
||||
cmake_options["PCBREV"] = "T18"
|
||||
firmware_options = options_jumper_t18
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "tx16s":
|
||||
cmake_options["PCB"] = "X10"
|
||||
cmake_options["PCBREV"] = "TX16S"
|
||||
firmware_options = options_radiomaster_tx16s
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "f16":
|
||||
cmake_options["PCB"] = "X10"
|
||||
cmake_options["PCBREV"] = "F16"
|
||||
firmware_options = options_fatfish_f16
|
||||
maxsize = 2 * 1024 * 1024
|
||||
elif board_name == "v12":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "V12"
|
||||
firmware_options = options_helloradiosky_v12
|
||||
maxsize = 65536 * 8 * 2
|
||||
elif board_name == "v14":
|
||||
cmake_options["PCB"] = "X7"
|
||||
cmake_options["PCBREV"] = "V14"
|
||||
firmware_options = options_helloradiosky_v14
|
||||
maxsize = 65536 * 8 * 2
|
||||
elif board_name == "v16":
|
||||
cmake_options["PCB"] = "X10"
|
||||
cmake_options["PCBREV"] = "V16"
|
||||
firmware_options = options_helloradiosky_v16
|
||||
maxsize = 2 * 1024 * 1024
|
||||
else:
|
||||
return INVALID_BOARD
|
||||
|
||||
if target == "firmware":
|
||||
binary = "firmware.bin"
|
||||
ext = ".bin"
|
||||
filename = "opentx"
|
||||
else:
|
||||
return INVALID_BOARD
|
||||
|
||||
filename += "-" + board_name
|
||||
optcount += 1
|
||||
|
||||
# The firmware options
|
||||
for opt, values in firmware_options.items():
|
||||
found = False
|
||||
for i in range(optcount, len(options)):
|
||||
if options[i] == opt:
|
||||
found = True
|
||||
break
|
||||
|
||||
if not isinstance(values, list):
|
||||
values = [values]
|
||||
|
||||
for name, value1, value2 in values:
|
||||
if found:
|
||||
value = value1
|
||||
filename += "-" + opt
|
||||
else:
|
||||
value = value2
|
||||
|
||||
if value is not None:
|
||||
cmake_options[name] = value
|
||||
|
||||
# The firmware display language
|
||||
language = ""
|
||||
for key in languages:
|
||||
if key == options[-1]:
|
||||
language = key
|
||||
if not language:
|
||||
return INVALID_LANGUAGE
|
||||
cmake_options["TRANSLATIONS"] = language.upper()
|
||||
|
||||
filename += "-" + language + ext
|
||||
path = os.path.join(directory, filename)
|
||||
errpath = path + ".err"
|
||||
|
||||
if os.path.isfile(errpath):
|
||||
print(filename)
|
||||
return COMPILATION_ERROR
|
||||
|
||||
if os.path.isfile(path):
|
||||
print(filename)
|
||||
return 0
|
||||
|
||||
result = build_target(target, path, cmake_options)
|
||||
if result != 0:
|
||||
print(filename)
|
||||
return result
|
||||
|
||||
if target == "firmware":
|
||||
# Check binary size
|
||||
size = os.stat(binary).st_size
|
||||
if size > maxsize:
|
||||
return FIRMWARE_SIZE_TOO_BIG
|
||||
|
||||
# Copy binary to the binaries directory
|
||||
shutil.move(binary, path)
|
||||
|
||||
print(filename)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
for f in glob.glob("*.bmp") + glob.glob("*.BMP"):
|
||||
t = f.title()
|
||||
if f != t:
|
||||
os.rename(f, t)
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
#!/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
SIGN_BIT = (0x80) # Sign bit for a A-law byte.
|
||||
QUANT_MASK = (0xf) # Quantization field mask.
|
||||
SEG_SHIFT = (4) # Left shift for segment number.
|
||||
SEG_MASK = (0x70) # Segment field mask.
|
||||
BIAS = (0x84) # Bias for linear code.
|
||||
|
||||
|
||||
def alaw2linear(a_val):
|
||||
a_val ^= 0x55
|
||||
|
||||
t = a_val & QUANT_MASK
|
||||
seg = (a_val & SEG_MASK) >> SEG_SHIFT
|
||||
if (seg):
|
||||
t = (t + t + 1 + 32) << (seg + 2)
|
||||
else:
|
||||
t = (t + t + 1) << 3
|
||||
|
||||
if a_val & SIGN_BIT:
|
||||
return t
|
||||
else:
|
||||
return -t
|
||||
|
||||
|
||||
def ulaw2linear(u_val):
|
||||
# Complement to obtain normal u-law value.
|
||||
u_val = ~u_val
|
||||
|
||||
# Extract and bias the quantization bits. Then
|
||||
# shift up by the segment number and subtract out the bias.
|
||||
t = ((u_val & QUANT_MASK) << 3) + BIAS
|
||||
t <<= (u_val & SEG_MASK) >> SEG_SHIFT
|
||||
|
||||
if u_val & SIGN_BIT:
|
||||
return (BIAS - t)
|
||||
else:
|
||||
return (t - BIAS)
|
||||
|
||||
|
||||
def pcmTable(fn):
|
||||
result = []
|
||||
for i in range(256):
|
||||
result.append(fn(i))
|
||||
return result
|
||||
|
||||
|
||||
def tableToString(name, table):
|
||||
result = 'const int16_t ' + name + '[256] = { '
|
||||
result += ', '.join(str(i) for i in table)
|
||||
result += ' };'
|
||||
return result
|
||||
|
||||
|
||||
print(tableToString('alawTable', pcmTable(alaw2linear)))
|
||||
print(tableToString('ulawTable', pcmTable(ulaw2linear)))
|
||||
Executable
+403
@@ -0,0 +1,403 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This program parses CRSF capture data
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
import sys, struct
|
||||
import math
|
||||
import argparse
|
||||
|
||||
lineNumber = 0
|
||||
timeData = 0
|
||||
prevTimeData = 0
|
||||
|
||||
crossfire_types = [
|
||||
"UINT8",
|
||||
"INT8",
|
||||
"UINT16",
|
||||
"INT16",
|
||||
"UINT32",
|
||||
"INT32",
|
||||
"UINT64",
|
||||
"INT64",
|
||||
"FLOAT",
|
||||
"TEXT_SELECTION",
|
||||
"STRING",
|
||||
"FOLDER",
|
||||
"INFO",
|
||||
"COMMAND",
|
||||
"VTX",
|
||||
]
|
||||
|
||||
cmd_status = [
|
||||
"READY",
|
||||
"START",
|
||||
"PROGRESS",
|
||||
"CONFIRMATION_NEEDED",
|
||||
"CONFIRM",
|
||||
"CANCEL",
|
||||
"POLL",
|
||||
]
|
||||
|
||||
|
||||
def dump(data, maxLen=None):
|
||||
if maxLen and len(data) > maxLen:
|
||||
data = data[:maxLen]
|
||||
return " ".join("{:02x}".format(c) for c in data)
|
||||
|
||||
|
||||
# CRC8 implementation with polynom = x^8+x^7+x^6+x^4+x^2+1 (0xD5)
|
||||
crc8tab = [
|
||||
0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
|
||||
0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
|
||||
0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
|
||||
0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
|
||||
0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
|
||||
0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
|
||||
0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
|
||||
0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
|
||||
0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
|
||||
0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
|
||||
0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
|
||||
0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
|
||||
0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
|
||||
0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
|
||||
0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
|
||||
0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
|
||||
0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
|
||||
0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
|
||||
0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
|
||||
0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
|
||||
0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
|
||||
0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
|
||||
0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
|
||||
0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
|
||||
0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
|
||||
0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
|
||||
0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
|
||||
0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
|
||||
0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
|
||||
0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
|
||||
0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
|
||||
0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
|
||||
]
|
||||
|
||||
def crc8(buffer):
|
||||
crc = 0
|
||||
for c in buffer:
|
||||
crc = crc8tab[crc ^ c]
|
||||
return crc
|
||||
|
||||
def ParseGPS(payload):
|
||||
lat, long, speed, head, alt, numsat = struct.unpack('>iiHHHB', bytes(bytearray(payload))) # bytes(bytearray) casting is required for python 2.7.3 compatibility
|
||||
return "[GPS] lat:%f long:%f speed:%d heading:%d alt:%d numsat:%d" % (lat / 1e7, long / 1e7, speed / 100, head / 100, alt - 1000, numsat)
|
||||
|
||||
def ParseBattery(payload):
|
||||
voltage = float((payload[0] << 8) + payload[1]) / 10
|
||||
current = float((payload[2] << 8) + payload[3]) / 10
|
||||
consumption = (payload[4] << 16) + (payload[5] << 8) + payload[6]
|
||||
return "[Battery] %.1fV %.1fA %dmAh" % (voltage, current, consumption)
|
||||
|
||||
def ParseBaroAltVario(payload):
|
||||
alt_packed = (payload[0] << 8) + payload[1]
|
||||
altitude = float(alt_packed & 0x7fff) if (alt_packed & 0x8000) else (float(alt_packed - 10000) / 10)
|
||||
if len(payload) == 3:
|
||||
# per CRSF spec
|
||||
vario_packed = float(payload[2])
|
||||
vario = (math.exp(abs(vario_packed) * 0.026) - 1) * 100 * math.copysign(1, vario_packed)
|
||||
else:
|
||||
# ELRS and Rotorflight
|
||||
vario = float(struct.unpack('>h', bytes(payload[2:4]))[0] / 100)
|
||||
|
||||
return "[Baro Altitude Vario] Altitude %.1f m, Vertical Speed %.2f m/s" % (altitude, vario)
|
||||
|
||||
def ParseVtxTelem(payload):
|
||||
return "[VTX Telemetry] freq=%d, power=%d, pitmode=%d" % (int.from_bytes(payload[1:3], 'big'), int(payload[3]), int(payload[4]))
|
||||
|
||||
def ParseLinkStatistics(payload):
|
||||
return "[Link Statistics] "
|
||||
|
||||
def ParseChannels(payload):
|
||||
return "[Channel Data] "
|
||||
|
||||
def ParseAttitude(payload):
|
||||
pitch = float((payload[0] << 8) + payload[1]) / 1000
|
||||
roll = float((payload[2] << 8) + payload[3]) / 1000
|
||||
yaw = float((payload[4] << 8) + payload[5]) / 1000
|
||||
return "[Attitude] pitch=%.3f roll=%.3f yaw=%.3f" % (pitch, roll, yaw)
|
||||
|
||||
def ParseFlightMode(payload):
|
||||
return '[Flight Mode] "%s"' % "".join([chr(c) for c in payload[:-1]])
|
||||
|
||||
def ParsePingDevices(_):
|
||||
return '[Ping Devices]'
|
||||
|
||||
def ParseDevice(payload):
|
||||
return '[Device] 0x%02x "%s" %d parameters' % (payload[1], "".join([chr(c) for c in payload[2:-14]]), payload[-2])
|
||||
|
||||
def ParseRadioId(payload):
|
||||
return '[RadioId] subcmd 0x%02x, interval %d, correction %d' % \
|
||||
(payload[2], int.from_bytes(payload[3:7], 'big')/10, int.from_bytes(payload[7:11], 'big', signed=True)/10)
|
||||
|
||||
def ParseLinkStatisticsRX(payload):
|
||||
return "[RX Link Stats] rssi=%d dBm rssi=%d%% lqi=%d snr=%d dB rf_power=%d dBm" % (payload[0], payload[1], payload[2], payload[3], payload[4])
|
||||
|
||||
def ParseCommand(payload):
|
||||
if payload[2]==0x10 and payload[3]==5:
|
||||
return '[Command] subcmd Crossfire, set ModelId, data %d' % (payload[4])
|
||||
if payload[2]==0x0a and payload[3]==0x70:
|
||||
return '[Command] subcmd General, Speed Proposal, port_id %d, bitrate %d' % (payload[4], int.from_bytes(payload[5:9], 'big'))
|
||||
if payload[2]==0x0a and payload[3]==0x71:
|
||||
return '[Command] subcmd General, Speed Response, port_id %d, %s' % (payload[4], 'accepted' if payload[5] else 'rejected')
|
||||
return '[Command] subcmd 0x%02x, datatype 0x%02x, data %d' % \
|
||||
(payload[2], payload[3], payload[4])
|
||||
|
||||
def ParseFieldsRequest(payload):
|
||||
return '[Fields request]'
|
||||
|
||||
lastChunkRequested = 0
|
||||
chunkOutOfOrder = False
|
||||
def ParseFieldRequest(payload):
|
||||
global lastChunkRequested, chunkOutOfOrder
|
||||
s = '[Field request] device=0x%02x field=%d chunk=%d' % (payload[1], payload[2], payload[3])
|
||||
if lastChunkRequested > 0 and payload[3] != lastChunkRequested+1:
|
||||
s += ' (OUT OF ORDER REQUEST!)'
|
||||
chunkOutOfOrder = True
|
||||
lastChunkRequested = payload[3]
|
||||
return s
|
||||
|
||||
def ParseFieldUpdate(payload):
|
||||
return '[Field update] device=0x%02x field=%d value=%s' % (payload[1], payload[2], ' '.join(f'{byte:02x}' for byte in payload[3:]))
|
||||
|
||||
def ParseELRSInfo(payload):
|
||||
return '[ELRS info] device=0x%02x bad=%d, good=%d, flags=0x%02x, flag_str=%s' % (payload[1], payload[2],
|
||||
int.from_bytes(payload[3:5], 'big'), payload[5], ''.join(map(chr, payload[6:-2])))
|
||||
|
||||
fieldBuff = []
|
||||
lastChunk = 0
|
||||
def ParseField(payload):
|
||||
global fieldBuff, lastChunk, lastChunkRequested, chunkOutOfOrder
|
||||
|
||||
fieldBuff += payload[4:]
|
||||
if lastChunk > 0 and payload[3] != lastChunk-1:
|
||||
s = '[Field] device=0x%02x field=%d chunk=%d (OUT OF ORDER CHUNK!)' % (payload[1], payload[2], payload[3])
|
||||
lastChunk = 0
|
||||
fieldBuff = []
|
||||
return s
|
||||
if payload[3] != 0:
|
||||
lastChunk = payload[3]
|
||||
return '[Field] device=0x%02x field=%d chunk=%d' % (payload[1], payload[2], payload[3])
|
||||
|
||||
print("fieldBuff: ", " ".join(f'{byte:02x}' for byte in fieldBuff))
|
||||
name = ""
|
||||
options = []
|
||||
i = 2
|
||||
try:
|
||||
while fieldBuff[i] != 0:
|
||||
name += chr(fieldBuff[i])
|
||||
i += 1
|
||||
i += 1
|
||||
ftype = crossfire_types[fieldBuff[1] & 0x7f]
|
||||
retstr = '[Field] %s device=0x%02x field=%d parent=%d type=%s' % (name, payload[1], payload[2], fieldBuff[0], ftype)
|
||||
if ftype == "TEXT_SELECTION":
|
||||
name = ""
|
||||
while fieldBuff[i] != 0:
|
||||
if fieldBuff[i] == 0x3b:
|
||||
options.append(name)
|
||||
name = ""
|
||||
i += 1
|
||||
continue
|
||||
name += chr(fieldBuff[i])
|
||||
i += 1
|
||||
options.append(name)
|
||||
i += 1
|
||||
retstr += ' selection=(%d) %s' % (fieldBuff[i], options[fieldBuff[i]])
|
||||
retstr += ' options %s' % (", ".join(options))
|
||||
if ftype == "INFO":
|
||||
value = ""
|
||||
while fieldBuff[i] != 0:
|
||||
value += chr(fieldBuff[i])
|
||||
i += 1
|
||||
retstr += ' name=%s value=%s' % (name, value)
|
||||
if ftype == "COMMAND":
|
||||
retstr += ' status=%s, timeout=%d ms, info=%s' % (cmd_status[fieldBuff[i]], fieldBuff[i+1], ''.join(map(chr, fieldBuff[i+2:])))
|
||||
fieldBuff = []
|
||||
lastChunk = 0
|
||||
lastChunkRequested = 0
|
||||
return retstr
|
||||
except Exception as inst:
|
||||
print(type(inst)) # the exception instance
|
||||
print(inst.args) # arguments stored in .args
|
||||
print(inst) # __str__ allows args to be printed directly,
|
||||
#... # but may be overridden in exception subclasses
|
||||
print("i: ", i)
|
||||
print("len(payload): ", len(payload))
|
||||
if i < len(payload):
|
||||
print("payload[i-1]: ", payload[i-1])
|
||||
fieldBuff = []
|
||||
lastChunk = 0
|
||||
return '[Exception]'
|
||||
|
||||
parsers = {
|
||||
0x02: ParseGPS,
|
||||
0x08: ParseBattery,
|
||||
0x09: ParseBaroAltVario,
|
||||
0x10: ParseVtxTelem,
|
||||
0x14: ParseLinkStatistics,
|
||||
0x16: ParseChannels,
|
||||
0x1c: ParseLinkStatisticsRX,
|
||||
0x1E: ParseAttitude,
|
||||
0x21: ParseFlightMode,
|
||||
0x28: ParsePingDevices,
|
||||
0x29: ParseDevice,
|
||||
0x2a: ParseFieldsRequest,
|
||||
0x2b: ParseField,
|
||||
0x2c: ParseFieldRequest,
|
||||
0x2d: ParseFieldUpdate,
|
||||
0x2e: ParseELRSInfo,
|
||||
0x32: ParseCommand,
|
||||
0x3a: ParseRadioId,
|
||||
}
|
||||
|
||||
def ParsePacket(packet):
|
||||
global timeData, prevTimeData, fieldBuff
|
||||
length = packet[1]
|
||||
command = packet[2]
|
||||
payload = packet[3:-1]
|
||||
crc = packet[-1]
|
||||
diffTime = timeData - prevTimeData
|
||||
prefix = '(%d)' % lineNumber if timeData == 0 else '%10.6f [%9.6f]' % (timeData, diffTime)
|
||||
prevTimeData = timeData
|
||||
timeData = 0
|
||||
if crc != crc8(packet[2:-1]):
|
||||
print(prefix, dump(packet), "[CRC error]")
|
||||
fieldBuff = []
|
||||
lastChunk = 0
|
||||
return
|
||||
if args.ignore and command == 0x16:
|
||||
return
|
||||
if args.omit and ((command == 0x2d and payload[2] == 0x00) or \
|
||||
command == 0x2e):
|
||||
return
|
||||
if args.remove and command == 0x3a:
|
||||
return
|
||||
parser = parsers.get(command, None)
|
||||
if parser != None:
|
||||
print(prefix, dump(packet), parser(payload))
|
||||
else:
|
||||
print(prefix, dump(packet), '[Unknown Command 0x%0x]' % command)
|
||||
|
||||
crossfireDataBuff = []
|
||||
chunkedBuffer = []
|
||||
def ParseData(data):
|
||||
global crossfireDataBuff
|
||||
crossfireDataBuff += data
|
||||
# build packet for parsing
|
||||
# separate buffers for data sources so chunked data handled correctly
|
||||
while len(crossfireDataBuff) > 1:
|
||||
if crossfireDataBuff[0] != 0xc8 and crossfireDataBuff[0] != 0x00 and crossfireDataBuff[0] != 0xee and crossfireDataBuff[0] != 0xea:
|
||||
print("Skipped 1 byte", dump(crossfireDataBuff[:1]))
|
||||
crossfireDataBuff = crossfireDataBuff[1:]
|
||||
continue
|
||||
length = crossfireDataBuff[1]
|
||||
if length < 2 or length > 0x40:
|
||||
print("Skipped 1 bytex", dump(crossfireDataBuff[:1]))
|
||||
crossfireDataBuff = crossfireDataBuff[1:]
|
||||
continue
|
||||
if len(crossfireDataBuff) < length+2:
|
||||
break
|
||||
ParsePacket(crossfireDataBuff[:length+2])
|
||||
crossfireDataBuff = crossfireDataBuff[length+2:]
|
||||
|
||||
def readSport(inp):
|
||||
global timeData
|
||||
line = inp.readline()
|
||||
lineNumber += 1
|
||||
if len(line) == 0:
|
||||
return
|
||||
line = line.strip('\r\n')
|
||||
if len(line) == 0:
|
||||
return
|
||||
parts = line.split(': ')
|
||||
if len(parts) < 2:
|
||||
print("weird data: \"%s\" at line %d" % (line, lineNumber))
|
||||
return
|
||||
timeData = float(parts[0].strip())
|
||||
crossfireData = parts[1].strip()
|
||||
# convert from hex
|
||||
parts = crossfireData.split(' ')
|
||||
binData = [int(hex, 16) for hex in parts]
|
||||
return binData
|
||||
|
||||
def readCsv(inp):
|
||||
global lineNumber
|
||||
global timeData
|
||||
crossfireData = []
|
||||
line = inp.readline()
|
||||
if ('Value' in line):
|
||||
line = inp.readline()
|
||||
lineNumber += 1
|
||||
line = "".join(line.split())
|
||||
parts = line.split(',')
|
||||
if len(parts) < 2:
|
||||
return []
|
||||
crossfireData = [int(parts[1][2:4],16)]
|
||||
if timeData == 0:
|
||||
timeData = float(parts[0].strip())
|
||||
return crossfireData
|
||||
|
||||
def readHex(inp):
|
||||
global lineNumber
|
||||
crossfireData = []
|
||||
line = inp.readline()
|
||||
lineNumber += 1
|
||||
line = "".join(line.split())
|
||||
crossfireData = [int(hex,16) for hex in [line[i:i+2] for i in range(0, len(line), 2)]]
|
||||
return crossfireData
|
||||
|
||||
def readBinary(inp):
|
||||
crossfireData = []
|
||||
while (b := inp.read(1)):
|
||||
crossfireData += b
|
||||
return crossfireData
|
||||
|
||||
|
||||
# execution starts here
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('inputFile', default='stdin', help='Input file with capture data (stdin works)')
|
||||
parser.add_argument('-f', '--format', default='sport',
|
||||
choices=['bin', 'hex', 'csv', 'sport'],
|
||||
help='Type of input file. bin=binary, hex=ascii hex, csv=salae async serial export, sport=s.port log')
|
||||
parser.add_argument('-i', '--ignore', action="store_true",
|
||||
help='Ignore rc data (stick) packets')
|
||||
parser.add_argument('-o', '--omit', action="store_true",
|
||||
help='Ignore ELRS status request/response packets')
|
||||
parser.add_argument('-r', '--remove', action="store_true",
|
||||
help='Ignore RadioId CRSFshot messages')
|
||||
args = parser.parse_args()
|
||||
|
||||
# open input
|
||||
if args.inputFile == 'stdin':
|
||||
if args.format == 'bin':
|
||||
inp = sys.stdin.buffer
|
||||
else:
|
||||
inp = sys.stdin
|
||||
else:
|
||||
if args.format == 'bin':
|
||||
inp = open(args.inputFile, 'rb')
|
||||
else:
|
||||
inp = open(args.inputFile, 'r')
|
||||
|
||||
if args.format == 'sport':
|
||||
get_data = readSport
|
||||
elif args.format == 'csv':
|
||||
get_data = readCsv
|
||||
elif args.format == 'bin':
|
||||
get_data = readBinary
|
||||
else:
|
||||
get_data = readHex
|
||||
|
||||
while (crossfireData := get_data(inp)):
|
||||
ParseData(crossfireData)
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
from __future__ import print_function
|
||||
|
||||
BITLEN_DSM2 = 16
|
||||
|
||||
|
||||
def sendByteDsm2(b):
|
||||
print("%02x:" % b, end=' ')
|
||||
lev = 0
|
||||
len = BITLEN_DSM2
|
||||
for i in range(9):
|
||||
nlev = b & 1
|
||||
if lev == nlev:
|
||||
len += BITLEN_DSM2
|
||||
else:
|
||||
print(len, end=' ')
|
||||
# _send_1(nlev ? len-5 : len+3);
|
||||
len = BITLEN_DSM2
|
||||
lev = nlev
|
||||
b = (b >> 1) | 0x80
|
||||
# _send_1(len+BITLEN_DSM2+3); // 2 stop bits
|
||||
print(len + BITLEN_DSM2)
|
||||
|
||||
|
||||
sendByteDsm2(24)
|
||||
sendByteDsm2(17)
|
||||
sendByteDsm2(2)
|
||||
sendByteDsm2(0x00)
|
||||
sendByteDsm2(0x06)
|
||||
sendByteDsm2(0)
|
||||
sendByteDsm2(10)
|
||||
sendByteDsm2(0)
|
||||
sendByteDsm2(14)
|
||||
sendByteDsm2(0)
|
||||
sendByteDsm2(18)
|
||||
sendByteDsm2(0)
|
||||
sendByteDsm2(22)
|
||||
sendByteDsm2(0)
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/python
|
||||
# vim: set fileencoding=utf-8
|
||||
import clang.cindex
|
||||
import asciitree # must be version 0.2
|
||||
import sys
|
||||
|
||||
def node_children(node):
|
||||
return list(c for c in node.get_children() if c is not None and c.location is not None and c.location.file is not None and c.location.file.name == sys.argv[1])
|
||||
|
||||
def print_node(node):
|
||||
text = node.spelling or node.displayname
|
||||
kind = str(node.kind)[str(node.kind).index('.')+1:]
|
||||
if clang.cindex.CursorKind.FIELD_DECL == node.kind:
|
||||
size = node.type.get_size()
|
||||
return '{} {} {}'.format(kind, text, size)
|
||||
return '{} {}'.format(kind, text)
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: dump_ast.py [header file name] [additional compile args]")
|
||||
sys.exit()
|
||||
|
||||
clang.cindex.Config.set_library_file('/usr/local/Cellar/llvm/6.0.0/lib/libclang.dylib')
|
||||
index = clang.cindex.Index.create()
|
||||
translation_unit = index.parse(sys.argv[1], ['-x', 'c++', '-std=c++11'] + sys.argv[2:])
|
||||
|
||||
print(asciitree.draw_tree(translation_unit.cursor, node_children, print_node))
|
||||
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/python
|
||||
# vim: set fileencoding=utf-8
|
||||
|
||||
from clang.cindex import *
|
||||
import asciitree # must be version 0.2
|
||||
import sys
|
||||
|
||||
TOP_NODE_TYPES = [
|
||||
CursorKind.ENUM_DECL,
|
||||
CursorKind.STRUCT_DECL ]
|
||||
|
||||
CHILD_NODE_TYPES = [
|
||||
CursorKind.FIELD_DECL,
|
||||
CursorKind.UNION_DECL,
|
||||
#CursorKind.STRUCT_DECL,
|
||||
CursorKind.ENUM_CONSTANT_DECL ]
|
||||
|
||||
def filter_node(node):
|
||||
if node is None:
|
||||
return False
|
||||
|
||||
# # no node or no location
|
||||
# if node is None or node.location is None or node.location.file is None:
|
||||
# return False
|
||||
|
||||
# # not the main source file
|
||||
# if node.location.file.name != sys.argv[1]:
|
||||
# return False
|
||||
|
||||
if node.kind in CHILD_NODE_TYPES:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_struct_decl(node):
|
||||
for c in node.get_children():
|
||||
if c is not None and c.kind == CursorKind.STRUCT_DECL:
|
||||
return c
|
||||
return None
|
||||
|
||||
def node_children(node):
|
||||
|
||||
if node is None:
|
||||
return []
|
||||
|
||||
if isinstance(node,list):
|
||||
return node
|
||||
|
||||
if node.kind == CursorKind.FIELD_DECL:
|
||||
if node.type.kind == TypeKind.ELABORATED:
|
||||
return node_children(node.type.get_declaration())
|
||||
elif node.type.kind == TypeKind.RECORD:
|
||||
return list(c for c in node.type.get_fields())
|
||||
elif node.type.kind == TypeKind.CONSTANTARRAY:
|
||||
et = node.type.element_type
|
||||
if et.kind == TypeKind.RECORD:
|
||||
return list(c for c in et.get_fields())
|
||||
elif node.type.kind == TypeKind.ENUM:
|
||||
return node_children(node.type.get_declaration())
|
||||
else:
|
||||
print("{} {}".format(str(node.type.kind),node.spelling))
|
||||
|
||||
return list(c for c in node.get_children() if filter_node(c))
|
||||
|
||||
def get_array_size(f):
|
||||
et = f.type.element_type
|
||||
ec = f.type.element_count
|
||||
if et.spelling == 'char':
|
||||
return 'string({})'.format(ec)
|
||||
else:
|
||||
return '{} x {} bytes'.format(ec,et.get_size())
|
||||
|
||||
def get_field_size(f):
|
||||
if f.is_bitfield():
|
||||
return '{} bits'.format(f.get_bitfield_width())
|
||||
elif f.type.kind == TypeKind.CONSTANTARRAY:
|
||||
return get_array_size(f)
|
||||
return '{} bytes'.format(f.type.get_size())
|
||||
|
||||
def print_field_decl(kind, text, f):
|
||||
ft = ''
|
||||
is_anon = f.is_anonymous()
|
||||
if f.type.kind == TypeKind.RECORD:
|
||||
decl = f.type.get_declaration()
|
||||
if decl.kind == CursorKind.UNION_DECL:
|
||||
if is_anon:
|
||||
ft = 'anonymous union ({})'.format(decl.mangled_name)
|
||||
else:
|
||||
ft = 'union {}'.format(f.type.spelling)
|
||||
elif decl.kind == CursorKind.STRUCT_DECL:
|
||||
if is_anon:
|
||||
ft = '{} anonymous struct'.format(f.kind)
|
||||
else:
|
||||
ft = 'struct {}'.format(f.type.spelling)
|
||||
elif f.type.kind == TypeKind.TYPEDEF:
|
||||
decl = f.type.get_canonical()
|
||||
ft = decl.spelling
|
||||
elif get_struct_decl(f) is not None:
|
||||
ft = 'anon struct'
|
||||
elif f.type.kind == TypeKind.CONSTANTARRAY:
|
||||
et = f.type.element_type
|
||||
ft = et.spelling
|
||||
else:
|
||||
ft = f.type.spelling
|
||||
|
||||
return '{} {} ({})'.format(ft, text, get_field_size(f))
|
||||
|
||||
def print_enum_decl(kind, text, e):
|
||||
return '{} {} ({})'.format(kind, text, e.enum_value)
|
||||
|
||||
def print_union_decl(kind, text, f):
|
||||
return '{} {} ({})'.format(kind, text, get_field_size(f))
|
||||
|
||||
def print_node(node):
|
||||
|
||||
if isinstance(node,list):
|
||||
return 'ROOT'
|
||||
|
||||
text = node.spelling or node.displayname
|
||||
kind = str(node.kind)[str(node.kind).index('.')+1:]
|
||||
|
||||
if CursorKind.FIELD_DECL == node.kind:
|
||||
return print_field_decl(kind, text, node)
|
||||
|
||||
if CursorKind.ENUM_CONSTANT_DECL == node.kind:
|
||||
return print_enum_decl(kind, text, node)
|
||||
|
||||
if CursorKind.UNION_DECL == node.kind:
|
||||
return print_union_decl(kind, text, node)
|
||||
|
||||
return '{} {}'.format(kind, text)
|
||||
|
||||
def get_top_node(name, node):
|
||||
for c in node.get_children():
|
||||
if c.spelling == name:
|
||||
# struct found
|
||||
return c
|
||||
|
||||
print("get_top_node: '{}' not found!".format(name))
|
||||
return None
|
||||
|
||||
def get_top_nodes(node):
|
||||
l = list()
|
||||
for c in node.get_children():
|
||||
# no node or no location
|
||||
if c is None or c.location is None or c.location.file is None:
|
||||
continue
|
||||
|
||||
# not the main source file
|
||||
if c.location.file.name != sys.argv[1]:
|
||||
continue
|
||||
|
||||
if c.kind in TOP_NODE_TYPES:
|
||||
# struct found
|
||||
l.append(c)
|
||||
|
||||
return l
|
||||
|
||||
def print_top_node(name):
|
||||
s = get_top_node(name, translation_unit.cursor)
|
||||
if s is None:
|
||||
return
|
||||
print(asciitree.draw_tree(s, node_children, print_node))
|
||||
|
||||
def print_all():
|
||||
s = get_top_nodes(translation_unit.cursor)
|
||||
print(asciitree.draw_tree(s, node_children, print_node))
|
||||
|
||||
|
||||
### Main ###
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: dump_ast_yaml.py [header file name] [top node] [additional compile args]")
|
||||
sys.exit()
|
||||
|
||||
Config.set_library_file('/usr/local/Cellar/llvm/6.0.0/lib/libclang.dylib')
|
||||
index = Index.create()
|
||||
translation_unit = index.parse(sys.argv[1], ['-x', 'c++', '-std=c++11'] + sys.argv[3:])
|
||||
|
||||
print_top_node(sys.argv[2])
|
||||
#print_top_node('CustomFunctionData')
|
||||
#print_all()
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/awk -nf
|
||||
#
|
||||
# Parses the output of elf-size-report.awk and calculates segment memory usage deltas between the analyzed elf files.
|
||||
#
|
||||
# License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
# Copyright (c)2016 Maxim Paperno
|
||||
# Copyright (c)2017 OpenTX
|
||||
#
|
||||
|
||||
|
||||
BEGIN {
|
||||
in_ttls = 0;
|
||||
elf_cnt = 0;
|
||||
sec_cnt = 0;
|
||||
}
|
||||
{
|
||||
if ($1 == "----" && NF > 5 && $5 ~ /\.elf$/) {
|
||||
fname[elf_cnt] = $5;
|
||||
}
|
||||
else if (tolower($1) ~ /totals/) {
|
||||
in_ttls = 1;
|
||||
elf_cnt++;
|
||||
}
|
||||
else if (in_ttls && NF != 5) {
|
||||
in_ttls = 0;
|
||||
}
|
||||
else if (in_ttls) {
|
||||
if (elf_cnt == 1)
|
||||
a[++sec_cnt] = $1;
|
||||
d[elf_cnt][$1]["total"] = $2;
|
||||
}
|
||||
}
|
||||
END {
|
||||
printf("\n---- Comparing results of %d files ----\n\n", elf_cnt);
|
||||
PROCINFO["sorted_in"] = "@ind_num_asc"
|
||||
for (j in d) {
|
||||
if (length(fname[j-1]))
|
||||
printf("file %d: %s\n", j, fname[j-1])
|
||||
}
|
||||
printf("\n%-8s ", "Section");
|
||||
for (j in d) {
|
||||
printf("%8s ", "file " j);
|
||||
if (j > 1)
|
||||
printf("(%7s) ", "\xCE\x94 vs f1");
|
||||
if (j > 2)
|
||||
printf("(%7s) ", "\xCE\x94 vs f" j-1);
|
||||
}
|
||||
printf("\n");
|
||||
for (i in a) {
|
||||
n = a[i];
|
||||
printf("%8s ", n);
|
||||
for (j in d) {
|
||||
printf("%8.2f ", d[j][n]["total"]);
|
||||
if (j > 1)
|
||||
printDelta(d[j][n]["total"] - d[1][n]["total"]);
|
||||
if (j > 2)
|
||||
printDelta(d[j][n]["total"] - d[j-1][n]["total"]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
function printDelta(dlta) {
|
||||
if (dlta)
|
||||
printf("(%+7.2f) ", dlta);
|
||||
else
|
||||
printf("(%7s) ", "--.--");
|
||||
}
|
||||
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/awk -nf
|
||||
#
|
||||
# Process gcc binutils 'size -A' output to show more specific and summarized information about memory segment usage.
|
||||
#
|
||||
# This script expects some variables to be set on the command line with -v:
|
||||
# names : list of segment names ("Flash", "RAM" etc.)
|
||||
# addrs : list of segment start addresses in hex/oct/dec (in same order as names)
|
||||
# sizes : list of segment sizes in KB (in same order as names)
|
||||
# elf : name of elf file (optional, for display only)
|
||||
# mcu : name of MCU (optional, for display only)
|
||||
# skip_data : skip duplicate .data in Flash (0/1 default: 0)
|
||||
#
|
||||
# NOTE: The memory segments should be specified in increasing address order (low to high).
|
||||
#
|
||||
# Usage example:
|
||||
# arm-none-eabi-size -A -x firmware.elf | ./elf-size-report.awk \
|
||||
# -v elf="firmware.elf" \
|
||||
# -v mcu="STM32F401VG" \
|
||||
# -v names="Flash RAM" \
|
||||
# -v addrs "0x08000000 0x100000000" \
|
||||
# -v sizes "512 128"
|
||||
#
|
||||
# License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
# Copyright (c)2016 Maxim Paperno
|
||||
# Copyright (c)2017 OpenTX
|
||||
#
|
||||
|
||||
|
||||
BEGIN {
|
||||
err = 0;
|
||||
len = split(names, a_names, " ");
|
||||
alen = split(addrs, a_addrs, " ");
|
||||
slen = split(sizes, a_sizes, " ");
|
||||
if (!len || len != alen || len != slen) {
|
||||
print "Error: No segment data provided or array sizes mismatch, exiting.";
|
||||
exit err = 1;
|
||||
}
|
||||
flash_name = "Flash";
|
||||
for (i in a_names) {
|
||||
n = a_names[i];
|
||||
a[i] = n; d[n]["addr"] = a_addrs[i]; d[n]["size"] = a_sizes[i]; d[n]["sum"] = 0;
|
||||
if (tolower(n) ~ /flash/)
|
||||
flash_name = n;
|
||||
}
|
||||
flmax = d[flash_name]["addr"];
|
||||
fmtstr = "%-20s %7d 0x%08x %s\n";
|
||||
|
||||
printf("\n---- Size report");
|
||||
if (length(elf)) printf(" for %s", elf);
|
||||
if (length(mcu)) printf(" (MCU: %s)", mcu);
|
||||
printf(" ----\n\n");
|
||||
printf("Section Details:\n");
|
||||
printf("%-20s %7s %10s %s\n", "section", "size(B)", "addr", "loc");
|
||||
}
|
||||
# Process each line of 'size' output listing the program's sections,
|
||||
# skip line if sections size or address are zero.
|
||||
NR > 2 && $2 != 0 && $3 != 0 {
|
||||
if ($1 == ".data") {
|
||||
# .data section is always in Flash but 'size' reports it only in RAM (sometimes twice)
|
||||
d[flash_name]["sum"] += $2;
|
||||
printf(fmtstr, $1 " (added)", $2, flmax, flash_name);
|
||||
flmax += $3;
|
||||
if (skip_data) { next; }
|
||||
}
|
||||
# Walk over each specified memory segment looking for a match
|
||||
# note: (this assumes segments were passed in ascending memory order)
|
||||
PROCINFO["sorted_in"] = "@ind_num_desc"
|
||||
addr = d[a[len]]["addr"];
|
||||
for (i in a) {
|
||||
n = a[i];
|
||||
if ($3 >= addr) {
|
||||
# check for overflow into contigious region
|
||||
t = d[n]["sum"] + $2 - (d[n]["size"] * 1024);
|
||||
if (t > 0 && i < len && d[a[i+1]]["addr"] = d[n]["addr"] + d[n]["size"] + 1) {
|
||||
d[n]["sum"] += $2 - t;
|
||||
d[a[i+1]]["sum"] += t;
|
||||
seg = n "+" a[i+1];
|
||||
}
|
||||
else {
|
||||
d[n]["sum"] += $2;
|
||||
seg = n;
|
||||
}
|
||||
printf(fmtstr, $1, $2, $3, seg);
|
||||
# track maximum flash address used
|
||||
if (n == flash_name)
|
||||
flmax += $2;
|
||||
break;
|
||||
}
|
||||
else if (i > 1)
|
||||
addr = d[a[i-1]]["addr"];
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (err) exit err;
|
||||
fmtstr = "%7s: %8.2f %6.2f%% %6d\t%7.2f\n";
|
||||
printf("\nTotals %8s usage of ttl\tKB free\n", "KB");
|
||||
PROCINFO["sorted_in"] = "@ind_num_asc"
|
||||
for (i in a) {
|
||||
n = a[i];
|
||||
if (d[n]["size"] > 0)
|
||||
printf(fmtstr, n, d[n]["sum"]/1024, d[n]["sum"]/(d[n]["size"]*1024)*100, d[n]["size"], d[n]["size"] - d[n]["sum"]/1024 );
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
Executable
+184
@@ -0,0 +1,184 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This is a wrapper for the elf-size-report.awk script which prints a detailed report
|
||||
# of memory segment allocations and usage in a given ELF file, based on gcc 'size' output.
|
||||
# This script sets up memory segment information needed by the awk script.
|
||||
# If more than one .elf file is given, then a comparison (delta memory use) report is
|
||||
# also performed using elf-size-compare.awk.
|
||||
# Currently supports some STMicro & Atmel ARM MCUs. May not work with all placement strategies.
|
||||
#
|
||||
# Usage:
|
||||
# [VAR=value] ./elf-memory-report.sh [options] [file.elf] [file2.elf] [...]
|
||||
#
|
||||
# Where VAR is any of the CAPITALIZED variables below. More than one can be specified,
|
||||
# and any VAR can also be set in the environment.
|
||||
# SIZE : gcc binutils 'size' command to use, default is "arm-none-eabi-size".
|
||||
# MCU :
|
||||
# Specifies MCU model on which to base default segment location/size parameters. Also see "--mcu=" option.
|
||||
# MEM_START_<segment> & MEM_SIZE_<segment> : (read code below for defaults)
|
||||
# Allows specifying additional/custom segment information, eg. MEM_SIZE_FLASH=768
|
||||
#
|
||||
# Options can be one or more of the following:
|
||||
# --mcu=<MCU>
|
||||
# Set MCU type. Same as setting the MCU env. variable, and overrides it.
|
||||
# --skip-data
|
||||
# Some linker scripts duplicate .data in the output (eg: .data and .data_run).
|
||||
# Set this option to skip .data from being counted in RAM a 2nd time
|
||||
# (it is always shown as being in Flash).
|
||||
# --compare-only
|
||||
# When specifying multiple elf files, only show the final comparison report.
|
||||
# --no-compare
|
||||
# Opposite and exclusive of previous option, that is, do NOT show comparison report (only size reports).
|
||||
#
|
||||
# If an elf file is not specified on the command line, this script will prompt for one.
|
||||
#
|
||||
# Examples:
|
||||
# MCU="STM32F439xI" MEM_SIZE_SDRAM2=8192 ./elf-memory-report.sh path/to/firmware.elf
|
||||
# ./elf-memory-report.sh --mcu ATSAM3S4C --compare-only firmware_new.elf firmware_old.elf
|
||||
# set -k && ./elf-memory-report.sh MCU=STM32F427VG --skip-data firmware.elf
|
||||
# (the -k switch allows variable assignment anywhere on the command line)
|
||||
# c:\cygwin\bin\bash -kc './elf-memory-report.sh --mcu ATSAM3S8C "c:\windows\path\with spaces\firmware.elf"'
|
||||
#
|
||||
# License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
# Copyright (c)2016 Maxim Paperno
|
||||
# Copyright (c)2017 OpenTX
|
||||
#
|
||||
|
||||
# -- gcc binutils 'size' command to use
|
||||
: ${SIZE:="arm-none-eabi-size"}
|
||||
|
||||
# -- MCU type, if defined will set certain memory defaults
|
||||
# e.g. STM32F205xE or ATSAM3S4C
|
||||
: ${MCU:="unknown"}
|
||||
|
||||
# -- process options
|
||||
compare=2
|
||||
skip_data=0
|
||||
for i in "$@" ; do
|
||||
case $i in
|
||||
--mcu=*) MCU="${i#*=}"; shift;;
|
||||
--skip-data) skip_data=1; shift;;
|
||||
--compare-only) compare=1; shift;;
|
||||
--no-compare) compare=0; shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
# -- make sure gawk is installed
|
||||
: ${AWKCMD:=""}
|
||||
if gawk --version >/dev/null 2>&1; then
|
||||
[[ "$OSTYPE" == "darwin"* ]] && AWKCMD="gawk -nf"
|
||||
else
|
||||
echo "GAWK is required, exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# -- defaults which may change based on MCU
|
||||
default_flash_addr=0x08000000
|
||||
default_flash_sz=1024 # KB
|
||||
default_ccm_sz=0
|
||||
default_ram1_sz=128
|
||||
default_ram2_sz=0
|
||||
default_ram3_sz=0
|
||||
# -- Set defaults based on MCU type
|
||||
if [[ $MCU != "unknown" ]] ; then
|
||||
mcu_brand=${MCU:0:2} # ST or AT
|
||||
if [[ $mcu_brand == "ST" && ${#MCU} -ge 7 ]] ; then
|
||||
# e.g.: STM32F427VG
|
||||
stm_series=${MCU:6:1} # 4
|
||||
stm_ser_ex=${MCU:7:1} # 2
|
||||
stm_flash=${MCU:10:1} # G
|
||||
default_ram1_sz=112
|
||||
default_ram2_sz=16
|
||||
case $stm_flash in
|
||||
"I") default_flash_sz=2048;;
|
||||
"G") default_flash_sz=1024;;
|
||||
"E") default_flash_sz=512;;
|
||||
"C") default_flash_sz=256;;
|
||||
esac
|
||||
if (( $stm_series == 4 )) ; then
|
||||
default_ccm_sz=64
|
||||
if (( $stm_ser_ex >= 2 )) ; then
|
||||
default_ram3_sz=64
|
||||
fi
|
||||
fi
|
||||
elif [[ $mcu_brand == "AT" && ${#MCU} -ge 9 ]] ; then
|
||||
# e.g.: ATSAM3S4C
|
||||
atm_series=${MCU:5:4} # 3S4C
|
||||
default_flash_addr=0x00400000
|
||||
case $atm_series in
|
||||
"3S8C") default_flash_sz=512; default_ram1_sz=64;;
|
||||
"3S4C") default_flash_sz=256; default_ram1_sz=48;;
|
||||
"3S2C") default_flash_sz=128; default_ram1_sz=32;;
|
||||
esac
|
||||
else
|
||||
echo "MCU type unrecognized, exiting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# -- target memory locations in hex
|
||||
: ${MEM_START_FLASH:=$default_flash_addr}
|
||||
: ${MEM_START_CCRAM:=0x10000000}
|
||||
: ${MEM_START_SRAM1:=0x20000000}
|
||||
: ${MEM_START_SRAM2:=0x2001c000}
|
||||
: ${MEM_START_SRAM3:=0x20020000}
|
||||
: ${MEM_START_PSRAM1:=0x60000000}
|
||||
: ${MEM_START_SDRAM1:=0xC0000000}
|
||||
: ${MEM_START_SDRAM2:=0xD0000000}
|
||||
|
||||
# -- target memory sizes in KB
|
||||
: ${MEM_SIZE_FLASH:=$default_flash_sz}
|
||||
: ${MEM_SIZE_CCRAM:=$default_ccm_sz}
|
||||
: ${MEM_SIZE_SRAM1:=$default_ram1_sz}
|
||||
: ${MEM_SIZE_SRAM2:=$default_ram2_sz}
|
||||
: ${MEM_SIZE_SRAM3:=$default_ram3_sz}
|
||||
: ${MEM_SIZE_PSRAM1:=0}
|
||||
: ${MEM_SIZE_SDRAM1:=0}
|
||||
: ${MEM_SIZE_SDRAM2:=0}
|
||||
|
||||
# -- prompt for elf file if not on command line
|
||||
if [[ -z "$@" ]] ; then
|
||||
read -p "Elf file(s): " ELF_FILES
|
||||
else
|
||||
ELF_FILES=$@
|
||||
fi
|
||||
|
||||
# -- Set arrays for awk script. The segments should be in increasing address order.
|
||||
names=("Flash" "CCRAM" "SRAM1" "SRAM2" "SRAM3" "PSRAM1" "SDRAM1" "SDRAM2")
|
||||
addrs=(${MEM_START_FLASH} ${MEM_START_CCRAM} ${MEM_START_SRAM1} ${MEM_START_SRAM2} ${MEM_START_SRAM3} \
|
||||
${MEM_START_PSRAM1} ${MEM_START_SDRAM1} ${MEM_START_SDRAM2})
|
||||
sizes=(${MEM_SIZE_FLASH} ${MEM_SIZE_CCRAM} ${MEM_SIZE_SRAM1} ${MEM_SIZE_SRAM2} ${MEM_SIZE_SRAM3} \
|
||||
${MEM_SIZE_PSRAM1} ${MEM_SIZE_SDRAM1} ${MEM_SIZE_SDRAM2})
|
||||
|
||||
base_dir="$(dirname "$BASH_SOURCE")"
|
||||
base_dir="${base_dir%%[[:space:]]}" # sometimes we get trailing \n
|
||||
|
||||
# -- run the ARM size command for each elf file and send output to awk script
|
||||
all_output=""
|
||||
file_cnt=0
|
||||
for elf in "$@"; do
|
||||
if [[ ! -f "$elf" ]] ; then
|
||||
echo "ELF file \"$elf\" not found."
|
||||
continue
|
||||
fi
|
||||
#${SIZE} -A -x ${elf}
|
||||
escelf="${elf//\\//}"
|
||||
output=`${SIZE} -A -x ${elf} | ${AWKCMD} "${base_dir}/elf-size-report.awk" \
|
||||
-v mcu="${MCU}" \
|
||||
-v elf="${escelf}" \
|
||||
-v skip_data=${skip_data} \
|
||||
-v names="${names[*]}" \
|
||||
-v addrs="${addrs[*]}" \
|
||||
-v sizes="${sizes[*]}"`
|
||||
if (( compare != 1 )) ; then
|
||||
echo "$output"
|
||||
echo
|
||||
fi
|
||||
file_cnt+=1
|
||||
all_output+="${output}\n"
|
||||
done
|
||||
# -- if more than one elf file was given, also run a comparison report
|
||||
if (( file_cnt > 1 && compare )) ; then
|
||||
echo "$all_output" | ${AWKCMD} "${base_dir}/elf-size-compare.awk"
|
||||
fi
|
||||
|
||||
Executable
+332
@@ -0,0 +1,332 @@
|
||||
#!/usr/bin/python
|
||||
from __future__ import annotations
|
||||
import argparse
|
||||
import struct
|
||||
import sys
|
||||
|
||||
from typing import BinaryIO, Literal, Optional, Iterator
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
DATA_BLOCK_SIZE = 256
|
||||
|
||||
UF2_MAGIC_START = b"UF2\n\x57\x51\x5d\x9e"
|
||||
UF2_MAGIC_END = b"\x30\x6f\xb1\n"
|
||||
|
||||
UF2_MAX_BLOCK_SIZE = 512
|
||||
|
||||
# extensions
|
||||
UF2_VERSION_TAG = 0x9FC7BC
|
||||
UF2_DEVICE_TAG = 0x650D9D
|
||||
UF2_REBOOT_TAG = 0xE60835
|
||||
|
||||
|
||||
def pad32(b: bytes) -> bytes:
|
||||
rem = len(b) % 4
|
||||
if rem == 0:
|
||||
return b
|
||||
|
||||
return b + (b"\x00" * (4 - rem))
|
||||
|
||||
|
||||
class UF2Extension:
|
||||
def __init__(self, tag: int, payload: bytes):
|
||||
self.tag = tag
|
||||
self.payload = payload
|
||||
|
||||
def __str__(self):
|
||||
return f"0x{self.tag:06X}: {self.payload}"
|
||||
|
||||
def _len(self):
|
||||
return 4 + len(self.payload)
|
||||
|
||||
def to_bytes(self):
|
||||
return (
|
||||
self._len().to_bytes(1, "little")
|
||||
+ self.tag.to_bytes(3, "little")
|
||||
+ pad32(self.payload)
|
||||
)
|
||||
|
||||
|
||||
class UF2Writer:
|
||||
def __init__(
|
||||
self,
|
||||
fstream: BinaryIO,
|
||||
*,
|
||||
block_size=DATA_BLOCK_SIZE,
|
||||
family=0,
|
||||
device="",
|
||||
version="",
|
||||
):
|
||||
self.out = fstream
|
||||
self.block_size = block_size
|
||||
self.family = family
|
||||
self.blockno = 0
|
||||
|
||||
self.extensions = []
|
||||
if device is not None and len(device):
|
||||
self.extensions.append(UF2Extension(UF2_DEVICE_TAG, device.encode("utf-8")))
|
||||
|
||||
if version is not None and len(version):
|
||||
self.extensions.append(
|
||||
UF2Extension(UF2_VERSION_TAG, version.encode("utf-8"))
|
||||
)
|
||||
|
||||
def _write_block(
|
||||
self,
|
||||
addr: int,
|
||||
payload: bytes | bytearray,
|
||||
nblocks: int,
|
||||
/,
|
||||
flags=0,
|
||||
extensions: list[UF2Extension] = [],
|
||||
):
|
||||
if self.family:
|
||||
flags |= 0x2000
|
||||
|
||||
merged_extensions = extensions + self.extensions
|
||||
if len(merged_extensions) > 0:
|
||||
flags |= 0x8000
|
||||
|
||||
hdr = UF2_MAGIC_START + struct.pack(
|
||||
b"<IIIIII", flags, addr, len(payload), self.blockno, nblocks, self.family
|
||||
)
|
||||
size = len(hdr) + len(payload)
|
||||
|
||||
self.out.write(hdr)
|
||||
self.out.write(payload)
|
||||
|
||||
for ext in merged_extensions:
|
||||
ext_bytes = ext.to_bytes()
|
||||
self.out.write(ext_bytes)
|
||||
size += len(ext_bytes)
|
||||
|
||||
fill = UF2_MAX_BLOCK_SIZE - size - 4
|
||||
self.out.write(b"\00" * fill)
|
||||
self.out.write(UF2_MAGIC_END)
|
||||
self.blockno += 1
|
||||
|
||||
|
||||
class ELFReader:
|
||||
def __init__(self, fstream):
|
||||
self.elf = ELFFile(fstream)
|
||||
self.segments = self._get_merged_elf_segments()
|
||||
|
||||
def _get_merged_elf_segments(self):
|
||||
def iter_segments():
|
||||
for i in range(self.elf.num_segments()):
|
||||
segment = self.elf.get_segment(i)
|
||||
type = segment["p_type"]
|
||||
addr = segment["p_paddr"]
|
||||
filesz = segment["p_filesz"]
|
||||
if type == "PT_LOAD" and filesz > 0:
|
||||
yield (i, addr, filesz)
|
||||
|
||||
def is_mergeable(last_addr, addr):
|
||||
if last_addr is None:
|
||||
return False
|
||||
diff = addr - last_addr
|
||||
return diff >= 0 and diff < 256
|
||||
|
||||
segments = []
|
||||
last_addr = None
|
||||
for i, addr, filesz in iter_segments():
|
||||
if is_mergeable(last_addr, addr):
|
||||
saddr, size, chunks = segments[-1]
|
||||
fill = addr - last_addr
|
||||
if fill > 0:
|
||||
chunks.append((-1, fill))
|
||||
size += fill
|
||||
chunks.append((i, filesz))
|
||||
size += filesz
|
||||
segments[-1] = (saddr, size, chunks)
|
||||
last_addr = saddr + size
|
||||
else:
|
||||
segments.append((addr, filesz, [(i, filesz)]))
|
||||
last_addr = addr + filesz
|
||||
|
||||
return segments
|
||||
|
||||
def iter_blocks(self, chunks, *, block_size=DATA_BLOCK_SIZE) -> Iterator[bytearray]:
|
||||
buffer = bytearray()
|
||||
for i, size in chunks:
|
||||
# fill buffer first
|
||||
if i >= 0:
|
||||
buffer += self.elf.get_segment(i).data()
|
||||
else:
|
||||
buffer += b"\x00" * size
|
||||
# then drain it
|
||||
while len(buffer) >= block_size:
|
||||
yield buffer[:block_size]
|
||||
buffer = buffer[block_size:]
|
||||
|
||||
# and finally drain it completely
|
||||
while len(buffer) > 0:
|
||||
yield buffer[:block_size]
|
||||
buffer = buffer[block_size:]
|
||||
|
||||
def get_total_blocks(self, /, block_size=DATA_BLOCK_SIZE) -> int:
|
||||
blocks = 0
|
||||
for _, size, _ in self.segments:
|
||||
blocks += (size + block_size - 1) // block_size
|
||||
return blocks
|
||||
|
||||
def get_total_size(self) -> int:
|
||||
total_size = 0
|
||||
for _, size, _ in self.segments:
|
||||
total_size += size
|
||||
return total_size
|
||||
|
||||
def get_section(self, name: str) -> tuple[int, int]:
|
||||
section = self.elf.get_section_by_name(name)
|
||||
if section is not None:
|
||||
return (section["sh_addr"], section["sh_size"])
|
||||
return (0, 0)
|
||||
|
||||
|
||||
class UF2InsertBlock:
|
||||
def __init__(
|
||||
self,
|
||||
insert_addr: int,
|
||||
addr: int,
|
||||
payload: bytes,
|
||||
*,
|
||||
extensions: list[UF2Extension] = [],
|
||||
flags=0,
|
||||
):
|
||||
self.insert_addr = insert_addr
|
||||
self.addr = addr
|
||||
self.payload = payload
|
||||
self.extensions = extensions
|
||||
self.flags = flags
|
||||
|
||||
|
||||
def write_uf2(
|
||||
reader: ELFReader, uf2: UF2Writer, insert_block: Optional[UF2InsertBlock] = None
|
||||
):
|
||||
nblocks = reader.get_total_blocks() + (1 if insert_block else 0)
|
||||
for addr, _, chunks in reader.segments:
|
||||
block_addr = addr
|
||||
for block in reader.iter_blocks(chunks):
|
||||
if insert_block and insert_block.insert_addr <= block_addr:
|
||||
uf2._write_block(
|
||||
insert_block.addr,
|
||||
insert_block.payload,
|
||||
nblocks,
|
||||
flags=insert_block.flags,
|
||||
extensions=insert_block.extensions,
|
||||
)
|
||||
insert_block = None
|
||||
|
||||
if len(block) < DATA_BLOCK_SIZE:
|
||||
block = block + b"\xff" * (DATA_BLOCK_SIZE - len(block))
|
||||
|
||||
uf2._write_block(block_addr, block, nblocks)
|
||||
block_addr += len(block)
|
||||
|
||||
|
||||
def elf_to_uf2(args: argparse.Namespace) -> None:
|
||||
reader = ELFReader(args.input)
|
||||
|
||||
total_blocks = reader.get_total_blocks()
|
||||
print(f"Total blocks: {total_blocks}")
|
||||
|
||||
total_size = reader.get_total_size()
|
||||
print(f"Total size: {total_size}")
|
||||
|
||||
insert_block = None
|
||||
if args.reboot is not None:
|
||||
insert = None
|
||||
addr = None
|
||||
start = None
|
||||
|
||||
if args.reboot == "auto":
|
||||
if len(reader.segments) > 1:
|
||||
addr, _ = reader.get_section(".reboot_buffer")
|
||||
start, bl_size = reader.get_section(".bootloader")
|
||||
insert = start + bl_size
|
||||
else:
|
||||
insert, addr, start = args.reboot
|
||||
|
||||
if insert and addr and start:
|
||||
print(f"Insert reboot block @{insert:08X} ({addr:08X}/{start:08X})")
|
||||
insert_block = UF2InsertBlock(
|
||||
insert,
|
||||
addr,
|
||||
b"BDFU",
|
||||
extensions=[UF2Extension(UF2_REBOOT_TAG, start.to_bytes(4, "little"))],
|
||||
flags=1,
|
||||
)
|
||||
|
||||
uf2 = UF2Writer(
|
||||
args.output, family=args.family, device=args.device, version=args.version
|
||||
)
|
||||
write_uf2(reader, uf2, insert_block)
|
||||
print(f"Blocks written: {uf2.blockno}")
|
||||
|
||||
|
||||
def parse_reboot_arg(arg: str) -> tuple[int, int, int] | Literal["auto"]:
|
||||
if arg == "auto":
|
||||
return arg
|
||||
|
||||
addresses = arg.split(":")
|
||||
if len(addresses) != 2:
|
||||
raise argparse.ArgumentTypeError("invalid addresses")
|
||||
|
||||
try:
|
||||
insert = int(addresses[0], 0)
|
||||
addr = int(addresses[1], 0)
|
||||
start = int(addresses[2], 0)
|
||||
return (insert, addr, start)
|
||||
except ValueError:
|
||||
raise argparse.ArgumentTypeError("invalid addresses")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--family", type=lambda x: int(x, 0), default=0, help="UF2 family ID"
|
||||
)
|
||||
parser.add_argument("--device", default="", help="UF2 device description")
|
||||
parser.add_argument("--version", default="", help="UF2 firmware version")
|
||||
parser.add_argument(
|
||||
"--reboot",
|
||||
type=parse_reboot_arg,
|
||||
metavar="{INSERT:ADDRESS:START | auto}",
|
||||
help="add reboot block",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--input",
|
||||
type=argparse.FileType("rb"),
|
||||
required=True,
|
||||
help="input ELF file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"output",
|
||||
nargs="?",
|
||||
help="output UF2 file",
|
||||
type=argparse.FileType("wb"),
|
||||
default="output.uf2",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
try:
|
||||
args = parse_args()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit(-1)
|
||||
|
||||
try:
|
||||
elf_to_uf2(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit(-1)
|
||||
finally:
|
||||
args.input.close()
|
||||
args.output.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+213
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
from PIL import Image
|
||||
|
||||
# LZ4 compression
|
||||
import lz4.block
|
||||
|
||||
class RawMixin:
|
||||
def encode_byte(self, byte):
|
||||
self.write(byte)
|
||||
|
||||
def encode_end(self):
|
||||
pass
|
||||
|
||||
class RleMixin:
|
||||
RLE_BYTE = 0
|
||||
RLE_SEQ = 1
|
||||
|
||||
def __init__(self):
|
||||
self.state = self.RLE_BYTE
|
||||
self.count = 0
|
||||
self.prev_byte = None
|
||||
|
||||
def eq_prev_byte(self, byte):
|
||||
if self.prev_byte is None:
|
||||
return False
|
||||
return byte == self.prev_byte
|
||||
|
||||
def encode_byte(self, byte):
|
||||
if self.state == self.RLE_BYTE:
|
||||
self.write(byte)
|
||||
if self.eq_prev_byte(byte):
|
||||
self.state = self.RLE_SEQ
|
||||
self.count = 0
|
||||
else:
|
||||
self.prev_byte = byte
|
||||
elif self.state == self.RLE_SEQ:
|
||||
if self.eq_prev_byte(byte):
|
||||
self.count += 1
|
||||
if self.count == 255:
|
||||
self.write(self.count)
|
||||
self.prev_byte = None
|
||||
self.state = self.RLE_BYTE
|
||||
else:
|
||||
self.write(self.count)
|
||||
self.write(byte)
|
||||
self.prev_byte = byte
|
||||
self.state = self.RLE_BYTE
|
||||
|
||||
def encode_end(self):
|
||||
if self.state == self.RLE_SEQ:
|
||||
self.write(self.count)
|
||||
|
||||
class Lz4Mixin:
|
||||
|
||||
def __init__(self):
|
||||
self.buffer = []
|
||||
|
||||
def encode_byte(self,byte):
|
||||
self.buffer.append(byte)
|
||||
|
||||
def encode_end(self):
|
||||
compressed_data = lz4.block.compress(bytes(self.buffer), compression=12, mode='high_compression', store_size=False)
|
||||
data_len = len(compressed_data).to_bytes(4, byteorder='little')
|
||||
for b in data_len:
|
||||
self.write(b)
|
||||
for b in compressed_data:
|
||||
self.write(b)
|
||||
|
||||
class ImageEncoder:
|
||||
def __init__(self, filename, size_format, reverse=False):
|
||||
self.f = open(filename, "w")
|
||||
self.size_format = size_format
|
||||
self.reverse = reverse
|
||||
|
||||
def write(self, value):
|
||||
if isinstance(value, bytes):
|
||||
value = int.from_bytes(value, 'little')
|
||||
self.f.write("0x%02x," % value)
|
||||
|
||||
def write_size(self, width, height):
|
||||
if self.size_format == 2:
|
||||
self.f.write("%d,%d,%d,%d,\n" % (width % 256, width // 256, height % 256, height // 256))
|
||||
else:
|
||||
self.f.write("%d,%d,\n" % (width, height))
|
||||
|
||||
def encode_1bit(self, image, rows):
|
||||
image = image.convert(mode='1')
|
||||
width, height = image.size
|
||||
self.write_size(width, height // rows)
|
||||
for y in range(0, height, 8):
|
||||
for x in range(width):
|
||||
value = 0
|
||||
for z in range(8):
|
||||
if y + z < height:
|
||||
if image.format == "XBM":
|
||||
if image.getpixel((x, y + z)) > 0:
|
||||
value += 1 << z
|
||||
else:
|
||||
if image.getpixel((x, y + z)) == 0:
|
||||
value += 1 << z
|
||||
self.encode_byte(value)
|
||||
self.f.write("\n")
|
||||
self.encode_end()
|
||||
|
||||
def encode_4bits(self, image):
|
||||
image = image.convert(mode='L')
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(0, height, 2):
|
||||
for x in range(width):
|
||||
value = 0xFF
|
||||
gray1 = self.get_pixel(image, x, y)
|
||||
if y + 1 < height:
|
||||
gray2 = self.get_pixel(image, x, y + 1)
|
||||
else:
|
||||
gray2 = 255
|
||||
for i in range(4):
|
||||
if gray1 & (1 << (4 + i)):
|
||||
value -= 1 << i
|
||||
if gray2 & (1 << (4 + i)):
|
||||
value -= 1 << (4 + i)
|
||||
self.encode_byte(value)
|
||||
self.f.write("\n")
|
||||
self.encode_end()
|
||||
|
||||
def encode_8bits(self, image):
|
||||
image = image.convert(mode='L')
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
value = self.get_pixel(image, x, y)
|
||||
value = 0xFF - value
|
||||
self.encode_byte(value)
|
||||
self.encode_end()
|
||||
|
||||
def encode_5_6_5(self, image):
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
pixel = self.get_pixel(image, x, y)
|
||||
val = ((pixel[0] >> 3) << 11) + ((pixel[1] >> 2) << 5) + ((pixel[2] >> 3) << 0)
|
||||
self.encode_byte(val & 255)
|
||||
self.encode_byte(val >> 8)
|
||||
self.encode_end()
|
||||
|
||||
def encode_4_4_4_4(self, image):
|
||||
width, height = image.size
|
||||
self.write_size(width, height)
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
pixel = self.get_pixel(image, x, y)
|
||||
val = ((pixel[3] // 16) << 12) + ((pixel[0] // 16) << 8) + ((pixel[1] // 16) << 4) + ((pixel[2] // 16) << 0)
|
||||
self.encode_byte(val & 255)
|
||||
self.encode_byte(val >> 8)
|
||||
self.encode_end()
|
||||
|
||||
def get_pixel(self, image, x, y):
|
||||
if self.reverse:
|
||||
return image.getpixel((image.width - x - 1, image.height - y - 1))
|
||||
else:
|
||||
return image.getpixel((x, y))
|
||||
|
||||
@staticmethod
|
||||
def create(filename, size_format=1, reverse=False, encode_mixin=RawMixin):
|
||||
class ResultClass(ImageEncoder, encode_mixin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
ImageEncoder.__init__(self, *args, **kwargs)
|
||||
encode_mixin.__init__(self)
|
||||
return ResultClass(filename, size_format, reverse)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Bitmaps encoder')
|
||||
parser.add_argument('input', action="store", help="Input file name")
|
||||
parser.add_argument('output', action="store", help="Output file name")
|
||||
parser.add_argument('--format', action="store", help="Output format")
|
||||
parser.add_argument("--reverse", help="Invert pixels order", action="store_true")
|
||||
parser.add_argument("--rle", help="Enable RLE compression", action="store_true")
|
||||
parser.add_argument("--lz4", help="Enable RLE compression", action="store_true")
|
||||
parser.add_argument("--rows", help="Image rows count (for 1bit format)", type=int, default=1)
|
||||
parser.add_argument("--size-format", help="Header image size format (1 or 2 bytes)", type=int, default=1)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
image = Image.open(args.input)
|
||||
output = args.output
|
||||
|
||||
byte_encoder = RawMixin
|
||||
if args.rle:
|
||||
byte_encoder = RleMixin
|
||||
if args.lz4:
|
||||
byte_encoder = Lz4Mixin
|
||||
|
||||
encoder = ImageEncoder.create(output, args.size_format, args.reverse, byte_encoder)
|
||||
|
||||
if args.format == "1bit":
|
||||
encoder.encode_1bit(image, args.rows)
|
||||
elif args.format == "4bits":
|
||||
encoder.encode_4bits(image)
|
||||
elif args.format == "8bits":
|
||||
encoder.encode_8bits(image)
|
||||
elif args.format == "4/4/4/4":
|
||||
encoder.encode_4_4_4_4(image)
|
||||
elif args.format == "5/6/5":
|
||||
encoder.encode_5_6_5(image)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
curr = 0
|
||||
idx = 0
|
||||
byte = 0
|
||||
|
||||
|
||||
def push4bits(val):
|
||||
global curr, idx, byte
|
||||
val = val & 0x0f
|
||||
curr += val << idx
|
||||
idx += 4
|
||||
if idx == 8:
|
||||
print("0x%02X," % curr, end=' ')
|
||||
idx = 0
|
||||
curr = 0
|
||||
byte += 1
|
||||
if byte % 16 == 0:
|
||||
print()
|
||||
|
||||
|
||||
cluster = 0
|
||||
|
||||
|
||||
def pushCluster(val):
|
||||
global cluster
|
||||
push4bits(val)
|
||||
push4bits(val >> 4)
|
||||
push4bits(val >> 8)
|
||||
cluster += 1
|
||||
|
||||
|
||||
def pushFile(size):
|
||||
sectors = size // 512
|
||||
count = sectors // 8
|
||||
for i in range(count - 1):
|
||||
pushCluster(cluster + 1)
|
||||
pushCluster(0xFFF)
|
||||
|
||||
|
||||
def pushDisk(eeprom, flash):
|
||||
global curr, idx, byte, cluster
|
||||
curr = idx = byte = cluster = 0
|
||||
print("Disk with %dk EEPROM and %dk FLASH:" % (eeprom, flash))
|
||||
pushCluster(0xFF8)
|
||||
pushCluster(0xFFF)
|
||||
pushFile(flash * 1024)
|
||||
if eeprom > 0:
|
||||
pushFile(eeprom * 1024)
|
||||
while byte < 512:
|
||||
push4bits(0)
|
||||
print()
|
||||
|
||||
|
||||
#pushDisk(32, 512)
|
||||
pushDisk(32, 512)
|
||||
|
||||
pushDisk(0, 2048)
|
||||
@@ -0,0 +1,141 @@
|
||||
#
|
||||
# Most of this code is from clang_complete:
|
||||
# https://github.com/xavierd/clang_complete/blob/master/plugin/libclang.py
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
from clang.cindex import *
|
||||
|
||||
# Check if libclang is able to find the builtin include files.
|
||||
#
|
||||
# libclang sometimes fails to correctly locate its builtin include files. This
|
||||
# happens especially if libclang is not installed at a standard location. This
|
||||
# function checks if the builtin includes are available.
|
||||
def canFindBuiltinHeaders(index, args = []):
|
||||
flags = 0
|
||||
currentFile = ("test.c", '#include "stddef.h"')
|
||||
try:
|
||||
tu = index.parse("test.c", args, [currentFile], flags)
|
||||
except TranslationUnitLoadError as e:
|
||||
return 0
|
||||
|
||||
return len(tu.diagnostics) == 0
|
||||
|
||||
# Derive path to clang builtin headers.
|
||||
#
|
||||
# This function tries to derive a path to clang's builtin header files. We are
|
||||
# just guessing, but the guess is very educated. In fact, we should be right
|
||||
# for all manual installations (the ones where the builtin header path problem
|
||||
# is very common) as well as a set of very common distributions.
|
||||
def getBuiltinHeaderPath(library_path):
|
||||
if not library_path:
|
||||
return None
|
||||
|
||||
if os.path.isfile(library_path):
|
||||
library_path = os.path.dirname(library_path)
|
||||
|
||||
knownPaths = [
|
||||
library_path + "/../lib/clang", # default value
|
||||
library_path + "/../clang", # gentoo
|
||||
library_path + "/clang", # opensuse
|
||||
library_path + "/", # Google
|
||||
"/usr/lib64/clang", # x86_64 (openSUSE, Fedora)
|
||||
"/usr/lib/clang"
|
||||
]
|
||||
|
||||
for path in knownPaths:
|
||||
try:
|
||||
subDirs = [f for f in os.listdir(path) if os.path.isdir(path + "/" + f)]
|
||||
subDirs = sorted(subDirs) or ['.']
|
||||
path = path + "/" + subDirs[-1] + "/include"
|
||||
#print("searching builtins in " + path)
|
||||
if canFindBuiltinHeaders(index, ["-I" + path]):
|
||||
return path
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def natural_sort_key(s):
|
||||
return [int(text) if text.isdigit() else text.lower()
|
||||
for text in re.split(r'(\d+)', s)]
|
||||
|
||||
def findLibClang():
|
||||
if sys.platform == "darwin":
|
||||
knownPaths = [
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
|
||||
"/Library/Developer/CommandLineTools/usr/lib"
|
||||
]
|
||||
if Config.library_path:
|
||||
knownPaths.insert(0, Config.library_path)
|
||||
libSuffix = ".dylib"
|
||||
elif sys.platform.startswith("linux"):
|
||||
base_dirs = ["/usr/lib", "/usr/local/lib"]
|
||||
version_paths = []
|
||||
|
||||
for base_dir in base_dirs:
|
||||
if os.path.exists(base_dir):
|
||||
for item in os.listdir(base_dir):
|
||||
if item.startswith("llvm-") and os.path.isdir(os.path.join(base_dir, item, "lib")):
|
||||
llvm_lib_path = os.path.join(base_dir, item, "lib")
|
||||
version = item[5:]
|
||||
version_paths.append((version, llvm_lib_path))
|
||||
|
||||
version_paths.sort(key=lambda x: natural_sort_key(x[0]), reverse=True)
|
||||
knownPaths = [path for _, path in version_paths]
|
||||
knownPaths.extend(["/usr/local/lib", "/usr/lib", "/usr/lib64"])
|
||||
|
||||
libSuffix = ".so"
|
||||
elif sys.platform == "win32" or sys.platform == "msys":
|
||||
knownPaths = os.environ.get("PATH").split(os.pathsep)
|
||||
libSuffix = ".dll"
|
||||
else:
|
||||
# Unsupported platform
|
||||
return None
|
||||
|
||||
for path in knownPaths:
|
||||
# print("trying " + path, file=sys.stderr)
|
||||
if os.path.exists(path + "/libclang" + libSuffix):
|
||||
return path
|
||||
elif (sys.platform == "win32" or sys.platform == "msys"):
|
||||
# Check for versioned and non-versioned libclang.dll if on msys
|
||||
pattern = re.compile(r'^libclang(-\d+(\.\d+)?)?\.dll$')
|
||||
if os.path.exists(path):
|
||||
for filename in os.listdir(path):
|
||||
if pattern.match(filename):
|
||||
return os.path.join(path, filename)
|
||||
|
||||
# If no known path is found
|
||||
return None
|
||||
|
||||
def initLibClang():
|
||||
global index
|
||||
|
||||
library_path = findLibClang()
|
||||
if library_path:
|
||||
print("libclang found: " + library_path, file=sys.stderr)
|
||||
if os.path.isdir(library_path):
|
||||
Config.set_library_path(library_path)
|
||||
else:
|
||||
Config.set_library_file(library_path)
|
||||
else:
|
||||
print("WARN (find_clang): libclang path not found", file=sys.stderr)
|
||||
|
||||
Config.set_compatibility_check(False)
|
||||
|
||||
try:
|
||||
index = Index.create()
|
||||
except Exception as e:
|
||||
print("ERROR (find_clang): could not load libclang from '%s'." % library_path, file=sys.stderr)
|
||||
print(" : detected platform '%s'" % sys.platform, file=sys.stderr)
|
||||
return False
|
||||
|
||||
global builtin_hdr_path
|
||||
builtin_hdr_path = getBuiltinHeaderPath(library_path)
|
||||
if builtin_hdr_path:
|
||||
print("builtin header path found: " + builtin_hdr_path, file=sys.stderr)
|
||||
|
||||
# Everything is OK, libclang can be used
|
||||
return True
|
||||
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, os
|
||||
import glob
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
chars_en = u""" !"#$%&'()*+,-./0123456789:;<=>?°ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz~|≥"""
|
||||
chars_fr = u"""éèàîç"""
|
||||
chars_da = u"""åæøÅÆØ"""
|
||||
chars_de = u"""ÄäÖöÜüß"""
|
||||
chars_cz = u"""ěščřžýáíéňóůúďťĚŠČŘŽÝÁÍÉŇÓÚŮĎŤ"""
|
||||
chars_es = u"""ÑñÁáÉéÍíÓóÚú"""
|
||||
chars_fi = u"""åäöÅÄÖ"""
|
||||
chars_it = u"""àù"""
|
||||
chars_pl = u"""ąćęłńóśżźĄĆĘŁŃÓŚŻŹ"""
|
||||
chars_pt = u"""ÁáÂâÃãÀàÇçÉéÊêÍíÓóÔôÕõÚú"""
|
||||
chars_ru = u"""АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя"""
|
||||
chars_ua = u"""БГҐДЄЖЗИЇЙЛПУФЦЧШЩЬЮЯбвгґдєжзиїйклмнптфцчшщьюя"""
|
||||
|
||||
COUNT_EXTRA_CHARS = 21
|
||||
|
||||
chars_extra = u"".join([chr(1+i) for i in range(COUNT_EXTRA_CHARS)])
|
||||
chars = chars_en + chars_extra + chars_fr + chars_da + chars_de + chars_cz + chars_es + chars_fi + chars_it + chars_pl + chars_pt + chars_ru + chars_ua
|
||||
|
||||
|
||||
def createFontBitmap(filename, fontname, fontsize, fontoffset, foreground, background, coordsfile=True):
|
||||
|
||||
|
||||
coords = []
|
||||
font_filename = 'fonts/' + fontname + '.ttf'
|
||||
|
||||
print("Font filename: %s" % font_filename)
|
||||
font = ImageFont.truetype(font_filename, fontsize)
|
||||
|
||||
extraImage = None
|
||||
extraFilename = 'fonts/extra_%dpx.png' % fontsize
|
||||
|
||||
try:
|
||||
extraImage = Image.open(extraFilename)
|
||||
extraImage = extraImage.convert('RGB');
|
||||
|
||||
except IOError:
|
||||
print("Missing extra symbol filename %s" % extraFilename)
|
||||
|
||||
def getCharWidth(c):
|
||||
if c in chars_extra:
|
||||
if extraImage:
|
||||
# Extra characters 16px
|
||||
#if fontsize == 16:
|
||||
if ord(c) <= 9:
|
||||
return 13
|
||||
else:
|
||||
return 15
|
||||
else:
|
||||
return 0
|
||||
elif c == " ":
|
||||
return 4
|
||||
else:
|
||||
w, h = font.getsize(c)
|
||||
return w + 1
|
||||
|
||||
def getFontWidth():
|
||||
width = 0
|
||||
for c in chars:
|
||||
width += getCharWidth(c)
|
||||
return width
|
||||
|
||||
width = getFontWidth()
|
||||
image = Image.new('RGB', (width, fontsize + 4), background)
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
width = 0
|
||||
for c in chars:
|
||||
coords.append(width)
|
||||
|
||||
if c in chars_extra:
|
||||
if extraImage and c == chars_extra[0]:
|
||||
image.paste(extraImage.copy(),(width,1))
|
||||
elif c == " ":
|
||||
pass
|
||||
elif c == "j" and fontsize == 32:
|
||||
w, h = font.getsize(c)
|
||||
draw.text((width + 2, fontoffset), c, fill=foreground, font=font)
|
||||
elif c == "j" and fontsize == 64:
|
||||
aw, h = font.getsize(c)
|
||||
draw.text((width + 3, fontoffset), c, fill=foreground, font=font)
|
||||
else:
|
||||
w, h = font.getsize(c)
|
||||
draw.text((width + 1, fontoffset), c, fill=foreground, font=font)
|
||||
|
||||
width += getCharWidth(c)
|
||||
|
||||
coords.append(width)
|
||||
|
||||
image.save(filename + ".png")
|
||||
if coordsfile:
|
||||
with open(filename + ".specs", "w") as f:
|
||||
f.write(",".join(str(tmp) for tmp in coords))
|
||||
|
||||
|
||||
# Main
|
||||
if __name__ == "__main__":
|
||||
createFontBitmap(sys.argv[4], sys.argv[1], int(sys.argv[2]), int(sys.argv[3]), (0,0,0), (255,255,255))
|
||||
Executable
+378
@@ -0,0 +1,378 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
languages = (
|
||||
"en",
|
||||
"fr",
|
||||
"se",
|
||||
"it",
|
||||
"cz",
|
||||
"de",
|
||||
"pt",
|
||||
"es",
|
||||
"pl",
|
||||
"nl"
|
||||
)
|
||||
|
||||
tts_languages = {
|
||||
"en",
|
||||
"fr",
|
||||
"it",
|
||||
"cz",
|
||||
"de",
|
||||
"pt"
|
||||
}
|
||||
|
||||
options_taranis_x9d = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"haptic": ("HAPTIC", "YES", "NO"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"sqt5font": ("FONT", "SQT5", None),
|
||||
"noras": ("RAS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
|
||||
options_taranis_x9dp = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"sqt5font": ("FONT", "SQT5", None),
|
||||
"noras": ("RAS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
options_taranis_x7 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"sqt5font": ("FONT", "SQT5", None),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
}
|
||||
|
||||
options_taranis_x9lite = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"sqt5font": ("FONT", "SQT5", None),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
|
||||
options_taranis_xlite = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"sqt5font": ("FONT", "SQT5", None),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
|
||||
options_taranis_xlites = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"sqt5font": ("FONT", "SQT5", None),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
|
||||
options_taranis_x9e = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"sqt5font": ("FONT", "SQT5", None),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"horussticks": ("STICKS", "HORUS", "STANDARD"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
|
||||
options_horus_x12s = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"pcbdev": ("PCBREV", "10", None),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)],
|
||||
"externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_horus_x10 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)],
|
||||
"externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_horus_x10express = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"luac": ("LUA_COMPILER", "YES", "NO"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
}
|
||||
|
||||
options_betafpv_lr3pro = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
}
|
||||
|
||||
options_jumper_tlite = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
}
|
||||
|
||||
options_jumper_t12 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"internalmulti": ("INTERNAL_MODULE_MULTI", "YES", "NO"),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
|
||||
options_jumper_t16 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"internalmulti": ("INTERNAL_MODULE_MULTI", "YES", "NO"),
|
||||
"bluetooth": ("BLUETOOTH", "YES", "NO"),
|
||||
"externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_jumper_t18 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"bluetooth": ("BLUETOOTH", "YES", "NO"),
|
||||
"externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_radiomaster_tx12 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO")
|
||||
}
|
||||
|
||||
options_radiomaster_tx12mk2 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_radiomaster_zorro = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_radiomaster_boxer = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_radiomaster_gx12 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_radiomaster_pocket = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_radiomaster_mt12 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_radiomaster_t8 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"bindkey": ("BIND_KEY", "NO", "YES"),
|
||||
}
|
||||
|
||||
options_radiomaster_tx16s = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"bluetooth": ("BLUETOOTH", "YES", "NO"),
|
||||
"internalgps": ("INTERNAL_GPS", "YES", "NO"),
|
||||
"externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_fatfish_f16 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"bluetooth": ("BLUETOOTH", "YES", "NO"),
|
||||
"internalgps": ("INTERNAL_GPS", "YES", "NO"),
|
||||
"externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_helloradiosky_v12 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_helloradiosky_v14 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"afhds3": ("AFHDS3", "YES", "NO"),
|
||||
"internalelrs": ("INTERNAL_MODULE_ELRS", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_helloradiosky_v16 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
|
||||
"bluetooth": ("BLUETOOTH", "YES", "NO"),
|
||||
"internalgps": ("INTERNAL_GPS", "YES", "NO"),
|
||||
"externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"),
|
||||
}
|
||||
|
||||
options_commando8_t8 = {
|
||||
"noheli": ("HELI", "NO", "YES"),
|
||||
"lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"),
|
||||
"nogvars": ("GVARS", "NO", "YES"),
|
||||
"faimode": ("FAI", "YES", None),
|
||||
"faichoice": ("FAI", "CHOICE", None),
|
||||
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2020 Inria
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
|
||||
"""Generate the vectors table for a given STM32 CPU line."""
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import re
|
||||
|
||||
|
||||
VECTORS_FORMAT = """
|
||||
#include "{cpu_line}.h"
|
||||
#include "cortex_m_isr.h"
|
||||
|
||||
void Default_Handler() {{ default_isr_handler(); }}
|
||||
|
||||
/* {cpu_line} specific interrupt vectors */
|
||||
{isr_lines}
|
||||
|
||||
/* CPU specific interrupt vector table */
|
||||
const isr_t _isr_vector[] ISR_VECTOR = {{
|
||||
[0] = (isr_t)&_estack,
|
||||
{irq_lines}
|
||||
}};
|
||||
"""
|
||||
|
||||
|
||||
def parse_cmsis(cmsis_dir, cpu_line):
|
||||
"""Parse the CMSIS to get the list IRQs."""
|
||||
cpu_line_cmsis = os.path.join("{}/{}.h".format(cmsis_dir, cpu_line.lower()))
|
||||
|
||||
with open(cpu_line_cmsis, "rb") as cmsis:
|
||||
cmsis_content = cmsis.readlines()
|
||||
|
||||
irq_lines = []
|
||||
use_line = False
|
||||
for line in cmsis_content:
|
||||
try:
|
||||
line = line.decode()
|
||||
except UnicodeDecodeError:
|
||||
# skip line that contains non unicode characters
|
||||
continue
|
||||
|
||||
# start filling lines after interrupt Doxygen comment
|
||||
if "typedef enum" in line:
|
||||
irq_lines = [] # Cleanup any previous content
|
||||
use_line = True
|
||||
|
||||
# enum not yet detected: skip
|
||||
if not use_line:
|
||||
continue
|
||||
|
||||
# Stop at the end of the IRQn_Type enum definition
|
||||
if "IRQn_Type" in line:
|
||||
break
|
||||
|
||||
# use a regexp to get the available IRQs
|
||||
match = re.match(r"[ ]+([a-zA-Z0-9_]+_IRQn)[ ]+= \d+", line)
|
||||
|
||||
# Skip lines that don't match
|
||||
if match:
|
||||
irq_lines.append(match.group(1).strip())
|
||||
|
||||
isrs = [
|
||||
{"irq": irq + " + 16", "func": irq.rsplit("_", 1)[0] + "_IRQHandler"}
|
||||
for irq in irq_lines
|
||||
]
|
||||
return {"isrs": isrs, "cpu_line": cpu_line}
|
||||
|
||||
|
||||
def generate_vectors(context):
|
||||
"""Use vector template string to generate the vectors C file."""
|
||||
isr_line_format = "WEAK_DEFAULT void {func}();"
|
||||
irq_line_format = " [{irq:<35}] = {func},"
|
||||
|
||||
isr_lines = []
|
||||
irq_lines = []
|
||||
|
||||
cortex_m_irqs = [
|
||||
"Reset_Handler",
|
||||
"NMI_Handler",
|
||||
"HardFault_Handler",
|
||||
"MemManage_Handler",
|
||||
"BusFault_Handler",
|
||||
"UsageFault_Handler",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"SVC_Handler",
|
||||
"DebugMon_Handler",
|
||||
"0",
|
||||
"PendSV_Handler",
|
||||
"SysTick_Handler",
|
||||
]
|
||||
|
||||
irqn = 1
|
||||
for isr in cortex_m_irqs:
|
||||
if isr != "0":
|
||||
isr_lines.append(isr_line_format.format(func=isr))
|
||||
irq_lines.append(irq_line_format.format(irq=irqn, func=isr))
|
||||
irqn += 1
|
||||
|
||||
for isr in context["isrs"]:
|
||||
isr_line = isr_line_format.format(**isr)
|
||||
if isr_line not in isr_lines:
|
||||
isr_lines.append(isr_line)
|
||||
irq_lines.append(irq_line_format.format(**isr))
|
||||
|
||||
vectors_content = VECTORS_FORMAT.format(
|
||||
cpu_line=context["cpu_line"],
|
||||
isr_lines="\n".join(isr_lines),
|
||||
irq_lines="\n".join(irq_lines),
|
||||
)
|
||||
|
||||
print(vectors_content)
|
||||
|
||||
|
||||
def main(args):
|
||||
"""Main function."""
|
||||
context = parse_cmsis(args.cmsis_dir, args.cpu_line)
|
||||
generate_vectors(context)
|
||||
|
||||
|
||||
PARSER = argparse.ArgumentParser()
|
||||
PARSER.add_argument("cmsis_dir", help="CMSIS directory")
|
||||
PARSER.add_argument("cpu_line", help="STM32 CPU line")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(PARSER.parse_args())
|
||||
Executable
+116
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import find_clang
|
||||
import sys
|
||||
import clang.cindex
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
structs = []
|
||||
extrastructs = []
|
||||
|
||||
def valid_spelling(spelling):
|
||||
return spelling and not spelling.startswith("(")
|
||||
|
||||
def build_struct(cursor, anonymousUnion=False):
|
||||
if not anonymousUnion:
|
||||
structs.append(cursor.spelling)
|
||||
print("template <class A, class B>\nvoid copy%s(A * dest, B * src)\n{" % cursor.spelling)
|
||||
|
||||
for c in cursor.get_children():
|
||||
if c.kind == clang.cindex.CursorKind.UNION_DECL:
|
||||
if valid_spelling(c.spelling):
|
||||
raise Exception("Cannot handle non anonymous unions")
|
||||
|
||||
copied_union_member = False
|
||||
for uc in c.get_children():
|
||||
if not valid_spelling(uc.spelling) or uc.kind == clang.cindex.CursorKind.PACKED_ATTR:
|
||||
# Ignore
|
||||
pass
|
||||
else:
|
||||
# per default we copy only the first member of a union and warn if there are more
|
||||
# members (declare the other members NOBACKUP)
|
||||
if copied_union_member:
|
||||
print("Warning more than one union member (%s) in anynomous union inside struct %s, consider NOBACKUP statements" % (uc.spelling, cursor.spelling), file=sys.stderr)
|
||||
else:
|
||||
copy_decl(uc, uc.spelling)
|
||||
copied_union_member = True
|
||||
|
||||
elif c.kind == clang.cindex.CursorKind.FIELD_DECL:
|
||||
copy_decl(c, c.spelling)
|
||||
|
||||
if not anonymousUnion:
|
||||
print("}\n")
|
||||
|
||||
|
||||
def build(cursor):
|
||||
result = []
|
||||
for c in cursor.get_children():
|
||||
if c.location.file.name == sys.argv[1]:
|
||||
if c.kind == clang.cindex.CursorKind.STRUCT_DECL:
|
||||
build_struct(c)
|
||||
for c, spelling in extrastructs:
|
||||
print("template <class A, class B>\nvoid copy%s(A * dest, B * src)\n{" % spelling)
|
||||
build_struct(c, True)
|
||||
print("}\n")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def copy_decl(c, spelling):
|
||||
children = [ch for ch in c.get_children()]
|
||||
if c.type.get_array_size() > 0:
|
||||
if c.type.get_array_element_type().spelling in structs:
|
||||
print(" for (int i=0; i<%d; i++) {" % c.type.get_array_size())
|
||||
print(" copy%s(&dest->%s[i], &src->%s[i]);" % (c.type.get_array_element_type().spelling, spelling, spelling))
|
||||
print(" }")
|
||||
else:
|
||||
print(" memcpy(dest->%s, src->%s, sizeof(dest->%s));" % (spelling, spelling, spelling))
|
||||
elif len(children) == 1 and children[0].kind == clang.cindex.CursorKind.STRUCT_DECL and not valid_spelling(children[0].spelling):
|
||||
# inline declared structs
|
||||
if valid_spelling(c.semantic_parent.spelling):
|
||||
spelling_func = c.semantic_parent.spelling + "_" + spelling
|
||||
else:
|
||||
spelling_func = c.semantic_parent.semantic_parent.spelling + "_" + spelling
|
||||
|
||||
extrastructs.append((children[0], spelling_func))
|
||||
print(" copy%s(&dest->%s, &src->%s);" % (spelling_func, spelling, spelling))
|
||||
elif c.type.get_declaration().spelling in structs:
|
||||
print(" copy%s(&dest->%s, &src->%s);" % (c.type.get_declaration().spelling, spelling, spelling))
|
||||
else:
|
||||
print(" dest->%s = src->%s;" % (spelling, spelling))
|
||||
|
||||
|
||||
def header():
|
||||
print("// This file was auto-generated by %s script on %s. Do not edit this file!\n\n\n" % (os.path.basename(sys.argv[0]), time.asctime()))
|
||||
|
||||
|
||||
def print_translation_unit_diags(diags, prefix=''):
|
||||
for diag in diags:
|
||||
print(prefix + str(diag), file=sys.stderr)
|
||||
print_translation_unit_diags(diag.children, ' ' + prefix)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
if not find_clang.initLibClang():
|
||||
sys.exit(-1)
|
||||
|
||||
index = find_clang.index
|
||||
args = ['-x', 'c++', '-std=c++11'] + sys.argv[2:]
|
||||
if find_clang.builtin_hdr_path:
|
||||
args.append("-I" + find_clang.builtin_hdr_path)
|
||||
|
||||
translation_unit = index.parse(sys.argv[1], args)
|
||||
|
||||
if translation_unit.diagnostics:
|
||||
print_translation_unit_diags(translation_unit.diagnostics)
|
||||
sys.exit(-1)
|
||||
|
||||
header()
|
||||
build(translation_unit.cursor)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,575 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import sys
|
||||
import find_clang
|
||||
|
||||
from clang.cindex import *
|
||||
|
||||
# debug
|
||||
import asciitree # must be version 0.2
|
||||
|
||||
# output
|
||||
import jinja2
|
||||
|
||||
DEBUG_ATTRS = ['layoutData','topbarData','widgetData']
|
||||
|
||||
#USE_FAKE_STRUCT = False
|
||||
USE_FAKE_STRUCT = True
|
||||
|
||||
def node_children(node):
|
||||
l = list(c for c in node.get_children() if c is not None)
|
||||
if len(l) > 0:
|
||||
return l
|
||||
|
||||
return []
|
||||
#decl = node.type.get_declaration()
|
||||
#return list(c for c in decl.get_children() if c is not None)
|
||||
|
||||
def print_node(node):
|
||||
text = node.spelling or node.displayname
|
||||
kind = str(node.kind)[str(node.kind).index('.')+1:]
|
||||
if CursorKind.FIELD_DECL == node.kind:
|
||||
size = node.type.get_size()
|
||||
return '{} {} {}'.format(kind, text, size)
|
||||
return '{} {}'.format(kind, text)
|
||||
|
||||
def dump_node(node):
|
||||
print(asciitree.draw_tree(node, node_children, print_node))
|
||||
|
||||
has_errors = False
|
||||
|
||||
def print_error(*args):
|
||||
print("ERROR:",*args,file=sys.stderr)
|
||||
has_errors = True
|
||||
|
||||
def print_debug(*args):
|
||||
print("DBG:",*args,file=sys.stderr)
|
||||
|
||||
def bail_out(*args):
|
||||
print_error(*args)
|
||||
sys.exit(-1)
|
||||
|
||||
_anon_cnt = 0
|
||||
|
||||
def get_next_anon():
|
||||
global _anon_cnt
|
||||
label = str(_anon_cnt)
|
||||
_anon_cnt = _anon_cnt + 1
|
||||
return label
|
||||
|
||||
SIGNED_TYPES = ['bool', 'char', 'short', 'int', 'long' ]
|
||||
|
||||
def map_type(type_name):
|
||||
if 'unsigned' in type_name:
|
||||
return 'unsigned'
|
||||
elif ('signed' in type_name) or (type_name in SIGNED_TYPES):
|
||||
return 'signed'
|
||||
|
||||
return type_name
|
||||
|
||||
def mangle_type(type_name):
|
||||
return type_name.replace(':','_')
|
||||
|
||||
# Cursor or Type
|
||||
def get_type(obj):
|
||||
if isinstance(obj,Cursor):
|
||||
return obj.type
|
||||
else:
|
||||
return obj
|
||||
|
||||
def is_string(type):
|
||||
if type.kind == TypeKind.CONSTANTARRAY:
|
||||
if type.element_type.spelling == 'char':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
class AST_Element:
|
||||
def __init__(self, name, cursor):
|
||||
self.name = name
|
||||
self.cursor = cursor
|
||||
self.elmts = []
|
||||
|
||||
def get_children(self):
|
||||
return self.cursor.get_children()
|
||||
|
||||
def get_elmts(self):
|
||||
return self.elmts
|
||||
|
||||
def append(self,elmt):
|
||||
if isinstance(elmt, list):
|
||||
self.elmts.extend(elmt)
|
||||
else:
|
||||
self.elmts.append(elmt)
|
||||
|
||||
def str(self):
|
||||
if hasattr(self,'value'):
|
||||
if hasattr(self,'ann'):
|
||||
return '{}:\t{} ({})'.format(self.name,self.value,self.ann)
|
||||
return '{}:\t{}'.format(self.name,self.value)
|
||||
elif hasattr(self,'type'):
|
||||
if hasattr(self,'var_type'):
|
||||
return '{} {}\t{}'.format(self.type, self.var_type, self.name)
|
||||
else:
|
||||
return '{}\t{}'.format(self.type, self.name)
|
||||
return self.name
|
||||
|
||||
class FieldAST(AST_Element):
|
||||
def __init__(self, name, cursor):
|
||||
super(FieldAST, self).__init__(name, cursor)
|
||||
|
||||
self.is_array = False
|
||||
self.func = 'NULL'
|
||||
|
||||
if self.name in DEBUG_ATTRS:
|
||||
#print("# field name={} type={} canon={} decl={}".format(self.name,cursor.type.spelling,cursor.type.get_canonical().spelling,str(cursor.type.kind)))
|
||||
#dump_node(cursor)
|
||||
pass
|
||||
|
||||
if isinstance(cursor,Cursor):
|
||||
t = cursor.type
|
||||
if cursor.is_bitfield():
|
||||
self.bits = cursor.get_bitfield_width()
|
||||
else:
|
||||
# cursor is a type...
|
||||
t = cursor
|
||||
|
||||
if not hasattr(self,'bits'):
|
||||
self.bits = t.get_size() * 8
|
||||
|
||||
if t.kind == TypeKind.TYPEDEF:
|
||||
self.type = map_type(t.get_canonical().spelling)
|
||||
elif t.kind == TypeKind.CONSTANTARRAY:
|
||||
self.type = t.element_type.spelling
|
||||
self.is_array = True
|
||||
self.length = t.element_count
|
||||
|
||||
if self.type == 'char':
|
||||
self.type = 'string'
|
||||
else:
|
||||
self.type = map_type(t.get_canonical().spelling)
|
||||
|
||||
|
||||
class StructAST(AST_Element):
|
||||
type = 'struct'
|
||||
|
||||
def __init__(self, name, cursor, alt_name=''):
|
||||
|
||||
self.var_name = name
|
||||
|
||||
if len(alt_name) > 0:
|
||||
name = alt_name
|
||||
|
||||
if name == '' or (isinstance(cursor,Cursor) and cursor.is_anonymous()):
|
||||
name = self.name_prefix() + 'anonymous_' + get_next_anon()
|
||||
else:
|
||||
name = self.name_prefix() + name
|
||||
|
||||
self.func = 'NULL'
|
||||
super(StructAST, self).__init__(name, cursor)
|
||||
|
||||
def name_prefix(self):
|
||||
return self.type + '_'
|
||||
|
||||
class UnionAST(StructAST):
|
||||
type = 'union'
|
||||
|
||||
class EnumAST(AST_Element):
|
||||
type = 'enum'
|
||||
|
||||
def __init__(self, name, cursor):
|
||||
self.var_name = name
|
||||
super(EnumAST, self).__init__('enum_' + name, cursor)
|
||||
|
||||
class AST:
|
||||
name = 'ROOT'
|
||||
|
||||
def __init__(self):
|
||||
self.structs = []
|
||||
self.enums = []
|
||||
|
||||
def has_enum(self,name):
|
||||
for e in self.enums:
|
||||
if e.name == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_enums(self):
|
||||
return self.enums
|
||||
|
||||
def get_structs(self):
|
||||
return self.structs
|
||||
|
||||
def has_struct(self,name):
|
||||
for s in self.structs:
|
||||
if s.name == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_struct(self,name):
|
||||
for s in self.structs:
|
||||
if s.name == name:
|
||||
return s
|
||||
return None
|
||||
|
||||
def get_elmts(self):
|
||||
return self.enums + self.structs
|
||||
|
||||
def append(self, elmt):
|
||||
if isinstance(elmt, StructAST):
|
||||
self.structs.append(elmt)
|
||||
elif isinstance(elmt, EnumAST):
|
||||
self.enums.append(elmt)
|
||||
|
||||
def str(self):
|
||||
return self.name
|
||||
|
||||
def parse_struct(ast, node, alt_name):
|
||||
st = None
|
||||
|
||||
if ast is not RootAST:
|
||||
ast.var_type = ast.type
|
||||
ast.type = 'struct'
|
||||
|
||||
st = StructAST(node.spelling, node, alt_name)
|
||||
if (ast is RootAST):
|
||||
old_st = RootAST.get_struct(st.name)
|
||||
if old_st is not None:
|
||||
return old_st
|
||||
|
||||
st.use_idx = False
|
||||
ann = get_annotations(node)
|
||||
if len(ann) > 0:
|
||||
#print(ann)
|
||||
for a in ann:
|
||||
if a['type'] == 'idx' and a['val'] == 'true':
|
||||
st.use_idx = True
|
||||
break
|
||||
|
||||
for c in node.get_children():
|
||||
parse_field(st,c)
|
||||
|
||||
if st is not ast:
|
||||
ast.append(st)
|
||||
|
||||
#print_debug("IDX ",st.name, " ", st.use_idx)
|
||||
return st
|
||||
|
||||
def parse_union(ast, node):
|
||||
st = None
|
||||
|
||||
if ast is not RootAST:
|
||||
ast.var_type = ast.type
|
||||
ast.type = 'union'
|
||||
|
||||
st = UnionAST(node.spelling, node)
|
||||
if (ast is RootAST):
|
||||
old_st = RootAST.get_struct(st.name)
|
||||
if old_st is not None:
|
||||
return old_st
|
||||
|
||||
for c in node.get_children():
|
||||
if c.kind == CursorKind.FIELD_DECL:
|
||||
parse_field(st,c)
|
||||
|
||||
ann = get_annotations(node)
|
||||
if len(ann) > 0:
|
||||
for a in ann:
|
||||
if a['type'] == 'func':
|
||||
st.func = a['val']
|
||||
|
||||
if st is not ast:
|
||||
ast.append(st)
|
||||
|
||||
return st
|
||||
|
||||
def get_annotations(node):
|
||||
l = list()
|
||||
for c in node.get_children():
|
||||
if c.kind == CursorKind.ANNOTATE_ATTR:
|
||||
ann = c.displayname.split(':')
|
||||
l.append({'type':ann[0], 'val':ann[1]})
|
||||
return l
|
||||
|
||||
def parse_field_record(f, node):
|
||||
alt_name = ''
|
||||
decl = node.type.get_declaration()
|
||||
|
||||
if not decl.spelling == '':
|
||||
alt_name = mangle_type(node.type.spelling)
|
||||
#print("alt_name = " + alt_name)
|
||||
|
||||
st = parse_node(RootAST,decl,alt_name)
|
||||
if st is not None:
|
||||
f.var_type = st.name
|
||||
f.var_name = alt_name
|
||||
f.type = st.type
|
||||
|
||||
def make_fake_array_struct(f, node_type, use_idx):
|
||||
|
||||
# if not USE_FAKE_STRUCT:
|
||||
# f.var_type = node_type.spelling
|
||||
# # if is_string(get_type(node_type)):
|
||||
# # f.type = 'array'
|
||||
# # f.length = get_type(node_type).element_count
|
||||
# return
|
||||
|
||||
field = FieldAST('val', node_type)
|
||||
#field.is_fake = True
|
||||
type_name = field.type + '_' + str(field.bits)
|
||||
struct_name = 'struct_' + type_name
|
||||
|
||||
if USE_FAKE_STRUCT and not RootAST.has_struct(struct_name):
|
||||
#print("# field created " + struct_name)
|
||||
st = StructAST(type_name, node_type)
|
||||
st.append(field)
|
||||
st.used_in_arrays = True
|
||||
st.use_idx = use_idx
|
||||
RootAST.append(st)
|
||||
|
||||
f.var_name = f.type
|
||||
f.type = 'array'
|
||||
f.var_type = struct_name
|
||||
#f.var_name = field.type
|
||||
|
||||
|
||||
def parse_field_array(f, node):
|
||||
et = node.type.element_type
|
||||
if f.type != 'string':
|
||||
elmt_decl = et.get_declaration()
|
||||
|
||||
use_idx = True
|
||||
ann = get_annotations(node)
|
||||
if len(ann) > 0:
|
||||
for a in ann:
|
||||
if a['type'] == 'idx' and a['val'] == 'false':
|
||||
use_idx = False
|
||||
elif a['type'] == 'raw':
|
||||
f.raw = a['val']
|
||||
|
||||
# let's see first if it's some kind of struct/union/enum
|
||||
elmt_st = parse_node(RootAST, elmt_decl)
|
||||
if elmt_st is not None:
|
||||
f.type = 'array'
|
||||
f.var_type = elmt_st.name
|
||||
f.var_name = elmt_st.var_name
|
||||
# mark array usage for unions
|
||||
elmt_st.used_in_arrays = True
|
||||
elmt_st.use_idx = use_idx
|
||||
elif elmt_decl.kind == CursorKind.TYPEDEF_DECL:
|
||||
# it's some typedef
|
||||
#print_error("TYPEDEF {} {}".format(f.name, elmt_decl.spelling));
|
||||
make_fake_array_struct(f, elmt_decl, use_idx)
|
||||
elif et.kind == TypeKind.CONSTANTARRAY:
|
||||
# it's an array:
|
||||
# let's create a fake struct with the element type
|
||||
#print_error("ARRAY {} {}".format(f.name, elmt_decl.spelling));
|
||||
make_fake_array_struct(f, et, use_idx)
|
||||
else:
|
||||
pass
|
||||
#print("# unknown array attr: {} {}".format(str(elmt_decl.kind), f.name))
|
||||
|
||||
|
||||
def parse_field(ast,node):
|
||||
|
||||
if (not node.is_anonymous()) and (node.kind != CursorKind.FIELD_DECL):
|
||||
return
|
||||
|
||||
f = FieldAST(node.spelling, node)
|
||||
|
||||
if node.type.kind in [TypeKind.ELABORATED, TypeKind.RECORD, TypeKind.ENUM]:
|
||||
parse_field_record(f, node)
|
||||
|
||||
elif node.type.kind == TypeKind.CONSTANTARRAY:
|
||||
parse_field_array(f, node)
|
||||
|
||||
ann = get_annotations(node)
|
||||
if len(ann) > 0:
|
||||
is_cust = False
|
||||
is_enum = False
|
||||
for a in ann:
|
||||
if a['type'] == 'enum':
|
||||
is_enum = True
|
||||
enum_name = 'enum_' + a['val']
|
||||
f.var_type = enum_name
|
||||
if not RootAST.has_enum(enum_name):
|
||||
parse_node(RootAST,get_top_node(a['val']))
|
||||
elif a['type'] == 'func':
|
||||
f.func = a['val']
|
||||
elif a['type'] == 'name':
|
||||
f.name = a['val']
|
||||
elif a['type'] == 'read':
|
||||
f.f_read = a['val']
|
||||
is_cust = True
|
||||
elif a['type'] == 'write':
|
||||
f.f_write = a['val']
|
||||
is_cust = True
|
||||
elif a['type'] == 'array':
|
||||
array_attrs = a['val'].split('|')
|
||||
elmt_size = int(array_attrs[0])
|
||||
f.var_type = array_attrs[1]
|
||||
f.type = 'array'
|
||||
f.length = int(f.bits / elmt_size)
|
||||
f.func = array_attrs[2]
|
||||
elif a['type'] == 'skip':
|
||||
f.skip = True
|
||||
|
||||
if is_enum and not is_cust:
|
||||
f.type = 'enum'
|
||||
|
||||
if len(f.name) == 0:
|
||||
print_error("in '{}', field of type '{}' does not have a name"
|
||||
.format(ast.name,f.var_type))
|
||||
return
|
||||
|
||||
ast.append(f)
|
||||
|
||||
|
||||
def parse_enum_field(ast,node):
|
||||
|
||||
ann = get_annotations(node)
|
||||
if len(ann) > 0:
|
||||
for a in ann:
|
||||
if a['type'] == 'skip':
|
||||
return
|
||||
|
||||
enum_value = node.spelling
|
||||
if '_' in enum_value:
|
||||
enum_value = enum_value[enum_value.index('_')+1:]
|
||||
|
||||
st = AST_Element(enum_value, node)
|
||||
st.value = node.spelling #node.enum_value
|
||||
ast.append(st)
|
||||
# debug
|
||||
if len(ann) > 0:
|
||||
#print(ann)
|
||||
st.ann = ann
|
||||
|
||||
def parse_enum(ast,node):
|
||||
st = EnumAST(node.spelling or node.displayname, node)
|
||||
for c in node.get_children():
|
||||
parse_enum_field(st,c)
|
||||
|
||||
ast.append(st)
|
||||
return st
|
||||
|
||||
def parse_node(ast,node,alt_name=''):
|
||||
st = None
|
||||
|
||||
if node.kind in [CursorKind.STRUCT_DECL,CursorKind.CLASS_DECL]:
|
||||
st = parse_struct(ast,node,alt_name)
|
||||
elif node.kind == CursorKind.UNION_DECL:
|
||||
st = parse_union(ast,node)
|
||||
elif node.kind == CursorKind.FIELD_DECL:
|
||||
parse_field(ast,node)
|
||||
elif node.kind == CursorKind.ENUM_DECL:
|
||||
st = parse_enum(ast,node)
|
||||
else:
|
||||
pass
|
||||
|
||||
return st
|
||||
|
||||
### main ###
|
||||
|
||||
def get_top_node(name):
|
||||
node = translation_unit.cursor
|
||||
for c in node.get_children():
|
||||
if c.spelling == name:
|
||||
# struct found
|
||||
return c.get_definition()
|
||||
|
||||
bail_out(f"'{name}' not found")
|
||||
|
||||
def ast_children(ast_node):
|
||||
if ast_node is not None:
|
||||
return ast_node.get_elmts()
|
||||
return []
|
||||
|
||||
def print_ast_node(ast_node):
|
||||
#if isinstance(ast_node,dict):
|
||||
# return str(ast_node)
|
||||
return ast_node.str()
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
bail_out(f"usage: {sys.argv[0]} [header file name] [template] [node name] [additional compile args]")
|
||||
|
||||
if not find_clang.initLibClang():
|
||||
sys.exit(-1)
|
||||
|
||||
index = find_clang.index
|
||||
args = ['-x', 'c++', '-std=c++11', '-Wno-deprecated-register'] + sys.argv[4:]
|
||||
if find_clang.builtin_hdr_path:
|
||||
args.append("-I" + find_clang.builtin_hdr_path)
|
||||
|
||||
translation_unit = index.parse(sys.argv[1], args)
|
||||
|
||||
def show_tu_diags(diags, prefix=''):
|
||||
tu_errors = 0
|
||||
for diag in diags:
|
||||
tu_errors = tu_errors + 1
|
||||
print_error(prefix + str(diag))
|
||||
show_tu_diags(diag.children, ' ' + prefix)
|
||||
return tu_errors
|
||||
|
||||
tu_errors = show_tu_diags(translation_unit.diagnostics)
|
||||
if tu_errors > 0:
|
||||
bail_out("{} error(s) while compiling '{}'".format(tu_errors, sys.argv[1]))
|
||||
|
||||
RootAST = AST()
|
||||
|
||||
root_nodes_name = ''
|
||||
top_node_names = sys.argv[3].split(',')
|
||||
# cycle on top nodes:
|
||||
for tn in top_node_names:
|
||||
top_node = get_top_node(tn)
|
||||
#dump_node(top_node)
|
||||
parse_node(RootAST, top_node)
|
||||
if len(root_nodes_name) > 0:
|
||||
root_nodes_name = root_nodes_name + '_' + tn
|
||||
else:
|
||||
root_nodes_name = tn
|
||||
|
||||
# Do not generate anything we had some errors
|
||||
if has_errors:
|
||||
sys.exit(-1)
|
||||
|
||||
#print("Enums:", RootAST.get_enums())
|
||||
#print("Structs:", RootAST.get_structs())
|
||||
#print(asciitree.draw_tree(RootAST, ast_children, print_ast_node))
|
||||
|
||||
#
|
||||
# Template rendering
|
||||
#
|
||||
|
||||
__max_str_len = 0
|
||||
|
||||
def max_len(str):
|
||||
global __max_str_len
|
||||
if len(str) > __max_str_len:
|
||||
__max_str_len = len(str)
|
||||
return str
|
||||
|
||||
def get_max_len():
|
||||
global __max_str_len
|
||||
return __max_str_len
|
||||
|
||||
def max_bits(struct):
|
||||
bits = 0
|
||||
for s in struct.get_elmts():
|
||||
if s.bits > bits:
|
||||
bits = s.bits
|
||||
return bits
|
||||
|
||||
def padding_bits(array):
|
||||
array_bits = (array.bits // array.length) * array.length
|
||||
return array.bits - array_bits
|
||||
|
||||
template = jinja2.Template(open(sys.argv[2]).read(), lstrip_blocks=True, trim_blocks=True)
|
||||
|
||||
template.globals['max_len'] = max_len
|
||||
template.globals['get_max_len'] = get_max_len
|
||||
template.globals['max_bits'] = max_bits
|
||||
template.globals['padding_bits'] = padding_bits
|
||||
|
||||
## fixme: root_node_name needs to be mangled (contains ',')
|
||||
print(template.render(root=RootAST,root_nodes=top_node_names,root_node_name=root_nodes_name))
|
||||
@@ -0,0 +1,18 @@
|
||||
# Hardware Definitions
|
||||
|
||||
The Python scripts in this directory are responsible for generating different
|
||||
include files used to describe the hardware to the software.
|
||||
|
||||
## Data model
|
||||
|
||||
The data model supported is described `models.py`. A script
|
||||
(`json_validator.py`) is available that validates the JSON files based on this
|
||||
model.
|
||||
|
||||
## Code generator
|
||||
|
||||
The various include files are generated based on Jinja2 templates and `generator.py`
|
||||
provided with a JSON target definition.
|
||||
|
||||
`legacy_names.py` contains some hard-coded definitions providing additional
|
||||
information related to analog inputs (by target; mostly names and labels).
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#from os import path
|
||||
|
||||
import argparse
|
||||
|
||||
from hal_json import parse_defines
|
||||
from generator import generate_from_template
|
||||
|
||||
# def eprint(*args, **kwargs):
|
||||
# print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser(description='Process hardware definitions')
|
||||
parser.add_argument('filename', metavar='filename', nargs='+')
|
||||
parser.add_argument('-i', metavar='input', choices=['json','defines'], default='json')
|
||||
parser.add_argument('-t', metavar='template')
|
||||
parser.add_argument('-T', metavar='target')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.i == 'defines':
|
||||
for filename in args.filename:
|
||||
parse_defines(filename, args.T)
|
||||
|
||||
elif args.i == 'json':
|
||||
for filename in args.filename:
|
||||
generate_from_template(filename, args.t, args.T)
|
||||
@@ -0,0 +1,102 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import jinja2
|
||||
import pydantic
|
||||
|
||||
import legacy_names
|
||||
import json_index
|
||||
|
||||
from models import HardwareDefinition, KeyEnum
|
||||
|
||||
MAIN_CONTROL_LUT = {
|
||||
# 2 Gimbal radios
|
||||
"LH": {"str": "Rud", "local": "STR_STICK_NAMES0"},
|
||||
"LV": {"str": "Ele", "local": "STR_STICK_NAMES1"},
|
||||
"RV": {"str": "Thr", "local": "STR_STICK_NAMES2"},
|
||||
"RH": {"str": "Ail", "local": "STR_STICK_NAMES3"},
|
||||
# Surface radios
|
||||
"ST": {"str": "ST", "local": "STR_SURFACE_NAMES0"},
|
||||
"TH": {"str": "TH", "local": "STR_SURFACE_NAMES1"},
|
||||
}
|
||||
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def is_ext_input(input):
|
||||
if str(getattr(input, "type", "")) != "FLEX":
|
||||
return False
|
||||
|
||||
name = str(getattr(input, "name", ""))
|
||||
return name.startswith("EXT")
|
||||
|
||||
|
||||
def generate_from_template(json_filename, template_filename, target):
|
||||
with open(json_filename) as json_file:
|
||||
raw_data = json_file.read()
|
||||
|
||||
# Validate using Pydantic model
|
||||
try:
|
||||
hw_def = HardwareDefinition.from_json(raw_data)
|
||||
except pydantic.ValidationError as e:
|
||||
eprint(f"ERROR validating '{json_filename}' (target={target}):")
|
||||
for err in e.errors():
|
||||
loc = " -> ".join(str(l) for l in err["loc"])
|
||||
eprint(f" {loc}: {err['msg']}")
|
||||
sys.exit(1)
|
||||
|
||||
# Load remaining fields not yet in the Pydantic model
|
||||
root_obj = json.loads(raw_data)
|
||||
|
||||
adc_index = json_index.build_adc_index(hw_def.adc_inputs)
|
||||
adc_gpios = json_index.build_adc_gpio_port_index(hw_def.adc_inputs)
|
||||
switch_gpios = json_index.build_switch_gpio_port_index(hw_def.switches)
|
||||
key_gpios = json_index.build_key_gpio_port_index(hw_def.keys)
|
||||
|
||||
trims = root_obj.get("trims")
|
||||
trim_gpios = json_index.build_trim_gpio_port_index(trims)
|
||||
|
||||
legacy_inputs = legacy_names.inputs_by_target(target)
|
||||
|
||||
template_dir = os.path.dirname(os.path.abspath(template_filename))
|
||||
template_name = os.path.basename(template_filename)
|
||||
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader(template_dir),
|
||||
lstrip_blocks=True,
|
||||
trim_blocks=True,
|
||||
)
|
||||
|
||||
env.tests["ext_input"] = is_ext_input
|
||||
|
||||
template = env.get_template(template_name)
|
||||
|
||||
key_index = list([str(i) for i in KeyEnum])
|
||||
|
||||
context = dict(
|
||||
adc_inputs=hw_def.adc_inputs,
|
||||
switches=hw_def.switches,
|
||||
keys=hw_def.keys,
|
||||
trims=trims,
|
||||
adc_index=adc_index,
|
||||
adc_gpios=adc_gpios,
|
||||
switch_gpios=switch_gpios,
|
||||
key_gpios=key_gpios,
|
||||
trim_gpios=trim_gpios,
|
||||
legacy_inputs=legacy_inputs,
|
||||
main_labels=MAIN_CONTROL_LUT,
|
||||
key_index=key_index,
|
||||
)
|
||||
|
||||
try:
|
||||
print(template.render(context))
|
||||
except jinja2.UndefinedError as e:
|
||||
eprint(f"ERROR rendering template '{template_name}'"
|
||||
f" with json='{json_filename}', target='{target}':")
|
||||
eprint(f" {e}")
|
||||
none_keys = [k for k, v in context.items() if v is None]
|
||||
if none_keys:
|
||||
eprint(f" None-valued context keys: {none_keys}")
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set main_inputs = adc_inputs.inputs | selectattr('type', '==', 'STICK') | list %}
|
||||
{% set n_mains = main_inputs | count %}
|
||||
static const etx_hal_adc_input_t _main_inputs[] = {
|
||||
{% for input in main_inputs %}
|
||||
{% set label = main_labels[input.name] %}
|
||||
{ "{{ input.name }}", "{{ label.str }}", {{ label.local }} },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% set flex_offset = n_mains %}
|
||||
{% set flex_inputs = adc_inputs.inputs | selectattr('type', '==', 'FLEX') | list %}
|
||||
{% set n_flex = flex_inputs | count %}
|
||||
static const etx_hal_adc_input_t _flex_inputs[] = {
|
||||
{% for input in flex_inputs %}
|
||||
{ "{{ input.name }}", "{{ input.label }}", "{{ input.short_label }}" },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% set raw_offset = flex_offset + n_flex %}
|
||||
{% set raw_inputs = adc_inputs.inputs | selectattr('type', '==', 'RAW') | list %}
|
||||
{% set n_raw = raw_inputs | count %}
|
||||
static const etx_hal_adc_input_t _raw_inputs[] = {
|
||||
{% for input in raw_inputs %}
|
||||
{ "{{ input.name }}", "{{ input.label }}", "{{ input.short_label }}" },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% set vbat_offset = raw_offset + n_raw %}
|
||||
{% set vbat_inputs = adc_inputs.inputs | selectattr('type', '==', 'VBAT') | list %}
|
||||
{% set n_vbat = vbat_inputs | count %}
|
||||
static const etx_hal_adc_input_t _vbat_inputs[] = {
|
||||
{% for input in vbat_inputs %}
|
||||
{ "{{ input.name }}", nullptr, nullptr },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% set rtc_bat_offset = vbat_offset + n_vbat %}
|
||||
{% set rtc_bat_inputs = adc_inputs.inputs | selectattr('type', '==', 'RTC_BAT') | list %}
|
||||
{% set n_rtc_bat = rtc_bat_inputs | count %}
|
||||
static const etx_hal_adc_input_t _rtc_bat_inputs[] = {
|
||||
{% for input in rtc_bat_inputs %}
|
||||
{ "{{ input.name }}", nullptr, nullptr },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% set lux_offset = rtc_bat_offset + n_rtc_bat %}
|
||||
{% set lux_inputs = adc_inputs.inputs | selectattr('type', '==', 'LUX') | list %}
|
||||
{% set n_lux = lux_inputs | count %}
|
||||
static const etx_hal_adc_input_t _lux_inputs[] = {
|
||||
{% for input in lux_inputs %}
|
||||
{ "{{ input.name }}", nullptr, nullptr },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% set n_inputs = lux_offset + n_lux %}
|
||||
static const etx_hal_adc_inputs_t _hal_inputs[] = {
|
||||
{ {{ n_mains }}, 0, _main_inputs },
|
||||
{ {{ n_flex }}, {{ flex_offset }}, _flex_inputs },
|
||||
{ {{ n_vbat }}, {{ vbat_offset }}, _vbat_inputs },
|
||||
{ {{ n_rtc_bat }}, {{ rtc_bat_offset }}, _rtc_bat_inputs },
|
||||
{ {{ n_lux }}, {{ lux_offset }}, _lux_inputs },
|
||||
{ {{ n_inputs }}, 0, nullptr },
|
||||
};
|
||||
|
||||
constexpr potconfig_t _pot_default_config = (0)
|
||||
{% for flex in flex_inputs %}
|
||||
{% if flex.default %}
|
||||
| ((potconfig_t)FLEX_{{ flex.default }} << ({{ loop.index0 }} * POT_CFG_BITS))
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
;
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
class CFS:
|
||||
|
||||
def __init__(self, cfs_rgb_led, cfs_groups):
|
||||
self.rgb_led = cfs_rgb_led
|
||||
self.groups = cfs_groups
|
||||
|
||||
def parse_cfs(hw_defs):
|
||||
|
||||
cfs_rgb_led = 0
|
||||
cfs_groups = 0
|
||||
|
||||
fcfs = f'FUNCTION_SWITCHES'
|
||||
frgb = f'FUNCTION_SWITCHES_RGB_LEDS'
|
||||
|
||||
if fcfs in hw_defs:
|
||||
if frgb in hw_defs:
|
||||
cfs_rgb_led = 1
|
||||
if f'RADIO_GX12' in hw_defs:
|
||||
cfs_groups = 4
|
||||
elif f'RADIO_PA01' in hw_defs:
|
||||
cfs_groups = 2
|
||||
else:
|
||||
cfs_groups = 3
|
||||
|
||||
return CFS(cfs_rgb_led, cfs_groups)
|
||||
@@ -0,0 +1,78 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
#
|
||||
# Return a file handle or STDIN
|
||||
#
|
||||
def open_file(filename):
|
||||
if filename and not filename == "-":
|
||||
return open(filename)
|
||||
else:
|
||||
return sys.stdin
|
||||
|
||||
|
||||
#
|
||||
# Read lines of defines into a dictionary
|
||||
#
|
||||
def parse_hw_defs(filename):
|
||||
hw_defs = {}
|
||||
|
||||
with open_file(filename) as file:
|
||||
for line in file.readlines():
|
||||
m = re.match(r"#define ([^\s]*)\s*(.*)", line.rstrip())
|
||||
if m:
|
||||
name = m.group(1)
|
||||
value = m.group(2)
|
||||
if value.isnumeric():
|
||||
value = int(value)
|
||||
elif not value:
|
||||
value = None
|
||||
hw_defs[name] = value
|
||||
|
||||
return hw_defs
|
||||
|
||||
|
||||
def prune_dict(d):
|
||||
# ret = {}
|
||||
# for k, v in d.items():
|
||||
# if v is not None:
|
||||
# ret[k] = v
|
||||
# return ret
|
||||
return d
|
||||
|
||||
|
||||
# class DictEncoder(json.JSONEncoder):
|
||||
# def default(self, o):
|
||||
# if isinstance(o, Switch):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, ADCInput):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, SPI_ADCInput):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, ADC):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, Trim):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, Key):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, Display):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, CFS):
|
||||
# return prune_dict(o.__dict__)
|
||||
# if isinstance(o, Misc):
|
||||
# return prune_dict(o.__dict__)
|
||||
|
||||
# # Let the base class default method raise the TypeError
|
||||
# return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
#
|
||||
# Parse HAL defines into JSON
|
||||
#
|
||||
def parse_defines(filename, target):
|
||||
# hw_defs = LoggingDict(parse_hw_defs(filename))
|
||||
# out_defs = {}
|
||||
#
|
||||
# print(json.dumps(out_defs, cls=DictEncoder, indent=2))
|
||||
pass
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
const char* const _key_labels[] = {
|
||||
{% for k in key_index %}
|
||||
{% set key = keys | selectattr("key","==",k) | first %}
|
||||
{% if key %}
|
||||
"{{ key.label }}",
|
||||
{% else %}
|
||||
nullptr,
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
constexpr uint32_t _defined_keys = 0
|
||||
{% for key in keys %}
|
||||
| (1 << {{ key.key }})
|
||||
{% endfor %}
|
||||
;
|
||||
|
||||
constexpr uint8_t _n_keys = {{ keys | length }};
|
||||
constexpr uint8_t _n_trims = {{ trims | length }};
|
||||
|
||||
static_assert(DIM(_key_labels) == MAX_KEYS, "wrong size _key_labels[]");
|
||||
|
||||
static_assert(_n_keys <= MAX_KEYS, "too many keys defined");
|
||||
static_assert(_n_trims <= MAX_TRIMS, "too many trims defined");
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
class Display:
|
||||
|
||||
def __init__(self, w, h, phys_w, phys_h, depth, color, oled, bl_color):
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.phys_w = phys_w
|
||||
self.phys_h = phys_h
|
||||
self.depth = depth
|
||||
self.color = color
|
||||
self.oled = oled
|
||||
self.backlight_color = bl_color
|
||||
|
||||
def parse_lcd(hw_defs):
|
||||
|
||||
fw = f'LCD_W'
|
||||
fh = f'LCD_H'
|
||||
fphys_w = f'LCD_PHYS_W'
|
||||
fphys_h = f'LCD_PHYS_H'
|
||||
fdepth = f'LCD_DEPTH'
|
||||
foled = f'OLED_SCREEN'
|
||||
fbl_color = f'HAS_BACKLIGHT_COLOR'
|
||||
|
||||
w = hw_defs[fw]
|
||||
h = hw_defs[fh]
|
||||
if fphys_w in hw_defs:
|
||||
phys_w = hw_defs[fphys_w]
|
||||
else:
|
||||
phys_w = w
|
||||
if fphys_h in hw_defs:
|
||||
phys_h = hw_defs[fphys_h]
|
||||
else:
|
||||
phys_h = h
|
||||
depth = hw_defs[fdepth]
|
||||
|
||||
if phys_w == fw:
|
||||
phys_w = w
|
||||
if phys_w == fh:
|
||||
phys_w = h
|
||||
if phys_h == fh:
|
||||
phys_h = h
|
||||
if phys_h == fw:
|
||||
phys_h = w
|
||||
|
||||
if foled in hw_defs:
|
||||
oled = 1
|
||||
else:
|
||||
oled = 0
|
||||
|
||||
if depth < 16:
|
||||
color = 0
|
||||
else:
|
||||
color = 1
|
||||
|
||||
if fbl_color in hw_defs:
|
||||
bl_color = 1
|
||||
else:
|
||||
bl_color = 0
|
||||
|
||||
return Display(w, h, phys_w, phys_h, depth, color, oled, bl_color)
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
class Misc:
|
||||
|
||||
def __init__(self, has_audio_mute, has_bling_leds, has_ext_module_support, has_int_module_support, sport_max_baudrate, surface, cpu, cpu_type):
|
||||
self.has_audio_mute = has_audio_mute
|
||||
self.has_bling_leds = has_bling_leds
|
||||
self.has_ext_module_support = has_ext_module_support
|
||||
self.has_int_module_support = has_int_module_support
|
||||
self.sport_max_baudrate = sport_max_baudrate
|
||||
self.surface = surface
|
||||
self.cpu = cpu
|
||||
self.cpu_type = cpu_type
|
||||
|
||||
def parse_misc(hw_defs):
|
||||
|
||||
if f'RADIO_MT12' in hw_defs:
|
||||
surface = 1
|
||||
else:
|
||||
surface = 0
|
||||
|
||||
if f'SPORT_MAX_BAUDRATE' in hw_defs:
|
||||
sport_max_baudrate = hw_defs[f'SPORT_MAX_BAUDRATE']
|
||||
else:
|
||||
sport_max_baudrate = 400000
|
||||
|
||||
if f'AUDIO_MUTE_GPIO' in hw_defs:
|
||||
has_audio_mute = 1
|
||||
else:
|
||||
has_audio_mute = 0
|
||||
|
||||
if f'BLING_LED_STRIP_LENGTH' in hw_defs:
|
||||
has_bling_leds = hw_defs[f'BLING_LED_STRIP_LENGTH']
|
||||
else:
|
||||
has_bling_leds = 0
|
||||
|
||||
if f'RADIO_T8' in hw_defs:
|
||||
has_ext_module_support = 0
|
||||
else:
|
||||
has_ext_module_support = 1
|
||||
|
||||
if f'PCBX9D' in hw_defs or f'PCBX9DP' in hw_defs or f'PCBX9E' in hw_defs:
|
||||
has_int_module_support = 0
|
||||
else:
|
||||
has_int_module_support = 1
|
||||
|
||||
if f'CPU_TYPE_FULL' in hw_defs:
|
||||
cpu = hw_defs[f'CPU_TYPE_FULL']
|
||||
else:
|
||||
cpu = f'Unknown'
|
||||
|
||||
if f'CPU_TYPE' in hw_defs:
|
||||
cpu_type = hw_defs[f'CPU_TYPE']
|
||||
else:
|
||||
cpu_type = f'Unknown'
|
||||
|
||||
return Misc(has_audio_mute, has_bling_leds, has_ext_module_support, has_int_module_support, sport_max_baudrate, surface, cpu, cpu_type)
|
||||
@@ -0,0 +1,92 @@
|
||||
#
|
||||
# These methods are used to build helper indexes on data structures
|
||||
#
|
||||
def build_adc_index(adc_inputs):
|
||||
i = 0
|
||||
index = {}
|
||||
for adc_input in adc_inputs.inputs:
|
||||
index[str(adc_input.name)] = i
|
||||
i = i + 1
|
||||
|
||||
return index
|
||||
|
||||
|
||||
def append_to_index(d, key, val):
|
||||
if key not in d:
|
||||
d[key] = []
|
||||
|
||||
d[key].append(val)
|
||||
|
||||
|
||||
def build_adc_gpio_port_index(adc_inputs):
|
||||
i = 0
|
||||
gpios = {}
|
||||
for adc_input in adc_inputs.inputs:
|
||||
if str(adc_input.adc) == "SPI":
|
||||
continue
|
||||
|
||||
gpio = getattr(adc_input, "gpio", None)
|
||||
if gpio is None:
|
||||
i = i + 1
|
||||
continue
|
||||
|
||||
if gpio not in gpios:
|
||||
gpios[gpio] = []
|
||||
|
||||
pin = {"pin": adc_input.pin, "idx": i}
|
||||
|
||||
gpios[gpio].append(pin)
|
||||
i = i + 1
|
||||
|
||||
return gpios
|
||||
|
||||
|
||||
def build_switch_gpio_port_index(switches):
|
||||
gpios = {}
|
||||
for switch in switches:
|
||||
sw_type = str(switch.type)
|
||||
|
||||
if sw_type == "2POS" or sw_type == "FSWITCH":
|
||||
gpio = switch.gpio
|
||||
pin = switch.pin
|
||||
if gpio is not None and pin is not None:
|
||||
append_to_index(gpios, gpio, pin)
|
||||
|
||||
elif sw_type == "3POS":
|
||||
gpio_high = switch.gpio_high
|
||||
pin_high = switch.pin_high
|
||||
if gpio_high is not None and pin_high is not None:
|
||||
append_to_index(gpios, gpio_high, pin_high)
|
||||
|
||||
gpio_low = switch.gpio_low
|
||||
pin_low = switch.pin_low
|
||||
if gpio_low is not None and pin_low is not None:
|
||||
append_to_index(gpios, gpio_low, pin_low)
|
||||
|
||||
return gpios
|
||||
|
||||
|
||||
def build_trim_gpio_port_index(trims):
|
||||
def index_contact(gpios, contact):
|
||||
gpio = contact["gpio"]
|
||||
pin = contact["pin"]
|
||||
if gpio and pin:
|
||||
append_to_index(gpios, contact["gpio"], contact["pin"])
|
||||
|
||||
gpios = {}
|
||||
for trim in trims:
|
||||
dec = trim.get("dec")
|
||||
inc = trim.get("inc")
|
||||
if dec and inc:
|
||||
index_contact(gpios, dec)
|
||||
index_contact(gpios, inc)
|
||||
|
||||
return gpios
|
||||
|
||||
|
||||
def build_key_gpio_port_index(keys):
|
||||
gpios = {}
|
||||
for key in keys:
|
||||
append_to_index(gpios, key.gpio, key.pin)
|
||||
|
||||
return gpios
|
||||
@@ -0,0 +1,116 @@
|
||||
from json import JSONDecodeError
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
from typing_extensions import Type
|
||||
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
|
||||
def validate_json_files(
|
||||
directory: str, model_class: Type[BaseModel]
|
||||
) -> Tuple[List[str], List[Tuple[str, str]]]:
|
||||
"""
|
||||
Validate all JSON files in a directory against a Pydantic model.
|
||||
|
||||
Args:
|
||||
directory: Path to the directory containing JSON files
|
||||
model_class: Pydantic model class to validate against
|
||||
|
||||
Returns:
|
||||
Tuple of (valid_files, invalid_files_with_errors)
|
||||
"""
|
||||
directory_path = Path(directory)
|
||||
|
||||
if not directory_path.exists():
|
||||
raise FileNotFoundError(f"Directory {directory} does not exist")
|
||||
|
||||
valid_files = []
|
||||
invalid_files = []
|
||||
|
||||
# Find all JSON files in the directory
|
||||
json_files = list(directory_path.glob("*.json"))
|
||||
|
||||
if not json_files:
|
||||
print(f"No JSON files found in {directory}")
|
||||
return valid_files, invalid_files
|
||||
|
||||
print(f"Found {len(json_files)} JSON files to validate")
|
||||
|
||||
for json_file in json_files:
|
||||
try:
|
||||
# Read the JSON file
|
||||
with open(json_file, "r", encoding="utf-8") as f:
|
||||
json_data = f.read()
|
||||
|
||||
# Validate against given model
|
||||
model_class.model_validate_json(json_data)
|
||||
|
||||
valid_files.append(str(json_file))
|
||||
print(f"✓ {json_file.name} - Valid")
|
||||
|
||||
except ValidationError as e:
|
||||
error_msg = str(e)
|
||||
invalid_files.append((str(json_file), error_msg))
|
||||
print(f"✗ {json_file.name} - Validation Error:")
|
||||
print(f" {error_msg}")
|
||||
|
||||
except JSONDecodeError as e:
|
||||
error_msg = f"Invalid JSON syntax: {e}"
|
||||
invalid_files.append((str(json_file), error_msg))
|
||||
print(f"✗ {json_file.name} - JSON Decode Error:")
|
||||
print(f" {error_msg}")
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Unexpected error: {e}"
|
||||
invalid_files.append((str(json_file), error_msg))
|
||||
print(f"✗ {json_file.name} - Unexpected Error:")
|
||||
print(f" {error_msg}")
|
||||
|
||||
return valid_files, invalid_files
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to run the validation"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Validate JSON files against HardwareDefinition model"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", action="store_true", help="Show detailed error messages"
|
||||
)
|
||||
parser.add_argument(
|
||||
"directory", help="Path to directory containing JSON files to validate"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
from models import HardwareDefinition
|
||||
|
||||
valid_files, invalid_files = validate_json_files(
|
||||
args.directory, HardwareDefinition
|
||||
)
|
||||
|
||||
print("\n=== Validation Summary ===")
|
||||
print(f"Total files processed: {len(valid_files) + len(invalid_files)}")
|
||||
print(f"Valid files: {len(valid_files)}")
|
||||
print(f"Invalid files: {len(invalid_files)}")
|
||||
|
||||
if invalid_files:
|
||||
print("\nInvalid files:")
|
||||
for file_path, error in invalid_files:
|
||||
if args.verbose:
|
||||
print(f" - {Path(file_path).name}: {error}")
|
||||
else:
|
||||
print(f" - {Path(file_path).name}")
|
||||
|
||||
return 0 if not invalid_files else 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during validation: {e}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,98 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Iterator, KeysView, Optional, ValuesView, ItemsView
|
||||
|
||||
|
||||
class LoggingDict:
|
||||
"""A dictionary wrapper that logs all lookups to stderr."""
|
||||
|
||||
def __init__(self, data: Optional[Dict[Any, Any]] = None):
|
||||
self._data = data if data is not None else {}
|
||||
|
||||
def __getitem__(self, key: Any) -> Any:
|
||||
"""Log the lookup and return the value."""
|
||||
print(f"{str(key)}", file=sys.stderr)
|
||||
return self._data[key]
|
||||
|
||||
def __setitem__(self, key: Any, value: Any) -> None:
|
||||
"""Set an item in the dictionary."""
|
||||
self._data[key] = value
|
||||
|
||||
def __delitem__(self, key: Any) -> None:
|
||||
"""Delete an item from the dictionary."""
|
||||
del self._data[key]
|
||||
|
||||
def __contains__(self, key: Any) -> bool:
|
||||
"""Check if key exists (this is also a lookup, so log it)."""
|
||||
print(f"{str(key)}", file=sys.stderr)
|
||||
return key in self._data
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Return the length of the dictionary."""
|
||||
return len(self._data)
|
||||
|
||||
def __iter__(self) -> Iterator:
|
||||
"""Return an iterator over the keys."""
|
||||
return iter(self._data)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return a string representation."""
|
||||
return f"LoggingDict({self._data})"
|
||||
|
||||
def get(self, key: Any, default: Any = None) -> Any:
|
||||
"""Get a value with optional default (logs the lookup)."""
|
||||
print(f"{str(key)}", file=sys.stderr)
|
||||
return self._data.get(key, default)
|
||||
|
||||
def keys(self) -> KeysView:
|
||||
"""Return dictionary keys."""
|
||||
return self._data.keys()
|
||||
|
||||
def values(self) -> ValuesView:
|
||||
"""Return dictionary values."""
|
||||
return self._data.values()
|
||||
|
||||
def items(self) -> ItemsView:
|
||||
"""Return dictionary items."""
|
||||
return self._data.items()
|
||||
|
||||
def update(self, other: Dict[Any, Any]) -> None:
|
||||
"""Update the dictionary with another dictionary."""
|
||||
self._data.update(other)
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Clear all items from the dictionary."""
|
||||
self._data.clear()
|
||||
|
||||
def pop(self, key: Any, default: Any = None) -> Any:
|
||||
"""Remove and return a value (logs the lookup)."""
|
||||
print(f"{str(key)}", file=sys.stderr)
|
||||
if default is None:
|
||||
return self._data.pop(key)
|
||||
return self._data.pop(key, default)
|
||||
|
||||
def setdefault(self, key: Any, default: Any = None) -> Any:
|
||||
"""Get a value or set/return default (logs the lookup)."""
|
||||
print(f"{str(key)}", file=sys.stderr)
|
||||
return self._data.setdefault(key, default)
|
||||
|
||||
|
||||
# Example usage
|
||||
if __name__ == "__main__":
|
||||
# Create a logging dictionary
|
||||
d = LoggingDict({"a": 1, "b": 2, "c": 3})
|
||||
|
||||
# These operations will be logged to stderr
|
||||
print("Value of 'a':", d["a"])
|
||||
print("Value of 'b':", d.get("b"))
|
||||
print("Does 'c' exist?", "c" in d)
|
||||
print("Does 'd' exist?", "d" in d)
|
||||
|
||||
# Add new items
|
||||
d["d"] = 4
|
||||
d["e"] = 5
|
||||
|
||||
# More logged lookups
|
||||
print("Value of 'd':", d["d"])
|
||||
print("Popped 'e':", d.pop("e"))
|
||||
|
||||
print("Final dictionary:", d)
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% macro lua_input(first, offset, input) %}
|
||||
{% set li = legacy_inputs[input.name] %}
|
||||
{ {{ first }} + {{ offset }}, "{{ li.lua }}", "{{ li.description }}" },
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro lua_inputs(first, inputs) %}
|
||||
{% for input in inputs %}
|
||||
{{ lua_input(first, loop.index0, input) }}
|
||||
{% endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
static const LuaSingleField _lua_inputs[] = {
|
||||
// main inputs
|
||||
{% set main_inputs = adc_inputs.inputs | selectattr('type', '==', 'STICK') | list %}
|
||||
{{ lua_inputs('MIXSRC_FIRST_STICK', main_inputs) }}
|
||||
// flex inputs
|
||||
{% set inputs = adc_inputs.inputs | selectattr('type', '==', 'FLEX') | list %}
|
||||
{{ lua_inputs('MIXSRC_FIRST_POT', inputs) }}
|
||||
// switches
|
||||
{% set inputs = switches | selectattr('type','!=','FSWITCH') | list %}
|
||||
{% set sw_count = inputs | count %}
|
||||
{% for n in range(sw_count) %}
|
||||
{% set sw = switches[loop.index0] %}
|
||||
{ MIXSRC_FIRST_SWITCH + {{ loop.index0 }}, "{{ sw.name }}", "{{ sw.name }}" },
|
||||
{% endfor %}
|
||||
// trims
|
||||
{% set trims_count = trims | count %}
|
||||
{% for n in range(trims_count) %}
|
||||
{% if n < (main_inputs | length) %}
|
||||
{% set input = main_inputs[loop.index0] %}
|
||||
{% set li = legacy_inputs[input.name] %}
|
||||
{ MIXSRC_FIRST_TRIM + {{ loop.index0 }}, "trim-{{ li.lua }}", "{{ li.description}} trim" },
|
||||
{% else %}
|
||||
{ MIXSRC_FIRST_TRIM + {{ loop.index0 }}, "trim-t{{ loop.index }}", "Aux trim T{{ loop.index }}" },
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set key_plus = keys | selectattr("key","==","KEY_PLUS") | first %}
|
||||
{% set key_up = keys | selectattr("key","==","KEY_UP") | first %}
|
||||
{% set key_shift = keys | selectattr("key","==","KEY_SHIFT") | first %}
|
||||
{% set key_pageup = keys | selectattr("key","==","KEY_PAGEUP") | first %}
|
||||
{% set key_pagedn = keys | selectattr("key","==","KEY_PAGEDN") | first %}
|
||||
{% set key_model = keys | selectattr("key","==","KEY_MODEL") | first %}
|
||||
{% set key_menu = keys | selectattr("key","==","KEY_MENU") | first %}
|
||||
{% set key_tele = keys | selectattr("key","==","KEY_TELE") | first %}
|
||||
{% set key_sys = keys | selectattr("key","==","KEY_SYS") | first %}
|
||||
{% set key_hats_as_keys = not key_pagedn and not key_menu and not key_up %}
|
||||
|
||||
{% if key_plus %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV, EVT_KEY_FIRST(KEY_PLUS) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV_REPT, EVT_KEY_REPT(KEY_PLUS) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT, EVT_KEY_FIRST(KEY_MINUS) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT_REPT, EVT_KEY_REPT(KEY_MINUS) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_DEC, EVT_KEY_FIRST(KEY_MINUS) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_DEC_REPT, EVT_KEY_REPT(KEY_MINUS) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_INC, EVT_KEY_FIRST(KEY_PLUS) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_INC_REPT, EVT_KEY_REPT(KEY_PLUS) )
|
||||
{% elif key_up %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV, EVT_KEY_FIRST(KEY_UP) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV_REPT, EVT_KEY_REPT(KEY_UP) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT, EVT_KEY_FIRST(KEY_DOWN) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT_REPT, EVT_KEY_REPT(KEY_DOWN) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_DEC, EVT_KEY_FIRST(KEY_DOWN) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_DEC_REPT, EVT_KEY_REPT(KEY_DOWN) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_INC, EVT_KEY_FIRST(KEY_UP) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_INC_REPT, EVT_KEY_REPT(KEY_UP) )
|
||||
{% else %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV, EVT_ROTARY_LEFT )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT, EVT_ROTARY_RIGHT )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_DEC, EVT_ROTARY_LEFT )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_INC, EVT_ROTARY_RIGHT )
|
||||
LROT_NUMENTRY( ROTENC_LOWSPEED, ROTENC_LOWSPEED )
|
||||
LROT_NUMENTRY( ROTENC_MIDSPEED, ROTENC_MIDSPEED )
|
||||
LROT_NUMENTRY( ROTENC_HIGHSPEED, ROTENC_HIGHSPEED )
|
||||
{% endif %}
|
||||
|
||||
{% if key_shift %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV_PAGE, EVT_KEY_LONG(KEY_LEFT) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT_PAGE, EVT_KEY_LONG(KEY_RIGHT) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU, EVT_KEY_BREAK(KEY_SHIFT) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU_LONG, EVT_KEY_LONG(KEY_SHIFT) )
|
||||
{% elif key_up %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV_PAGE, EVT_KEY_LONG(KEY_LEFT) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT_PAGE, EVT_KEY_BREAK(KEY_LEFT) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU, EVT_KEY_BREAK(KEY_RIGHT) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU_LONG, EVT_KEY_LONG(KEY_RIGHT) )
|
||||
{% else %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_PREV_PAGE, EVT_KEY_BREAK(KEY_PAGEUP) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_NEXT_PAGE, EVT_KEY_BREAK(KEY_PAGEDN) )
|
||||
|
||||
{% if key_model or key_hats_as_keys %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU, EVT_KEY_BREAK(KEY_MODEL) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU_LONG, EVT_KEY_LONG(KEY_MODEL) )
|
||||
{% else %}
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU, EVT_KEY_BREAK(KEY_MENU) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_MENU_LONG, EVT_KEY_LONG(KEY_MENU) )
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_ENTER, EVT_KEY_BREAK(KEY_ENTER) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_ENTER_LONG, EVT_KEY_LONG(KEY_ENTER) )
|
||||
LROT_NUMENTRY( EVT_VIRTUAL_EXIT, EVT_KEY_BREAK(KEY_EXIT) )
|
||||
|
||||
LROT_NUMENTRY( EVT_EXIT_BREAK, EVT_KEY_BREAK(KEY_EXIT) )
|
||||
|
||||
{% macro key_event(name, key) %}
|
||||
LROT_NUMENTRY( EVT_{{ name }}_FIRST, EVT_KEY_FIRST({{ key }}) )
|
||||
LROT_NUMENTRY( EVT_{{ name }}_BREAK, EVT_KEY_BREAK({{ key }}) )
|
||||
LROT_NUMENTRY( EVT_{{ name }}_LONG, EVT_KEY_LONG({{ key }}) )
|
||||
LROT_NUMENTRY( EVT_{{ name }}_REPT, EVT_KEY_REPT({{ key }}) )
|
||||
{% endmacro %}
|
||||
|
||||
{{ key_event('ENTER','KEY_ENTER') }}
|
||||
|
||||
{% if key_menu %}
|
||||
{{ key_event('MENU','KEY_MENU') }}
|
||||
{% endif %}
|
||||
|
||||
{% if key_tele or key_hats_as_keys %}
|
||||
{{ key_event('TELEM','KEY_TELE') }}
|
||||
{% endif %}
|
||||
|
||||
{% if key_model or key_hats_as_keys %}
|
||||
{{ key_event('MODEL','KEY_MODEL') }}
|
||||
{% endif %}
|
||||
|
||||
{% if key_sys or key_hats_as_keys %}
|
||||
{{ key_event('SYS','KEY_SYS') }}
|
||||
{% endif %}
|
||||
|
||||
{% if key_up %}
|
||||
{{ key_event('UP', 'KEY_UP') }}
|
||||
{{ key_event('DOWN', 'KEY_DOWN') }}
|
||||
{{ key_event('LEFT', 'KEY_LEFT') }}
|
||||
{{ key_event('RIGHT', 'KEY_RIGHT') }}
|
||||
{% endif %}
|
||||
|
||||
{% if key_pageup or key_hats_as_keys %}
|
||||
{{ key_event('PAGEUP', 'KEY_PAGEUP') }}
|
||||
{{ key_event('PAGEDN', 'KEY_PAGEDN') }}
|
||||
{% elif key_pagedn %}
|
||||
{% if key_menu %}
|
||||
LROT_NUMENTRY( EVT_PAGE_FIRST, EVT_KEY_FIRST(KEY_PAGEDN) )
|
||||
LROT_NUMENTRY( EVT_PAGE_BREAK, EVT_KEY_BREAK(KEY_PAGEDN) )
|
||||
LROT_NUMENTRY( EVT_PAGE_LONG, EVT_KEY_BREAK(KEY_PAGEUP) )
|
||||
LROT_NUMENTRY( EVT_PAGE_REPT, EVT_KEY_REPT(KEY_PAGEDN) )
|
||||
{% else %}
|
||||
LROT_NUMENTRY( EVT_PAGEDN_FIRST, EVT_KEY_FIRST(KEY_PAGEDN) )
|
||||
LROT_NUMENTRY( EVT_PAGEDN_BREAK, EVT_KEY_BREAK(KEY_PAGEDN) )
|
||||
LROT_NUMENTRY( EVT_PAGEDN_LONG, EVT_KEY_BREAK(KEY_PAGEUP) )
|
||||
LROT_NUMENTRY( EVT_PAGEDN_REPT, EVT_KEY_REPT(KEY_PAGEDN) )
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if key_plus %}
|
||||
{{ key_event('PLUS', 'KEY_PLUS') }}
|
||||
{{ key_event('MINUS', 'KEY_MINUS') }}
|
||||
{% endif %}
|
||||
|
||||
{% if key_shift %}
|
||||
{{ key_event('SHIFT', 'KEY_SHIFT') }}
|
||||
{% endif %}
|
||||
|
||||
{% if (not key_plus) and (not key_up) %}
|
||||
{{ key_event('ROT', 'KEY_ENTER') }}
|
||||
LROT_NUMENTRY( EVT_ROT_LEFT, EVT_ROTARY_LEFT )
|
||||
LROT_NUMENTRY( EVT_ROT_RIGHT, EVT_ROTARY_RIGHT )
|
||||
{% endif %}
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set main_inputs = adc_inputs.inputs | selectattr('type', '==', 'STICK') | list %}
|
||||
{% for input in main_inputs %}
|
||||
{% set label = main_labels[input.name] %}
|
||||
LROT_NUMENTRY( MIXSRC_{{ label.str }}, MIXSRC_FIRST_STICK + {{ loop.index0 }} )
|
||||
{% endfor %}
|
||||
|
||||
{% set regular_switches = switches | selectattr('type','!=','FSWITCH') | list %}
|
||||
{% for switch in regular_switches %}
|
||||
LROT_NUMENTRY( MIXSRC_{{ switch.name }}, MIXSRC_FIRST_SWITCH + {{ loop.index0 }} )
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,315 @@
|
||||
from enum import Enum
|
||||
from typing_extensions import List, Literal, Optional, Tuple, Union
|
||||
|
||||
from pydantic import BaseModel, model_validator
|
||||
from pydantic_core import from_json, PydanticCustomError
|
||||
|
||||
|
||||
class StrEnum(str, Enum):
|
||||
@staticmethod
|
||||
def _generate_next_value_(name, start, count, last_values):
|
||||
return name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
|
||||
ADCNameType = Literal["MAIN", "EXT", "SPI"]
|
||||
|
||||
|
||||
class ADC(BaseModel):
|
||||
name: ADCNameType
|
||||
adc: str
|
||||
sample_time: Optional[str] = None
|
||||
dma: Optional[str] = None
|
||||
dma_channel: Optional[str] = None
|
||||
dma_stream: Optional[str] = None
|
||||
dma_stream_irq: Optional[str] = None
|
||||
dma_stream_irq_handler: Optional[str] = None
|
||||
# SPI ADC fields
|
||||
gpio_pin_sck: Optional[str] = None
|
||||
gpio_pin_miso: Optional[str] = None
|
||||
gpio_pin_mosi: Optional[str] = None
|
||||
gpio_pin_cs: Optional[str] = None
|
||||
|
||||
|
||||
StickEnum = StrEnum(
|
||||
"StickEnum",
|
||||
(
|
||||
# 2 Gimbal radios
|
||||
"LH",
|
||||
"LV",
|
||||
"RV",
|
||||
"RH",
|
||||
# Surface radios
|
||||
"ST",
|
||||
"TH",
|
||||
),
|
||||
)
|
||||
|
||||
MAX_POTS = 8
|
||||
MAX_SLIDERS = 8
|
||||
MAX_EXT = 16
|
||||
MAX_RAW = 8
|
||||
|
||||
FlexInputEnum = StrEnum(
|
||||
"FlexInputEnum",
|
||||
(
|
||||
[f"P{i}" for i in range(1, MAX_POTS)]
|
||||
+ [f"SL{i}" for i in range(1, MAX_SLIDERS)]
|
||||
+ [f"EXT{i}" for i in range(1, MAX_EXT)]
|
||||
+ ["JSx", "JSy"]
|
||||
),
|
||||
)
|
||||
|
||||
SwitchInputEnum = StrEnum(
|
||||
"SwitchInputEnum",
|
||||
list([f"SW{chr(i)}" for i in range(ord("A"), ord("Z") + 1)]),
|
||||
)
|
||||
|
||||
RawInputEnum = StrEnum("RawInputEnum", list([f"RAW{i}" for i in range(1, MAX_RAW)]))
|
||||
|
||||
InputNameType = Union[StickEnum, FlexInputEnum, SwitchInputEnum, RawInputEnum]
|
||||
|
||||
InputType = StrEnum(
|
||||
"InputType",
|
||||
(
|
||||
"STICK",
|
||||
"FLEX",
|
||||
"SWITCH",
|
||||
"VBAT",
|
||||
"RTC_BAT",
|
||||
"RAW",
|
||||
"LUX",
|
||||
),
|
||||
)
|
||||
|
||||
FlexType = StrEnum(
|
||||
"FlexType",
|
||||
(
|
||||
"NONE",
|
||||
"POT",
|
||||
"POT_CENTER",
|
||||
"SLIDER",
|
||||
"MULTIPOS",
|
||||
"AXIS_X",
|
||||
"AXIS_Y",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class StickInput(BaseModel):
|
||||
name: StickEnum
|
||||
type: Literal["STICK"]
|
||||
adc: Optional[ADCNameType] = None
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
inverted: Optional[bool] = False
|
||||
pwm_channel: Optional[int] = None
|
||||
|
||||
|
||||
class FlexInput(BaseModel):
|
||||
name: FlexInputEnum
|
||||
type: Literal["FLEX"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
inverted: Optional[bool] = False
|
||||
default: Optional[FlexType] = None
|
||||
label: Optional[str] = None
|
||||
short_label: Optional[str] = None
|
||||
|
||||
|
||||
class SwitchInput(BaseModel):
|
||||
name: SwitchInputEnum
|
||||
type: Literal["SWITCH"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
inverted: Optional[bool] = False
|
||||
|
||||
|
||||
class RawInput(BaseModel):
|
||||
name: RawInputEnum
|
||||
type: Literal["RAW"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
|
||||
|
||||
class VBatInput(BaseModel):
|
||||
name: Literal["VBAT"]
|
||||
type: Literal["VBAT"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
|
||||
|
||||
class RTCBatInput(BaseModel):
|
||||
name: Literal["RTC_BAT"]
|
||||
type: Literal["RTC_BAT"]
|
||||
adc: Literal["MAIN", "EXT"]
|
||||
channel: str
|
||||
|
||||
|
||||
class LuxInput(BaseModel):
|
||||
name: Literal["LUX"]
|
||||
type: Literal["LUX"]
|
||||
adc: ADCNameType
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
channel: Optional[Union[str, int]] = None
|
||||
|
||||
|
||||
Input = Union[StickInput, FlexInput, SwitchInput, RawInput, VBatInput, RTCBatInput, LuxInput]
|
||||
|
||||
|
||||
class ADCInputs(BaseModel):
|
||||
adcs: List[ADC]
|
||||
inputs: List[Input]
|
||||
|
||||
|
||||
# MUST be the same order as 'EnumKeys'
|
||||
KeyEnum = StrEnum(
|
||||
"KeyEnum",
|
||||
(
|
||||
"KEY_MENU",
|
||||
"KEY_EXIT",
|
||||
"KEY_ENTER",
|
||||
"KEY_PAGEUP",
|
||||
"KEY_PAGEDN",
|
||||
"KEY_UP",
|
||||
"KEY_DOWN",
|
||||
"KEY_LEFT",
|
||||
"KEY_RIGHT",
|
||||
"KEY_PLUS",
|
||||
"KEY_MINUS",
|
||||
"KEY_MODEL",
|
||||
"KEY_TELE",
|
||||
"KEY_SYS",
|
||||
"KEY_SHIFT",
|
||||
"KEY_BIND",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class Key(BaseModel):
|
||||
name: str
|
||||
label: str
|
||||
key: KeyEnum
|
||||
active_low: Optional[bool] = False
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_hardware(self: "Key") -> "Key":
|
||||
if bool(self.gpio) != bool(self.pin):
|
||||
raise PydanticCustomError(
|
||||
"KeyHardwareError",
|
||||
"Key missing either 'gpio' or 'pin'",
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
SwitchHardwareTypeEnum = StrEnum(
|
||||
"SwitchTypeEnum",
|
||||
(
|
||||
"2POS",
|
||||
"3POS",
|
||||
"ADC",
|
||||
"FSWITCH",
|
||||
),
|
||||
)
|
||||
|
||||
SwitchTypeEnum = StrEnum(
|
||||
"SwitchTypeEnum",
|
||||
(
|
||||
"2POS",
|
||||
"3POS",
|
||||
"TOGGLE",
|
||||
"NONE",
|
||||
),
|
||||
)
|
||||
|
||||
SwitchDisplayType = Union[Tuple[int, int], Tuple]
|
||||
|
||||
|
||||
class Switch(BaseModel):
|
||||
name: str
|
||||
type: SwitchHardwareTypeEnum
|
||||
default: Optional[SwitchTypeEnum] = SwitchTypeEnum.NONE
|
||||
flags: Optional[int] = 0
|
||||
inverted: Optional[bool] = False
|
||||
is_cfs: Optional[bool] = False
|
||||
cfs_idx: Optional[int] = None
|
||||
adc_input: Optional[str] = None
|
||||
gpio: Optional[str] = None
|
||||
pin: Optional[str] = None
|
||||
gpio_high: Optional[str] = None
|
||||
pin_high: Optional[str] = None
|
||||
gpio_low: Optional[str] = None
|
||||
pin_low: Optional[str] = None
|
||||
display: Optional[SwitchDisplayType] = None
|
||||
|
||||
def _uses_single_gpio(self: "Switch") -> bool:
|
||||
return bool(self.pin)
|
||||
|
||||
def _uses_two_gpios(self: "Switch") -> bool:
|
||||
return bool(self.pin_high or self.pin_low)
|
||||
|
||||
def _uses_gpio(self: "Switch") -> bool:
|
||||
return bool(self.gpio_high or self.gpio_low or self.gpio)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_hardware(self: "Switch") -> "Switch":
|
||||
if bool(self.adc_input) == self._uses_gpio():
|
||||
if self.adc_input:
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"A switch is either using ADC or it's own GPIO pin(s)",
|
||||
)
|
||||
|
||||
if self._uses_gpio() and (self._uses_single_gpio() == self._uses_two_gpios()):
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"A switch based on GPIO pin(s) uses either a single or two GPIOs",
|
||||
)
|
||||
|
||||
if self._uses_single_gpio():
|
||||
if str(self.type) not in ["2POS", "FSWITCH"]:
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"Single GPIO switch type is either '2POS' or 'FSWITCH'",
|
||||
)
|
||||
# TODO: check 'default' as well?
|
||||
|
||||
if self._uses_two_gpios():
|
||||
if not self.pin_high or not self.pin_low:
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"Switch missing 'pin_high' or 'pin_low'",
|
||||
)
|
||||
if str(self.type) != "3POS":
|
||||
raise PydanticCustomError(
|
||||
"SwitchHardwareError",
|
||||
"Dual GPIO switch type is always '3POS",
|
||||
)
|
||||
# TODO: check 'default' as well?
|
||||
|
||||
return self
|
||||
|
||||
|
||||
class HardwareDefinition(BaseModel):
|
||||
adc_inputs: ADCInputs
|
||||
switches: List[Switch]
|
||||
keys: List[Key]
|
||||
|
||||
@staticmethod
|
||||
def from_json(data: Union[str, bytes, bytearray]) -> "HardwareDefinition":
|
||||
return HardwareDefinition.model_validate(from_json(data))
|
||||
@@ -0,0 +1,11 @@
|
||||
const hw_key_def _hw_key_defs[] = {
|
||||
{% for key in keys %}
|
||||
{ "{{ key.name }}", {{ key.key }} },
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
const char* const _hw_trim_defs[] = {
|
||||
{% for trim in trims %}
|
||||
"{{ trim.name }}",
|
||||
{% endfor %}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set regular_switches = switches | selectattr('is_cfs','==',False) | list %}
|
||||
{% set display_switches = regular_switches | selectattr('display','!=',None) | list %}
|
||||
|
||||
const hw_switch_def _switch_defs[] = {
|
||||
{% for switch in switches %}
|
||||
{% if switch.is_cfs %}
|
||||
{ "{{ switch.name }}", SWITCH_HW_{{ switch.type }}, SWITCH_{{ switch.default }}, true, {{ switch.cfs_idx }} },
|
||||
{% else %}
|
||||
{ "{{ switch.name }}", SWITCH_HW_{{ switch.type }}, SWITCH_{{ switch.default }} },
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
constexpr uint8_t n_switches = {{ switches | count }};
|
||||
|
||||
{% if display_switches | count > 0 %}
|
||||
const switch_display_pos_t _switch_display[] = {
|
||||
{% for sw in switches %}
|
||||
{% if sw.display %}
|
||||
{ {{ sw.display[0] }}, {{ sw.display[1] }} },
|
||||
{% else %}
|
||||
{ 0, 0 },
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
{% endif %}
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
#include "stm32_gpio.h"
|
||||
|
||||
static const stm32_adc_input_t _ADC_inputs[] = {
|
||||
{% for input in adc_inputs.inputs %}
|
||||
{
|
||||
// {{ input.name }}
|
||||
// ADC_INPUT_{{ input.type }},
|
||||
{{ input.gpio if input.gpio else 'nullptr' }},
|
||||
{{ input.pin if input.gpio else '0' }},
|
||||
{{ input.channel if input.channel else '0' }},
|
||||
{{ '1 // inverted' if input.inverted else '0 // normal' }}
|
||||
},
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% for adc in adc_inputs.adcs %}
|
||||
{% set inputs = adc_inputs.inputs | selectattr('adc', '==', adc.name) | selectattr('channel','defined') %}
|
||||
static const uint8_t _ADC_{{ adc.name }}_channels[] = {
|
||||
{% for input in inputs %}
|
||||
{{ adc_index[input.name] }}, // {{ input.name }}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% endfor %}
|
||||
{% set offset = namespace(value=0) %}
|
||||
static const stm32_adc_t _ADC_adc[] = {
|
||||
{% for adc in adc_inputs.adcs | selectattr('name', '!=', 'SPI') %}
|
||||
{% set inputs = adc_inputs.inputs | selectattr('adc', '==', adc.name) | selectattr('channel','defined') %}
|
||||
{% set input_count = inputs | list | count %}
|
||||
{
|
||||
{{ adc.adc }},
|
||||
{{ adc.dma if adc.dma else 'nullptr' }},
|
||||
{{ adc.dma_channel if adc.dma else '0' }},
|
||||
{{ adc.dma_stream if adc.dma else '0' }},
|
||||
{{ adc.dma_stream_irq if adc.dma else '(IRQn_Type)-1' }},
|
||||
_ADC_{{ adc.name }}_channels,
|
||||
{{ offset.value }},
|
||||
{{ input_count }},
|
||||
{{ adc.sample_time if adc.sample_time else '0' }}
|
||||
},
|
||||
{% set offset.value = offset.value + input_count %}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
static const stm32_spi_adc_t _ADC_spi[] = {
|
||||
{% for adc in adc_inputs.adcs | selectattr('name', '==', 'SPI') %}
|
||||
{% set inputs = adc_inputs.inputs | selectattr('adc', '==', adc.name) | selectattr('channel','defined') %}
|
||||
{% set input_count = inputs | list | count %}
|
||||
{
|
||||
.spi = {
|
||||
{{ adc.adc }},
|
||||
{{ adc.gpio_pin_sck }},
|
||||
{{ adc.gpio_pin_miso }},
|
||||
{{ adc.gpio_pin_mosi }},
|
||||
{{ adc.gpio_pin_cs }},
|
||||
},
|
||||
_ADC_{{ adc.name }}_channels,
|
||||
{{ input_count }}
|
||||
},
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% for adc in adc_inputs.adcs | selectattr('name', '!=', 'SPI') %}
|
||||
{% if adc.dma %}
|
||||
extern "C" void {{ adc.dma_stream_irq_handler }} (void)
|
||||
{
|
||||
stm32_hal_adc_dma_isr(&_ADC_adc[{{ loop.index0 }}]);
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
extern "C" void ADC_IRQHandler()
|
||||
{
|
||||
{% for adc in adc_inputs.adcs | selectattr('name', '!=', 'SPI') %}
|
||||
stm32_hal_adc_isr(&_ADC_adc[{{ loop.index0 }}]);
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
#if defined(STM32H7)
|
||||
extern "C" void ADC3_IRQHandler()
|
||||
{
|
||||
{% for adc in adc_inputs.adcs | selectattr('name', '!=', 'SPI') %}
|
||||
stm32_hal_adc_isr(&_ADC_adc[{{ loop.index0 }}]);
|
||||
{% endfor %}
|
||||
}
|
||||
#endif
|
||||
|
||||
{% for adc_gpio, adc_inputs in adc_gpios.items() | sort %}
|
||||
static const uint32_t _ADC_{{ adc_gpio }}_pins[] = {
|
||||
{% for input in adc_inputs %}
|
||||
{{ input.pin }},
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
{% endfor %}
|
||||
static const stm32_adc_gpio_t _ADC_GPIOs[] = {
|
||||
{% for adc_gpio, adc_inputs in adc_gpios.items() | sort %}
|
||||
{ {{ adc_gpio }}, _ADC_{{ adc_gpio }}_pins, {{ adc_inputs|count }} },
|
||||
{% endfor %}
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set hw_keys = keys | rejectattr('pin', 'none') | rejectattr('gpio', 'none') | list %}
|
||||
static inline void _init_keys()
|
||||
{
|
||||
{% for key_gpio, pins in key_gpios | dictsort %}
|
||||
{% if key_gpio %}
|
||||
stm32_gpio_enable_clock({{ key_gpio }});
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
LL_GPIO_InitTypeDef pinInit;
|
||||
LL_GPIO_StructInit(&pinInit);
|
||||
pinInit.Mode = LL_GPIO_MODE_INPUT;
|
||||
{% for key in hw_keys %}
|
||||
pinInit.Pin = {{ key.pin }};
|
||||
pinInit.Pull = {{ 'LL_GPIO_PULL_UP' if key.active_low else 'LL_GPIO_PULL_DOWN' }};
|
||||
LL_GPIO_Init({{ key.gpio }}, &pinInit);
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
static inline uint32_t _read_keys()
|
||||
{
|
||||
uint32_t keys = 0;
|
||||
{% for key in hw_keys %}
|
||||
if ({{'!' if key.active_low }}LL_GPIO_IsInputPinSet({{ key.gpio }}, {{ key.pin }}))
|
||||
keys |= (1 << {{ key.key }});
|
||||
{% endfor %}
|
||||
return keys;
|
||||
}
|
||||
|
||||
{% set hw_trims = trims | selectattr('dec', 'defined') | selectattr('inc', 'defined') | list %}
|
||||
static inline void _init_trims()
|
||||
{
|
||||
{% for trim_gpio, pins in trim_gpios | dictsort %}
|
||||
stm32_gpio_enable_clock({{ trim_gpio }});
|
||||
{% endfor %}
|
||||
LL_GPIO_InitTypeDef pinInit;
|
||||
LL_GPIO_StructInit(&pinInit);
|
||||
pinInit.Mode = LL_GPIO_MODE_INPUT;
|
||||
{% for trim in hw_trims %}
|
||||
pinInit.Pin = {{ trim.dec.pin }};
|
||||
pinInit.Pull = {{ 'LL_GPIO_PULL_UP' if trim.dec.active_low else 'LL_GPIO_PULL_DOWN' }};
|
||||
LL_GPIO_Init({{ trim.dec.gpio }}, &pinInit);
|
||||
pinInit.Pin = {{ trim.inc.pin }};
|
||||
pinInit.Pull = {{ 'LL_GPIO_PULL_UP' if trim.inc.active_low else 'LL_GPIO_PULL_DOWN' }};
|
||||
LL_GPIO_Init({{ trim.inc.gpio }}, &pinInit);
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
static inline uint32_t _read_trims()
|
||||
{
|
||||
uint32_t trims = 0;
|
||||
{% for trim in hw_trims %}
|
||||
if ({{'!' if trim.dec.active_low }}LL_GPIO_IsInputPinSet({{ trim.dec.gpio }}, {{ trim.dec.pin }}))
|
||||
trims |= (1 << {{ loop.index0 * 2 }});
|
||||
if ({{'!' if trim.inc.active_low }}LL_GPIO_IsInputPinSet({{ trim.inc.gpio }}, {{ trim.inc.pin }}))
|
||||
trims |= (1 << {{ loop.index0 * 2 + 1 }});
|
||||
{% endfor %}
|
||||
return trims;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set pwm_inputs = adc_inputs.inputs | selectattr('type', '==', 'STICK') | selectattr('pwm_channel', 'ne', none) | list %}
|
||||
static const stick_pwm_input_t _PWM_inputs[] = {
|
||||
{% for input in pwm_inputs %}
|
||||
{
|
||||
// ADC_INPUT_{{ input.type }}, {{ input.name }}
|
||||
{{ input.pwm_channel }}, // channel
|
||||
{{ '1 // inverted' if input.inverted else '0 // normal' }}
|
||||
},
|
||||
{% endfor %}
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set regular_switches = switches | selectattr('is_cfs','==',False) | list %}
|
||||
{% set display_switches = regular_switches | selectattr('display','!=',None) | list %}
|
||||
|
||||
static const stm32_switch_t _switch_defs[] = {
|
||||
{% for switch in switches %}
|
||||
{% if switch.type == '2POS' %}
|
||||
{
|
||||
"{{ switch.name }}",
|
||||
{{ switch.gpio or "nullptr" }}, {{ switch.pin or 0 }},
|
||||
nullptr, 0,
|
||||
SWITCH_HW_2POS, {{ 'SWITCH_HW_INVERTED' if switch.inverted else 0 }}, SWITCH_{{ switch.default }},
|
||||
{% if switch.is_cfs %}
|
||||
true, {{ switch.cfs_idx }}
|
||||
{% endif %}
|
||||
},
|
||||
{% elif switch.type == '3POS' %}
|
||||
{
|
||||
"{{ switch.name }}",
|
||||
{{ switch.gpio_high or "nullptr" }}, {{ switch.pin_high or 0 }},
|
||||
{{ switch.gpio_low or "nullptr" }}, {{ switch.pin_low or 0 }},
|
||||
SWITCH_HW_3POS, {{ 'SWITCH_HW_INVERTED' if switch.inverted else 0 }}, SWITCH_{{ switch.default }},
|
||||
},
|
||||
{% elif switch.type == 'ADC' %}
|
||||
{
|
||||
"{{ switch.name }}",
|
||||
nullptr, {{ adc_index[switch.adc_input] }},
|
||||
nullptr, 0,
|
||||
SWITCH_HW_ADC, {{ 'SWITCH_HW_INVERTED' if switch.inverted else 0 }}, SWITCH_{{ switch.default }},
|
||||
},
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
static inline void _init_switches()
|
||||
{
|
||||
{% if switch_gpios|count > 0 %}
|
||||
LL_GPIO_InitTypeDef pinInit;
|
||||
LL_GPIO_StructInit(&pinInit);
|
||||
pinInit.Mode = LL_GPIO_MODE_INPUT;
|
||||
pinInit.Pull = LL_GPIO_PULL_UP;
|
||||
{% for sw_gpio, pins in switch_gpios.items() | sort %}
|
||||
{% if sw_gpio %}
|
||||
stm32_gpio_enable_clock({{ sw_gpio }});
|
||||
pinInit.Pin = {{ pins | join('|') }};
|
||||
LL_GPIO_Init({{ sw_gpio }}, &pinInit);
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
constexpr uint8_t n_switches = {{ switches | count }};
|
||||
|
||||
{% if display_switches | count > 0 %}
|
||||
const switch_display_pos_t _switch_display[] = {
|
||||
{% for sw in switches %}
|
||||
{% if sw.display %}
|
||||
{ {{ sw.display[0] }}, {{ sw.display[1] }} },
|
||||
{% else %}
|
||||
{ 0, 0 },
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
{% endif %}
|
||||
@@ -0,0 +1,67 @@
|
||||
"""Test that all templates render successfully for all board hw_defs.
|
||||
|
||||
Runs all .jinja templates against all .json board definitions in a single
|
||||
process, accumulating failures rather than stopping at the first one.
|
||||
|
||||
Usage:
|
||||
python3 test_templates.py <hw_defs_dir>
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from generator import generate_from_template
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Test all templates x all boards")
|
||||
parser.add_argument("hw_defs_dir", help="Directory containing board .json files")
|
||||
args = parser.parse_args()
|
||||
|
||||
hw_defs_dir = Path(args.hw_defs_dir)
|
||||
if not hw_defs_dir.is_dir():
|
||||
print(f"ERROR: {hw_defs_dir} is not a directory", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
script_dir = Path(os.path.dirname(os.path.abspath(__file__)))
|
||||
templates = sorted(script_dir.glob("*.jinja"))
|
||||
json_files = sorted(hw_defs_dir.glob("*.json"))
|
||||
|
||||
if not templates:
|
||||
print("ERROR: no .jinja templates found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not json_files:
|
||||
print(f"ERROR: no .json files found in {hw_defs_dir}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Testing {len(json_files)} boards x {len(templates)} templates "
|
||||
f"= {len(json_files) * len(templates)} combinations")
|
||||
|
||||
failures = []
|
||||
|
||||
for json_file in json_files:
|
||||
board = json_file.stem
|
||||
for tmpl in templates:
|
||||
try:
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
generate_from_template(str(json_file), str(tmpl), board)
|
||||
except SystemExit as e:
|
||||
if e.code != 0:
|
||||
failures.append((board, tmpl.name))
|
||||
|
||||
if failures:
|
||||
print(f"\nFAILED ({len(failures)}):", file=sys.stderr)
|
||||
for board, tmpl in failures:
|
||||
print(f" board={board} template={tmpl}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"All combinations passed.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// WARNING: DO NOT EDIT THIS FILE
|
||||
// This file has been generated from the target's JSON hardware description
|
||||
//
|
||||
|
||||
{% set main_inputs = adc_inputs.inputs | selectattr('type', '==', 'STICK') | list %}
|
||||
{% set flex_inputs = adc_inputs.inputs | selectattr('type', '==', 'FLEX') | list %}
|
||||
|
||||
struct legacy_input_t {
|
||||
const char* legacy;
|
||||
uint16_t src_raw;
|
||||
};
|
||||
|
||||
static const legacy_input_t _legacy_inputs[] = {
|
||||
// main inputs
|
||||
{% for input in main_inputs %}
|
||||
{% set li = legacy_inputs[input.name] %}
|
||||
{ "{{ li.yaml }}", MIXSRC_FIRST_STICK + {{ loop.index0 }} },
|
||||
{% endfor %}
|
||||
// flex inputs
|
||||
{% for input in flex_inputs %}
|
||||
{% set li = legacy_inputs[input.name] %}
|
||||
{ "{{ li.yaml }}", MIXSRC_FIRST_POT + {{ loop.index0 }} },
|
||||
{% endfor %}
|
||||
// trims
|
||||
{% set trims_count = trims | count %}
|
||||
{% for n in range(trims_count) %}
|
||||
{% if n < (main_inputs | length) %}
|
||||
{% set input = main_inputs[loop.index0] %}
|
||||
{% set li = legacy_inputs[input.name] %}
|
||||
{ "Trim{{ li.yaml }}", MIXSRC_FIRST_TRIM + {{ loop.index0 }} },
|
||||
{% else %}
|
||||
{ "TrimT{{ loop.index }}", MIXSRC_FIRST_TRIM + {{ loop.index0 }} },
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
local toolName = "TNS|LUA event tests|TNE"
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) EdgeTX
|
||||
---- #
|
||||
---- # Based on code named
|
||||
---- # opentx - https://github.com/opentx/opentx
|
||||
---- # th9x - http://code.google.com/p/th9x
|
||||
---- # er9x - http://code.google.com/p/er9x
|
||||
---- # gruvin9x - http://code.google.com/p/gruvin9x
|
||||
---- #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
---- #
|
||||
---- # This program is free software; you can redistribute it and/or modify
|
||||
---- # it under the terms of the GNU General Public License version 2 as
|
||||
---- # published by the Free Software Foundation.
|
||||
---- #
|
||||
---- # This program is distributed in the hope that it will be useful,
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
---- # GNU General Public License for more details.
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local virtual_next = 0
|
||||
local virtual_prev = 0
|
||||
local virtual_inc = 0
|
||||
local virtual_dec = 0
|
||||
local virtual_next_rept = 0
|
||||
local virtual_prev_rept = 0
|
||||
local virtual_page_next = 0
|
||||
local virtual_page_prev = 0
|
||||
local virtual_enter = 0
|
||||
local virtual_enter_long = 0
|
||||
local virtual_menu = 0
|
||||
local virtual_menu_long = 0
|
||||
|
||||
-- Init
|
||||
local function init()
|
||||
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
virtual_next = virtual_next + 1
|
||||
end
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
virtual_prev = virtual_prev + 1
|
||||
end
|
||||
if event == EVT_VIRTUAL_INC then
|
||||
virtual_inc = virtual_inc + 1
|
||||
end
|
||||
if event == EVT_VIRTUAL_DEC then
|
||||
virtual_dec = virtual_dec + 1
|
||||
end
|
||||
if event == EVT_VIRTUAL_NEXT_REPT then
|
||||
virtual_next_rept = virtual_next_rept + 1
|
||||
end
|
||||
if event == EVT_VIRTUAL_PREV_REPT then
|
||||
virtual_prev_rept = virtual_prev_rept + 1
|
||||
end
|
||||
if event == EVT_VIRTUAL_NEXT_PAGE then
|
||||
virtual_page_next = virtual_page_next +1
|
||||
end
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
virtual_page_prev = virtual_page_prev + 1
|
||||
killEvents(event);
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
virtual_enter = virtual_enter + 1
|
||||
end
|
||||
if event == EVT_VIRTUAL_MENU then
|
||||
virtual_menu = virtual_menu + 1
|
||||
end
|
||||
|
||||
lcd.clear()
|
||||
lcd.drawScreenTitle("LUA EVENT TEST", 0, 0)
|
||||
lcd.drawText(1, 10, "PREV:"..virtual_prev)
|
||||
lcd.drawText(LCD_W/2, 10, "NEXT: "..virtual_next)
|
||||
lcd.drawText(1, 20, "DEC:"..virtual_dec)
|
||||
lcd.drawText(LCD_W/2, 20, "INC:"..virtual_inc)
|
||||
lcd.drawText(1, 30, "NXT PAGE: "..virtual_page_next)
|
||||
lcd.drawText(LCD_W/2, 30, "PRV PAGE: "..virtual_page_prev)
|
||||
lcd.drawText(1, 50, "ENTER: "..virtual_enter)
|
||||
lcd.drawText(LCD_W/2, 50, "MENU: "..virtual_menu)
|
||||
return 0
|
||||
end
|
||||
|
||||
return { init=init, run=run }
|
||||
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This script parses debug log events related to Lua memory (de)allocations ( lines
|
||||
starting wiht "LT: ") and produces a data for gnuplot program
|
||||
|
||||
Usage:
|
||||
|
||||
./simu 2>&1 | grep "^LT" | ../radio/util/lua_trace2plot.py > data.plot
|
||||
gnuplot -e 'set xtics rotate; plot "data.plot" using 2:xtic(1) ; pause mouse close'
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
inputFile = sys.argv[1]
|
||||
inp = open(inputFile, "r")
|
||||
else:
|
||||
inp = sys.stdin
|
||||
|
||||
|
||||
x = 0
|
||||
memUsed = 0
|
||||
while True:
|
||||
skip = True
|
||||
line = inp.readline()
|
||||
if len(line) == 0:
|
||||
break
|
||||
line = line.strip('\r\n')
|
||||
if len(line) == 0:
|
||||
skip = True
|
||||
if line.startswith("LT:"):
|
||||
skip = False
|
||||
|
||||
if not skip:
|
||||
parts = line.split()
|
||||
if len(parts) >= 3:
|
||||
data = parts[1].strip("[").strip("]").split(",")
|
||||
alloc = int(data[0])
|
||||
free = int(data[1])
|
||||
line = parts[2]
|
||||
if alloc > 0:
|
||||
memUsed += alloc
|
||||
print("'%s'\t%d" % (line, memUsed))
|
||||
x += 1
|
||||
if free < 0:
|
||||
memUsed += free
|
||||
print("'%s'\t%d" % (line, memUsed))
|
||||
x += 1
|
||||
|
||||
inp.close()
|
||||
@@ -0,0 +1,16 @@
|
||||
echo off
|
||||
|
||||
|
||||
echo Getting max amplitude..
|
||||
sox %1.wav -n stat -v 2> %1_apl.txt
|
||||
Set /P apl_value= < %1_apl.txt
|
||||
|
||||
echo Normalizing audio.. gain: %apl_value%
|
||||
sox --show-progress -v %apl_value% %1.wav %1_norm.wav
|
||||
|
||||
copy %1_norm.wav %1.wav
|
||||
|
||||
echo Cleaning..
|
||||
del %1_norm.wav
|
||||
del %1_apl.txt
|
||||
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
filename = sys.argv[1]
|
||||
print(filename)
|
||||
fr = open(filename)
|
||||
fw = open(filename + ".new", "w")
|
||||
ew = open(filename + ".en", "w")
|
||||
hw = open(filename + ".stringsh", "w")
|
||||
cw = open(filename + ".stringsc", "w")
|
||||
|
||||
replacements = {}
|
||||
|
||||
for line in fr.readlines():
|
||||
pos_pstr = line.find("\""
|
||||
MENU = False
|
||||
if pos_pstr < 0:
|
||||
pos_pstr = line.find("MENU(\"")
|
||||
MENU = True
|
||||
while pos_pstr >= 0:
|
||||
# print line,
|
||||
if MENU:
|
||||
pos_endparenthesis = line.find('"', pos_pstr + 7)
|
||||
else:
|
||||
pos_endparenthesis = line.find("\")", pos_pstr)
|
||||
pstr = line[pos_pstr + 6:pos_endparenthesis]
|
||||
|
||||
str_rep = "STR_" + pstr.upper()
|
||||
for s in (" ", ".", "[", "]", "-", "!", "/", ")", "(", "%", "+", ":"):
|
||||
str_rep = str_rep.replace(s, "")
|
||||
|
||||
if "14" in pstr or "32" in pstr or "@" in pstr or len(str_rep) <= 5:
|
||||
pos_pstr = -1
|
||||
else:
|
||||
if MENU:
|
||||
glob_str = line[pos_pstr + 5:pos_endparenthesis + 1]
|
||||
str_rep = "STR_MENU" + pstr.upper()
|
||||
else:
|
||||
glob_str = line[pos_pstr:pos_endparenthesis + 2]
|
||||
str_rep = "STR_" + pstr.upper()
|
||||
for s in (" ", ".", "[", "]", "-", "!", "/", ")", "(", "%", "+", ":"):
|
||||
str_rep = str_rep.replace(s, "")
|
||||
|
||||
line = line.replace(glob_str, str_rep)
|
||||
|
||||
if str_rep in replacements.keys():
|
||||
if replacements[str_rep] != pstr:
|
||||
print("!!!!! NON !!!!!")
|
||||
else:
|
||||
replacements[str_rep] = pstr
|
||||
print(glob_str, "=>", pstr, str_rep)
|
||||
ew.write("#define " + str_rep[1:] + " " * (17 - len(str_rep)) + '"%s"\n' % pstr)
|
||||
hw.write("extern const char %s[];\n" % str_rep)
|
||||
cw.write("const prog_char APM %s[] = %s;\n" % (str_rep, str_rep[1:]))
|
||||
|
||||
pos_pstr = line.find("\""
|
||||
|
||||
fw.write(line)
|
||||
|
||||
fw.close()
|
||||
ew.close()
|
||||
hw.close()
|
||||
cw.close()
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import math
|
||||
|
||||
samples = 1024
|
||||
amplitudes = (32000, 0, 4000, 0, 4000)
|
||||
|
||||
max = 0
|
||||
min = 0
|
||||
|
||||
for i in range(samples):
|
||||
sample = 0.0
|
||||
for harmonic, amplitude in enumerate(amplitudes):
|
||||
sample += math.sin(math.pi * 2 * i * (harmonic + 1) / samples) * amplitude / 2
|
||||
sample = int(sample)
|
||||
if sample > max:
|
||||
max = sample
|
||||
elif sample < min:
|
||||
min = sample
|
||||
print("%d," % sample, end=' ')
|
||||
if i % 10 == 9:
|
||||
print()
|
||||
|
||||
print()
|
||||
print('Range is:', min, max)
|
||||
|
||||
if max > 32767 or min < -32768:
|
||||
print("Invalid range!")
|
||||
Executable
+194
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This program parses sport.log files
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
import sys
|
||||
import struct
|
||||
|
||||
|
||||
START_STOP = '\x7e'
|
||||
BYTE_STUFF = '\x7d'
|
||||
STUFF_MASK = '\x20'
|
||||
|
||||
DATA_FRAME = 0x10
|
||||
|
||||
|
||||
lineNumber = 0
|
||||
sportDataBuff = ""
|
||||
|
||||
quiet = False
|
||||
|
||||
|
||||
def ParseFlVSS(packet, dataId, prim, appId, data, crc):
|
||||
# if dataId != 0xa1:
|
||||
# return
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
cells = (data & 0xF0) >> 4
|
||||
battnumber = data & 0xF
|
||||
voltage1 = ((data & 0x000FFF00) >> 8) // 5
|
||||
voltage2 = ((data & 0xFFF00000) >> 20) // 5
|
||||
print(" FLVSS: no cells: %d, cell: %d: voltages: %0.2f %0.2f" % (cells, battnumber, voltage1 / 100., voltage2 / 100.))
|
||||
|
||||
|
||||
def ParseASS(packet, dataId, prim, appId, data, crc):
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
print(" ASS: %dkm/h" % (float(data) / 10))
|
||||
|
||||
|
||||
def ParseRSSI(packet, dataId, prim, appId, data, crc):
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
print(" RSSI: %d" % (data & 0xFF))
|
||||
|
||||
|
||||
def ParseAdc(packet, dataId, prim, appId, data, crc):
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
print(" A%d: %d" % (dataId - 0xf102, data & 0xFF))
|
||||
|
||||
|
||||
def ParseBatt(packet, dataId, prim, appId, data, crc):
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
print(" Batt: %d" % (data & 0xFF))
|
||||
|
||||
|
||||
def ParseRAS(packet, dataId, prim, appId, data, crc):
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
print(" RAS: %d" % (data & 0xFF))
|
||||
|
||||
|
||||
def ParseVersion(packet, dataId, prim, appId, data, crc):
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
print(" VERSION: %d" % data)
|
||||
|
||||
|
||||
def ParseAirSpeed(packet, dataId, prim, appId, data, crc):
|
||||
print("packet: %s (%4d)" % (dump(packet), lineNumber), end=' ')
|
||||
print(" Aspd: %.1f km/h" % (data / 10.0))
|
||||
|
||||
|
||||
appIdParsers = (
|
||||
(0x0300, 0x030f, ParseFlVSS),
|
||||
(0x0a00, 0x0a0f, ParseASS),
|
||||
(0xf101, 0xf101, ParseRSSI),
|
||||
(0xf102, 0xf103, ParseAdc),
|
||||
(0xf104, 0xf104, ParseBatt),
|
||||
(0xf105, 0xf105, ParseRAS),
|
||||
(0xf106, 0xf106, ParseVersion),
|
||||
)
|
||||
|
||||
|
||||
def dump(data, maxLen=None):
|
||||
if maxLen and len(data) > maxLen:
|
||||
data = data[:maxLen]
|
||||
return ":".join("{:02x}".format(ord(c)) for c in data)
|
||||
|
||||
|
||||
def CheckSportCrc(packet):
|
||||
return True
|
||||
|
||||
|
||||
def ParseSportPacket(packet):
|
||||
global lineNumber
|
||||
(dataId, prim, appId, data, crc) = struct.unpack('<BBHIB', packet)
|
||||
# print "dataId:%02x, prim:%02x, appId:%04x, data:%08x, crc:%02x)\n" % (dataId, prim, appId, data, crc)
|
||||
if prim != DATA_FRAME:
|
||||
print("unknown prim: %02x for packet %s in line %s" % (prim, dump(packet), lineNumber))
|
||||
# process according to appId
|
||||
for firstId, lastId, parser in appIdParsers:
|
||||
if firstId <= appId <= lastId:
|
||||
parser(packet, dataId, prim, appId, data, crc)
|
||||
return
|
||||
# no parser found
|
||||
if not quiet:
|
||||
print("\tdataId:%02x, prim:%02x, appId:%04x, data:%08x, crc:%02x)" % (dataId, prim, appId, data, crc))
|
||||
print("\tparser for appId %02x not implemented" % appId)
|
||||
|
||||
|
||||
def ParsePacket(packet):
|
||||
global lineNumber
|
||||
# unstuff packet
|
||||
while True:
|
||||
pos = packet.find(BYTE_STUFF)
|
||||
if pos == -1:
|
||||
break
|
||||
# print "found stuff at %d in %s" % (pos, dump(packet, 20))
|
||||
# if we have nex char, then unstuff it
|
||||
if len(packet) > pos + 1:
|
||||
unstuffed = ord(packet[pos]) ^ ord(STUFF_MASK)
|
||||
# print "unstuffed data: %02x" % unstuffed
|
||||
# buffer[pos] = chr(unstuffed)
|
||||
packet = packet[:pos] + chr(unstuffed) + packet[pos + 2:]
|
||||
# print "buff after unstuff %s" % dump(packet, 20)
|
||||
else:
|
||||
# missing data, wait for more data
|
||||
print("unstuff missing data")
|
||||
return
|
||||
|
||||
# print "packet: %s" % dump(packet, 10)
|
||||
if len(packet) == 9:
|
||||
# valid sport packet length
|
||||
# print "\npacket: %s @%d" % (dump(packet), lineNumber)
|
||||
# check crc
|
||||
if not CheckSportCrc(packet):
|
||||
print("error: wrong CRC for packet %s at line %d" % (dump(packet), lineNumber))
|
||||
ParseSportPacket(packet)
|
||||
else:
|
||||
if len(packet) > 1:
|
||||
print("warning: wrong length %s for packet %s at line %d" % (len(packet), dump(packet, 10), lineNumber))
|
||||
|
||||
|
||||
def ParseSportData(data):
|
||||
global sportDataBuff
|
||||
# convert from hex
|
||||
parts = data.split(' ')
|
||||
binData = [chr(int(hex, 16)) for hex in parts]
|
||||
# print binData
|
||||
data = ''.join(binData)
|
||||
sportDataBuff += data
|
||||
# process whole packets
|
||||
while True:
|
||||
# find whole frame
|
||||
# remove all data before START_STOP
|
||||
# find next START_STOP
|
||||
# print "start: %s" % dump(sportDataBuff, 10)
|
||||
posStop = sportDataBuff.find(START_STOP)
|
||||
# process pacet between two START_STOPs
|
||||
if posStop > -1:
|
||||
# print "found stop at %d" % posStop
|
||||
ParsePacket(sportDataBuff[:posStop])
|
||||
# remove processed data
|
||||
sportDataBuff = sportDataBuff[posStop + 1:]
|
||||
# print "after: %s" % dump(sportDataBuff, 10)
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
inputFile = None
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
inputFile = sys.argv[1]
|
||||
|
||||
# open input
|
||||
if inputFile:
|
||||
inp = open(inputFile, 'r')
|
||||
else:
|
||||
inp = sys.stdin
|
||||
|
||||
while True:
|
||||
line = inp.readline()
|
||||
lineNumber += 1
|
||||
if len(line) == 0:
|
||||
break
|
||||
line = line.strip('\r\n')
|
||||
if len(line) == 0:
|
||||
continue
|
||||
# print line
|
||||
parts = line.split(': ')
|
||||
if len(parts) < 2:
|
||||
print("weird data: \"%s\" at line %d" % (line, lineNumber))
|
||||
continue
|
||||
sportData = parts[1].strip()
|
||||
# print "sd: %s" % sportData
|
||||
ParseSportData(sportData)
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
try:
|
||||
from PyQt5 import Qt, QtGui
|
||||
except:
|
||||
from PyQt4 import Qt, QtGui
|
||||
|
||||
menu = ["radio_setup", "model_select", "model_settings", "model_checklist", "files", "version"]
|
||||
|
||||
image = QtGui.QImage(24 * 8, 24, QtGui.QImage.Format_RGB32)
|
||||
image.fill(QtGui.QColor(255, 255, 255))
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(image)
|
||||
for i, str in enumerate(menu):
|
||||
icon = QtGui.QImage("../src/bitmaps/taranis/std/%s.png" % str)
|
||||
painter.drawImage(Qt.QPoint(24 * i, 0), icon)
|
||||
painter.end()
|
||||
image.save("../src/bitmaps/taranis/mainmenu.png")
|
||||
@@ -0,0 +1,6 @@
|
||||
def filename(idx):
|
||||
ext = ".wav"
|
||||
if isinstance(idx, int):
|
||||
return "%04d%s" % (idx, ext)
|
||||
else:
|
||||
return idx + ext
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Czech language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
for i, s in enumerate(["nula", "jedna", "dva"]):
|
||||
systemSounds.append((s, filename(i)))
|
||||
for i in range(97):
|
||||
systemSounds.append((str(3 + i), filename(3 + i)))
|
||||
for i, s in enumerate(["sto", "dvěsta", "třista", "čtyřista", "pětset", "šestset", "sedmset", "osmset", "devětset", "tisíc"]):
|
||||
systemSounds.append((s, filename(100 + i)))
|
||||
for i, s in enumerate(["tisíce", "jeden", "jedno", "dvě", "celá", "celé", "celých", "mínus"]):
|
||||
systemSounds.append((s, filename(110 + i)))
|
||||
for i, (s, f) in enumerate([("volt", "volt0"), ("volty", "volt1"), ("voltů", "volt2"),("voltu", "volt3"),
|
||||
("ampér", "amp0"), ("ampéry", "amp1"), ("ampérů", "amp2"), ("ampéru", "amp3"),
|
||||
("miliampér", "mamp0"), ("miliampéry", "mamp1"), ("miliampérů", "mamp2"), ("miliampéru", "mamp3"),
|
||||
("uzel", "knot0"), ("uzly", "knot1"), ("uzlů", "knot2"), ("uzlu", "knot3"),
|
||||
("metr za sekundu", "mps0"), ("metry za sekundu", "mps1"), ("metrů za sekundu", "mps2"), ("metru za sekundu", "mps3"),
|
||||
("stopa za sekundu", "fps0"), ("stopy za sekundu", "fps1"), ("stop za sekundu", "fps2"), ("stopy za sekundu", "fps3"),
|
||||
("kilometr za hodinu", "kph0"), ("kilometry za hodinu", "kph1"), ("kilometrů za hodinu", "kph2"), ("kilometru za hodinu", "kph3"),
|
||||
("míle za hodinu", "mph0"), ("míle za hodinu", "mph1"), ("mil za hodinu", "mph2"), ("míle za hodinu", "mph3"),
|
||||
("metr", "meter0"), ("metry", "meter1"), ("metrů", "meter2"), ("metru", "meter3"),
|
||||
("stopa", "foot0"), ("stopy", "foot1"), ("stop", "foot2"),("stopy", "foot3"),
|
||||
("stupeň celsia", "celsius0"), ("stupně celsia", "celsius1"), ("stupňů celsia", "celsius2"), ("stupně celsia", "celsius3"),
|
||||
("stupeň fahrenheita", "fahr0"), ("stupně fahrenheita", "fahr1"), ("stupňů fahrenheita", "fahr2"), ("stupně fahrenheita", "fahr3"),
|
||||
("procento", "percent0"), ("procenta", "percent1"), ("procent", "percent2"), ("procenta", "percent3"),
|
||||
("miliampérhodina", "mamph0"), ("miliampérhodiny", "mamph1"), ("miliampérhodin", "mamph2"), ("miliampérhodiny", "mamph3"),
|
||||
("vat", "watt0"), ("vaty", "watt1"), ("vatů", "watt2"), ("vatu", "watt3"),
|
||||
("milivat", "mwatt0"), ("milivaty", "mwatt1"), ("milivatů", "mwatt2"), ("milivatu", "mwatt3"),
|
||||
("decibel", "db0"), ("decibely", "db1"), ("decibelů", "db2"), ("decibelu", "db3"),
|
||||
("otáčka za minutu", "rpm0"), ("otáčky za minutu", "rpm1"), ("otáček za minutu", "rpm2"), ("otáčky za minutu", "rpm3"),
|
||||
("gé", "g0"), ("gé", "g1"), ("gé", "g2"), ("gé", "g3"),
|
||||
("stupeň", "degree0"), ("stupně", "degree1"), ("stupňů", "degree2"), ("stupně", "degree3"),
|
||||
("radián", "rad0"), ("radiány", "rad1"), ("radiánů", "rad2"), ("radiánu", "rad3"),
|
||||
("mililitr", "ml0"), ("mililitry", "ml1"), ("mililitrů", "ml2"), ("mililitru", "ml3"),
|
||||
("dutá unce", "founce0"), ("duté unce", "founce1"), ("dutých uncí", "founce2"), ("duté unce", "founce3"),
|
||||
("milliliter per minute", "mlpm0"), ("milliliters per minute", "mlpm1"),
|
||||
("hodina", "hour0"), ("hodiny", "hour1"), ("hodin", "hour2"), ("hodiny", "hour3"),
|
||||
("minuta", "minute0"), ("minuty", "minute1"), ("minut", "minute2"), ("minuty", "minute3"),
|
||||
("sekunda", "second0"), ("sekundy", "second1"), ("sekund", "second2"), ("sekundy", "second3"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
for s, f in [("střed trimu", "midtrim"),
|
||||
("maximum trimu", "maxtrim"),
|
||||
("minimum trimu", "mintrim"),
|
||||
("stopky 1 doběhly", "timovr1"),
|
||||
("stopky 2 doběhly", "timovr2"),
|
||||
("stopky 3 doběhly", "timovr3"),
|
||||
("baterie rádia je vybitá", "lowbatt"),
|
||||
("zapoměl jsi na mě!", "inactiv"),
|
||||
("plyn není na nule", "thralert"),
|
||||
("přepínače nejsou ve výchozí poloze", "swalert"),
|
||||
("neplatná eeprom", "eebad"),
|
||||
("Žádám o povolení ke startu.", "hello"),
|
||||
("Tak zase příště!", "bye"),
|
||||
("nízký RF signál", "rssi_org"),
|
||||
("kritický RF signál", "rssi_red"),
|
||||
("problém s anténou rádia", "swr_red"),
|
||||
("telemetrie ztracena", "telemko"),
|
||||
("telemetrie je funkční", "telemok"),
|
||||
("trenér port odpojen", "trainko"),
|
||||
("trenér port připojen", "trainok"),
|
||||
("senzor ztracen", "sensorko"),
|
||||
("servo přetíženo", "servoko"),
|
||||
("r f přebuzeno", "rxko"),
|
||||
("receiver still connected", "modelpwr"),
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, (s, f) in enumerate([("podvozek je zasunut", "podvo0"),
|
||||
("podvozek je vysunut", "podvo1"),
|
||||
("klapky jsou zapnuty", "klapk1"),
|
||||
("klapky jsou vypnuty", "klapk0"),
|
||||
("trenér je zapnut", "trene1"),
|
||||
("trenér je vypnutý", "trene0"),
|
||||
("motor je vypnut", "motor0"),
|
||||
("motor je aktivován", "motor1"),
|
||||
("jsi příliš vysoko", "vysoko"),
|
||||
("jsi příliš nízko", "nizko"),
|
||||
("baterie modelu je vybitá", "bat0"),
|
||||
("dochází palivo", "palivo"),
|
||||
("nízký signál!", "nsigna"),
|
||||
("kritický signál!", "ksigna"),
|
||||
("rychlý režim aktivován", "rrychl"),
|
||||
("termický režim aktivován", "rtermi"),
|
||||
("normální režim aktivován", "rnorm"),
|
||||
("režim start aktivován", "rstart"),
|
||||
("režim přistání aktivován", "prista"),
|
||||
("vario je zapnuto", "vario0"),
|
||||
("vario je vypnuto", "vario1"),
|
||||
("start povolen", "start1"),
|
||||
("letový režim jedna", "fm-1"),
|
||||
("letový režim dva", "fm-2"),
|
||||
("letový režim tři", "fm-3"),
|
||||
("letový režim čtyři", "fm-4"),
|
||||
("letový režim pět", "fm-5"),
|
||||
("letový režim šest", "fm-6"),
|
||||
("letový režim sedm", "fm-7"),
|
||||
("letový režim osm", "fm-8"),
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# German language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
for i in range(100):
|
||||
systemSounds.append((str(i), filename(i)))
|
||||
systemSounds.append(("ein", filename(100)))
|
||||
systemSounds.append(("eine", filename(101)))
|
||||
systemSounds.append(("hundert", filename(102)))
|
||||
systemSounds.append(("tausend", filename(103)))
|
||||
|
||||
for i, s in enumerate(["komma", "und", "minus", "uhr", "minute", "minuten", "sekunde", "sekunden", "stunde", "stunden"]):
|
||||
systemSounds.append((s, filename(104 + i)))
|
||||
|
||||
for i, (s, f) in enumerate([("Wolt", "volt0"),
|
||||
("Ampär", "amp0"),
|
||||
("MilliAmpär", "mamp0"),
|
||||
("Knoten", "knot0"),
|
||||
("Meter pro sekunde", "mps0"),
|
||||
("Fuß pro sekunde", "fps0"),
|
||||
("Kilometer pro stunde", "kph0"),
|
||||
("Meilen pro Stunde", "mph0"),
|
||||
("Meter", "meter0"),
|
||||
("Fuß", "foot0"),
|
||||
("Grad Celsius", "celsius0"),
|
||||
("Grad Fahrenheit", "fahr0"),
|
||||
("Prozent", "percent0"),
|
||||
("Milliampärstunde", "mamph0"), ("Milliampärstunden", "mamph1"),
|
||||
("Watt", "watt0"),
|
||||
("Milli Watt", "mwatt0"),
|
||||
("D B", "db0"),
|
||||
("Umdrehungen pro Minute", "rpm0"),
|
||||
("g", "g0"),
|
||||
("Grad", "degree0"),
|
||||
("radiant", "rad0"), ("radianten", "rad1"),
|
||||
("Milliliter", "ml0"),
|
||||
("Unze", "founce0"),("Unzen", "founce1"),
|
||||
("Milliliter pro minute", "mlpm0"),
|
||||
("Hertz", "hertz0"),
|
||||
("Millisekunde", "ms0"), ("Millisekunden", "ms1"),
|
||||
("Mikrosekunde", "us0"), ("Mikrosekunden", "us1"),
|
||||
("Stunde", "hour0"), ("Stunden", "hour1"),
|
||||
("Minute", "minute0"), ("Minuten", "minute1"),
|
||||
("Sekunde", "second0"), ("Sekunden", "second1"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
|
||||
for s, f in [("Trimmung zentriert", "midtrim"),
|
||||
("Obere Trimmungsgrenze erreicht", "maxtrim"),
|
||||
("Untere Trimmungsgrenze erreicht", "mintrim"),
|
||||
("timer eins abgelaufen", "timovr1"),
|
||||
("timer zwei abgelaufen", "timovr2"),
|
||||
("timer drei abgelaufen", "timovr3"),
|
||||
("Senderspannung schwach", "lowbatt"),
|
||||
("Inaktivitätsalarm", "inactiv"),
|
||||
("Gaskanal nicht Null, bitte prüfen", "thralert"),
|
||||
("Schalter fehlpositioniert, bitte prüfen", "swalert"),
|
||||
("EEPROM fehlerhaft", "eebad"),
|
||||
("Willkommen bei open t x", "hello"),
|
||||
("Funksignal schwach!", "rssi_org"),
|
||||
("Funksignal kritisch!", "rssi_red"),
|
||||
("Senderantenne fehlerhaft", "swr_red"),
|
||||
("Telemetrie verloren", "telemko"),
|
||||
("Telemetrie wiederhergestellt", "telemok"),
|
||||
("Schülersignal verloren", "trainko"),
|
||||
("Schülersignal wiederhergestellt", "trainok"),
|
||||
("Sensor verloren", "sensorko"),
|
||||
("servo Überlast", "servoko"),
|
||||
("power Überlast", "rxko"),
|
||||
("Empfänger noch verbunden", "modelpwr"),
|
||||
("Fehler", "error"), # Not shure if this is needed
|
||||
("Senderstrom zu hoch!", "highmah"), # Not shure if this is needed. Only used in PCBX9E
|
||||
("Sendertemperatur zu hoch!", "hightemp"), # Not shure if this is needed. Only used in PCBX9E
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
|
||||
for i, s in enumerate(["Uhr", "Uhr", "Sender", "Empfang", "A1", "A2", "Hoehe", "Motor",
|
||||
"Treibstoff", "Temperatur", "Temperatur", "Geschwindigkeit", "Entfernung", "Höhe", "Lipo-Zelle",
|
||||
"Zellen gesamt", "Spannung", "Strom", "Verbrauch", "Power", "Beschleunigung X", "Beschleunigung Y", "Beschleunigung Z",
|
||||
"Richtung", "Variometer", "Minimum", "Maximum"]):
|
||||
systemSounds.append((s, filename(134 + i)))
|
||||
|
||||
for i, (s, f) in enumerate([("Fahrwerk eingezogen", "gearup"),
|
||||
("Fahrwerk ausgefahren", "geardn"),
|
||||
("Klappen eingefahren", "flapup"),
|
||||
("Klappen ausgefahren", "flapdn"),
|
||||
("Landung", "lnding"),
|
||||
("Trainer-Modus ein", "trnon"),
|
||||
("Trainer-Modus aus", "trnoff"),
|
||||
("Motor aus", "engoff"),
|
||||
("Motor an", "engon"),
|
||||
("zu hoch", "tohigh"),
|
||||
("zu niedrig", "tolow"),
|
||||
("Batterie schwach", "lowbatt"),
|
||||
("Butterfly ein", "crowon"),
|
||||
("Butterfly aus", "crowof"),
|
||||
("Geschwindigkeits-Modus ist aktiviert", "fm-spd"),
|
||||
("Thermik-Modus ist aktiviert", "fm-thm"),
|
||||
("Normal-Modus ist aktiviert", "fm-nrm"),
|
||||
("Flugmodus 1", "fm-1"),
|
||||
("Flugmodus 2", "fm-2"),
|
||||
("Flugmodus 3", "fm-3"),
|
||||
("Flugmodus 4", "fm-4"),
|
||||
("Flugmodus 5", "fm-5"),
|
||||
("Flugmodus 6", "fm-6"),
|
||||
("Flugmodus 7", "fm-7"),
|
||||
("Flugmodus 8", "fm-8"),
|
||||
("Flugmodus 9", "fm-9"),
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
@@ -0,0 +1,84 @@
|
||||
The purpose of this document is to document the principle of TTS for CZ languages to non CZ speaker, with a strict focus on OpenTX TTS
|
||||
|
||||
## Large 'multiparts' numbers
|
||||
This is for numbers requiring assembly of basic number blocks, like 110 in english : `ONE` `HUNDRED` `TEN`
|
||||
|
||||
## Plural units forms
|
||||
|
||||
4 forms of plural exist in otx cz tts, bellow is the exemple for volts
|
||||
|
||||
`(u"volt", u"volt0"), (u"volty", u"volt1"), (u"voltů", u"volt2"),(u"voltu", u"volt3")`
|
||||
|
||||
In this document, we will use unit0 to unit3 to describe those 4 variations
|
||||
|
||||
## Interger numbers with unit
|
||||
|
||||
The number takes a from like X UNIT
|
||||
|
||||
#### "one ..."
|
||||
The number "one" has 3 gender depending on the unit F/M/N
|
||||
The forms are "jedna","jeden", "jedno"
|
||||
|
||||
See unit table bellow to find out wich gender of one should be used
|
||||
|
||||
unit0 is used with the 3 gender of one.
|
||||
|
||||
#### "two ..."
|
||||
The number "two" has 3 gender depending on the unit
|
||||
The forms are "dva","dvě"
|
||||
|
||||
See unit table bellow to find out wich gender of two should be used
|
||||
|
||||
unit1 is used with the 2 gender of two.
|
||||
|
||||
### "tree to five"
|
||||
|
||||
unit1 is used
|
||||
|
||||
### "five and more"
|
||||
|
||||
unit2 is used
|
||||
|
||||
|
||||
## decimal numbers with unit
|
||||
X.Y UNIT
|
||||
In this case unit is unit3. X and Y is allways FEM.
|
||||
|
||||
"point" has three forms depending on the value of X :
|
||||
0 and 1 : "celá"
|
||||
2, 3 , 4 : "celé"
|
||||
5 :"celých"
|
||||
|
||||
Note : opentx audio only deals with PREC1 numbers, so Y can only be integer 1 to 9
|
||||
|
||||
# Unit table
|
||||
|
||||
| Index | Unit | Defined as | One | Two | Gender
|
||||
| --- | --- |--- |--- |--- |---
|
||||
| 0 | Raw unit (no unit) | UNIT_RAW | jedna | dvě | Female
|
||||
| 1 | Volts | UNIT_VOLTS | jeden | dva | Male
|
||||
| 2 | Amps | UNIT_AMPS | jeden | dva | Male
|
||||
| 3 | Milliamps | UNIT_MILLIAMPS | jeden | dva | Male
|
||||
| 4 | Knots | UNIT_KTS | jeden | dva | Male
|
||||
| 5 | Meters per Second | UNIT_METERS_PER_SECOND | jeden | dva | Male
|
||||
| 6 | Feet per Second | UNIT_FEET_PER_SECOND | jedna | dvě | Female
|
||||
| 7 | Kilometers per Hour| UNIT_KMH | jeden | dva | Male
|
||||
| 8 | Miles per Hour | UNIT_MPH | jedna | dvě | Female
|
||||
| 9 | Meters | UNIT_METERS | jeden | dva | Male
|
||||
| 10 | Feet | UNIT_FEET | jedna | dvě | Female
|
||||
| 11 | Degrees Celsius | UNIT_CELSIUS | jeden | dva | Male
|
||||
| 12 | Degrees Fahrenheit | UNIT_FAHRENHEIT | jeden | dva | Male
|
||||
| 13 | Percent | UNIT_PERCENT | jedno | dvě | Neutral
|
||||
| 14 | Milliamp per Hour | UNIT_MAH | jedna | dvě | Female
|
||||
| 15 | Watts | UNIT_WATTS | jeden | dva | Male
|
||||
| 16 | Milliwatts | UNIT_MILLIWATTS | jeden | dva | Male
|
||||
| 17 | dB | UNIT_DB | jeden | dva | Male
|
||||
| 18 | RPM | UNIT_RPMS | jedna | dvě | Female
|
||||
| 19 | G | UNIT_G | jedno | dvě | Neutral
|
||||
| 20 | Degrees | UNIT_DEGREE | jeden | dva | Male
|
||||
| 21 | Radians | UNIT_RADIANS | jeden | dva | Male
|
||||
| 22 | Milliliters | UNIT_MILLILITERS | jeden | dva | Male
|
||||
| 23 | Fluid Ounces | UNIT_FLOZ | jedna | dvě | Female
|
||||
| 24 | Hours | UNIT_HOURS | jedna | dvě | Female
|
||||
| 25 | Minutes | UNIT_MINUTES | jedna | dvě | Female
|
||||
| 26 | Seconds | UNIT_SECONDS | jedna | dvě | Female
|
||||
Executable
+139
@@ -0,0 +1,139 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# English language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
for i in range(100):
|
||||
systemSounds.append((str(i), filename(i)))
|
||||
for i in range(9):
|
||||
systemSounds.append((str(100 * (i + 1)), filename(100 + i)))
|
||||
for i, s in enumerate(["thousand", "and", "minus", "point"]):
|
||||
systemSounds.append((s, filename(109 + i)))
|
||||
for i, (s, f) in enumerate([("volt", "volt0"), ("volts", "volt1"),
|
||||
("amp", "amp0"), ("amps", "amp1"),
|
||||
("milliamp", "mamp0"), ("milliamps", "mamp1"),
|
||||
("knot", "knot0"), ("knots", "knot1"),
|
||||
("meter per second", "mps0"), ("meters per second", "mps1"),
|
||||
("foot per second", "fps0"), ("feet per second", "fps1"),
|
||||
("kilometer per hour", "kph0"), ("kilometers per hour", "kph1"),
|
||||
("mile per hour", "mph0"), ("miles per hour", "mph1"),
|
||||
("meter", "meter0"), ("meters", "meter1"),
|
||||
("foot", "foot0"), ("feet", "foot1"),
|
||||
("degree celsius", "celsius0"), ("degrees celsius", "celsius1"),
|
||||
("degree fahrenheit", "fahr0"), ("degrees fahrenheit", "fahr1"),
|
||||
("percent", "percent0"), ("percent", "percent1"),
|
||||
("milliamp-hour", "mamph0"), ("milliamp-hours", "mamph1"),
|
||||
("watt", "watt0"), ("watts", "watt1"),
|
||||
("milli-watt", "mwatt0"), ("milli-watts", "mwatt1"),
|
||||
("D B", "db0"),("D B", "db1"),
|
||||
("r p m", "rpm0"),("r p m", "rpm1"),
|
||||
("g", "g0"),("g", "g1"),
|
||||
("degree", "degree0"), ("degrees", "degree1"),
|
||||
("radian", "rad0"), ("radians", "rad1"),
|
||||
("milliliter", "ml0"), ("milliliters", "ml1"),
|
||||
("fluid ounce", "founce0"), ("fluid ounces", "founce1"),
|
||||
("milliliter per minute", "mlpm0"), ("milliliters per minute", "mlpm1"),
|
||||
("hertz", "hertz0"), ("hertz", "hertz1"),
|
||||
("milisecond", "ms0"), ("miliseconds", "ms1"),
|
||||
("microsecond", "us0"), ("microseconds", "us1"),
|
||||
("kilometer", "km0"), ("kilometers", "km1"),
|
||||
("hour", "hour0"), ("hours", "hour1"),
|
||||
("minute", "minute0"), ("minutes", "minute1"),
|
||||
("second", "second0"), ("seconds", "second1"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, s in enumerate(["point zero", "point one", "point two", "point three",
|
||||
"point four", "point five", "point six",
|
||||
"point seven", "point eight", "point nine"]):
|
||||
systemSounds.append((s, filename(167 + i)))
|
||||
for s, f in [("trim center", "midtrim"),
|
||||
("maximum trim reached", "maxtrim"),
|
||||
("minimum trim reached", "mintrim"),
|
||||
("timer 1 elapsed", "timovr1"),
|
||||
("timer 2 elapsed", "timovr2"),
|
||||
("timer 3 elapsed", "timovr3"),
|
||||
("transmitter battery low", "lowbatt"),
|
||||
("inactivity alarm", "inactiv"),
|
||||
("throttle warning", "thralert"),
|
||||
("switch warning", "swalert"),
|
||||
("bad eeprom", "eebad"),
|
||||
("Welcome to open tea ex!", "hello"),
|
||||
("RF signal, low", "rssi_org"),
|
||||
("RF signal, critical", "rssi_red"),
|
||||
("radio antenna defective", "swr_red"),
|
||||
("telemetry lost", "telemko"),
|
||||
("telemetry recovered", "telemok"),
|
||||
("trainer signal lost", "trainko"),
|
||||
("trainer signal recovered", "trainok"),
|
||||
("sensor lost", "sensorko"),
|
||||
("servo overload", "servoko"),
|
||||
("power overload", "rxko"),
|
||||
("receiver still connected", "modelpwr"),
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, (s, f) in enumerate([("armed", "armed"),
|
||||
("disarmed", "disarm"),
|
||||
("throttle cut", "thrcut"),
|
||||
("throttle active", "thract"),
|
||||
("gear!, up!", "gearup"),
|
||||
("gear!, down!", "geardn"),
|
||||
("flaps!, up!", "flapup"),
|
||||
("flaps!, down!", "flapdn"),
|
||||
("spoiler!, up!", "splrup"),
|
||||
("spoiler!, down!", "splrdn"),
|
||||
("trainer!, on!", "trnon"),
|
||||
("trainer!, off!", "trnoff"),
|
||||
("engine!, off!", "engoff"),
|
||||
("too. high!", "tohigh"),
|
||||
("too. low!", "tolow"),
|
||||
("low. battery!", "lowbat"),
|
||||
("crow!, on!", "crowon"),
|
||||
("crow!, off!", "crowof"),
|
||||
("rf. signal!, low!", "siglow"),
|
||||
("rf. signal!, critical!", "sigcrt"),
|
||||
("LQ", "lq"),
|
||||
("RF mode", "rfmode"),
|
||||
("high. speed. mode!, active", "spdmod"),
|
||||
("thermal. mode!, on", "thmmod"),
|
||||
("normal. mode!, on", "nrmmod"),
|
||||
("landing. mode!, on", "lnding"),
|
||||
("acro. mode!, on", "acro"),
|
||||
("flight mode one", "fm-1"),
|
||||
("flight mode two", "fm-2"),
|
||||
("flight mode three", "fm-3"),
|
||||
("flight mode four", "fm-4"),
|
||||
("flight mode five", "fm-5"),
|
||||
("flight mode six", "fm-6"),
|
||||
("flight mode seven", "fm-7"),
|
||||
("flight mode eight", "fm-8"),
|
||||
("vario!, on", "vrion"),
|
||||
("vario!, off", "vrioff"),
|
||||
("flight mode power", "fm-pwr"),
|
||||
("flight mode land", "fm-lnd"),
|
||||
("flight mode float", "fm-flt"),
|
||||
("flight mode speed", "fm-spd"),
|
||||
("flight mode fast", "fm-fst"),
|
||||
("flight mode normal", "fm-nrm"),
|
||||
("flight mode cruise", "fm-crs"),
|
||||
("flight mode acro", "fm-acr"),
|
||||
("flight mode race", "fm-rce"),
|
||||
("flight mode launch", "fm-lch"),
|
||||
("flight mode ping", "fm-png"),
|
||||
("flight mode thermal", "fm-thm"),
|
||||
("flight mode thermal left", "fm-thl"),
|
||||
("flight mode thermal right", "fm-thr"),
|
||||
("flight mode stabilize", "fm-stb"),
|
||||
("flight mode horizon", "fm-hor"),
|
||||
("flight mode angle", "fm-ang"),
|
||||
("flight mode idle up 1", "fm-id1"),
|
||||
("flight mode idle up 2", "fm-id2"),
|
||||
("low rate", "ratlow"),
|
||||
("medium rate", "ratmed"),
|
||||
("high rate", "rathi"),
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
Executable
+110
@@ -0,0 +1,110 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Spanish language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
for i in range(101):
|
||||
systemSounds.append((str(i), filename(i)))
|
||||
systemSounds.append(("ciento", filename(101)))
|
||||
systemSounds.append(("doscientos", filename(102)))
|
||||
systemSounds.append(("trescientos", filename(103)))
|
||||
systemSounds.append(("cuatrocientos", filename(104)))
|
||||
systemSounds.append(("quinientos", filename(105)))
|
||||
systemSounds.append(("sescientos", filename(106)))
|
||||
systemSounds.append(("setecientos", filename(107)))
|
||||
systemSounds.append(("ochocientos", filename(108)))
|
||||
systemSounds.append(("nuevecientos", filename(109)))
|
||||
systemSounds.append(("mil", filename(110)))
|
||||
for i, s in enumerate(["coma", "un", "una", "i", "meno", "hora", "horas", "minuto", "minutos", "segundo", "segundos"]):
|
||||
systemSounds.append((s, filename(111 + i)))
|
||||
for i, (s, f) in enumerate([("Voltio","volt0"),
|
||||
("ampério", "amp0"),
|
||||
("miliamperios", "mamp0"),
|
||||
("knots", "knot0"),
|
||||
("metros por segundo", "mps0"),
|
||||
("pie por segundo", "fps0"),
|
||||
("kilómetro por hora", "kph0"),
|
||||
("millas por hora", "mph0"),
|
||||
("metros", "meter0"),
|
||||
("pie", "foot0"),
|
||||
("grados", "celsius0"),
|
||||
("fahrenheit", "fahr0"),
|
||||
("por ciento", "percent0"),
|
||||
("miliamperios por hora", "mamph0"),
|
||||
("vatio", "watt0"),
|
||||
("millivatio", "mwatt0"),
|
||||
("D B", "db0"),
|
||||
("R P M", "rpm0"),
|
||||
("g", "g0"),
|
||||
("grados", "degree0"),
|
||||
("radianes ", "rad0"),
|
||||
("mililitro", "ml0"),
|
||||
("onzas", "founce0"),
|
||||
("hora", "hour0"), ("horas", "hour1"),
|
||||
("milliliter per minute", "mlpm0"), ("milliliters per minute", "mlpm1"),
|
||||
("minuto", "minute0"), ("minutos", "minute1"),
|
||||
("segundo", "second0"), ("segundos", "second1"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
for s, f in [("me tienes abandonada", "inactiv"),
|
||||
("batería del transmisor baja", "lowbatt"),
|
||||
("El acelerador está activado, por favor, corrijalo", "thralert"),
|
||||
("Los interruptores no están en la posición correcta, por favor corrijalo", "swalert"),
|
||||
("eeprom corrompida", "eebad"),
|
||||
("error", "error"),
|
||||
("trim centrado", "midtrim"),
|
||||
("trim al máximo", "maxtrim"),
|
||||
("trim al mínimo", "mintrim"),
|
||||
("consumo alto", "highmah"),
|
||||
("temperatura alta", "hightemp"),
|
||||
("Bienvenido a open t equis", "hello"),
|
||||
("señal baja", "rssi_org"),
|
||||
("señal crítica", "rssi_red"),
|
||||
("Problemas con la antena del transmisor", "swr_red"),
|
||||
("Sin telemetría", "telemko"),
|
||||
("Telemetría disponible", "telemok"),
|
||||
("sobrecarga de servo", "servoko"),
|
||||
("sobrecarga de potencia", "rxko"),
|
||||
("El receptor aún está encendido", "modelpwr"),
|
||||
("cronómetro uno terminado", "timovr1"),
|
||||
("cronómetro dos terminado", "timovr2"),
|
||||
("cronómetro tres terminado", "timovr3"),
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, s in enumerate(["cronómetro", "cronómetro", "transmisión", "recepción", "A1", "A2", "altitud", "motor",
|
||||
"combustible", "temperatura", "temperatura", "velocidad", "distancia", "altitude", "célula lipo",
|
||||
"Total lipo", "voltaje", "corriente", "consumo", "potencia", "aceleración X", "aceleración Y", "aceleración Z",
|
||||
"dirección", "variómetro", "minimo", "máximo"]):
|
||||
systemSounds.append((s, filename(141 + i)))
|
||||
for i, (s, f) in enumerate([("tren arriba.", "gearup"),
|
||||
("tren abajo.", "geardn"),
|
||||
("flaps arriba", "flapup"),
|
||||
("flaps abajo", "flapdn"),
|
||||
("aterrizaje", "attero"),
|
||||
("modo de entrenamiento activado", "trnon"),
|
||||
("modo de entrenamiento deshabilitado", "trnoff"),
|
||||
("motor apagado", "engoff"),
|
||||
("muy alto", "tohigh"),
|
||||
("muy bajo", "tolow"),
|
||||
("bateria baja", "lowbat"),
|
||||
("crou, activo", "crowon"),
|
||||
("crou, desligado", "crowof"),
|
||||
("modo de velocidad", "spdmod"),
|
||||
("modo de térmica", "thmmod"),
|
||||
("modo de vuelo normal", "nrmmod"),
|
||||
("modo de vuelo 1", "fltmd1"),
|
||||
("modo de vuelo 2", "fltmd2"),
|
||||
("modo de vuelo 3", "fltmd3"),
|
||||
("modo de vuelo 4", "fltmd4"),
|
||||
("modo de vuelo 5", "fltmd5"),
|
||||
("modo de vuelo 6", "fltmd6"),
|
||||
("modo de vuelo 7", "fltmd7"),
|
||||
("modo de vuelo 8", "fltmd8"),
|
||||
("modo de vuelo 9", "fltmd9"),
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# French language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
for i in range(100):
|
||||
systemSounds.append((str(i), filename(i)))
|
||||
for i in range(10):
|
||||
systemSounds.append((str(100 * (i + 1)), filename(100 + i)))
|
||||
for i, s in enumerate(["une", "onze", "vingt et une", "trente et une", "quarante et une", "cinquante et une", "soixante et une", "soixante et onze", "quatre vingt une"]):
|
||||
systemSounds.append((s, filename(110 + i)))
|
||||
for i, s in enumerate(["virgule", "et", "moins", "minuit", "midi"]):
|
||||
systemSounds.append((s, filename(119 + i)))
|
||||
for i, (s, f) in enumerate([("volts", "volt0"),
|
||||
("ampères", "amp0"),
|
||||
("milli ampères", "mamp0"),
|
||||
("noeud", "knot0"),
|
||||
("mètres seconde", "mps0"),
|
||||
("pieds par seconde", "fps0"),
|
||||
("kilomètre heure", "kph0"),
|
||||
("miles par heure", "mph0"),
|
||||
("mètres", "meter0"),
|
||||
("pieds", "foot0"),
|
||||
("degrés", "celsius0"),
|
||||
("degrés fahrenheit", "degf0"),
|
||||
("pourcents", "percent0"),
|
||||
("milli ampères heure", "mamph0"),
|
||||
("watt", "watt0"),
|
||||
("milli watt", "mwatt0"),
|
||||
("d b", "db0"),
|
||||
("tours minute", "rpm0"),
|
||||
("g", "g0"),
|
||||
("degrés", "degree0"),
|
||||
("radians", "rad0"),
|
||||
("millilitres", "ml0"),
|
||||
("onces", "founce0"),
|
||||
("millilitre minute", "mlpm0"),
|
||||
("microsecond", "us0"),
|
||||
("milisecond", "ms0"),
|
||||
("hertz", "hertz0"),
|
||||
("kilometre", "km0"),
|
||||
("heure", "hour0"),
|
||||
("minute", "minute0"),
|
||||
("seconde", "second0"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, s in enumerate(["virgule 0", "virgule 1", "virgule 2", "virgule 3", "virgule 4", "virgule 5", "virgule 6", "virgule 7", "virgule 8", "virgule 9"]):
|
||||
systemSounds.append((s, filename(180 + i)))
|
||||
for s, f in [("Trim centré", "midtrim"),
|
||||
("Trim maximum atteint", "maxtrim"),
|
||||
("Trim minimum atteint", "mintrim"),
|
||||
("Chrono 1 à 0", "timovr1"),
|
||||
("Chrono 2 à 0", "timovr2"),
|
||||
("Chrono 3 à 0", "timovr3"),
|
||||
("Batterie radio faible !", "lowbatt"),
|
||||
("Radio inactive !", "inactiv"),
|
||||
("Alerte manche des gaz", "thralert"),
|
||||
("Alerte inters", "swalert"),
|
||||
("éprome corrompue", "eebad"),
|
||||
("Bienvenue sur o pun t x", "hello"),
|
||||
("Signal RF, faible", "rssi_org"),
|
||||
("Signal RF, critique", "rssi_red"),
|
||||
("Antenne défectueuse", "swr_red"),
|
||||
("Télémétrie perdue", "telemko"),
|
||||
("Télémétrie retrouvée", "telemok"),
|
||||
("Signal écolage perdu", "trainko"),
|
||||
("Signal écolage retrouvé", "trainok"),
|
||||
("Sonde de télémétrie perdue", "sensorko"),
|
||||
("Servo en surcharge", "servoko"),
|
||||
("Surcharge réception", "rxko"),
|
||||
("Récepteur encore sous tension", "modelpwr"),
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, (s, f) in enumerate([("armé", "armed"),
|
||||
("désarmé", "disarm"),
|
||||
("altitude", "alt"),
|
||||
("température moteur", "moteur"),
|
||||
("température contrôleur", "tctrl"),
|
||||
("train rentré", "gearup"),
|
||||
("train sorti", "geardn"),
|
||||
("volets rentrés", "flapup"),
|
||||
("volets sortis", "flapdn"),
|
||||
("atterrissage", "attero"),
|
||||
("écolage", "trnon"),
|
||||
("fin écolage", "trnoff"),
|
||||
("moteur coupé", "engoff"),
|
||||
("high. speed. mode!, active", "spdmod"),
|
||||
("thermal. mode!, on", "thmmod"),
|
||||
("normal. mode!, on", "nrmmod"),
|
||||
("landing. mode!, on", "lnding"),
|
||||
("mode acro", "acro"),
|
||||
("mode de vol un", "fm-1"),
|
||||
("mode de vol deux", "fm-2"),
|
||||
("mode de vol trois", "fm-3"),
|
||||
("mode de vol quatre", "fm-4"),
|
||||
("mode de vol 5", "fm-5"),
|
||||
("mode de vol 6", "fm-6"),
|
||||
("mode de vol sept", "fm-7"),
|
||||
("mode de vol 8", "fm-8"),
|
||||
("vario activé", "vrion"),
|
||||
("vario désactivé", "vrioff"),
|
||||
("mode de vol puissance", "fm-pwr"),
|
||||
("mode de vol attérissage", "fm-lnd"),
|
||||
("mode de vol amérissage", "fm-flt"),
|
||||
("mode de vol vitesse", "fm-spd"),
|
||||
("mode de vol rapide", "fm-fst"),
|
||||
("mode de vol normal", "fm-nrm"),
|
||||
("mode de vol de croisière", "fm-crs"),
|
||||
("mode de vol acro", "fm-acr"),
|
||||
("mode de vol course", "fm-rce"),
|
||||
("mode de vol lancé", "fm-lch"),
|
||||
("mode de vol ping", "fm-png"),
|
||||
("mode de vol thermique", "fm-thm"),
|
||||
("mode de vol thermique gauche", "fm-thl"),
|
||||
("mode de vol thermique droit", "fm-thr"),
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Italian language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
for i in range(101):
|
||||
systemSounds.append((str(i), filename(i)))
|
||||
systemSounds.append(("mila", filename(101)))
|
||||
systemSounds.append(("mille", filename(102)))
|
||||
for i, s in enumerate(["virgola", "un", "e", "meno", "ora", "ore", "minuto", "minuti", "secondo", "secondi"]):
|
||||
systemSounds.append((s, filename(103 + i)))
|
||||
for i, (s, f) in enumerate([("volt", "volt0"),("volt", "volt1"),
|
||||
("ampere", "amp0"),("ampere", "amp1"),
|
||||
("milliampere", "mamp0"),("milliampere", "mamp1"),
|
||||
("nodo", "knot0"), ("nodi", "knot1"),
|
||||
("metri al secondo", "mps0"), ("metri al secondo", "msp1"),
|
||||
("piedi al secondo", "fps0"), ("piedi al secondo", "fps1"),
|
||||
("chilometri orari", "kph0"), ("chilometri orari", "kph1"),
|
||||
("miglia orarie", "mph0"), ("miglia orarie", "mph1"),
|
||||
("metro", "meter0"), ("metri", "meter1"),
|
||||
("piede", "foot0"), ("piedi", "foot1"),
|
||||
("grado celsius", "celsius0"), ("gradi celsius", "celsius1"),
|
||||
("grado fahrenheit", "fahr0"), ("gradi fahrenheit", "fahr1"),
|
||||
("percento", "percent0"), ("percento", "percent1"),
|
||||
("milliampere ora", "mamph0"), ("milliampere ora", "mamph1"),
|
||||
("watt", "watt0"), ("watt", "watt1"),
|
||||
("milli-watt", "mwatt0"), ("milli-watt", "mwatt1"),
|
||||
("d b", "db0"), ("d b", "db1"),
|
||||
("r p m", "rpm0"), ("r p m", "rpm1"),
|
||||
("g", "g0"), ("g", "g1"),
|
||||
("grado", "degree0"), ("gradi", "degree1"),
|
||||
("radiante", "rad0"), ("radianti", "rad1"),
|
||||
("millilitro", "m10"), ("millilitri", "m11"),
|
||||
("oncia fluida", "founce0"), ("once fluide", "founce1"),
|
||||
("millilitro per minuto", "mlpm0"), ("millilitri per minuto", "mlpm1"),
|
||||
("ora", "hour0"), ("ore", "hour1"),
|
||||
("minuto", "minute0"), ("minuti", "minute1"),
|
||||
("secondo", "second0"), ("secondi", "second1"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
for s, f in [("radio inattiva controllare", "inactiv"),
|
||||
("batteria della radio scarica", "lowbatt"),
|
||||
("controllo motore non in posizione, verificare", "thralert"),
|
||||
("interruttori non in posizione, verificare", "swalert"),
|
||||
("eeprom corrotta", "eebad"),
|
||||
("errore", "error"),
|
||||
("trim centrato", "midtrim"),
|
||||
("massimo trim raggiunto", "maxtrim"),
|
||||
("minimo trim raggiunto", "mintrim"),
|
||||
("assorbimento elevato", "highmah"),
|
||||
("temperatura elevata", "hightemp"),
|
||||
("Segnale radio basso", "rssi_org"),
|
||||
("Segnale radio critico", "rssi_red"),
|
||||
("Problema all'antenna della radio", "swr_red"),
|
||||
("Telemetria assente", "telemko"),
|
||||
("Telemetria disponibile", "telemok"),
|
||||
("Segnale trainer perso", "trainko"),
|
||||
("Segnale trainer disponibile", "trainok"),
|
||||
("Sensore perso", "sensorko"),
|
||||
("sovraccarico servo", "servoko"),
|
||||
("sovraccarico di alimentazione", "rxko"),
|
||||
("ricevente ancora connessa", "modelpwr"),
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, s in enumerate(["timer", "", "tensione", "tensione", "trasmissione", "ricezione", "altitudine", "motore",
|
||||
"carburante", "temperatura", "temperatura", "velocità", "distanza", "altitudine", "cella lipo",
|
||||
"totale lipo", "tensione", "corrente", "consumo", "potenza", "accelerazione X", "accelerazione Y", "accelerazione Z",
|
||||
"direzione", "variometro", "minimo", "massimo"]):
|
||||
systemSounds.append((s, filename(155 + i)))
|
||||
for i, (s, f) in enumerate([("carrello chiuso", "gearup"),
|
||||
("carrello aperto", "geardn"),
|
||||
("flap rientrati", "flapup"),
|
||||
("flap estesi", "flapdn"),
|
||||
("spoiler su", "splrup"),
|
||||
("spoiler giù", "splrdn"),
|
||||
("atterraggio", "attero"),
|
||||
("modalità maestro attiva", "trnon"),
|
||||
("modalità maestro disattiva", "trnoff"),
|
||||
("motore spento", "engoff"),
|
||||
("troppo alto", "tohigh"),
|
||||
("troppo basso", "tolow"),
|
||||
("batteria scarica", "lowbat"),
|
||||
("crow attivato", "crowon"),
|
||||
("crow disattivato", "crowof"),
|
||||
("segnale radio basso", "siglow"),
|
||||
("segnale radio critico", "sigcrt"),
|
||||
("modo velocità", "spdmod"),
|
||||
("modo termica", "thmmod"),
|
||||
("modo volo normale", "nrmmod"),
|
||||
("modo atterraggio", "lnding"),
|
||||
("modo acro", "acro"),
|
||||
("fase di volo 1", "fltmd1"),
|
||||
("fase di volo 2", "fltmd2"),
|
||||
("fase di volo 3", "fltmd3"),
|
||||
("fase di volo 4", "fltmd4"),
|
||||
("fase di volo 5", "fltmd5"),
|
||||
("fase di volo 6", "fltmd6"),
|
||||
("fase di volo 7", "fltmd7"),
|
||||
("variometro attivato", "vrion"),
|
||||
("variometro disabilitato", "vrioff"),
|
||||
("fase di volo power", "fm-pwr"),
|
||||
("fase di volo land", "fm-lnd"),
|
||||
("fase di volo planata", "fm-flt"),
|
||||
("fase di volo velocità", "fm-spd"),
|
||||
("fase di volo veloce", "fm-fst"),
|
||||
("fase di volo normale", "fm-nrm"),
|
||||
("fase di volo cruise", "fm-crs"),
|
||||
("fase di volo acro", "fm-acr"),
|
||||
("fase di volo race", "fm-rce"),
|
||||
("fase di volo lancio", "fm-lch"),
|
||||
("fase di volo ping", "fm-png"),
|
||||
("fase di volo termica", "fm-thm"),
|
||||
("fase di volo termica sinistra", "fm-thl"),
|
||||
("fase di volo termica destra", "fm-thr"),
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Portuguese language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
for i in range(101):
|
||||
systemSounds.append((str(i), filename(i)))
|
||||
systemSounds.append(("cento", filename(101)))
|
||||
systemSounds.append(("duzentos", filename(102)))
|
||||
systemSounds.append(("trezentos", filename(103)))
|
||||
systemSounds.append(("quatrocentos", filename(104)))
|
||||
systemSounds.append(("quinhentos", filename(105)))
|
||||
systemSounds.append(("seiscentos", filename(106)))
|
||||
systemSounds.append(("setecentos", filename(107)))
|
||||
systemSounds.append(("oitocentos", filename(108)))
|
||||
systemSounds.append(("novecentos", filename(109)))
|
||||
systemSounds.append(("mil", filename(110)))
|
||||
for i, s in enumerate(["virgula", "uma", "duas", "e", "menos", "hora", "horas", "minuto", "minutos", "segundo", "segundos"]):
|
||||
systemSounds.append((s, filename(111 + i)))
|
||||
for i, (s, f) in enumerate([("Volt", "volt0"),
|
||||
("ampére", "amp0"),
|
||||
("miliamperes", "mamp0"),
|
||||
("knot", "knot0"),
|
||||
("metros por segundo", "mps0"),
|
||||
("foot per second", "fps0"),
|
||||
("quilômetros por hora", "kph0"),
|
||||
("mile per hour", "mph0"),
|
||||
("metros", "meter0"),
|
||||
("foot", "foot0"),
|
||||
("degree celsius", "celsius0"),
|
||||
("degree fahrenheit", "fahr0"),
|
||||
("percent", "percent0"),
|
||||
("miliamperes por hora", "mamph0"),
|
||||
("watt", "watt0"),
|
||||
("milli-watt", "mwatt0"),
|
||||
("db", "db0"),
|
||||
("r p m", "rpm0"),
|
||||
("g", "g0"),
|
||||
("degree", "degree0"),
|
||||
("radian", "rad0"),
|
||||
("milliliter", "ml0"),
|
||||
("onças", "founce0"),
|
||||
("milliliter per minute", "mlpm0"), ("milliliters per minute", "mlpm1"),
|
||||
("horas", "hour0"),
|
||||
("minutos", "minute0"),
|
||||
("segundos", "second0"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
for s, f in [("atenção, o rádio foi esquecido ligado, por favor desligue-o", "inactiv"),
|
||||
("bateria do rádio fraca", "lowbatt"),
|
||||
("atenção,acelerador não está no mínimo", "thralert"),
|
||||
("atenção, certifique-se que os interruptores estão na posição certa", "swalert"),
|
||||
("eeprom corrompida", "eebad"),
|
||||
("erro", "error"),
|
||||
("trim centrado", "midtrim"),
|
||||
("trim no máximo", "maxtrim"),
|
||||
("trim no mínimo", "mintrim"),
|
||||
("assorbimento elevato", "highmah"),
|
||||
("temperatura elevata", "hightemp"),
|
||||
("recepção de sinal muito baixa", "rssi_org"),
|
||||
("recepção de sinal crítica", "rssi_red"),
|
||||
("Problema com a antena do transmissor", "swr_red"),
|
||||
("servo overload", "servoko"),
|
||||
("power overload", "rxko"),
|
||||
("receiver still connected", "modelpwr"),
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
for i, s in enumerate(["cronómetro", "cronómetro", "transmissão", "recepção", "A1", "A2", "altitude", "motor",
|
||||
"combustível", "temperatura", "temperatura", "velocidade", "distância", "altitude", "célula lipo",
|
||||
"Total lipo", "tensão", "corrente", "consumo", "potência", "aceleração X", "aceleração Y", "aceleração Z",
|
||||
"Direcção", "variómetro", "mínimo", "máximo"]):
|
||||
systemSounds.append((s, filename(141 + i)))
|
||||
for i, (s, f) in enumerate([("trem, em cima.", "gearup"),
|
||||
("trem, em baixo.", "geardn"),
|
||||
("flaps recolhidos", "flapup"),
|
||||
("flaps estendidos", "flapdn"),
|
||||
("aterragem", "attero"),
|
||||
("modo de treino ligado", "trnon"),
|
||||
("modo de treino desligado", "trnoff"),
|
||||
("motor desligado", "engoff"),
|
||||
("muito alto", "tohigh"),
|
||||
("muito baixo", "tolow"),
|
||||
("bateria fraca", "lowbat"),
|
||||
("crou, activo", "crowon"),
|
||||
("crou, desligado", "crowof"),
|
||||
("modo de velocidade", "spdmod"),
|
||||
("modo de térmica", "thmmod"),
|
||||
("modo de voo normal", "nrmmod"),
|
||||
("fase de voo 1", "fltmd1"),
|
||||
("fase de voo 2", "fltmd2"),
|
||||
("fase de voo 3", "fltmd3"),
|
||||
("fase de voo 4", "fltmd4"),
|
||||
("fase de voo 5", "fltmd5"),
|
||||
("fase de vôo 6", "fltmd6"),
|
||||
("fase de voo 7", "fltmd7"),
|
||||
("fase de voo 8", "fltmd8"),
|
||||
("fase de voo 9", "fltmd9"),
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
@@ -0,0 +1,171 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Russian language sounds configuration
|
||||
|
||||
from tts_common import filename
|
||||
|
||||
|
||||
systemSounds = []
|
||||
sounds = []
|
||||
|
||||
# 0 - 100
|
||||
for i in range(100):
|
||||
systemSounds.append((str(i), filename(i)))
|
||||
# 100, 200, ... 900
|
||||
for i in range(9):
|
||||
systemSounds.append((str(100 * (i + 1)), filename(100 + i)))
|
||||
for i, s in enumerate([u"тысяча", u"и", u"минус"]):
|
||||
systemSounds.append((s, filename(109 + i)))
|
||||
|
||||
for i, s in enumerate([u"тысяча", u"тысячи", u"тысяч"]):
|
||||
systemSounds.append((s, filename(200 + i)))
|
||||
|
||||
# decimal point
|
||||
for i, s in enumerate([u"ровно", u"и одна десятая", u"и две десятых", u"и три десятых", u"и четыре десятых",
|
||||
u"и пять десятых", u"и шесть десятых", u"и семь десятых", u"и восемь десятых", u"и девять десятых" ]):
|
||||
systemSounds.append((s, filename(165 + i)))
|
||||
|
||||
# last digit = 1, female
|
||||
for i, s in enumerate([u"одна", u"одиннадцать", u"двадцать одна", u"тридцать одна", u"сорок одна",
|
||||
u"пятьдесят одна", u"шестьдесят одна", u"семьдесят одна", u"восемьдесят одна", u"девяносто одна"]):
|
||||
systemSounds.append((s, filename(180 + i)))
|
||||
|
||||
# last digit = 2, female
|
||||
for i, s in enumerate([u"две", u"двенадцать", u"двадцать две", u"тридцать две", u"сорок две",
|
||||
u"пятьдесят две", u"шестьдесят две", u"семьдесят две", u"восемьдесят две", u"девяносто две"]):
|
||||
systemSounds.append((s, filename(190 + i)))
|
||||
|
||||
for i, (s, f) in enumerate([(u"вольт", "volt0"), (u"вольт", "volt1"),
|
||||
(u"вольта", "volt2"), (u"вольт", "volt5"),
|
||||
(u"ампер", "amp0"), (u"ампер", "amp1"),
|
||||
(u"ампера", "amp2"), (u"ампер", "amp5"),
|
||||
(u"миллиампер", "mamp0"), (u"миллиампер", "mamp1"),
|
||||
(u"миллиампера", "mamp2"), (u"миллиампер", "mamp5"),
|
||||
(u"узлов", "knot0"), (u"узел", "knot1"),
|
||||
(u"узла", "knot2"), (u"узлов", "knot5"),
|
||||
(u"метров в секунду", "mps0"), (u"метр в секунду", "mps1"),
|
||||
(u"метра в секунду", "mps2"), (u"метров в секунду", "mps5"),
|
||||
(u"футов в секунду", "fps0"), (u"фут в секунду", "fps1"),
|
||||
(u"фута в секунду", "fps2"), (u"футов в секунду", "fps5"),
|
||||
(u"километров в час", "kph0"), (u"километр в час", "kph1"),
|
||||
(u"километра в час", "kph2"), (u"километров в час", "kph5"),
|
||||
(u"миль в час", "mph0"), (u"миля в час", "mph1"),
|
||||
(u"мили в час", "mph2"), (u"миль в час", "mph5"),
|
||||
(u"метров", "meter0"), (u"метр", "meter1"),
|
||||
(u"метра", "meter2"), (u"метров", "meter5"),
|
||||
(u"футов", "foot0"), (u"фут", "foot1"),
|
||||
(u"фута", "foot2"), (u"футов", "foot5"),
|
||||
(u"градусов", "celsius0"), (u"градус", "celsius1"),
|
||||
(u"градуса", "celsius2"), (u"градусов", "celsius5"),
|
||||
(u"градусов по фаренгейту", "fahr0"), (u"градус по фаренгейту", "fahr1"),
|
||||
(u"градуса по фаренгейту", "fahr2"), (u"градусов по фаренгейту", "fahr5"),
|
||||
(u"процентов", "percent0"), (u"процент", "percent1"),
|
||||
(u"процента", "percent2"), (u"процентов", "percent5"),
|
||||
(u"миллиампер в час", "mamph0"), (u"миллиампер в час", "mamph1"),
|
||||
(u"миллиампера в час", "mamph2"), (u"миллиампер в час", "mamph5"),
|
||||
(u"ватт", "watt0"), (u"ватт", "watt1"),
|
||||
(u"ватта", "watt2"), (u"ватт", "watt5"),
|
||||
(u"милливатт", "mwatt0"), (u"милливатт", "mwatt1"),
|
||||
(u"милливатта", "mwatt2"), (u"милливатт", "mwatt5"),
|
||||
(u"децибел", "db0"),(u"децибел", "db1"),
|
||||
(u"децибела", "db2"),(u"децибел", "db5"),
|
||||
(u"оборотов в минуту", "rpm0"),(u"оборот в минуту", "rpm1"),
|
||||
(u"оборота в минуту", "rpm2"),(u"оборотов в минуту", "rpm5"),
|
||||
(u"джи", "g0"),(u"джи", "g1"),
|
||||
(u"джи", "g2"),(u"джи", "g5"),
|
||||
(u"градусов", "degree0"), (u"градус", "degree1"),
|
||||
(u"градуса", "degree2"), (u"градусов", "degree5"),
|
||||
(u"радиан", "rad0"), (u"радиан", "rad1"),
|
||||
(u"радиана", "rad2"), (u"радиан", "rad5"),
|
||||
(u"миллилитров", "ml0"), (u"миллилитр", "ml1"),
|
||||
(u"миллилитра", "ml2"), (u"миллилитров", "ml5"),
|
||||
(u"унций", "founce0"), (u"унция", "founce1"),
|
||||
(u"унции", "founce2"), (u"унций", "founce5"),
|
||||
(u"часов", "hour0"), (u"час", "hour1"),
|
||||
(u"часа", "hour2"), (u"часов", "hour5"),
|
||||
(u"минут", "minute0"), (u"минута", "minute1"),
|
||||
(u"минуты", "minute2"), (u"минут", "minute5"),
|
||||
(u"секунд", "second0"), (u"секунда", "second1"),
|
||||
(u"секунды", "second2"), (u"секунд", "second5"),
|
||||
]):
|
||||
systemSounds.append((s, filename(f)))
|
||||
|
||||
for s, f in [
|
||||
(u"Триммер по центру", "midtrim"),
|
||||
(u"Триммер максимум", "maxtrim"),
|
||||
(u"Триммер минимум", "mintrim"),
|
||||
(u"Таймер 1. Время вышло", "timovr1"),
|
||||
(u"Таймер 2. Время вышло", "timovr2"),
|
||||
(u"Таймер 3. Время вышло", "timovr3"),
|
||||
(u"Аккумулятор садится!", "lowbatt"),
|
||||
(u"Внимание, пульт не выключен!", "inactiv"),
|
||||
(u"Проверь газ!", "thralert"),
|
||||
(u"Проверь, тумблеры!", "swalert"),
|
||||
(u"Ошибка памяти", "eebad"),
|
||||
(u"Опен тэ, икс приветствует вас!", "hello"),
|
||||
(u"Слабый сигнал!", "rssi_org"),
|
||||
(u"Очень слабый сигнал!", "rssi_red"),
|
||||
(u"Проблема с антэнной!", "swr_red"),
|
||||
(u"Телеметрия потеряна", "telemko"),
|
||||
(u"Телеметрия восстановлена", "telemok"),
|
||||
(u"Тренерский сигнал потерян", "trainko"),
|
||||
(u"Тренерский сигнал восстановлен", "trainok"),
|
||||
(u"Сенсор отключен", "sensorko"),
|
||||
(u"Серва перегружена", "servoko"),
|
||||
(u"Перегрузка", "rxko"),
|
||||
(u"Приемник всё ещё подключен!", "modelpwr"),
|
||||
]:
|
||||
systemSounds.append((s, filename(f)))
|
||||
|
||||
for i, (s, f) in enumerate([
|
||||
(u"Аккумулятор садится!", "lowbat"),
|
||||
(u"Шасси, убраны'", "gearup"),
|
||||
(u"Шасси, выпущены", "geardn"),
|
||||
(u"Закрылки убраны'", "flapup"),
|
||||
(u"Закрылки выпущены", "flapdn"),
|
||||
(u"Спойлеры выпущены", "splrup"),
|
||||
(u"Спойлеры - убраны'", "splrdn"),
|
||||
(u"Тренер: подключен", "trnon"),
|
||||
(u"Тренер: отключен", "trnoff"),
|
||||
(u"Двигатели запущены!", "armed"),
|
||||
(u"Двигатели выключены", "disarm"),
|
||||
(u"Слишком высоко", "tohigh"),
|
||||
(u"Слишком низко", "tolow"),
|
||||
(u"Низкий уровень сигнала", "siglow"),
|
||||
(u"Критически низкий уровень сигнала", "sigcrt"),
|
||||
(u"Полетный режим один", "fm-1"),
|
||||
(u"Полетный режим два", "fm-2"),
|
||||
(u"Полетный режим три", "fm-3"),
|
||||
(u"Полетный режим четыре", "fm-4"),
|
||||
(u"Полетный режим пять", "fm-5"),
|
||||
(u"Полетный режим шесть", "fm-6"),
|
||||
(u"Полетный режим семь", "fm-7"),
|
||||
(u"Полетный режим восемь", "fm-8"),
|
||||
(u"Режим,акро", "fm-acr"),
|
||||
(u"Режим круиза", "fm-crs"),
|
||||
(u"Режим взлета", "fm-lch"),
|
||||
(u"Режим посадки", "fm-lnd"),
|
||||
(u"Нормальный режим", "fm-nrm"),
|
||||
(u"Ручной режим", "fm-man"),
|
||||
(u"Стабилизация", "fm-stb"),
|
||||
(u"Удержание позиции", "fm-hld"),
|
||||
(u"Возврат в точку старта", "fm-rth"),
|
||||
(u"Горизонт", "fm-hor"),
|
||||
(u"Стабилизация", "fm-ang"),
|
||||
(u"аирмод включен", "airmon"),
|
||||
(u"аирмод выключен", "airmof"),
|
||||
(u"Высота", "alt"),
|
||||
(u"Удержание высоты", "althld"),
|
||||
(u"Критический разряд!", "batcrt"),
|
||||
(u"Время полета", "flttm"),
|
||||
(u"Аварийный режим выключен", "fsoff"),
|
||||
(u"Аварийный режим включен", "fson"),
|
||||
(u"ДжиПи Эс", "gps"),
|
||||
(u"Высокие расходы", "hirate"),
|
||||
(u"Низкие расходы", "lorate"),
|
||||
(u"Спутники найдены!", "satfix"),
|
||||
(u"Спутники потеряны!", "satlst"),
|
||||
(u"Бортовые огни выключены", "ledoff"),
|
||||
(u"Бортовые огни включены", "ledon")
|
||||
]):
|
||||
sounds.append((s, filename(f)))
|
||||
@@ -0,0 +1,272 @@
|
||||
SYSTEM|0000|0
|
||||
SYSTEM|0001|1
|
||||
SYSTEM|0002|2
|
||||
SYSTEM|0003|3
|
||||
SYSTEM|0004|4
|
||||
SYSTEM|0005|5
|
||||
SYSTEM|0006|6
|
||||
SYSTEM|0007|7
|
||||
SYSTEM|0008|8
|
||||
SYSTEM|0009|9
|
||||
SYSTEM|0010|10
|
||||
SYSTEM|0011|11
|
||||
SYSTEM|0012|12
|
||||
SYSTEM|0013|13
|
||||
SYSTEM|0014|14
|
||||
SYSTEM|0015|15
|
||||
SYSTEM|0016|16
|
||||
SYSTEM|0017|17
|
||||
SYSTEM|0018|18
|
||||
SYSTEM|0019|19
|
||||
SYSTEM|0020|20
|
||||
SYSTEM|0021|21
|
||||
SYSTEM|0022|22
|
||||
SYSTEM|0023|23
|
||||
SYSTEM|0024|24
|
||||
SYSTEM|0025|25
|
||||
SYSTEM|0026|26
|
||||
SYSTEM|0027|27
|
||||
SYSTEM|0028|28
|
||||
SYSTEM|0029|29
|
||||
SYSTEM|0030|30
|
||||
SYSTEM|0031|31
|
||||
SYSTEM|0032|32
|
||||
SYSTEM|0033|33
|
||||
SYSTEM|0034|34
|
||||
SYSTEM|0035|35
|
||||
SYSTEM|0036|36
|
||||
SYSTEM|0037|37
|
||||
SYSTEM|0038|38
|
||||
SYSTEM|0039|39
|
||||
SYSTEM|0040|40
|
||||
SYSTEM|0041|41
|
||||
SYSTEM|0042|42
|
||||
SYSTEM|0043|43
|
||||
SYSTEM|0044|44
|
||||
SYSTEM|0045|45
|
||||
SYSTEM|0046|46
|
||||
SYSTEM|0047|47
|
||||
SYSTEM|0048|48
|
||||
SYSTEM|0049|49
|
||||
SYSTEM|0050|50
|
||||
SYSTEM|0051|51
|
||||
SYSTEM|0052|52
|
||||
SYSTEM|0053|53
|
||||
SYSTEM|0054|54
|
||||
SYSTEM|0055|55
|
||||
SYSTEM|0056|56
|
||||
SYSTEM|0057|57
|
||||
SYSTEM|0058|58
|
||||
SYSTEM|0059|59
|
||||
SYSTEM|0060|60
|
||||
SYSTEM|0061|61
|
||||
SYSTEM|0062|62
|
||||
SYSTEM|0063|63
|
||||
SYSTEM|0064|64
|
||||
SYSTEM|0065|65
|
||||
SYSTEM|0066|66
|
||||
SYSTEM|0067|67
|
||||
SYSTEM|0068|68
|
||||
SYSTEM|0069|69
|
||||
SYSTEM|0070|70
|
||||
SYSTEM|0071|71
|
||||
SYSTEM|0072|72
|
||||
SYSTEM|0073|73
|
||||
SYSTEM|0074|74
|
||||
SYSTEM|0075|75
|
||||
SYSTEM|0076|76
|
||||
SYSTEM|0077|77
|
||||
SYSTEM|0078|78
|
||||
SYSTEM|0079|79
|
||||
SYSTEM|0080|80
|
||||
SYSTEM|0081|81
|
||||
SYSTEM|0082|82
|
||||
SYSTEM|0083|83
|
||||
SYSTEM|0084|84
|
||||
SYSTEM|0085|85
|
||||
SYSTEM|0086|86
|
||||
SYSTEM|0087|87
|
||||
SYSTEM|0088|88
|
||||
SYSTEM|0089|89
|
||||
SYSTEM|0090|90
|
||||
SYSTEM|0091|91
|
||||
SYSTEM|0092|92
|
||||
SYSTEM|0093|93
|
||||
SYSTEM|0094|94
|
||||
SYSTEM|0095|95
|
||||
SYSTEM|0096|96
|
||||
SYSTEM|0097|97
|
||||
SYSTEM|0098|98
|
||||
SYSTEM|0099|99
|
||||
SYSTEM|0100|100
|
||||
SYSTEM|0101|200
|
||||
SYSTEM|0102|300
|
||||
SYSTEM|0103|400
|
||||
SYSTEM|0104|500
|
||||
SYSTEM|0105|600
|
||||
SYSTEM|0106|700
|
||||
SYSTEM|0107|800
|
||||
SYSTEM|0108|900
|
||||
SYSTEM|0109|1000
|
||||
SYSTEM|0110|č
|
||||
SYSTEM|0111|ěčíóń
|
||||
SYSTEM|0112|
|
||||
SYSTEM|0165|đîâíî
|
||||
SYSTEM|0166|č îäíŕ äĺń˙ňŕ˙
|
||||
SYSTEM|0167|č äâĺ äĺń˙ňűő
|
||||
SYSTEM|0168|č ňđč äĺń˙ňűő
|
||||
SYSTEM|0169|č ÷ĺňűđĺ äĺń˙ňűő
|
||||
SYSTEM|0170|č ď˙ňü äĺń˙ňűő
|
||||
SYSTEM|0171|č řĺńňü äĺń˙ňűő
|
||||
SYSTEM|0172|č ńĺěü äĺń˙ňűő
|
||||
SYSTEM|0173|č âîńĺěü äĺń˙ňűő
|
||||
SYSTEM|0174|č äĺâ˙ňü äĺń˙ňűő
|
||||
SYSTEM|volt0|âîëüň
|
||||
SYSTEM|volt1|âîëüň
|
||||
SYSTEM|volt2|âîëüňŕ
|
||||
SYSTEM|volt5|âîëüň
|
||||
SYSTEM|amp0|ŕěďĺđ
|
||||
SYSTEM|amp1|ŕěďĺđ
|
||||
SYSTEM|amp2|ŕěďĺđŕ
|
||||
SYSTEM|amp5|ŕěďĺđ
|
||||
SYSTEM|mamp0|ěčëëčŕěďĺđ
|
||||
SYSTEM|mamp1|ěčëëčŕěďĺđ
|
||||
SYSTEM|mamp2|ěčëëčŕěďĺđŕ
|
||||
SYSTEM|mamp5|ěčëëčŕěďĺđ
|
||||
SYSTEM|knot0|óçëîâ
|
||||
SYSTEM|knot1|óçĺë
|
||||
SYSTEM|knot2|óçëŕ
|
||||
SYSTEM|knot5|óçëîâ
|
||||
SYSTEM|mps0|ěĺňđîâ â ńĺęóíäó
|
||||
SYSTEM|mps1|ěĺňđ â ńĺęóíäó
|
||||
SYSTEM|mps2|ěĺňđŕ â ńĺęóíäó
|
||||
SYSTEM|mps5|ěĺňđîâ â ńĺęóíäó
|
||||
SYSTEM|celsius0|ăđŕäóńîâ
|
||||
SYSTEM|celsius1|ăđŕäóń
|
||||
SYSTEM|celsius2|ăđŕäóńŕ
|
||||
SYSTEM|celsius5|ăđŕäóńîâ
|
||||
SYSTEM|db0|äĺöčáĺë
|
||||
SYSTEM|db1|äĺöčáĺë
|
||||
SYSTEM|db2|äĺöčáĺëŕ
|
||||
SYSTEM|db5|äĺöčáĺë
|
||||
SYSTEM|degree0|ăđŕäóńîâ
|
||||
SYSTEM|degree1|ăđŕäóń
|
||||
SYSTEM|degree2|ăđŕäóńŕ
|
||||
SYSTEM|degree5|ăđŕäóńîâ
|
||||
SYSTEM|fahr0|ăđŕäóńîâ ďî ôŕđĺíăĺéňó
|
||||
SYSTEM|fahr1|ăđŕäóń ďî ôŕđĺíăĺéňó
|
||||
SYSTEM|fahr2|ăđŕäóńŕ ďî ôŕđĺíăĺéňó
|
||||
SYSTEM|fahr5|ăđŕäóńîâ ďî ôŕđĺíăĺéňó
|
||||
SYSTEM|foot0|ôóňîâ
|
||||
SYSTEM|foot1|ôóň
|
||||
SYSTEM|foot2|ôóňŕ
|
||||
SYSTEM|foot5|ôóňîâ
|
||||
SYSTEM|founce0|óíöčé
|
||||
SYSTEM|founce1|óíöč˙
|
||||
SYSTEM|founce2|óíöčč
|
||||
SYSTEM|founce5|óíöčé
|
||||
SYSTEM|fps0|ôóňîâ â ńĺęóíäó
|
||||
SYSTEM|fps1|ôóň â ńĺęóíäó
|
||||
SYSTEM|fps2|ôóňŕ â ńĺęóíäó
|
||||
SYSTEM|fps5|ôóňîâ â ńĺęóíäó
|
||||
SYSTEM|g0|äćč
|
||||
SYSTEM|g1|äćč
|
||||
SYSTEM|g2|äćč
|
||||
SYSTEM|g5|äćč
|
||||
SYSTEM|hour0|÷ŕńîâ
|
||||
SYSTEM|hour1|÷ŕń
|
||||
SYSTEM|hour2|÷ŕńŕ
|
||||
SYSTEM|hour5|÷ŕńîâ
|
||||
SYSTEM|kph0|ęčëîěĺňđîâ â ÷ŕń
|
||||
SYSTEM|kph1|ęčëîěĺňđ â ÷ŕń
|
||||
SYSTEM|kph2|ęčëîěĺňđŕ â ÷ŕń
|
||||
SYSTEM|kph5|ęčëîěĺňđîâ â ÷ŕń
|
||||
SYSTEM|mamph0|ěčëëčŕěďĺđ â ÷ŕń
|
||||
SYSTEM|mamph1|ěčëëčŕěďĺđ â ÷ŕń
|
||||
SYSTEM|mamph2|ěčëëčŕěďĺđŕ â ÷ŕń
|
||||
SYSTEM|mamph5|ěčëëčŕěďĺđ â ÷ŕń
|
||||
SYSTEM|meter0|ěĺňđîâ
|
||||
SYSTEM|meter1|ěĺňđ
|
||||
SYSTEM|meter2|ěĺňđŕ
|
||||
SYSTEM|meter5|ěĺňđîâ
|
||||
SYSTEM|minute0|ěčíóň
|
||||
SYSTEM|minute1|ěčíóňŕ
|
||||
SYSTEM|minute2|ěčíóňű
|
||||
SYSTEM|minute5|ěčíóň
|
||||
SYSTEM|ml0|ěčëëčëčňđîâ
|
||||
SYSTEM|ml1|ěčëëčëčňđ
|
||||
SYSTEM|ml2|ěčëëčëčňđŕ
|
||||
SYSTEM|ml5|ěčëëčëčňđîâ
|
||||
SYSTEM|mph0|ěčëü â ÷ŕń
|
||||
SYSTEM|mph1|ěčë˙ â ÷ŕń
|
||||
SYSTEM|mph2|ěčëč â ÷ŕń
|
||||
SYSTEM|mph5|ěčëü â ÷ŕń
|
||||
SYSTEM|mwatt0|ěčëëčâŕňň
|
||||
SYSTEM|mwatt1|ěčëëčâŕňň
|
||||
SYSTEM|mwatt2|ěčëëčâŕňňŕ
|
||||
SYSTEM|mwatt5|ěčëëčâŕňň
|
||||
SYSTEM|percent0|ďđîöĺíňîâ
|
||||
SYSTEM|percent1|ďđîöĺíň
|
||||
SYSTEM|percent2|ďđîöĺíňŕ
|
||||
SYSTEM|percent5|ďđîöĺíňîâ
|
||||
SYSTEM|radian0|đŕäčŕí
|
||||
SYSTEM|radian1|đŕäčŕí
|
||||
SYSTEM|radian2|đŕäčŕíŕ
|
||||
SYSTEM|radian5|đŕäčŕí
|
||||
SYSTEM|rpm0|îáîđîňîâ â ěčíóňó
|
||||
SYSTEM|rpm1|îáîđîň â ěčíóňó
|
||||
SYSTEM|rpm2|îáîđîňŕ â ěčíóňó
|
||||
SYSTEM|rpm5|îáîđîňîâ â ěčíóňó
|
||||
SYSTEM|second0|ńĺęóíä
|
||||
SYSTEM|second1|ńĺęóíäŕ
|
||||
SYSTEM|second2|ńĺęóíäű
|
||||
SYSTEM|second5|ńĺęóíä
|
||||
SYSTEM|watt0|âŕňň
|
||||
SYSTEM|watt1|âŕňň
|
||||
SYSTEM|watt2|âŕňňŕ
|
||||
SYSTEM|watt5|âŕňň
|
||||
SYSTEM|eebad|Îřčáęŕ ďŕě˙ňč
|
||||
SYSTEM|hello|Ňŕęč çäđŕâńňâóéňĺ!
|
||||
SYSTEM|inactiv|ß ňóň! Ďđî ěĺí˙ çŕáűëč!
|
||||
SYSTEM|lowbatt|Ŕęęóěóë˙ňîđ đŕçđ˙ćĺí
|
||||
SYSTEM|maxtrim|Ňđčěěĺđ ěŕęńčěóě
|
||||
SYSTEM|midtrim|Ňđčěěĺđ ďî öĺíňđó
|
||||
SYSTEM|mintrim|Ňđčěěĺđ ěčíčěóě
|
||||
SYSTEM|rssi_org|Ńëŕáűé ńčăíŕë!
|
||||
SYSTEM|rssi_red|Î÷ĺíü ńëŕáűé ńčăíŕë!
|
||||
SYSTEM|rxko|
|
||||
SYSTEM|sensorko|Ńĺíńîđ îňęëţ÷ĺí
|
||||
SYSTEM|servoko|
|
||||
SYSTEM|swalert|Ďđîâĺđü ňóěáëĺđű!
|
||||
SYSTEM|swr_red|Ďđîáëĺěű ń ŕíňĺííîé ďĺđĺäŕň÷čęŕ!
|
||||
SYSTEM|telemko|Ďîňĺđ˙í ńčăíŕë ňĺëĺěĺňđčč
|
||||
SYSTEM|telemok|Ňĺëĺěĺňđč˙ âîńńňŕíîâëĺíŕ
|
||||
SYSTEM|thralert|Óáĺđč ăŕç!
|
||||
SYSTEM|timovr1|Ňŕéěĺđ 1. Âđĺě˙ âűřëî
|
||||
SYSTEM|timovr2|Ňŕéěĺđ 2. Âđĺě˙ âűřëî
|
||||
SYSTEM|timovr3|Ňŕéěĺđ 3. Âđĺě˙ âűřëî
|
||||
SYSTEM|trainko|Ňđĺíĺđńęčé ńčăíŕë ďîňĺđ˙í
|
||||
SYSTEM|trainok|Ďî˙âčëń˙ ňđĺíĺđńęčé ńčăíŕë
|
||||
SYSTEM|0180|îäíŕ
|
||||
SYSTEM|0181|îäčííŕäöŕňü
|
||||
SYSTEM|0182|äâŕäöŕňü îäíŕ
|
||||
SYSTEM|0183|ňđčäöŕňü îäíŕ
|
||||
SYSTEM|0184|ńîđîę îäíŕ
|
||||
SYSTEM|0185|ď˙ňüäĺń˙ň îäíŕ
|
||||
SYSTEM|0186|řĺńňüäĺń˙ň îäíŕ
|
||||
SYSTEM|0187|ńĺěüäĺń˙ň îäíŕ
|
||||
SYSTEM|0188|âîńĺěüäĺń˙ň îäíŕ
|
||||
SYSTEM|0189|äĺâ˙íîńňî îäíŕ
|
||||
SYSTEM|0190|äâĺ
|
||||
SYSTEM|0191|äâĺíŕäöŕňü
|
||||
SYSTEM|0192|äâŕäöŕňü äâĺ
|
||||
SYSTEM|0193|ňđčäöŕňü äâĺ
|
||||
SYSTEM|0194|ńîđîę äâĺ
|
||||
SYSTEM|0195|ď˙ňüäĺń˙ň äâĺ
|
||||
SYSTEM|0196|řĺńňüäĺń˙ň äâĺ
|
||||
SYSTEM|0197|ńĺěüäĺń˙ň äâĺ
|
||||
SYSTEM|0198|âîńĺěüäĺń˙ň äâĺ
|
||||
SYSTEM|0199|äĺâ˙íîńňî äâĺ
|
||||
SYSTEM|0200|ňűń˙÷ŕ
|
||||
SYSTEM|0201|ňűń˙÷č
|
||||
SYSTEM|0202|ňűń˙÷
|
||||
@@ -0,0 +1,77 @@
|
||||
// generated by generate_yaml.py
|
||||
|
||||
//
|
||||
// Enums first
|
||||
//
|
||||
|
||||
{% for enum in root.get_enums() %}
|
||||
const struct YamlIdStr {{ enum.name }}[] = {
|
||||
{% for elmt in enum.get_elmts() %}
|
||||
{ {{ elmt.value }}, "{{ max_len(elmt.name) }}" },
|
||||
{% endfor %}
|
||||
{ 0, NULL }
|
||||
};
|
||||
{% endfor %}
|
||||
|
||||
//
|
||||
// Structs last
|
||||
//
|
||||
|
||||
{% for struct in root.get_structs() %}
|
||||
{% if struct.name.startswith('union_') %}
|
||||
static const struct YamlNode {{ struct.name }}_elmts[] = {
|
||||
{% else %}
|
||||
static const struct YamlNode {{ struct.name }}[] = {
|
||||
{% if struct.use_idx %}
|
||||
YAML_IDX,
|
||||
{% endif%}
|
||||
{% endif %}
|
||||
{% for elmt in struct.get_elmts() %}
|
||||
{% if elmt.skip %}
|
||||
YAML_PADDING( {{ elmt.bits }} ),
|
||||
{% elif elmt.type == 'string' %}
|
||||
YAML_STRING("{{ max_len(elmt.name) }}", {{elmt.length}}),
|
||||
{% elif elmt.type in ['signed','unsigned'] %}
|
||||
{% if elmt.f_read and elmt.f_write %}
|
||||
YAML_{{elmt.type|upper}}_CUST( "{{ max_len(elmt.name) }}", {{ elmt.bits }}, {{ elmt.f_read}}, {{ elmt.f_write}} ),
|
||||
{% else %}
|
||||
YAML_{{elmt.type|upper}}( "{{ max_len(elmt.name) }}", {{ elmt.bits }} ),
|
||||
{% endif %}
|
||||
{% elif elmt.type == 'enum' %}
|
||||
YAML_ENUM("{{ max_len(elmt.name) }}", {{elmt.bits}}, {{elmt.var_type}}, {{ elmt.func }}),
|
||||
{% elif elmt.type == 'struct' %}
|
||||
YAML_STRUCT("{{ max_len(elmt.name) }}", {{elmt.bits}}, {{elmt.var_type}}, {{ elmt.func }}),
|
||||
{% elif elmt.type == 'union' %}
|
||||
YAML_UNION("{{ max_len(elmt.name) }}", {{elmt.bits}}, {{elmt.var_type}}_elmts, {{ elmt.func}}),
|
||||
{% elif elmt.type == 'array' %}
|
||||
YAML_ARRAY("{{ max_len(elmt.name) }}", {{elmt.bits // elmt.length}}, {{elmt.length}}, {{elmt.var_type}}, {{ elmt.func }}),
|
||||
{% if padding_bits(elmt) > 0 %}
|
||||
YAML_PADDING({{ padding_bits(elmt) }}),
|
||||
{% endif %}
|
||||
{% elif elmt.raw %}
|
||||
{{ elmt.raw }},
|
||||
{% else %}
|
||||
// name='{{elmt.name}}', type='{{elmt.type}}', bits='{{elmt.bits}}', is_array='{{elmt.is_array}}', var_type='{{elmt.var_type}}', kind='{{elmt.cursor.kind}}' , type.kind='{{elmt.cursor.type.kind}}', raw='{{elmt.raw}}'
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
YAML_END
|
||||
};
|
||||
{% if struct.name.startswith('union_') and struct.used_in_arrays %}
|
||||
static const struct YamlNode {{ struct.name }}[] = {
|
||||
YAML_IDX,
|
||||
YAML_UNION("u", {{ max_bits(struct) }}, {{ struct.name }}_elmts, {{ struct.func }}),
|
||||
YAML_END
|
||||
};
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
#define MAX_{{ root_node_name | upper }}_STR_LEN {{ get_max_len() }}
|
||||
|
||||
{% for tn in root_nodes %}
|
||||
static const struct YamlNode __{{ tn }}_root_node = YAML_ROOT( struct_{{ tn }} );
|
||||
|
||||
const YamlNode* get_{{ tn | lower }}_nodes()
|
||||
{
|
||||
return &__{{ tn }}_root_node;
|
||||
}
|
||||
{% endfor %}
|
||||
Reference in New Issue
Block a user