Compare commits
303 commits
main
...
MK3_3.11.1
Author | SHA1 | Date | |
---|---|---|---|
3ea88ef1bb | |||
![]() |
700d241e8e | ||
![]() |
9ac1523126 | ||
![]() |
7c108c9420 | ||
![]() |
1fa87da2d0 | ||
![]() |
e63af1a1e5 | ||
![]() |
dc812dabb2 | ||
![]() |
d4d5294964 | ||
![]() |
7162b224a7 | ||
![]() |
0af88574fb | ||
![]() |
81a8418dd6 | ||
![]() |
a01c19cade | ||
![]() |
0d7680dbf7 | ||
![]() |
880853650d | ||
![]() |
38081f0a30 | ||
![]() |
53046ffeee | ||
![]() |
44eb9d4ff9 | ||
![]() |
d3df8389ef | ||
![]() |
70c73cbf6b | ||
![]() |
aa59d9b5eb | ||
![]() |
3ae4b6d329 | ||
![]() |
4cd5777380 | ||
![]() |
f893d93d63 | ||
![]() |
a319e32c7e | ||
![]() |
137e607fef | ||
![]() |
8cc89c7207 | ||
![]() |
859f6215a9 | ||
![]() |
312f3070c2 | ||
![]() |
e58495ef39 | ||
![]() |
b52597f1b2 | ||
![]() |
6b6e06695f | ||
![]() |
b1bb1d9d05 | ||
![]() |
b03acf0d03 | ||
![]() |
14f07963ac | ||
![]() |
d00b20ee62 | ||
![]() |
c2e56f6a4a | ||
![]() |
509c13a9c1 | ||
![]() |
4752b2b479 | ||
![]() |
d2a542b554 | ||
![]() |
b244cedd7f | ||
![]() |
9a3f412aad | ||
![]() |
8bd3b473c4 | ||
![]() |
09c53408af | ||
![]() |
bf20d18711 | ||
![]() |
92e733fdcb | ||
![]() |
3954c44bc9 | ||
![]() |
19b4c333c0 | ||
![]() |
85a5986e9e | ||
![]() |
7a64210043 | ||
![]() |
12b184cf68 | ||
![]() |
61695eebcc | ||
![]() |
3aab3b7148 | ||
![]() |
7c55cf801b | ||
![]() |
764a1fd411 | ||
![]() |
7265174a93 | ||
![]() |
08332a8942 | ||
![]() |
00ec8bb01c | ||
![]() |
3e6c4ac6fd | ||
![]() |
ce5a9613ce | ||
![]() |
e9e84d4390 | ||
![]() |
626e5b43eb | ||
![]() |
1f4da80609 | ||
![]() |
18859a3609 | ||
![]() |
b4492067a4 | ||
![]() |
94f9a97344 | ||
![]() |
a4050b3e26 | ||
![]() |
f0a498abb1 | ||
![]() |
d6de893ac5 | ||
![]() |
5c0a443b4f | ||
![]() |
f9f76520d9 | ||
![]() |
c1e971c2ad | ||
![]() |
45cd904520 | ||
![]() |
bcd2b6f8bf | ||
![]() |
879803daa9 | ||
![]() |
7939142922 | ||
![]() |
81d8c72cc4 | ||
![]() |
4a73cad3fd | ||
![]() |
6822b65e9c | ||
![]() |
ab48e9880e | ||
![]() |
53bbd36cf3 | ||
![]() |
ff9e79202e | ||
![]() |
851f72b059 | ||
![]() |
0889b3f49e | ||
![]() |
e10e196982 | ||
![]() |
97b6356476 | ||
![]() |
bb2a64387c | ||
![]() |
11ff93b78e | ||
![]() |
f33e5f1770 | ||
![]() |
41902315bd | ||
![]() |
9dd7540566 | ||
![]() |
22e51e1de7 | ||
![]() |
484827f43f | ||
![]() |
dfa936aa09 | ||
![]() |
571e6fabfa | ||
![]() |
93d2a8ef70 | ||
![]() |
dee2061d73 | ||
![]() |
3da07d34f3 | ||
![]() |
9d2f3acd13 | ||
![]() |
f5d4ba972b | ||
![]() |
3ddbea14bb | ||
![]() |
a51f799e73 | ||
![]() |
e0b18b279d | ||
![]() |
4934e6caf1 | ||
![]() |
a33340c176 | ||
![]() |
715f466fda | ||
![]() |
436b6f206a | ||
![]() |
087b545e0f | ||
![]() |
913cc502b9 | ||
![]() |
153f412012 | ||
![]() |
90734c9eff | ||
![]() |
c5999888e6 | ||
![]() |
b9ca45fea1 | ||
![]() |
a07b7291b4 | ||
![]() |
679730c9ed | ||
![]() |
73c0837856 | ||
![]() |
7016a1241a | ||
![]() |
a1711f727e | ||
![]() |
8d0f4b766a | ||
![]() |
1bba7815fc | ||
![]() |
f1ff5907f4 | ||
![]() |
4f49f085b0 | ||
![]() |
7c9369ede6 | ||
![]() |
592af52802 | ||
![]() |
8db5ad1044 | ||
![]() |
2eb32ac2c6 | ||
![]() |
d9cd5324e7 | ||
![]() |
480c30221e | ||
![]() |
e36d5ebe1c | ||
![]() |
2a65086f75 | ||
![]() |
ea39a245af | ||
![]() |
1940cdca30 | ||
![]() |
8e73bb030e | ||
![]() |
3031f68d31 | ||
![]() |
65e99c62de | ||
![]() |
5b45553f38 | ||
![]() |
6689581364 | ||
![]() |
489e4fd35c | ||
![]() |
c9f17b30e6 | ||
![]() |
9f093ee404 | ||
![]() |
ed8252527c | ||
![]() |
54e4966f2c | ||
![]() |
79aa067a8a | ||
![]() |
0ac7874d27 | ||
![]() |
834cc24e6c | ||
![]() |
42ac9c0ec3 | ||
![]() |
35cee44df1 | ||
![]() |
db7b41e294 | ||
![]() |
9ef0acba5d | ||
![]() |
00036bcfcc | ||
![]() |
752eef0876 | ||
![]() |
048117c3cb | ||
![]() |
8cf969eb1d | ||
![]() |
5c0d2767a8 | ||
![]() |
fb1c8ee0a3 | ||
![]() |
dd72b079ea | ||
![]() |
a4b605ba16 | ||
![]() |
d80cef5443 | ||
![]() |
881db2e747 | ||
![]() |
e7d7068840 | ||
![]() |
8d0af30aa7 | ||
![]() |
709cdf5131 | ||
![]() |
c06ec9d05b | ||
![]() |
5d29c4fab2 | ||
![]() |
b3a53f6436 | ||
![]() |
db79ae9d5e | ||
![]() |
0b8ecfbf7c | ||
![]() |
a3930cbff6 | ||
![]() |
1dd2e237a0 | ||
![]() |
4302fccca8 | ||
![]() |
6167813f07 | ||
![]() |
546eafae8b | ||
![]() |
9e8ed08092 | ||
![]() |
fc94322a10 | ||
![]() |
37662afdd1 | ||
![]() |
22b3fbfe09 | ||
![]() |
1e5421906f | ||
![]() |
9993026202 | ||
![]() |
103c6e8819 | ||
![]() |
eb04c5861d | ||
![]() |
75118d540f | ||
![]() |
0f7dcdf885 | ||
![]() |
f3a817ae45 | ||
![]() |
cc4601f3fe | ||
![]() |
82dba06602 | ||
![]() |
f2fdbb3485 | ||
![]() |
ce6b92052c | ||
![]() |
fbe33ed28f | ||
![]() |
f290039dff | ||
![]() |
c3347dd2cb | ||
![]() |
256c3f453b | ||
![]() |
92ec7d3d24 | ||
![]() |
a7839a6cc6 | ||
![]() |
1abd2be96d | ||
![]() |
86235259a3 | ||
![]() |
2a4e90bd93 | ||
![]() |
183eaf80ec | ||
![]() |
058c75f3ec | ||
![]() |
0f76c05a36 | ||
![]() |
45c121c7a4 | ||
![]() |
d19fa38afe | ||
![]() |
cbae08991c | ||
![]() |
3b82333fcb | ||
![]() |
9e36c80963 | ||
![]() |
77cba57eb6 | ||
![]() |
0928d28def | ||
![]() |
b7806bf25f | ||
![]() |
67a470e0ab | ||
![]() |
14f309819d | ||
![]() |
4d27b623ea | ||
![]() |
f922f4d1fa | ||
![]() |
0b8e65bd6c | ||
![]() |
bbf23d4473 | ||
![]() |
3936da7529 | ||
![]() |
311aa2a4c6 | ||
![]() |
9308593f5e | ||
![]() |
a28631638f | ||
![]() |
2d01cb37ef | ||
![]() |
84cba7f769 | ||
![]() |
68cf57272c | ||
![]() |
2568ca66f2 | ||
![]() |
7ab715c2dd | ||
![]() |
036bc38b82 | ||
![]() |
44ea34bb72 | ||
![]() |
f59fe20393 | ||
![]() |
365bd003f9 | ||
![]() |
4f8be42555 | ||
![]() |
1a6b668ede | ||
![]() |
f9a591052c | ||
![]() |
625fa3ea50 | ||
![]() |
a49ef30477 | ||
![]() |
e3712a72e6 | ||
![]() |
f50eaf4762 | ||
![]() |
e1e0dac635 | ||
![]() |
5096073507 | ||
![]() |
4d348fa953 | ||
![]() |
5d601e5ba0 | ||
![]() |
669f15a269 | ||
![]() |
93b1a6b736 | ||
![]() |
7442057aba | ||
![]() |
1d491e772b | ||
![]() |
255e05d6b9 | ||
![]() |
0ac5cff5d3 | ||
![]() |
db4859ce9a | ||
![]() |
687746a80a | ||
![]() |
eb25e5f0da | ||
![]() |
1544a79b4e | ||
![]() |
931e88022b | ||
![]() |
6dd7681f6b | ||
![]() |
9aebf23d41 | ||
![]() |
54d7e9331b | ||
![]() |
75dc5bd410 | ||
![]() |
8911161f6b | ||
![]() |
7083529990 | ||
![]() |
f8a0d3ad7b | ||
![]() |
5bce397fab | ||
![]() |
ba54dc3d35 | ||
![]() |
7fea716391 | ||
![]() |
20494f7260 | ||
![]() |
fda665f9de | ||
![]() |
e02dd42765 | ||
![]() |
b57fd94f05 | ||
![]() |
7b0872be64 | ||
![]() |
8708b1d413 | ||
![]() |
d59c08192b | ||
![]() |
ecc8898b58 | ||
![]() |
363a89c235 | ||
![]() |
253d04438d | ||
![]() |
17301872cf | ||
![]() |
4d664cedf4 | ||
![]() |
3e5452ef21 | ||
![]() |
66439f6ad0 | ||
![]() |
a1e2ca32e4 | ||
![]() |
21b11b90d5 | ||
![]() |
2e776de9a9 | ||
![]() |
e3e0ff0524 | ||
![]() |
026f2ccae2 | ||
![]() |
d2af15a35e | ||
![]() |
a0e7bc8ebc | ||
![]() |
29e863e425 | ||
![]() |
ba0e14f898 | ||
![]() |
d66927b0e0 | ||
![]() |
0be90dc5d1 | ||
![]() |
98d4e6972a | ||
![]() |
13f0f4d85a | ||
![]() |
e9fe7607a7 | ||
![]() |
eff9cd9f21 | ||
![]() |
b37e289a8f | ||
![]() |
400f673fe0 | ||
![]() |
d087973e00 | ||
![]() |
6aee17b4ca | ||
![]() |
3cfd706fff | ||
![]() |
31c8e4bc4c | ||
![]() |
eb9c8c8c20 | ||
![]() |
538ce06bf0 | ||
![]() |
bbe62b136a | ||
![]() |
d04ea859fb | ||
![]() |
47b1e6ccef | ||
![]() |
1888c783cb | ||
![]() |
d853c19a21 | ||
![]() |
31b913cddb | ||
![]() |
710852a1f2 | ||
![]() |
16602f4003 | ||
![]() |
d8996af574 |
101 changed files with 44046 additions and 40506 deletions
|
@ -15,4 +15,3 @@ max_line_length = 100
|
|||
|
||||
[lang/po/*.po]
|
||||
end_of_line = crlf
|
||||
trim_trailing_whitespace = false
|
||||
|
|
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -6,14 +6,14 @@ labels: bug
|
|||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Please, before you create a new bug report, please make sure you searched in open and closed issues and couldn't find anything that matches.
|
||||
|
||||
-->
|
||||
**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
|
||||
**Printer firmware version**- [e.g. 3.8.1, 3.8.1-RC1, ...]
|
||||
**Printer firmware version** - [e.g. 3.8.1, 3.8.1-RC1, ...]
|
||||
|
||||
**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
|
||||
**MMU upgrade firmware version [e.g. 1.0.6, 1.0.6-RC2, ...]
|
||||
**MMU upgrade** - [e.g. MMU2S, MMU2, MMU1]
|
||||
**MMU upgrade firmware version** - [e.g. 1.0.6, 1.0.6-RC2, ...]
|
||||
|
||||
**SD card or USB/Octoprint**
|
||||
Please let us know if you print via SD card or USB/Octoprint
|
||||
|
|
72
.gitignore
vendored
72
.gitignore
vendored
|
@ -1,57 +1,19 @@
|
|||
.settings
|
||||
.project
|
||||
.cproject
|
||||
Debug
|
||||
# Temporary configuration
|
||||
/Firmware/Configuration_prusa.h
|
||||
|
||||
# Temporary language files
|
||||
/lang/po/*.mo
|
||||
/lang/tmp/
|
||||
/lang/Firmware-intl.hex
|
||||
/lang/Firmware-intl-en_*.hex
|
||||
|
||||
# Temporary files and directories
|
||||
*[~#]
|
||||
*.tmp
|
||||
*.bak
|
||||
.DS_Store
|
||||
__pycache__
|
||||
Firmware/Configuration_prusa.h
|
||||
Firmware/Doc
|
||||
/Firmware/.vs/Firmware/v14
|
||||
/Firmware/__vm
|
||||
/Firmware/Firmware.sln
|
||||
/Firmware/Firmware.vcxproj
|
||||
/Firmware/Firmware.vcxproj.filters
|
||||
/Firmware/Firmware - Shortcut.lnk
|
||||
/Firmware/variants/1_75mm_MK3-MMU-EINSy10a-E3Dv6full.h.bak
|
||||
/Firmware/Marlin_main.cpp~RF12cfae7.TMP
|
||||
/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h.bak
|
||||
/html
|
||||
/latex
|
||||
/Doxyfile
|
||||
/Firmware/builds/1_75mm_MK3-EINY04-E3Dv6full
|
||||
/Firmware/Configuration_prusa.h.bak
|
||||
/Firmware/Configuration_prusa_backup.h
|
||||
/Firmware/ultralcd_implementation_hitachi_HD44780.h.bak
|
||||
/Firmware/ultralcd.cpp.bak
|
||||
/Firmware/temperature.cpp.bak
|
||||
/Firmware/pins.h.bak
|
||||
/Firmware/Marlin_main.cpp.bak
|
||||
/Firmware/language_pl.h.bak
|
||||
/Firmware/language_it.h.bak
|
||||
/Firmware/language_es.h.bak
|
||||
/Firmware/language_en.h.bak
|
||||
/Firmware/language_de.h.bak
|
||||
/Firmware/language_cz.h.bak
|
||||
/Firmware/variants/1_75mm_MK2-MultiMaterial-RAMBo13a-E3Dv6full.h
|
||||
/Firmware/variants/1_75mm_MK2-MultiMaterial-RAMBo10a-E3Dv6full.h
|
||||
/Firmware/variants/1_75mm_MK2-EINY01-E3Dv6full.h.bak
|
||||
/Firmware/variants/1_75mm_MK1-RAMBo13a-E3Dv6full.h
|
||||
/Firmware/variants/1_75mm_MK1-RAMBo10a-E3Dv6full.h
|
||||
/lang/*.bin
|
||||
/lang/*.hex
|
||||
/lang/*.dat
|
||||
/lang/*.tmp
|
||||
/lang/*.out
|
||||
/lang/not_tran*.txt
|
||||
/lang/not_used*.txt
|
||||
/lang/progmem1.chr
|
||||
/lang/progmem1.lss
|
||||
/lang/progmem1.txt
|
||||
/lang/progmem1.var
|
||||
/lang/text.sym
|
||||
/lang/textaddr.txt
|
||||
|
||||
# Generated files
|
||||
/build-env/
|
||||
/Firmware/Firmware.vcxproj
|
||||
/Firmware/Configuration_prusa_bckp.h
|
||||
/Firmware/variants/printers.h
|
||||
Configuration.tmp
|
||||
config.tmp
|
||||
/Firmware/Doc/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
dist: trusty
|
||||
dist: focal
|
||||
before_install:
|
||||
- sudo apt-get install -y ninja-build
|
||||
- sudo apt-get install -y ninja-build python3-polib python3-pyelftools
|
||||
# Arduino IDE adds a lot of noise caused by network traffic, trying to firewall it off
|
||||
- sudo iptables -P INPUT DROP
|
||||
- sudo iptables -P FORWARD DROP
|
||||
|
|
|
@ -17,17 +17,17 @@ extern PGM_P sPrinterName;
|
|||
|
||||
// Firmware version
|
||||
#define FW_MAJOR 3
|
||||
#define FW_MINOR 10
|
||||
#define FW_MINOR 11
|
||||
#define FW_REVISION 1
|
||||
//#define FW_FLAVOR RC //uncomment if DEBUG, DEVEL, APLHA, BETA or RC
|
||||
//#define FW_FLAVERSION 1 //uncomment if FW_FLAVOR is defined and versioning is needed.
|
||||
#define FW_FLAVOR RC //uncomment if DEBUG, DEVEL, APLHA, BETA or RC
|
||||
#define FW_FLAVERSION 1 //uncomment if FW_FLAVOR is defined and versioning is needed.
|
||||
#ifndef FW_FLAVOR
|
||||
#define FW_VERSION STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION)
|
||||
#else
|
||||
#define FW_VERSION STR(FW_MAJOR) "." STR(FW_MINOR) "." STR(FW_REVISION) "-" STR(FW_FLAVOR) "" STR(FW_FLAVERSION)
|
||||
#endif
|
||||
|
||||
#define FW_COMMIT_NR 4697
|
||||
#define FW_COMMIT_NR 4987
|
||||
|
||||
// FW_VERSION_UNKNOWN means this is an unofficial build.
|
||||
// The firmware should only be checked into github with this symbol.
|
||||
|
|
|
@ -538,26 +538,20 @@ const char* dcode_9_ADC_name(uint8_t i)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef AMBIENT_THERMISTOR
|
||||
extern int current_temperature_raw_ambient;
|
||||
#endif //AMBIENT_THERMISTOR
|
||||
|
||||
#ifdef VOLT_PWR_PIN
|
||||
extern int current_voltage_raw_pwr;
|
||||
#endif //VOLT_PWR_PIN
|
||||
|
||||
#ifdef VOLT_BED_PIN
|
||||
extern int current_voltage_raw_bed;
|
||||
#endif //VOLT_BED_PIN
|
||||
|
||||
uint16_t dcode_9_ADC_val(uint8_t i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
#ifdef SHOW_TEMP_ADC_VALUES
|
||||
case 0: return current_temperature_raw[0];
|
||||
#endif //SHOW_TEMP_ADC_VALUES
|
||||
case 1: return 0;
|
||||
#ifdef SHOW_TEMP_ADC_VALUES
|
||||
case 2: return current_temperature_bed_raw;
|
||||
#endif //SHOW_TEMP_ADC_VALUES
|
||||
#ifdef PINDA_THERMISTOR
|
||||
case 3: return current_temperature_raw_pinda;
|
||||
#endif //PINDA_THERMISTOR
|
||||
#ifdef VOLT_PWR_PIN
|
||||
case 4: return current_voltage_raw_pwr;
|
||||
#endif //VOLT_PWR_PIN
|
||||
|
|
|
@ -248,7 +248,7 @@ bool IsStopped(); // Returns true if the print has been stopped
|
|||
//put an ASCII command at the begin of the current buffer, read from flash
|
||||
#define enquecommand_front_P(cmd) enquecommand_front(cmd, true)
|
||||
|
||||
void prepare_arc_move(char isclockwise);
|
||||
void prepare_arc_move(bool isclockwise);
|
||||
void clamp_to_software_endstops(float target[3]);
|
||||
void refresh_cmd_timeout(void);
|
||||
|
||||
|
@ -352,7 +352,6 @@ extern unsigned long t_fan_rising_edge;
|
|||
extern bool mesh_bed_leveling_flag;
|
||||
extern bool mesh_bed_run_from_menu;
|
||||
|
||||
extern int8_t lcd_change_fil_state;
|
||||
// save/restore printing
|
||||
extern bool saved_printing;
|
||||
extern uint8_t saved_printing_type;
|
||||
|
@ -500,6 +499,7 @@ void raise_z_above(float target, bool plan=true);
|
|||
|
||||
extern "C" void softReset();
|
||||
void stack_error();
|
||||
void pullup_error(bool fromTempISR);
|
||||
|
||||
extern uint32_t IP_address;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -231,7 +231,7 @@ static void finISR(timer16_Sequence_t timer)
|
|||
#endif
|
||||
}
|
||||
|
||||
static boolean isTimerActive(timer16_Sequence_t timer)
|
||||
static bool isTimerActive(timer16_Sequence_t timer)
|
||||
{
|
||||
// returns true if any servo is active on this timer
|
||||
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
|
||||
|
|
|
@ -877,7 +877,10 @@ void CardReader::presort() {
|
|||
uint16_t counter = 0;
|
||||
uint16_t total = 0;
|
||||
for (uint16_t i = sortCountFiles/2; i > 0; i /= 2) total += sortCountFiles - i; //total runs for progress bar
|
||||
menu_progressbar_init(total, (runs == 0)?_i("Sorting files"):_i("Sorting folders"));
|
||||
menu_progressbar_init(
|
||||
total, (runs == 0)
|
||||
? _i("Sorting files") ////MSG_SORTING_FILES c=20
|
||||
: _i("Sorting folders")); ////MSG_SORTING_FOLDERS c=20
|
||||
|
||||
for (uint16_t gap = sortCountFiles/2; gap > 0; gap /= 2)
|
||||
{
|
||||
|
|
|
@ -135,7 +135,7 @@ private:
|
|||
|
||||
bool autostart_stilltocheck; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
|
||||
|
||||
int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
|
||||
uint16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
|
||||
char* diveDirName;
|
||||
|
||||
bool diveSubfolder (const char *&fileName);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
#include "cardreader.h"
|
||||
#include "ultralcd.h"
|
||||
|
||||
extern bool Stopped;
|
||||
|
||||
// Reserve BUFSIZE lines of length MAX_CMD_SIZE plus CMDBUFFER_RESERVE_FRONT.
|
||||
char cmdbuffer[BUFSIZE * (MAX_CMD_SIZE + 1) + CMDBUFFER_RESERVE_FRONT];
|
||||
// Head of the circular buffer, where to read.
|
||||
|
@ -23,11 +21,10 @@ bool cmdbuffer_front_already_processed = false;
|
|||
bool cmdqueue_serial_disabled = false;
|
||||
|
||||
int serial_count = 0; //index of character read from serial line
|
||||
boolean comment_mode = false;
|
||||
bool comment_mode = false;
|
||||
char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc
|
||||
|
||||
unsigned long TimeSent = _millis();
|
||||
unsigned long TimeNow = _millis();
|
||||
ShortTimer serialTimeoutTimer;
|
||||
|
||||
long gcode_N = 0;
|
||||
long gcode_LastN = 0;
|
||||
|
@ -402,8 +399,7 @@ void get_command()
|
|||
MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode
|
||||
selectedSerialPort = 1;
|
||||
} */ //RP - removed
|
||||
TimeSent = _millis();
|
||||
TimeNow = _millis();
|
||||
serialTimeoutTimer.start();
|
||||
|
||||
if (serial_char < 0)
|
||||
// Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names
|
||||
|
@ -537,22 +533,11 @@ void get_command()
|
|||
}
|
||||
} // end of serial line processing loop
|
||||
|
||||
if(farm_mode){
|
||||
TimeNow = _millis();
|
||||
if ( ((TimeNow - TimeSent) > 800) && (serial_count > 0) ) {
|
||||
cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0;
|
||||
|
||||
bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE);
|
||||
if (bufindw == sizeof(cmdbuffer))
|
||||
bufindw = 0;
|
||||
++ buflen;
|
||||
|
||||
serial_count = 0;
|
||||
|
||||
SERIAL_ECHOPGM("TIMEOUT:");
|
||||
//memset(cmdbuffer, 0 , sizeof(cmdbuffer));
|
||||
return;
|
||||
}
|
||||
if (serial_count > 0 && serialTimeoutTimer.expired(farm_mode ? 800 : 2000)) {
|
||||
comment_mode = false;
|
||||
serial_count = 0;
|
||||
SERIAL_ECHOLNPGM("RX timeout");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SDSUPPORT
|
||||
|
|
|
@ -49,12 +49,9 @@ extern bool cmdqueue_serial_disabled;
|
|||
extern uint32_t sdpos_atomic;
|
||||
|
||||
extern int serial_count;
|
||||
extern boolean comment_mode;
|
||||
extern bool comment_mode;
|
||||
extern char *strchr_pointer;
|
||||
|
||||
extern unsigned long TimeSent;
|
||||
extern unsigned long TimeNow;
|
||||
|
||||
extern long gcode_N;
|
||||
extern long gcode_LastN;
|
||||
extern long Stopped_gcode_LastN;
|
||||
|
|
|
@ -58,14 +58,32 @@
|
|||
//#define LANG_MODE 0 // primary language only
|
||||
#define LANG_MODE 1 // sec. language support
|
||||
|
||||
#define LANG_SIZE_RESERVED 0x3000 // reserved space for secondary language (12288 bytes)
|
||||
#define LANG_SIZE_RESERVED 0x3000 // reserved space for secondary language (12288 bytes). Maximum 32768 bytes
|
||||
|
||||
#if (LANG_SIZE_RESERVED % 256)
|
||||
#error "LANG_SIZE_RESERVED should be a multiple of a page size"
|
||||
#endif
|
||||
|
||||
//Community language support
|
||||
#define COMMUNITY_LANG_NL // Community Dutch language
|
||||
//#define COMMUNITY_LANG_QR // Community new language //..use this as a template and replace 'QR'
|
||||
#define COMMUNITY_LANG_GROUP 1
|
||||
|
||||
#if defined(COMMUNITY_LANG_NL) //|| defined(COMMUNITY_LANG_QR) //..use last part as a template and replace 'QR'
|
||||
#define COMMUNITY_LANG_SUPPORT
|
||||
#if (COMMUNITY_LANG_GROUP == 1)
|
||||
#define COMMUNITY_LANG_GROUP1_NL // Community Dutch language
|
||||
#define COMMUNITY_LANG_GROUP1_RO // Community Romanian language
|
||||
#define COMMUNITY_LANG_GROUP1_HU // Community Hungarian language
|
||||
#define COMMUNITY_LANG_GROUP1_HR // Community Croatian language
|
||||
#define COMMUNITY_LANG_GROUP1_SK // Community Slovak language
|
||||
#define COMMUNITY_LANG_GROUP1_SV // Community Swedish language
|
||||
#define COMMUNITY_LANG_GROUP1_NO // Community Norwegian language
|
||||
//#define COMMUNITY_LANG_GROUP1_DA // Community Danish language
|
||||
//#define COMMUNITY_LANG_GROUP1_SL // Community Slovanian language
|
||||
//#define COMMUNITY_LANG_GROUP1_LB // Community Luxembourgish language
|
||||
//#define COMMUNITY_LANG_GROUP1_LT // Community Lithuanian language
|
||||
//#define COMMUNITY_LANG_GROUP1_QR // Community new language //..use this as a template and replace 'QR'
|
||||
#endif
|
||||
|
||||
#if (COMMUNITY_LANG_GROUP >=1 )
|
||||
#define COMMUNITY_LANGUAGE_SUPPORT
|
||||
#endif
|
||||
|
||||
// Sanity checks for correct configuration of XFLASH_DUMP options
|
||||
|
|
|
@ -327,7 +327,13 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
|
|||
| 0x0D05 3333 | uint32_t | EEPROM_JOB_ID | ??? | 00 00 00 00h | Job ID used by host software | D3 only | D3 Ax0d05 C4
|
||||
| 0x0D04 3332 | uint8_t | EEPROM_ECOOL_ENABLE | ffh 255 | ^ | Disable extruder motor scaling for non-farm print | LCD menu | D3 Ax0d04 C1
|
||||
| ^ | ^ | ^ | 2ah 42 | ^ | Enable extruder motor scaling for non-farm print | ^ | D3 Ax0d04 C1
|
||||
| 0x0D03 3321 | uint8_t | EEPROM_FW_CRASH_FLAG | 01h 1 | ff/00 | Last FW crash reason (dump_crash_reason) | D21/D22 | D3 Ax0d03 C1
|
||||
| 0x0D03 3321 | uint8_t | EEPROM_FW_CRASH_FLAG | ffh 255 | ffh 255 | Last FW crash reason (dump_crash_reason) | D21/D22 | D3 Ax0d03 C1
|
||||
| ^ | ^ | ^ | 00h 0 | ^ | manual | ^ | ^
|
||||
| ^ | ^ | ^ | 01h 1 | ^ | stack_error | ^ | ^
|
||||
| ^ | ^ | ^ | 02h 2 | ^ | watchdog | ^ | ^
|
||||
| ^ | ^ | ^ | 03h 3 | ^ | bad_isr | ^ | ^
|
||||
| ^ | ^ | ^ | 04h 4 | ^ | bad_pullup_temp_isr | ^ | ^
|
||||
| ^ | ^ | ^ | 05h 5 | ^ | bad_pullup_step_isr | ^ | ^
|
||||
|
||||
| Address begin | Bit/Type | Name | Valid values | Default/FactoryReset | Description | Gcode/Function| Debug code
|
||||
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--:
|
||||
|
|
|
@ -28,7 +28,7 @@ uint8_t lang_is_selected(void) { return 1; }
|
|||
#else //(LANG_MODE == 0) //secondary languages in progmem or xflash
|
||||
|
||||
//reserved xx kbytes for secondary language table
|
||||
const char _SEC_LANG[LANG_SIZE_RESERVED] PROGMEM_I2 = "_SEC_LANG";
|
||||
const char __attribute__((aligned(256))) _SEC_LANG[LANG_SIZE_RESERVED] PROGMEM_I2 = "_SEC_LANG";
|
||||
|
||||
//primary language signature
|
||||
const uint32_t _PRI_LANG_SIGNATURE[1] __attribute__((section(".progmem0"))) = {0xffffffff};
|
||||
|
@ -41,7 +41,7 @@ const char* lang_get_translation(const char* s)
|
|||
if (lang_selected == 0) return s + 2; //primary language selected, return orig. str.
|
||||
if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str.
|
||||
uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id
|
||||
if (ui == 0xffff) return s + 2; //translation not found, return orig. str.
|
||||
if (ui == 0xffff) return s + 2; //id not assigned, return orig. str.
|
||||
ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset
|
||||
if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character
|
||||
return s + 2;//zero length string == not translated, return orig. str.
|
||||
|
@ -211,16 +211,46 @@ const char* lang_get_name_by_code(uint16_t code)
|
|||
case LANG_CODE_FR: return _n("Francais");
|
||||
case LANG_CODE_IT: return _n("Italiano");
|
||||
case LANG_CODE_PL: return _n("Polski");
|
||||
#ifdef COMMUNITY_LANG_SUPPORT //Community language support
|
||||
#ifdef COMMUNITY_LANG_NL
|
||||
case LANG_CODE_NL: return _n("Nederlands"); //community contribution
|
||||
#endif // COMMUNITY_LANG_NL
|
||||
#ifdef COMMUNITY_LANGUAGE_SUPPORT //Community language support
|
||||
#ifdef COMMUNITY_LANG_GROUP1_NL
|
||||
case LANG_CODE_NL: return _n("Nederlands"); //community Dutch contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_NL
|
||||
#ifdef COMMUNITY_LANG_GROUP1_SV
|
||||
case LANG_CODE_SV: return _n("Svenska"); //community Swedish contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_SV
|
||||
#ifdef COMMUNITY_LANG_GROUP1_NO
|
||||
case LANG_CODE_NO: return _n("Norsk"); //community Swedish contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_NO
|
||||
#ifdef COMMUNITY_LANG_GROUP1_DA
|
||||
case LANG_CODE_DA: return _n("Dansk"); //community Danish contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_DA
|
||||
#ifdef COMMUNITY_LANG_GROUP1_SK
|
||||
case LANG_CODE_SK: return _n("Slovencina"); //community Slovak contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_SK
|
||||
#ifdef COMMUNITY_LANG_GROUP1_SL
|
||||
case LANG_CODE_SL: return _n("Slovenscina"); //community Slovanian contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_SL
|
||||
#ifdef COMMUNITY_LANG_GROUP1_HU
|
||||
case LANG_CODE_HU: return _n("Magyar"); //community Hungarian contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_HU
|
||||
#ifdef COMMUNITY_LANG_GROUP1_LB
|
||||
case LANG_CODE_LB: return _n("Letzebuergesch"); //community Luxembourgish contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_LB
|
||||
#ifdef COMMUNITY_LANG_GROUP1_HR
|
||||
case LANG_CODE_HR: return _n("Hrvatski"); //community Croatian contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_HR
|
||||
#ifdef COMMUNITY_LANG_GROUP1_LT
|
||||
case LANG_CODE_LT: return _n("Lietuviu"); //community Lithuanian contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_LT
|
||||
#ifdef COMMUNITY_LANG_GROUP1_RO
|
||||
case LANG_CODE_RO: return _n("Romana"); //community Romanian contribution
|
||||
#endif // COMMUNITY_LANG_GROUP1_RO
|
||||
|
||||
//Use the 3 lines below as a template and replace 'QR' and 'New language'
|
||||
//#ifdef COMMUNITY_LANG_QR
|
||||
//#ifdef COMMUNITY_LANG_GROUP1_QR
|
||||
// case LANG_CODE_QR: return _n("New language"); //community contribution
|
||||
//#endif // COMMUNITY_LANG_QR
|
||||
#endif // COMMUNITY_LANG_SUPPORT
|
||||
//#endif // COMMUNITY_LANG_GROUP1_QR
|
||||
#endif // COMMUNITY_LANGUAGE_SUPPORT
|
||||
}
|
||||
return _n("??");
|
||||
}
|
||||
|
@ -279,5 +309,5 @@ void lang_boot_update_start(uint8_t lang)
|
|||
{
|
||||
uint8_t cnt = lang_get_count();
|
||||
if ((lang < 2) || (lang > cnt)) return; //only languages from xflash can be selected
|
||||
bootapp_reboot_user0(lang << 4);
|
||||
bootapp_reboot_user0(lang << 3);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#define ISTR(s) s
|
||||
#define _i(s) _I(s)
|
||||
#define _T(s) s
|
||||
#define _O(s) s
|
||||
#else //(LANG_MODE == 0)
|
||||
// section .loc_sec (originaly .progmem0) will be used for localized translated strings
|
||||
#define PROGMEM_I2 __attribute__((section(".loc_sec")))
|
||||
|
@ -40,6 +41,7 @@
|
|||
#define ISTR(s) "\xff\xff" s
|
||||
#define _i(s) lang_get_translation(_I(s))
|
||||
#define _T(s) lang_get_translation(s)
|
||||
#define _O(s) (s + 2)
|
||||
#endif //(LANG_MODE == 0)
|
||||
#define _N(s) (__extension__({static const char __c[] PROGMEM_N1 = s; &__c[0];}))
|
||||
#define _n(s) _N(s)
|
||||
|
@ -94,15 +96,45 @@ typedef struct
|
|||
#define LANG_CODE_FR 0x6672 //!<'fr'
|
||||
#define LANG_CODE_IT 0x6974 //!<'it'
|
||||
#define LANG_CODE_PL 0x706c //!<'pl'
|
||||
#ifdef COMMUNITY_LANG_SUPPORT //Community language support
|
||||
#ifdef COMMUNITY_LANG_NL
|
||||
#ifdef COMMUNITY_LANGUAGE_SUPPORT //Community language support
|
||||
#ifdef COMMUNITY_LANG_GROUP1_NL
|
||||
#define LANG_CODE_NL 0x6e6c //!<'nl'
|
||||
#endif // COMMUNITY_LANG_NL
|
||||
#endif // COMMUNITY_LANG_GROUP1_NL
|
||||
#ifdef COMMUNITY_LANG_GROUP1_SV
|
||||
#define LANG_CODE_SV 0x7376 //!<'sv'
|
||||
#endif // COMMUNITY_LANG_GROUP1_SV
|
||||
#ifdef COMMUNITY_LANG_GROUP1_NO
|
||||
#define LANG_CODE_NO 0x6E6F //!<'no'
|
||||
#endif // COMMUNITY_LANG_GROUP1_NO
|
||||
#ifdef COMMUNITY_LANG_GROUP1_DA
|
||||
#define LANG_CODE_DA 0x6461 //!<'da'
|
||||
#endif // COMMUNITY_LANG_GROUP1_DA
|
||||
#ifdef COMMUNITY_LANG_GROUP1_SL
|
||||
#define LANG_CODE_SL 0x736C //!<'sl'
|
||||
#endif // COMMUNITY_LANG_GROUP1_SL
|
||||
#ifdef COMMUNITY_LANG_GROUP1_HU
|
||||
#define LANG_CODE_HU 0x6875 //!<'hu'
|
||||
#endif // COMMUNITY_LANG_GROUP1_HU
|
||||
#ifdef COMMUNITY_LANG_GROUP1_LB
|
||||
#define LANG_CODE_LB 0x6C62 //!<'lb'
|
||||
#endif // COMMUNITY_LANG_GROUP1_LB
|
||||
#ifdef COMMUNITY_LANG_GROUP1_HR
|
||||
#define LANG_CODE_HR 0x6872 //!<'hr'
|
||||
#endif // COMMUNITY_LANG_GROUP1_HR
|
||||
#ifdef COMMUNITY_LANG_GROUP1_LT
|
||||
#define LANG_CODE_LT 0x6C74 //!<'lt'
|
||||
#endif // COMMUNITY_LANG_GROUP1_LT
|
||||
#ifdef COMMUNITY_LANG_GROUP1_SK
|
||||
#define LANG_CODE_SK 0x736b //!<'sk'
|
||||
#endif // COMMUNITY_LANG_GROUP1_SK
|
||||
#ifdef COMMUNITY_LANG_GROUP1_RO
|
||||
#define LANG_CODE_RO 0x726F //!<'ro'
|
||||
#endif // COMMUNITY_LANG_GROUP1_RO
|
||||
//Use the 3 lines below as a template and replace 'QR', '0X7172' and 'qr'
|
||||
//#ifdef COMMUNITY_LANG_QR
|
||||
//#ifdef COMMUNITY_LANG_GROUP1_QR
|
||||
//#define LANG_CODE_QR 0x7172 //!<'qr'
|
||||
//#endif // COMMUNITY_LANG_QR
|
||||
#endif // COMMUNITY_LANG_SUPPORT
|
||||
//#endif // COMMUNITY_LANG_GROUP1_QR
|
||||
#endif // COMMUNITY_LANGUAGE_SUPPORT
|
||||
///@}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
@ -115,9 +147,7 @@ extern uint8_t lang_selected;
|
|||
#if (LANG_MODE != 0)
|
||||
extern const char _SEC_LANG[LANG_SIZE_RESERVED];
|
||||
extern const char* lang_get_translation(const char* s);
|
||||
/** @def _SEC_LANG_TABLE
|
||||
* @brief Align table to start of 256 byte page */
|
||||
#define _SEC_LANG_TABLE ((((uint16_t)&_SEC_LANG) + 0x00ff) & 0xff00)
|
||||
#define _SEC_LANG_TABLE ((uint16_t)&_SEC_LANG)
|
||||
#endif //(LANG_MODE != 0)
|
||||
|
||||
/** @brief selects language, eeprom is updated in case of success */
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "static_assert.h"
|
||||
#include "sound.h"
|
||||
|
||||
extern int32_t lcd_encoder;
|
||||
|
||||
#define MENU_DEPTH_MAX 7
|
||||
|
||||
static menu_record_t menu_stack[MENU_DEPTH_MAX];
|
||||
|
|
|
@ -993,7 +993,7 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
|
|||
// we have to let the planner know where we are right now as it is not where we said to go.
|
||||
update_current_position_z();
|
||||
//printf_P(PSTR("Zs: %f, Z: %f, delta Z: %f"), z_bckp, current_position[Z_AXIS], (z_bckp - current_position[Z_AXIS]));
|
||||
if (abs(current_position[Z_AXIS] - z_bckp) < 0.025) {
|
||||
if (fabs(current_position[Z_AXIS] - z_bckp) < 0.025) {
|
||||
//printf_P(PSTR("PINDA triggered immediately, move Z higher and repeat measurement\n"));
|
||||
current_position[Z_AXIS] += 0.5;
|
||||
go_to_current(homing_feedrate[Z_AXIS]/60);
|
||||
|
@ -1019,7 +1019,7 @@ bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
|
|||
// SERIAL_ECHOPGM("Bed find_bed_induction_sensor_point_z low, height: ");
|
||||
// MYSERIAL.print(current_position[Z_AXIS], 5);
|
||||
// SERIAL_ECHOLNPGM("");
|
||||
float dz = i?abs(current_position[Z_AXIS] - (z / i)):0;
|
||||
float dz = i?fabs(current_position[Z_AXIS] - (z / i)):0;
|
||||
z += current_position[Z_AXIS];
|
||||
//printf_P(PSTR("Z[%d] = %d, dz=%d\n"), i, (int)(current_position[Z_AXIS] * 1000), (int)(dz * 1000));
|
||||
//printf_P(PSTR("Z- measurement deviation from avg value %f um\n"), dz);
|
||||
|
|
|
@ -8,168 +8,170 @@
|
|||
#include "Configuration_prusa.h"
|
||||
|
||||
//internationalized messages
|
||||
const char MSG_AUTO_HOME[] PROGMEM_I1 = ISTR("Auto home"); ////c=18
|
||||
const char MSG_BABYSTEP_Z[] PROGMEM_I1 = ISTR("Live adjust Z"); ////c=18
|
||||
const char MSG_BABYSTEP_Z_NOT_SET[] PROGMEM_I1 = ISTR("Distance between tip of the nozzle and the bed surface has not been set yet. Please follow the manual, chapter First steps, section First layer calibration."); ////c=20 r=12
|
||||
const char MSG_BED[] PROGMEM_I1 = ISTR("Bed"); ////c=13
|
||||
const char MSG_BED_DONE[] PROGMEM_I1 = ISTR("Bed done"); ////c=20
|
||||
const char MSG_BED_HEATING[] PROGMEM_I1 = ISTR("Bed Heating"); ////c=20
|
||||
const char MSG_BED_LEVELING_FAILED_POINT_LOW[] PROGMEM_I1 = ISTR("Bed leveling failed. Sensor didn't trigger. Debris on nozzle? Waiting for reset."); ////c=20 r=6
|
||||
const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED[] PROGMEM_I1 = ISTR("XYZ calibration failed. Please consult the manual."); ////c=20 r=8
|
||||
const char MSG_BELT_STATUS[] PROGMEM_I1 = ISTR("Belt status");////c=18
|
||||
const char MSG_CANCEL[] PROGMEM_I1 = ISTR(">Cancel");////c=9
|
||||
const char MSG_CALIBRATE_Z_AUTO[] PROGMEM_I1 = ISTR("Calibrating Z"); ////c=20 r=2
|
||||
const char MSG_CARD_MENU[] PROGMEM_I1 = ISTR("Print from SD"); ////c=18
|
||||
const char MSG_CHECKING_X[] PROGMEM_I1 = ISTR("Checking X axis"); ////c=20
|
||||
const char MSG_CHECKING_Y[] PROGMEM_I1 = ISTR("Checking Y axis"); ////c=20
|
||||
const char MSG_COMMUNITY_MADE[] PROGMEM_I1 = ISTR("Community made"); ////c=18
|
||||
const char MSG_CONFIRM_NOZZLE_CLEAN[] PROGMEM_I1 = ISTR("Please clean the nozzle for calibration. Click when done."); ////c=20 r=8
|
||||
const char MSG_COOLDOWN[] PROGMEM_I1 = ISTR("Cooldown"); ////c=18
|
||||
const char MSG_CRASH[] PROGMEM_I1 = ISTR("Crash"); ////c=7
|
||||
const char MSG_CRASH_DETECTED[] PROGMEM_I1 = ISTR("Crash detected."); ////c=20
|
||||
const char MSG_CRASHDETECT[] PROGMEM_I1 = ISTR("Crash det."); ////c=13
|
||||
const char MSG_ERROR[] PROGMEM_I1 = ISTR("ERROR:"); ////c=10
|
||||
const char MSG_EXTRUDER[] PROGMEM_I1 = ISTR("Extruder"); ////c=17
|
||||
const char MSG_FANS_CHECK[] PROGMEM_I1 = ISTR("Fans check"); ////c=13
|
||||
const char MSG_FIL_RUNOUTS[] PROGMEM_I1 = ISTR("Fil. runouts"); ////c=15
|
||||
const char MSG_FILAMENT[] PROGMEM_I1 = ISTR("Filament"); ////c=17
|
||||
const char MSG_FAN_SPEED[] PROGMEM_I1 = ISTR("Fan speed"); ////c=14
|
||||
const char MSG_FILAMENT_CLEAN[] PROGMEM_I1 = ISTR("Filament extruding & with correct color?"); ////c=20 r=2
|
||||
const char MSG_FILAMENT_LOADED[] PROGMEM_I1 = ISTR("Is filament loaded?"); ////c=20 r=2
|
||||
const char MSG_FILAMENT_LOADING_T0[] PROGMEM_I1 = ISTR("Insert filament into extruder 1. Click when done."); ////c=20 r=4
|
||||
const char MSG_FILAMENT_LOADING_T1[] PROGMEM_I1 = ISTR("Insert filament into extruder 2. Click when done."); ////c=20 r=4
|
||||
const char MSG_FILAMENT_LOADING_T2[] PROGMEM_I1 = ISTR("Insert filament into extruder 3. Click when done."); ////c=20 r=4
|
||||
const char MSG_FILAMENT_LOADING_T3[] PROGMEM_I1 = ISTR("Insert filament into extruder 4. Click when done."); ////c=20 r=4
|
||||
const char MSG_FILAMENTCHANGE[] PROGMEM_I1 = ISTR("Change filament"); ////c=18
|
||||
const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1[] PROGMEM_I1 = ISTR("Searching bed calibration point"); ////c=20 r=3
|
||||
const char MSG_FINISHING_MOVEMENTS[] PROGMEM_I1 = ISTR("Finishing movements"); ////c=20
|
||||
const char MSG_FOLLOW_CALIBRATION_FLOW[] PROGMEM_I1 = ISTR("Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow."); ////c=20 r=8
|
||||
const char MSG_FOLLOW_Z_CALIBRATION_FLOW[] PROGMEM_I1 = ISTR("There is still a need to make Z calibration. Please follow the manual, chapter First steps, section Calibration flow."); ////c=20 r=9
|
||||
const char MSG_FSENSOR_AUTOLOAD[] PROGMEM_I1 = ISTR("F. autoload"); ////c=13
|
||||
const char MSG_FSENSOR[] PROGMEM_I1 = ISTR("Fil. sensor"); ////c=12
|
||||
const char MSG_HEATING[] PROGMEM_I1 = ISTR("Heating"); ////c=20
|
||||
const char MSG_HEATING_COMPLETE[] PROGMEM_I1 = ISTR("Heating done."); ////c=20
|
||||
const char MSG_HOMEYZ[] PROGMEM_I1 = ISTR("Calibrate Z"); ////c=18
|
||||
const char MSG_ITERATION[] PROGMEM_I1 = ISTR("Iteration"); ////c=12
|
||||
const char MSG_CHOOSE_EXTRUDER[] PROGMEM_I1 = ISTR("Choose extruder:"); ////c=20
|
||||
const char MSG_CHOOSE_FILAMENT[] PROGMEM_I1 = ISTR("Choose filament:"); ////c=20
|
||||
const char MSG_LAST_PRINT[] PROGMEM_I1 = ISTR("Last print"); ////c=18
|
||||
const char MSG_LAST_PRINT_FAILURES[] PROGMEM_I1 = ISTR("Last print failures"); ////c=20
|
||||
const char MSG_LOAD_FILAMENT[] PROGMEM_I1 = ISTR("Load filament"); //// Number 1 to 5 is added behind text e.g. "Load filament 1" c=16
|
||||
const char MSG_LOADING_FILAMENT[] PROGMEM_I1 = ISTR("Loading filament"); ////c=20
|
||||
const char MSG_EJECT_FILAMENT[] PROGMEM_I1 = ISTR("Eject filament"); //// Number 1 to 5 is added behind text e.g. "Eject filament 1" c=16
|
||||
const char MSG_CUT_FILAMENT[] PROGMEM_I1 = ISTR("Cut filament"); //// Number 1 to 5 is added behind text e.g. "Cut filament 1" c=16
|
||||
const char MSG_M117_V2_CALIBRATION[] PROGMEM_I1 = ISTR("M117 First layer cal."); ////c=25
|
||||
const char MSG_MAIN[] PROGMEM_I1 = ISTR("Main"); ////c=18
|
||||
const char MSG_BACK[] PROGMEM_I1 = ISTR("Back"); ////c=18
|
||||
const char MSG_SHEET[] PROGMEM_I1 = ISTR("Sheet"); ////c=10
|
||||
const char MSG_STEEL_SHEETS[] PROGMEM_I1 = ISTR("Steel sheets"); ////c=18
|
||||
const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1[] PROGMEM_I1 = ISTR("Measuring reference height of calibration point"); ////c=20 r=3
|
||||
const char MSG_MENU_CALIBRATION[] PROGMEM_I1 = ISTR("Calibration"); ////c=18
|
||||
const char MSG_MMU_FAILS[] PROGMEM_I1 = ISTR("MMU fails"); ////c=15
|
||||
const char MSG_MMU_LOAD_FAILS[] PROGMEM_I1 = ISTR("MMU load fails"); ////c=15
|
||||
const char MSG_NO[] PROGMEM_I1 = ISTR("No"); ////c=4
|
||||
const char MSG_NOZZLE[] PROGMEM_I1 = ISTR("Nozzle"); ////c=12
|
||||
const char MSG_PAPER[] PROGMEM_I1 = ISTR("Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately."); ////c=20 r=10
|
||||
const char MSG_PAUSE_PRINT[] PROGMEM_I1 = ISTR("Pause print");////c=18
|
||||
const char MSG_PLACE_STEEL_SHEET[] PROGMEM_I1 = ISTR("Please place steel sheet on heatbed."); ////c=20 r=5
|
||||
const char MSG_PLEASE_WAIT[] PROGMEM_I1 = ISTR("Please wait"); ////c=20
|
||||
const char MSG_POWER_FAILURES[] PROGMEM_I1 = ISTR("Power failures"); ////c=15
|
||||
const char MSG_PREHEAT_NOZZLE[] PROGMEM_I1 = ISTR("Preheat the nozzle!"); ////c=20
|
||||
const char MSG_PRESS_TO_UNLOAD[] PROGMEM_I1 = ISTR("Please press the knob to unload filament"); ////c=20 r=4
|
||||
const char MSG_PRINT_ABORTED[] PROGMEM_I1 = ISTR("Print aborted"); ////c=20
|
||||
const char MSG_PULL_OUT_FILAMENT[] PROGMEM_I1 = ISTR("Please pull out filament immediately"); ////c=20 r=4
|
||||
const char MSG_RECOVER_PRINT[] PROGMEM_I1 = ISTR("Blackout occurred. Recover print?"); ////c=20 r=2
|
||||
const char MSG_REFRESH[] PROGMEM_I1 = ISTR("\x04Refresh"); ////c=18
|
||||
const char MSG_REMOVE_STEEL_SHEET[] PROGMEM_I1 = ISTR("Please remove steel sheet from heatbed."); ////c=20 r=4
|
||||
const char MSG_RESET[] PROGMEM_I1 = ISTR("Reset"); ////c=14
|
||||
const char MSG_RESUME_PRINT[] PROGMEM_I1 = ISTR("Resume print"); ////c=18
|
||||
const char MSG_RESUMING_PRINT[] PROGMEM_I1 = ISTR("Resuming print"); ////c=20
|
||||
const char MSG_SELFTEST_COOLING_FAN[] PROGMEM_I1 = ISTR("Front print fan?"); ////c=20
|
||||
const char MSG_SELFTEST_EXTRUDER_FAN[] PROGMEM_I1 = ISTR("Left hotend fan?"); ////c=20
|
||||
const char MSG_SELFTEST_FAILED[] PROGMEM_I1 = ISTR("Selftest failed"); ////c=20
|
||||
const char MSG_SELFTEST_FAN[] PROGMEM_I1 = ISTR("Fan test"); ////c=20
|
||||
const char MSG_SELFTEST_FAN_NO[] PROGMEM_I1 = ISTR("Not spinning"); ////c=19
|
||||
const char MSG_SELFTEST_FAN_YES[] PROGMEM_I1 = ISTR("Spinning"); ////c=19
|
||||
const char MSG_SELFTEST_CHECK_BED[] PROGMEM_I1 = ISTR("Checking bed"); ////c=20
|
||||
const char MSG_SELFTEST_CHECK_FSENSOR[] PROGMEM_I1 = ISTR("Checking sensors"); ////c=20
|
||||
const char MSG_SELFTEST_MOTOR[] PROGMEM_I1 = ISTR("Motor"); ////c=18
|
||||
const char MSG_SELFTEST_FILAMENT_SENSOR[] PROGMEM_I1 = ISTR("Filament sensor"); ////c=17
|
||||
const char MSG_SELFTEST_WIRINGERROR[] PROGMEM_I1 = ISTR("Wiring error"); ////c=18
|
||||
const char MSG_SETTINGS[] PROGMEM_I1 = ISTR("Settings"); ////c=18
|
||||
const char MSG_TOTAL[] PROGMEM_I1 = ISTR("Total"); ////c=6
|
||||
const char MSG_TOTAL_FAILURES[] PROGMEM_I1 = ISTR("Total failures"); ////c=20
|
||||
const char MSG_HW_SETUP[] PROGMEM_I1 = ISTR("HW Setup"); ////c=18
|
||||
const char MSG_MODE[] PROGMEM_I1 = ISTR("Mode"); ////c=6
|
||||
const char MSG_HIGH_POWER[] PROGMEM_I1 = ISTR("High power"); ////c=10
|
||||
const char MSG_AUTO_POWER[] PROGMEM_I1 = ISTR("Auto power"); ////c=10
|
||||
const char MSG_SILENT[] PROGMEM_I1 = ISTR("Silent"); ////c=7
|
||||
const char MSG_NORMAL[] PROGMEM_I1 = ISTR("Normal"); ////c=7
|
||||
const char MSG_STEALTH[] PROGMEM_I1 = ISTR("Stealth"); ////c=7
|
||||
const char MSG_STEEL_SHEET_CHECK[] PROGMEM_I1 = ISTR("Is steel sheet on heatbed?"); ////c=20 r=2
|
||||
const char MSG_STOP_PRINT[] PROGMEM_I1 = ISTR("Stop print"); ////c=18
|
||||
const char MSG_STOPPED[] PROGMEM_I1 = ISTR("STOPPED."); ////c=20
|
||||
const char MSG_TEMP_CALIBRATION[] PROGMEM_I1 = ISTR("Temp. cal."); ////c=14
|
||||
const char MSG_TEMP_CALIBRATION_DONE[] PROGMEM_I1 = ISTR("Temperature calibration is finished and active. Temp. calibration can be disabled in menu Settings->Temp. cal."); ////c=20 r=12
|
||||
const char MSG_UNLOAD_FILAMENT[] PROGMEM_I1 = ISTR("Unload filament"); ////Number 1 to 5 is added behind text e.g. "Unload filament" c=16
|
||||
const char MSG_UNLOADING_FILAMENT[] PROGMEM_I1 = ISTR("Unloading filament"); ////c=20
|
||||
const char MSG_WATCH[] PROGMEM_I1 = ISTR("Info screen"); ////c=18
|
||||
const char MSG_WIZARD_CALIBRATION_FAILED[] PROGMEM_I1 = ISTR("Please check our handbook and fix the problem. Then resume the Wizard by rebooting the printer."); ////c=20 r=8
|
||||
const char MSG_WIZARD_DONE[] PROGMEM_I1 = ISTR("All is done. Happy printing!"); ////c=20 r=8
|
||||
const char MSG_WIZARD_HEATING[] PROGMEM_I1 = ISTR("Preheating nozzle. Please wait."); ////c=20 r=3
|
||||
const char MSG_WIZARD_QUIT[] PROGMEM_I1 = ISTR("You can always resume the Wizard from Calibration -> Wizard."); ////c=20 r=8
|
||||
const char MSG_WIZARD_WELCOME[] PROGMEM_I1 = ISTR("Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?"); //// c=20 r=7
|
||||
const char MSG_WIZARD_WELCOME_SHIPPING[] PROGMEM_I1 = ISTR("Hi, I am your Original Prusa i3 printer. I will guide you through a short setup process, in which the Z-axis will be calibrated. Then, you will be ready to print."); ////c=20 r=16
|
||||
const char MSG_YES[] PROGMEM_I1 = ISTR("Yes"); ////c=3
|
||||
const char MSG_V2_CALIBRATION[] PROGMEM_I1 = ISTR("First layer cal."); ////c=18
|
||||
const char MSG_OFF[] PROGMEM_I1 = ISTR("Off"); ////c=3
|
||||
const char MSG_ON[] PROGMEM_I1 = ISTR("On"); ////c=3
|
||||
const char MSG_NA[] PROGMEM_I1 = ISTR("N/A"); ////c=3
|
||||
const char MSG_CUTTER[] PROGMEM_I1 = ISTR("Cutter"); ////c=9
|
||||
const char MSG_NONE[] PROGMEM_I1 = ISTR("None"); ////c=8
|
||||
const char MSG_WARN[] PROGMEM_I1 = ISTR("Warn"); ////c=8
|
||||
const char MSG_STRICT[] PROGMEM_I1 = ISTR("Strict"); ////c=8
|
||||
const char MSG_MODEL[] PROGMEM_I1 = ISTR("Model"); ////c=8
|
||||
const char MSG_GCODE[] PROGMEM_I1 = ISTR("Gcode"); ////c=8
|
||||
const char MSG_GCODE_DIFF_PRINTER_CONTINUE[] PROGMEM_I1 = ISTR("G-code sliced for a different printer type. Continue?"); ////c=20 r=5
|
||||
const char MSG_GCODE_DIFF_PRINTER_CANCELLED[] PROGMEM_I1 =ISTR("G-code sliced for a different printer type. Please re-slice the model again. Print cancelled."); ////c=20 r=8
|
||||
const char MSG_NOZZLE_DIAMETER[] PROGMEM_I1 = ISTR("Nozzle d."); ////c=10
|
||||
const char MSG_MMU_MODE[] PROGMEM_I1 = ISTR("MMU Mode"); ////c=8
|
||||
const char MSG_SD_CARD[] PROGMEM_I1 = ISTR("SD card"); ////c=8
|
||||
const char MSG_SORT[] PROGMEM_I1 = ISTR("Sort"); ////c=7
|
||||
const char MSG_SORT_TIME[] PROGMEM_I1 = ISTR("Time"); ////c=8
|
||||
const char MSG_SORT_ALPHA[] PROGMEM_I1 = ISTR("Alphabet"); ////c=8
|
||||
const char MSG_RPI_PORT[] PROGMEM_I1 = ISTR("RPi port"); ////c=13
|
||||
const char MSG_SOUND[] PROGMEM_I1 = ISTR("Sound"); ////c=9
|
||||
const char MSG_SOUND_LOUD[] PROGMEM_I1 = ISTR("Loud"); ////c=7
|
||||
const char MSG_SOUND_ONCE[] PROGMEM_I1 = ISTR("Once"); ////c=7
|
||||
const char MSG_SOUND_BLIND[] PROGMEM_I1 = ISTR("Assist"); ////c=7
|
||||
const char MSG_MESH[] PROGMEM_I1 = ISTR("Mesh"); ////c=12
|
||||
const char MSG_MESH_BED_LEVELING[] PROGMEM_I1 = ISTR("Mesh Bed Leveling"); ////c=18
|
||||
const char MSG_Z_PROBE_NR[] PROGMEM_I1 = ISTR("Z-probe nr."); ////c=14
|
||||
const char MSG_MAGNETS_COMP[] PROGMEM_I1 = ISTR("Magnets comp."); ////c=13
|
||||
const char MSG_FS_ACTION[] PROGMEM_I1 = ISTR("FS Action"); ////c=10
|
||||
const char MSG_FS_CONTINUE[] PROGMEM_I1 = ISTR("Cont."); ////c=5
|
||||
const char MSG_FS_PAUSE[] PROGMEM_I1 = ISTR("Pause"); ////c=5
|
||||
const char MSG_BRIGHTNESS[] PROGMEM_I1 = ISTR("Brightness"); ////c=18
|
||||
const char MSG_BL_HIGH[] PROGMEM_I1 = ISTR("Level Bright"); ////c=12
|
||||
const char MSG_BL_LOW[] PROGMEM_I1 = ISTR("Level Dimmed"); ////c=12
|
||||
const char MSG_TIMEOUT[] PROGMEM_I1 = ISTR("Timeout"); ////c=12
|
||||
const char MSG_BRIGHT[] PROGMEM_I1 = ISTR("Bright"); ////c=6
|
||||
const char MSG_DIM[] PROGMEM_I1 = ISTR("Dim"); ////c=6
|
||||
const char MSG_AUTO[] PROGMEM_I1 = ISTR("Auto"); ////c=6
|
||||
const char MSG_AUTO_HOME[] PROGMEM_I1 = ISTR("Auto home"); ////MSG_AUTO_HOME c=18
|
||||
const char MSG_BABYSTEP_Z[] PROGMEM_I1 = ISTR("Live adjust Z"); ////MSG_BABYSTEP_Z c=18
|
||||
const char MSG_BABYSTEP_Z_NOT_SET[] PROGMEM_I1 = ISTR("Distance between tip of the nozzle and the bed surface has not been set yet. Please follow the manual, chapter First steps, section First layer calibration."); ////MSG_BABYSTEP_Z_NOT_SET c=20 r=12
|
||||
const char MSG_BED[] PROGMEM_I1 = ISTR("Bed"); ////MSG_BED c=13
|
||||
const char MSG_BED_DONE[] PROGMEM_I1 = ISTR("Bed done"); ////MSG_BED_DONE c=20
|
||||
const char MSG_BED_HEATING[] PROGMEM_I1 = ISTR("Bed Heating"); ////MSG_BED_HEATING c=20
|
||||
const char MSG_BED_LEVELING_FAILED_POINT_LOW[] PROGMEM_I1 = ISTR("Bed leveling failed. Sensor didn't trigger. Debris on nozzle? Waiting for reset."); ////MSG_BED_LEVELING_FAILED_POINT_LOW c=20 r=6
|
||||
const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED[] PROGMEM_I1 = ISTR("XYZ calibration failed. Please consult the manual."); ////MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED c=20 r=8
|
||||
const char MSG_BELT_STATUS[] PROGMEM_I1 = ISTR("Belt status");////MSG_BELT_STATUS c=18
|
||||
const char MSG_CANCEL[] PROGMEM_I1 = ISTR(">Cancel");////MSG_CANCEL c=9
|
||||
const char MSG_CALIBRATE_Z_AUTO[] PROGMEM_I1 = ISTR("Calibrating Z"); ////MSG_CALIBRATE_Z_AUTO c=20 r=2
|
||||
const char MSG_CARD_MENU[] PROGMEM_I1 = ISTR("Print from SD"); ////MSG_CARD_MENU c=18
|
||||
const char MSG_CHECKING_X[] PROGMEM_I1 = ISTR("Checking X axis"); ////MSG_CHECKING_X c=20
|
||||
const char MSG_CHECKING_Y[] PROGMEM_I1 = ISTR("Checking Y axis"); ////MSG_CHECKING_Y c=20
|
||||
const char MSG_COMMUNITY_MADE[] PROGMEM_I1 = ISTR("Community made"); ////MSG_COMMUNITY_MADE c=18
|
||||
const char MSG_CONFIRM_NOZZLE_CLEAN[] PROGMEM_I1 = ISTR("Please clean the nozzle for calibration. Click when done."); ////MSG_CONFIRM_NOZZLE_CLEAN c=20 r=8
|
||||
const char MSG_COOLDOWN[] PROGMEM_I1 = ISTR("Cooldown"); ////MSG_COOLDOWN c=18
|
||||
const char MSG_CRASH[] PROGMEM_I1 = ISTR("Crash"); ////MSG_CRASH c=7
|
||||
const char MSG_CRASH_DETECTED[] PROGMEM_I1 = ISTR("Crash detected."); ////MSG_CRASH_DETECTED c=20
|
||||
const char MSG_CRASHDETECT[] PROGMEM_I1 = ISTR("Crash det."); ////MSG_CRASHDETECT c=13
|
||||
const char MSG_ERROR[] PROGMEM_I1 = ISTR("ERROR:"); ////MSG_ERROR c=10
|
||||
const char MSG_EXTRUDER[] PROGMEM_I1 = ISTR("Extruder"); ////MSG_EXTRUDER c=17
|
||||
const char MSG_FANS_CHECK[] PROGMEM_I1 = ISTR("Fans check"); ////MSG_FANS_CHECK c=13
|
||||
const char MSG_FIL_RUNOUTS[] PROGMEM_I1 = ISTR("Fil. runouts"); ////MSG_FIL_RUNOUTS c=15
|
||||
const char MSG_FILAMENT[] PROGMEM_I1 = ISTR("Filament"); ////MSG_FILAMENT c=17
|
||||
const char MSG_FAN_SPEED[] PROGMEM_I1 = ISTR("Fan speed"); ////MSG_FAN_SPEED c=14
|
||||
const char MSG_EXTRUDER_FAN_SPEED[] PROGMEM_I1 = ISTR("Extruder fan:");////MSG_EXTRUDER_FAN_SPEED c=16
|
||||
const char MSG_PRINT_FAN_SPEED[] PROGMEM_I1 = ISTR("Print fan:"); ////MSG_PRINT_FAN_SPEED c=16
|
||||
const char MSG_FILAMENT_CLEAN[] PROGMEM_I1 = ISTR("Filament extruding & with correct color?"); ////MSG_FILAMENT_CLEAN c=20 r=2
|
||||
const char MSG_FILAMENT_LOADED[] PROGMEM_I1 = ISTR("Is filament loaded?"); ////MSG_FILAMENT_LOADED c=20 r=2
|
||||
const char MSG_FILAMENT_LOADING_T0[] PROGMEM_I1 = ISTR("Insert filament into extruder 1. Click when done."); ////MSG_FILAMENT_LOADING_T0 c=20 r=4
|
||||
const char MSG_FILAMENT_LOADING_T1[] PROGMEM_I1 = ISTR("Insert filament into extruder 2. Click when done."); ////MSG_FILAMENT_LOADING_T1 c=20 r=4
|
||||
const char MSG_FILAMENT_LOADING_T2[] PROGMEM_I1 = ISTR("Insert filament into extruder 3. Click when done."); ////MSG_FILAMENT_LOADING_T2 c=20 r=4
|
||||
const char MSG_FILAMENT_LOADING_T3[] PROGMEM_I1 = ISTR("Insert filament into extruder 4. Click when done."); ////MSG_FILAMENT_LOADING_T3 c=20 r=4
|
||||
const char MSG_FILAMENTCHANGE[] PROGMEM_I1 = ISTR("Change filament"); ////MSG_FILAMENTCHANGE c=18
|
||||
const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1[] PROGMEM_I1 = ISTR("Searching bed calibration point"); ////MSG_FIND_BED_OFFSET_AND_SKEW_LINE1 c=20 r=3
|
||||
const char MSG_FINISHING_MOVEMENTS[] PROGMEM_I1 = ISTR("Finishing movements"); ////MSG_FINISHING_MOVEMENTS c=20
|
||||
const char MSG_FOLLOW_CALIBRATION_FLOW[] PROGMEM_I1 = ISTR("Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow."); ////MSG_FOLLOW_CALIBRATION_FLOW c=20 r=8
|
||||
const char MSG_FOLLOW_Z_CALIBRATION_FLOW[] PROGMEM_I1 = ISTR("There is still a need to make Z calibration. Please follow the manual, chapter First steps, section Calibration flow."); ////MSG_FOLLOW_Z_CALIBRATION_FLOW c=20 r=9
|
||||
const char MSG_FSENSOR_AUTOLOAD[] PROGMEM_I1 = ISTR("F. autoload"); ////MSG_FSENSOR_AUTOLOAD c=13
|
||||
const char MSG_FSENSOR[] PROGMEM_I1 = ISTR("Fil. sensor"); ////MSG_FSENSOR c=12
|
||||
const char MSG_HEATING[] PROGMEM_I1 = ISTR("Heating"); ////MSG_HEATING c=20
|
||||
const char MSG_HEATING_COMPLETE[] PROGMEM_I1 = ISTR("Heating done."); ////MSG_HEATING_COMPLETE c=20
|
||||
const char MSG_HOMEYZ[] PROGMEM_I1 = ISTR("Calibrate Z"); ////MSG_HOMEYZ c=18
|
||||
const char MSG_ITERATION[] PROGMEM_I1 = ISTR("Iteration"); ////MSG_ITERATION c=12
|
||||
const char MSG_SELECT_EXTRUDER[] PROGMEM_I1 = ISTR("Select extruder:"); ////MSG_SELECT_EXTRUDER c=20
|
||||
const char MSG_SELECT_FILAMENT[] PROGMEM_I1 = ISTR("Select filament:"); ////MSG_SELECT_FILAMENT c=20
|
||||
const char MSG_LAST_PRINT[] PROGMEM_I1 = ISTR("Last print"); ////MSG_LAST_PRINT c=18
|
||||
const char MSG_LAST_PRINT_FAILURES[] PROGMEM_I1 = ISTR("Last print failures"); ////MSG_LAST_PRINT_FAILURES c=20
|
||||
const char MSG_LOAD_FILAMENT[] PROGMEM_I1 = ISTR("Load filament"); ////MSG_LOAD_FILAMENT c=17
|
||||
const char MSG_LOADING_FILAMENT[] PROGMEM_I1 = ISTR("Loading filament"); ////MSG_LOADING_FILAMENT c=20
|
||||
const char MSG_EJECT_FILAMENT[] PROGMEM_I1 = ISTR("Eject filament"); ////MSG_EJECT_FILAMENT c=17
|
||||
const char MSG_CUT_FILAMENT[] PROGMEM_I1 = ISTR("Cut filament"); ////MSG_CUT_FILAMENT c=17
|
||||
const char MSG_M117_V2_CALIBRATION[] PROGMEM_I1 = ISTR("M117 First layer cal."); ////MSG_M117_V2_CALIBRATION c=25
|
||||
const char MSG_MAIN[] PROGMEM_I1 = ISTR("Main"); ////MSG_MAIN c=18
|
||||
const char MSG_BACK[] PROGMEM_I1 = ISTR("Back"); ////MSG_BACK c=18
|
||||
const char MSG_SHEET[] PROGMEM_I1 = ISTR("Sheet"); ////MSG_SHEET c=10
|
||||
const char MSG_STEEL_SHEETS[] PROGMEM_I1 = ISTR("Steel sheets"); ////MSG_STEEL_SHEETS c=18
|
||||
const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1[] PROGMEM_I1 = ISTR("Measuring reference height of calibration point"); ////MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1 c=20 r=3
|
||||
const char MSG_CALIBRATION[] PROGMEM_I1 = ISTR("Calibration"); ////MSG_CALIBRATION c=18
|
||||
const char MSG_MMU_FAILS[] PROGMEM_I1 = ISTR("MMU fails"); ////MSG_MMU_FAILS c=15
|
||||
const char MSG_MMU_LOAD_FAILS[] PROGMEM_I1 = ISTR("MMU load fails"); ////MSG_MMU_LOAD_FAILS c=15
|
||||
const char MSG_NO[] PROGMEM_I1 = ISTR("No"); ////MSG_NO c=4
|
||||
const char MSG_NOZZLE[] PROGMEM_I1 = ISTR("Nozzle"); ////MSG_NOZZLE c=10
|
||||
const char MSG_PAPER[] PROGMEM_I1 = ISTR("Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately."); ////MSG_PAPER c=20 r=10
|
||||
const char MSG_PAUSE_PRINT[] PROGMEM_I1 = ISTR("Pause print");////MSG_PAUSE_PRINT c=18
|
||||
const char MSG_PLACE_STEEL_SHEET[] PROGMEM_I1 = ISTR("Please place steel sheet on heatbed."); ////MSG_PLACE_STEEL_SHEET c=20 r=5
|
||||
const char MSG_PLEASE_WAIT[] PROGMEM_I1 = ISTR("Please wait"); ////MSG_PLEASE_WAIT c=20
|
||||
const char MSG_POWER_FAILURES[] PROGMEM_I1 = ISTR("Power failures"); ////MSG_POWER_FAILURES c=15
|
||||
const char MSG_PREHEAT_NOZZLE[] PROGMEM_I1 = ISTR("Preheat the nozzle!"); ////MSG_PREHEAT_NOZZLE c=20
|
||||
const char MSG_PRESS_TO_UNLOAD[] PROGMEM_I1 = ISTR("Please press the knob to unload filament"); ////MSG_PRESS_TO_UNLOAD c=20 r=4
|
||||
const char MSG_PRINT_ABORTED[] PROGMEM_I1 = ISTR("Print aborted"); ////MSG_PRINT_ABORTED c=20
|
||||
const char MSG_PULL_OUT_FILAMENT[] PROGMEM_I1 = ISTR("Please pull out filament immediately"); ////MSG_PULL_OUT_FILAMENT c=20 r=4
|
||||
const char MSG_RECOVER_PRINT[] PROGMEM_I1 = ISTR("Blackout occurred. Recover print?"); ////MSG_RECOVER_PRINT c=20 r=2
|
||||
const char MSG_REFRESH[] PROGMEM_I1 = ISTR("\x04Refresh"); ////MSG_REFRESH c=18
|
||||
const char MSG_REMOVE_STEEL_SHEET[] PROGMEM_I1 = ISTR("Please remove steel sheet from heatbed."); ////MSG_REMOVE_STEEL_SHEET c=20 r=4
|
||||
const char MSG_RESET[] PROGMEM_I1 = ISTR("Reset"); ////MSG_RESET c=14
|
||||
const char MSG_RESUME_PRINT[] PROGMEM_I1 = ISTR("Resume print"); ////MSG_RESUME_PRINT c=18
|
||||
const char MSG_RESUMING_PRINT[] PROGMEM_I1 = ISTR("Resuming print"); ////MSG_RESUMING_PRINT c=20
|
||||
const char MSG_SELFTEST_PART_FAN[] PROGMEM_I1 = ISTR("Front print fan?"); ////MSG_SELFTEST_PART_FAN c=20
|
||||
const char MSG_SELFTEST_EXTRUDER_FAN[] PROGMEM_I1 = ISTR("Left hotend fan?"); ////MSG_SELFTEST_EXTRUDER_FAN c=20
|
||||
const char MSG_SELFTEST_FAILED[] PROGMEM_I1 = ISTR("Selftest failed"); ////MSG_SELFTEST_FAILED c=20
|
||||
const char MSG_SELFTEST_FAN[] PROGMEM_I1 = ISTR("Fan test"); ////MSG_SELFTEST_FAN c=20
|
||||
const char MSG_SELFTEST_FAN_NO[] PROGMEM_I1 = ISTR("Not spinning"); ////MSG_SELFTEST_FAN_NO c=19
|
||||
const char MSG_SELFTEST_FAN_YES[] PROGMEM_I1 = ISTR("Spinning"); ////MSG_SELFTEST_FAN_YES c=19
|
||||
const char MSG_SELFTEST_CHECK_BED[] PROGMEM_I1 = ISTR("Checking bed"); ////MSG_SELFTEST_CHECK_BED c=20
|
||||
const char MSG_SELFTEST_CHECK_FSENSOR[] PROGMEM_I1 = ISTR("Checking sensors"); ////MSG_SELFTEST_CHECK_FSENSOR c=20
|
||||
const char MSG_SELFTEST_MOTOR[] PROGMEM_I1 = ISTR("Motor"); ////MSG_SELFTEST_MOTOR c=18
|
||||
const char MSG_SELFTEST_FILAMENT_SENSOR[] PROGMEM_I1 = ISTR("Filament sensor"); ////MSG_SELFTEST_FILAMENT_SENSOR c=17
|
||||
const char MSG_SELFTEST_WIRINGERROR[] PROGMEM_I1 = ISTR("Wiring error"); ////MSG_SELFTEST_WIRINGERROR c=18
|
||||
const char MSG_SETTINGS[] PROGMEM_I1 = ISTR("Settings"); ////MSG_SETTINGS c=18
|
||||
const char MSG_TOTAL[] PROGMEM_I1 = ISTR("Total"); ////MSG_TOTAL c=6
|
||||
const char MSG_TOTAL_FAILURES[] PROGMEM_I1 = ISTR("Total failures"); ////MSG_TOTAL_FAILURES c=20
|
||||
const char MSG_HW_SETUP[] PROGMEM_I1 = ISTR("HW Setup"); ////MSG_HW_SETUP c=18
|
||||
const char MSG_MODE[] PROGMEM_I1 = ISTR("Mode"); ////MSG_MODE c=6
|
||||
const char MSG_HIGH_POWER[] PROGMEM_I1 = ISTR("High power"); ////MSG_HIGH_POWER c=10
|
||||
const char MSG_AUTO_POWER[] PROGMEM_I1 = ISTR("Auto power"); ////MSG_AUTO_POWER c=10
|
||||
const char MSG_SILENT[] PROGMEM_I1 = ISTR("Silent"); ////MSG_SILENT c=7
|
||||
const char MSG_NORMAL[] PROGMEM_I1 = ISTR("Normal"); ////MSG_NORMAL c=7
|
||||
const char MSG_STEALTH[] PROGMEM_I1 = ISTR("Stealth"); ////MSG_STEALTH c=7
|
||||
const char MSG_STEEL_SHEET_CHECK[] PROGMEM_I1 = ISTR("Is steel sheet on heatbed?"); ////MSG_STEEL_SHEET_CHECK c=20 r=2
|
||||
const char MSG_STOP_PRINT[] PROGMEM_I1 = ISTR("Stop print"); ////MSG_STOP_PRINT c=18
|
||||
const char MSG_STOPPED[] PROGMEM_I1 = ISTR("STOPPED."); ////MSG_STOPPED c=20
|
||||
const char MSG_PINDA_CALIBRATION[] PROGMEM_I1 = ISTR("PINDA cal."); ////MSG_PINDA_CALIBRATION c=13
|
||||
const char MSG_PINDA_CALIBRATION_DONE[] PROGMEM_I1 = ISTR("PINDA calibration is finished and active. It can be disabled in menu Settings->PINDA cal."); ////MSG_PINDA_CALIBRATION_DONE c=20 r=8
|
||||
const char MSG_UNLOAD_FILAMENT[] PROGMEM_I1 = ISTR("Unload filament"); ////MSG_UNLOAD_FILAMENT c=18
|
||||
const char MSG_UNLOADING_FILAMENT[] PROGMEM_I1 = ISTR("Unloading filament"); ////MSG_UNLOADING_FILAMENT c=20
|
||||
const char MSG_INFO_SCREEN[] PROGMEM_I1 = ISTR("Info screen"); ////MSG_INFO_SCREEN c=18
|
||||
const char MSG_WIZARD_CALIBRATION_FAILED[] PROGMEM_I1 = ISTR("Please check our handbook and fix the problem. Then resume the Wizard by rebooting the printer."); ////MSG_WIZARD_CALIBRATION_FAILED c=20 r=8
|
||||
const char MSG_WIZARD_DONE[] PROGMEM_I1 = ISTR("All is done. Happy printing!"); ////MSG_WIZARD_DONE c=20 r=3
|
||||
const char MSG_WIZARD_HEATING[] PROGMEM_I1 = ISTR("Preheating nozzle. Please wait."); ////MSG_WIZARD_HEATING c=20 r=3
|
||||
const char MSG_WIZARD_QUIT[] PROGMEM_I1 = ISTR("You can always resume the Wizard from Calibration -> Wizard."); ////MSG_WIZARD_QUIT c=20 r=8
|
||||
const char MSG_WIZARD_WELCOME[] PROGMEM_I1 = ISTR("Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?"); ////MSG_WIZARD_WELCOME c=20 r=7
|
||||
const char MSG_WIZARD_WELCOME_SHIPPING[] PROGMEM_I1 = ISTR("Hi, I am your Original Prusa i3 printer. I will guide you through a short setup process, in which the Z-axis will be calibrated. Then, you will be ready to print."); ////MSG_WIZARD_WELCOME_SHIPPING c=20 r=16
|
||||
const char MSG_YES[] PROGMEM_I1 = ISTR("Yes"); ////MSG_YES c=4
|
||||
const char MSG_V2_CALIBRATION[] PROGMEM_I1 = ISTR("First layer cal."); ////MSG_V2_CALIBRATION c=18
|
||||
const char MSG_OFF[] PROGMEM_I1 = ISTR("Off"); ////MSG_OFF c=3
|
||||
const char MSG_ON[] PROGMEM_I1 = ISTR("On"); ////MSG_ON c=3
|
||||
const char MSG_NA[] PROGMEM_I1 = ISTR("N/A"); ////MSG_NA c=3
|
||||
const char MSG_CUTTER[] PROGMEM_I1 = ISTR("Cutter"); ////MSG_CUTTER c=9
|
||||
const char MSG_NONE[] PROGMEM_I1 = ISTR("None"); ////MSG_NONE c=8
|
||||
const char MSG_WARN[] PROGMEM_I1 = ISTR("Warn"); ////MSG_WARN c=8
|
||||
const char MSG_STRICT[] PROGMEM_I1 = ISTR("Strict"); ////MSG_STRICT c=8
|
||||
const char MSG_MODEL[] PROGMEM_I1 = ISTR("Model"); ////MSG_MODEL c=8
|
||||
const char MSG_GCODE[] PROGMEM_I1 = ISTR("Gcode"); ////MSG_GCODE c=8
|
||||
const char MSG_GCODE_DIFF_PRINTER_CONTINUE[] PROGMEM_I1 = ISTR("G-code sliced for a different printer type. Continue?"); ////MSG_GCODE_DIFF_PRINTER_CONTINUE c=20 r=5
|
||||
const char MSG_GCODE_DIFF_PRINTER_CANCELLED[] PROGMEM_I1 =ISTR("G-code sliced for a different printer type. Please re-slice the model again. Print cancelled."); ////MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=8
|
||||
const char MSG_NOZZLE_DIAMETER[] PROGMEM_I1 = ISTR("Nozzle d."); ////MSG_NOZZLE_DIAMETER c=10
|
||||
const char MSG_MMU_MODE[] PROGMEM_I1 = ISTR("MMU Mode"); ////MSG_MMU_MODE c=8
|
||||
const char MSG_SD_CARD[] PROGMEM_I1 = ISTR("SD card"); ////MSG_SD_CARD c=8
|
||||
const char MSG_SORT[] PROGMEM_I1 = ISTR("Sort"); ////MSG_SORT c=7
|
||||
const char MSG_SORT_TIME[] PROGMEM_I1 = ISTR("Time"); ////MSG_SORT_TIME c=8
|
||||
const char MSG_SORT_ALPHA[] PROGMEM_I1 = ISTR("Alphabet"); ////MSG_SORT_ALPHA c=8
|
||||
const char MSG_RPI_PORT[] PROGMEM_I1 = ISTR("RPi port"); ////MSG_RPI_PORT c=13
|
||||
const char MSG_SOUND[] PROGMEM_I1 = ISTR("Sound"); ////MSG_SOUND c=9
|
||||
const char MSG_SOUND_LOUD[] PROGMEM_I1 = ISTR("Loud"); ////MSG_SOUND_LOUD c=7
|
||||
const char MSG_SOUND_ONCE[] PROGMEM_I1 = ISTR("Once"); ////MSG_SOUND_ONCE c=7
|
||||
const char MSG_SOUND_BLIND[] PROGMEM_I1 = ISTR("Assist"); ////MSG_SOUND_BLIND c=7
|
||||
const char MSG_MESH[] PROGMEM_I1 = ISTR("Mesh"); ////MSG_MESH c=12
|
||||
const char MSG_MESH_BED_LEVELING[] PROGMEM_I1 = ISTR("Mesh Bed Leveling"); ////MSG_MESH_BED_LEVELING c=18
|
||||
const char MSG_Z_PROBE_NR[] PROGMEM_I1 = ISTR("Z-probe nr."); ////MSG_Z_PROBE_NR c=14
|
||||
const char MSG_MAGNETS_COMP[] PROGMEM_I1 = ISTR("Magnets comp."); ////MSG_MAGNETS_COMP c=13
|
||||
const char MSG_FS_ACTION[] PROGMEM_I1 = ISTR("FS Action"); ////MSG_FS_ACTION c=10
|
||||
const char MSG_CONTINUE_SHORT[] PROGMEM_I1 = ISTR("Cont."); ////MSG_CONTINUE_SHORT c=5
|
||||
const char MSG_PAUSE[] PROGMEM_I1 = ISTR("Pause"); ////MSG_PAUSE c=5
|
||||
const char MSG_BRIGHTNESS[] PROGMEM_I1 = ISTR("Brightness"); ////MSG_BRIGHTNESS c=18
|
||||
const char MSG_BL_HIGH[] PROGMEM_I1 = ISTR("Level Bright"); ////MSG_BL_HIGH c=12
|
||||
const char MSG_BL_LOW[] PROGMEM_I1 = ISTR("Level Dimmed"); ////MSG_BL_LOW c=12
|
||||
const char MSG_TIMEOUT[] PROGMEM_I1 = ISTR("Timeout"); ////MSG_TIMEOUT c=12
|
||||
const char MSG_BRIGHT[] PROGMEM_I1 = ISTR("Bright"); ////MSG_BRIGHT c=6
|
||||
const char MSG_DIM[] PROGMEM_I1 = ISTR("Dim"); ////MSG_DIM c=6
|
||||
const char MSG_AUTO[] PROGMEM_I1 = ISTR("Auto"); ////MSG_AUTO c=6
|
||||
#ifdef IR_SENSOR_ANALOG
|
||||
// Beware - the space at the beginning is necessary since it is reused in LCD menu items which are to be with a space
|
||||
const char MSG_IR_04_OR_NEWER[] PROGMEM_I1 = ISTR(" 0.4 or newer");////c=18
|
||||
const char MSG_IR_03_OR_OLDER[] PROGMEM_I1 = ISTR(" 0.3 or older");////c=18
|
||||
const char MSG_IR_UNKNOWN[] PROGMEM_I1 = ISTR("unknown state");////c=18
|
||||
const char MSG_IR_04_OR_NEWER[] PROGMEM_I1 = ISTR(" 0.4 or newer");////MSG_IR_04_OR_NEWER c=18
|
||||
const char MSG_IR_03_OR_OLDER[] PROGMEM_I1 = ISTR(" 0.3 or older");////MSG_IR_03_OR_OLDER c=18
|
||||
const char MSG_IR_UNKNOWN[] PROGMEM_I1 = ISTR("unknown state");////MSG_IR_UNKNOWN c=18
|
||||
#endif
|
||||
|
||||
//not internationalized messages
|
||||
const char MSG_AUTO_DEPLETE[] PROGMEM_N1 = ISTR("SpoolJoin"); ////c=13
|
||||
const char MSG_FIRMWARE[] PROGMEM_N1 = ISTR("Firmware"); ////c=8
|
||||
const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY[] PROGMEM_N1 = ISTR("FlashAir"); ////c=8
|
||||
const char MSG_PINDA[] PROGMEM_N1 = ISTR("PINDA");////c=5
|
||||
const char MSG_AUTO_DEPLETE[] PROGMEM_N1 = ISTR("SpoolJoin"); ////MSG_AUTO_DEPLETE c=13
|
||||
const char MSG_FIRMWARE[] PROGMEM_N1 = ISTR("Firmware"); ////MSG_FIRMWARE c=8
|
||||
const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY[] PROGMEM_N1 = ISTR("FlashAir"); ////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY c=8
|
||||
const char MSG_PINDA[] PROGMEM_N1 = ISTR("PINDA");////MSG_PINDA c=5
|
||||
const char WELCOME_MSG[] PROGMEM_N1 = ISTR(CUSTOM_MENDEL_NAME " OK."); ////c=20
|
||||
const char MSG_SD_WORKDIR_FAIL[] PROGMEM_N1 = "workDir open failed"; ////
|
||||
const char MSG_BROWNOUT_RESET[] PROGMEM_N1 = " Brown out Reset"; ////
|
||||
|
@ -204,3 +206,4 @@ const char MSG_M112_KILL[] PROGMEM_N1 = "M112 called. Emergency Stop."; ////c=20
|
|||
const char MSG_ADVANCE_K[] PROGMEM_N1 = "Advance K:"; ////c=13
|
||||
const char MSG_POWERPANIC_DETECTED[] PROGMEM_N1 = "POWER PANIC DETECTED"; ////c=20
|
||||
const char MSG_LCD_STATUS_CHANGED[] PROGMEM_N1 = "LCD status changed";
|
||||
const char MSG_UNKNOWN_CODE[] PROGMEM_N1 = "Unknown %c code: %s\n";
|
||||
|
|
|
@ -35,6 +35,8 @@ extern const char MSG_FANS_CHECK[];
|
|||
extern const char MSG_FIL_RUNOUTS[];
|
||||
extern const char MSG_FILAMENT[];
|
||||
extern const char MSG_FAN_SPEED[];
|
||||
extern const char MSG_EXTRUDER_FAN_SPEED[];
|
||||
extern const char MSG_PRINT_FAN_SPEED[];
|
||||
extern const char MSG_FILAMENT_CLEAN[];
|
||||
extern const char MSG_FILAMENT_LOADED[];
|
||||
extern const char MSG_FILAMENT_LOADING_T0[];
|
||||
|
@ -52,8 +54,8 @@ extern const char MSG_HEATING[];
|
|||
extern const char MSG_HEATING_COMPLETE[];
|
||||
extern const char MSG_HOMEYZ[];
|
||||
extern const char MSG_ITERATION[];
|
||||
extern const char MSG_CHOOSE_EXTRUDER[];
|
||||
extern const char MSG_CHOOSE_FILAMENT[];
|
||||
extern const char MSG_SELECT_EXTRUDER[];
|
||||
extern const char MSG_SELECT_FILAMENT[];
|
||||
extern const char MSG_LAST_PRINT[];
|
||||
extern const char MSG_LAST_PRINT_FAILURES[];
|
||||
extern const char MSG_LOAD_FILAMENT[];
|
||||
|
@ -64,7 +66,7 @@ extern const char MSG_BACK[];
|
|||
extern const char MSG_SHEET[];
|
||||
extern const char MSG_STEEL_SHEETS[];
|
||||
extern const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1[];
|
||||
extern const char MSG_MENU_CALIBRATION[];
|
||||
extern const char MSG_CALIBRATION[];
|
||||
extern const char MSG_MMU_FAILS[];
|
||||
extern const char MSG_MMU_LOAD_FAILS[];
|
||||
extern const char MSG_NO[];
|
||||
|
@ -86,7 +88,7 @@ extern const char MSG_RESET[];
|
|||
extern const char MSG_RESUME_PRINT[];
|
||||
extern const char MSG_RESUMING_PRINT[];
|
||||
extern const char MSG_SD_WORKDIR_FAIL[];
|
||||
extern const char MSG_SELFTEST_COOLING_FAN[];
|
||||
extern const char MSG_SELFTEST_PART_FAN[];
|
||||
extern const char MSG_SELFTEST_EXTRUDER_FAN[];
|
||||
extern const char MSG_SELFTEST_FAILED[];
|
||||
extern const char MSG_SELFTEST_FAN[];
|
||||
|
@ -110,11 +112,11 @@ extern const char MSG_STEALTH[];
|
|||
extern const char MSG_STEEL_SHEET_CHECK[];
|
||||
extern const char MSG_STOP_PRINT[];
|
||||
extern const char MSG_STOPPED[];
|
||||
extern const char MSG_TEMP_CALIBRATION[];
|
||||
extern const char MSG_TEMP_CALIBRATION_DONE[];
|
||||
extern const char MSG_PINDA_CALIBRATION[];
|
||||
extern const char MSG_PINDA_CALIBRATION_DONE[];
|
||||
extern const char MSG_UNLOAD_FILAMENT[];
|
||||
extern const char MSG_UNLOADING_FILAMENT[];
|
||||
extern const char MSG_WATCH[];
|
||||
extern const char MSG_INFO_SCREEN[];
|
||||
extern const char MSG_WIZARD_CALIBRATION_FAILED[];
|
||||
extern const char MSG_WIZARD_DONE[];
|
||||
extern const char MSG_WIZARD_HEATING[];
|
||||
|
@ -154,8 +156,8 @@ extern const char MSG_MESH_BED_LEVELING[];
|
|||
extern const char MSG_Z_PROBE_NR[];
|
||||
extern const char MSG_MAGNETS_COMP[];
|
||||
extern const char MSG_FS_ACTION[];
|
||||
extern const char MSG_FS_CONTINUE[];
|
||||
extern const char MSG_FS_PAUSE[];
|
||||
extern const char MSG_CONTINUE_SHORT[];
|
||||
extern const char MSG_PAUSE[];
|
||||
extern const char MSG_BRIGHTNESS[];
|
||||
extern const char MSG_BL_HIGH[];
|
||||
extern const char MSG_BL_LOW[];
|
||||
|
@ -204,6 +206,7 @@ extern const char MSG_M112_KILL[];
|
|||
extern const char MSG_ADVANCE_K[];
|
||||
extern const char MSG_POWERPANIC_DETECTED[];
|
||||
extern const char MSG_LCD_STATUS_CHANGED[];
|
||||
extern const char MSG_UNKNOWN_CODE[];
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
@ -757,14 +757,14 @@ void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move)
|
|||
lcd_clear();
|
||||
setTargetHotend(hotend_temp_bckp, active_extruder);
|
||||
if (((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5)) {
|
||||
lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature..."));
|
||||
lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature...")); ////MSG_MMU_OK_RESUMING_TEMPERATURE c=20 r=4
|
||||
delay_keep_alive(3000);
|
||||
}
|
||||
mmu_wait_for_heater_blocking();
|
||||
}
|
||||
if (move_axes) {
|
||||
lcd_clear();
|
||||
lcd_display_message_fullscreen_P(_i("MMU OK. Resuming position..."));
|
||||
lcd_display_message_fullscreen_P(_i("MMU OK. Resuming position...")); ////MSG_MMU_OK_RESUMING_POSITION c=20 r=4
|
||||
current_position[X_AXIS] = x_position_bckp;
|
||||
current_position[Y_AXIS] = y_position_bckp;
|
||||
plan_buffer_line_curposXYZE(50);
|
||||
|
@ -775,7 +775,7 @@ void manage_response(bool move_axes, bool turn_off_nozzle, uint8_t move)
|
|||
}
|
||||
else {
|
||||
lcd_clear();
|
||||
lcd_display_message_fullscreen_P(_i("MMU OK. Resuming..."));
|
||||
lcd_display_message_fullscreen_P(_i("MMU OK. Resuming...")); ////MSG_MMU_OK_RESUMING c=20 r=4
|
||||
delay_keep_alive(1000); //delay just for showing MMU OK message for a while in case that there are no xyz movements
|
||||
}
|
||||
}
|
||||
|
@ -1340,7 +1340,7 @@ bool mmu_check_version()
|
|||
void mmu_show_warning()
|
||||
{
|
||||
printf_P(PSTR("MMU2 firmware version invalid. Required version: build number %d or higher."), MMU_REQUIRED_FW_BUILDNR);
|
||||
kill(_i("Please update firmware in your MMU2. Waiting for reset."));
|
||||
kill(_i("Please update firmware in your MMU2. Waiting for reset.")); ////MSG_UPDATE_MMU2_FW c=20 r=4
|
||||
}
|
||||
|
||||
void lcd_mmu_load_to_nozzle(uint8_t filament_nr)
|
||||
|
@ -1414,13 +1414,13 @@ bFilamentAction=false; // NOT in "mmu_fil_eject_menu(
|
|||
{
|
||||
LcdUpdateDisabler disableLcdUpdate;
|
||||
lcd_clear();
|
||||
lcd_puts_at_P(0, 1, _i("Ejecting filament"));
|
||||
lcd_puts_at_P(0, 1, _i("Ejecting filament")); ////MSG_EJECTING_FILAMENT c=20
|
||||
mmu_filament_ramming();
|
||||
mmu_command(MmuCmd::E0 + filament);
|
||||
manage_response(false, false, MMU_UNLOAD_MOVE);
|
||||
if (recover)
|
||||
{
|
||||
lcd_show_fullscreen_message_and_wait_P(_i("Please remove filament and then press the knob."));
|
||||
lcd_show_fullscreen_message_and_wait_P(_i("Please remove filament and then press the knob.")); ////MSG_EJECT_REMOVE c=20 r=4
|
||||
mmu_command(MmuCmd::R0);
|
||||
manage_response(false, false);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
// The arc is approximated by generating a huge number of tiny, linear segments. The length of each
|
||||
// segment is configured in settings.mm_per_arc_segment.
|
||||
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
|
||||
uint8_t axis_linear, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder)
|
||||
uint8_t axis_linear, float feed_rate, float radius, bool isclockwise, uint8_t extruder)
|
||||
{
|
||||
// int acceleration_manager_was_enabled = plan_is_acceleration_manager_enabled();
|
||||
// plan_set_acceleration_manager_enabled(false); // disable acceleration management for the duration of the arc
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
|
||||
// for vector transformation direction.
|
||||
void mc_arc(float *position, float *target, float *offset, unsigned char axis_0, unsigned char axis_1,
|
||||
unsigned char axis_linear, float feed_rate, float radius, unsigned char isclockwise, uint8_t extruder);
|
||||
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
|
||||
uint8_t axis_linear, float feed_rate, float radius, bool isclockwise, uint8_t extruder);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -88,8 +88,8 @@ uint8_t optiboot_xflash_enter()
|
|||
if ((boot_app_magic == BOOT_APP_MAGIC) && (boot_app_flags & BOOT_APP_FLG_USER0)) return 1;
|
||||
uint8_t ch;
|
||||
uint8_t rampz = 0;
|
||||
register uint16_t address = 0;
|
||||
register pagelen_t length;
|
||||
uint16_t address = 0;
|
||||
pagelen_t length;
|
||||
// Use the planner's queue for the receive / transmit buffers.
|
||||
// uint8_t *buff = (uint8_t*)block_buffer;
|
||||
uint8_t buff[260];
|
||||
|
@ -271,7 +271,7 @@ uint8_t optiboot_xflash_enter()
|
|||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE) {
|
||||
uint32_t addr = (((uint32_t)rampz) << 16) | address;
|
||||
register pagelen_t i;
|
||||
pagelen_t i;
|
||||
// Read the page length, with the length transferred each nibble separately to work around
|
||||
// the Prusa's USB to serial infamous semicolon issue.
|
||||
length = ((pagelen_t)getch()) << 8;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#define AMBIENT_THERMISTOR
|
||||
#define PINDA_THERMISTOR
|
||||
|
||||
#define PRUSA_SN_SUPPORT //enables the "PRUSA SN" command and 32u2 enhanced firmware support
|
||||
|
||||
#define XFLASH // external 256kB flash
|
||||
#define BOOTAPP // bootloader support
|
||||
|
||||
|
|
|
@ -1095,7 +1095,7 @@ Having the real displacement of the head, we can calculate the total movement le
|
|||
*/
|
||||
block->use_advance_lead = extruder_advance_K > 0
|
||||
&& delta_mm[E_AXIS] >= 0
|
||||
&& abs(delta_mm[Z_AXIS]) < 0.5;
|
||||
&& fabs(delta_mm[Z_AXIS]) < 0.5;
|
||||
if (block->use_advance_lead) {
|
||||
#ifdef LA_FLOWADJ
|
||||
// M221/FLOW should change uniformly the extrusion thickness
|
||||
|
|
|
@ -19,7 +19,6 @@ extern eSOUND_MODE eSoundMode;
|
|||
|
||||
extern void Sound_Init(void);
|
||||
extern void Sound_Default(void);
|
||||
extern void Sound_Save(void);
|
||||
extern void Sound_CycleState(void);
|
||||
extern void Sound_MakeSound(eSOUND_TYPE eSoundType);
|
||||
extern void Sound_MakeCustom(uint16_t ms,uint16_t tone_ ,bool critical);
|
||||
|
|
|
@ -8,7 +8,7 @@ extern const uint16_t speed_lookuptable_slow[256][2] PROGMEM;
|
|||
|
||||
#ifndef _NO_ASM
|
||||
|
||||
// intRes = intIn1 * intIn2 >> 16
|
||||
// intRes = intIn1 * intIn2 >> 8
|
||||
// uses:
|
||||
// r26 to store 0
|
||||
// r27 to store the byte 1 of the 24 bit result
|
||||
|
@ -82,7 +82,7 @@ asm volatile ( \
|
|||
|
||||
static inline void MultiU16X8toH16(uint16_t& intRes, uint8_t& charIn1, uint16_t& intIn2)
|
||||
{
|
||||
intRes = ((uint32_t)charIn1 * (uint32_t)intIn2) >> 16;
|
||||
intRes = ((uint32_t)charIn1 * (uint32_t)intIn2) >> 8;
|
||||
}
|
||||
|
||||
static inline void MultiU24X24toH16(uint16_t& intRes, uint32_t& longIn1, uint32_t& longIn2)
|
||||
|
|
|
@ -299,6 +299,15 @@ ISR(TIMER1_COMPA_vect) {
|
|||
if (sp < SP_min) SP_min = sp;
|
||||
#endif //DEBUG_STACK_MONITOR
|
||||
|
||||
#ifdef DEBUG_PULLUP_CRASH
|
||||
// check for faulty pull-ups enabled on thermistor inputs
|
||||
if ((PORTF & (uint8_t)(ADC_DIDR_MSK & 0xff)) || (PORTK & (uint8_t)((ADC_DIDR_MSK >> 8) & 0xff)))
|
||||
pullup_error(false);
|
||||
#else
|
||||
PORTF &= ~(uint8_t)(ADC_DIDR_MSK & 0xff);
|
||||
PORTK &= ~(uint8_t)((ADC_DIDR_MSK >> 8) & 0xff);
|
||||
#endif // DEBUG_PULLUP_CRASH
|
||||
|
||||
#ifdef LIN_ADVANCE
|
||||
advance_isr_scheduler();
|
||||
#else
|
||||
|
|
|
@ -472,7 +472,7 @@ void __attribute__((noinline)) PID_autotune(float temp, int extruder, int ncycle
|
|||
//SERIAL_ECHOPGM("s. Difference between current and ambient T: ");
|
||||
//MYSERIAL.println(input - temp_ambient);
|
||||
|
||||
if (abs(input - temp_ambient) < 5.0) {
|
||||
if (fabs(input - temp_ambient) < 5.0) {
|
||||
temp_runaway_stop(false, (extruder<0));
|
||||
pid_tuning_finished = true;
|
||||
return;
|
||||
|
@ -1683,6 +1683,16 @@ void adc_ready(void) //callback from adc when sampling finished
|
|||
|
||||
FORCE_INLINE static void temperature_isr()
|
||||
{
|
||||
#ifdef DEBUG_PULLUP_CRASH
|
||||
// check for faulty pull-ups enabled on thermistor inputs
|
||||
if ((PORTF & (uint8_t)(ADC_DIDR_MSK & 0xff)) || (PORTK & (uint8_t)((ADC_DIDR_MSK >> 8) & 0xff)))
|
||||
pullup_error(true);
|
||||
#else
|
||||
PORTF &= ~(uint8_t)(ADC_DIDR_MSK & 0xff);
|
||||
PORTK &= ~(uint8_t)((ADC_DIDR_MSK >> 8) & 0xff);
|
||||
#endif // DEBUG_PULLUP_CRASH
|
||||
|
||||
|
||||
if (!temp_meas_ready) adc_cycle();
|
||||
lcd_buttons_update();
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ bool has_temperature_compensation();
|
|||
#endif
|
||||
|
||||
#ifdef AMBIENT_THERMISTOR
|
||||
//extern int current_temperature_raw_ambient;
|
||||
extern int current_temperature_raw_ambient;
|
||||
extern float current_temperature_ambient;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -243,8 +243,6 @@ uint8_t tmc2130_sample_diag()
|
|||
return mask;
|
||||
}
|
||||
|
||||
extern bool is_usb_printing;
|
||||
|
||||
void tmc2130_st_isr()
|
||||
{
|
||||
if (tmc2130_mode == TMC2130_MODE_SILENT || tmc2130_sg_stop_on_crash == false) return;
|
||||
|
@ -979,7 +977,7 @@ void bubblesort_uint8(uint8_t* data, uint8_t size, uint8_t* data2)
|
|||
for (uint8_t i = 0; i < (size - 1); i++)
|
||||
if (data[i] > data[i+1])
|
||||
{
|
||||
uint8_t register d = data[i];
|
||||
uint8_t d = data[i];
|
||||
data[i] = data[i+1];
|
||||
data[i+1] = d;
|
||||
if (data2)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -49,7 +49,6 @@ void lcd_pause_usb_print();
|
|||
void lcd_resume_print();
|
||||
void lcd_print_stop();
|
||||
void prusa_statistics(int _message, uint8_t _col_nr = 0);
|
||||
unsigned char lcd_choose_color();
|
||||
void lcd_load_filament_color_check();
|
||||
//void lcd_mylang();
|
||||
|
||||
|
@ -222,7 +221,6 @@ void bowden_menu();
|
|||
char reset_menu();
|
||||
uint8_t choose_menu_P(const char *header, const char *item, const char *last_item = nullptr);
|
||||
|
||||
void lcd_pinda_calibration_menu();
|
||||
void lcd_calibrate_pinda();
|
||||
void lcd_temp_calibration_set();
|
||||
|
||||
|
|
|
@ -168,6 +168,8 @@
|
|||
#define DEBUG_DCODE3
|
||||
#define DEBUG_DCODE6
|
||||
|
||||
//#define DEBUG_PULLUP_CRASH //Test Pullup crash
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
//#define DEBUG_SEC_LANG //secondary language debug output at startup
|
||||
//#define DEBUG_XFLASH //debug external spi flash
|
||||
|
|
|
@ -170,6 +170,8 @@
|
|||
#define DEBUG_DCODE3
|
||||
#define DEBUG_DCODE6
|
||||
|
||||
//#define DEBUG_PULLUP_CRASH //Test Pullup crash
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
//#define DEBUG_SEC_LANG //secondary language debug output at startup
|
||||
//#define DEBUG_XFLASH //debug external spi flash
|
||||
|
|
|
@ -8,6 +8,8 @@ enum class dump_crash_reason : uint8_t
|
|||
stack_error,
|
||||
watchdog,
|
||||
bad_isr,
|
||||
bad_pullup_temp_isr,
|
||||
bad_pullup_step_isr,
|
||||
};
|
||||
|
||||
#ifdef XFLASH_DUMP
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
# 3. Install latest updates with 'sudo apt-get upgrade'
|
||||
#
|
||||
#
|
||||
# Version: 1.0.0-Build_13
|
||||
# Version: 1.0.0-Build_14
|
||||
# Change log:
|
||||
# 11 Feb 2021, 3d-gussner, Inital
|
||||
# 11 Feb 2021, 3d-gussner, Optional flags to check for updates
|
||||
|
@ -22,6 +22,8 @@
|
|||
# 18 Jun 2021, 3d-gussner, Added -g 3 and 4 for more details extrusion lines
|
||||
# 18 Jun 2021, 3d-gussner, Check for updates is default. Fix update if internet connection is lost.
|
||||
# 21 Jun 2021, 3d-gussner, Change board_flash argument to 'y' and firmware_version to 'f'
|
||||
# 25 Jan 2021, 3d-gussner, Allow upper and lower case in selection
|
||||
# Add update option to release OR devel
|
||||
|
||||
#### Start: Failures
|
||||
failures()
|
||||
|
@ -74,7 +76,7 @@ while getopts c:f:g:m:n:p:u:x:y:?h flag
|
|||
# '?' 'h' argument usage and help
|
||||
if [ "$help_flag" == "1" ] ; then
|
||||
echo "***************************************"
|
||||
echo "* MK404-build.sh Version: 1.0.0-Build_13 *"
|
||||
echo "* MK404-build.sh Version: 1.0.0-Build_14 *"
|
||||
echo "***************************************"
|
||||
echo "Arguments:"
|
||||
echo "$(tput setaf 2)-c$(tput sgr0) Check for update"
|
||||
|
@ -98,7 +100,7 @@ echo " -g : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' l
|
|||
echo " -m : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes '$(tput setaf 2)2$(tput sgr0)' with MMU2"
|
||||
echo " -n : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes"
|
||||
echo " -p : '$(tput setaf 2)MK25$(tput sgr0)', '$(tput setaf 2)MK25S$(tput sgr0)', '$(tput setaf 2)MK3$(tput sgr0)' or '$(tput setaf 2)MK3S$(tput sgr0)'"
|
||||
echo " -u : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes '"
|
||||
echo " -u : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' release ', '$(tput setaf 2)2$(tput sgr0)' devel '"
|
||||
echo " -x : '$(tput setaf 2)8$(tput sgr0)',$(tput setaf 2)16$(tput sgr0)',$(tput setaf 2)32$(tput sgr0)' or '$(tput setaf 2)64$(tput sgr0)' Kb."
|
||||
echo " -y : '$(tput setaf 2)256$(tput sgr0)','$(tput setaf 2)384$(tput sgr0)','$(tput setaf 2)512$(tput sgr0)','$(tput setaf 2)1024$(tput sgr0)''$(tput setaf 2)32M$(tput sgr0)'"
|
||||
echo
|
||||
|
@ -170,9 +172,8 @@ fi
|
|||
#Start: Check if new build is selected
|
||||
if [ "$new_build_flag" == "1" ]; then
|
||||
check_flag=1
|
||||
update_flag=1
|
||||
fi
|
||||
if [ "$update_flag" == "1" ]; then
|
||||
if [[ "$update_flag" == "1" || "$update_flag" == "2" ]]; then
|
||||
check_flag=1
|
||||
fi
|
||||
#End: Check if new build is selected
|
||||
|
@ -196,11 +197,13 @@ if [ ! -z $firmware_version_flag ]; then
|
|||
if [ ! -z $MK404_PRINTER_TEMP ]; then
|
||||
MK404_PRINTER=MK25S
|
||||
fi
|
||||
elif [[ ! -z $new_build_flag || ! -z $update_flag || ! -z $check_flag ]]; then
|
||||
echo "continue"
|
||||
else
|
||||
failures 8
|
||||
fi
|
||||
|
||||
if [ -z "$MK404_PRINTER" ]; then
|
||||
if [[ -z $MK404_PRINTER && -z $new_build_flag && -z $update_flag && -z $check_flag ]]; then
|
||||
failures 9
|
||||
fi
|
||||
|
||||
|
@ -232,7 +235,7 @@ if [ ! -z $mk404_printer_flag ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ -z $MK404_PRINTER ]; then
|
||||
if [[ -z $MK404_PRINTER && -z $new_build_flag && -z $update_flag && -z $check_flag ]]; then
|
||||
failures 10
|
||||
fi
|
||||
|
||||
|
@ -399,38 +402,58 @@ if [ "$check_flag" == "1" ]; then
|
|||
# Get latest release
|
||||
MK404_release_url=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/$MK404_owner/$MK404_project/releases/latest)
|
||||
MK404_release_tag=$(basename $MK404_release_url)
|
||||
# Get remote Commit_Hash
|
||||
#MK404_remote_GIT_COMMIT_HASH=$(git ls-remote --heads $(git config --get remote.origin.url) | grep "refs/heads/master" | cut -f 1)
|
||||
MK404_remote_GIT_COMMIT_HASH=$(git ls-remote | grep "refs/tags/$MK404_release_tag" | cut -f 1)
|
||||
# Get remote Commit_Number
|
||||
MK404_remote_GIT_COMMIT_NUMBER=$(git rev-list $MK404_release_tag --count)
|
||||
# Get release Commit_Hash
|
||||
MK404_release_GIT_COMMIT_HASH=$(git ls-remote | grep "refs/tags/$MK404_release_tag" | cut -f 1)
|
||||
# Get release Commit_Number
|
||||
MK404_release_GIT_COMMIT_NUMBER=$(git rev-list $MK404_release_tag --count)
|
||||
# Get latest development Commit_Hash
|
||||
MK404_devel_GIT_COMMIT_HASH=$(git for-each-ref refs/remotes/origin/master | cut -d" " -f 1)
|
||||
# Get latest development Commit_Number
|
||||
MK404_devel_GIT_COMMIT_NUMBER=$(git rev-list refs/remotes/origin/master --count)
|
||||
# Output
|
||||
echo ""
|
||||
echo "Current version : $MK404_current_version"
|
||||
echo ""
|
||||
echo "Current local hash : $MK404_local_GIT_COMMIT_HASH"
|
||||
echo "Current local commit nr : $MK404_local_GIT_COMMIT_NUMBER"
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_remote_GIT_COMMIT_HASH" ]; then
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_release_GIT_COMMIT_HASH" ]; then
|
||||
echo "$(tput setaf 1)"
|
||||
else
|
||||
echo "$(tput setaf 2)"
|
||||
fi
|
||||
echo "Latest release tag : $MK404_release_tag"
|
||||
echo "Latest release hash : $MK404_remote_GIT_COMMIT_HASH"
|
||||
echo "Latest remote commit nr : $MK404_remote_GIT_COMMIT_NUMBER"
|
||||
echo "Latest release hash : $MK404_release_GIT_COMMIT_HASH"
|
||||
echo "Latest release commit nr: $MK404_release_GIT_COMMIT_NUMBER"
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_devel_GIT_COMMIT_HASH" ]; then
|
||||
echo "$(tput setaf 1)"
|
||||
else
|
||||
echo "$(tput setaf 2)"
|
||||
fi
|
||||
echo "Latest devel hash : $MK404_devel_GIT_COMMIT_HASH"
|
||||
echo "Latest devel commit nr : $MK404_devel_GIT_COMMIT_NUMBER"
|
||||
echo "$(tput sgr 0)"
|
||||
|
||||
# Check for updates
|
||||
if [ ! -z $MK404_remote_GIT_COMMIT_HASH ]; then
|
||||
if [[ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_remote_GIT_COMMIT_HASH" && -z "$update_flag" ]]; then
|
||||
echo "$(tput setaf 2)Update is availible.$(tput sgr 0)"
|
||||
read -t 10 -n 1 -p "$(tput setaf 3)Update now Y/n$(tput sgr 0)" update_answer
|
||||
if [ "$update_answer" == "Y" ]; then
|
||||
if [ ! -z $MK404_release_GIT_COMMIT_HASH ]; then
|
||||
if [[ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_release_GIT_COMMIT_HASH" && -z "$update_flag" ]]; then
|
||||
echo "$(tput setaf 2)Update to release is availible.$(tput sgr 0)"
|
||||
read -t 10 -n 1 -p "$(tput setaf 3)Update to release now Y/n$(tput sgr 0)" update_answer
|
||||
if [[ "$update_answer" == "Y" || "$update_answer" == "y" ]]; then
|
||||
update_flag=1
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
if [ ! -z $MK404_devel_GIT_COMMIT_HASH ]; then
|
||||
if [[ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_devel_GIT_COMMIT_HASH" && -z "$update_flag" ]]; then
|
||||
echo "$(tput setaf 2)Update to devel is availible.$(tput sgr 0)"
|
||||
read -t 10 -n 1 -p "$(tput setaf 3)Update to devel now Y/n$(tput sgr 0)" update_answer
|
||||
if [[ "$update_answer" == "Y" || "$update_answer" == "y" ]]; then
|
||||
update_flag=2
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
#### End: Check for updates
|
||||
|
@ -439,14 +462,27 @@ fi
|
|||
fetch_updates()
|
||||
{
|
||||
if [ "$update_flag" == "1" ]; then
|
||||
if [ ! -z $MK404_remote_GIT_COMMIT_HASH ]; then
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_remote_GIT_COMMIT_HASH" ]; then
|
||||
if [ ! -z $MK404_release_GIT_COMMIT_HASH ]; then
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_release_GIT_COMMIT_HASH" ]; then
|
||||
echo ""
|
||||
git fetch --all
|
||||
read -t 10 -p "$(tput setaf 2)Updating MK404 !$(tput sgr 0)"
|
||||
read -t 5 -p "$(tput setaf 2)Updating MK404 to release!$(tput sgr 0)"
|
||||
echo ""
|
||||
git reset --hard $MK404_release_tag
|
||||
read -t 10 -p "$(tput setaf 2)Compiling MK404 !$(tput sgr 0)"
|
||||
read -t 5 -p "$(tput setaf 2)Compiling MK404 release!$(tput sgr 0)"
|
||||
echo ""
|
||||
new_build_flag=1
|
||||
fi
|
||||
fi
|
||||
elif [ "$update_flag" == "2" ]; then
|
||||
if [ ! -z $MK404_devel_GIT_COMMIT_HASH ]; then
|
||||
if [ "$MK404_local_GIT_COMMIT_HASH" != "$MK404_devel_GIT_COMMIT_HASH" ]; then
|
||||
echo ""
|
||||
git fetch --all
|
||||
read -t 5 -p "$(tput setaf 2)Updating MK404 to devel!$(tput sgr 0)"
|
||||
echo ""
|
||||
git reset --hard origin/master
|
||||
read -t 5 -p "$(tput setaf 2)Compiling MK404 devel!$(tput sgr 0)"
|
||||
echo ""
|
||||
new_build_flag=1
|
||||
fi
|
||||
|
|
100
PF-build.sh
100
PF-build.sh
|
@ -56,7 +56,7 @@
|
|||
# Some may argue that this is only used by a script, BUT as soon someone accidentally or on purpose starts Arduino IDE
|
||||
# it will use the default Arduino IDE folders and so can corrupt the build environment.
|
||||
#
|
||||
# Version: 2.0.0-Build_63
|
||||
# Version: 2.0.2-Build_69
|
||||
# Change log:
|
||||
# 12 Jan 2019, 3d-gussner, Fixed "compiler.c.elf.flags=-w -Os -Wl,-u,vfprintf -lprintf_flt -lm -Wl,--gc-sections" in 'platform.txt'
|
||||
# 16 Jan 2019, 3d-gussner, Build_2, Added development check to modify 'Configuration.h' to prevent unwanted LCD messages that Firmware is unknown
|
||||
|
@ -165,8 +165,23 @@
|
|||
# 23 Jun 2021, 3d-gussner, Improve MK404 usage
|
||||
# 24 Jun 2021, 3d-gussner, Fix MK404 user interaction not to show if compiling 'All' variants
|
||||
# 24 Jun 2021, 3d-gussner, MK404 is only supported on Linux at this moment.
|
||||
# 03 Jan 2022, 3d-gussner, Remove calling lang-community.sh as not needed anymore
|
||||
# 21 Jan 2022, 3d-gussner, Sort variants
|
||||
# Add Arduino 1.8.19 as an option
|
||||
# 25 Jan 2022, 3d-gussner, Allow upper and lower case for MK404
|
||||
# 09 Feb 2022, 3d-gussner, Add community language firmware files for MK2.5/S
|
||||
# Add selection of language in MK404 for MK2.5/S
|
||||
# 10 Feb 2022, 3d-gussner, Add SRCDIR for compatibility with build server
|
||||
# 13 Feb 2022, leptun , Fix -o for "Restoring" messages after failure
|
||||
# 24 Feb 2022, 3d-gussner, Change to Arduino IDE 1.8.19 and Arduino boards 1.0.5
|
||||
# Fix DEV_STATUS to set correctly on RC/BETA/ALPHA/DEVEL
|
||||
# Fix atmegaMK404 Board mem and flash modifications
|
||||
# Limit atmegaMK404 boards mem to 8,16,32
|
||||
# 20 Jun 2022, 3d-gussner, Change to Ardunio_boards v 1.0.5-1
|
||||
|
||||
|
||||
SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
export SRCDIR=$SCRIPT_PATH
|
||||
|
||||
#### Start: Failures
|
||||
failures()
|
||||
|
@ -183,8 +198,8 @@ case "$1" in
|
|||
12) echo "$(tput setaf 5)Failed to copy file $(tput sgr0)" ; exit 12 ;;
|
||||
13) echo "$(tput setaf 5)Failed to delete $(tput sgr0)" ; exit 13 ;;
|
||||
20) echo "$(tput setaf 2)Conditional stop initiated by user $(tput sgr0)" ; exit 20 ;;
|
||||
21) echo "$(tput setaf 1)PF-build.sh has been interrupted/failed. $(tput setaf 6)Restoring 'Configuration.h'$(tput sgr0)" ; sleep 5 ;;
|
||||
22) echo "$(tput setaf 1)PF-build.sh has been interrupted/failed. $(tput setaf 6)Restoring 'config.h'$(tput sgr0)" ; sleep 5 ;;
|
||||
21) echo "$(tput setaf 1)PF-build.sh has been interrupted/failed. $(tput setaf 6)Restoring 'Configuration.h'$(tput sgr0)" ; if [ $OUTPUT == "1" ] ; then sleep 5 ; fi ;;
|
||||
22) echo "$(tput setaf 1)PF-build.sh has been interrupted/failed. $(tput setaf 6)Restoring 'config.h'$(tput sgr0)" ; if [ $OUTPUT == "1" ] ; then sleep 5 ; fi ;;
|
||||
24) echo "$(tput setaf 1)PF-build.sh stopped due to compiling errors! Try to restore modified files.$(tput sgr0)"; check_script_failed_nr1 ; check_script_failed_nr2 ; cleanup_firmware ; exit 24 ;;
|
||||
25) echo "$(tput setaf 1)Failed to execute $(tput sgr0)" ; exit 25 ;;
|
||||
esac
|
||||
|
@ -220,7 +235,7 @@ while getopts b:c:d:g:h:i:j:l:m:n:o:p:v:x:y:?h flag
|
|||
# '?' 'h' argument usage and help
|
||||
if [ "$help_flag" == "1" ] ; then
|
||||
echo "***************************************"
|
||||
echo "* PF-build.sh Version: 2.0.0-Build_63 *"
|
||||
echo "* PF-build.sh Version: 2.0.2-Build_69 *"
|
||||
echo "***************************************"
|
||||
echo "Arguments:"
|
||||
echo "$(tput setaf 2)-b$(tput sgr0) Build/commit number"
|
||||
|
@ -246,7 +261,7 @@ echo " -b : '$(tput setaf 2)Auto$(tput sgr0)' needs git or a number"
|
|||
echo " -c : '$(tput setaf 2)0$(tput sgr0)' clean up, '$(tput setaf 2)1$(tput sgr0)' keep"
|
||||
echo " -d : '$(tput setaf 2)GOLD$(tput sgr0)', '$(tput setaf 2)RC$(tput sgr0)', '$(tput setaf 2)BETA$(tput sgr0)', '$(tput setaf 2)ALPHA$(tput sgr0)', '$(tput setaf 2)DEBUG$(tput sgr0)', '$(tput setaf 2)DEVEL$(tput sgr0)' and '$(tput setaf 2)UNKNOWN$(tput sgr0)'"
|
||||
echo " -g : '$(tput setaf 2)0$(tput sgr0)' no '$(tput setaf 2)1$(tput sgr0)' lite '$(tput setaf 2)2$(tput sgr0)' fancy '$(tput setaf 2)3$(tput sgr0)' lite with Quad_HR '$(tput setaf 2)4$(tput sgr0)' fancy with Quad_HR"
|
||||
echo " -i : '$(tput setaf 2)1.8.5$(tput sgr0)', '$(tput setaf 2)1.8.13$(tput sgr0)'"
|
||||
echo " -i : '$(tput setaf 2)1.8.5$(tput sgr0)', '$(tput setaf 2)1.8.13$(tput sgr0)', '$(tput setaf 2)1.8.19$(tput sgr0)'"
|
||||
echo " -j : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes"
|
||||
echo " -l : '$(tput setaf 2)ALL$(tput sgr0)' for multi language or '$(tput setaf 2)EN_ONLY$(tput sgr0)' for English only"
|
||||
echo " -m : '$(tput setaf 2)0$(tput sgr0)' no, '$(tput setaf 2)1$(tput sgr0)' yes '$(tput setaf 2)2$(tput sgr0)' with MMU2"
|
||||
|
@ -342,7 +357,7 @@ fi
|
|||
|
||||
#Start: Check if Arduino IDE version is correct
|
||||
if [ ! -z "$IDE_flag" ]; then
|
||||
if [[ "$IDE_flag" == "1.8.5" || "$IDE_flag" == "1.8.13" ]]; then
|
||||
if [[ "$IDE_flag" == "1.8.5" || "$IDE_flag" == "1.8.13" || "$IDE_flag" == "1.8.19" ]]; then
|
||||
ARDUINO_ENV="${IDE_flag}"
|
||||
else
|
||||
ARDUINO_ENV="1.8.5"
|
||||
|
@ -534,16 +549,24 @@ set_build_env_variables()
|
|||
BUILD_ENV="1.0.6"
|
||||
BOARD="prusa_einsy_rambo"
|
||||
BOARD_PACKAGE_NAME="PrusaResearch"
|
||||
if [ "$ARDUINO_ENV" == "1.8.13" ]; then
|
||||
BOARD_VERSION="1.0.4"
|
||||
if [ "$ARDUINO_ENV" == "1.8.19" ]; then
|
||||
BOARD_VERSION="1.0.5-1"
|
||||
else
|
||||
BOARD_VERSION="1.0.4"
|
||||
fi
|
||||
#BOARD_URL="https://raw.githubusercontent.com/3d-gussner/Arduino_Boards/master/IDE_Board_Manager/package_prusa3d_index.json"
|
||||
BOARD_URL="https://raw.githubusercontent.com/prusa3d/Arduino_Boards/master/IDE_Board_Manager/package_prusa3d_index.json"
|
||||
if [ "$ARDUINO_ENV" == "1.8.19" ]; then
|
||||
BOARD_URL="https://raw.githubusercontent.com/prusa3d/Arduino_Boards/devel/IDE_Board_Manager/package_prusa3d_index.json"
|
||||
#BOARD_URL="https://raw.githubusercontent.com/3d-gussner/Arduino_Boards/devel/IDE_Board_Manager/package_prusa3d_index.json"
|
||||
else
|
||||
BOARD_URL="https://raw.githubusercontent.com/prusa3d/Arduino_Boards/master/IDE_Board_Manager/package_prusa3d_index.json"
|
||||
fi
|
||||
BOARD_FILENAME="prusa3dboards"
|
||||
#BOARD_FILE_URL="https://raw.githubusercontent.com/3d-gussner/Arduino_Boards/master/IDE_Board_Manager/prusa3dboards-$BOARD_VERSION.tar.bz2"
|
||||
BOARD_FILE_URL="https://raw.githubusercontent.com/prusa3d/Arduino_Boards/master/IDE_Board_Manager/prusa3dboards-$BOARD_VERSION.tar.bz2"
|
||||
if [ "$ARDUINO_ENV" == "1.8.19" ]; then
|
||||
BOARD_FILE_URL="https://raw.githubusercontent.com/prusa3d/Arduino_Boards/devel/IDE_Board_Manager/prusa3dboards-$BOARD_VERSION.tar.bz2"
|
||||
#BOARD_FILE_URL="https://raw.githubusercontent.com/3d-gussner/Arduino_Boards/devel/IDE_Board_Manager/prusa3dboards-$BOARD_VERSION.tar.bz2"
|
||||
else
|
||||
BOARD_FILE_URL="https://raw.githubusercontent.com/prusa3d/Arduino_Boards/master/IDE_Board_Manager/prusa3dboards-$BOARD_VERSION.tar.bz2"
|
||||
fi
|
||||
#PF_BUILD_FILE_URL="https://github.com/3d-gussner/PF-build-env-1/releases/download/$BUILD_ENV-WinLin/PF-build-env-WinLin-$BUILD_ENV.zip"
|
||||
if [[ "$BOARD_VERSION" == "1.0.3" || "$BOARD_VERSION" == "1.0.2" || "$BOARD_VERSION" == "1.0.1" ]]; then
|
||||
PF_BUILD_FILE_URL="https://github.com/prusa3d/PF-build-env/releases/download/$BUILD_ENV-WinLin/PF-build-env-WinLin-$BUILD_ENV.zip"
|
||||
|
@ -817,7 +840,8 @@ if [ -z "$variant_flag" ] ; then
|
|||
while IFS= read -r -d $'\0' f; do
|
||||
options[i++]="$f"
|
||||
done < <(find Firmware/variants/ -maxdepth 1 -type f -name "*.h" -print0 )
|
||||
select opt in "${options[@]}" "All" "Quit"; do
|
||||
IFS=$'\n' sorted=($(sort -n <<<"${options[*]}")); unset IFS
|
||||
select opt in "${sorted[@]}" "All" "Quit"; do
|
||||
case $opt in
|
||||
*.h)
|
||||
VARIANT=$(basename "$opt" ".h")
|
||||
|
@ -1299,15 +1323,9 @@ create_multi_firmware()
|
|||
./fw-clean.sh
|
||||
echo "$(tput sgr 0)"
|
||||
fi
|
||||
# build languages
|
||||
# Combine compiled firmware with languages
|
||||
echo "$(tput setaf 3)"
|
||||
./lang-build.sh || failures 25
|
||||
# build community languages
|
||||
./lang-community.sh || failures 25
|
||||
# Combine compiled firmware with languages
|
||||
./fw-build.sh || failures 25
|
||||
cp not_tran.txt not_tran_$VARIANT.txt
|
||||
cp not_used.txt not_used_$VARIANT.txt
|
||||
echo "$(tput sgr 0)"
|
||||
# Check if the motherboard is an EINSY and if so only one hex file will generated
|
||||
MOTHERBOARD=$(grep --max-count=1 "\bMOTHERBOARD\b" $SCRIPT_PATH/Firmware/variants/$VARIANT.h | sed -e's/ */ /g' |cut -d ' ' -f3)
|
||||
|
@ -1315,28 +1333,27 @@ create_multi_firmware()
|
|||
if [ "$MOTHERBOARD" = "BOARD_EINSY_1_0a" ]; then
|
||||
echo "$(tput setaf 2)Copying multi language firmware for MK3/Einsy board to PF-build-hex folder$(tput sgr 0)"
|
||||
# End of "lang.bin" for MK3 and MK3S copy
|
||||
cp -f firmware.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.hex
|
||||
cp -f Firmware-intl.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.hex
|
||||
cp -f $BUILD_PATH/Firmware.ino.elf $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.elf
|
||||
else
|
||||
echo "$(tput setaf 2)Zip multi language firmware for MK2.5/miniRAMbo board to PF-build-hex folder$(tput sgr 0)"
|
||||
cp -f firmware_cz.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-cz.hex
|
||||
cp -f firmware_de.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-de.hex
|
||||
cp -f firmware_es.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-es.hex
|
||||
cp -f firmware_fr.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-fr.hex
|
||||
cp -f firmware_it.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-it.hex
|
||||
cp -f firmware_pl.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-pl.hex
|
||||
cp -f firmware_nl.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-nl.hex
|
||||
#Search for created firmware languages
|
||||
langs=$(find firmware_*.hex | cut -d "_" -f2 | cut -d "." -f1)
|
||||
#Copy found firmware_*.hex files
|
||||
for la in $langs; do
|
||||
cp -f firmware_$la.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-$la.hex
|
||||
done
|
||||
cp -f $BUILD_PATH/Firmware.ino.elf $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.elf
|
||||
echo "$(tput setaf 2)Zip multi language firmware for MK2.5/miniRAMbo board to PF-build-hex folder$(tput sgr 0)"
|
||||
if [ $TARGET_OS == "windows" ]; then
|
||||
zip a $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.zip $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-??.hex
|
||||
rm $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-??.hex
|
||||
#rm $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-??.hex
|
||||
elif [ $TARGET_OS == "linux" ]; then
|
||||
# Make a copy for MK404 sim of MK2, MK2.5, MK2.5S firmware
|
||||
if [ ! -z "$mk404_flag" ]; then
|
||||
cp -f firmware_de.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.hex
|
||||
fi
|
||||
# End of MK2, MK2.5, MK2.5S firmware copy
|
||||
zip -m -j ../../$OUTPUT_FOLDER/$OUTPUT_FILENAME.zip ../../$OUTPUT_FOLDER/$OUTPUT_FILENAME-??.hex
|
||||
zip -j ../../$OUTPUT_FOLDER/$OUTPUT_FILENAME.zip ../../$OUTPUT_FOLDER/$OUTPUT_FILENAME-??.hex
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -1344,7 +1361,6 @@ create_multi_firmware()
|
|||
if [[ -z "$clean_flag" || "$clean_flag" == "0" ]]; then
|
||||
echo "$(tput setaf 3)"
|
||||
./fw-clean.sh || failures 25
|
||||
./lang-clean.sh || failures 25
|
||||
echo "$(tput sgr 0)"
|
||||
fi
|
||||
}
|
||||
|
@ -1454,7 +1470,7 @@ if [[ "$output_flag" == "1" || -z "$output_flag" ]]; then
|
|||
if [[ -z "$mk404_flag" && "$variant_flag" != "All" ]]; then
|
||||
echo
|
||||
read -t 10 -n 1 -p "Do you want to start MK404? Y/$(tput setaf 2)n$(tput sgr 0)" mk404_start
|
||||
if [ "$mk404_start" == "Y" ]; then
|
||||
if [[ "$mk404_start" == "Y" || "$mk404_start" == "y" ]]; then
|
||||
echo
|
||||
read -t 10 -n 1 -p "Do you want to start MK404 with or without MMU2S? $(tput setaf 2)1$(tput sgr 0)/2" mk404_choose1
|
||||
if [ "$mk404_choose1" == "1" ]; then
|
||||
|
@ -1497,11 +1513,6 @@ fi
|
|||
|
||||
if [[ ! -z "$mk404_flag" && "$variant_flag" != "All " ]]; then
|
||||
|
||||
# For Prusa MK2, MK2.5/S
|
||||
if [ "$MOTHERBOARD" == "BOARD_RAMBO_MINI_1_3" ]; then
|
||||
MK404_PRINTER="${MK404_PRINTER}_mR13"
|
||||
fi
|
||||
|
||||
# Run MK404 with 'debugcore' and/or 'bootloader-file'
|
||||
if [ ! -z "$board_mem_flag" ]; then
|
||||
MK404_options="-x $board_mem_flag"
|
||||
|
@ -1532,7 +1543,16 @@ if [[ ! -z "$mk404_flag" && "$variant_flag" != "All " ]]; then
|
|||
|
||||
#Decide which hex file to use EN_ONLY or Multi language
|
||||
if [ "$LANGUAGES" == "ALL" ]; then
|
||||
MK404_firmware_file=$SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.hex
|
||||
if [[ "$MK404_PRINTER" == "MK3" || "$MK404_PRINTER" == "MK3S" ]]; then
|
||||
MK404_firmware_file=$SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME.hex
|
||||
else
|
||||
PS3="Select a language:"
|
||||
select lan in ${langs[@]}
|
||||
do
|
||||
MK404_firmware_file=$SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-$lan.hex
|
||||
break
|
||||
done
|
||||
fi
|
||||
else
|
||||
MK404_firmware_file=$SCRIPT_PATH/../$OUTPUT_FOLDER/$OUTPUT_FILENAME-EN_ONLY.hex
|
||||
fi
|
||||
|
@ -1604,4 +1624,4 @@ done
|
|||
finish_pf-build
|
||||
if [ $TARGET_OS == "linux" ]; then
|
||||
MK404_SIM
|
||||
fi
|
||||
fi
|
||||
|
|
18
README.md
18
README.md
|
@ -73,7 +73,7 @@ _Note: Multi language build is not supported._
|
|||
|
||||
**a.** Install `"Arduino Software IDE"` from the official website `https://www.arduino.cc -> Software->Downloads`
|
||||
|
||||
_It is recommended to use version `"1.8.5"`, as it is used on out build server to produce official builds._
|
||||
_It is recommended to use version `"1.8.5"`, as it is used on our build server to produce official builds._
|
||||
|
||||
**b.** Setup Arduino to use Prusa Rambo board definition
|
||||
|
||||
|
@ -128,7 +128,7 @@ _notes: Script and instructions contributed by 3d-gussner. Use at your own risk.
|
|||
- to install zip run `sudo apt-get install zip`
|
||||
- to install dos2unix run `sudo apt-get install dos2unix`
|
||||
- run `dos2unix PF-build.sh` to convert the windows line endings to unix line endings
|
||||
- add few lines at the top of `~/.bashrc` by running `sudo nano ~/.bashrc`
|
||||
- add a few lines at the top of `~/.bashrc` by running `sudo nano ~/.bashrc`
|
||||
export OS="Linux"
|
||||
export JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true"
|
||||
export GPG_TTY=$(tty)
|
||||
|
@ -143,14 +143,14 @@ _notes: Script and instructions contributed by 3d-gussner. Use at your own risk.
|
|||
- Example: You files are under `C:\Users\<your-username>\Downloads\Prusa-Firmware-MK3`
|
||||
- use under Ubuntu the following command `cd /mnt/c/Users/<your-username>/Downloads/Prusa-Firmware-MK3`
|
||||
to change to the right folder
|
||||
- Unix and windows have different line endings (LF vs CRLF), try dos2unix to convert
|
||||
- Unix and Windows have different line endings (LF vs CRLF), use dos2unix to convert
|
||||
- This should fix the `"$'\r': command not found"` error
|
||||
- to install run `apt-get install dos2unix`
|
||||
- If your Windows isn't in English the Paths may look different
|
||||
Example in other languages
|
||||
- English `/mnt/c/Users/<your-username>/Downloads/Prusa-Firmware-MK3` will be on a German Windows`/mnt/c/Anwender/<your-username>/Downloads/Prusa-Firmware-MK3`
|
||||
#### Compile Prusa-firmware with Ubuntu/Debian Linux subsystem installed
|
||||
- open Ubuntu bash
|
||||
- open Ubuntu bash shell
|
||||
- change to your source code folder (case sensitive)
|
||||
- run `./PF-build.sh`
|
||||
- follow the instructions
|
||||
|
@ -220,14 +220,14 @@ Q:I built firmware using Arduino and I see "?" instead of numbers in printer use
|
|||
|
||||
A:Step 1.c was omitted or you updated Arduino and now platform.txt located somewhere in your user profile is used.
|
||||
|
||||
Q:I built firmware using Arduino and printer now speaks Klingon (nonsense characters and symbols are displayed @^#$&*°;~ÿ)
|
||||
Q:I built firmware using Arduino and my printer now speaks "Klingon" (nonsense characters and symbols are displayed @^#$&*°;~ÿ)
|
||||
|
||||
A:Step 2.c was omitted.
|
||||
|
||||
Q:What environment does Prusa use to build the firmware in the first place?
|
||||
Q:What environment does Prusa use to build its official firmware releases?
|
||||
|
||||
A:Our production builds are 99.9% equivalent to https://github.com/prusa3d/Prusa-Firmware#linux this is also easiest way to build as only one step is needed - run single script, which downloads patched Arduino from github, builds using it, then extracts translated strings and creates language variants (for MK2x) or language hex file for external SPI flash (MK3x). But you need Linux or Linux in virtual machine. This is also what happens when you open pull request to our repository - all variants are built by Travis http://travis-ci.org/ (to check for compilation errors). You can see, what is happening in .travis.yml. It would be also possible to get hex built by travis, only deploy step is missing in .travis.yml. You can get inspiration how to deploy hex by travis and how to setup travis in https://github.com/prusa3d/MM-control-01/ repository. Final hex is located in ./lang/firmware.hex Community reproduced this for Windows in https://github.com/prusa3d/Prusa-Firmware#using-linux-subsystem-under-windows-10-64-bit or https://github.com/prusa3d/Prusa-Firmware#using-git-bash-under-windows-10-64-bit .
|
||||
A:Our production builds are 99.9% equivalent to https://github.com/prusa3d/Prusa-Firmware#linux this is also easiest way to build as only one step is needed - run a single script, which downloads patched Arduino from GitHub, builds using it, then extracts translated strings and creates language variants (for MK2x) or language hex file for external SPI flash (MK3x). But you need Linux or Linux in a virtual machine. This is also what happens when you open a pull request to our repository - all variants are built by Travis http://travis-ci.org/ (to check for compilation errors). You can see, what is happening in .travis.yml. It would be also possible to get hex built by Travis, only the deploy step is missing in .travis.yml. You can find inspiration on how to deploy hex in Travis and how to setup Travis in https://github.com/prusa3d/MM-control-01/ repository. The final hex is located in ./lang/firmware.hex - community reproduced this for Windows in https://github.com/prusa3d/Prusa-Firmware#using-linux-subsystem-under-windows-10-64-bit or https://github.com/prusa3d/Prusa-Firmware#using-git-bash-under-windows-10-64-bit .
|
||||
|
||||
Q:Why are build instructions for Arduino mess.
|
||||
Q:Why are build instructions for Arduino a mess?
|
||||
|
||||
Y:We are too lazy to ship proper board definition for Arduino. We plan to switch to cmake + ninja to be inherently multiplatform, easily integrate build tools, suport more IDEs, get 10 times shorter build times and be able to update compiler whenever we want.
|
||||
Y:We are too lazy to ship a proper board definition for Arduino. We plan to switch to CMake + ninja to be inherently multiplatform, easily integrate build tools, suport more IDEs, get 10 times shorter build times and be able to update compiler whenever we want.
|
||||
|
|
17
build.sh
17
build.sh
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
BUILD_ENV="1.0.6.1"
|
||||
BUILD_ENV="1.0.8"
|
||||
SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
|
||||
if [ ! -d "build-env" ]; then
|
||||
|
@ -7,12 +7,11 @@ if [ ! -d "build-env" ]; then
|
|||
fi
|
||||
cd build-env || exit 2
|
||||
|
||||
if [ ! -f "PF-build-env-Linux64-$BUILD_ENV.zip" ]; then
|
||||
#wget https://github.com/3d-gussner/PF-build-env-1/releases/download/$BUILD_ENV-Linux64/PF-build-env-Linux64-$BUILD_ENV.zip || exit 3
|
||||
wget https://github.com/prusa3d/PF-build-env/releases/download/$BUILD_ENV-Linux64/PF-build-env-Linux64-$BUILD_ENV.zip || exit 3
|
||||
fi
|
||||
|
||||
if [ ! -d "../../PF-build-env-$BUILD_ENV" ]; then
|
||||
if [ ! -f "PF-build-env-Linux64-$BUILD_ENV.zip" ]; then
|
||||
#wget https://github.com/3d-gussner/PF-build-env-1/releases/download/$BUILD_ENV-Linux64/PF-build-env-Linux64-$BUILD_ENV.zip || exit 3
|
||||
wget https://github.com/prusa3d/PF-build-env/releases/download/$BUILD_ENV-Linux64/PF-build-env-Linux64-$BUILD_ENV.zip || exit 3
|
||||
fi
|
||||
unzip -q PF-build-env-Linux64-$BUILD_ENV.zip -d ../../PF-build-env-$BUILD_ENV || exit 4
|
||||
fi
|
||||
|
||||
|
@ -32,11 +31,9 @@ if [ ! -f "$SCRIPT_PATH/Firmware/Configuration_prusa.h" ]; then
|
|||
cp $SCRIPT_PATH/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h $SCRIPT_PATH/Firmware/Configuration_prusa.h || exit 8
|
||||
fi
|
||||
|
||||
$BUILD_ENV_PATH/arduino $SCRIPT_PATH/Firmware/Firmware.ino --verify --board PrusaResearchRambo:avr:rambo --pref build.path=$BUILD_PATH --pref compiler.warning_level=all || exit 9
|
||||
$BUILD_ENV_PATH/arduino $SCRIPT_PATH/Firmware/Firmware.ino --verify --board PrusaResearch:avr:prusa_einsy_rambo --pref build.path=$BUILD_PATH --pref compiler.warning_level=all || exit 9
|
||||
|
||||
export ARDUINO=$BUILD_ENV_PATH
|
||||
|
||||
cd $SCRIPT_PATH/lang
|
||||
./lang-build.sh || exit 10
|
||||
./lang-community.sh || exit 11
|
||||
./fw-build.sh || exit 12
|
||||
./fw-build.sh || exit 10
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
# How-to add a new language to Prusa Firmware
|
||||
|
||||
We will use Dutch as an example here.
|
||||
|
||||
## Prepare Prusa Firmware
|
||||
|
||||
QR = palceholder for language in upper case
|
||||
|
||||
qr = placehodler for language in lower case
|
||||
|
||||
AB = palceholder for hexadecial
|
||||
|
||||
Files needs to be modified
|
||||
- `../Firmware/language.h`
|
||||
|
||||
In section `/** @name Language codes (ISO639-1)*/` add the new `#define LANG_CODE_QR 0xABAB //!<'qr'`following ISO639-1 convention for QR.
|
||||
https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||||
|
||||
Example:
|
||||
`#define LANG_CODE_NL 0x6e6c //!<'nl'` where the hex value `0x6e6c` is in ascii `nl`
|
||||
|
||||
- `../Firmware/language.c`
|
||||
|
||||
In section `const char* lang_get_name_by_code(uint16_t code)` add `case LANG_CODE_NL: return _n("Language");`
|
||||
|
||||
Example:
|
||||
|
||||
`case LANG_CODE_NL: return _n("Nederlands");` Where `Language` is native spoken version, here `Nederlands` (Netherlands) or `Vlaams` (Belgium). This will be displayed on the LCD menu.
|
||||
|
||||
- `../lang/lang-add.sh`
|
||||
|
||||
In section `cat lang_add.txt | sed 's/^/"/;s/$/"/' | while read new_s; do` add `insert_qr "$new_s" 'qr'`where qr
|
||||
|
||||
Example:
|
||||
`insert_qr "$new_s" 'nl'` with qr value `nl`for Dutch
|
||||
|
||||
- `../lang/lang-build.sh`
|
||||
|
||||
In section `#returns hexadecial data for lang code` add a case `*qr*) echo '0x71\0x72'`
|
||||
|
||||
Example:
|
||||
`*nl*) echo '\x6c\x6e' ;;` !!! IMPORTANT that the hex values are switched so 'nl' is here in 'ln' !!!
|
||||
|
||||
In generate "all" section add `generate_binary 'qr'
|
||||
|
||||
Example:
|
||||
`generate_binary 'nl'`
|
||||
|
||||
- `../lang/lang-check.py`
|
||||
|
||||
Add in `help` the new language `qr`
|
||||
|
||||
Example:
|
||||
From `help="Check lang file (en|cs|de|es|fr|it|pl)")` to `help="Check lang file (en|cs|de|es|fr|nl|it|pl)")`
|
||||
|
||||
- In `../lang/lang-clean.sh`
|
||||
|
||||
In section echo `"lang-clean.sh started" >&2` add `clean_lang qr`
|
||||
|
||||
Example:
|
||||
`clean_lang nl`
|
||||
|
||||
|
||||
- `../lang/lang-export.sh`
|
||||
|
||||
In section `# if 'all' is selected, script will generate all po files and also pot file` add `./lang-export.sh qr`
|
||||
|
||||
Example:
|
||||
|
||||
`./lang-export.sh nl`
|
||||
|
||||
In section ` # language name in english` add `*qr*) echo "Language-in-English" ;;`
|
||||
|
||||
Example:
|
||||
`*nl*) echo "Dutch" ;;`
|
||||
|
||||
|
||||
|
||||
|
||||
- `../lang/lang-import.sh`
|
||||
|
||||
In section `#replace in languages translation` add new rule set for the language.
|
||||
As the LCD screen doesn't not support äöüßéè and other special characters, it makes sense to "normalize" these.
|
||||
|
||||
Example:
|
||||
```
|
||||
#replace in dutch translation according to https://nl.wikipedia.org/wiki/Accenttekens_in_de_Nederlandse_spelling
|
||||
if [ "$LNG" = "nl" ]; then
|
||||
#replace 'ë' with 'e'
|
||||
sed -i 's/\xc3\xab/e/g' $LNG'_filtered.po'
|
||||
#replace 'ï' with 'i'
|
||||
sed -i 's/\xc3\xaf/i/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'è' with 'e' (left)
|
||||
sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
|
||||
#replace 'ö' with 'o' (left)
|
||||
sed -i 's/\xc3\xb6/o/g' $LNG'_filtered.po'
|
||||
#replace 'ê' with 'e' (left)
|
||||
sed -i 's/\xc3\xaa/e/g' $LNG'_filtered.po'
|
||||
#replace 'ü' with 'u' (left)
|
||||
sed -i 's/\xc3\xbc/u/g' $LNG'_filtered.po'
|
||||
#replace 'ç' with 'c' (left)
|
||||
sed -i 's/\xc3\xa7/c/g' $LNG'_filtered.po'
|
||||
#replace 'á' with 'a' (left)
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace 'à' with 'a' (left)
|
||||
sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
|
||||
#replace 'ä' with 'a' (left)
|
||||
sed -i 's/\xc3\xa4/a/g' $LNG'_filtered.po'
|
||||
#replace 'û' with 'u' (left)
|
||||
sed -i 's/\xc3\xbc/u/g' $LNG'_filtered.po'
|
||||
#replace 'î' with 'i' (left)
|
||||
sed -i 's/\xc3\xae/i/g' $LNG'_filtered.po'
|
||||
#replace 'í' with 'i' (left)
|
||||
sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
|
||||
#replace 'ô' with 'o' (left)
|
||||
sed -i 's/\xc3\xb4/o/g' $LNG'_filtered.po'
|
||||
#replace 'ú' with 'u' (left)
|
||||
sed -i 's/\xc3\xba/u/g' $LNG'_filtered.po'
|
||||
#replace 'ñ' with 'n' (left)
|
||||
sed -i 's/\xc3\xb1/n/g' $LNG'_filtered.po'
|
||||
#replace 'â' with 'a' (left)
|
||||
sed -i 's/\xc3\xa2/a/g' $LNG'_filtered.po'
|
||||
#replace 'Å' with 'A' (left)
|
||||
sed -i 's/\xc3\x85/A/g' $LNG'_filtered.po'
|
||||
fi
|
||||
```
|
||||
|
||||
- `../lang/fw-build.sh`
|
||||
|
||||
In section `#update _SEC_LANG in binary file if language is selected` add
|
||||
```
|
||||
if [ -e lang_qr.bin ]; then
|
||||
echo -n " Language-in-English : " >&2
|
||||
./update_lang.sh qr 2>./update_lang_qr.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; fi
|
||||
fi
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
if [ -e lang_nl.bin ]; then
|
||||
echo -n " Dutch : " >&2
|
||||
./update_lang.sh nl 2>./update_lang_nl.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; fi
|
||||
fi
|
||||
```
|
||||
|
||||
In section `#create binary file with all languages` add `if [ -e lang_qr.bin ]; then cat lang_qr.bin >> lang.bin; fi`
|
||||
|
||||
Example:
|
||||
|
||||
`if [ -e lang_nl.bin ]; then cat lang_nl.bin >> lang.bin; fi`
|
||||
|
||||
- `../lang/fw-clean.sh`
|
||||
|
||||
In section `echo "fw-clean.sh started" >&2` add
|
||||
|
||||
```
|
||||
rm_if_exists firmware_qr.hex
|
||||
...
|
||||
...
|
||||
rm_if_exists update_lang_qr.out
|
||||
```
|
||||
|
||||
Example:
|
||||
`rm_if_exists firmware_nl.hex`
|
||||
|
||||
and
|
||||
|
||||
`rm_if_exists update_lang_nl.out`
|
||||
|
||||
|
||||
## Prepare language part
|
||||
|
||||
To prepare the acutal language translation files we need create the `lang_en_qr.txt` file.
|
||||
1. Copy and `lang_en.txt` as `lang_en_qr.txt`
|
||||
2. run `../lang/lang-export.sh`
|
||||
3. copy `../lang/po/Firmware_qr.po` file to `../lang/po/new/qr.po`
|
||||
4. translate all messages using POEdit or other tools.
|
||||
5. use `lang/lang-import.sh qr` to generate `lang_en_qr.txt` from translated po files
|
||||
6. move `../lang/po/new/lang_en_qr.txt` to `../lang/lang_en_qr.txt`
|
||||
7. cleanup `../lang/po/new` folder by deleting
|
||||
```
|
||||
qr_filtered.po
|
||||
qr_new.po
|
||||
noasci.txt
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
##
|
96
lang/README.md
Normal file
96
lang/README.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
# Internationalization support
|
||||
|
||||
Multi-language support in the Prusa MK3 firmware is based on PO language files.
|
||||
|
||||
Firmware support is controlled by the ``LANG_MODE`` define in the configuration, which defaults to 1 (enabled). When ``LANG_MODE`` is set, the firmware *can* load additional languages, but these extra languages need to be "baked in" in the firmware image for flashing. This last step is performed using the tools in this directory.
|
||||
|
||||
## Quick reference
|
||||
|
||||
### Required tools
|
||||
|
||||
Python 3 with the ``regex``, ``pyelftools`` and ``polib`` modules as well as ``gettext`` and ``dos2unix``. On a debian-based distribution, install the required packages with:
|
||||
|
||||
sudo apt-get install python3-regex python3-pyelftools python3-polib gettext dos2unix
|
||||
|
||||
### Main summary
|
||||
|
||||
Language files:
|
||||
|
||||
* ``po/Firmware.pot``: Main list of strings to translate (do *not* change this file manually - it is automatically generated)
|
||||
* ``po/Firmware_XY.po``: Translations for "XY", where XY is the ISO639-1 language code.
|
||||
|
||||
PO files are simple text files that can be edited with any text editor, but are best handled using dedicated tools such as POEdit, Lokalize or Linguist.
|
||||
|
||||
High-level tools:
|
||||
|
||||
* ``config.sh``: Language selection/configuration
|
||||
* ``fw-build.sh``: Builds the final multi-language hex file into this directory
|
||||
* ``fw-clean.sh``: Cleanup temporary files left by ``fw-build.sh``
|
||||
* ``update-pot.sh``: Extract internationalized strings from the sources and place them inside ``po/Firmware.pot``
|
||||
* ``update-po.sh``: Refresh po file/s with new translations from the main pot file.
|
||||
|
||||
Lower-level tools:
|
||||
|
||||
* ``lang-check.py``: Checks a single po file for screen formatting issues.
|
||||
* ``lang-extract.py``: Extract internationalized strings from source files.
|
||||
* ``lang-map.py``: Extract and patch the translation symbol map in the firmware.
|
||||
* ``lang-build.py``: Build a binary language catalog for a single po file.
|
||||
* ``lang-patchsec.py``: Embed a single secondary language catalog in the firmware.
|
||||
|
||||
### Building an internationalized firmware
|
||||
|
||||
This is accomplished by running ``fw-build.sh`` after building the firmware with ``LANG_MODE = 1``. Language selection is done by modifying ``config.sh``.
|
||||
|
||||
After running the script, the final ``Firmware-intl.hex`` will be generated in this directory.
|
||||
|
||||
This step is already performed for you when using ``build.sh`` or ``PF-build.sh``. You can however re-run ``fw-build.sh`` to update just the language catalogs inside the image.
|
||||
|
||||
### Updating an existing translation
|
||||
|
||||
#### Typo or incorrect translation in existing text
|
||||
|
||||
If you see a typo or an incorrect translation, simply edit ``po/Firmware_XY.po`` and make a pull request with the changes.
|
||||
|
||||
You can use the following command:
|
||||
|
||||
./lang-check.py po/Firmware_XY.po
|
||||
|
||||
to check for screen formatting issues in isolation, or use the ``--information`` flag:
|
||||
|
||||
./lang-check.py --information po/Firmware_XY.po
|
||||
|
||||
to preview all translations as formatted on the screen.
|
||||
|
||||
#### Missing translation without entry in po file
|
||||
|
||||
If some text is missing, but there is no reference text in the po file, you need to refresh the translation file by picking up new strings and annotations from the template.
|
||||
|
||||
Run ``./update-po.sh po/Firmware_XY.po`` to propagate the new strings to your language. This will merge the new strings, update references/annotations as well as marking unused strings as obsolete.
|
||||
|
||||
Update the translations, then proceed as for [typo or incorrect translation](#typo-or-incorrect-translation-in-existing-text).
|
||||
|
||||
### Fixing an incorrect screen annotation or english text
|
||||
|
||||
The screen annotations as well as the original english text is extracted from the firmware sources. **Do not change the main pot file**. The ``pot`` and ``po`` file contains the location of the annotation to help you fix the sources themselves.
|
||||
|
||||
Run ``./update-pot.sh`` to regenerate ``po/Firmware.pot`` and verify that the annotation has been picked up correctly. You can stop here if you only care about the annotation.
|
||||
|
||||
Run ``./update-po.sh po/Firmware_XY.po`` otherwise to propagate the annotation to your language, then proceed as for [typo or incorrect translation](#typo-or-incorrect-translation-in-existing-text).
|
||||
|
||||
### Adding a new language
|
||||
|
||||
Each language is assigned a two-letter ISO639-1 language code.
|
||||
|
||||
The firmware needs to be aware of the language code. It's probably necessary to update the "Language codes" section in ``Firmware/language.h`` to add the new code as a ``LANG_CODE_XY`` define as well as add the proper language name in the function ``lang_get_name_by_code`` in ``Firmware/language.c``.
|
||||
|
||||
It is a good idea to ensure the translation template is up-to-date before starting to translate. Run ``./update-pot.sh`` to regenerate ``po/Firmware.pot`` if possible.
|
||||
|
||||
Copy ``po/Firmware.pot`` to ``po/Firmware_XY.po``. The *same* language code needs to be used for the "Language" entry in the metadata. Other entries can be customized freely.
|
||||
|
||||
The new language needs to be explicitly added to the list of bundled languages in ``config.sh``.
|
||||
|
||||
At this point the new language should be picked-up normally. See [how to build an internationalized firmware](#building-an-internationalized-firmware) and use ``lang-check.py`` for [previewing the translation](#typo-or-incorrect-translation-in-existing-text) without having to perform a complete rebuild.
|
||||
|
||||
## Internal details
|
||||
|
||||
TODO
|
138
lang/config.sh
138
lang/config.sh
|
@ -1,68 +1,142 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
#
|
||||
# Version 1.0.1 Build 10
|
||||
#
|
||||
# config.sh - multi-language support configuration script
|
||||
# Definition of absolute paths etc.
|
||||
# This file is 'included' in all scripts.
|
||||
#
|
||||
#############################################################################
|
||||
# Change log:
|
||||
# 31 May 2018, XPila, Initial
|
||||
# 17 Dec. 2021, 3d-gussner, Change default Arduino path to by PF-build.sh
|
||||
# created one
|
||||
# Prepare to use one config file for all languages
|
||||
# 11 Jan. 2022, 3d-gussner, Added version and Change log colored output
|
||||
# Use `git rev-list --count HEAD config.sh`
|
||||
# to get Build Nr
|
||||
# Check if variables are set by other scripts
|
||||
# and use these. More flexible for different build
|
||||
# scripts
|
||||
# Check correctly if files or dirs exist
|
||||
# 10 Feb. 2022, 3d-gussner, Add SRCDIR for compatibility with build server
|
||||
#############################################################################
|
||||
#
|
||||
if [ -z "$SRCDIR" ]; then
|
||||
export SRCDIR=".."
|
||||
fi
|
||||
|
||||
LNGDIR="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
export LNGDIR=$LNGDIR
|
||||
|
||||
# Arduino main folder:
|
||||
if [ -z "$ARDUINO" ]; then
|
||||
export ARDUINO=C:/arduino-1.8.5
|
||||
export ARDUINO=../../PF-build-env-1.0.6/1.8.5-1.0.4-linux-64 #C:/arduino-1.8.5
|
||||
fi
|
||||
#
|
||||
# Arduino builder:
|
||||
export BUILDER=$ARDUINO/arduino-builder
|
||||
#
|
||||
# AVR gcc tools:
|
||||
export OBJCOPY=$ARDUINO/hardware/tools/avr/bin/avr-objcopy
|
||||
export OBJDUMP=$ARDUINO/hardware/tools/avr/bin/avr-objdump
|
||||
if [ -z "$OBJCOPY" ]; then
|
||||
export OBJCOPY=$ARDUINO/hardware/tools/avr/bin/avr-objcopy
|
||||
fi
|
||||
#
|
||||
# Output folder:
|
||||
if [ -z "$OUTDIR" ]; then
|
||||
export OUTDIR="../../Prusa-Firmware-build"
|
||||
fi
|
||||
#
|
||||
# Objects folder:
|
||||
export OBJDIR="$OUTDIR/sketch"
|
||||
# Output elf file:
|
||||
if [ -z "$INOELF" ]; then
|
||||
export INOELF="$OUTDIR/Firmware.ino.elf"
|
||||
fi
|
||||
#
|
||||
# Generated elf file:
|
||||
export INOELF="$OUTDIR/Firmware.ino.elf"
|
||||
# Output hex file:
|
||||
if [ -z "$INOHEX" ]; then
|
||||
export INOHEX="$OUTDIR/Firmware.ino.hex"
|
||||
fi
|
||||
#
|
||||
# Generated hex file:
|
||||
export INOHEX="$OUTDIR/Firmware.ino.hex"
|
||||
# Generated multi-language hex file prefix:
|
||||
if [ -z "$INTLHEX" ]; then
|
||||
export INTLHEX="$LNGDIR/Firmware-intl"
|
||||
fi
|
||||
#
|
||||
# Set default languages
|
||||
if [ -z "$LANGUAGES" ]; then
|
||||
export LANGUAGES="cs de es fr it pl"
|
||||
fi
|
||||
#
|
||||
# Check for community languages
|
||||
MAX_COMMINITY_LANG=10 # Total 16 - 6 default
|
||||
COMMUNITY_LANGUAGES=""
|
||||
#Search Firmware/config.h for active community group
|
||||
COMMUNITY_LANG_GROUP=$(grep --max-count=1 "^#define COMMUNITY_LANG_GROUP" $SRCDIR/Firmware/config.h| cut -d ' ' -f3)
|
||||
|
||||
# Search Firmware/config.h for active community languanges
|
||||
if [ "$COMMUNITY_LANG_GROUP" = "1" ]; then
|
||||
COMMUNITY_LANGUAGES=$(grep --max-count=$MAX_COMMINITY_LANG "^#define COMMUNITY_LANG_GROUP1_" $SRCDIR/Firmware/config.h| cut -d '_' -f4 |cut -d ' ' -f1 |tr '[:upper:]' '[:lower:]'| tr '\n' ' ')
|
||||
elif [ "$COMMUNITY_LANG_GROUP" = "2" ]; then
|
||||
COMMUNITY_LANGUAGES=$(grep --max-count=$MAX_COMMINITY_LANG "^#define COMMUNITY_LANG_GROUP2_" $SRCDIR/Firmware/config.h| cut -d '_' -f4 |cut -d ' ' -f1 |tr '[:upper:]' '[:lower:]'| tr '\n' ' ')
|
||||
elif [ "$COMMUNITY_LANG_GROUP" = "3" ]; then
|
||||
COMMUNITY_LANGUAGES=$(grep --max-count=$MAX_COMMINITY_LANG "^#define COMMUNITY_LANG_GROUP3_" $SRCDIR/Firmware/config.h| cut -d '_' -f4 |cut -d ' ' -f1 |tr '[:upper:]' '[:lower:]'| tr '\n' ' ')
|
||||
fi
|
||||
|
||||
echo "config.sh started" >&2
|
||||
# End of customization
|
||||
######################
|
||||
|
||||
if [ -z "$COMMUNITY_LANGUAGES" ]; then
|
||||
export COMMUNITY_LANGUAGES="$COMMUNITY_LANGUAGES"
|
||||
fi
|
||||
|
||||
if [ ! -t 2 -o "$TERM" = "dumb" ]; then
|
||||
NO_COLOR=1
|
||||
fi
|
||||
|
||||
color()
|
||||
{
|
||||
color=$1
|
||||
shift
|
||||
if [ "$NO_COLOR" = 0 -o -z "$NO_COLOR" ]; then
|
||||
echo "$(tput setaf $color)$*$(tput sgr 0)"
|
||||
else
|
||||
echo "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
ok() { color 2 "OK"; }
|
||||
ng() { color 1 "NG!"; }
|
||||
|
||||
color 2 "config.sh started" >&2
|
||||
|
||||
_err=0
|
||||
|
||||
echo -n " Arduino main folder: " >&2
|
||||
if [ -e $ARDUINO ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=1; fi
|
||||
|
||||
echo -n " Arduino builder: " >&2
|
||||
if [ -e $BUILDER ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=2; fi
|
||||
if [ -d $ARDUINO ]; then ok >&2; else ng >&2; _err=1; fi
|
||||
|
||||
echo " AVR gcc tools:" >&2
|
||||
echo -n " objcopy " >&2
|
||||
if [ -e $OBJCOPY ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=3; fi
|
||||
echo -n " objdump " >&2
|
||||
if [ -e $OBJDUMP ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=4; fi
|
||||
if [ -e $OBJCOPY ]; then ok >&2; else ng >&2; _err=3; fi
|
||||
|
||||
echo -n " Output folder: " >&2
|
||||
if [ -e $OUTDIR ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=5; fi
|
||||
if [ -d $OUTDIR ]; then ok >&2; else ng >&2; _err=5; fi
|
||||
|
||||
echo -n " Objects folder: " >&2
|
||||
if [ -e $OBJDIR ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=6; fi
|
||||
echo -n " Output elf file: " >&2
|
||||
if [ -e $INOELF ]; then ok >&2; else ng >&2; _err=7; fi
|
||||
|
||||
echo -n " Generated elf file: " >&2
|
||||
if [ -e $INOELF ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=7; fi
|
||||
echo -n " Output hex file: " >&2
|
||||
if [ -e $INOHEX ]; then ok >&2; else ng >&2; _err=8; fi
|
||||
|
||||
echo -n " Generated hex file: " >&2
|
||||
if [ -e $INOHEX ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=8; fi
|
||||
echo -n " Intl hex file prefix: " >&2
|
||||
if [ -n $INTLHEX ]; then ok >&2; else ng >&2; _err=8; fi
|
||||
|
||||
echo -n " Languages: " >&2
|
||||
color 2 "$LANGUAGES" >&2
|
||||
|
||||
echo -n " Community languages: " >&2
|
||||
color 2 "$COMMUNITY_LANGUAGES" >&2
|
||||
|
||||
if [ $_err -eq 0 ]; then
|
||||
echo "config.sh finished with success" >&2
|
||||
export CONFIG_OK=1
|
||||
color 2 "config.sh finished with success" >&2
|
||||
export CONFIG_OK=1
|
||||
else
|
||||
echo "config.sh finished with errors!" >&2
|
||||
export CONFIG_OK=0
|
||||
color 1 "config.sh finished with errors!" >&2
|
||||
export CONFIG_OK=0
|
||||
fi
|
||||
|
|
313
lang/fw-build.sh
313
lang/fw-build.sh
|
@ -1,224 +1,131 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# postbuild.sh - multi-language support script
|
||||
# Generate binary with secondary language.
|
||||
#
|
||||
# Input files:
|
||||
# $OUTDIR/Firmware.ino.elf
|
||||
# $OUTDIR/sketch/*.o (all object files)
|
||||
#
|
||||
# Output files:
|
||||
# text.sym
|
||||
# $PROGMEM.sym (progmem1.sym)
|
||||
# $PROGMEM.lss (...)
|
||||
# $PROGMEM.hex
|
||||
# $PROGMEM.chr
|
||||
# $PROGMEM.var
|
||||
# $PROGMEM.txt
|
||||
# textaddr.txt
|
||||
#
|
||||
#
|
||||
# Config:
|
||||
if [ -z "$CONFIG_OK" ]; then eval "$(cat config.sh)"; fi
|
||||
if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo 'Config NG!' >&2; exit 1; fi
|
||||
#
|
||||
# Selected language:
|
||||
LNG=$1
|
||||
#if [ -z "$LNG" ]; then LNG='cz'; fi
|
||||
#
|
||||
# Params:
|
||||
IGNORE_MISSING_TEXT=1
|
||||
# TODO: write some up-to-date description
|
||||
|
||||
# Config:
|
||||
if [ -z "$CONFIG_OK" ]; then source config.sh; fi
|
||||
if [ -z "$CONFIG_OK" -o "$CONFIG_OK" -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr0)" >&2; exit 1; fi
|
||||
|
||||
# Community languages
|
||||
if [ ! -z "$COMMUNITY_LANGUAGES" ]; then
|
||||
LANGUAGES+=" $COMMUNITY_LANGUAGES"
|
||||
fi
|
||||
|
||||
color 2 "fw-build.sh started" >&2
|
||||
echo -n "fw-build languages: " >&2
|
||||
color 2 "$LANGUAGES" >&2
|
||||
|
||||
finish()
|
||||
{
|
||||
echo
|
||||
if [ "$1" = "0" ]; then
|
||||
echo "postbuild.sh finished with success" >&2
|
||||
else
|
||||
echo "postbuild.sh finished with errors!" >&2
|
||||
fi
|
||||
case "$-" in
|
||||
*i*) echo "press enter key"; read ;;
|
||||
esac
|
||||
exit $1
|
||||
echo >&2
|
||||
if [ "$1" = "0" ]; then
|
||||
color 2 "fw-build.sh finished with success" >&2
|
||||
else
|
||||
color 1 "fw-build.sh finished with errors!" >&2
|
||||
fi
|
||||
case "$-" in
|
||||
*i*)
|
||||
echo "press enter key"; read ;;
|
||||
esac
|
||||
exit $1
|
||||
}
|
||||
|
||||
echo "postbuild.sh started" >&2
|
||||
# Clean the temporary directory
|
||||
TMPDIR=$(dirname "$0")/tmp
|
||||
rm -rf "$TMPDIR"
|
||||
mkdir -p "$TMPDIR"
|
||||
BIN=$TMPDIR/firmware.bin
|
||||
MAP=$TMPDIR/firmware.map
|
||||
|
||||
#check input files
|
||||
echo " checking files:" >&2
|
||||
if [ ! -e $OUTDIR ]; then echo " folder '$OUTDIR' not found!" >&2; finish 1; fi
|
||||
echo " folder OK" >&2
|
||||
if [ ! -e $INOELF ]; then echo " elf file '$INOELF' not found!" >&2; finish 1; fi
|
||||
echo " elf OK" >&2
|
||||
if ! ls $OBJDIR/*.o >/dev/null 2>&1; then echo " no object files in '$OBJDIR/'!" >&2; finish 1; fi
|
||||
echo " objects OK" >&2
|
||||
# Extract and patch the symbol table/language map
|
||||
color 4 "generating firmware symbol map" >&2
|
||||
"$OBJCOPY" -I ihex -O binary "$INOHEX" "$BIN"
|
||||
./lang-map.py "$INOELF" "$BIN" > "$MAP"
|
||||
|
||||
#run progmem.sh - examine content of progmem1
|
||||
echo -n " running progmem.sh..." >&2
|
||||
./progmem.sh 1 2>progmem.out
|
||||
if [ $? -ne 0 ]; then echo "NG! - check progmem.out file" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
# Get the maximum size of a single language table
|
||||
maxsize=$(grep '^#define \+LANG_SIZE_RESERVED \+' "$SRCDIR/Firmware/config.h" | sed -e 's/\s\+/ /g' | cut -d ' ' -f3)
|
||||
|
||||
#run textaddr.sh - map progmem addreses to text identifiers
|
||||
echo -n " running textaddr.sh..." >&2
|
||||
./textaddr.sh 2>textaddr.out
|
||||
if [ $? -ne 0 ]; then echo "NG! - check progmem.out file" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
# Build language catalogs
|
||||
for lang in $LANGUAGES; do
|
||||
pofile="po/Firmware_$lang.po"
|
||||
binfile="$TMPDIR/lang_$lang.bin"
|
||||
|
||||
#check for messages declared in progmem1, but not found in lang_en.txt
|
||||
echo -n " checking textaddr.txt..." >&2
|
||||
cat textaddr.txt | grep "^TEXT NF" | sed "s/[^\"]*\"//;s/\"$//" >not_used.txt
|
||||
cat textaddr.txt | grep "^ADDR NF" | sed "s/[^\"]*\"//;s/\"$//" >not_tran.txt
|
||||
if cat textaddr.txt | grep "^ADDR NF" >/dev/null; then
|
||||
echo "NG! - some texts not found in lang_en.txt!"
|
||||
if [ $IGNORE_MISSING_TEXT -eq 0 ]; then
|
||||
finish 1
|
||||
else
|
||||
echo " missing text ignored!" >&2
|
||||
fi
|
||||
color 4 "compiling language \"$lang\" from $pofile" >&2
|
||||
./lang-check.py --map "$MAP" "$pofile"
|
||||
if [ "$?" != 0 ]; then
|
||||
color 1 "$pofile: NG! - translation contains warnings or errors" >&2
|
||||
fi
|
||||
|
||||
./lang-build.py "$MAP" "$pofile" "$binfile"
|
||||
|
||||
# ensure each catalog fits the reserved size
|
||||
if [[ $(stat -c '%s' "$binfile") -gt $maxsize ]]; then
|
||||
color 1 "$pofile: NG! - language data exceeds $maxsize bytes" >&2
|
||||
finish 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Detect the printer type and choose the language type
|
||||
if grep -q '^#define \+PRINTER_TYPE \+PRINTER_\(MK25\|MK25S\)\b' "$SRCDIR/Firmware/Configuration_prusa.h"; then
|
||||
has_xflash=0
|
||||
else
|
||||
echo "OK" >&2
|
||||
has_xflash=1
|
||||
fi
|
||||
|
||||
#extract binary file
|
||||
echo -n " extracting binary..." >&2
|
||||
$OBJCOPY -I ihex -O binary $INOHEX ./firmware.bin
|
||||
echo "OK" >&2
|
||||
if [ "$has_xflash" = 1 ]; then
|
||||
# Build the final hex file with XFLASH support (catalogs appended to a single hex file)
|
||||
OUTHEX="${INTLHEX}.hex"
|
||||
|
||||
#update binary file
|
||||
echo " updating binary:" >&2
|
||||
color 4 "assembling final firmware image" >&2
|
||||
"$OBJCOPY" -I binary -O ihex "$BIN" "$OUTHEX"
|
||||
truncate -s0 "$TMPDIR/lang.bin"
|
||||
for lang in $LANGUAGES; do
|
||||
cat "$TMPDIR/lang_$lang.bin" >> "$TMPDIR/lang.bin"
|
||||
done
|
||||
"$OBJCOPY" -I binary -O ihex "$TMPDIR/lang.bin" "$TMPDIR/lang.hex"
|
||||
cat "$TMPDIR/lang.hex" >> "$OUTHEX"
|
||||
|
||||
#update progmem1 id entries in binary file
|
||||
echo -n " primary language ids..." >&2
|
||||
cat textaddr.txt | grep "^ADDR OK" | cut -f3- -d' ' | sed "s/^0000/0x/" |\
|
||||
awk '{ id = $2 - 1; hi = int(id / 256); lo = int(id - 256 * hi); printf("%d \\\\x%02x\\\\x%02x\n", strtonum($1), lo, hi); }' |\
|
||||
while read addr data; do
|
||||
/bin/echo -n -e $data | dd of=./firmware.bin bs=1 count=2 seek=$addr conv=notrunc oflag=nonblock 2>/dev/null
|
||||
done
|
||||
echo "OK" >&2
|
||||
# Check that the language data doesn't exceed the reserved XFLASH space
|
||||
lang_size=$(stat -c '%s' "$TMPDIR/lang.bin")
|
||||
lang_size_pad=$(( ($lang_size+4096-1) / 4096 * 4096 ))
|
||||
|
||||
#update primary language signature in binary file
|
||||
echo -n " primary language signature..." >&2
|
||||
if [ -e lang_en.bin ]; then
|
||||
#find symbol _PRI_LANG_SIGNATURE in section '.text'
|
||||
pri_lang=$(cat text.sym | grep -E "\b_PRI_LANG_SIGNATURE\b")
|
||||
if [ -z "$pri_lang" ]; then echo "NG!\n symbol _PRI_LANG_SIGNATURE not found!" >&2; finish 1; fi
|
||||
#get pri_lang address
|
||||
pri_lang_addr='0x'$(echo $pri_lang | cut -f1 -d' ')
|
||||
#read header from primary language binary file
|
||||
header=$(dd if=lang_en.bin bs=1 count=16 2>/dev/null | xxd | cut -c11-49 | sed 's/\([0-9a-f][0-9a-f]\)[\ ]*/\1 /g')
|
||||
#read checksum and count data as 4 byte signature
|
||||
chscnt=$(echo $header | cut -c18-29 | sed "s/ /\\\\x/g")
|
||||
/bin/echo -e -n "$chscnt" |\
|
||||
dd of=firmware.bin bs=1 count=4 seek=$(($pri_lang_addr)) conv=notrunc 2>/dev/null
|
||||
echo "OK" >&2
|
||||
# TODO: hard-coded! get value by preprocessing LANG_SIZE from xflash_layout.h!
|
||||
lang_reserved=249856
|
||||
|
||||
echo >&2
|
||||
echo -n " total size usage: " >&2
|
||||
[ $lang_size_pad -gt $lang_reserved ] && c=1 || c=2
|
||||
color $c "$lang_size_pad ($lang_size)" >&2
|
||||
echo -n " reserved size: " >&2
|
||||
color 2 "$lang_reserved" >&2
|
||||
if [ $lang_size_pad -gt $lang_reserved ]; then
|
||||
color 1 "NG! - language data too large" >&2
|
||||
finish 1
|
||||
fi
|
||||
|
||||
echo -n " multilanguage fw: " >&2
|
||||
color 2 "$OUTHEX" >&2
|
||||
else
|
||||
echo "NG! - file lang_en.bin not found!" >&2;
|
||||
finish 1
|
||||
# Build one hex file for each secondary language
|
||||
color 4 "assembling final firmware images" >&2
|
||||
echo >&2
|
||||
echo -n " maximum size: " >&2
|
||||
color 2 "$(( $maxsize ))" >&2
|
||||
|
||||
for lang in $LANGUAGES; do
|
||||
OUTHEX="${INTLHEX}-en_${lang}.hex"
|
||||
catfile="$TMPDIR/lang_$lang.bin"
|
||||
bintmp="$TMPDIR/fw-en_$lang.bin"
|
||||
|
||||
# patch the secondary language table
|
||||
cp "$BIN" "$bintmp"
|
||||
./lang-patchsec.py "$INOELF" "$catfile" "$bintmp"
|
||||
"$OBJCOPY" -I binary -O ihex "$bintmp" "$OUTHEX"
|
||||
|
||||
# print some stats
|
||||
catsize=$(stat -c '%s' "$catfile")
|
||||
echo -n " $lang: " >&2
|
||||
color 2 "$(printf "%5d %s" "$catsize" "$OUTHEX")" >&2
|
||||
done
|
||||
fi
|
||||
|
||||
#convert bin to hex
|
||||
echo -n " converting to hex..." >&2
|
||||
$OBJCOPY -I binary -O ihex ./firmware.bin ./firmware.hex
|
||||
echo "OK" >&2
|
||||
|
||||
#update _SEC_LANG in binary file if language is selected
|
||||
echo -n " secondary language data..." >&2
|
||||
if [ ! -z "$LNG" ]; then
|
||||
./update_lang.sh $LNG 2>./update_lang.out
|
||||
if [ $? -ne 0 ]; then echo "NG! - check update_lang.out file" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
finish 0
|
||||
else
|
||||
echo "Updating languages:" >&2
|
||||
if [ -e lang_cz.bin ]; then
|
||||
echo -n " Czech : " >&2
|
||||
./update_lang.sh cz 2>./update_lang_cz.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_de.bin ]; then
|
||||
echo -n " German : " >&2
|
||||
./update_lang.sh de 2>./update_lang_de.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_it.bin ]; then
|
||||
echo -n " Italian: " >&2
|
||||
./update_lang.sh it 2>./update_lang_it.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_es.bin ]; then
|
||||
echo -n " Spanish: " >&2
|
||||
./update_lang.sh es 2>./update_lang_es.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_fr.bin ]; then
|
||||
echo -n " French : " >&2
|
||||
./update_lang.sh fr 2>./update_lang_fr.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_pl.bin ]; then
|
||||
echo -n " Polish : " >&2
|
||||
./update_lang.sh pl 2>./update_lang_pl.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
#Community language support
|
||||
#Dutch
|
||||
if [ -e lang_nl.bin ]; then
|
||||
echo -n " Dutch : " >&2
|
||||
./update_lang.sh nl 2>./update_lang_nl.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; fi
|
||||
fi
|
||||
|
||||
#Use the 6 lines below as a template and replace 'qr' and 'New language'
|
||||
#New language
|
||||
# if [ -e lang_qr.bin ]; then
|
||||
# echo -n " New language : " >&2
|
||||
# ./update_lang.sh qr 2>./update_lang_qr.out 1>/dev/null
|
||||
# if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; fi
|
||||
# fi
|
||||
|
||||
# echo "skipped" >&2
|
||||
fi
|
||||
|
||||
#create binary file with all languages
|
||||
rm -f lang.bin
|
||||
if [ -e lang_cz.bin ]; then cat lang_cz.bin >> lang.bin; fi
|
||||
if [ -e lang_de.bin ]; then cat lang_de.bin >> lang.bin; fi
|
||||
if [ -e lang_es.bin ]; then cat lang_es.bin >> lang.bin; fi
|
||||
if [ -e lang_fr.bin ]; then cat lang_fr.bin >> lang.bin; fi
|
||||
if [ -e lang_it.bin ]; then cat lang_it.bin >> lang.bin; fi
|
||||
if [ -e lang_pl.bin ]; then cat lang_pl.bin >> lang.bin; fi
|
||||
#Community language support
|
||||
# Dutch
|
||||
if [ -e lang_nl.bin ]; then cat lang_nl.bin >> lang.bin; fi
|
||||
|
||||
#Use the 2 lines below as a template and replace 'qr'
|
||||
## New language
|
||||
#if [ -e lang_qr.bin ]; then cat lang_qr.bin >> lang.bin; fi
|
||||
|
||||
# Check that the language data doesn't exceed the reserved XFLASH space
|
||||
echo " checking language data size:"
|
||||
lang_size=$(wc -c lang.bin | cut -f1 -d' ')
|
||||
lang_size_pad=$(( ($lang_size+4096-1) / 4096 * 4096 ))
|
||||
|
||||
# TODO: hard-coded! get value by preprocessing LANG_SIZE from xflash_layout.h!
|
||||
lang_reserved=249856
|
||||
|
||||
echo " total size usage: $lang_size_pad ($lang_size)"
|
||||
echo " reserved size: $lang_reserved"
|
||||
if [ $lang_size_pad -gt $lang_reserved ]; then
|
||||
echo "NG! - language data too large" >&2
|
||||
finish 1
|
||||
fi
|
||||
|
||||
#convert lang.bin to lang.hex
|
||||
echo -n " converting to hex..." >&2
|
||||
$OBJCOPY -I binary -O ihex ./lang.bin ./lang.hex
|
||||
echo "OK" >&2
|
||||
|
||||
#append languages to hex file
|
||||
cat ./lang.hex >> firmware.hex
|
||||
|
||||
finish 0
|
||||
|
|
|
@ -1,72 +1,13 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# fw-clean.sh - multi-language support script
|
||||
# Remove all firmware output files from lang folder.
|
||||
#
|
||||
set -e
|
||||
|
||||
result=0
|
||||
# Config
|
||||
if [ -z "$CONFIG_OK" ]; then source config.sh; fi
|
||||
if [ -z "$CONFIG_OK" -o "$CONFIG_OK" -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr0)" >&2; exit 1; fi
|
||||
|
||||
rm_if_exists()
|
||||
{
|
||||
if [ -e $1 ]; then
|
||||
echo -n " removing '$1'..." >&2
|
||||
if rm $1; then
|
||||
echo "OK" >&2
|
||||
else
|
||||
echo "NG!" >&2
|
||||
result=1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
# Clean the temporary directory
|
||||
TMPDIR=$(dirname "$0")/tmp
|
||||
rm -rf "$TMPDIR"
|
||||
|
||||
echo "fw-clean.sh started" >&2
|
||||
|
||||
rm_if_exists text.sym
|
||||
rm_if_exists progmem1.sym
|
||||
rm_if_exists progmem1.lss
|
||||
rm_if_exists progmem1.hex
|
||||
rm_if_exists progmem1.chr
|
||||
rm_if_exists progmem1.var
|
||||
rm_if_exists progmem1.txt
|
||||
rm_if_exists textaddr.txt
|
||||
rm_if_exists firmware.bin
|
||||
rm_if_exists firmware.hex
|
||||
rm_if_exists firmware_cz.hex
|
||||
rm_if_exists firmware_de.hex
|
||||
rm_if_exists firmware_es.hex
|
||||
rm_if_exists firmware_fr.hex
|
||||
rm_if_exists firmware_it.hex
|
||||
rm_if_exists firmware_pl.hex
|
||||
rm_if_exists progmem.out
|
||||
rm_if_exists textaddr.out
|
||||
rm_if_exists update_lang.out
|
||||
rm_if_exists update_lang_cz.out
|
||||
rm_if_exists update_lang_de.out
|
||||
rm_if_exists update_lang_es.out
|
||||
rm_if_exists update_lang_fr.out
|
||||
rm_if_exists update_lang_it.out
|
||||
rm_if_exists update_lang_pl.out
|
||||
rm_if_exists lang.bin
|
||||
rm_if_exists lang.hex
|
||||
#Community language support
|
||||
#Dutch
|
||||
rm_if_exists firmware_nl.hex
|
||||
rm_if_exists update_lang_nl.out
|
||||
|
||||
#Use the 2 lines below as a template and replace 'qr'
|
||||
##New language
|
||||
#rm_if_exists firmware_qr.hex
|
||||
#rm_if_exists update_lang_qr.out
|
||||
|
||||
echo -n "fw-clean.sh finished" >&2
|
||||
if [ $result -eq 0 ]; then
|
||||
echo " with success" >&2
|
||||
else
|
||||
echo " with errors!" >&2
|
||||
fi
|
||||
|
||||
case "$-" in
|
||||
*i*) echo "press enter key"; read ;;
|
||||
esac
|
||||
|
||||
exit $result
|
||||
# Remove internationalized firmware files
|
||||
rm -f "${INTLHEX}"*.hex
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang-add.sh - multi-language support script
|
||||
# add new texts from list (lang_add.txt) to all dictionary files
|
||||
#
|
||||
# Input files:
|
||||
# lang_add.txt
|
||||
# Updated files:
|
||||
# lang_en.txt and all lang_en_xx.txt
|
||||
#
|
||||
|
||||
|
||||
# insert single text to english dictionary
|
||||
# $1 - text to insert
|
||||
insert_en()
|
||||
{
|
||||
#replace '[' and ']' in string with '\[' and '\]'
|
||||
str=$(echo "$1" | sed "s/\[/\\\[/g;s/\]/\\\]/g")
|
||||
# extract english texts, merge new text, grep line number
|
||||
ln=$((cat lang_en.txt; echo "$1") | sed "/^$/d;/^#/d" | sort | grep -n "$str" | sed "s/:.*//")
|
||||
# calculate position for insertion
|
||||
ln=$((3*(ln-2)+1))
|
||||
# insert new text
|
||||
sed -i "$ln"'i\\' lang_en.txt
|
||||
sed -i "$ln"'i\'"$1"'\' lang_en.txt
|
||||
sed -i "$ln"'i\#\' lang_en.txt
|
||||
}
|
||||
|
||||
# insert single text to translated dictionary
|
||||
# $1 - text to insert
|
||||
# $2 - sufix
|
||||
insert_xx()
|
||||
{
|
||||
#replace '[' and ']' in string with '\[' and '\]'
|
||||
str=$(echo "$1" | sed "s/\[/\\\[/g;s/\]/\\\]/g")
|
||||
# extract english texts, merge new text, grep line number
|
||||
ln=$((cat lang_en_$2.txt; echo "$1") | sed "/^$/d;/^#/d" | sed -n 'p;n' | sort | grep -n "$str" | sed "s/:.*//")
|
||||
# calculate position for insertion
|
||||
ln=$((4*(ln-2)+1))
|
||||
# insert new text
|
||||
sed -i "$ln"'i\\' lang_en_$2.txt
|
||||
sed -i "$ln"'i\"\x00"\' lang_en_$2.txt
|
||||
sed -i "$ln"'i\'"$1"'\' lang_en_$2.txt
|
||||
sed -i "$ln"'i\#\' lang_en_$2.txt
|
||||
}
|
||||
|
||||
# check if input file exists
|
||||
if ! [ -e lang_add.txt ]; then
|
||||
echo "file lang_add.txt not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat lang_add.txt | sed 's/^/"/;s/$/"/' | while read new_s; do
|
||||
if grep "$new_s" lang_en.txt >/dev/null; then
|
||||
echo "text already exist:"
|
||||
echo "$new_s"
|
||||
echo
|
||||
else
|
||||
echo "adding text:"
|
||||
echo "$new_s"
|
||||
echo
|
||||
insert_en "$new_s"
|
||||
insert_xx "$new_s" 'cz'
|
||||
insert_xx "$new_s" 'de'
|
||||
insert_xx "$new_s" 'es'
|
||||
insert_xx "$new_s" 'fr'
|
||||
insert_xx "$new_s" 'it'
|
||||
insert_xx "$new_s" 'pl'
|
||||
#Community language support
|
||||
#Dutch
|
||||
insert_xx "$new_s" 'nl'
|
||||
|
||||
#Use the 2 lines below as a template and replace 'qr'
|
||||
##New language
|
||||
# insert_xx "$new_s" 'qr'
|
||||
fi
|
||||
done
|
||||
|
||||
read -t 5
|
||||
exit 0
|
151
lang/lang-build.py
Executable file
151
lang/lang-build.py
Executable file
|
@ -0,0 +1,151 @@
|
|||
#!/usr/bin/env python3
|
||||
from collections import defaultdict
|
||||
import codecs
|
||||
import argparse
|
||||
import os
|
||||
import polib
|
||||
import struct
|
||||
import sys
|
||||
|
||||
import lib.charset as cs
|
||||
from lib.io import info, warn, fatal, load_map
|
||||
|
||||
FW_MAGIC = 0x4bb45aa5
|
||||
|
||||
|
||||
def translation_ref(translation):
|
||||
cmt = translation.comment
|
||||
if cmt and cmt.startswith('MSG_'):
|
||||
return cmt.split(' ', 1)[0]
|
||||
else:
|
||||
return repr(translation.msgid)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--warn-unused', action='store_true',
|
||||
help='Warn about unused translations')
|
||||
ap.add_argument('--show-coalesced', action='store_true',
|
||||
help='List coalesced translations')
|
||||
ap.add_argument('map', help='Firmware symbol map file')
|
||||
ap.add_argument('po', help='PO file')
|
||||
ap.add_argument('out', help='output')
|
||||
args = ap.parse_args()
|
||||
|
||||
# check arguments
|
||||
for path in [args.map, args.po]:
|
||||
if not os.path.isfile(path):
|
||||
fatal("{} does not exist or is not a regular file".format(args.po))
|
||||
|
||||
# load the map file
|
||||
syms = load_map(args.map)
|
||||
fw_sig_data = None
|
||||
msgid_data = defaultdict(list)
|
||||
id_msgid = {}
|
||||
sym_cnt = 0
|
||||
for sym in syms:
|
||||
if sym['name'] == '_PRI_LANG_SIGNATURE':
|
||||
fw_sig_data = sym['data']
|
||||
else:
|
||||
# redo forward text transformation for transparent matching
|
||||
msgid = cs.source_to_unicode(codecs.decode(sym['data'], 'unicode_escape', 'strict'))
|
||||
msgid_data[msgid].append(sym)
|
||||
id_msgid[sym['id']] = msgid
|
||||
|
||||
# update the max symbol count
|
||||
if sym_cnt <= sym['id']:
|
||||
sym_cnt = sym['id'] + 1
|
||||
|
||||
if fw_sig_data is None:
|
||||
fatal('_PRI_LANG_SIGNATURE not found in map')
|
||||
|
||||
# open translations
|
||||
po = polib.pofile(args.po)
|
||||
lang_code = po.metadata['Language']
|
||||
if not lang_code.isascii() or len(lang_code) != 2:
|
||||
fatal(f'unsupported language code {lang_code}')
|
||||
|
||||
# build a catalog of all translations
|
||||
trans_table = {}
|
||||
for translation in po:
|
||||
msgid = translation.msgid
|
||||
found = msgid in msgid_data
|
||||
if found:
|
||||
trans_table[msgid] = (translation, msgid_data[msgid])
|
||||
elif args.warn_unused:
|
||||
err = "{}:{}".format(args.po, translation.linenum)
|
||||
err += ": unused translation "
|
||||
err += translation_ref(translation)
|
||||
warn(err)
|
||||
|
||||
for msgid, syms in msgid_data.items():
|
||||
if msgid not in trans_table:
|
||||
# warn about missing translations
|
||||
warn("untranslated text: " + repr(msgid))
|
||||
|
||||
# write the binary catalog
|
||||
with open(args.out, "w+b") as fd:
|
||||
fixed_offset = 16+2*sym_cnt
|
||||
written_locs = {}
|
||||
|
||||
# compute final data tables
|
||||
offsets = b''
|
||||
strings = b'\0'
|
||||
for i in range(sym_cnt):
|
||||
msgid = id_msgid.get(i)
|
||||
translation = trans_table.get(msgid)
|
||||
if translation is None or len(translation[0].msgstr) == 0 or translation[0].msgstr == msgid:
|
||||
# first slot reserved for untraslated/identical entries
|
||||
offsets += struct.pack("<H", fixed_offset)
|
||||
else:
|
||||
string_bin = cs.unicode_to_source(translation[0].msgstr)
|
||||
|
||||
# check for invalid characters
|
||||
invalid_char = cs.translation_check(string_bin)
|
||||
if invalid_char is not None:
|
||||
line = translation[0].linenum
|
||||
warn(f'{args.po}:{line} contains unhandled character ' + repr(invalid_char))
|
||||
|
||||
string_bin = string_bin.encode('raw_unicode_escape', 'ignore')
|
||||
string_off = written_locs.get(string_bin)
|
||||
offset = fixed_offset + len(strings)
|
||||
if string_off is not None:
|
||||
# coalesce repeated strings
|
||||
if args.show_coalesced:
|
||||
info(f'coalescing {offset:04x}:{string_off:04x} {string_bin}')
|
||||
offset = string_off
|
||||
else:
|
||||
# allocate a new string
|
||||
written_locs[string_bin] = offset
|
||||
strings += string_bin + b'\0'
|
||||
offsets += struct.pack("<H", offset)
|
||||
|
||||
# header
|
||||
size = 16 + len(offsets) + len(strings)
|
||||
header = struct.pack(
|
||||
"<IHHHHI",
|
||||
FW_MAGIC,
|
||||
size,
|
||||
sym_cnt,
|
||||
0, # no checksum yet
|
||||
(ord(lang_code[0]) << 8) + ord(lang_code[1]),
|
||||
fw_sig_data)
|
||||
|
||||
fd.write(header)
|
||||
fd.write(offsets)
|
||||
fd.write(strings)
|
||||
|
||||
# calculate and update the checksum
|
||||
cksum = 0
|
||||
fd.seek(0)
|
||||
for i in range(size):
|
||||
cksum += (ord(fd.read(1)) << (0 if i % 2 else 8))
|
||||
cksum &= 0xffff
|
||||
fd.seek(8)
|
||||
fd.write(struct.pack("<H", cksum))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
|
@ -1,149 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# lang-build.sh - multi-language support script
|
||||
# generate lang_xx.bin (language binary file)
|
||||
#
|
||||
# Input files:
|
||||
# lang_en.txt or lang_en_xx.txt
|
||||
#
|
||||
# Output files:
|
||||
# lang_xx.bin
|
||||
#
|
||||
# Temporary files:
|
||||
# lang_xx.tmp
|
||||
# lang_xx.dat
|
||||
#
|
||||
|
||||
#awk code to format ui16 variables for dd
|
||||
awk_ui16='{ h=int($1/256); printf("\\x%02x\\x%02x\n", int($1-256*h), h); }'
|
||||
|
||||
#startup message
|
||||
echo "lang-build.sh started" >&2
|
||||
|
||||
#exiting function
|
||||
finish()
|
||||
{
|
||||
if [ $1 -eq 0 ]; then
|
||||
echo "lang-build.sh finished with success" >&2
|
||||
else
|
||||
echo "lang-build.sh finished with errors!" >&2
|
||||
fi
|
||||
exit $1
|
||||
}
|
||||
|
||||
#returns hexadecial data for lang code
|
||||
lang_code_hex_data()
|
||||
# $1 - language code ('en', 'cz'...)
|
||||
{
|
||||
case "$1" in
|
||||
*en*) echo '\x6e\x65' ;;
|
||||
*cz*) echo '\x73\x63' ;;
|
||||
*de*) echo '\x65\x64' ;;
|
||||
*es*) echo '\x73\x65' ;;
|
||||
*fr*) echo '\x72\x66' ;;
|
||||
*it*) echo '\x74\x69' ;;
|
||||
*pl*) echo '\x6c\x70' ;;
|
||||
#Community language support
|
||||
#Dutch
|
||||
*nl*) echo '\x6c\x6e' ;;
|
||||
#Use the 2 lines below as a template and replace 'qr' and `\x71\x72`
|
||||
##New language
|
||||
# *qr*) echo '\x71\x72' ;;
|
||||
esac
|
||||
echo '??'
|
||||
}
|
||||
|
||||
write_header()
|
||||
# $1 - lang
|
||||
# $2 - size
|
||||
# $3 - count
|
||||
# $4 - checksum
|
||||
# $5 - signature
|
||||
{
|
||||
/bin/echo -n -e "\xa5\x5a\xb4\x4b" |\
|
||||
dd of=lang_$1.bin bs=1 count=4 seek=0 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e $(echo -n "$(($2))" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=4 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e $(echo -n "$(($3))" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=6 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e $(echo -n "$(($4))" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=8 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e "$(lang_code_hex_data $1)" |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=10 conv=notrunc 2>/dev/null
|
||||
sig_h=$(($5 / 65536))
|
||||
/bin/echo -n -e $(echo -n "$sig_h" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=14 conv=notrunc 2>/dev/null
|
||||
sig_l=$(($5 - $sig_h * 65536))
|
||||
/bin/echo -n -e $(echo -n "$sig_l" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=12 conv=notrunc 2>/dev/null
|
||||
}
|
||||
|
||||
generate_binary()
|
||||
# $1 - language code ('en', 'cz'...)
|
||||
{
|
||||
echo "lang="$1 >&2
|
||||
#remove output and temporary files
|
||||
rm -f lang_$1.bin
|
||||
rm -f lang_$1.tmp
|
||||
rm -f lang_$1.dat
|
||||
LNG=$1
|
||||
#check lang dictionary
|
||||
./lang-check.py $1 #--no-warning
|
||||
#create lang_xx.tmp - different processing for 'en' language
|
||||
if [ "$1" = "en" ]; then
|
||||
#remove comments and empty lines
|
||||
cat lang_en.txt | sed '/^$/d;/^#/d'
|
||||
else
|
||||
#remove comments and empty lines, print lines with translated text only
|
||||
cat lang_en_$1.txt | sed '/^$/d;/^#/d' | sed -n 'n;p'
|
||||
fi | sed 's/^\"\\x00\"$/\"\"/' > lang_$1.tmp
|
||||
#create lang_xx.dat (binary text data file)
|
||||
# cat lang_$1.tmp | sed 's/^\"/\/bin\/echo -e \"/;s/"$/\\x00\"/' > lang_$1.shx
|
||||
cat lang_$1.tmp | sed 's/^\"/\/bin\/echo -e -n \"/;s/"$/\\x00\"/' | sh >lang_$1.dat
|
||||
#calculate number of strings
|
||||
count=$(grep -c '^"' lang_$1.tmp)
|
||||
echo "count="$count >&2
|
||||
#calculate text data offset
|
||||
offs=$((16 + 2 * $count))
|
||||
echo "offs="$offs >&2
|
||||
#calculate text data size
|
||||
size=$(($offs + $(wc -c lang_$1.dat | cut -f1 -d' ')))
|
||||
echo "size="$size >&2
|
||||
#write header with empty signature and checksum
|
||||
write_header $1 $size $count 0x0000 0x00000000
|
||||
#write offset table
|
||||
offs_hex=$(cat lang_$1.tmp | sed 's/^\"//;s/\"$//' |\
|
||||
sed 's/\\x[0-9a-f][0-9a-f]/\./g;s/\\[0-7][0-7][0-7]/\./g;s/\ /\./g' |\
|
||||
awk 'BEGIN { o='$offs';} { h=int(o/256); printf("\\x%02x\\x%02x",int(o-256*h), h); o+=(length($0)+1); }')
|
||||
/bin/echo -n -e "$offs_hex" | dd of=./lang_$1.bin bs=1 seek=16 conv=notrunc 2>/dev/null
|
||||
#write binary text data
|
||||
dd if=./lang_$1.dat of=./lang_$1.bin bs=1 seek=$offs conv=notrunc 2>/dev/null
|
||||
#write signature
|
||||
if [ "$1" != "en" ]; then
|
||||
dd if=lang_en.bin of=lang_$1.bin bs=1 count=4 skip=6 seek=12 conv=notrunc 2>/dev/null
|
||||
fi
|
||||
#calculate and update checksum
|
||||
chsum=$(cat lang_$1.bin | xxd | cut -c11-49 | tr ' ' "\n" | sed '/^$/d' | awk 'BEGIN { sum = 0; } { sum += strtonum("0x"$1); if (sum > 0xffff) sum -= 0x10000; } END { printf("%x\n", sum); }')
|
||||
/bin/echo -n -e $(echo -n $((0x$chsum)) | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=8 conv=notrunc 2>/dev/null
|
||||
#remove temporary files
|
||||
# rm -f lang_$1.tmp
|
||||
# rm -f lang_$1.dat
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then set 'all'; fi
|
||||
|
||||
if [ "$1" = "all" ]; then
|
||||
generate_binary 'en'
|
||||
generate_binary 'cz'
|
||||
generate_binary 'de'
|
||||
generate_binary 'es'
|
||||
generate_binary 'fr'
|
||||
generate_binary 'it'
|
||||
generate_binary 'pl'
|
||||
#DO NOT add Community languages here !!!
|
||||
else
|
||||
generate_binary $1
|
||||
fi
|
||||
|
||||
finish 0
|
|
@ -1,29 +1,50 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Version 1.0.1
|
||||
#
|
||||
# Version 1.0.2 - Build 43
|
||||
#############################################################################
|
||||
# Change log:
|
||||
# 7 May 2019, Ondrej Tuma, Initial
|
||||
# 9 June 2020, 3d-gussner, Added version and Change log
|
||||
# 9 June 2020, 3d-gussner, Wrap text to 20 char and rows
|
||||
# 9 June 2020, 3d-gussner, colored output
|
||||
# 7 May 2019, ondratu , Initial
|
||||
# 13 June 2019, 3d-gussner, Fix length false positives
|
||||
# 14 Sep. 2019, 3d-gussner, Prepare adding new language
|
||||
# 18 Sep. 2020, 3d-gussner, Fix execution of lang-check.py
|
||||
# 2 Apr. 2021, 3d-gussner, Fix and improve text warp
|
||||
# 22 Apr. 2021, DRracer , add English source to output
|
||||
# 23 Apr. 2021, wavexx , improve
|
||||
# 24 Apr. 2021, wavexx , improve
|
||||
# 26 Apr. 2021, 3d-gussner, add character ruler
|
||||
# 26 Apr. 2021, wavexx , add character ruler
|
||||
# 21 Dec. 2021, 3d-gussner, Prepare more community languages
|
||||
# Swedish
|
||||
# Danish
|
||||
# Slovanian
|
||||
# Hungarian
|
||||
# Luxembourgian
|
||||
# Croatian
|
||||
# 3 Jan. 2022, 3d-gussner, Prepare Lithuanian
|
||||
# 7 Jan. 2022, 3d-gussner, Check for Syntax errors and exit with error
|
||||
# , add Build number 'git rev-list --count HEAD lang-check.py'
|
||||
# 30 Jan. 2022, 3d-gussner, Add arguments. Requested by @AttilaSVK
|
||||
# --information == output all source and translated messages
|
||||
# --import-check == used by `lang-import.sh`to verify
|
||||
# newly import `lang_en_??.txt` files
|
||||
# 14 Mar. 2022, 3d-gussner, Check if translation isn't equal to origin
|
||||
#############################################################################
|
||||
#
|
||||
"""Check lang files."""
|
||||
|
||||
"""Check PO files for formatting errors."""
|
||||
from argparse import ArgumentParser
|
||||
from traceback import print_exc
|
||||
from sys import stdout, stderr
|
||||
from sys import stdout, stderr, exit
|
||||
import codecs
|
||||
import polib
|
||||
import textwrap
|
||||
import re
|
||||
import os
|
||||
|
||||
from lib import charset as cs
|
||||
from lib.io import load_map
|
||||
|
||||
COLORIZE = (stdout.isatty() and os.getenv("TERM", "dumb") != "dumb") or os.getenv('NO_COLOR') == "0"
|
||||
|
||||
def color_maybe(color_attr, text):
|
||||
if stdout.isatty():
|
||||
if COLORIZE:
|
||||
return '\033[0;' + str(color_attr) + 'm' + text + '\033[0m'
|
||||
else:
|
||||
return text
|
||||
|
@ -81,188 +102,231 @@ def highlight_trailing_white(text):
|
|||
return ret
|
||||
|
||||
def wrap_text(text, cols):
|
||||
# wrap text
|
||||
ret = list(textwrap.TextWrapper(width=cols).wrap(text))
|
||||
if len(ret):
|
||||
# add back trailing whitespace
|
||||
ret[-1] += ' ' * (len(text) - len(text.rstrip()))
|
||||
ret = []
|
||||
for line in text.split('\n'):
|
||||
# wrap each input line in text individually
|
||||
tmp = list(textwrap.TextWrapper(width=cols).wrap(line))
|
||||
if len(ret):
|
||||
# add back trailing whitespace
|
||||
tmp[-1] += ' ' * (len(text) - len(text.rstrip()))
|
||||
ret.extend(tmp)
|
||||
return ret
|
||||
|
||||
def unescape(text):
|
||||
if '\\' not in text:
|
||||
return text
|
||||
return text.encode('ascii').decode('unicode_escape')
|
||||
|
||||
def ign_char_first(c):
|
||||
return c.isalnum() or c in {'%', '?'}
|
||||
|
||||
def ign_char_last(c):
|
||||
return c.isalnum() or c in {'.', "'"}
|
||||
|
||||
def check_translation(entry, msgids, is_pot, no_warning, no_suggest, warn_empty, warn_same, information):
|
||||
"""Check strings to display definition."""
|
||||
|
||||
def parse_txt(lang, no_warning, warn_empty):
|
||||
"""Parse txt file and check strings to display definition."""
|
||||
if lang == "en":
|
||||
file_path = "lang_en.txt"
|
||||
else:
|
||||
file_path = "lang_en_%s.txt" % lang
|
||||
# fetch/decode entry for easy access
|
||||
meta = entry.comment.split('\n', 1)[0]
|
||||
source = entry.msgid
|
||||
translation = entry.msgstr
|
||||
line = entry.linenum
|
||||
known_msgid = msgids is None or source in msgids
|
||||
errors = 0
|
||||
|
||||
print(green("Start %s lang-check" % lang))
|
||||
# Check comment syntax (non-empty and include a MSG id)
|
||||
if known_msgid or warn_empty:
|
||||
if len(meta) == 0:
|
||||
print(red("[E]: Translation doesn't contain any comment metadata on line %d" % line))
|
||||
return False
|
||||
if not meta.startswith('MSG'):
|
||||
print(red("[E]: Critical syntax error: comment doesn't start with MSG on line %d" % line))
|
||||
print(red(" comment: " + meta))
|
||||
return False
|
||||
|
||||
lines = 1
|
||||
with open(file_path) as src:
|
||||
while True:
|
||||
comment = src.readline().split(' ')
|
||||
#print (comment) #Debug
|
||||
# Check if columns and rows are defined
|
||||
tokens = meta.split(' ')
|
||||
cols = None
|
||||
rows = None
|
||||
for item in tokens[1:]:
|
||||
try:
|
||||
key, val = item.split('=')
|
||||
if key == 'c':
|
||||
cols = int(val)
|
||||
elif key == 'r':
|
||||
rows = int(val)
|
||||
else:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
print(red("[E]: Invalid display definition on line %d" % line))
|
||||
print(red(" definition: " + meta))
|
||||
return False
|
||||
|
||||
#Check if columns and rows are defined
|
||||
cols = None
|
||||
rows = None
|
||||
for item in comment[1:]:
|
||||
key, val = item.split('=')
|
||||
if key == 'c':
|
||||
cols = int(val)
|
||||
#print ("c=",cols) #Debug
|
||||
elif key == 'r':
|
||||
rows = int(val)
|
||||
#print ("r=",rows) #Debug
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Unknown display definition %s on line %d" %
|
||||
(' '.join(comment), lines))
|
||||
if cols is None and rows is None:
|
||||
if not no_warning:
|
||||
print(yellow("[W]: No display definition on line %d" % lines))
|
||||
cols = len(translation) # propably fullscreen
|
||||
if rows is None:
|
||||
rows = 1
|
||||
elif rows > 1 and cols != 20:
|
||||
print(yellow("[W]: Multiple rows with odd number of columns on line %d" % lines))
|
||||
if cols is None and rows is None:
|
||||
if not no_warning and known_msgid:
|
||||
errors += 1
|
||||
print(yellow("[W]: No usable display definition on line %d" % line))
|
||||
# probably fullscreen, guess from the message length to continue checking
|
||||
cols = len(source)
|
||||
if rows is None:
|
||||
rows = 1
|
||||
elif rows > 1 and cols != 20:
|
||||
errors += 1
|
||||
print(yellow("[W]: Multiple rows with odd number of columns on line %d" % line))
|
||||
|
||||
#Wrap text to 20 chars and rows
|
||||
source = src.readline()[:-1].strip('"')
|
||||
#print (source) #Debug
|
||||
translation = src.readline()[:-1].strip('"')
|
||||
if translation == '\\x00':
|
||||
# crude hack to handle intentionally-empty translations
|
||||
translation = ''
|
||||
# Check if translation contains unsupported characters
|
||||
invalid_char = cs.translation_check(cs.unicode_to_source(translation))
|
||||
if invalid_char is not None:
|
||||
print(red('[E]: Critical syntax: Unhandled char %s found on line %d' % (repr(invalid_char), line)))
|
||||
print(red(' translation: ' + translation))
|
||||
return False
|
||||
|
||||
# handle backslash sequences
|
||||
source = unescape(source)
|
||||
translation = unescape(translation)
|
||||
# Pre-process the translation to translated characters for a correct preview and length check
|
||||
translation = cs.trans_replace(translation)
|
||||
|
||||
#print (translation) #Debug
|
||||
wrapped_source = wrap_text(source, cols)
|
||||
rows_count_source = len(wrapped_source)
|
||||
wrapped_translation = wrap_text(translation, cols)
|
||||
rows_count_translation = len(wrapped_translation)
|
||||
wrapped_source = wrap_text(source, cols)
|
||||
rows_count_source = len(wrapped_source)
|
||||
wrapped_translation = wrap_text(translation, cols)
|
||||
rows_count_translation = len(wrapped_translation)
|
||||
|
||||
# Check for potential errors in the definition
|
||||
if not no_warning:
|
||||
# Incorrect number of rows/cols on the definition
|
||||
if rows == 1 and (len(source) > cols or rows_count_source > rows):
|
||||
print(yellow('[W]: Source text longer than %d cols as defined on line %d:' % (cols, lines)))
|
||||
print_ruler(4, cols);
|
||||
print_truncated(source, cols)
|
||||
print()
|
||||
elif rows_count_source > rows:
|
||||
print(yellow('[W]: Wrapped source text longer than %d rows as defined on line %d:' % (rows, lines)))
|
||||
print_ruler(6, cols);
|
||||
print_wrapped(wrapped_source, rows, cols)
|
||||
print()
|
||||
# Incorrect number of rows/cols on the definition
|
||||
if rows == 1 and (len(source) > cols or rows_count_source > rows):
|
||||
errors += 1
|
||||
print(yellow('[W]: Source text longer than %d cols as defined on line %d:' % (cols, line)))
|
||||
print_ruler(4, cols);
|
||||
print_truncated(source, cols)
|
||||
print()
|
||||
elif rows_count_source > rows:
|
||||
errors += 1
|
||||
print(yellow('[W]: Wrapped source text longer than %d rows as defined on line %d:' % (rows, line)))
|
||||
print_ruler(6, cols);
|
||||
print_wrapped(wrapped_source, rows, cols)
|
||||
print()
|
||||
|
||||
# Missing translation
|
||||
if len(translation) == 0 and (warn_empty or rows > 1):
|
||||
if rows == 1:
|
||||
print(yellow("[W]: Empty translation for \"%s\" on line %d" % (source, lines)))
|
||||
else:
|
||||
print(yellow("[W]: Empty translation on line %d" % lines))
|
||||
print_ruler(6, cols);
|
||||
print_wrapped(wrapped_source, rows, cols)
|
||||
print()
|
||||
# All further checks are against the translation
|
||||
if is_pot:
|
||||
return (errors == 0)
|
||||
|
||||
# Missing translation
|
||||
if len(translation) == 0 and (known_msgid or warn_empty):
|
||||
errors += 1
|
||||
if rows == 1:
|
||||
print(yellow("[W]: Empty translation for \"%s\" on line %d" % (source, line)))
|
||||
else:
|
||||
print(yellow("[W]: Empty translation on line %d" % line))
|
||||
print_ruler(6, cols);
|
||||
print_wrapped(wrapped_source, rows, cols)
|
||||
print()
|
||||
|
||||
# Check for translation lenght
|
||||
if (rows_count_translation > rows) or (rows == 1 and len(translation) > cols):
|
||||
print(red('[E]: Text is longer than definition on line %d: cols=%d rows=%d (rows diff=%d)'
|
||||
% (lines, cols, rows, rows_count_translation-rows)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
# Check for translation lenght
|
||||
if (rows_count_translation > rows) or (rows == 1 and len(translation) > cols):
|
||||
errors += 1
|
||||
print(red('[E]: Text is longer than definition on line %d: cols=%d rows=%d (rows diff=%d)'
|
||||
% (line, cols, rows, rows_count_translation-rows)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
|
||||
# Different count of % sequences
|
||||
if source.count('%') != translation.count('%') and len(translation) > 0:
|
||||
print(red('[E]: Unequal count of %% escapes on line %d:' % (lines)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
# Different count of % sequences
|
||||
if source.count('%') != translation.count('%') and len(translation) > 0:
|
||||
errors += 1
|
||||
print(red('[E]: Unequal count of %% escapes on line %d:' % (line)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
|
||||
# Different first/last character
|
||||
if not no_warning and len(source) > 0 and len(translation) > 0:
|
||||
source_end = source.rstrip()[-1]
|
||||
translation_end = translation.rstrip()[-1]
|
||||
start_diff = not (ign_char_first(source[0]) and ign_char_first(translation[0])) and source[0] != translation[0]
|
||||
end_diff = not (ign_char_last(source_end) and ign_char_last(translation_end)) and source_end != translation_end
|
||||
if start_diff or end_diff:
|
||||
if start_diff:
|
||||
print(yellow('[W]: Differing first punctuation character (%s => %s) on line %d:' % (source[0], translation[0], lines)))
|
||||
if end_diff:
|
||||
print(yellow('[W]: Differing last punctuation character (%s => %s) on line %d:' % (source[-1], translation[-1], lines)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
# Different first/last character
|
||||
if not no_suggest and len(source) > 0 and len(translation) > 0:
|
||||
source_end = source.rstrip()[-1]
|
||||
translation_end = translation.rstrip()[-1]
|
||||
start_diff = not (ign_char_first(source[0]) and ign_char_first(translation[0])) and source[0] != translation[0]
|
||||
end_diff = not (ign_char_last(source_end) and ign_char_last(translation_end)) and source_end != translation_end
|
||||
if start_diff or end_diff:
|
||||
if start_diff:
|
||||
print(yellow('[S]: Differing first punctuation character (%s => %s) on line %d:' % (source[0], translation[0], line)))
|
||||
if end_diff:
|
||||
print(yellow('[S]: Differing last punctuation character (%s => %s) on line %d:' % (source[-1], translation[-1], line)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
if not no_suggest and source == translation and (warn_same or len(source.split(' ', 1)) > 1):
|
||||
print(yellow('[S]: Translation same as original on line %d:' %line))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
|
||||
# Short translation
|
||||
if not no_warning and len(source) > 0 and len(translation) > 0:
|
||||
if len(translation.rstrip()) < len(source.rstrip()) / 2:
|
||||
print(yellow('[W]: Short translation on line %d:' % (lines)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
# Short translation
|
||||
if not no_suggest and len(source) > 0 and len(translation) > 0:
|
||||
if len(translation.rstrip()) < len(source.rstrip()) / 2:
|
||||
print(yellow('[S]: Short translation on line %d:' % (line)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
|
||||
# Incorrect trailing whitespace in translation
|
||||
if not no_warning and len(translation) > 0 and \
|
||||
(source.rstrip() == source or (rows == 1 and len(source) == cols)) and \
|
||||
translation.rstrip() != translation and \
|
||||
(rows > 1 or len(translation) != len(source)):
|
||||
print(yellow('[W]: Incorrect trailing whitespace for translation on line %d:' % (lines)))
|
||||
source = highlight_trailing_white(source)
|
||||
translation = highlight_trailing_white(translation)
|
||||
wrapped_translation = highlight_trailing_white(wrapped_translation)
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
# Incorrect trailing whitespace in translation
|
||||
if not no_warning and len(translation) > 0 and \
|
||||
(source.rstrip() == source or (rows == 1 and len(source) == cols)) and \
|
||||
translation.rstrip() != translation and \
|
||||
(rows > 1 or len(translation) != len(source)):
|
||||
errors += 1
|
||||
print(yellow('[W]: Incorrect trailing whitespace for translation on line %d:' % (line)))
|
||||
source = highlight_trailing_white(source)
|
||||
translation = highlight_trailing_white(translation)
|
||||
wrapped_translation = highlight_trailing_white(wrapped_translation)
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
|
||||
if len(src.readline()) != 1: # empty line
|
||||
break
|
||||
lines += 4
|
||||
print(green("End %s lang-check" % lang))
|
||||
# show the information
|
||||
if information and errors == 0:
|
||||
print(green('[I]: %s' % (meta)))
|
||||
print_source_translation(source, translation,
|
||||
wrapped_source, wrapped_translation,
|
||||
rows, cols)
|
||||
return (errors == 0)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function."""
|
||||
parser = ArgumentParser(
|
||||
description=__doc__,
|
||||
usage="%(prog)s lang")
|
||||
parser.add_argument(
|
||||
"lang", nargs='?', default="en", type=str,
|
||||
help="Check lang file (en|cs|de|es|fr|nl|it|pl)")
|
||||
parser = ArgumentParser(description=__doc__)
|
||||
parser.add_argument("po", help="PO file to check")
|
||||
parser.add_argument(
|
||||
"--no-warning", action="store_true",
|
||||
help="Disable warnings")
|
||||
parser.add_argument(
|
||||
"--no-suggest", action="store_true",
|
||||
help="Disable suggestions")
|
||||
parser.add_argument(
|
||||
"--pot", action="store_true",
|
||||
help="Do not check translations")
|
||||
parser.add_argument(
|
||||
"--information", action="store_true",
|
||||
help="Output all translations")
|
||||
parser.add_argument("--map",
|
||||
help="Provide a map file to suppress warnings about unused translations")
|
||||
parser.add_argument(
|
||||
"--warn-empty", action="store_true",
|
||||
help="Warn about empty translations")
|
||||
help="Warn about empty definitions and translations even if unused")
|
||||
parser.add_argument(
|
||||
"--warn-same", action="store_true",
|
||||
help="Warn about one-word translations which are identical to the source")
|
||||
|
||||
# load the translations
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
parse_txt(args.lang, args.no_warning, args.warn_empty)
|
||||
return 0
|
||||
except Exception as exc:
|
||||
print_exc()
|
||||
parser.error("%s" % exc)
|
||||
if not os.path.isfile(args.po):
|
||||
print("{}: file does not exist or is not a regular file".format(args.po), file=stderr)
|
||||
return 1
|
||||
|
||||
# load the symbol map to supress empty (but unused) translation warnings
|
||||
msgids = None
|
||||
if args.map:
|
||||
msgids = set()
|
||||
for sym in load_map(args.map):
|
||||
if type(sym['data']) == bytes:
|
||||
msgid = cs.source_to_unicode(codecs.decode(sym['data'], 'unicode_escape', 'strict'))
|
||||
msgids.add(msgid)
|
||||
|
||||
# check each translation in turn
|
||||
status = True
|
||||
for translation in polib.pofile(args.po):
|
||||
status &= check_translation(translation, msgids, args.pot, args.no_warning, args.no_suggest,
|
||||
args.warn_empty, args.warn_same, args.information)
|
||||
return 0 if status else os.EX_DATAERR
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang_check.sh - multi-language support script
|
||||
# check lang_xx.bin (language binary file)
|
||||
#
|
||||
# Input files:
|
||||
# lang_$1.bin
|
||||
# lang_en.txt or lang_en_$1.txt
|
||||
#
|
||||
#
|
||||
|
||||
#set 'cz'
|
||||
|
||||
#dictionary txt file
|
||||
fn_t=lang_en_$1.txt
|
||||
if [ "$1" = "en" ]; then fn_t=lang_en.txt; fi
|
||||
#binary file to check
|
||||
fn_b=lang_$1.bin
|
||||
|
||||
#check txt dictionary file
|
||||
echo -n "dictionary file: $fn_t"
|
||||
if [ -e $fn_t ]; then echo " - OK"; else echo " - Not found!"; exit 1; fi
|
||||
|
||||
#create lang_xx.tmp - different processing for 'en' language
|
||||
if [ "$1" = "en" ]; then
|
||||
#remove comments and empty lines
|
||||
cat lang_en.txt | sed '/^$/d;/^#/d'
|
||||
else
|
||||
#remove comments and empty lines, print lines with translated text only
|
||||
cat lang_en_$1.txt | sed '/^$/d;/^#/d' | sed -n 'n;p'
|
||||
fi | sed 's/^\"\\x00\"$/\"\"/' > lang_$1.tmp
|
||||
|
||||
count_txt=$(grep -c '^"' lang_$1.tmp)
|
||||
|
||||
echo -n "language bin file: $fn_b"
|
||||
if [ -e $fn_b ]; then echo " - OK"; else echo " - Not found!"; exit 1; fi
|
||||
|
||||
#read header and convert to hex
|
||||
header=$(dd if=$fn_b bs=1 count=16 2>/dev/null | xxd | cut -c11-49 | sed 's/\([0-9a-f][0-9a-f]\)[\ ]*/\1 /g')
|
||||
echo "header='$header'"
|
||||
magic=0x$(echo $header | tr -d ' ' | cut -c1-8)
|
||||
echo "magic='$magic'"
|
||||
size=$(echo $header | tr -d ' ' | cut -c9-12)
|
||||
size=0x${size:2:2}${size:0:2}
|
||||
echo "size='$size' ($(($size)))"
|
||||
count=$(echo $header | tr -d ' ' | cut -c13-16)
|
||||
count=0x${count:2:2}${count:0:2}
|
||||
echo "count='$count' ($(($count)))"
|
||||
o=0
|
||||
l=0
|
||||
#create lang_xx_1.tmp (temporary text file from binary data)
|
||||
(dd if=$fn_b bs=1 count=$((2*$count)) skip=16 2>/dev/null | xxd | cut -c11-49 | tr ' ' "\n" |\
|
||||
sed 's/\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)/\2\1 /g;/^$/d'; printf "%04x\n" $(($size)) ) |\
|
||||
while read offs; do
|
||||
if [ $o -ne 0 ]; then
|
||||
l=$((0x$offs - $o))
|
||||
echo -n '"'
|
||||
dd if=$fn_b bs=1 count=$((l-1)) skip=$o 2>/dev/null
|
||||
echo '"'
|
||||
fi
|
||||
o=$((0x$offs))
|
||||
done > lang_$1_1.tmp
|
||||
#create lang_xx_2.tmp (temporary text file from dictionary)
|
||||
cat lang_$1.tmp | sed 's/^\"/printf \"\\x22/;s/"$/\\x22\\x0a\"/' | sh >lang_$1_2.tmp
|
||||
#compare temporary files
|
||||
diff -a lang_$1_1.tmp lang_$1_2.tmp >lang_$1_check.dif
|
||||
dif=$(cat lang_$1_check.dif)
|
||||
if [ -z "$dif" ]; then
|
||||
echo 'binary data OK'
|
||||
else
|
||||
echo 'binary data NG!'
|
||||
fi
|
||||
|
||||
read -t 5
|
||||
exit
|
|
@ -1,68 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# clean.sh - multi-language support script
|
||||
# Remove all language output files from lang folder.
|
||||
#
|
||||
|
||||
result=0
|
||||
|
||||
rm_if_exists()
|
||||
{
|
||||
if [ -e $1 ]; then
|
||||
echo -n " removing '$1'..." >&2
|
||||
if rm $1; then
|
||||
echo "OK" >&2
|
||||
else
|
||||
echo "NG!" >&2
|
||||
result=1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
clean_lang()
|
||||
{
|
||||
if [ "$1" = "en" ]; then
|
||||
rm_if_exists lang_$1.tmp
|
||||
else
|
||||
rm_if_exists lang_$1.tmp
|
||||
rm_if_exists lang_en_$1.tmp
|
||||
rm_if_exists lang_en_$1.dif
|
||||
rm_if_exists lang_$1.ofs
|
||||
rm_if_exists lang_$1.txt
|
||||
fi
|
||||
rm_if_exists lang_$1_check.dif
|
||||
rm_if_exists lang_$1.bin
|
||||
rm_if_exists lang_$1.dat
|
||||
rm_if_exists lang_$1_1.tmp
|
||||
rm_if_exists lang_$1_2.tmp
|
||||
}
|
||||
|
||||
echo "lang-clean.sh started" >&2
|
||||
|
||||
clean_lang en
|
||||
clean_lang cz
|
||||
clean_lang de
|
||||
clean_lang es
|
||||
clean_lang fr
|
||||
clean_lang it
|
||||
clean_lang pl
|
||||
#Community language support
|
||||
#Dutch
|
||||
clean_lang nl
|
||||
|
||||
#Use the 2 lines below as a template and replace 'qr'
|
||||
##New language
|
||||
#clean_lang_qr
|
||||
|
||||
echo -n "lang-clean.sh finished" >&2
|
||||
if [ $result -eq 0 ]; then
|
||||
echo " with success" >&2
|
||||
else
|
||||
echo " with errors!" >&2
|
||||
fi
|
||||
|
||||
case "$-" in
|
||||
*i*) echo "press enter key" >&2; read ;;
|
||||
esac
|
||||
|
||||
exit $result
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# lang-community.sh - Community language support script
|
||||
# Check community languages are defined in `config.h`
|
||||
#
|
||||
|
||||
# Root path
|
||||
if [ -z "$ROOT_PATH" ]; then
|
||||
export ROOT_PATH=".."
|
||||
fi
|
||||
|
||||
# Check community language NL = Dutch
|
||||
COMMUNITY_LANG_NL=$(grep --max-count=1 "^#define COMMUNITY_LANG_NL" $ROOT_PATH/Firmware/config.h| cut -d '_' -f3 |cut -d ' ' -f1)
|
||||
export NL=$COMMUNITY_LANG_NL
|
||||
|
||||
# Use the lines below as a template and replace 'QR' and 'new language'
|
||||
# Check comminity language QR = new language
|
||||
#COMMUNITY_LANG_QR=$(grep --max-count=1 "^#define COMMUNITY_LANG_QR" $ROOT_PATH/Firmware/config.h| cut -d '_' -f3 |cut -d ' ' -f1)
|
||||
#export QR=$COMMUNITY_LANG_QR
|
||||
|
||||
#startup message
|
||||
echo "lang-community.sh started" >&2
|
||||
echo -n " Source code path: " >&2
|
||||
if [ -e $ROOT_PATH ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=1; fi
|
||||
|
||||
echo " Found: " >&2
|
||||
if [ "$COMMUNITY_LANG_NL" = "NL" ]; then
|
||||
echo " $COMMUNITY_LANG_NL" >&2
|
||||
echo
|
||||
./lang-build.sh nl
|
||||
fi
|
||||
|
||||
# Use the 5 lines below as a template and replace 'QR' and 'qr'
|
||||
#if [ "$COMMUNITY_LANG_QR" = "QR" ]; then
|
||||
# echo " $COMMUNITY_LANG_QR" >&2
|
||||
# echo
|
||||
# ./lang-build.sh qr
|
||||
#fi
|
||||
|
||||
|
||||
#exiting function
|
||||
finish()
|
||||
{
|
||||
if [ $1 -eq 0 ]; then
|
||||
echo "lang-community.sh finished with success" >&2
|
||||
else
|
||||
echo "lang-community.sh finished with errors!" >&2
|
||||
fi
|
||||
echo
|
||||
exit $1
|
||||
}
|
||||
|
||||
finish 0
|
|
@ -1,145 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang-export.sh - multi-language support script
|
||||
# for generating lang_xx.po
|
||||
#
|
||||
|
||||
# relative path to source folder
|
||||
SRCDIR="../Firmware"
|
||||
|
||||
# selected language is 1st argument (cz, de, ...)
|
||||
LNG=$1
|
||||
|
||||
# if no arguments, 'all' is selected (all po and also pot will be generated)
|
||||
if [ -z "$LNG" ]; then LNG=all; fi
|
||||
|
||||
# if 'all' is selected, script will generate all po files and also pot file
|
||||
if [ "$LNG" = "all" ]; then
|
||||
./lang-export.sh en
|
||||
./lang-export.sh cz
|
||||
./lang-export.sh de
|
||||
./lang-export.sh es
|
||||
./lang-export.sh fr
|
||||
./lang-export.sh it
|
||||
./lang-export.sh pl
|
||||
#Community language support
|
||||
#Dutch
|
||||
./lang-export.sh nl
|
||||
#Use the 2 lines below as a template and replace 'qr' and 'New language'
|
||||
##New language
|
||||
# ./lang-export.sh qr
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# language code (iso639-1) is equal to LNG
|
||||
LNGISO=$LNG
|
||||
# exception for 'cz' (code='cs')
|
||||
if [ "$LNG" = "cz" ]; then LNGISO=cs; fi
|
||||
|
||||
# po/pot creation/revision date
|
||||
DATE=$(date)
|
||||
|
||||
# if 'en' is selected, generate pot instead of po
|
||||
if [ "$LNG" = "en" ]; then
|
||||
INFILE=lang_en.txt
|
||||
OUTFILE=po/Firmware.pot
|
||||
LNGNAME="English"
|
||||
else
|
||||
# language name in english
|
||||
LNGNAME=$(\
|
||||
case "$LNG" in
|
||||
*cz*) echo "Czech" ;;
|
||||
*de*) echo "German" ;;
|
||||
*es*) echo "Spanish" ;;
|
||||
*fr*) echo "French" ;;
|
||||
*it*) echo "Italian" ;;
|
||||
*pl*) echo "Polish" ;;
|
||||
#Community language support
|
||||
#Dutch
|
||||
*nl*) echo "Dutch" ;;
|
||||
#Use the 2 lines below as a template and replace 'qr' and 'New language'
|
||||
##New language
|
||||
# *qr*) echo "New language" ;;
|
||||
esac)
|
||||
# unknown language - error
|
||||
if [ -z "LNGNAME" ]; then
|
||||
echo "Invalid argument '$LNG'."
|
||||
exit 1
|
||||
fi
|
||||
INFILE=lang_en_$LNG.txt
|
||||
OUTFILE=po/Firmware_$LNGISO.po
|
||||
fi
|
||||
|
||||
# remove output file if exists
|
||||
if [ -e $OUTFILE ]; then rm -f -v $OUTFILE; fi
|
||||
|
||||
echo "lang-export.sh started"
|
||||
|
||||
#total strings
|
||||
CNTTXT=$(grep '^#' -c $INFILE)
|
||||
#not translated strings
|
||||
CNTNT=$(grep '^\"\\x00\"' -c $INFILE)
|
||||
echo " $CNTTXT texts, $CNTNT not translated"
|
||||
|
||||
# list .cpp, .c and .h files from source folder
|
||||
SRCFILES=$(ls "$SRCDIR"/*.cpp "$SRCDIR"/*.c "$SRCDIR"/*.h)
|
||||
|
||||
echo " selected language=$LNGNAME"
|
||||
|
||||
# write po/pot header
|
||||
(
|
||||
echo "# Translation of Prusa-Firmware into $LNGNAME."
|
||||
echo "#"
|
||||
echo 'msgid ""'
|
||||
echo 'msgstr ""'
|
||||
echo '"MIME-Version: 1.0\n"'
|
||||
echo '"Content-Type: text/plain; charset=UTF-8\n"'
|
||||
echo '"Content-Transfer-Encoding: 8bit\n"'
|
||||
echo '"Language: '$LNGISO'\n"'
|
||||
echo '"Project-Id-Version: Prusa-Firmware\n"'
|
||||
echo '"POT-Creation-Date: '$DATE'\n"'
|
||||
echo '"PO-Revision-Date: '$DATE'\n"'
|
||||
echo '"Language-Team: \n"'
|
||||
echo '"X-Generator: Poedit 2.0.7\n"'
|
||||
echo '"X-Poedit-SourceCharset: UTF-8\n"'
|
||||
echo '"Last-Translator: \n"'
|
||||
echo '"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"'
|
||||
echo
|
||||
) >$OUTFILE
|
||||
|
||||
#loop over all messages
|
||||
s0=''
|
||||
s1=''
|
||||
s2=''
|
||||
num=1
|
||||
(cat $INFILE | sed "s/\\\\/\\\\\\\\/g" | while read -r s; do
|
||||
if [ "$s" = "" ]; then
|
||||
echo " processing $num of $CNTTXT" >&2
|
||||
# write po/pot item
|
||||
(
|
||||
if [ -z "$s2" ]; then s2=$s1; s1=$s0; s0='""'; fi
|
||||
search=$(/bin/echo -e "$s1")
|
||||
found=$(grep -m1 -n -F "$search" $SRCFILES | head -n1 | cut -f1-2 -d':' | sed "s/^.*\///")
|
||||
echo "$s2" | sed 's/ c=0//;s/ r=0//;s/^#/# /'
|
||||
echo "#: $found"
|
||||
/bin/echo -e "msgid $s1"
|
||||
if [ "$s0" = "\"\\\\x00\"" ]; then
|
||||
echo 'msgstr ""'
|
||||
else
|
||||
/bin/echo -e "msgstr $s0"
|
||||
fi
|
||||
echo
|
||||
)
|
||||
num=$((num+1))
|
||||
fi
|
||||
s2=$s1
|
||||
s1=$s0
|
||||
s0=$s
|
||||
done >>$OUTFILE) 2>&1
|
||||
|
||||
#replace LF with CRLF
|
||||
sync
|
||||
sed -i 's/$/\r/' $OUTFILE
|
||||
|
||||
echo "lang-export.sh finished"
|
||||
exit 0
|
305
lang/lang-extract.py
Executable file
305
lang/lang-extract.py
Executable file
|
@ -0,0 +1,305 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import bisect
|
||||
import codecs
|
||||
import polib
|
||||
import regex
|
||||
import sys
|
||||
import lib.charset as cs
|
||||
|
||||
def line_warning(path, line, msg):
|
||||
print(f'{path}:{line}: {msg}', file=sys.stderr)
|
||||
|
||||
def line_error(path, line, msg):
|
||||
print(f'{path}:{line}: {msg}', file=sys.stderr)
|
||||
|
||||
def entry_warning_locs(entries):
|
||||
for msgid, data in entries:
|
||||
print(' text: ' + repr(msgid), file=sys.stderr)
|
||||
positions = ', '.join(map(lambda x: x[0] + ':' + str(x[1]), data['occurrences']))
|
||||
print(' in: ' + positions, file=sys.stderr)
|
||||
|
||||
def entries_warning(entries, msg):
|
||||
print('warning: ' + msg, file=sys.stderr)
|
||||
entry_warning_locs(entries)
|
||||
|
||||
def entry_warning(entry, msg):
|
||||
entries_warning([entry], msg)
|
||||
|
||||
|
||||
def newline_positions(source):
|
||||
lines = [-1]
|
||||
while True:
|
||||
idx = source.find('\n', lines[-1] + 1)
|
||||
if idx < 0:
|
||||
break
|
||||
lines.append(idx)
|
||||
if lines[-1] != len(source) - 1:
|
||||
lines.append(len(source) - 1)
|
||||
return lines[1:]
|
||||
|
||||
def index_to_line(index, lines):
|
||||
return bisect.bisect_left(lines, index) + 1
|
||||
|
||||
|
||||
def extract_file(path, catalog, warn_skipped=False):
|
||||
source = open(path).read()
|
||||
newlines = newline_positions(source)
|
||||
|
||||
# match internationalized quoted strings
|
||||
RE_START = r'\b (_[iI]|ISTR) \s* \('
|
||||
RE_META = r'//// \s* ([^\n]*)$'
|
||||
|
||||
RE_I = fr'''
|
||||
(?<!(?:/[/*]|^\s*\#) [^\n]*) # not on a comment or preprocessor
|
||||
{RE_START} # $1 ref type _i( or ISTR(
|
||||
(?:
|
||||
\s*
|
||||
("(?:[^"\\]|\\.)*") # $2 quoted string (chunk)
|
||||
(?:\s* {RE_META} )? # $3 inline metadata
|
||||
)+
|
||||
\s* \) # )
|
||||
(?:
|
||||
(?:[^\n] (?!{RE_START}))* # anything except another entry
|
||||
{RE_META} # $5 final metadata
|
||||
)?
|
||||
'''
|
||||
|
||||
r_ref_type = 1
|
||||
r_quoted_chunk = 2
|
||||
r_inline_data = 3
|
||||
r_eol_data = 5
|
||||
|
||||
for m in regex.finditer(RE_I, source, regex.M|regex.X):
|
||||
# parse the text
|
||||
line = index_to_line(m.start(0), newlines)
|
||||
|
||||
text = ""
|
||||
for block in m.captures(r_quoted_chunk):
|
||||
# remove quotes and unescape
|
||||
block = block[1:-1]
|
||||
block = codecs.decode(block, 'unicode-escape', 'strict')
|
||||
block = cs.source_to_unicode(block)
|
||||
text += block
|
||||
|
||||
# check if text is non-empty
|
||||
if len(text) == 0:
|
||||
line_warning(path, line, 'empty source text, ignored')
|
||||
continue
|
||||
|
||||
data = set()
|
||||
comments = set()
|
||||
for n in [r_inline_data, r_eol_data]:
|
||||
meta = m.group(n)
|
||||
if meta is not None:
|
||||
meta_parts = meta.split('//', 1)
|
||||
data.add(meta_parts[0].strip())
|
||||
if len(meta_parts) > 1:
|
||||
comments.add(meta_parts[1].strip())
|
||||
|
||||
# check if this message should be ignored
|
||||
ignored = False
|
||||
for meta in data:
|
||||
if regex.search(r'\bIGNORE\b', meta) is not None:
|
||||
ignored = True
|
||||
break
|
||||
if ignored:
|
||||
if warn_skipped:
|
||||
line_warning(path, line, 'skipping explicitly ignored translation')
|
||||
continue
|
||||
|
||||
# extra message catalog name (if any)
|
||||
cat_name = set()
|
||||
for meta in data:
|
||||
sm = regex.search(r'\b(MSG_\w+)', meta)
|
||||
if sm is not None:
|
||||
cat_name.add(sm.group(1))
|
||||
|
||||
# reference type annotation
|
||||
ref_type = 'def' if m.group(r_ref_type) == 'ISTR' else 'ref'
|
||||
if ref_type == 'def':
|
||||
# ISTR definition: lookup nearby assignment
|
||||
lineup_def = source[newlines[line-2]+1:m.end(r_ref_type)]
|
||||
sm = regex.search(r'\b PROGMEM_(\S+) \s*=\s* ISTR $', lineup_def, regex.M|regex.X)
|
||||
if sm is None:
|
||||
line_warning(path, line, 'ISTR not used in an assignment')
|
||||
elif sm.group(1) != 'I1':
|
||||
line_warning(path, line, 'ISTR not used with PROGMEM_I1')
|
||||
|
||||
# append the translation to the catalog
|
||||
pos = [(path, line)]
|
||||
entry = catalog.get(text)
|
||||
if entry is None:
|
||||
catalog[text] = {'occurrences': set(pos),
|
||||
'data': data,
|
||||
'cat_name': cat_name,
|
||||
'comments': comments,
|
||||
'ref_type': set([ref_type])}
|
||||
else:
|
||||
entry['occurrences'] = entry['occurrences'].union(pos)
|
||||
entry['data'] = entry['data'].union(data)
|
||||
entry['cat_name'] = entry['cat_name'].union(cat_name)
|
||||
entry['comments'] = entry['comments'].union(comments)
|
||||
entry['ref_type'].add(ref_type)
|
||||
|
||||
|
||||
def extract_refs(path, catalog):
|
||||
source = open(path).read()
|
||||
newlines = newline_positions(source)
|
||||
|
||||
# match message catalog references to add backrefs
|
||||
RE_CAT = r'''
|
||||
(?<!(?:/[/*]|^\s*\#) [^\n]*) # not on a comment or preprocessor
|
||||
\b (?:_[TO]) \s* \( \s* (\w+) \s* \) # $1 catalog name
|
||||
'''
|
||||
|
||||
for m in regex.finditer(RE_CAT, source, regex.M|regex.X):
|
||||
line = index_to_line(m.start(0), newlines)
|
||||
pos = [(path, line)]
|
||||
cat_name = m.group(1)
|
||||
found = False
|
||||
defined = False
|
||||
for entry in catalog.values():
|
||||
if cat_name in entry['cat_name']:
|
||||
entry['occurrences'] = entry['occurrences'].union(pos)
|
||||
entry['ref_type'].add('ref')
|
||||
found = True
|
||||
if 'def' in entry['ref_type']:
|
||||
defined = True
|
||||
if not found:
|
||||
line_error(path, line, f'{cat_name} not found')
|
||||
elif not defined:
|
||||
line_error(path, line, f'{cat_name} referenced but never defined')
|
||||
|
||||
|
||||
def check_entries(catalog, warn_missing, warn_same_line):
|
||||
cat_entries = {}
|
||||
|
||||
for entry in catalog.items():
|
||||
msgid, data = entry
|
||||
|
||||
# ensure we have at least one name
|
||||
if len(data['cat_name']) == 0 and warn_missing:
|
||||
entry_warning(entry, 'missing MSG identifier')
|
||||
|
||||
# ensure references are being defined
|
||||
if data['ref_type'] == set(['def']):
|
||||
if len(data['cat_name']) == 0:
|
||||
if warn_missing:
|
||||
entry_warning(entry, 'entry defined, but never used')
|
||||
else:
|
||||
id_name = next(iter(data['cat_name']))
|
||||
entry_warning(entry, f'{id_name} defined, but never used')
|
||||
|
||||
# check custom characters
|
||||
invalid_char = cs.source_check(msgid)
|
||||
if invalid_char is not None:
|
||||
entry_warning(entry, 'source contains unhandled custom character ' + repr(invalid_char))
|
||||
|
||||
tokens = []
|
||||
for meta in data['data']:
|
||||
tokens.extend(regex.split(r'\s+', meta))
|
||||
seen_keys = set()
|
||||
for token in tokens:
|
||||
if len(token) == 0:
|
||||
continue
|
||||
|
||||
# check metadata syntax
|
||||
if regex.match(r'[cr]=\d+$', token) is None and \
|
||||
regex.match(r'MSG_[A-Z_0-9]+$', token) is None:
|
||||
entry_warning(entry, 'bogus annotation: ' + repr(token))
|
||||
|
||||
# check for repeated keys
|
||||
key = regex.match(r'([^=])+=', token)
|
||||
if key is not None:
|
||||
key_name = key.group(1)
|
||||
if key_name in seen_keys:
|
||||
entry_warning(entry, 'repeated annotation: ' + repr(token))
|
||||
else:
|
||||
seen_keys.add(key_name)
|
||||
|
||||
# build the inverse catalog map
|
||||
if token.startswith('MSG_'):
|
||||
if token not in cat_entries:
|
||||
cat_entries[token] = [entry]
|
||||
else:
|
||||
cat_entries[token].append(entry)
|
||||
|
||||
# ensure the same id is not used in multiple entries
|
||||
for cat_name, entries in cat_entries.items():
|
||||
if len(entries) > 1:
|
||||
entries_warning(entries, f'{cat_name} used in multiple translations')
|
||||
|
||||
if warn_same_line:
|
||||
# build the inverse location map
|
||||
entry_locs = {}
|
||||
for entry in catalog.items():
|
||||
msgid, data = entry
|
||||
for loc in data['occurrences']:
|
||||
if loc not in entry_locs:
|
||||
entry_locs[loc] = [loc]
|
||||
else:
|
||||
entry_locs[loc].append(loc)
|
||||
|
||||
# check for multiple translations on the same location
|
||||
for loc, entries in entry_locs.items():
|
||||
if len(entries) > 1:
|
||||
line_warning(loc[0], loc[1], f'line contains multiple translations')
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('-o', dest='pot', required=True, help='PO template output file')
|
||||
ap.add_argument('--no-missing', action='store_true',
|
||||
help='Do not warn about missing MSG entries')
|
||||
ap.add_argument('--warn-same-line', action='store_true',
|
||||
help='Warn about multiple translations on the same line')
|
||||
ap.add_argument('--warn-skipped', action='store_true',
|
||||
help='Warn about explicitly ignored translations')
|
||||
ap.add_argument('-s', '--sort', action='store_true',
|
||||
help='Sort output catalog')
|
||||
ap.add_argument('file', nargs='+', help='Input files')
|
||||
args = ap.parse_args()
|
||||
|
||||
# extract strings
|
||||
catalog = {}
|
||||
for path in args.file:
|
||||
extract_file(path, catalog, warn_skipped=args.warn_skipped)
|
||||
|
||||
# process backreferences in a 2nd pass
|
||||
for path in args.file:
|
||||
extract_refs(path, catalog)
|
||||
|
||||
# check the catalog entries
|
||||
check_entries(catalog, warn_missing=not args.no_missing, warn_same_line=args.warn_same_line)
|
||||
|
||||
# write the output PO template
|
||||
po = polib.POFile()
|
||||
po.metadata = {
|
||||
'Language': 'en',
|
||||
'MIME-Version': '1.0',
|
||||
'Content-Type': 'text/plain; charset=utf-8',
|
||||
'Content-Transfer-Encoding': '8bit'}
|
||||
|
||||
messages = catalog.keys()
|
||||
if args.sort:
|
||||
messages = sorted(messages)
|
||||
for msgid in messages:
|
||||
data = catalog[msgid]
|
||||
comment = ', '.join(data['data'])
|
||||
if len(data['comments']):
|
||||
comment += '\n' + '\n'.join(data['comments'])
|
||||
occurrences = data['occurrences']
|
||||
if args.sort:
|
||||
occurrences = list(sorted(occurrences))
|
||||
po.append(
|
||||
polib.POEntry(
|
||||
msgid=msgid,
|
||||
comment=comment,
|
||||
occurrences=occurrences))
|
||||
|
||||
po.save(args.pot)
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
|
@ -1,200 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang-import.sh - multi-language support script
|
||||
# for importing translated xx.po
|
||||
|
||||
LNG=$1
|
||||
# if no arguments, 'all' is selected (all po and also pot will be generated)
|
||||
if [ -z "$LNG" ]; then LNG=all; fi
|
||||
|
||||
# if 'all' is selected, script will generate all po files and also pot file
|
||||
if [ "$LNG" = "all" ]; then
|
||||
./lang-import.sh cz
|
||||
./lang-import.sh de
|
||||
./lang-import.sh es
|
||||
./lang-import.sh fr
|
||||
./lang-import.sh it
|
||||
./lang-import.sh pl
|
||||
#DO NOT add Community languages here !!!
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# language code (iso639-1) is equal to LNG
|
||||
LNGISO=$LNG
|
||||
# exception for 'cz' (code='cs')
|
||||
if [ "$LNG" = "cz" ]; then LNGISO=cs; fi
|
||||
|
||||
# cd to input folder
|
||||
cd po/new
|
||||
|
||||
# check if input file exists
|
||||
if ! [ -e $LNGISO.po ]; then
|
||||
echo "Input file $LNGISO.po not found!" >&2
|
||||
exit -1
|
||||
fi
|
||||
|
||||
#convert '\\e' sequencies to 'x1b' and '\\' to '\'
|
||||
cat $LNGISO.po | sed 's/\\e/\\x1b/g;s/\\\\/\\/g' > $LNG'_filtered.po'
|
||||
|
||||
#replace '\n' with ' ' (single space)
|
||||
sed -i 's/ \\n/ /g;s/\\n/ /g' $LNG'_filtered.po'
|
||||
|
||||
#replace in czech translation
|
||||
if [ "$LNG" = "cz" ]; then
|
||||
#replace 'ž' with 'z'
|
||||
sed -i 's/\xc5\xbe/z/g' $LNG'_filtered.po'
|
||||
#replace 'ì' with 'e'
|
||||
sed -i 's/\xc4\x9b/e/g' $LNG'_filtered.po'
|
||||
#replace 'í' with 'i'
|
||||
sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
|
||||
#replace 'ø' with 'r'
|
||||
sed -i 's/\xc5\x99/r/g' $LNG'_filtered.po'
|
||||
#replace 'è' with 'c'
|
||||
sed -i 's/\xc4\x8d/c/g' $LNG'_filtered.po'
|
||||
#replace 'á' with 'a'
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in german translation https://en.wikipedia.org/wiki/German_orthography
|
||||
if [ "$LNG" = "de" ]; then
|
||||
#replace 'ä' with 'ae'
|
||||
sed -i 's/\xc3\xa4/ae/g' $LNG'_filtered.po'
|
||||
#replace 'Ä' with 'Ae'
|
||||
sed -i 's/\xc3\x84/Ae/g' $LNG'_filtered.po'
|
||||
#replace 'ü' with 'ue'
|
||||
sed -i 's/\xc3\xbc/ue/g' $LNG'_filtered.po'
|
||||
#replace 'Ü' with 'Ue'
|
||||
sed -i 's/\xc3\x9c/Ue/g' $LNG'_filtered.po'
|
||||
#replace 'ö' with 'oe'
|
||||
sed -i 's/\xc3\xb6/oe/g' $LNG'_filtered.po'
|
||||
#replace 'Ö' with 'Oe'
|
||||
sed -i 's/\xc3\x96/Oe/g' $LNG'_filtered.po'
|
||||
#replace 'ß' with 'ss'
|
||||
sed -i 's/\xc3\x9f/ss/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in spain translation
|
||||
if [ "$LNG" = "es" ]; then
|
||||
#replace 'á' with 'a'
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace '¿' with '?'
|
||||
sed -i 's/\xc2\xbf/?/g' $LNG'_filtered.po'
|
||||
#replace 'ó' with 'o'
|
||||
sed -i 's/\xc3\xb3/o/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'í' with 'i'
|
||||
sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
|
||||
#replace '!' with '!'
|
||||
sed -i 's/\xc2\xa1/!/g' $LNG'_filtered.po'
|
||||
#replace 'n~' with 'n'
|
||||
sed -i 's/\xc3\xb1/n/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in french translation https://en.wikipedia.org/wiki/French_orthography
|
||||
if [ "$LNG" = "fr" ]; then
|
||||
#replace 'á' with 'a' (right)
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace 'Á' with 'A' (right)
|
||||
sed -i 's/\xc3\x81/A/g' $LNG'_filtered.po'
|
||||
#replace 'à' with 'a' (left)
|
||||
sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
|
||||
#replace 'À' with 'A' (left)
|
||||
sed -i 's/\xc3\x80/A/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e' (right)
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'É' with 'E' (right)
|
||||
sed -i 's/\xc3\x89/E/g' $LNG'_filtered.po'
|
||||
#replace 'è' with 'e' (left)
|
||||
sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
|
||||
#replace 'È' with 'E' (left)
|
||||
sed -i 's/\xc3\x88/E/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in italian translation
|
||||
if [ "$LNG" = "it" ]; then
|
||||
#replace 'é' with 'e' (left)
|
||||
sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
|
||||
#replace 'á' with 'a' (left)
|
||||
sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
|
||||
#replace 'ó' with 'o' (left)
|
||||
sed -i 's/\xc3\xb2/o/g' $LNG'_filtered.po'
|
||||
#replace 'ú' with 'u' (left)
|
||||
sed -i 's/\xc3\xb9/u/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'É' with 'E' (left)
|
||||
sed -i 's/\xc3\x88/E/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in dutch translation according to https://nl.wikipedia.org/wiki/Accenttekens_in_de_Nederlandse_spelling
|
||||
if [ "$LNG" = "nl" ]; then
|
||||
#replace 'ë' with 'e'
|
||||
sed -i 's/\xc3\xab/e/g' $LNG'_filtered.po'
|
||||
#replace 'ï' with 'i'
|
||||
sed -i 's/\xc3\xaf/i/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'è' with 'e' (left)
|
||||
sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
|
||||
#replace 'ö' with 'o' (left)
|
||||
sed -i 's/\xc3\xb6/o/g' $LNG'_filtered.po'
|
||||
#replace 'ê' with 'e' (left)
|
||||
sed -i 's/\xc3\xaa/e/g' $LNG'_filtered.po'
|
||||
#replace 'ü' with 'u' (left)
|
||||
sed -i 's/\xc3\xbc/u/g' $LNG'_filtered.po'
|
||||
#replace 'ç' with 'c' (left)
|
||||
sed -i 's/\xc3\xa7/c/g' $LNG'_filtered.po'
|
||||
#replace 'á' with 'a' (left)
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace 'à' with 'a' (left)
|
||||
sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
|
||||
#replace 'ä' with 'a' (left)
|
||||
sed -i 's/\xc3\xa4/a/g' $LNG'_filtered.po'
|
||||
#replace 'û' with 'u' (left)
|
||||
sed -i 's/\xc3\xbc/u/g' $LNG'_filtered.po'
|
||||
#replace 'î' with 'i' (left)
|
||||
sed -i 's/\xc3\xae/i/g' $LNG'_filtered.po'
|
||||
#replace 'í' with 'i' (left)
|
||||
sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
|
||||
#replace 'ô' with 'o' (left)
|
||||
sed -i 's/\xc3\xb4/o/g' $LNG'_filtered.po'
|
||||
#replace 'ú' with 'u' (left)
|
||||
sed -i 's/\xc3\xba/u/g' $LNG'_filtered.po'
|
||||
#replace 'ñ' with 'n' (left)
|
||||
sed -i 's/\xc3\xb1/n/g' $LNG'_filtered.po'
|
||||
#replace 'â' with 'a' (left)
|
||||
sed -i 's/\xc3\xa2/a/g' $LNG'_filtered.po'
|
||||
#replace 'Å' with 'A' (left)
|
||||
sed -i 's/\xc3\x85/A/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in polish translation
|
||||
#if [ "$LNG" = "pl" ]; then
|
||||
#fi
|
||||
|
||||
#check for nonasci characters
|
||||
if grep --color='auto' -P -n '[^\x00-\x7F]' $LNG'_filtered.po' >nonasci.txt; then
|
||||
exit
|
||||
fi
|
||||
|
||||
#join lines with multi-line string constants
|
||||
cat $LNG'_filtered.po' | sed ':a;N;$!ba;s/\x22\n\x22//g' > $LNG'_new.po'
|
||||
|
||||
#generate new dictionary
|
||||
cat ../../lang_en.txt | sed 's/\\/\\\\/g' | while read -r s; do
|
||||
/bin/echo -e "$s"
|
||||
if [ "${s:0:1}" = "\"" ]; then
|
||||
# /bin/echo -e "$s"
|
||||
s=$(/bin/echo -e "$s")
|
||||
s2=$(grep -F -A1 -B0 "$s" "$LNG"_new.po | tail -n1 | sed 's/^msgstr //')
|
||||
if [ -z "$s2" ]; then
|
||||
echo '"\x00"'
|
||||
else
|
||||
echo "$s2"
|
||||
fi
|
||||
# echo
|
||||
fi
|
||||
done > lang_en_$LNG.txt
|
124
lang/lang-map.py
Executable file
124
lang/lang-map.py
Executable file
|
@ -0,0 +1,124 @@
|
|||
#!/usr/bin/env python3
|
||||
from collections import defaultdict
|
||||
import argparse
|
||||
import elftools.elf.elffile
|
||||
import struct
|
||||
import sys
|
||||
import zlib
|
||||
|
||||
from lib.io import warn
|
||||
|
||||
|
||||
def warn_sym(name, start, size, msg):
|
||||
warn(f'{name}[{start:x}+{size:x}]: {msg}')
|
||||
|
||||
|
||||
def get_lang_symbols(elf, symtab):
|
||||
# fetch language markers
|
||||
pri_start = symtab.get_symbol_by_name("__loc_pri_start")[0].entry.st_value
|
||||
pri_end = symtab.get_symbol_by_name("__loc_pri_end")[0].entry.st_value
|
||||
text_data = elf.get_section_by_name('.text').data()
|
||||
|
||||
# extract translatable symbols
|
||||
syms = []
|
||||
sym_id = 0
|
||||
for sym in sorted(symtab.iter_symbols(), key=lambda x: x.entry.st_value):
|
||||
sym_start = sym.entry.st_value
|
||||
sym_size = sym.entry.st_size
|
||||
sym_end = sym_start + sym_size
|
||||
if sym_start >= pri_start and sym_end < pri_end and sym_size > 0:
|
||||
data = text_data[sym_start:sym_end]
|
||||
|
||||
# perform basic checks on the language section
|
||||
if data[0] != 255 or data[1] != 255:
|
||||
warn_sym(sym.name, sym_start, sym_size, 'invalid location offset')
|
||||
if data[-1] != 0:
|
||||
warn_sym(sym.name, sym_start, sym_size, 'unterminated string')
|
||||
|
||||
syms.append({'start': sym_start,
|
||||
'size': sym_size,
|
||||
'name': sym.name,
|
||||
'id': sym_id,
|
||||
'data': data[2:-1]})
|
||||
sym_id += 1
|
||||
|
||||
return syms
|
||||
|
||||
|
||||
def fw_signature(syms):
|
||||
# any id which is stable when the translatable string do not change would do, so build it out of
|
||||
# the firmware translation symbol table itself
|
||||
data = b''
|
||||
for sym in syms:
|
||||
data += struct.pack("<HHH", sym['start'], sym['size'], sym['id'])
|
||||
data += sym['name'].encode('ascii') + b'\0'
|
||||
data += sym['data'] + b'\0'
|
||||
return zlib.crc32(data)
|
||||
|
||||
|
||||
def get_sig_sym(symtab, syms):
|
||||
pri_sym = symtab.get_symbol_by_name('_PRI_LANG_SIGNATURE')[0]
|
||||
pri_sym_data = fw_signature(syms)
|
||||
pri_sym = {'start': pri_sym.entry.st_value,
|
||||
'size': pri_sym.entry.st_size,
|
||||
'name': pri_sym.name,
|
||||
'id': '',
|
||||
'data': pri_sym_data}
|
||||
return pri_sym
|
||||
|
||||
|
||||
def patch_binary(path, syms, pri_sym):
|
||||
fw = open(path, "r+b")
|
||||
|
||||
# signature
|
||||
fw.seek(pri_sym['start'])
|
||||
fw.write(struct.pack("<I", pri_sym['data']))
|
||||
|
||||
# string IDs
|
||||
for sym in syms:
|
||||
fw.seek(sym['start'])
|
||||
fw.write(struct.pack("<H", sym['id']))
|
||||
|
||||
|
||||
def check_duplicate_data(syms):
|
||||
data_syms = defaultdict(list)
|
||||
for sym in syms:
|
||||
data_syms[sym['data']].append(sym)
|
||||
for data, sym_list in data_syms.items():
|
||||
if len(sym_list) > 1:
|
||||
sym_names = [x['name'] for x in sym_list]
|
||||
warn(f'symbols {sym_names} contain the same data: {data}')
|
||||
|
||||
|
||||
def output_map(syms):
|
||||
print('OFFSET\tSIZE\tNAME\tID\tSTRING')
|
||||
for sym in syms:
|
||||
print('{:04x}\t{:04x}\t{}\t{}\t{}'.format(sym['start'], sym['size'], sym['name'], sym['id'], sym['data']))
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('elf', help='Firmware ELF file')
|
||||
ap.add_argument('bin', nargs='?', help='Firmware BIN file')
|
||||
args = ap.parse_args()
|
||||
|
||||
# extract translatable symbols
|
||||
elf = elftools.elf.elffile.ELFFile(open(args.elf, "rb"))
|
||||
symtab = elf.get_section_by_name('.symtab')
|
||||
syms = get_lang_symbols(elf, symtab)
|
||||
pri_sym = get_sig_sym(symtab, syms)
|
||||
|
||||
# do one additional pass to check for symbols containing the same data
|
||||
check_duplicate_data(syms)
|
||||
|
||||
# output the symbol table map
|
||||
output_map(syms + [pri_sym])
|
||||
|
||||
# patch the symbols in the final binary
|
||||
if args.bin is not None:
|
||||
patch_binary(args.bin, syms, pri_sym)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
35
lang/lang-patchsec.py
Executable file
35
lang/lang-patchsec.py
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import elftools.elf.elffile
|
||||
|
||||
from lib.io import fatal
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('elf', help='Firmware ELF file')
|
||||
ap.add_argument('cat', help='Binary language catalog file')
|
||||
ap.add_argument('bin', help='Firmware BIN file')
|
||||
args = ap.parse_args()
|
||||
|
||||
# get the language table position
|
||||
elf = elftools.elf.elffile.ELFFile(open(args.elf, "rb"))
|
||||
symtab = elf.get_section_by_name('.symtab')
|
||||
lang_table_sym = symtab.get_symbol_by_name('_SEC_LANG')[0]
|
||||
lang_table_start = lang_table_sym.entry.st_value
|
||||
lang_table_size = lang_table_sym.entry.st_size
|
||||
|
||||
# read the binary catalog
|
||||
cat = open(args.cat, "rb").read()
|
||||
if len(cat) > lang_table_size:
|
||||
fatal("language catalog too large")
|
||||
|
||||
# patch the symbol
|
||||
with open(args.bin, "r+b") as fw:
|
||||
fw.seek(lang_table_start)
|
||||
fw.write(cat)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
1052
lang/lang_en.txt
1052
lang/lang_en.txt
File diff suppressed because it is too large
Load diff
1403
lang/lang_en_cz.txt
1403
lang/lang_en_cz.txt
File diff suppressed because it is too large
Load diff
1403
lang/lang_en_de.txt
1403
lang/lang_en_de.txt
File diff suppressed because it is too large
Load diff
1403
lang/lang_en_es.txt
1403
lang/lang_en_es.txt
File diff suppressed because it is too large
Load diff
1403
lang/lang_en_fr.txt
1403
lang/lang_en_fr.txt
File diff suppressed because it is too large
Load diff
1403
lang/lang_en_it.txt
1403
lang/lang_en_it.txt
File diff suppressed because it is too large
Load diff
1403
lang/lang_en_nl.txt
1403
lang/lang_en_nl.txt
File diff suppressed because it is too large
Load diff
1403
lang/lang_en_pl.txt
1403
lang/lang_en_pl.txt
File diff suppressed because it is too large
Load diff
59
lang/lib/charset.py
Normal file
59
lang/lib/charset.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
# Mapping from LCD source encoding to unicode characters
|
||||
CUSTOM_CHARS = {
|
||||
'\x04': '🔃',
|
||||
'\xe4': 'µ',
|
||||
'\xdf': '°',
|
||||
'\xe1': 'ä',
|
||||
'\xe4': 'μ',
|
||||
'\xef': 'ö',
|
||||
'\xf5': 'ü',
|
||||
}
|
||||
|
||||
# Charaters to be remapped prior to source-encoding transformation
|
||||
# This transformation is applied to the translation prior to being converted to the final encoding,
|
||||
# and maps UTF8 to UTF8. It replaces unavailable symbols in the translation to a close
|
||||
# representation in the source encoding.
|
||||
TRANS_CHARS = {
|
||||
'Ä': 'ä',
|
||||
'Å': 'A',
|
||||
'Ö': 'ö',
|
||||
'Ü': 'ü',
|
||||
'å': 'a',
|
||||
'æ': 'ä',
|
||||
'ø': 'ö',
|
||||
'ß': 'ss',
|
||||
}
|
||||
|
||||
|
||||
def _character_check(buf, valid_chars):
|
||||
for c in buf:
|
||||
if (not c.isascii() or not c.isprintable()) and c not in valid_chars:
|
||||
return c
|
||||
return None
|
||||
|
||||
def source_check(buf):
|
||||
valid_chars = set(CUSTOM_CHARS.values())
|
||||
valid_chars.add('\n')
|
||||
return _character_check(buf, valid_chars)
|
||||
|
||||
def translation_check(buf):
|
||||
valid_chars = set(CUSTOM_CHARS.keys())
|
||||
valid_chars.add('\n')
|
||||
return _character_check(buf, valid_chars)
|
||||
|
||||
|
||||
def source_to_unicode(buf):
|
||||
for src, dst in CUSTOM_CHARS.items():
|
||||
buf = buf.replace(src, dst)
|
||||
return buf
|
||||
|
||||
def trans_replace(buf):
|
||||
for src, dst in TRANS_CHARS.items():
|
||||
buf = buf.replace(src, dst)
|
||||
return buf
|
||||
|
||||
def unicode_to_source(buf):
|
||||
buf = trans_replace(buf)
|
||||
for dst, src in CUSTOM_CHARS.items():
|
||||
buf = buf.replace(src, dst)
|
||||
return buf
|
35
lang/lib/io.py
Normal file
35
lang/lib/io.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
import os
|
||||
import sys
|
||||
import ast
|
||||
|
||||
def info(msg):
|
||||
print(os.path.basename(sys.argv[0]) + ": " + msg)
|
||||
|
||||
def warn(msg):
|
||||
print(os.path.basename(sys.argv[0]) + ": " + msg, file=sys.stderr)
|
||||
|
||||
def fatal(msg):
|
||||
warn(msg)
|
||||
exit(1)
|
||||
|
||||
|
||||
def load_map(path):
|
||||
fd = open(path, "r")
|
||||
|
||||
# check the header
|
||||
if fd.readline() != 'OFFSET\tSIZE\tNAME\tID\tSTRING\n':
|
||||
fatal("invalid map file")
|
||||
|
||||
# parse symbols
|
||||
syms = []
|
||||
for line in fd:
|
||||
line = line.rstrip('\n')
|
||||
offset, size, name, tr_id, data = line.split('\t', 4)
|
||||
data = ast.literal_eval(data)
|
||||
tr_id = int(tr_id) if len(tr_id) else None
|
||||
syms.append({'offset': int(offset, 16),
|
||||
'size': int(size, 16),
|
||||
'id': tr_id,
|
||||
'name': name,
|
||||
'data': data})
|
||||
return syms
|
4018
lang/po/Firmware.pot
4018
lang/po/Firmware.pot
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2262
lang/po/Firmware_da.po
Normal file
2262
lang/po/Firmware_da.po
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2330
lang/po/Firmware_hr.po
Normal file
2330
lang/po/Firmware_hr.po
Normal file
File diff suppressed because it is too large
Load diff
2337
lang/po/Firmware_hu.po
Normal file
2337
lang/po/Firmware_hu.po
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2262
lang/po/Firmware_lb.po
Normal file
2262
lang/po/Firmware_lb.po
Normal file
File diff suppressed because it is too large
Load diff
2262
lang/po/Firmware_lt.po
Normal file
2262
lang/po/Firmware_lt.po
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2314
lang/po/Firmware_no.po
Normal file
2314
lang/po/Firmware_no.po
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2334
lang/po/Firmware_ro.po
Normal file
2334
lang/po/Firmware_ro.po
Normal file
File diff suppressed because it is too large
Load diff
2323
lang/po/Firmware_sk.po
Normal file
2323
lang/po/Firmware_sk.po
Normal file
File diff suppressed because it is too large
Load diff
2262
lang/po/Firmware_sl.po
Normal file
2262
lang/po/Firmware_sl.po
Normal file
File diff suppressed because it is too large
Load diff
2332
lang/po/Firmware_sv.po
Normal file
2332
lang/po/Firmware_sv.po
Normal file
File diff suppressed because it is too large
Load diff
1767
lang/po/new/cs.po
1767
lang/po/new/cs.po
File diff suppressed because it is too large
Load diff
1767
lang/po/new/de.po
1767
lang/po/new/de.po
File diff suppressed because it is too large
Load diff
1767
lang/po/new/es.po
1767
lang/po/new/es.po
File diff suppressed because it is too large
Load diff
1767
lang/po/new/fr.po
1767
lang/po/new/fr.po
File diff suppressed because it is too large
Load diff
1767
lang/po/new/it.po
1767
lang/po/new/it.po
File diff suppressed because it is too large
Load diff
1767
lang/po/new/nl.po
1767
lang/po/new/nl.po
File diff suppressed because it is too large
Load diff
1767
lang/po/new/pl.po
1767
lang/po/new/pl.po
File diff suppressed because it is too large
Load diff
116
lang/progmem.sh
116
lang/progmem.sh
|
@ -1,116 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# progmem.sh - multi-language support script
|
||||
# Examine content of progmem sections (default is progmem1).
|
||||
#
|
||||
# Input files:
|
||||
# $OUTDIR/Firmware.ino.elf
|
||||
# $OUTDIR/sketch/*.o (all object files)
|
||||
#
|
||||
# Output files:
|
||||
# text.sym - formated symbol listing of section '.text'
|
||||
# $PROGMEM.sym - formated symbol listing of section '.progmemX'
|
||||
# $PROGMEM.lss - disassembly listing file
|
||||
# $PROGMEM.hex - variables - hex
|
||||
# $PROGMEM.chr - variables - char escape
|
||||
# $PROGMEM.var - variables - strings
|
||||
# $PROGMEM.txt - text data only (not used)
|
||||
#
|
||||
#
|
||||
# Config:
|
||||
if [ -z "$CONFIG_OK" ]; then eval "$(cat config.sh)"; fi
|
||||
if [ -z "$OUTDIR" ]; then echo 'variable OUTDIR not set!' >&2; exit 1; fi
|
||||
if [ -z "$OBJDIR" ]; then echo 'variable OBJDIR not set!' >&2; exit 1; fi
|
||||
if [ -z "$INOELF" ]; then echo 'variable INOELF not set!' >&2; exit 1; fi
|
||||
if [ -z "$OBJDUMP" ]; then echo 'variable OBJDUMP not set!' >&2; exit 1; fi
|
||||
if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo 'Config NG!' >&2; exit 1; fi
|
||||
#
|
||||
# Program memory used
|
||||
PROGMEM=progmem$1
|
||||
if [ -z "$1" ]; then PROGMEM=progmem1; fi
|
||||
#
|
||||
# Description of process:
|
||||
# 0. check input files
|
||||
# 1. remove output files
|
||||
# 2. list symbol table of section '.text' from output elf file to text.sym (sorted by address)
|
||||
# 3. calculate start and stop address of section '.$PROGMEM'
|
||||
# 4. extract string data from elf file to $PROGMEM.hex
|
||||
# 5. prepare string data for character check and conversion (output to $PROGMEM.chr)
|
||||
# 6. perform character check and conversion (output to $PROGMEM.var and $PROGMEM.txt)
|
||||
#
|
||||
|
||||
echo "progmem.sh started" >&2
|
||||
|
||||
# (0)
|
||||
echo " progmem.sh (0) - checking input files" >&2
|
||||
if [ ! -e $OUTDIR ]; then echo "progmem.sh - file '$INOELF' not found!" >&2; exit 1; fi
|
||||
|
||||
# (1)
|
||||
echo " progmem.sh (1) - removing output files" >&2
|
||||
#remove output files if exists
|
||||
if [ -e text.sym ]; then rm text.sym; fi
|
||||
if [ -e $PROGMEM.sym ]; then rm $PROGMEM.sym; fi
|
||||
if [ -e $PROGMEM.lss ]; then rm $PROGMEM.lss; fi
|
||||
if [ -e $PROGMEM.hex ]; then rm $PROGMEM.hex; fi
|
||||
if [ -e $PROGMEM.chr ]; then rm $PROGMEM.chr; fi
|
||||
if [ -e $PROGMEM.var ]; then rm $PROGMEM.var; fi
|
||||
if [ -e $PROGMEM.txt ]; then rm $PROGMEM.txt; fi
|
||||
|
||||
# (2)
|
||||
echo " progmem.sh (2) - listing symbol table of section '.text'" >&2
|
||||
#list symbols from section '.text' into file text.sym (only address, size and name)
|
||||
#$OBJDUMP -t -j ".text" $INOELF | sort > text.sym
|
||||
$OBJDUMP -t -j ".text" $INOELF | tail -n +5 | grep -E "^[0-9a-f]{8} [gl] [O ]" | cut -c1-9,28-36,37- | sed "/^$/d" | sort > text.sym
|
||||
|
||||
# (3)
|
||||
echo " progmem.sh (3) - calculating start and end address" >&2
|
||||
#calculate start addres of section ".$PROGMEM"
|
||||
PROGMEM_BEG=$(cat text.sym | grep "__loc_pri_start" | while read offs size name; do echo "0x"$offs; done)
|
||||
#calculate stop addres of section ".$PROGMEM"
|
||||
PROGMEM_END=$(cat text.sym | grep "__loc_pri_end" | while read offs size name; do echo "0x"$offs; done)
|
||||
echo " START address = "$PROGMEM_BEG >&2
|
||||
echo " STOP address = "$PROGMEM_END >&2
|
||||
|
||||
# (4)
|
||||
echo " progmem.sh (4) - extracting string data from elf" >&2
|
||||
#dump $PROGMEM data in hex format, cut disassembly (keep hex data only)
|
||||
$OBJDUMP -D -j ".text" -w -z --start-address=$PROGMEM_BEG --stop-address=$PROGMEM_END $INOELF |\
|
||||
tail -n +7 | sed "s/ \t.*$//" > $PROGMEM.lss
|
||||
#convert $PROGMEM.lss to $PROGMEM.hex:
|
||||
# replace empty lines with '|' (variables separated by empty lines)
|
||||
# remove address from multiline variables (keep address at first variable line only)
|
||||
# remove '<' and '>:', remove whitespace at end of lines
|
||||
# remove line-endings, replace separator with '\n' (join hex data lines - each line will contain single variable)
|
||||
cat $PROGMEM.lss | sed -E 's/^$/|/;s/^ ....:\t//;s/[ ]*$/ /' | tr -d '\n' | tr '|' '\n' |\
|
||||
sed "s/^ //;s/<//;s/>:/ /;s/00 [1-9a-f][1-9a-f] $/00 /; s/ $//" > $PROGMEM.hex
|
||||
|
||||
# (5)
|
||||
echo " progmem.sh (5) - preparing string data" >&2
|
||||
#convert $PROGMEM.hex to $PROGMEM.chr (prepare string data for character check and conversion)
|
||||
# replace first space with tab
|
||||
# replace second and third space with tab and space
|
||||
# replace all remaining spaces with '\x'
|
||||
# replace all tabs with spaces
|
||||
cat $PROGMEM.hex | sed 's/ /\t/;s/ /\t /;s/ /\\x/g;s/\t/ /g' > $PROGMEM.chr
|
||||
|
||||
# (6)
|
||||
#convert $PROGMEM.chr to $PROGMEM.var (convert data to text)
|
||||
echo " progmem.sh (6) - converting string data" >&2
|
||||
(\
|
||||
echo "/bin\/echo -e \\"; \
|
||||
cat $PROGMEM.chr | \
|
||||
sed 's/ \\xff\\xff/ /;' | \
|
||||
sed 's/\\x22/\\\\\\x22/g;' | \
|
||||
sed 's/\\x1b/\\\\\\x1b/g;' | \
|
||||
sed 's/\\x01/\\\\\\x01/g;' | \
|
||||
sed 's/\\xf8/\\\\\\xf8/g;' | \
|
||||
sed 's/\\x0a/\\\\\\x0a/g;' | \
|
||||
sed 's/\\x00$/\n/;s/^/\"/;s/$/\"\\/'; \
|
||||
) | sh > $PROGMEM.var
|
||||
|
||||
#this step can be omitted because .txt file is not used
|
||||
cat $PROGMEM.var | sed 's/\r/\n/g' | sed -E 's/^[0-9a-f]{8} [^ ]* //' >$PROGMEM.txt
|
||||
|
||||
echo "progmem.sh finished" >&2
|
||||
|
||||
exit 0
|
|
@ -1,48 +0,0 @@
|
|||
Nova podpora vice jazyku ve firmware
|
||||
|
||||
|
||||
Zmeny oproti stavajicimu frameworku:
|
||||
1. Deklarace lokalizovanych textu primo v kodu, neni nutne udrzovat tabulky.
|
||||
2. Zatim dvoj jazycna verze (en_cz, en_de atd). Moznost rozsirit na vicejazycnou (en_cz_de - pro MK2).
|
||||
3. Moznost vyberu druheho jazyka ulozeneho v SPI flash (nebude zabirat misto v interni flash, pouze MK3).
|
||||
5. Bash postbuild proces namisto perloveho skriptu + nastroje na spravu slovniku.
|
||||
|
||||
Popis:
|
||||
Novy framework je trochu podobny jako znamy i18n20, ale sity na miru pro AVR atmega s ohledem na maximalni jednoduchost a usporu interni flashe.
|
||||
Stringy ktere maji byt prelozene se deklaruji pomoci specialnich maker, zbytek obstara postbuild.
|
||||
Vsechny lokalizovane texty se nachazi ve specialni sekci, v pripade AVR musi byt stringy umisteny v dolnich 64kB flash - tzv 'progmem'.
|
||||
Po zbuildovani arduinem bude fungovat pouze anglictina, je treba spustit postbuild ktery na zaklade slovniku doplni data sekundarniho jazka a vytvori modifikovany hexfile.
|
||||
Jedina data ktera je treba udrzovat jsou slovniky pro preklad. Jsou to textove soubory kde je vzdy sparovan anglicky text s prelozenym textem.
|
||||
Kazdy text ve slovniku je jeden radek, muze obsahovat specialni znaky v hexadecimalni podobe (e.g. '\x0a'). Nasledujici radek je vzdy prelozeny text.
|
||||
Tento jednoduchy format je zvolen proto aby bylo mozno slovniky a proces prekladu spravovat jen pomoci gitu a nekolika skriptu.
|
||||
|
||||
Pokud pridame nebo zmenime nejaky text v kodu, zmeni se po zbuildovani a spusteni nastroje 'update.sh' soubor lang_en_code.txt.
|
||||
To je generovany soubor ktery obsahuje vsechny lokalizovane texty pouzite v kodu setridene podle abecedy.
|
||||
V gitu uvidime zmenu kterou rucne preneseme do slovniku lang_en_xx.txt, zaroven vytvorime pozadavek na preklad ci korekturu pozadovaneho textu.
|
||||
Pokud pridame nebo zmenime nejaky text ve slovnikach, zmeni se po spusteni nastroje 'update.sh' soubor lang_en_dict.txt.
|
||||
Ten obsahuje vsechny lokalizovane texty ze slovniku (v anglictine), respektive mnozinu jejich sjednoceni.
|
||||
V idealnim pripade by soubory lang_en_code.txt a lang_en_dict.txt mely byt totozne.
|
||||
Pokud se zmeni slovnik, je treba znovu vygenerovat binarni soubory lang_en_xx.bin.
|
||||
|
||||
|
||||
Pouziti v kodu, priklady:
|
||||
|
||||
1. deklarace lokalizovaneho textu v kodu - makro '_i':
|
||||
puts_P(_i("Kill all humans!")); //v cz vypise "Zabit vsechny lidi!"
|
||||
|
||||
2. deklarace lokalizovaneho textu jako globalni konstanty - makro 'PROGMEM_I1' a 'ISTR':
|
||||
const char MSG_PREHEAT[] PROGMEM_I1 = ISTR("Preheat"); //deklarace
|
||||
puts_P(get_translation(MSG_PREHEAT)); //v cz vypise "Predehrev"
|
||||
|
||||
3. fukce get_translation - zkratka makro '_T':
|
||||
puts_P(_T(MSG_PREHEAT)); //v cz vypise "Predehrev"
|
||||
|
||||
4. deklarace lokalizovaneho textu jako lokalni promenne - makro '_I':
|
||||
const char* text = preheat?_I("Preheat"):_I("Cooldown");
|
||||
puts_P(_T(text)); //v cz vypise "Predehrev" nebo "Zchlazeni"
|
||||
|
||||
5. deklarace nelokalizovaneho textu - makro 'PROGMEM_N1' a '_n' nebo '_N':
|
||||
const char MSG_MK3[] PROGMEM_N1 = "MK3"; //deklarace
|
||||
const char* text = _n("MK3");
|
||||
nebo
|
||||
const char* text = _N("MK3");
|
|
@ -1,68 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# textaddr.sh - multi-language support script
|
||||
# Compile progmem1.var and lang_en.txt files to textaddr.txt file (mapping of progmem addreses to text idenifiers)
|
||||
#
|
||||
# Input files:
|
||||
# progmem1.var
|
||||
# lang_en.txt
|
||||
#
|
||||
# Output files:
|
||||
# textaddr.txt
|
||||
#
|
||||
#
|
||||
# Dscription of process:
|
||||
# check if input files exists
|
||||
# create sorted list of strings from progmem1.var and lang_en.txt
|
||||
# lines from progmem1.var will contain addres (8 chars) and english text
|
||||
# lines from lang_en.txt will contain linenumber and english text
|
||||
# after sort this will generate pairs of lines (line from progmem1 first)
|
||||
# result of sort is compiled with simple script and stored into file textaddr.txt
|
||||
#
|
||||
|
||||
echo "textaddr.sh started" >&2
|
||||
|
||||
if [ ! -e progmem1.var ]; then echo 'textaddr.sh - file progmem1.var not found!' >&2; exit 1; fi
|
||||
if [ ! -e lang_en.txt ]; then echo 'textaddr.sh - file lang_en.txt not found!' >&2; exit 1; fi
|
||||
addr=''
|
||||
text=''
|
||||
(cat progmem1.var | sed -E "s/^([^ ]*) ([^ ]*) (.*)/\1 \"\3\"/";\
|
||||
cat lang_en.txt | sed "/^$/d;/^#/d" | sed = | sed '{N;s/\n/ /}') |\
|
||||
sort -k2 |\
|
||||
sed "s/\\\/\\\\\\\/g" | while read num txt; do
|
||||
if [ ${#num} -eq 8 ]; then
|
||||
if [ -z "$addr" ]; then
|
||||
addr=$num
|
||||
else
|
||||
if [ "$text" = "$txt" ]; then
|
||||
addr="$addr $num"
|
||||
else
|
||||
echo "ADDR NF $addr $text"
|
||||
addr=$num
|
||||
fi
|
||||
fi
|
||||
text=$txt
|
||||
else
|
||||
if [ -z "$addr" ]; then
|
||||
if ! [ -z "$num" ]; then echo "TEXT NF $num $txt"; fi
|
||||
else
|
||||
if [ "$text" = "$txt" ]; then
|
||||
if [ ${#addr} -eq 8 ]; then
|
||||
echo "ADDR OK $addr $num"
|
||||
else
|
||||
echo "$addr" | sed "s/ /\n/g" | while read ad; do
|
||||
echo "ADDR OK $ad $num"
|
||||
done
|
||||
fi
|
||||
addr=''
|
||||
text=''
|
||||
else
|
||||
if ! [ -z "$num" ]; then echo "TEXT NF $num $txt"; fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done > textaddr.txt
|
||||
|
||||
echo "textaddr.sh finished" >&2
|
||||
|
||||
exit 0
|
|
@ -1,251 +0,0 @@
|
|||
# Translations
|
||||
|
||||
## Workflow
|
||||
|
||||
- Build firmware
|
||||
- using `build.sh`
|
||||
- using `PF-build.sh` with a parameter `-c 1` to keep lang build files after compiling
|
||||
- change to `lang` folder
|
||||
- check if lang scripts being able to run with `config.sh`
|
||||
- if you get `Arduino main folder: NG` message change in `config.sh` `export ARDUINO=C:/arduino-1.8.5` to `export ARDUINO=<Path to your Arduino IDE folder>`
|
||||
-example: `export ARDUINO=D:/Github/Prusa-Firmware/PF-build-env-1.0.6/windows-64`
|
||||
- run `lang-build.sh en` to create english `lang_en.tmp`, `lang_en.dat` and `lang_en.bin` files
|
||||
- change in `fw-build.sh` `IGNORE_MISSING_TEXT=1` to `IGNORE_MISSING_TEXT=0` so it stops with error and generates `not_used<variant>.txt` and `not_tran<variant>.txt`
|
||||
- run modified `fw-build.sh`
|
||||
- `not_tran<variant>.txt` should be reviewed and added as these are potential missing translations
|
||||
- copy `not_tran<variant>.txt` as `lang_add.txt`
|
||||
- check if there are things you don't want to translate or must be modifed
|
||||
- als check that the strings do not start with `spaces` as the scripts doesn't handle these well at this moment.
|
||||
- run `lang-add.sh lang_add.txt` to add the missing translations to `lang_en.txt` and `lang_en_??.txt`
|
||||
- `not_used<variant>.txt` should only contain messages that aren't used in this variant like MK2.5/S vs MK3/S
|
||||
- run `fw-clean.sh` to cleanup firmware related files
|
||||
- delete `not_used<variant>.txt` and `not_tran<variant>.txt`
|
||||
- run `lang-clean.sh` to cleanup language related files
|
||||
- run `lang-export.sh all` to create PO files for translation these are stored in `/lang/po` folder
|
||||
- Send them to translators and reviewers or
|
||||
- copy these to `/lang/po/new` and
|
||||
- translate these with POEdit the newly added messages
|
||||
- easiest way is to choose `Validate`in POEdit as it shows you `errors` and the `missing transalations` / most likely the newly added at the top.
|
||||
- The new translated files are expected in `/lang/po/new` folder so store the received files these
|
||||
- run `lang-import.sh <language code (iso639-1)>` for each newly translated language
|
||||
- script improvement to import "all" and other things would be great.
|
||||
- Double check if something is missing or faulty
|
||||
- run `PF-build.sh -v all -n 1 -c 1` to compile for all variants files
|
||||
- check if there are still some messages in `not_tran<variant>.txt` that need attention
|
||||
- After approval
|
||||
- run `fw-clean.sh` to cleanup firmware related files
|
||||
- run `lang-clean.sh` to cleanup language related files
|
||||
- change in `fw-build.sh` back to `IGNORE_MISSING_TEXT=1`
|
||||
- build your firmware with `build.sh`, `PF-build.sh` or how you normally do it.
|
||||
- Check/Test firmware on printer
|
||||
|
||||
## Code / usage
|
||||
There are 2 modes of operation. If `LANG_MODE==0`, only one language is being used (the default compilation approach from plain Arduino IDE).
|
||||
The reset of this explanation is devoted to `LANG_MODE==1`:
|
||||
|
||||
`language.h`:
|
||||
```C++
|
||||
// section .loc_sec (originaly .progmem0) will be used for localized translated strings
|
||||
#define PROGMEM_I2 __attribute__((section(".loc_sec")))
|
||||
// section .loc_pri (originaly .progmem1) will be used for localized strings in english
|
||||
#define PROGMEM_I1 __attribute__((section(".loc_pri")))
|
||||
// section .noloc (originaly progmem2) will be used for not localized strings in english
|
||||
#define PROGMEM_N1 __attribute__((section(".noloc")))
|
||||
#define _I(s) (__extension__({static const char __c[] PROGMEM_I1 = "\xff\xff" s; &__c[0];}))
|
||||
#define ISTR(s) "\xff\xff" s
|
||||
#define _i(s) lang_get_translation(_I(s))
|
||||
#define _T(s) lang_get_translation(s)
|
||||
```
|
||||
That explains the macros:
|
||||
- `_i` expands into `lang_get_translation((__extension__({static const char __c[] PROGMEM_I1 = "\xff\xff" s; &__c[0];})))` . Note the two 0xff's in the beginning of the string. `_i` allows for declaring a string directly inplace of C++ code, no string table is used. The downside of this approach is obvious - the compiler is not able/willing to merge duplicit strings into one.
|
||||
- `_T` expands into `lang_get_translation(s)` without the two 0xff's at the beginning. Must be used in conjunction with MSG tables in `messages.h`. Allows to declare a string only once and use many times.
|
||||
- `_N` means not-translated. These strings reside in a different segment of memory.
|
||||
|
||||
The two 0xff's are somehow magically replaced by real string ID's where the translations are available (still don't know where).
|
||||
```C++
|
||||
const char* lang_get_translation(const char* s){
|
||||
if (lang_selected == 0) return s + 2; //primary language selected, return orig. str.
|
||||
if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str.
|
||||
uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id
|
||||
if (ui == 0xffff) return s + 2; //translation not found, return orig. str.
|
||||
ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset
|
||||
if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character
|
||||
return s + 2;//zero length string == not translated, return orig. str.
|
||||
return (const char*)((char*)lang_table + ui); //return calculated pointer
|
||||
}
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
### `lang_en.txt`
|
||||
```
|
||||
#MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4
|
||||
"Crash detection can\x0abe turned on only in\x0aNormal mode"
|
||||
```
|
||||
|
||||
### `lang_en_*.txt`
|
||||
```
|
||||
#MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4
|
||||
"Crash detection can\x0abe turned on only in\x0aNormal mode"
|
||||
"Crash detekce muze\x0abyt zapnuta pouze v\x0aNormal modu"
|
||||
```
|
||||
1. a comment - usually a MSG define with number of characters (c) and rows (r)
|
||||
2. English text
|
||||
3. translated text
|
||||
|
||||
### `not_tran.txt`
|
||||
A simple list of strings that are not translated yet.
|
||||
|
||||
### `not_used.txt`
|
||||
A list os strings not currently used in this variant of the firmware or are obsolete.
|
||||
Example: There are MK2.5 specific messages that aren't used when you compile a MK3 variant and vice versa. So be carefull and double check the code if this message is obsolete or just not used due to the chosen variant.
|
||||
|
||||
## Scripts
|
||||
|
||||
### `config.sh`
|
||||
- Checks setup and sets auxiliary env vars used in many other scripts.
|
||||
- Looks for env var `ARDUINO`. If not found/empty, a default `C:/arduino-1.8.5` is used.
|
||||
- Sets env var `CONFIG_OK=1` when all good, otherwise sets `CONFIG_OK=0`
|
||||
|
||||
### `fw-build.sh`
|
||||
Joins firmware HEX and language binaries into one file.
|
||||
|
||||
### `fw-clean.sh`
|
||||
|
||||
### `lang-add.sh`
|
||||
Adds new messages into the dictionary regardless of whether there have been any older versions.
|
||||
|
||||
### `lang-build.sh`
|
||||
Generates lang_xx.bin (language binary files) for the whole firmware build.
|
||||
|
||||
Arguments:
|
||||
- `$1` : language code (`en`, `cz`, `de`, `es`, `fr`, `it`, `pl`) or `all`
|
||||
- empty/no arguments defaults to `all`
|
||||
|
||||
Input: `lang_en.txt` or `lang_en_xx.txt`
|
||||
|
||||
Output: `lang_xx.bin`
|
||||
|
||||
Temporary files: `lang_xx.tmp` and `lang_xx.dat`
|
||||
|
||||
Description of the process:
|
||||
The script first runs `lang-check.py $1` and removes empty lines and comments (and non-translated texts) into `lang_$1.tmp`.
|
||||
The tmp file now contains all translated texts (some of them empty, i.e. "").
|
||||
The tmp file is then transformed into `lang_$1.dat`, which is a simple dump of all texts together, each terminated with a `\x00`.
|
||||
Format of the `bin` file:
|
||||
- 00-01: `A5 5A`
|
||||
- 02-03: `B4 4B`
|
||||
- 04-05: 2B size
|
||||
- 06-07: 2B number of strings
|
||||
- 08-09: 2B checksum
|
||||
- 0A-0B: 2B lang code hex data: basically `en` converted into `ne`, i.e. characters swapped. Only `cz` is changed into `sc` (old `cs` ISO code).
|
||||
- 0C-0D: 2B signature low
|
||||
- 0E-0F: 2B signature high
|
||||
- 10-(10 + 2*number of strings): table of string offsets from the beginning of this file
|
||||
- after the table there are the strings themselves, each terminated with `\x00`
|
||||
|
||||
The signature is composed of 2B number of strings and 2B checksum in lang_en.bin. Signature in lang_en.bin is zero.
|
||||
|
||||
### `lang-check.sh` and `lang-check.py`
|
||||
Both do the same, only lang-check.py is newer, i.e. lang-check.sh is not used anymore.
|
||||
lang-check.py makes a binary comparison between what's in the dictionary and what's in the binary.
|
||||
|
||||
### `lang-clean.sh`
|
||||
Removes all language output files from lang folder. That means deleting:
|
||||
- if [ "$1" = "en" ]; then
|
||||
rm_if_exists lang_$1.tmp
|
||||
else
|
||||
rm_if_exists lang_$1.tmp
|
||||
rm_if_exists lang_en_$1.tmp
|
||||
rm_if_exists lang_en_$1.dif
|
||||
rm_if_exists lang_$1.ofs
|
||||
rm_if_exists lang_$1.txt
|
||||
fi
|
||||
rm_if_exists lang_$1_check.dif
|
||||
rm_if_exists lang_$1.bin
|
||||
rm_if_exists lang_$1.dat
|
||||
rm_if_exists lang_$1_1.tmp
|
||||
rm_if_exists lang_$1_2.tmp
|
||||
|
||||
### `lang-export.sh`
|
||||
Exports PO (gettext) for external translators.
|
||||
|
||||
### `lang-import.sh`
|
||||
Import from PO.
|
||||
|
||||
Arguments:
|
||||
- `$1` : language code (`en`, `cz`, `de`, `es`, `fr`, `it`, `pl`)
|
||||
- empty/no arguments quits the script
|
||||
|
||||
Input files: `<language code>.po` files like `de.po`, `es.po`, etc.
|
||||
|
||||
Input folder: ´/lang/po/new´
|
||||
|
||||
Output files:
|
||||
|
||||
Output foler: ´/lang/po/new´
|
||||
|
||||
Needed improments to scrpit:
|
||||
- add `all` argument
|
||||
- update `replace in <language> translations` to all known special characters the LCD display with Japanese ROM cannot display
|
||||
- move `lang_en_<language code>.txt` to folder `/lang`
|
||||
- cleanup `<language code>_filtered.po`, `<language code>_new.po` and `nonasci.txt`
|
||||
|
||||
### `progmem.sh`
|
||||
|
||||
Examine content of progmem sections (default is progmem1).
|
||||
|
||||
Input:
|
||||
- $OUTDIR/Firmware.ino.elf
|
||||
- $OUTDIR/sketch/*.o (all object files)
|
||||
|
||||
Outputs:
|
||||
- text.sym - formated symbol listing of section '.text'
|
||||
- $PROGMEM.sym - formated symbol listing of section '.progmemX'
|
||||
- $PROGMEM.lss - disassembly listing file
|
||||
- $PROGMEM.hex - variables - hex
|
||||
- $PROGMEM.chr - variables - char escape
|
||||
- $PROGMEM.var - variables - strings
|
||||
- $PROGMEM.txt - text data only (not used)
|
||||
|
||||
Description of process:
|
||||
- check input files
|
||||
- remove output files
|
||||
- list symbol table of section '.text' from output elf file to text.sym (sorted by address)
|
||||
- calculate start and stop address of section '.$PROGMEM'
|
||||
- dump $PROGMEM data in hex format, cut disassembly (keep hex data only) into $PROGMEM.lss
|
||||
- convert $PROGMEM.lss to $PROGMEM.hex:
|
||||
- replace empty lines with '|' (variables separated by empty lines)
|
||||
- remove address from multiline variables (keep address at first variable line only)
|
||||
- remove '<' and '>:', remove whitespace at end of lines
|
||||
- remove line-endings, replace separator with '\n' (join hex data lines - each line will contain single variable)
|
||||
- convert $PROGMEM.hex to $PROGMEM.chr (prepare string data for character check and conversion)
|
||||
- replace first space with tab
|
||||
- replace second and third space with tab and space
|
||||
- replace all remaining spaces with '\x'
|
||||
- replace all tabs with spaces
|
||||
- convert $PROGMEM.chr to $PROGMEM.var (convert data to text) - a set of special characters is escaped here including `\x0a`
|
||||
|
||||
|
||||
### `textaddr.sh`
|
||||
|
||||
Compiles `progmem1.var` and `lang_en.txt` files to `textaddr.txt` file (mapping of progmem addreses to text idenifiers).
|
||||
|
||||
Description of process:
|
||||
- check if input files exists
|
||||
- create sorted list of strings from progmem1.var and lang_en.txt
|
||||
- lines from progmem1.var will contain addres (8 chars) and english text
|
||||
- lines from lang_en.txt will contain linenumber and english text
|
||||
- after sort this will generate pairs of lines (line from progmem1 first)
|
||||
- result of sort is compiled with simple script and stored into file textaddr.txt
|
||||
|
||||
Input:
|
||||
- progmem1.var
|
||||
- lang_en.txt
|
||||
|
||||
Output:
|
||||
- textaddr.txt
|
||||
|
||||
|
||||
|
||||
update_lang.sh
|
14
lang/update-po.sh
Executable file
14
lang/update-po.sh
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
FILES=$@
|
||||
[ -z "$FILES" ] && FILES=po/*.po
|
||||
|
||||
for file in $FILES; do
|
||||
# convert the po file to unix to avoid garbage with msgmerge
|
||||
dos2unix "$file"
|
||||
|
||||
# merge from the template
|
||||
msgmerge -U -s -N --suffix=".bak" "$file" po/Firmware.pot
|
||||
|
||||
# ... and back
|
||||
unix2dos "$file"
|
||||
done
|
3
lang/update-pot.sh
Executable file
3
lang/update-pot.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
# Extract language data in the po subdir to keep the relative paths intact
|
||||
cd po && ../lang-extract.py --no-missing -s -o Firmware.pot ../../Firmware/[a-zA-Z]*.[ch]*
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue