Browse Source

Add some documentation
WIP

3d-gussner 3 years ago
parent
commit
92ec7d3d24
10 changed files with 330 additions and 130 deletions
  1. 48 19
      lang/config.sh
  2. 67 42
      lang/fw-build.sh
  3. 19 10
      lang/fw-clean.sh
  4. 54 7
      lang/lang-build.sh
  5. 24 11
      lang/lang-clean.sh
  6. 29 10
      lang/lang-export.sh
  7. 34 7
      lang/lang-import.sh
  8. 18 8
      lang/progmem.sh
  9. 14 4
      lang/textaddr.sh
  10. 23 12
      lang/update_lang.sh

+ 48 - 19
lang/config.sh

@@ -1,20 +1,43 @@
 #!/bin/bash
 #
+# Version 1.0.1 Build 9
+#
 # 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
+#############################################################################
+#
 # Arduino main folder:
 if [ -z "$ARDUINO" ]; then
     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
+if [ -z "$BUILDER" ]; then
+    export BUILDER=$ARDUINO/arduino-builder
+fi
 #
 # 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
+if [ -z "$OBJDUMP" ]; then
+    export OBJDUMP=$ARDUINO/hardware/tools/avr/bin/avr-objdump
+fi
 #
 # Output folder:
 if [ -z "$OUTDIR" ]; then
@@ -22,13 +45,19 @@ if [ -z "$OUTDIR" ]; then
 fi
 #
 # Objects folder:
-export OBJDIR="$OUTDIR/sketch"
+if [ -z "$OBJDIR" ]; then
+    export OBJDIR="$OUTDIR/sketch"
+fi
 #
 # Generated elf file:
-export INOELF="$OUTDIR/Firmware.ino.elf"
+if [ -z "$INOELF" ]; then
+    export INOELF="$OUTDIR/Firmware.ino.elf"
+fi
 #
 # Generated hex file:
-export INOHEX="$OUTDIR/Firmware.ino.hex"
+if [ -z "$INOHEX" ]; then
+    export INOHEX="$OUTDIR/Firmware.ino.hex"
+fi
 #
 # Set default languages
 if [ -z "$LANGUAGES" ]; then
@@ -54,44 +83,44 @@ if [ -z "$COMMUNITY_LANGUAGES" ]; then
     export COMMUNITY_LANGUAGES="$COMMUNITY_LANGUAGES"
 fi
 
-echo "config.sh started" >&2
+echo "$(tput setaf 2)config.sh started$(tput sgr0)" >&2
 
 _err=0
 
 echo -n " Arduino main folder: " >&2
