",
"homeDisclaimerHeader": "Disclaimer",
- "homeDisclamierText": "Diese App unterstützt ESCs, die BLHeli für Atmel, BLHeli für SiLabs und BLHeli_S verwenden.BLHeli FC passthrough ist die einzige derzeit unterstützte Schnittstelle. Falls Probleme auftreten sollten, klicke auf Debug-Protokoll speichern und sende einen Fehlerericht über GitHub.
Der aktuellste CP210x Treiber kann von hier heruntergeladen werden Der aktuellste STM USB VCP Treiber kann von hier heruntergeladen werden ",
+ "homeDisclaimerText": "Diese App unterstützt ESCs, die BLHeli für Atmel, BLHeli für SiLabs und BLHeli_S verwenden.BLHeli FC passthrough ist die einzige derzeit unterstützte Schnittstelle. Falls Probleme auftreten sollten, klicke auf Debug-Protokoll speichern und sende einen Fehlerericht über GitHub.
Der aktuellste CP210x Treiber kann von hier heruntergeladen werden Der aktuellste STM USB VCP Treiber kann von hier heruntergeladen werden ",
"homeWelcome": "Willkommen im ESC - Konfigurator, eine Anwendung um Updates und Konfiguration deiner ESC's zu erleichtern.",
"betaWarning": "Dieses App befindet sich im BETA Stadium. Möglicherweise funktioniert noch nicht alles wie erwartet - falls du irgendwelche Fehler findest, melde sie bitte.",
"escButtonSelectLocally": "Lokale Datei flashen",
@@ -53,7 +53,7 @@
"forceFlashText": "Falsches MCU Layout ignorieren?",
"forceFlashHint": "(Ungeeignete Firmware könnte deinen ESC beschädigen. Auf eigene Verantwortung fortfahren.)",
"migrateFlashText": "Einstellungen wenn möglich übernehmen?",
- "migrateFlashHint": "(Dies wird die Standardeinstellungen der Firmware wiederherstellen)",
+ "migrateFlashHint": "(Dies wird alle Einstellungen auf die Firmware-Standardwerte zurücksetzen)",
"escDirectionReversed": "Richtung umgekehrt",
"escBidirectionalMode": "Bidirektionaler Modus",
"escSinusoidalStartup": "Sinusförmiges Starten",
@@ -61,9 +61,9 @@
"escVariablePwmFrequency": "Variable PWM Frequenz",
"escStuckRotorProtection": "Blockierschutz für Rotor",
"escStallProtection": "Blockierschutz",
- "escTimingAdvance": "Motor Timing (Grad)",
- "escPwmFrequency": "PWM-Frequenz (kHz)",
- "escMotorKv": "Motor KV",
+ "escTimingAdvance": "Motor Timing [Grad]",
+ "escPwmFrequency": "PWM-Frequenz [kHz]",
+ "escMotorKv": "Motor [Kv]",
"escMotorPoles": "Motor Pole",
"escBeepVolume": "Beacon Lautstärke",
"escIntervalTelemetry": "30ms Telemetrie Ausgabe",
@@ -74,9 +74,9 @@
"escLowVoltageCutoff": "Abschaltung bei niedriger Spannung",
"escLowVoltageThreshold": "Wert für Abschaltung bei niedriger Spannung",
"escRcCarReversing": "Motorendrehrichtung umkehren wie bei RC Autos",
- "bluejayText": "
Bluejay ist eine auf BLHELI_S basierende Firmware die bi-direktionales DSHOT unterstützt - eine gute Wahl falls du RPM Filter verwenden möchtest. Dieses Projekt beschäftigt sich damit BLHELI_S zu vereinfachen und zu verbessern.
Als Bonus bekommst du noch einen Startmelodie Editor dazu.
",
- "blheli32ToAM32": "
Die aufstrebende Firmware für ARM-basierte ESCs. Obwohl es relativ neu in der Szene ist, hat es viel Interesse, sowohl bei Anwendern als auch bei Herstellern erregt. AM32 ESC's werden in Kürze von verschiedenen Herstellern erhältlich sein.
AM32 kann auf BLHELI_32 ESC'sgeflashed werden. Aber du musst zuerst den AM32 Bootloader über STM32 Cube Programmierer und ST Link V2 flashen. Der erforderliche Bootloader befindet sich im AM32 Bootloader Repository.
",
- "blhelisText": "
BLHELI_S benötigt wahrscheinlich keine Einführung - die beliebte ESC-Firmware für fast jeden EFM8-basierten ESC im Quadrocopter-Hobby.
Erprobt und getestet, unterstützt es alle analogen und digitalen Protokolle die in Betaflight existieren
",
+ "bluejayText": "
Bluejay ist eine auf BLHeli_S basierende Firmware die bi-direktionales DShot unterstützt - eine gute Wahl falls du RPM Filter verwenden möchtest. Dieses Projekt beschäftigt sich damit BLHeli_S zu vereinfachen und zu verbessern.
Als Bonus bekommst du noch einen Startmelodie Editor dazu.
",
+ "blheli32ToAM32": "
Die aufstrebende Firmware für ARM-basierte ESCs. Obwohl diese relativ neu in der Szene ist, hat sie viel Interesse, sowohl bei Anwendern als auch bei Herstellern erregt. AM32 ESCs werden in Kürze von diversen Herstellern erhältlich sein.
AM32 kann auf BLHELI_32 ESCsgeflashed werden. Aber du musst zuerst den AM32 Bootloader über STM32 Cube Programmierer und ST Link V2 flashen. Der erforderliche Bootloader befindet sich im AM32 Bootloader Repository.
",
+ "blhelisText": "
BLHeli_S benötigt wahrscheinlich keine Einführung - die beliebte ESC-Firmware für fast jeden EFM8-basierten ESC im Quadrocopter-Hobby.
Erprobt und getestet, unterstützt es alle analogen und digitalen Protokolle die in Betaflight existieren
",
"whatsNextHeader": "Was kommt als nächstes?",
"whatsNextText": "
Wenn du mitverfolgen willst welche Funktionen in Zukunft entstehen, kannst du dies im github-Repositorybeobachten. Gerne kannst du auch eine Feature-Anfrage erstellen, wenn du eine Idee zu einem Feature hast, welches du gerne implementiert hättest.
",
"openPortSelection": "Portauswahl öffnen",
@@ -86,5 +86,19 @@
"masterSpeed": "Geschwindigkeit aller Motoren",
"motorNr": "Motor {{index}}",
"homeDiscordHeader": "Komm auf unseren Discord Server!",
- "homeDiscordText": "Wenn du Fragen hast oder rasche Hilfe brauchst, schau bei uns am Discord Server vorbei:"
+ "homeDiscordText": "Wenn du Fragen hast oder rasche Hilfe brauchst, schau bei uns am Discord Server vorbei:",
+ "homeChinaHeader": "Für unsere chinesischen Besucher",
+ "homeChinaText": "Sag deinen Freunden hinter der großen chinesischen Firewall, dass sie uns über einen lokalen Spiegel direkt in China erreichen können.",
+ "melodyEditor": "Melodie Editor",
+ "homeAttributionHeader": "Beteiligung",
+ "homeAttributionText": "Dieses Projekt wurde stark vom BLHeli Configuratorinspiriert. Der Großteil der Benutzeroberfläche wurde von Grund auf neu geschrieben, aber viele der mit dem Flashen und Firmware-Handling zusammenhängenden Low-Level-Funktionen wurden wiederverwendet - also großen Dank an alle, die am ursprünglichen BLHeli Configurator beteiligt waren.",
+ "multiOnly": "Nur der MULTI-Modus wird derzeit unterstützt",
+ "selectFirmware": "Firmware auswählen",
+ "selectEsc": "ESC auswählen",
+ "selectMode": "Modus auswählen",
+ "selectVersion": "Version auswählen",
+ "selectPwmFrequency": "PWM Frequenz auswählen",
+ "selectTarget": "Target wählen",
+ "battery": "Akku:",
+ "settings": "Einstellungen"
}
diff --git a/src/translations/de/hints.json b/src/translations/de/hints.json
index 171546272..31332376c 100644
--- a/src/translations/de/hints.json
+++ b/src/translations/de/hints.json
@@ -16,10 +16,10 @@
"COMPLEMENTARY_PWM": "Aktiviert das aktive Bremsen durch die Verwendung der Low-Side-Schalter im Current-Decay-Betrieb anstatt der MOSFET Body-Dioden.",
"VARIABLE_PWM_FREQUENCY": "Erhöht die PWM-Frequenz proportional zu Motordrehzahl von 24-48kHz, um Störungen zu vermeiden.",
"STUCK_ROTOR_PROTECTION": "Trennt den Strom vom Motor, stoppt und versucht einen Neustart nach 10 gescheiterten Versuchen.",
- "STALL_PROTECTION": "Erhöht Schub automatisch wenn unter einem Drehzahl Schwellwert und versuch das Stoppen vom Motor zu verhindert. Für Multicopter nicht empfohlen.",
+ "STALL_PROTECTION": "Erhöht den Schub automatisch wenn dieser unter einen Drehzahl Schwellwert fällt und versucht das Stoppen des Motors zu verhindern. Für Multicopter nicht empfohlen.",
"TIMING_ADVANCE": "Motorkommutations Timing. Höhere Werte führen in der Regel zu weniger de-syncs und bringen mehr Leistung auf Kosten der Effizienz.",
"MOTOR_KV": "Der vom Hersteller angegebene KV-Wert des Motors. Dieser Wert wird verwendet um das Limit für den Schutz bei niedriger Drehzahl zu bestimmen.",
- "MOTOR_POLES": "Pol Anzahl des Motors. Dieser Wert wird verwendet, um die sinusförmige Startgeschwindigkeit anzupassen.",
+ "MOTOR_POLES": "Polzahl des Motors. Dieser Wert wird verwendet, um die sinusförmige Startgeschwindigkeit anzupassen.",
"STARTUP_POWER": "Steuert die dem Motor während des Starts verliehene Ausgangsleistung und den minimalen Schub.",
"PWM_FREQUENCY": "Wenn variables PWM deaktiviert ist, wird die Schaltfrequenz (PWM) manuell auf den gewählten Bereich gesetzt.",
"BEEP_VOLUME": "Die Lautstärke für die Piep-Töne. Zu hohe Werte können den Motor beschädigen.",
diff --git a/src/translations/de/log.json b/src/translations/de/log.json
index f59e71d1d..0650f72fd 100644
--- a/src/translations/de/log.json
+++ b/src/translations/de/log.json
@@ -15,7 +15,7 @@
"readEscs": "Lese {{connected}} ESCs",
"readEscsSuccess": "ESCs gelesen",
"readEscsFailed": "ESCs lesen fehlgeschlagen",
- "readEsc": "ESC {{index}} gelesen",
+ "readEsc": "ESC {{index}}: {{name}}",
"flashingEsc": "ESC {{index}} wird geflasht",
"flashingEscFailed": "ESC {{index}} konnte nicht geflasht werden - prüfe den Dateityp",
"readEscFailed": "ESC {{index}} konnte nicht gelesen werden",
@@ -27,5 +27,7 @@
"escSettingsLayoutMismatch": "Layout stimmt nicht überein, Layout ignorieren nicht aktiv - abgebrochen",
"escSettingsMcuMismatch": "MCU stimmt nicht überein, ignorieren nicht aktiv - abgebrochen",
"escFlashedInTime": "ESC {{index}} - in {{seconds}}s geflasht",
- "passthroughNotSupported": "BLHELI passthrough nicht unterstützt"
+ "passthroughNotSupported": "BLHELI passthrough nicht unterstützt",
+ "firmwareMismatch": "Firmware stimmt nicht überein! Flash: {{flash}} vs. EEPROM: {{eeprom}}",
+ "bootloaderMismatch": "Bootloader Versionen stimmen nicht überein! Flash: {{flash}} vs. EEPROM: {{eeprom}}"
}
diff --git a/src/translations/en/common.json b/src/translations/en/common.json
index 46bcc40c4..cf57db51b 100644
--- a/src/translations/en/common.json
+++ b/src/translations/en/common.json
@@ -19,7 +19,7 @@
"escBeaconDelay": "Beacon Delay",
"escBeepStrength": "Beep Strength",
"escBeaconStrength": "Beacon Strength",
- "escStartupBeep": "Staartup Beep",
+ "escStartupBeep": "Startup Beep",
"escDithering": "Dithering",
"escMotorDirection": "Motor Direction",
"escPPMMinThrottle": "PPM Min Throttle",
@@ -29,7 +29,6 @@
"_RPM Power Protection (Rampup)": "RPM Power Protection (Rampup)",
"_Minimum Startup Power (Boost)": "Minimum Startup Power (Boost)",
"_Maximum Startup Power (Protection)": "Maximum Startup Power (Protection)",
- "_Maximum Startup Power (Protection)": "Maximum Startup Power (Protection)",
"escButtonFlash": "Flash Firmware",
"defaultChangelogHead": "Changelog",
"escButtonRead": "Read Setup",
@@ -41,11 +40,11 @@
"defaultChangelogTitle": "Changelog",
"changelogClose": "Close",
"homeExperimental": "This is an experimental web app to configure ESC firmware online.",
- "homeVersionInfo": "You will always find the latest stable version here. Currently the following firmwares are supported:",
+ "homeVersionInfo": "You will always find the latest stable version here. Currently the following firmware are supported:",
"homeContributionHeader": "Contributing",
- "homeContributionText": "If you would like to help make Bluejay Configurator even better you can help in many ways, including:
Answering other users questions on the forums
Contributing code - new features, fixes, improvements
",
"homeDisclaimerHeader": "Disclaimer",
- "homeDisclamierText": "The web application supports ESCs running BLHeli for Atmel, BLHeli for SiLabs and BLHeli_S.BLHeli FC passthrough is the only interface currently supported. Should you run into any problems, make sure to use the Save Debug Log button and submit a new issue via GitHub.
Application source code can be downloaded from here
Latest CP210x Drivers can be downloaded from here Latest STM USB VCP Drivers can be downloaded from here ",
+ "homeDisclaimerText": "The web application supports ESCs running BLHeli for Atmel, BLHeli for SiLabs and BLHeli_S.BLHeli FC passthrough is the only interface currently supported. Should you run into any problems, make sure to use the Save Debug Log button and submit a new issue via GitHub.
Application source code can be downloaded from here
Latest CP210x Drivers can be downloaded from here Latest STM USB VCP Drivers can be downloaded from here ",
"homeWelcome": "Welcome to ESC - Configurator, a utility designed to simplify updating and configuring of your ESCs.",
"betaWarning": "This tool is considered BETA. Things might not work as expected yet - if you find any bugs please report them.",
"escButtonSelectLocally": "Flash Local Firmware",
@@ -54,7 +53,7 @@
"forceFlashText": "Ignore inappropriate MCU and Layout?",
"forceFlashHint": "(Flashing inappropriate firmware may damage your ESC, do so at your own risk)",
"migrateFlashText": "Migrate settings if possible?",
- "migrateFlashHint": "(This will set the default settings from firmware)",
+ "migrateFlashHint": "(This will reset all settings to the firmware defaults)",
"escDirectionReversed": "Direction Reversed",
"escBidirectionalMode": "Bidirectional Mode",
"escSinusoidalStartup": "Sinusoidal Startup",
@@ -62,9 +61,9 @@
"escVariablePwmFrequency": "Variable PWM Frequency",
"escStuckRotorProtection": "Stuck Rotor Protection",
"escStallProtection": "Stall Protection",
- "escTimingAdvance": "Timing Advance (degrees)",
- "escPwmFrequency": "PWM Frequency (kHz)",
- "escMotorKv": "Motor KV",
+ "escTimingAdvance": "Timing Advance [degrees]",
+ "escPwmFrequency": "PWM Frequency [kHz]",
+ "escMotorKv": "Motor [Kv]",
"escMotorPoles": "Motor Poles",
"escBeepVolume": "Beeper Volume",
"escIntervalTelemetry": "30ms Telemetry Output",
@@ -74,10 +73,10 @@
"escServoDeadBand": "Servo Neutral Dead Band",
"escLowVoltageCutoff": "Low Voltage Cut Off",
"escLowVoltageThreshold": "Low Voltage Cut-Off Threshold",
- "escRcCarReversing": "Rc Car Style Reversing",
- "bluejayText": "
Bluejay is BLHELI_S based firmware capable of bi-directional DSHOT - so a great choice if you want to run RPM filtering on your rig. This project also aims to clean up and simplify the original BLHELI_S source code.
A startup sound editor is also part of the deal.
",
- "blheli32ToAM32": "
The up and coming firmware for ARM based ESC's. Although being relatively new on the scene it has a lot of interest, both from users and manufacturers. AM32 ESC's will soon be available from different manufacturers.
AM32 can be flashed on BLHELI_32 ESC's. But, you will have to first flash the AM32 Bootloader via STM32 Cube Programmer and ST Link V2 programming adapter. The required bootloader can be found in the AM32 bootloader repository.
",
- "blhelisText": "
BLHELI_S probably does not need an introduction - the wildly popular ESC firmware used on almost every EFM8 based ESC in the quadrocopter hobby.
Tried and tested, supports every analog and digital protocol out there.
",
+ "escRcCarReversing": "RC Car Style Reversing",
+ "bluejayText": "
Bluejay is BLHeli_S based firmware capable of bi-directional DShot - so a great choice if you want to run RPM filtering on your rig. This project also aims to clean up and simplify the original BLHeli_S source code.
A startup sound editor is also part of the deal.
",
+ "blheli32ToAM32": "
The up and coming firmware for ARM based ESCs. Although being relatively new on the scene it has a lot of interest, both from users and manufacturers. AM32 ESCs will soon be available from different manufacturers.
AM32 can be flashed on BLHeli_32 ESCs. But, you will have to first flash the AM32 bootloader via STM32 Cube Programmer and ST Link V2 programming adapter. The required bootloader can be found in the AM32 bootloader repository.
",
+ "blhelisText": "
BLHeli_S probably does not need an introduction - the wildly popular ESC firmware used on almost every EFM8 based ESC in the quadcopter hobby.
Tried and tested, supports every analog and digital protocol out there.
If you want to see which features are upcoming, drop by in the github repository. Also feel free to add a feature request if you have an idea that you want to see implemented.
",
"openPortSelection": "Open Port Selection",
@@ -88,9 +87,18 @@
"motorNr": "Motor {{index}}",
"homeDiscordHeader": "Join us on Discord!",
"homeDiscordText": "If you have any questions or need a quick helping hand, join us on our Discord server:",
- "homeChinaHeader": "For our Chinese Visiotors",
+ "homeChinaHeader": "For our Chinese visitors",
"homeChinaText": "Tell your friends behind the great firewall of China, that they can reach us via a local mirror directly in China.",
"melodyEditor": "Melody Editor",
"homeAttributionHeader": "Attribution",
- "homeAttributionText": "This project was heavily inspired by the Blheli Configurator. Most of the UI has been re-written from scratch but a lot of the low level stuff related to flashing and firmware handling have been re-used - so a big shout out to everyone involved in the original Blheli Configurator."
+ "homeAttributionText": "This project was heavily inspired by the BLHeli Configurator. Most of the UI has been re-written from scratch but a lot of the low level stuff related to flashing and firmware handling have been re-used - so a big shout out to everyone involved in the original BLHeli Configurator.",
+ "multiOnly": "Only MULTI mode currently supported",
+ "selectFirmware": "Select Firmware",
+ "selectEsc": "Select ESC",
+ "selectMode": "Select Mode",
+ "selectVersion": "Select Version",
+ "selectPwmFrequency": "Select PWM Frequency",
+ "selectTarget": "Select Target",
+ "battery": "Battery:",
+ "settings": "Settings"
}
diff --git a/src/translations/en/log.json b/src/translations/en/log.json
index 25ffa17c0..98d216e0d 100644
--- a/src/translations/en/log.json
+++ b/src/translations/en/log.json
@@ -15,7 +15,7 @@
"readEscs": "Trying to read {{connected}} ESC's",
"readEscsSuccess": "Done reading ESC's",
"readEscsFailed": "Failed reading ESC's",
- "readEsc": "Read ESC {{index}}",
+ "readEsc": "Read ESC {{index}}: {{name}}",
"flashingEsc": "Flashing ESC {{index}}",
"flashingEscFailed": "Failed flashing ESC {{index}} - check file type",
"readEscFailed": "Failed reading ESC {{index}}",
@@ -27,5 +27,7 @@
"escSettingsLayoutMismatch": "Layout mismatch, override not enabled - aborted",
"escSettingsMcuMismatch": "MCU mismatch, override not enabled - aborted",
"escFlashedInTime": "Flashed ESC {{index}} - {{seconds}}s",
- "passthroughNotSupported": "BLHELI passthrough not supported"
+ "passthroughNotSupported": "BLHELI passthrough not supported",
+ "firmwareMismatch": "Firmware mismatch! Flash: {{flash}} vs. EEPROM: {{eeprom}}",
+ "bootloaderMismatch": "Bootloader mismatch! Flash: {{flash}} vs. EEPROM: {{eeprom}}"
}
diff --git a/src/translations/zh-CN/common.json b/src/translations/zh-CN/common.json
new file mode 100644
index 000000000..6cfedae64
--- /dev/null
+++ b/src/translations/zh-CN/common.json
@@ -0,0 +1,104 @@
+{
+ "port": "端口",
+ "baudRate": "波特率",
+ "connect": "连接",
+ "disconnect": "断开连接",
+ "serialPermission": "选择串行端口",
+ "showLog": "显示日志",
+ "hideLog": "隐藏日志",
+ "notePropsOff": "注意: 在使用本页面前,请确保您已经 取下 所有螺旋桨。",
+ "noteConnectPower": "注意: 请将电源连接至电调。",
+ "commonParameters": "公用参数",
+ "escProgrammingByTX": "通过 TX 编程",
+ "escLowRPMPowerProtection": "低转速功率保护",
+ "escBrakeOnStop": "停止时刹车",
+ "escStartupPower": "启动功率",
+ "escTemperatureProtection": "温度保护",
+ "escDemagCompensation": "退磁补偿",
+ "escMotorTiming": "电机进角",
+ "escBeaconDelay": "信标延迟",
+ "escBeepStrength": "蜂鸣强度",
+ "escBeaconStrength": "信标强度",
+ "escStartupBeep": "启动蜂鸣音",
+ "escDithering": "抖动",
+ "escMotorDirection": "电机方向",
+ "escPPMMinThrottle": "PPM 最小油门",
+ "escPPMMaxThrottle": "PPM 最大油门",
+ "statusbarPortUtilization": "端口利用率:",
+ "statusbarPacketError": "数据包错误:",
+ "_RPM Power Protection (Rampup)": "RPM 功率保护 (爬升功率)",
+ "_Minimum Startup Power (Boost)": "最小启动功率 (升压)",
+ "_Maximum Startup Power (Protection)": "最大启动功率 (保护)",
+ "escButtonFlash": "烧录固件",
+ "defaultChangelogHead": "更新日志",
+ "escButtonRead": "读取配置",
+ "escButtonFlashAll": "烧录全部",
+ "escButtonSaveLog": "保存调试日志",
+ "escButtonWrite": "写入配置",
+ "buttonCancel": "取消",
+ "escButtonSelect": "烧录",
+ "defaultChangelogTitle": "更新日志",
+ "changelogClose": "关闭",
+ "homeExperimental": "这是一个实验性的 web 应用程序,可以在线配置 ESC 固件。",
+ "homeVersionInfo": "您可以在这里找到最新的稳定版本。目前支持以下固件:",
+ "homeContributionHeader": "贡献",
+ "homeContributionText": "如果您想要帮助 ESC 配置程序变得更好,您可以通过多种方式提供帮助。包括:
",
"homeDisclaimerHeader": "Disclaimer",
- "homeDisclamierText": "The web application supports ESCs running BLHeli for Atmel, BLHeli for SiLabs and BLHeli_S.BLHeli FC passthrough is the only interface currently supported. Should you run into any problems, make sure to use the Save Debug Log button and submit a new issue via GitHub.
Application source code can be downloaded from here
Latest CP210x Drivers can be downloaded from here Latest STM USB VCP Drivers can be downloaded from here ",
+ "homeDisclaimerText": "The web application supports ESCs running BLHeli for Atmel, BLHeli for SiLabs and BLHeli_S.BLHeli FC passthrough is the only interface currently supported. Should you run into any problems, make sure to use the Save Debug Log button and submit a new issue via GitHub.
Application source code can be downloaded from here
Latest CP210x Drivers can be downloaded from here Latest STM USB VCP Drivers can be downloaded from here ",
"homeWelcome": "Welcome to ESC - Configurator, a utility designed to simplify updating and configuring of your ESCs.",
"betaWarning": "This tool is considered BETA. Things might not work as expected yet - if you find any bugs please report them.",
"escButtonSelectLocally": "Flash Local Firmware",
@@ -53,7 +53,7 @@
"forceFlashText": "Ignore inappropriate MCU and Layout?",
"forceFlashHint": "(Flashing inappropriate firmware may damage your ESC, do so at your own risk)",
"migrateFlashText": "Migrate settings if possible?",
- "migrateFlashHint": "(This will set the default settings from firmware)",
+ "migrateFlashHint": "(This will reset all settings to the firmware defaults)",
"escDirectionReversed": "Direction Reversed",
"escBidirectionalMode": "Bidirectional Mode",
"escSinusoidalStartup": "Sinusoidal Startup",
@@ -61,9 +61,9 @@
"escVariablePwmFrequency": "Variable PWM Frequency",
"escStuckRotorProtection": "Stuck Rotor Protection",
"escStallProtection": "Stall Protection",
- "escTimingAdvance": "Timing Advance (degrees)",
- "escPwmFrequency": "PWM Frequency (kHz)",
- "escMotorKv": "Motor KV",
+ "escTimingAdvance": "Timing Advance [degrees]",
+ "escPwmFrequency": "PWM Frequency [kHz]",
+ "escMotorKv": "Motor [Kv]",
"escMotorPoles": "Motor Poles",
"escBeepVolume": "Beeper Volume",
"escIntervalTelemetry": "30ms Telemetry Output",
@@ -73,10 +73,10 @@
"escServoDeadBand": "Servo Neutral Dead Band",
"escLowVoltageCutoff": "Low Voltage Cut Off",
"escLowVoltageThreshold": "Low Voltage Cut-Off Threshold",
- "escRcCarReversing": "Rc Car Style Reversing",
- "bluejayText": "
Bluejay is BLHELI_S based firmware capable of bi-directional DSHOT - so a great choice if you want to run RPM filtering on your rig. This project also aims to clean up and simplify the original BLHELI_S source code.
A startup sound editor is also part of the deal.
",
- "blheli32ToAM32": "
The up and coming firmware for ARM based ESC's. Although being relatively new on the scene it has a lot of interest, both from users and manufacturers. AM32 ESC's will soon be available from different manufacturers.
AM32 can be flashed on BLHELI_32 ESC's. But, you will have to first flash the AM32 Bootloader via STM32 Cube Programmer and ST Link V2 programming adapter. The required bootloader can be found in the AM32 bootloader repository.
",
- "blhelisText": "
BLHELI_S probably does not need an introduction - the wildly popular ESC firmware used on almost every EFM8 based ESC in the quadrocopter hobby.
Tried and tested, supports every analog and digital protocol out there.
",
+ "escRcCarReversing": "RC Car Style Reversing",
+ "bluejayText": "
Bluejay is BLHeli_S based firmware capable of bi-directional DShot - so a great choice if you want to run RPM filtering on your rig. This project also aims to clean up and simplify the original BLHeli_S source code.
A startup sound editor is also part of the deal.
",
+ "blheli32ToAM32": "
The up and coming firmware for ARM based ESCs. Although being relatively new on the scene it has a lot of interest, both from users and manufacturers. AM32 ESCs will soon be available from different manufacturers.
AM32 can be flashed on BLHeli_32 ESCs. But, you will have to first flash the AM32 bootloader via STM32 Cube Programmer and ST Link V2 programming adapter. The required bootloader can be found in the AM32 bootloader repository.
",
+ "blhelisText": "
BLHeli_S probably does not need an introduction - the wildly popular ESC firmware used on almost every EFM8 based ESC in the quadcopter hobby.
Tried and tested, supports every analog and digital protocol out there.
If you want to see which features are upcoming, drop by in the github repository. Also feel free to add a feature request if you have an idea that you want to see implemented.
",
"openPortSelection": "Open Port Selection",
@@ -86,5 +86,19 @@
"masterSpeed": "Master Speed",
"motorNr": "Motor {{index}}",
"homeDiscordHeader": "Join us on Discord!",
- "homeDiscordText": "If you have any questions or need a quick helping hand, join us on our Discord server:"
+ "homeDiscordText": "If you have any questions or need a quick helping hand, join us on our Discord server:",
+ "homeChinaHeader": "For our Chinese visitors",
+ "homeChinaText": "Tell your friends behind the great firewall of China, that they can reach us via a local mirror directly in China.",
+ "melodyEditor": "Melody Editor",
+ "homeAttributionHeader": "Attribution",
+ "homeAttributionText": "This project was heavily inspired by the BLHeli Configurator. Most of the UI has been re-written from scratch but a lot of the low level stuff related to flashing and firmware handling have been re-used - so a big shout out to everyone involved in the original BLHeli Configurator.",
+ "multiOnly": "Only MULTI mode currently supported",
+ "selectFirmware": "Select Firmware",
+ "selectEsc": "Select ESC",
+ "selectMode": "Select Mode",
+ "selectVersion": "Select Version",
+ "selectPwmFrequency": "Select PWM Frequency",
+ "selectTarget": "Select Target",
+ "battery": "Battery:",
+ "settings": "Settings"
}
diff --git a/src/translations/zh/log.json b/src/translations/zh-TW/log.json
similarity index 84%
rename from src/translations/zh/log.json
rename to src/translations/zh-TW/log.json
index 25ffa17c0..98d216e0d 100644
--- a/src/translations/zh/log.json
+++ b/src/translations/zh-TW/log.json
@@ -15,7 +15,7 @@
"readEscs": "Trying to read {{connected}} ESC's",
"readEscsSuccess": "Done reading ESC's",
"readEscsFailed": "Failed reading ESC's",
- "readEsc": "Read ESC {{index}}",
+ "readEsc": "Read ESC {{index}}: {{name}}",
"flashingEsc": "Flashing ESC {{index}}",
"flashingEscFailed": "Failed flashing ESC {{index}} - check file type",
"readEscFailed": "Failed reading ESC {{index}}",
@@ -27,5 +27,7 @@
"escSettingsLayoutMismatch": "Layout mismatch, override not enabled - aborted",
"escSettingsMcuMismatch": "MCU mismatch, override not enabled - aborted",
"escFlashedInTime": "Flashed ESC {{index}} - {{seconds}}s",
- "passthroughNotSupported": "BLHELI passthrough not supported"
+ "passthroughNotSupported": "BLHELI passthrough not supported",
+ "firmwareMismatch": "Firmware mismatch! Flash: {{flash}} vs. EEPROM: {{eeprom}}",
+ "bootloaderMismatch": "Bootloader mismatch! Flash: {{flash}} vs. EEPROM: {{eeprom}}"
}
diff --git a/src/translations/zh/settings.json b/src/translations/zh-TW/settings.json
similarity index 100%
rename from src/translations/zh/settings.json
rename to src/translations/zh-TW/settings.json
diff --git a/src/translations/zh/hints.json b/src/translations/zh/hints.json
deleted file mode 100644
index 0b704e489..000000000
--- a/src/translations/zh/hints.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "STARTUP_BEEP": "Enable beep melody when the ESC is powered up.",
- "BRAKE_ON_STOP": "Brake when motors are stopped.",
- "BEACON_DELAY": "After how much time of inactivity the beacon should start to go off.",
- "TEMPERATURE_PROTECTION": "At which temperature the ESC will shut down.",
- "BEEP_STRENGTH": "The volume of the startup beeps. Setting this too high might damage the motors.",
- "BEACON_STRENGTH": "The volume of the beacon. Setting this too high might damage the motors.",
- "STARTUP_POWER_MIN": "The least amount of power applied when starting up the motors. Increase if motors are not able to start up with low throttle input.",
- "DITHERING": "Increases the effective pwm resolution 2000 steps. It is generally recommended to leave this on especially with pwm frequencies above 24kHz.",
- "STARTUP_POWER_MAX": "Limits power when starting motors or reversing direction.",
- "RPM_POWER_SLOPE": "Limits how much power can be increased according to how fast the motor is spinning. Lower values will avoid power spikes but can also decrease acceleration and maximum attainable speed.",
- "MOTOR_DIRECTION": "The motor rotation direction can be normal or reversed. In bidirectional mode, center throttle is zero.",
- "COMMUTATION_TIMING": "Motor commutation advance timing. Higher timing are less prone to desyncs and can provide more power at the cost of efficiency.",
- "DEMAG_COMPENSATION": "The extent to which power should be cut to protect against motor stalls caused by long winding demagnetization time after commutation.",
- "SINUSOIDAL_STARTUP": "During the first 10 percent of throttle the motor is stepped in sinusoidal open loop commutation.",
- "COMPLEMENTARY_PWM": "Enables active braking by using low side switches for current decay instead of MOSFET body diodes.",
- "VARIABLE_PWM_FREQUENCY": "Increases PWM frequency proportionally to motor rpm from 24-48khz to avoid thottle disturbances.",
- "STUCK_ROTOR_PROTECTION": "Cuts power to the motor and stops trying to restart after 10 failed start attempts.",
- "STALL_PROTECTION": "Increases throttle automatically below a rpm threshold to try and avoid stalling the motor, not reccomended for multirotors.",
- "TIMING_ADVANCE": "Motor commutation advance timing. Higher timing are less prone to desyncs and can provide more power at the cost of efficiency.",
- "MOTOR_KV": "The KV rating of the motor stated by the manufacturer. The value is used to set RPM limit for low rpm throttle protection.",
- "MOTOR_POLES": "Pole count of the motor. This value is used to adjust sinusoidal startup speed.",
- "STARTUP_POWER": "Controls the initial power given to the motor during startup and minimum throttle level.",
- "PWM_FREQUENCY": "When variable PWM is disabled, this manually sets the switching frequency (PWM) to the chosen range.",
- "BEEP_VOLUME": "The level of power for the audible beeps made by the motor. Settings too high might damage the motors.",
- "INTERVAL_TELEMETRY": "Outputs telemetry data on a 30ms interval.",
- "SERVO_LOW_THRESHOLD": "Any signal below this point is considered zero throttle.",
- "SERVO_HIGH_THRESHOLD": "Any signal above this point is considered maximum throttle.",
- "SERVO_NEUTRAL": "For bi-directional modes this is the zero throttle position in microseconds.",
- "SERVO_DEAD_BAND": "Applied to either side of Servo Neutral, anything in this range is considered zero throttle.",
- "LOW_VOLTAGE_CUTOFF": "When enabled will cut power to the motor when the voltage drops below the low voltage threshold.",
- "LOW_VOLTAGE_THRESHOLD": "Voltage level per cell where power is cut. Units in volts * 10. To cut off at 3.3v enter 330 for example.",
- "RC_CAR_REVERSING": "For ground vehicles only. Overrides user settings and places ESC into bi-directional mode with double tap to reverse type control."
-}
diff --git a/src/utils/Blheli.js b/src/utils/Blheli.js
deleted file mode 100644
index a267200ee..000000000
--- a/src/utils/Blheli.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import {
- BLHELI_MODES,
-} from '../sources/Blheli/eeprom';
-
-class Blheli {
- modeToString(mode) {
- for (const property in BLHELI_MODES) {
- if (Object.prototype.hasOwnProperty.call(
- BLHELI_MODES,
- property
- )) {
- if (BLHELI_MODES[property] === mode) {
- return property;
- }
- }
- }
- }
-
- settingsObject(settingsUint8Array, layout) {
- const object = {};
-
- for (const prop in layout) {
- if (Object.prototype.hasOwnProperty.call(
- layout,
- prop
- )) {
- const setting = layout[prop];
-
- if (setting.size === 1) {
- object[prop] = settingsUint8Array[setting.offset];
- } else if (setting.size === 2) {
- object[prop] = settingsUint8Array[setting.offset] << 8 |
- settingsUint8Array[setting.offset + 1];
- } else if (setting.size > 2) {
- object[prop] = String.fromCharCode.apply(
- undefined,
- settingsUint8Array.subarray(setting.offset).
- subarray(
- 0,
- setting.size
- )
- ).trim();
- } else {
- throw new Error('Logic error');
- }
- }
- }
-
- return object;
- }
-
- settingsArray(settingsObject, layout, layoutSize) {
- const array = new Uint8Array(layoutSize).fill(0xff);
-
- for (const prop in layout) {
- if (Object.prototype.hasOwnProperty.call(
- layout,
- prop
- )) {
- const setting = layout[prop];
-
- if (setting.size === 1) {
- array[setting.offset] = settingsObject[prop];
- } else if (setting.size === 2) {
- array[setting.offset] = settingsObject[prop] >> 8 & 0xff;
- array[setting.offset + 1] = settingsObject[prop] & 0xff;
- } else if (setting.size > 2) {
- const { length } = settingsObject[prop];
- for (let i = 0; i < setting.size; i += 1) {
- array[setting.offset + i] = i < length ?
- settingsObject[prop].charCodeAt(i) :
- ' '.charCodeAt(0);
- }
- } else {
- throw new Error('Logic error');
- }
- }
- }
-
- return array;
- }
-}
-
-export default Blheli;
diff --git a/src/utils/FourWay.js b/src/utils/FourWay.js
index 719ee3320..1b2dedbeb 100644
--- a/src/utils/FourWay.js
+++ b/src/utils/FourWay.js
@@ -1,29 +1,26 @@
-import Blheli from './Blheli';
+import Convert from './helpers/Convert';
+import Flash from './helpers/Flash';
import {
- BLHELI_SILABS,
-} from '../sources/Blheli/eeprom';
+ buildDisplayName as blheliBuildDisplayName,
+ EEPROM as BLHELI_EEPROM,
+} from '../sources/Blheli';
import {
- AM32_RESET_DELAY_MS,
-} from '../sources/AM32/eeprom';
+ buildDisplayName as am32BuildDisplayName,
+ EEPROM as AM32_EEPROM,
+} from '../sources/AM32';
-import blheliSource from '../sources/Blheli';
-import bluejaySource from '../sources/Bluejay';
-import am32Source from '../sources/AM32';
+import {
+ buildDisplayName as bluejayBuildDisplayName,
+ EEPROM as BLUEJAY_EEPROM,
+} from '../sources/Bluejay';
// TODO: We might use the ones from the source here...
import BLHELI_ESCS from '../sources/Blheli/escs.json';
import BLUEJAY_ESCS from '../sources/Bluejay/escs.json';
import AM32_ESCS from '../sources/AM32/escs.json';
-import {
- fillImage,
- parseHex,
- buf2ascii,
- ascii2buf,
-} from './helpers/Flash';
-
import {
canMigrate,
getIndividualSettings,
@@ -44,14 +41,7 @@ import {
MODES,
SILABS_MODES,
} from './FourWayConstants';
-
-import {
- NotEnoughDataError,
-} from './helpers/QueueProcessor';
-
-const BLHELI_EEPROM = blheliSource.getEeprom();
-const BLUEJAY_EEPROM = bluejaySource.getEeprom();
-const AM32_EEPROM = am32Source.getEeprom();
+import { NotEnoughDataError } from './helpers/QueueProcessor';
class FourWay {
constructor(serial) {
@@ -210,9 +200,11 @@ class FourWay {
const message = self.createMessage(command, params, address);
// Debug print all messages except the keep alive messages
+ /*
if (command !== COMMANDS.cmd_InterfaceTestAlive) {
console.debug('sending', this.commandToString(command), address.toString(0x10));
}
+ */
const processMessage = async(resolve, reject) => {
/**
@@ -230,7 +222,7 @@ class FourWay {
return resolve(msg);
}
} catch(e) {
- console.debug('Command failed:', e.message);
+ console.debug(`Command ${this.commandToString(command)} failed: ${e.message}`);
return reject(e);
}
@@ -256,9 +248,8 @@ class FourWay {
flash.meta = {};
try {
- const blheli = new Blheli();
const interfaceMode = flash.params[3];
-
+ flash.meta.input = flash.params[2];
flash.meta.signature = flash.params[1] << 8 | flash.params[0];
flash.meta.interfaceMode = interfaceMode;
flash.meta.available = true;
@@ -273,7 +264,7 @@ class FourWay {
if (isSiLabs) {
layoutSize = BLHELI_EEPROM.LAYOUT_SIZE;
- settingsArray = (await this.read(BLHELI_SILABS.EEPROM_OFFSET, layoutSize)).params;
+ settingsArray = (await this.read(BLHELI_EEPROM.SILABS.EEPROM_OFFSET, layoutSize)).params;
} else if (isArm) {
layoutSize = AM32_EEPROM.LAYOUT_SIZE;
layout = AM32_EEPROM.LAYOUT;
@@ -288,10 +279,7 @@ class FourWay {
flash.isAtmel = isAtmel;
flash.settingsArray = settingsArray;
- flash.settings = blheli.settingsObject(
- settingsArray,
- layout
- );
+ flash.settings = Convert.arrayToSettingsObject(settingsArray, layout);
/**
* Baased on the name we can decide if the initially guessed layout
@@ -310,11 +298,7 @@ class FourWay {
if(newLayout) {
layout = newLayout;
-
- flash.settings = blheli.settingsObject(
- settingsArray,
- layout
- );
+ flash.settings = Convert.arrayToSettingsObject(settingsArray, layout);
}
const layoutRevision = flash.settings.LAYOUT_REVISION.toString();
@@ -342,7 +326,7 @@ class FourWay {
flash.individualSettingsDescriptions = individualSettingsDescriptions[layoutRevision];
if (interfaceMode !== MODES.ARMBLB) {
- const mode = blheli.modeToString(flash.settings.MODE);
+ const mode = Convert.modeToString(flash.settings.MODE);
try {
const descriptions = settingsDescriptions[layoutRevision][mode];
flash.settingsDescriptions = descriptions;
@@ -352,23 +336,63 @@ class FourWay {
}
const layoutName = (flash.settings.LAYOUT || '').trim();
- let bootloaderRevision = null;
let make = null;
+ let displayName = 'UNKNOWN';
if (isSiLabs) {
const blheliLayouts = BLHELI_ESCS.layouts[BLHELI_EEPROM.TYPES.SILABS];
const blheliSLayouts = BLHELI_ESCS.layouts[BLHELI_EEPROM.TYPES.BLHELI_S_SILABS];
const bluejayLayouts = BLUEJAY_ESCS.layouts[BLUEJAY_EEPROM.TYPES.EFM8];
- if (layoutName in blheliLayouts) {
+ if (BLUEJAY_EEPROM.NAMES.includes(name) && layoutName in bluejayLayouts) {
+ make = bluejayLayouts[layoutName].name;
+ displayName = bluejayBuildDisplayName(flash, make);
+ }
+ else if (layoutName in blheliLayouts) {
make = blheliLayouts[layoutName].name;
} else if (layoutName in blheliSLayouts) {
make = blheliSLayouts[layoutName].name;
- } else if (layoutName in bluejayLayouts) {
- make = bluejayLayouts[layoutName].name;
+ displayName = blheliBuildDisplayName(flash, make);
}
} else if (isArm) {
- bootloaderRevision = flash.settings.BOOT_LOADER_REVISION;
- flash.settings.LAYOUT = flash.settings.NAME;
+ /* Read version information direct from EEPROM so we can later
+ * compare to the settings object. This allows us to verify, that
+ * everything went well after flashing.
+ */
+ const [mainRevision, subRevision] = (await this.read(AM32_EEPROM.VERSION_OFFSET, AM32_EEPROM.VERSION_SIZE)).params;
+
+ if(
+ flash.settings.MAIN_REVISION !== mainRevision ||
+ flash.settings.SUB_REVISION !== subRevision
+ ) {
+ const flashFirmware = `${flash.settings.MAIN_REVISION}.${flash.settings.SUB_REVISION}`;
+ const eepromFirmware = `${mainRevision}.${subRevision}`;
+ this.addLogMessage('firmwareMismatch', {
+ flash: flashFirmware,
+ eeprom: eepromFirmware,
+ });
+ }
+
+ flash.bootloader = {};
+ if(flash.meta.input) {
+ flash.bootloader.input = flash.meta.input;
+ flash.bootloader.valid = false;
+ }
+
+ /* Bootloader input pins are limited. If something different is set,
+ * then the user probably has an old fw flashed.
+ */
+ for(let [key, value] of Object.entries(AM32_EEPROM.BOOT_LOADER_PINS)) {
+ if(value === flash.bootloader.input) {
+ flash.bootloader.valid = true;
+ flash.bootloader.pin = key;
+ flash.bootloader.version = flash.settings.BOOT_LOADER_REVISION;
+ }
+ }
+
+ flash.settings.MAIN_REVISION = mainRevision;
+ flash.settings.SUB_REVISION = subRevision;
+
+ displayName = am32BuildDisplayName(flash, flash.settings.NAME);
} else {
const blheliAtmelLayouts = BLHELI_ESCS.layouts[BLHELI_EEPROM.TYPES.ATMEL];
if (layoutName in blheliAtmelLayouts) {
@@ -377,7 +401,7 @@ class FourWay {
}
flash.defaultSettings = defaultSettings[layoutRevision];
- flash.bootloaderRevision = bootloaderRevision;
+ flash.displayName = displayName;
flash.layoutSize = layoutSize;
flash.layout = layout;
flash.make = make;
@@ -411,8 +435,7 @@ class FourWay {
const flash = await this.sendMessagePromised(COMMANDS.cmd_DeviceInitFlash, [target]);
if (flash) {
- const blheli = new Blheli();
- const newSettingsArray = blheli.settingsArray(settings, esc.layout, esc.layoutSize);
+ const newSettingsArray = Convert.objectToSettingsArray(settings, esc.layout, esc.layoutSize);
if(newSettingsArray.length !== esc.settingsArray.length) {
throw new Error('byteLength of buffers do not match');
}
@@ -476,7 +499,7 @@ class FourWay {
switch(interfaceMode) {
case MODES.SiLC2: {
- return BLHELI_SILABS.FLASH_SIZE;
+ return BLHELI_EEPROM.SILABS.FLASH_SIZE;
}
case MODES.SiLBLB: {
@@ -590,7 +613,7 @@ class FourWay {
this.totalBytes = BLHELI_EEPROM.PAGE_SIZE * 14 * 2;
this.bytesWritten = 0;
- const message = await this.read(BLHELI_SILABS.EEPROM_OFFSET, BLHELI_EEPROM.LAYOUT_SIZE);
+ const message = await this.read(BLHELI_EEPROM.SILABS.EEPROM_OFFSET, BLHELI_EEPROM.LAYOUT_SIZE);
// checkESCAndMCU
const escSettingArrayTmp = message.params;
@@ -604,7 +627,7 @@ class FourWay {
BLHELI_EEPROM.LAYOUT.LAYOUT.offset + BLHELI_EEPROM.LAYOUT.LAYOUT.size);
if (!compare(target_layout, fw_layout)) {
- var target_layout_str = buf2ascii(target_layout).trim();
+ var target_layout_str = Convert.bufferToAscii(target_layout).trim();
if (target_layout_str.length === 0) {
target_layout_str = 'EMPTY';
}
@@ -622,7 +645,7 @@ class FourWay {
BLHELI_EEPROM.LAYOUT.MCU.offset,
BLHELI_EEPROM.LAYOUT.MCU.offset + BLHELI_EEPROM.LAYOUT.MCU.size);
if (!compare(target_mcu, fw_mcu)) {
- var target_mcu_str = buf2ascii(target_mcu).trim();
+ var target_mcu_str = Convert.bufferToAscii(target_mcu).trim();
if (target_mcu_str.length === 0) {
target_mcu_str = 'EMPTY';
}
@@ -678,7 +701,7 @@ class FourWay {
const eepromInfo = new Uint8Array(17).fill(0x00);
eepromInfo.set([originalSettings[1], originalSettings[2]], 1);
- eepromInfo.set(ascii2buf('FLASH FAIL '), 5);
+ eepromInfo.set(Convert.asciiToBuffer('FLASH FAIL '), 5);
await this.write(AM32_EEPROM.EEPROM_OFFSET, eepromInfo);
@@ -687,7 +710,7 @@ class FourWay {
originalSettings[0] = 0x01;
originalSettings.fill(0x00, 3, 5);
- originalSettings.set(ascii2buf('NOT READY '), 5);
+ originalSettings.set(Convert.asciiToBuffer('NOT READY '), 5);
await this.write(AM32_EEPROM.EEPROM_OFFSET, originalSettings);
};
@@ -708,7 +731,7 @@ class FourWay {
// Reset after flashing to update name and settings
await this.reset(target);
- await delay(AM32_RESET_DELAY_MS);
+ await delay(AM32_EEPROM.RESET_DELAY);
} break;
default: throw new Error(`Flashing with ${interfaceMode} is not yet implemented`);
@@ -731,9 +754,9 @@ class FourWay {
if(esc.isArm) {
try {
- const parsed = parseHex(hex);
+ const parsed = Flash.parseHex(hex);
const endAddress = parsed.data[parsed.data.length - 1].address + parsed.data[parsed.data.length - 1].bytes;
- const flash = fillImage(parsed, endAddress - flashOffset, flashOffset);
+ const flash = Flash.fillImage(parsed, endAddress - flashOffset, flashOffset);
//TODO: Also check for the firmware name
// But we first need to get this moved to a fixed location
@@ -754,12 +777,12 @@ class FourWay {
}
} else if(!esc.isAtmel) {
try {
- const parsed = parseHex(hex);
- const flash = fillImage(parsed, flashSize, flashOffset);
+ const parsed = Flash.parseHex(hex);
+ const flash = Flash.fillImage(parsed, flashSize, flashOffset);
// Check pseudo-eeprom page for BLHELI signature
- const mcu = buf2ascii(
- flash.subarray(BLHELI_SILABS.EEPROM_OFFSET)
+ const mcu = Convert.bufferToAscii(
+ flash.subarray(BLHELI_EEPROM.SILABS.EEPROM_OFFSET)
.subarray(BLHELI_EEPROM.LAYOUT.MCU.offset)
.subarray(0, BLHELI_EEPROM.LAYOUT.MCU.size));
@@ -828,7 +851,7 @@ class FourWay {
}
async writeEEpromSafeguard(settings) {
- settings.set(ascii2buf('**FLASH*FAILED**'), BLHELI_EEPROM.LAYOUT.NAME.offset);
+ settings.set(Convert.asciiToBuffer('**FLASH*FAILED**'), BLHELI_EEPROM.LAYOUT.NAME.offset);
const response = await this.write(BLHELI_EEPROM.EEPROM_OFFSET, settings);
const verifySafeguard = async (resolve, reject) => {
@@ -907,11 +930,12 @@ class FourWay {
return this.sendMessagePromised(COMMANDS.cmd_DevicePageErase, [page]);
}
- read(address, bytes) {
+ read(address, bytes, retries = 10) {
return this.sendMessagePromised(
COMMANDS.cmd_DeviceRead,
[bytes === 256 ? 0 : bytes],
- address
+ address,
+ retries
);
}
@@ -936,9 +960,7 @@ class FourWay {
}
exit() {
- if (this.interval) {
- clearInterval(this.interval);
- }
+ clearInterval(this.interval);
return this.sendMessagePromised(COMMANDS.cmd_InterfaceExit);
}
diff --git a/src/utils/Msp.js b/src/utils/Msp.js
index b9b63c919..6585ee26c 100644
--- a/src/utils/Msp.js
+++ b/src/utils/Msp.js
@@ -1,6 +1,6 @@
-import {
- NotEnoughDataError,
-} from './helpers/QueueProcessor';
+import compareVersions from 'compare-versions';
+
+import { NotEnoughDataError } from './helpers/QueueProcessor';
const MSP = {
MSP_API_VERSION: 1,
@@ -9,6 +9,8 @@ const MSP = {
MSP_BOARD_INFO: 4,
MSP_BUILD_INFO: 5,
+ MSP_BATTERY_STATE: 130,
+
MSP_SET_MOTOR: 214,
MSP_SET_PASSTHROUGH: 245,
@@ -41,6 +43,8 @@ class Msp {
const speedBufferOut = new ArrayBuffer(16);
this.speedBufView = new Uint8Array(speedBufferOut);
+
+ this.version = null;
}
setLogCallback(logCallback) {
@@ -289,6 +293,10 @@ class Msp {
return this.send(MSP.MSP_MOTOR);
}
+ getBatteryState() {
+ return this.send(MSP.MSP_BATTERY_STATE);
+ }
+
set4WayIf() {
return this.send(MSP.MSP_SET_PASSTHROUGH);
}
@@ -388,6 +396,8 @@ class Msp {
config.apiVersion = `${data.getUint8(offset++)}.`;
config.apiVersion += `${data.getUint8(offset++)}.0`;
+ this.version = config.apiVersion;
+
return config;
}
@@ -451,6 +461,23 @@ class Msp {
return config;
}
+ case MSP.MSP_BATTERY_STATE: {
+ const battery = {
+ cellCount: data.getUint8(0),
+ capacity: data.getUint16(1, 1), // mAh
+ voltage: data.getUint8(3) / 10.0, // V
+ drawn: data.getUint16(4, 1), // mAh
+ amps: data.getUint16(6, 1) / 100, // A
+ state: data.getUint8(8),
+ };
+
+ if(compareVersions.compare(this.version, '1.41.0', '>=')) {
+ battery.voltage = data.getUint16(9, 1) / 100.0; // V
+ }
+
+ return battery;
+ }
+
case MSP.MSP_SET_3D: {
console.debug('3D settings saved');
} break;
diff --git a/src/utils/Serial.js b/src/utils/Serial.js
index 64e0e2e73..2924cc571 100644
--- a/src/utils/Serial.js
+++ b/src/utils/Serial.js
@@ -1,9 +1,6 @@
import Msp from './Msp';
import FourWay from './FourWay';
-
-import {
- QueueProcessor,
-} from './helpers/QueueProcessor';
+import { QueueProcessor } from './helpers/QueueProcessor';
/**
* Abstraction layer for all serial communication
@@ -33,7 +30,6 @@ class Serial {
this.logCallback = null;
this.packetErrorsCallback = null;
- this.utilizationCallback = null;
this.qp = new QueueProcessor();
@@ -43,16 +39,26 @@ class Serial {
this.receivedTotal = 0;
}
- /**
- * Send a buffer via serial and process response with the response handler
- */
- async executeCommand(buffer, responseHandler) {
- const sendHandler = async function() {
- await this.writeBuffer(buffer);
- }.bind(this);
-
- return this.qp.addCommand(sendHandler, responseHandler);
- }
+ /* MSP commands */
+ enable4WayInterface = () => this.msp.set4WayIf();
+ getApiVersion = () => this.msp.getApiVersion();
+ getBatteryState = () => this.msp.getBatteryState();
+ getBoardInfo = () => this.msp.getBoardInfo();
+ getBuildInfo = () => this.msp.getBuildInfo();
+ getFcVariant = () => this.msp.getFcVariant();
+ getFcVersion = () => this.msp.getFcVersion();
+ getMotorData = () => this.msp.getMotorData();
+ getUid = () => this.msp.getUid();
+ spinAllMotors = (speed) => this.msp.spinAllMotors(speed);
+ spinMotor = (index, speed) => this.msp.spinMotor(index, speed);
+
+ /* 4 Way interface commands */
+ exitFourWayInterface = () => this.fourWay.exit();
+ getFourWayInterfaceInfo = (esc) => this.fourWay.getInfo(esc);
+ resetFourWayInterface = (esc) => this.fourWay.reset(esc);
+ startFourWayInterface = () => this.fourWay.start();
+ writeHex = (index, esc, hex, force, migrate, cbProgress) => this.fourWay.writeHex(index, esc, hex, force, migrate, cbProgress);
+ writeSettings = (index, esc, settings) => this.fourWay.writeSettings(index, esc, settings);
setLogCallback(logCallback) {
this.logCallback = logCallback;
@@ -61,10 +67,6 @@ class Serial {
this.msp.setLogCallback(logCallback);
}
- setUtilizationCallback(utilizationCallback) {
- this.utilizationCallback = utilizationCallback;
- }
-
setPacketErrorsCallback(packetErrorsCallback) {
this.packetErrorsCallback = packetErrorsCallback;
@@ -72,83 +74,15 @@ class Serial {
this.msp.setPacketErrorsCallback(packetErrorsCallback);
}
- async getApiVersion() {
- return this.msp.getApiVersion();
- }
-
- async getFcVariant() {
- return this.msp.getFcVariant();
- }
-
- async getFcVersion() {
- return this.msp.getFcVersion();
- }
-
- async getBuildInfo() {
- return this.msp.getBuildInfo();
- }
-
- async getBoardInfo() {
- return this.msp.getBoardInfo();
- }
-
- async getMotorData() {
- return this.msp.getMotorData();
- }
-
- async getUid() {
- return this.msp.getUid();
- }
-
- async enable4WayInterface() {
- return this.msp.set4WayIf();
- }
-
- async spinMotor(index, speed) {
- return this.msp.spinMotor(index, speed);
- }
-
- async spinAllMotors(speed) {
- return this.msp.spinAllMotors(speed);
- }
-
- async fourWayWriteSettings(index, esc, settings) {
- return this.fourWay.writeSettings(index, esc, settings);
- }
-
- async fourWayWriteHex(index, esc, hex, force, migrate, cbProgress) {
- return this.fourWay.writeHex(index, esc, hex, force, migrate, cbProgress);
- }
-
- async fourWayStart() {
- this.fourWay.start();
- }
-
- async fourWayExit() {
- return this.fourWay.exit();
- }
-
- async fourWayReset(esc) {
- return this.fourWay.reset(esc);
- }
-
- async fourWayTestAlive() {
- return this.fourWay.testAlive();
- }
-
- async fourWayReadEEprom(address, bytes) {
- return this.fourWay.readEEprom(
- address,
- bytes
- );
- }
-
- async fourWayInitFlash(esc) {
- return this.fourWay.initFlash(esc);
- }
+ /**
+ * Send a buffer via serial and process response with the response handler
+ */
+ async executeCommand(buffer, responseHandler) {
+ const sendHandler = async function() {
+ await this.writeBuffer(buffer);
+ }.bind(this);
- async fourWayGetInfo(esc) {
- return this.fourWay.getInfo(esc);
+ return this.qp.addCommand(sendHandler, responseHandler);
}
async writeBuffer(buffer) {
@@ -189,7 +123,7 @@ class Serial {
};
}
- async open(baudRate) {
+ async open(baudRate = 115200) {
this.baudRate = baudRate;
await this.port.open({ baudRate });
@@ -208,18 +142,18 @@ class Serial {
this.startReader();
}
- disconnect() {
+ async disconnect() {
this.running = false;
this.reader = null;
this.writer = null;
- }
-
- async close() {
- this.running = false;
if(this.fourWay) {
await this.fourWay.exit();
}
+ }
+
+ async close() {
+ this.running = false;
if(this.reader) {
this.reader.cancel();
@@ -235,6 +169,8 @@ class Serial {
} catch(e) {
// we tried...
}
+
+ this.disconnect();
}
}
diff --git a/src/utils/helpers/Convert.js b/src/utils/helpers/Convert.js
new file mode 100644
index 000000000..65d7029e5
--- /dev/null
+++ b/src/utils/helpers/Convert.js
@@ -0,0 +1,74 @@
+import { EEPROM } from '../../sources/Blheli';
+
+class Convert {
+ static modeToString(mode) {
+ for (const [key, value] of Object.entries(EEPROM.MODES)) {
+ if (value === mode) {
+ return key;
+ }
+ }
+ }
+
+ static arrayToSettingsObject(settingsUint8Array, layout) {
+ const object = {};
+
+ for (const [prop, setting] of Object.entries(layout)) {
+ if (setting.size === 1) {
+ object[prop] = settingsUint8Array[setting.offset];
+ } else if (setting.size === 2) {
+ object[prop] = settingsUint8Array[setting.offset] << 8 |
+ settingsUint8Array[setting.offset + 1];
+ } else if (setting.size > 2) {
+ object[prop] = String.fromCharCode.apply(
+ undefined,
+ settingsUint8Array.subarray(setting.offset).
+ subarray(0, setting.size)
+ ).trim();
+ } else {
+ throw new Error('Logic error');
+ }
+ }
+
+ return object;
+ }
+
+ static objectToSettingsArray(settingsObject, layout, layoutSize) {
+ const array = new Uint8Array(layoutSize).fill(0xff);
+
+ for (const [prop, setting] of Object.entries(layout)) {
+ if (setting.size === 1) {
+ array[setting.offset] = settingsObject[prop];
+ } else if (setting.size === 2) {
+ array[setting.offset] = settingsObject[prop] >> 8 & 0xff;
+ array[setting.offset + 1] = settingsObject[prop] & 0xff;
+ } else if (setting.size > 2) {
+ const { length } = settingsObject[prop];
+ for (let i = 0; i < setting.size; i += 1) {
+ array[setting.offset + i] = i < length ?
+ settingsObject[prop].charCodeAt(i) :
+ ' '.charCodeAt(0);
+ }
+ } else {
+ throw new Error('Logic error');
+ }
+ }
+
+ return array;
+ }
+
+ static bufferToAscii(buffer) {
+ return String.fromCharCode.apply(null, buffer);
+ }
+
+ static asciiToBuffer(ascii) {
+ const buffer = new Uint8Array(ascii.length);
+
+ for (var i = 0; i < ascii.length; i += 1) {
+ buffer[i] = ascii.charCodeAt(i);
+ }
+
+ return buffer;
+ }
+}
+
+export default Convert;
diff --git a/src/utils/helpers/Flash.js b/src/utils/helpers/Flash.js
index f4603055e..74546121c 100644
--- a/src/utils/helpers/Flash.js
+++ b/src/utils/helpers/Flash.js
@@ -1,143 +1,126 @@
-// Pad data to fixed size
-function fillImage(data, size, flashOffset) {
- var image = new Uint8Array(size).fill(0xFF);
-
- //data.data.forEach((block) => {
- for(let i = 0; i < data.data.length; i += 1) {
- const block = data.data[i];
- const address = block.address - flashOffset;
-
- // Check preconditions
- if (address >= image.byteLength) {
- return null;
+class Flash {
+ // Pad data to fixed size
+ static fillImage(data, size, flashOffset) {
+ var image = new Uint8Array(size).fill(0xFF);
+
+ //data.data.forEach((block) => {
+ for(let i = 0; i < data.data.length; i += 1) {
+ const block = data.data[i];
+ const address = block.address - flashOffset;
+
+ // Check preconditions
+ if (address >= image.byteLength) {
+ return null;
+ }
+
+ // block.data may be too large, select maximum allowed size
+ var clampedLength = Math.min(block.bytes, image.byteLength - address);
+ image.set(block.data.slice(0, clampedLength), address);
}
- // block.data may be too large, select maximum allowed size
- var clampedLength = Math.min(block.bytes, image.byteLength - address);
- image.set(block.data.slice(0, clampedLength), address);
+ return image;
}
- return image;
-}
-
-function parseHex(string) {
- string = string.split("\n");
-
- // check if there is an empty line in the end of hex file, if there is, remove it
- if (string[string.length - 1] === "") {
- string.pop();
- }
+ static parseHex(string) {
+ string = string.split("\n");
- var result = {
- data: [],
- endOfFile: false,
- bytes: 0,
- startLinearAddress: 0,
- };
-
- var extendedLinearAddress = 0;
- var nextAddress = 0;
-
- for (var i = 0; i < string.length; i += 1) {
- // each byte is represnted by two chars
- var byteCount = parseInt(string[i].substr(1, 2), 16);
- var address = parseInt(string[i].substr(3, 4), 16);
- var recordType = parseInt(string[i].substr(7, 2), 16);
- var content = string[i].substr(9, byteCount * 2); // still in string format
- var checksum = parseInt(string[i].substr(9 + byteCount * 2, 2), 16); // (this is a 2's complement value)
-
- switch (recordType) {
- // data record
- case 0x00: {
- if (address !== nextAddress || nextAddress === 0) {
- result.data.push({
- 'address': extendedLinearAddress + address,
- 'bytes': 0,
- 'data': [],
- });
- }
-
- // store address for next comparison
- nextAddress = address + byteCount;
-
- // process data
- var crc = byteCount + parseInt(string[i].substr(3, 2), 16) + parseInt(string[i].substr(5, 2), 16) + recordType;
- for (var needle = 0; needle < byteCount * 2; needle += 2) { // * 2 because of 2 hex chars per 1 byte
- var num = parseInt(content.substr(needle, 2), 16); // get one byte in hex and convert it to decimal
- var string_block = result.data.length - 1;
-
- result.data[string_block].data.push(num);
- result.data[string_block].bytes += 1;
-
-
- crc += num;
- result.bytes += 1;
- }
-
- // change crc to 2's complement
- crc = (~crc + 1) & 0xFF;
-
- // Return in case of fail
- if (crc !== checksum) {
- return null;
- }
- } break;
-
- // end of file record
- case 0x01: {
- result.endOfFile = true;
- } break;
-
- // extended segment address record
- case 0x02: {
- if (parseInt(content, 16) !== 0) { // ignore if segment is 0
- console.debug('extended segment address record found - NOT IMPLEMENTED!');
- }
- } break;
-
- // start segment address record
- case 0x03: {
- if (parseInt(content, 16) !== 0) { // ignore if segment is 0
- console.debug('start segment address record found - NOT IMPLEMENTED!');
- }
- } break;
-
- // extended linear address record
- case 0x04: {
- extendedLinearAddress = (parseInt(content.substr(0, 2), 16) << 24) | parseInt(content.substr(2, 2), 16) << 16;
- } break;
-
- // start linear address record
- case 0x05: {
- result.startLinearAddress = parseInt(content, 16);
- } break;
+ // check if there is an empty line in the end of hex file, if there is, remove it
+ if (string[string.length - 1] === "") {
+ string.pop();
}
- }
-
- if (result.endOfFile) {
- return result;
- }
- return null;
-}
-
-function buf2ascii(buffer) {
- return String.fromCharCode.apply(null, buffer);
-}
+ var result = {
+ data: [],
+ endOfFile: false,
+ bytes: 0,
+ startLinearAddress: 0,
+ };
+
+ var extendedLinearAddress = 0;
+ var nextAddress = 0;
+
+ for (var i = 0; i < string.length; i += 1) {
+ // each byte is represnted by two chars
+ var byteCount = parseInt(string[i].substr(1, 2), 16);
+ var address = parseInt(string[i].substr(3, 4), 16);
+ var recordType = parseInt(string[i].substr(7, 2), 16);
+ var content = string[i].substr(9, byteCount * 2); // still in string format
+ var checksum = parseInt(string[i].substr(9 + byteCount * 2, 2), 16); // (this is a 2's complement value)
+
+ switch (recordType) {
+ // data record
+ case 0x00: {
+ if (address !== nextAddress || nextAddress === 0) {
+ result.data.push({
+ 'address': extendedLinearAddress + address,
+ 'bytes': 0,
+ 'data': [],
+ });
+ }
+
+ // store address for next comparison
+ nextAddress = address + byteCount;
+
+ // process data
+ var crc = byteCount + parseInt(string[i].substr(3, 2), 16) + parseInt(string[i].substr(5, 2), 16) + recordType;
+ for (var needle = 0; needle < byteCount * 2; needle += 2) { // * 2 because of 2 hex chars per 1 byte
+ var num = parseInt(content.substr(needle, 2), 16); // get one byte in hex and convert it to decimal
+ var string_block = result.data.length - 1;
+
+ result.data[string_block].data.push(num);
+ result.data[string_block].bytes += 1;
+
+
+ crc += num;
+ result.bytes += 1;
+ }
+
+ // change crc to 2's complement
+ crc = (~crc + 1) & 0xFF;
+
+ // Return in case of fail
+ if (crc !== checksum) {
+ return null;
+ }
+ } break;
+
+ // end of file record
+ case 0x01: {
+ result.endOfFile = true;
+ } break;
+
+ // extended segment address record
+ case 0x02: {
+ if (parseInt(content, 16) !== 0) { // ignore if segment is 0
+ console.debug('extended segment address record found - NOT IMPLEMENTED!');
+ }
+ } break;
+
+ // start segment address record
+ case 0x03: {
+ if (parseInt(content, 16) !== 0) { // ignore if segment is 0
+ console.debug('start segment address record found - NOT IMPLEMENTED!');
+ }
+ } break;
+
+ // extended linear address record
+ case 0x04: {
+ extendedLinearAddress = (parseInt(content.substr(0, 2), 16) << 24) | parseInt(content.substr(2, 2), 16) << 16;
+ } break;
+
+ // start linear address record
+ case 0x05: {
+ result.startLinearAddress = parseInt(content, 16);
+ } break;
+ }
+ }
-function ascii2buf(ascii) {
- const buffer = new Uint8Array(ascii.length);
+ if (result.endOfFile) {
+ return result;
+ }
- for (var i = 0; i < ascii.length; i += 1) {
- buffer[i] = ascii.charCodeAt(i);
+ return null;
}
-
- return buffer;
}
-export {
- fillImage,
- parseHex,
- buf2ascii,
- ascii2buf,
-};
+export default Flash;
diff --git a/src/utils/helpers/General.js b/src/utils/helpers/General.js
index 2818a221f..1c8289ebc 100644
--- a/src/utils/helpers/General.js
+++ b/src/utils/helpers/General.js
@@ -1,21 +1,16 @@
-import {
- EEPROM as BLUEJAY_EEPROM
-} from '../../sources/Bluejay';
-
-const BLUEJAY_TYPES = BLUEJAY_EEPROM.TYPES;
+import { EEPROM as BLHELI_EEPROM } from '../../sources/Blheli';
+import BLHELI_ESCS from '../../sources/Blheli/escs.json';
+import { EEPROM as BLUEJAY_EEPROM } from '../../sources/Bluejay';
import BLUEJAY_ESCS from '../../sources/Bluejay/escs.json';
-import {
- BLHELI_TYPES,
-} from '../../sources/Blheli/eeprom';
-import BLHELI_ESCS from '../../sources/Blheli/escs.json';
-
-import {
- AM32_TYPES,
-} from '../../sources/AM32/eeprom';
+import { EEPROM as AM32_EEPROM } from '../../sources/AM32';
import AM32_ESCS from '../../sources/AM32/escs.json';
+const BLHELI_TYPES = BLHELI_EEPROM.TYPES;
+const BLUEJAY_TYPES = BLUEJAY_EEPROM.TYPES;
+const AM32_TYPES = AM32_EEPROM.TYPES;
+
function compare(a, b) {
if (a.byteLength !== b.byteLength) {
return false;
diff --git a/src/utils/helpers/React.js b/src/utils/helpers/React.js
new file mode 100644
index 000000000..3a753e3d0
--- /dev/null
+++ b/src/utils/helpers/React.js
@@ -0,0 +1,31 @@
+import {
+ useEffect,
+ useRef,
+} from 'react';
+
+function useInterval(callback, delay) {
+ const savedCallback = useRef();
+
+ // Remember the latest callback.
+ useEffect(() => {
+ savedCallback.current = callback;
+ }, [callback]);
+
+ // Set up the interval.
+ useEffect(() => {
+ function tick() {
+ savedCallback.current();
+ }
+
+ if (delay !== null) {
+ let id = setInterval(tick, delay);
+ return () => clearInterval(id);
+ } else {
+ savedCallback.current();
+ }
+ }, [delay]);
+}
+
+export {
+ useInterval,
+};
diff --git a/src/utils/helpers/Settings.js b/src/utils/helpers/Settings.js
index 6867961e8..e79f76efd 100644
--- a/src/utils/helpers/Settings.js
+++ b/src/utils/helpers/Settings.js
@@ -1,6 +1,4 @@
-import {
- BLHELI_MODES,
-} from '../../sources/Blheli/eeprom';
+import { EEPROM as BLHELI_EEPROM } from '../../sources/Blheli';
const getMasterSettings = (escs) => {
const master = getMaster(escs);
@@ -49,7 +47,7 @@ const getMaster = (escs) => escs.find((esc) => esc.meta.available);
const getAllSettings = (escs) => escs.map((esc) => esc.settings);
-const isMulti = (escs) => escs.every((esc) => !esc.settings.MODE || esc.settings.MODE === BLHELI_MODES.MULTI);
+const isMulti = (escs) => escs.every((esc) => !esc.settings.MODE || esc.settings.MODE === BLHELI_EEPROM.MODES.MULTI);
function canMigrate(settingName, from, to, toSettingsDescriptions, toIndividualSettingsDescriptions) {
if (from.MODE === to.MODE) {
@@ -62,7 +60,7 @@ function canMigrate(settingName, from, to, toSettingsDescriptions, toIndividualS
}
const fromLayout = toSettingsDescriptions[from.LAYOUT_REVISION];
- const toLayout = toSettingsDescriptions[from.LAYOUT_REVISION];
+ const toLayout = toSettingsDescriptions[to.LAYOUT_REVISION];
let fromCommons = null;
let toCommons = null;
diff --git a/src/utils/helpers/__tests__/Convert.test.js b/src/utils/helpers/__tests__/Convert.test.js
new file mode 100644
index 000000000..474d75282
--- /dev/null
+++ b/src/utils/helpers/__tests__/Convert.test.js
@@ -0,0 +1,153 @@
+import Convert from '../Convert';
+import { EEPROM } from '../../../sources/Bluejay';
+
+const settingsArray = new Uint8Array(Object.values({
+ "0":0,
+ "1":11,
+ "2":201,
+ "3":255,
+ "4":51,
+ "5":1,
+ "6":1,
+ "7":25,
+ "8":255,
+ "9":9,
+ "10":96,
+ "11":1,
+ "12":255,
+ "13":85,
+ "14":170,
+ "15":255,
+ "16":255,
+ "17":255,
+ "18":255,
+ "19":255,
+ "20":255,
+ "21":4,
+ "22":255,
+ "23":255,
+ "24":255,
+ "25":255,
+ "26":255,
+ "27":40,
+ "28":80,
+ "29":4,
+ "30":255,
+ "31":2,
+ "32":255,
+ "33":255,
+ "34":255,
+ "35":7,
+ "36":255,
+ "37":255,
+ "38":255,
+ "39":0,
+ "40":0,
+ "41":255,
+ "42":255,
+ "43":255,
+ "44":255,
+ "45":255,
+ "46":255,
+ "47":255,
+ "48":255,
+ "49":255,
+ "50":255,
+ "51":255,
+ "52":255,
+ "53":255,
+ "54":255,
+ "55":255,
+ "56":255,
+ "57":255,
+ "58":255,
+ "59":255,
+ "60":255,
+ "61":255,
+ "62":255,
+ "63":255,
+ "64":35,
+ "65":83,
+ "66":95,
+ "67":72,
+ "68":95,
+ "69":53,
+ "70":48,
+ "71":35,
+ "72":32,
+ "73":32,
+ "74":32,
+ "75":32,
+ "76":32,
+ "77":32,
+ "78":32,
+ "79":32,
+ "80":35,
+ "81":66,
+ "82":76,
+ "83":72,
+ "84":69,
+ "85":76,
+ "86":73,
+ "87":36,
+ "88":69,
+ "89":70,
+ "90":77,
+ "91":56,
+ "92":66,
+ "93":50,
+ "94":49,
+ "95":35,
+ "96":66,
+ "97":108,
+ "98":117,
+ "99":101,
+ "100":106,
+ "101":97,
+ "102":121,
+ "103":32,
+ "104":40,
+ "105":66,
+ "106":69,
+ "107":84,
+ "108":65,
+ "109":41,
+ "110":32,
+ "111":32,
+}));
+
+test('modeToString', () => {
+ expect(Convert.modeToString(0x55AA)).toEqual('MULTI');
+});
+
+test('settingsUint8Array', () => {
+ const layout = JSON.parse(JSON.stringify(EEPROM.LAYOUT));
+
+ const settingsObject = Convert.arrayToSettingsObject(settingsArray, layout);
+ const keys = Object.keys(settingsObject);
+ expect(keys.length).toEqual(43);
+
+ layout.MAIN_REVISION.size = 0;
+ expect(() => Convert.arrayToSettingsObject(settingsArray, layout)).toThrow();
+});
+
+test('settingsArray', () => {
+ const layout = JSON.parse(JSON.stringify(EEPROM.LAYOUT));
+
+ const settingsObject = Convert.arrayToSettingsObject(settingsArray, layout);
+ const settingsArrayResult = Convert.objectToSettingsArray(settingsObject, layout, EEPROM.LAYOUT_SIZE);
+ expect(settingsArrayResult.length).toEqual(112);
+
+ layout.MAIN_REVISION.size = 0;
+ expect(() => Convert.objectToSettingsArray(settingsObject, layout, EEPROM.LAYOUT_SIZE)).toThrow();
+});
+
+test('bufferToAscii', () => {
+ const ascii = Convert.bufferToAscii([0x0054, 0x0045, 0x0053, 0x0054]);
+ expect(ascii).toEqual('TEST');
+});
+
+test('asciiToBuffer', () => {
+ const buffer = Convert.asciiToBuffer('TEST');
+ expect(buffer).toEqual(new Uint8Array([0x0054, 0x0045, 0x0053, 0x0054]));
+});
diff --git a/src/utils/helpers/__tests__/Flash.test.js b/src/utils/helpers/__tests__/Flash.test.js
index 3c3d6eccd..9ee851a83 100644
--- a/src/utils/helpers/__tests__/Flash.test.js
+++ b/src/utils/helpers/__tests__/Flash.test.js
@@ -1,27 +1,11 @@
import fs from 'fs';
-import path from 'path';
-import {
- buf2ascii,
- ascii2buf,
- parseHex,
- fillImage,
-} from '../Flash';
-
-test('buffer to ACSII', () => {
- const ascii = buf2ascii([0x0054, 0x0045, 0x0053, 0x0054]);
- expect(ascii).toEqual('TEST');
-});
-
-test('ASCII to buffer', () => {
- const buffer = ascii2buf('TEST');
- expect(buffer).toEqual(new Uint8Array([0x0054, 0x0045, 0x0053, 0x0054]));
-});
+import Flash from '../Flash';
test('should parse a valid hex file', () => {
const hexContent = fs.readFileSync(`${__dirname}/valid.hex`);
const hexString = hexContent.toString();
- const result = parseHex(hexString);
+ const result = Flash.parseHex(hexString);
expect(result).not.toBeNull();
});
@@ -29,7 +13,7 @@ test('should parse a valid hex file', () => {
test('should not parse an invalid hex file', () => {
const hexContent = fs.readFileSync(`${__dirname}/invalid.hex`);
const hexString = hexContent.toString();
- const result = parseHex(hexString);
+ const result = Flash.parseHex(hexString);
expect(result).toBeNull();
});
@@ -37,7 +21,7 @@ test('should not parse an invalid hex file', () => {
test('should not parse a hex file with broken checksum', () => {
const hexContent = fs.readFileSync(`${__dirname}/broken_checksum.hex`);
const hexString = hexContent.toString();
- const result = parseHex(hexString);
+ const result = Flash.parseHex(hexString);
expect(result).toBeNull();
});
@@ -45,10 +29,10 @@ test('should not parse a hex file with broken checksum', () => {
test('should fill an Image to a given size', () => {
const hexContent = fs.readFileSync(`${__dirname}/valid.hex`);
const hexString = hexContent.toString();
- const parsed = parseHex(hexString);
+ const parsed = Flash.parseHex(hexString);
const endAddress = parsed.data[parsed.data.length - 1].address + parsed.data[parsed.data.length - 1].bytes;
const flashOffset = 0;
- const result = fillImage(parsed, endAddress - flashOffset, flashOffset);
+ const result = Flash.fillImage(parsed, endAddress - flashOffset, flashOffset);
expect(result.length).toEqual(endAddress);
});
@@ -56,10 +40,10 @@ test('should fill an Image to a given size', () => {
test('should fail filling an Image with address higher than length', () => {
const hexContent = fs.readFileSync(`${__dirname}/valid.hex`);
const hexString = hexContent.toString();
- const parsed = parseHex(hexString);
+ const parsed = Flash.parseHex(hexString);
const endAddress = parsed.data[parsed.data.length - 1].address + parsed.data[parsed.data.length - 1].bytes;
const flashOffset = 0;
- const result = fillImage(parsed, endAddress - flashOffset - 1000, flashOffset);
+ const result = Flash.fillImage(parsed, endAddress - flashOffset - 1000, flashOffset);
expect(result).toBeNull();
});
diff --git a/src/utils/helpers/__tests__/General.test.js b/src/utils/helpers/__tests__/General.test.js
index de33bcc45..43d96e019 100644
--- a/src/utils/helpers/__tests__/General.test.js
+++ b/src/utils/helpers/__tests__/General.test.js
@@ -1,18 +1,12 @@
import fs from 'fs';
-import path from 'path';
-import {
- parseHex,
- fillImage
-} from '../Flash';
+import Flash from '../Flash';
import {
retry,
delay,
compare,
- isValidFlash,
- isValidLayout,
- getPossibleTypes,
+ isValidFlash, isValidLayout, getPossibleTypes,
} from '../General';
test('compare same buffers', () => {
@@ -45,10 +39,10 @@ test('delay', async() => {
test('valid Flash', () => {
const hexContent = fs.readFileSync(`${__dirname}/valid.hex`);
const hexString = hexContent.toString();
- const parsed = parseHex(hexString);
+ const parsed = Flash.parseHex(hexString);
const endAddress = parsed.data[parsed.data.length - 1].address + parsed.data[parsed.data.length - 1].bytes;
const flashOffset = 0;
- const flash = fillImage(parsed, endAddress - flashOffset, flashOffset);
+ const flash = Flash.fillImage(parsed, endAddress - flashOffset, flashOffset);
expect(isValidFlash('#BLHELI$EFM8B21#', flash)).toBeTruthy();
});
@@ -62,11 +56,7 @@ test('retry failing each time', async() => {
reject(new Error('Fail'));
}
- try {
- await retry(test, 5, 10);
- } catch(e) {
- expect();
- }
+ await expect(retry(test, 5, 10)).rejects.toThrow();
});
test('retry failing each time without delay', async() => {
@@ -74,15 +64,11 @@ test('retry failing each time without delay', async() => {
reject(new Error('Fail'));
}
- try {
- await retry(test, 5);
- } catch(e) {
- expect();
- }
+ await expect(retry(test, 5)).rejects.toThrow();
});
test('retry succeeds at first try', async() => {
- function test(resolve, reject) {
+ function test(resolve) {
resolve(true);
}
diff --git a/src/utils/helpers/__tests__/QueueProcessor.test.js b/src/utils/helpers/__tests__/QueueProcessor.test.js
index 0f37a227f..f69e76fbd 100644
--- a/src/utils/helpers/__tests__/QueueProcessor.test.js
+++ b/src/utils/helpers/__tests__/QueueProcessor.test.js
@@ -1,6 +1,3 @@
-import fs from 'fs';
-import path from 'path';
-
import {
NotEnoughDataError,
TimeoutError,
@@ -17,11 +14,7 @@ test('command times out', async() => {
qp.addData(new Uint8Array([1, 2, 3]));
};
- try {
- const result = await qp.addCommand(transmit, receive);
- } catch(e) {
- expect(e).not.toBeNull();
- }
+ await expect(qp.addCommand(transmit, receive)).rejects.toThrow(TimeoutError);
});
test('command times out while processing', async() => {
@@ -39,11 +32,7 @@ test('command times out while processing', async() => {
}, 2000);
};
- try {
- const result = await qp.addCommand(transmit, command);
- } catch(e) {
- expect(e).not.toBeNull();
- }
+ await expect(qp.addCommand(transmit, command)).rejects.toThrow(TimeoutError);
});
test('command fails', async() => {
@@ -58,16 +47,12 @@ test('command fails', async() => {
}, 200);
};
- try {
- const result = await qp.addCommand(transmit, command);
- } catch(e) {
- expect(e).not.toBeNull();
- }
+ await expect(qp.addCommand(transmit, command)).rejects.toThrow(Error);
});
test('command resolves', async() => {
const qp = new QueueProcessor();
- const command = (buffer, resolve, reject) => {
+ const command = (buffer, resolve) => {
resolve(true);
};
@@ -96,7 +81,7 @@ test('command no receive handler', async() => {
test('command has Data instantly', async() => {
const qp = new QueueProcessor();
- const command = (buffer, resolve, reject) => {
+ const command = (buffer, resolve) => {
resolve(true);
};
diff --git a/src/utils/helpers/__tests__/React.test.jsx b/src/utils/helpers/__tests__/React.test.jsx
new file mode 100644
index 000000000..a940177f6
--- /dev/null
+++ b/src/utils/helpers/__tests__/React.test.jsx
@@ -0,0 +1,57 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { render } from '@testing-library/react';
+import { useInterval } from '../React';
+
+function TestComponent({
+ callback,
+ timeout,
+}) {
+ useInterval(() => {
+ callback();
+ }, timeout);
+
+ return (
+