-if [ -e $ARDUINO ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=1; fi
+if [ -d $ARDUINO ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=1; fi
 
 echo -n " Arduino builder: " >&2
-if [ -e $BUILDER ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=2; fi
+if [ -e $BUILDER ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=2; fi
 
 echo " AVR gcc tools:" >&2
 echo -n "   objcopy " >&2
-if [ -e $OBJCOPY ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=3; fi
+if [ -e $OBJCOPY ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=3; fi
 echo -n "   objdump " >&2
-if [ -e $OBJDUMP ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=4; fi
+if [ -e $OBJDUMP ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=4; fi
 
 echo -n " Output folder: " >&2
-if [ -e $OUTDIR ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=5; fi
+if [ -d $OUTDIR ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=5; fi
 
 echo -n " Objects folder: " >&2
-if [ -e $OBJDIR ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=6; fi
+if [ -d $OBJDIR ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=6; fi
 
 echo -n " Generated elf file: " >&2
-if [ -e $INOELF ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=7; fi
+if [ -e $INOELF ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=7; fi
 
 echo -n " Generated hex file: " >&2
-if [ -e $INOHEX ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=8; fi
+if [ -e $INOHEX ]; then echo "$(tput setaf 2)OK$(tput sgr0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr0)" >&2; _err=8; fi
 
 echo -n " Languages: " >&2
-echo "$LANGUAGES" >&2
+echo "$(tput setaf 2)$LANGUAGES$(tput sgr0)" >&2
 
 echo -n " Community languages: " >&2
-echo "$COMMUNITY_LANGUAGES" >&2
+echo "$(tput setaf 2)$COMMUNITY_LANGUAGES$(tput sgr0)" >&2
 
 if [ $_err -eq 0 ]; then
- echo "config.sh finished with success" >&2
+ echo "$(tput setaf 2)config.sh finished with success$(tput sgr0)" >&2
  export CONFIG_OK=1
 else
- echo "config.sh finished with errors!" >&2
+ echo "$(tput setaf 1)config.sh finished with errors!$(tput sgr0)" >&2
  export CONFIG_OK=0
 fi

+ 67 - 42
lang/fw-build.sh

@@ -1,5 +1,7 @@
 #!/bin/bash
 #
+# Version 1.0.2 Build 12
+#
 # postbuild.sh - multi-language support script
 #  Generate binary with secondary language.
 #
@@ -17,17 +19,32 @@
 #  $PROGMEM.txt
 #  textaddr.txt
 #
+#############################################################################
+# Change log:
+# 31 May  2018, XPila,      Initial
+# 17 Dec. 2021, 3d-gussner, Use one config file for all languages
+# 11 Jan. 2022, 3d-gussner, Add check for not translated messages using a
+#                           parameter
+#                           Added version and Change log
+#                           colored output
+#                           Add Community language support
+#                           Use `git rev-list --count HEAD fw-build.sh`
+#                           to get Build Nr
+#############################################################################
 #
 # 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
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr0)" >&2; exit 1; fi
 #
 # Selected language:
 LNG=$1
-#if [ -z "$LNG" ]; then LNG='cz'; fi
-#
-# Params:
-IGNORE_MISSING_TEXT=1
+
+#Set default to ignore missing text
+CHECK_MISSING_TEXT=0
+#Check if script should check for missing messages in the source code aren't translated by using parameter "--check-missing-text"
+if [ "$1" = "--check-missing-text" ]; then
+ CHECK_MISSING_TEXT=1
+fi
 
 # List of supported languages
 if [ -z "$LANGUAGES" ]; then
@@ -38,15 +55,16 @@ fi
 if [ ! -z "$COMMUNITY_LANGUAGES" ]; then
   LANGUAGES+=" $COMMUNITY_LANGUAGES"
 fi
-echo "fw-build languages:$LANGUAGES" >&2
+echo "$(tput setaf 2)fw-build.sh started$(tput sgr 0)" >&2
+echo "fw-build languages:$(tput setaf 2)$LANGUAGES$(tput sgr 0)" >&2
 
 finish()
 {
  echo
  if [ "$1" = "0" ]; then
-  echo "postbuild.sh finished with success" >&2
+  echo "$(tput setaf 2)fw-build.sh finished with success$(tput sgr 0)" >&2
  else
-  echo "postbuild.sh finished with errors!" >&2
+  echo "$(tput setaf 1)fw-build.sh finished with errors!$(tput sgr 0)" >&2
  fi
  case "$-" in
   *i*) echo "press enter key"; read ;;
@@ -54,48 +72,48 @@ finish()
  exit $1
 }
 
-echo "postbuild.sh started" >&2
-
 #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
+if [ ! -e $OUTDIR ]; then echo "$(tput setaf 1)  folder '$OUTDIR' not found!$(tput sgr 0)" >&2; finish 1; fi
+echo "$(tput setaf 2)  folder  OK$(tput sgr 0)" >&2
+if [ ! -e $INOELF ]; then echo "$(tput setaf 1)  elf file '$INOELF' not found!$(tput sgr 0)" >&2; finish 1; fi
+echo "$(tput setaf 2)  elf     OK$(tput sgr 0)" >&2
+if ! ls $OBJDIR/*.o >/dev/null 2>&1; then echo "$(tput setaf 1)  no object files in '$OBJDIR/'!$(tput sgr 0)" >&2; finish 1; fi
+echo "$(tput setaf 2)  objects OK$(tput sgr 0)" >&2
 
 #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
+if [ $? -ne 0 ]; then echo "$(tput setaf 1)NG! - check progmem.out file$(tput sgr 0)" >&2; finish 1; fi
+echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 
 #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
+if [ $? -ne 0 ]; then echo "$(tput setaf 1)NG! - check progmem.out file$(tput sgr 0)" >&2; finish 1; fi
+echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 
 #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
+ echo "$(tput setaf 1)NG! - some texts not found in lang_en.txt!$(tput sgr 0)"
+ if [ $CHECK_MISSING_TEXT -eq 1 ]; then
+  echo "$(tput setaf 1)Missing text found, please update the language files!$(tput setaf 6)" >&2
+  cat not_tran.txt >&2
   finish 1
  else
-  echo "  missing text ignored!" >&2
+  echo "$(tput setaf 3)  missing text ignored!$(tput sgr 0)" >&2
  fi
 else
- echo "OK" >&2
+ echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 fi
 
 #extract binary file
 echo -n " extracting binary..." >&2
 $OBJCOPY -I ihex -O binary $INOHEX ./firmware.bin
-echo "OK" >&2
+echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 
 #update binary file
 echo " updating binary:" >&2
@@ -107,14 +125,14 @@ cat textaddr.txt | grep "^ADDR OK" | cut -f3- -d' ' | sed "s/^0000/0x/" |\
  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
+echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 
 #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
+ if [ -z "$pri_lang" ]; then echo "$(tput setaf 1)NG!\n  symbol _PRI_LANG_SIGNATURE not found!$(tput sgr 0)" >&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
@@ -123,31 +141,32 @@ if [ -e lang_en.bin ]; then
  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
+ echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 else
- echo "NG! - file lang_en.bin not found!" >&2;
+ echo "$(tput setaf 1)NG! - file lang_en.bin not found!$(tput sgr 0)" >&2;
  finish 1
 fi
 
 #convert bin to hex
-echo -n " converting to hex..." >&2
+echo -n " converting primary to hex..." >&2
 $OBJCOPY -I binary -O ihex ./firmware.bin ./firmware.hex
-echo "OK" >&2
+echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 
 #update _SEC_LANG in binary file if language is selected
-echo -n "  secondary language data..." >&2
+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
+ if [ $? -ne 0 ]; then echo "$(tput setaf 1)NG! - check update_lang.out file$(tput sgr 0)" >&2; finish 1; fi
+ echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
  finish 0
 else
- echo "Updating languages:" >&2
+ echo >&2
+ echo "  Updating languages:" >&2
  for lang in $LANGUAGES; do
   if [ -e lang_$lang.bin ]; then
-   echo -n " $lang  : " >&2
+   echo -n "   $lang  : " >&2
    ./update_lang.sh $lang 2>./update_lang_$lang.out 1>/dev/null
-   if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
+   if [ $? -eq 0 ]; then echo "$(tput setaf 2)OK$(tput sgr 0)" >&2; else echo "$(tput setaf 1)NG!$(tput sgr 0)" >&2; finish 1; fi
   fi
  done 
 fi
@@ -166,17 +185,23 @@ 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"
+echo -n "  total size usage: " >&2
+if [ $lang_size_pad -gt $lang_reserved ]; then
+  echo -n "$(tput setaf 1)" >&2
+else
+  echo -n "$(tput setaf 2)" >&2
+fi
+echo "$lang_size_pad ($lang_size)$(tput sgr 0)" >&2
+echo "  reserved size:    $(tput setaf 2)$lang_reserved$(tput sgr 0)" >&2
 if [ $lang_size_pad -gt $lang_reserved ]; then
-  echo "NG! - language data too large" >&2
+  echo "$(tput setaf 1)NG! - language data too large$(tput sgr 0)" >&2
   finish 1
 fi
 
 #convert lang.bin to lang.hex
-echo -n " converting to hex..." >&2
+echo -n " converting multi language to hex..." >&2
 $OBJCOPY -I binary -O ihex ./lang.bin ./lang.hex
-echo "OK" >&2
+echo "$(tput setaf 2)OK$(tput sgr 0)" >&2
 
 #append languages to hex file
 cat ./lang.hex >> firmware.hex

+ 19 - 10
lang/fw-clean.sh

@@ -1,34 +1,44 @@
 #!/bin/bash
 #
+# Version 1.0.1 Build 10
+#
 # fw-clean.sh - multi-language support script
 #  Remove all firmware output files from lang folder.
 #
-
+#############################################################################
+# Change log:
+# 21 June 2018, XPila,      Initial
+# 17 Dec. 2021, 3d-gussner, 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 fw-clean.sh`
+#                           to get Build Nr
+#############################################################################
 # 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
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr0)" >&2; exit 1; fi
 
 if [ ! -z "$COMMUNITY_LANGUAGES" ]; then
   LANGUAGES+=" $COMMUNITY_LANGUAGES"
 fi
-echo "fw-clean languages:$LANGUAGES" >&2
+echo "$(tput setaf 2)fw-clean.sh started$(tput sgr0)" >&2
+echo "fw-clean languages:$(tput setaf 2)$LANGUAGES$(tput sgr0)" >&2
 
 result=0
 
 rm_if_exists()
 {
  if [ -e $1 ]; then
-  echo -n " removing '$1'..." >&2
+  echo -n "$(tput sgr0) removing $(tput sgr0) '$1'..." >&2
   if rm $1; then
-   echo "OK" >&2
+   echo "$(tput setaf 2)OK$(tput sgr0)" >&2
   else
-   echo "NG!" >&2
+   echo "$(tput setaf 1)NG!$(tput sgr0)" >&2
    result=1
   fi
  fi
 }
 
-echo "fw-clean.sh started" >&2
 
 rm_if_exists text.sym
 rm_if_exists progmem1.sym
@@ -52,11 +62,10 @@ for lang in $LANGUAGES; do
  rm_if_exists update_lang_$lang.out
 done
 
-echo -n "fw-clean.sh finished" >&2
 if [ $result -eq 0 ]; then
- echo " with success" >&2
+ echo "$(tput setaf 2)fw-clean.sh finished with success$(tput sgr0)" >&2
 else
- echo " with errors!" >&2
+ echo "$(tput setaf 1)fw-clean.sh finished with errors!$(tput sgr0)" >&2
 fi
 
 case "$-" in

+ 54 - 7
lang/lang-build.sh

@@ -1,5 +1,7 @@
 #!/bin/bash
 #
+# Version 1.0.2 Build 24
+#
 # lang-build.sh - multi-language support script
 #  generate lang_xx.bin (language binary file)
 #
@@ -9,21 +11,39 @@
 # Output files:
 #  lang_xx.bin
 #
+# Depending on files:
+#  ../Firmware/config.h to read the max allowed size for translations
+#
 # Temporary files:
+#  lang_en.cnt //calculated number of messages in english
+#  lang_en.max //maximum size determined by reading "../Firmware/config.h"
 #  lang_xx.tmp
 #  lang_xx.dat
 #
+#############################################################################
+# Change log:
+# 18 June 2018, XPila,      Initial
+# 17 Dec. 2021, 3d-gussner, Use one config file for all languages
+# 11 Jan. 2022, 3d-gussner, Add message and size count comparison
+#                           Added version and Change log
+#                           colored output
+#                           Add Community language support
+#                           Use `git rev-list --count HEAD lang-build.sh`
+#                           to get Build Nr
+#############################################################################
+#
 # Config:
-#startup message
-echo "lang-build.sh started" >&2
 
 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
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr 0)" >&2; exit 1; fi
 
 if [ ! -z "$COMMUNITY_LANGUAGES" ]; then
   LANGUAGES+=" $COMMUNITY_LANGUAGES"
 fi
-echo "lang-build languages:$LANGUAGES" >&2
+
+#startup message
+echo "$(tput setaf 2)lang-build.sh started$(tput sgr 0)" >&2
+echo "lang-build languages:$(tput setaf 2)$LANGUAGES$(tput sgr 0)" >&2
 
 #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); }'
@@ -33,9 +53,9 @@ awk_ui16='{ h=int($1/256); printf("\\x%02x\\x%02x\n", int($1-256*h), h); }'
 finish()
 {
  if [ $1 -eq 0 ]; then
-  echo "lang-build.sh finished with success" >&2
+  echo "$(tput setaf 2)lang-build.sh finished with success$(tput sgr 0)" >&2
  else
-  echo "lang-build.sh finished with errors!" >&2
+  echo "$(tput setaf 1)lang-build.sh finished with errors!$(tput sgr 0)" >&2
  fi
  exit $1
 }
@@ -106,7 +126,7 @@ write_header()
 generate_binary()
 # $1 - language code ('en', 'cz'...)
 {
- echo "lang="$1 >&2
+ echo "lang=$(tput setaf 2)$1$(tput sgr 0)" >&2
  #remove output and temporary files
  rm -f lang_$1.bin
  rm -f lang_$1.tmp
@@ -118,6 +138,16 @@ generate_binary()
  if [ "$1" = "en" ]; then
   #remove comments and empty lines
   cat lang_en.txt | sed '/^$/d;/^#/d'
+  #calculate number of strings
+  count=$(grep -c '^"' lang_en.txt)
+  echo "count="$count >&2
+  #Calculate the number of strings and save to temporary file
+  echo $count >lang_en.cnt
+  #read the allowed maxsize from "../Firmware/config.h" and save to temporary file
+  maxsize=$(($(grep "#define LANG_SIZE_RESERVED" ../Firmware/config.h|sed -e's/  */ /g' |cut -d ' ' -f3)))
+
+  echo "maxsize="$maxsize >&2
+  echo $maxsize >lang_en.max
  else
   #remove comments and empty lines, print lines with translated text only
   cat lang_en_$1.txt | sed '/^$/d;/^#/d' | sed -n 'n;p'
@@ -128,12 +158,29 @@ generate_binary()
  #calculate number of strings
  count=$(grep -c '^"' lang_$1.tmp)
  echo "count="$count >&2
+ # read string count of English and compare it with the translation
+ encount=$(cat lang_en.cnt)
+ if [ "$count" -eq "$encount" ]; then
+	echo "$(tput setaf 2)OK:"$1"="$count"$(tput sgr 0) is equal to $(tput setaf 2)en="$encount"$(tput sgr 0)" >&2
+ else
+	echo "$(tput setaf 1)Error:"$1"="$count"$(tput sgr 0) is NOT equal to $(tput setaf 1)en="$encount"$(tput sgr 0)" >&2
+	finish 1
+ fi
  #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
+ # read maxsize and compare with the translation
+ maxsize=$(cat lang_en.max)
+ if [ "$size" -lt "$maxsize" ]; then
+	free_space=$(($maxsize - $size))
+	echo "$(tput setaf 2)OK:"$1"="$size"$(tput sgr 0) is less than $(tput setaf 2)"$maxsize"$(tput sgr 0). Free space:$(tput setaf 2)"$free_space"$(tput sgr 0)" >&2
+ else
+	echo "$(tput setaf 1)Error:"$1"="$size"$(tput sgr 0) is higer than $(tput setaf 3)"$maxsize"$(tput sgr 0)" >&2
+	finish 1
+ fi
  #write header with empty signature and checksum
  write_header $1 $size $count 0x0000 0x00000000
  #write offset table

+ 24 - 11
lang/lang-clean.sh

@@ -1,13 +1,25 @@
 #!/bin/bash
 #
+# Version 1.0.1 Build 9
+#
 # clean.sh - multi-language support script
 #  Remove all language output files from lang folder.
 #
-
+#############################################################################
+# Change log:
+#  1 Nov. 2018, XPila,      Initial
+# 17 Dec. 2021, 3d-gussner, Use one config file for all languages
+# 11 Jan. 2022, 3d-gussner, Also remove temporally files which have been
+#                           generated for message and size count comparison
+#                           Added version and Change log
+#                           colored output
+#                           Add Community language support
+#                           Use `git rev-list --count HEAD lang-clean.sh`
+#                           to get Build Nr
+#############################################################################
 # Config:
-echo "CONFIG: $CONFIG_OK"
 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
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr0)" >&2; exit 1; fi
 
 if [ ! -z "$COMMUNITY_LANGUAGES" ]; then
   LANGUAGES+=" $COMMUNITY_LANGUAGES"
@@ -18,11 +30,11 @@ result=0
 rm_if_exists()
 {
  if [ -e $1 ]; then
-  echo -n " removing '$1'..." >&2
+  echo -n "$(tput sgr0) removing $(tput setaf 3)'$1'$(tput sgr0)..." >&2
   if rm $1; then
-   echo "OK" >&2
+   echo "$(tput setaf 2)OK$(tput sgr0)" >&2
   else
-   echo "NG!" >&2
+   echo "$(tput setaf 1)NG!$(tput sgr0)" >&2
    result=1
   fi
  fi
@@ -32,6 +44,8 @@ clean_lang()
 {
  if [ "$1" = "en" ]; then
   rm_if_exists lang_$1.tmp
+  rm_if_exists lang_$1.cnt
+  rm_if_exists lang_$1.max
  else
   rm_if_exists lang_$1.tmp
   rm_if_exists lang_en_$1.tmp
@@ -46,21 +60,20 @@ clean_lang()
  rm_if_exists lang_$1_2.tmp
 }
 
+echo "$(tput setaf 2)lang-clean.sh started$(tput sgr0)" >&2
 #Clean English
  clean_lang en
 
 #Clean languages
-echo "lang-clean.sh started" >&2
-echo "lang-clean languages:$LANGUAGES" >&2
+echo "lang-clean languages:$(tput setaf 2)$LANGUAGES$(tput sgr0)" >&2
  for lang in $LANGUAGES; do
   clean_lang $lang
  done
 
-echo -n "lang-clean.sh finished" >&2
 if [ $result -eq 0 ]; then
- echo " with success" >&2
+ echo "$(tput setaf 2) lang-clean.sh with success$(tput sgr0)" >&2
 else
- echo " with errors!" >&2
+ echo "$(tput setaf 1) lang-clean.sh with errors!$(tput sgr0)" >&2
 fi
 
 case "$-" in

+ 29 - 10
lang/lang-export.sh

@@ -1,16 +1,37 @@
 #!/bin/bash
 #
+# Version 1.0.1 Build 17
+#
 # lang-export.sh - multi-language support script
 #  for generating lang_xx.po
 #
+#############################################################################
+# Change log:
+#  9 Nov  2018, XPila,      Initial
+# 14 Sep. 2019, 3d-gussner, Prepare adding new language
+#  1 Mar. 2019, 3d-gussner, Move `Dutch` language parts
+#                           Add templates for future community languages
+# 17 Dec. 2021, 3d-gussner, Use one config file for all languages
+#                           Fix missing last translation
+# 21 Dec. 2021, 3d-gussner, Add Swedish, Danish, Slovanian, Hungarian,
+#                           Luxembourgish, Croatian
+#  3 Jan. 2022, 3d-gussner, Add Lithuanian
+# 11 Jan. 2022, 3d-gussner, Added version and Change log
+#                           colored output
+#                           Add Community language support
+#                           Use `git rev-list --count HEAD lang-export.sh`
+#                           to get Build Nr
+#############################################################################
 # 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
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr 0)" >&2; exit 1; fi
+
+echo "$(tput setaf 2)lang-export.sh started$(tput sgr 0)" >&2
 
 if [ ! -z "$COMMUNITY_LANGUAGES" ]; then
   LANGUAGES+=" $COMMUNITY_LANGUAGES"
 fi
-echo "lang-export languages:$LANGUAGES" >&2
+echo "$(tput setaf 2)lang-export languages:$LANGUAGES$(tput sgr 0)" >&2
 
 # relative path to source folder
 SRCDIR="../Firmware"
@@ -78,7 +99,7 @@ else
   esac)
  # unknown language - error
  if [ -z "LNGNAME" ]; then
-  echo "Invalid argument '$LNG'."
+  echo "Invalid argument $(tput setaf 1)'$LNG'$(tput sgr 0).">&2
   exit 1
  fi
  INFILE=lang_en_$LNG.txt
@@ -88,18 +109,16 @@ 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"
+echo " $(tput setaf 2)$CNTTXT$(tput sgr 0) texts, $(tput setaf 3)$CNTNT$(tput sgr 0) not translated" >&2
 
 # list .cpp, .c and .h files from source folder
 SRCFILES=$(ls "$SRCDIR"/*.cpp "$SRCDIR"/*.c "$SRCDIR"/*.h)
 
-echo " selected language=$LNGNAME"
+echo " selected language=$(tput setaf 2)$LNGNAME$(tput sgr 0)" >&2
 
 # write po/pot header
 (
@@ -138,7 +157,7 @@ num=1
  #end debug
  if [ "${s:0:1}" = "\"" ]; then
   if [[ "${s0:0:1}" = "\"" || "$LNG" = "en" ]]; then
-   echo "  processing $num of $CNTTXT" >&2
+   echo -ne "  processing $num of $CNTTXT\033[0K\r" >&2
    # write po/pot item
    (
    if [ "$LNG" = "en" ]; then s1=$s0; s0=$s; fi
@@ -166,6 +185,6 @@ done >>$OUTFILE) 2>&1
 #replace LF with CRLF
 sync
 sed -i 's/$/\r/' $OUTFILE
-
-echo "lang-export.sh finished"
+echo >&2
+echo "$(tput setaf 2)lang-export.sh finished$(tput sgr 0)">&2
 exit 0

+ 34 - 7
lang/lang-import.sh

@@ -1,15 +1,39 @@
 #!/bin/bash
 #
+# Version 1.0.1 Build 23
+#
 # lang-import.sh - multi-language support script
 #  for importing translated xx.po
+#
+#############################################################################
+# Change log:
+#  9 Nov  2018, XPila,      Initial
+# 14 Sep. 2019, 3d-gussner, Prepare adding new language
+#  1 Mar. 2019, 3d-gussner, Move `Dutch` language parts
+#                           Add templates for future community languages
+# 17 Dec. 2021, 3d-gussner, Use one config file for all languages
+#                           Fix missing last translation
+#                           Add counter
+#                           replace two double quotes with `\x00`
+# 21 Dec. 2021, 3d-gussner, Add Swedish, Danish, Slovanian, Hungarian,
+#                           Luxembourgish, Croatian
+#  3 Jan. 2022, 3d-gussner, Add Lithuanian
+# 11 Jan. 2022, 3d-gussner, Added version and Change log
+#                           colored output
+#                           Add Community language support
+#                           Use `git rev-list --count HEAD lang-export.sh`
+#                           to get Build Nr
+#############################################################################
 # 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
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr 0)" >&2; exit 1; fi
+
+echo "$(tput setaf 2)lang-import.sh started$(tput sgr 0)" >&2
 
 if [ ! -z "$COMMUNITY_LANGUAGES" ]; then
   LANGUAGES+=" $COMMUNITY_LANGUAGES"
 fi
-echo "lang-import languages:$LANGUAGES" >&2
+echo "$(tput setaf 2)lang-import languages:$LANGUAGES$(tput sgr 0)" >&2
 
 LNG=$1
 # if no arguments, 'all' is selected (all po and also pot will be generated)
@@ -33,7 +57,7 @@ cd po/new
 
 # check if input file exists
 if ! [ -e $LNGISO.po ]; then
- echo "Input file $LNGISO.po not found!" >&2
+ echo "$(tput setaf 1)Input file $LNGISO.po not found!$(tput sgr 0)" >&2
  exit -1
 fi
 
@@ -249,7 +273,7 @@ cat $LNG'_filtered.po' | sed ':a;N;$!ba;s/\x22\n\x22//g' > $LNG'_new.po'
 
 CNTTXT=$(grep '^# MSG' -c $LNGISO.po)
 num=1
-echo " selected language=$LNGISO" >&2
+echo " selected language=$(tput setaf 2)$LNGISO$(tput sgr 0)" >&2
 #generate new dictionary
 cat ../../lang_en.txt | sed 's/\\/\\\\/g' | while read -r s; do
  /bin/echo -e "$s"
@@ -260,11 +284,11 @@ cat ../../lang_en.txt | sed 's/\\/\\\\/g' | while read -r s; do
   s=$(/bin/echo -e "$s")
   s2=$(grep -F -A1 -B0  "msgid $s" "$LNG"_new.po | tail -n1 | sed 's/^msgstr //')
   if [ -z "$s2" ]; then
-   echo "  processing $num of $CNTTXT" >&2
+   echo -ne "  processing $num of $CNTTXT\033[0K\r" >&2
    echo '"\x00"'
    num=$((num+1))
   else
-   echo "  processing $num of $CNTTXT" >&2
+   echo -ne "  processing $num of $CNTTXT\033[0K\r" >&2
    echo "$s2"
    num=$((num+1))
   fi
@@ -272,8 +296,11 @@ cat ../../lang_en.txt | sed 's/\\/\\\\/g' | while read -r s; do
  fi
 
 done > lang_en_$LNG.txt
-echo "Finished with $LNGISO" >&2
+echo >&2
+echo "$(tput setaf 2)Finished with $LNGISO$(tput sgr 0)" >&2
 #replace two double quotes to "\x00"
 sed -i 's/""/"\\x00"/g' lang_en_$LNG.txt
 #remove CR
 sed -i "s/\r//g" lang_en_$LNG.txt
+echo >&2
+echo "$(tput setaf 2)lang-import.sh finished$(tput sgr 0)">&2

+ 18 - 8
lang/progmem.sh

@@ -1,5 +1,7 @@
 #!/bin/bash
 #
+# Version 1.0.1 Build 12
+#
 # progmem.sh - multi-language support script
 #  Examine content of progmem sections (default is progmem1).
 #
@@ -16,14 +18,22 @@
 #  $PROGMEM.var - variables - strings
 #  $PROGMEM.txt - text data only (not used)
 #
+#############################################################################
+# Change log:
+# 31 May  2018, XPila,     Initial
+#  9 June 2020, 3d-gussner, Added version and Change log
+#  9 June 2020, 3d-gussner, colored output
+#  2 Apr. 2021, 3d-gussner, Use `git rev-list --count HEAD progmem.sh`
+#                           to get Build Nr
+#############################################################################
 #
 # 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
+if [ -z "$OUTDIR" ]; then echo "$(tput setaf 1)variable OUTDIR not set!$(tput sgr0)" >&2; exit 1; fi
+if [ -z "$OBJDIR" ]; then echo "$(tput setaf 1)variable OBJDIR not set!$(tput sgr0)" >&2; exit 1; fi
+if [ -z "$INOELF" ]; then echo "$(tput setaf 1)variable INOELF not set!$(tput sgr0)" >&2; exit 1; fi
+if [ -z "$OBJDUMP" ]; then echo "$(tput setaf 1)variable OBJDUMP not set!$(tput sgr0)" >&2; exit 1; fi
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr0)" >&2; exit 1; fi
 #
 # Program memory used
 PROGMEM=progmem$1
@@ -39,11 +49,11 @@ if [ -z "$1" ]; then PROGMEM=progmem1; fi
 #  6. perform character check and conversion (output to $PROGMEM.var and $PROGMEM.txt)
 #
 
-echo "progmem.sh started" >&2
+echo "$(tput setaf 2)progmem.sh started$(tput sgr0)" >&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
+if [ ! -e $OUTDIR ]; then echo "progmem.sh - file $(tput setaf 2)"$INOELF"$(tput sgr 0) not found!" >&2; exit 1; fi
 
 # (1)
 echo " progmem.sh (1) - removing output files" >&2
@@ -111,6 +121,6 @@ cat $PROGMEM.chr | \
 #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
+echo "$(tput setaf 2)progmem.sh finished$(tput sgr0)" >&2
 
 exit 0

+ 14 - 4
lang/textaddr.sh

@@ -1,5 +1,7 @@
 #!/bin/sh
 #
+# Version 1.0.1 Build 7
+#
 # 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)
 #
@@ -19,11 +21,19 @@
 #  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
 #
+#############################################################################
+# Change log:
+# 30 May  2018, XPila,     Initial
+#  9 June 2020, 3d-gussner, Added version and Change log
+#  9 June 2020, 3d-gussner, colored output
+#  2 Apr. 2021, 3d-gussner, Use `git rev-list --count HEAD textaddr.sh`
+#                           to get Build Nr
+#############################################################################
 
-echo "textaddr.sh started" >&2
+echo "$(tput setaf 2)textaddr.sh started$(tput sgr0)" >&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 
+if [ ! -e progmem1.var ]; then echo "$(tput setaf 1)textaddr.sh - file progmem1.var not found!$(tput sgr0)" >&2; exit 1; fi 
+if [ ! -e lang_en.txt ]; then echo "$(tput setaf 1)textaddr.sh - file lang_en.txt not found!$(tput sgr0)" >&2; exit 1; fi 
 addr=''
 text=''
 (cat progmem1.var | sed -E "s/^([^ ]*) ([^ ]*) (.*)/\1 \"\3\"/";\
@@ -63,6 +73,6 @@ text=''
  fi
 done > textaddr.txt
 
-echo "textaddr.sh finished" >&2
+echo "$(tput setaf 2)textaddr.sh finished$(tput sgr0)" >&2
 
 exit 0

+ 23 - 12
lang/update_lang.sh

@@ -1,12 +1,23 @@
 #!/bin/sh
 #
+# Version 1.0.1 Build 10
+#
 # update_lang.sh - multi-language support script
 #  Update secondary language in binary file.
 #
+#############################################################################
+# Change log:
+# 17 June 2018, XPila,     Initial
+#  9 June 2020, 3d-gussner, Added version and Change log
+#  9 June 2020, 3d-gussner, colored output
+#  2 Apr. 2021, 3d-gussner, Use `git rev-list --count HEAD update_lang.sh`
+#                           to get Build Nr
+#############################################################################
+#
 # Config:
 if [ -z "$CONFIG_OK" ]; then eval "$(cat config.sh)"; fi
-if [ -z "$OBJCOPY" ]; then echo 'variable OBJCOPY not set!' >&2; exit 1; fi
-if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo 'Config NG!' >&2; exit 1; fi
+if [ -z "$OBJCOPY" ]; then echo "$(tput setaf 1)variable OBJCOPY not set!$(tput sgr0)" >&2; exit 1; fi
+if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo "$(tput setaf 1)Config NG!$(tput sgr0)" >&2; exit 1; fi
 #
 # Selected language:
 LNG=$1
@@ -17,9 +28,9 @@ finish()
 {
  echo
  if [ "$1" = "0" ]; then
-  echo "update_lang.sh finished with success" >&2
+  echo "$(tput setaf 2)update_lang.sh finished with success$(tput sgr0)" >&2
  else
-  echo "update_lang.sh finished with errors!" >&2
+  echo "$(tput setaf 1)update_lang.sh finished with errors!$(tput sgr0)" >&2
  fi
  case "$-" in
   *i*) echo "press enter key" >&2; read ;;
@@ -27,22 +38,22 @@ finish()
  exit $1
 }
 
-echo "update_lang.sh started" >&2
-echo " selected language=$LNG" >&2
+echo "$(tput setaf 2)update_lang.sh started$(tput sgr0)" >&2
+echo " selected language=$(tput setaf 2)$LNG$(tput sgr0)" >&2
 
 echo -n " checking files..." >&2
-if [ ! -e text.sym ]; then echo "NG!  file text.sym not found!" >&2; finish 1; fi
-if [ ! -e lang_$LNG.bin ]; then echo "NG!  file lang_$LNG.bin not found!" >&2; finish 1; fi
-if [ ! -e firmware.bin ]; then echo "NG!  file firmware.bin not found!" >&2; finish 1; fi
+if [ ! -e text.sym ]; then echo "$(tput setaf 1)NG!  file text.sym not found!$(tput sgr0)" >&2; finish 1; fi
+if [ ! -e lang_$LNG.bin ]; then echo "$(tput setaf 1)NG!  file lang_$LNG.bin not found!$(tput sgr0)" >&2; finish 1; fi
+if [ ! -e firmware.bin ]; then echo "$(tput setaf 1)NG!  file firmware.bin not found!$(tput sgr0)" >&2; finish 1; fi
 echo "OK" >&2
 
 echo -n " checking symbols..." >&2
 #find symbol _SEC_LANG in section '.text'
 sec_lang=$(cat text.sym | grep -E "\b_SEC_LANG\b")
-if [ -z "$sec_lang" ]; then echo "NG!\n  symbol _SEC_LANG not found!" >&2; finish 1; fi
+if [ -z "$sec_lang" ]; then echo "$(tput setaf 1)NG!\n  symbol _SEC_LANG not found!$(tput sgr0)" >&2; finish 1; fi
 #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
+if [ -z "$pri_lang" ]; then echo "$(tput setaf 1)NG!\n  symbol _PRI_LANG_SIGNATURE not found!$(tput sgr0)" >&2; finish 1; fi
 echo "OK" >&2
 
 echo " calculating vars:" >&2
@@ -65,7 +76,7 @@ printf "  lang_table_size =0x%04x (=%d bytes)\n" $lang_table_size $lang_table_si
 lang_file_size=$(wc -c lang_$LNG.bin | cut -f1 -d' ')
 printf "  lang_file_size  =0x%04x (=%d bytes)\n" $lang_file_size $lang_file_size >&2
 
-if [ $lang_file_size -gt $lang_table_size ]; then echo "Lanaguage binary file size too big!" >&2; finish 1; fi
+if [ $lang_file_size -gt $lang_table_size ]; then echo "$(tput setaf 1)Lanaguage binary file size too big!$(tput sgr0)" >&2; finish 1; fi
 
 echo "updating 'firmware.bin'..." >&2