Browse Source

New ML support
lang_en.txt - fix missing empty line
progmem.sh, postbuild.sh - improved
textaddr.sh, update_lang.sh - new files

Robert Pelnar 6 years ago
parent
commit
b8075e1132
5 changed files with 251 additions and 96 deletions
  1. 2 1
      lang/lang_en.txt
  2. 75 68
      lang/postbuild.sh
  3. 38 27
      lang/progmem.sh
  4. 68 0
      lang/textaddr.sh
  5. 68 0
      lang/update_lang.sh

+ 2 - 1
lang/lang_en.txt

@@ -638,7 +638,8 @@
 "Please clean the nozzle for calibration. Click when done."
 "Please clean the nozzle for calibration. Click when done."
 
 
 #MSG_SELFTEST_PLEASECHECK c=0 r=0
 #MSG_SELFTEST_PLEASECHECK c=0 r=0
-"Please check :"	
+"Please check :"
+
 #MSG_WIZARD_CALIBRATION_FAILED c=20 r=8
 #MSG_WIZARD_CALIBRATION_FAILED c=20 r=8
 "Please check our handbook and fix the problem. Then resume the Wizard by rebooting the printer."
 "Please check our handbook and fix the problem. Then resume the Wizard by rebooting the printer."
 
 

+ 75 - 68
lang/postbuild.sh

@@ -1,5 +1,20 @@
 #!/bin/sh
 #!/bin/sh
-# postbuild.sh
+# postbuild.sh - multi-language support high-level script
+#  for generating 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.dat
+#  $PROGMEM.chr
+#  $PROGMEM.var
+#  $PROGMEM.txt
+#  textaddr.txt
 #
 #
 # Output folder and elf file:
 # Output folder and elf file:
 OUTDIR="../../output"
 OUTDIR="../../output"
@@ -7,93 +22,85 @@ OUTELF="$OUTDIR/Firmware.ino.elf"
 #
 #
 # AVR gcc tools used:
 # AVR gcc tools used:
 OBJCOPY=C:/arduino-1.6.8/hardware/tools/avr/bin/avr-objcopy.exe
 OBJCOPY=C:/arduino-1.6.8/hardware/tools/avr/bin/avr-objcopy.exe
+#
+# Selected language:
+LANG=$1
+#if [ -z "$LANG" ]; then LANG='cz'; fi
+
 
 
 function finish
 function finish
 {
 {
  echo
  echo
- echo "postbuild.sh finished... press enter key"
- read
- exit
+ 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 "postbuild.sh started..."
+echo "postbuild.sh started" >&2
 
 
 #check input files
 #check input files
-echo " checking files:"
-if [ ! -e $OUTDIR ]; then echo "  folder '$OUTDIR' not found!"; finish; fi
-echo "  folder OK"
-if [ ! -e $OUTELF ]; then echo "  elf file '$OUTELF' not found!"; finish; fi
-echo "  elf OK"
-if ! ls $OUTDIR/sketch/*.o >/dev/null 2>&1; then echo "  no object files in '$OUTDIR/sketch/'!"; finish; fi
-echo "  objects OK"
+echo " checking files:" >&2
+if [ ! -e $OUTDIR ]; then echo "  folder '$OUTDIR' not found!" >&2; finish 1; fi
+echo "  folder  OK" >&2
+if [ ! -e $OUTELF ]; then echo "  elf file '$OUTELF' not found!" >&2; finish 1; fi
+echo "  elf     OK" >&2
+if ! ls $OUTDIR/sketch/*.o >/dev/null 2>&1; then echo "  no object files in '$OUTDIR/sketch/'!" >&2; finish 1; fi
+echo "  objects OK" >&2
 
 
-#run progmem.sh to examine content of progmem1
-./progmem.sh 1
+#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
 
 
-#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 to file textaddr.txt
-echo "compiling progmem1.var and lang_en.txt"
-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
-   echo "TEXT NF $num $txt"
-  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
-    echo "TEXT NF $num $txt"
-   fi
-  fi
- fi
-done > textaddr.txt
+#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
 
 
 #check for messages declared in progmem1, but not found in lang_en.txt
 #check for messages declared in progmem1, but not found in lang_en.txt
-echo "checking textaddr.txt..."
-if cat textaddr.txt | grep "^ADDR NF"; then echo "Some strings not found in lang_en.txt!"; finish; fi
+echo -n " checking textaddr.txt..." >&2
+if cat textaddr.txt | grep "^ADDR NF"; then echo "NG! - some strings not found in lang_en.txt!"; finish 1; fi
+echo "OK" >&2
 
 
 #update progmem1 id entries in binary file
 #update progmem1 id entries in binary file
-echo "extracting binary..."
+echo -n " extracting binary..." >&2
 $OBJCOPY -I ihex -O binary $OUTDIR/Firmware.ino.hex ./firmware.bin
 $OBJCOPY -I ihex -O binary $OUTDIR/Firmware.ino.hex ./firmware.bin
+echo "OK" >&2
+
+#update binary file
+echo " updating binary:" >&2
 
 
 #update progmem1 id entries in binary file
 #update progmem1 id entries in binary file
-echo "updating binary..."
-#dd if=/dev/zero of=test.bin bs=512 count=64 2>/dev/null
-time cat textaddr.txt | grep "^ADDR OK" | cut -f3- -d' ' | sed "s/^0000/0x/" |\
- awk '{ hi = int($2 / 256); lo = int($2 - 256 * hi); printf("%d \\\\x%02x\\\\x%02x\n", strtonum($1), hi, lo); }' |\
+echo -n "  primary language ids..." >&2
+cat textaddr.txt | grep "^ADDR OK" | cut -f3- -d' ' | sed "s/^0000/0x/" |\
+ awk '{ hi = int($2 / 256); lo = int($2 - 256 * hi); printf("%d \\\\x%02x\\\\x%02x\n", strtonum($1), lo, hi); }' |\
  while read addr data; do
  while read addr data; do
   echo -n -e $data | dd of=./firmware.bin bs=1 count=2 seek=$addr conv=notrunc oflag=nonblock 2>/dev/null
   echo -n -e $data | dd of=./firmware.bin bs=1 count=2 seek=$addr conv=notrunc oflag=nonblock 2>/dev/null
  done
  done
+echo "OK" >&2
 
 
-#update progmem1 id entries in binary file
-echo "converting to hex..."
+#update _SEC_LANG in binary file if language is selected
+echo -n "  secondary language data..." >&2
+if [ ! -z "$LANG" ]; then
+ ./update_lang.sh $LANG 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 "skipped" >&2
+fi
+
+#convert bin to hex
+echo -n " converting to hex..." >&2
 $OBJCOPY -I binary -O ihex ./firmware.bin ./firmware.hex
 $OBJCOPY -I binary -O ihex ./firmware.bin ./firmware.hex
+echo "OK" >&2
 
 
-finish
+finish 0

+ 38 - 27
lang/progmem.sh

@@ -1,19 +1,10 @@
 #!/bin/sh
 #!/bin/sh
-#
-# Multi-language support postbuild script
-# Description of proces:
-#  0. remove output files
-#  1. list symbol table of section '.text' from output elf file to text.sym (sorted by address)
-#  2. list symbol table of section '.$PROGMEM' from all output object files to $PROGMEM.sym
-#  3. filter only $PROGMEM symbols from text.sym and store it back to $PROGMEM.sym with absolute address
-#  4. calculate start and stop address of section '.$PROGMEM'
-#  5. extract string data from elf file to $PROGMEM.dat
-#  6. prepare string data for character check and conversion (output to $PROGMEM.chr)
-#  7. perform character check and conversion (output to $PROGMEM.var and $PROGMEM.txt)
+# progmem.sh - multi-language support low-level script
+#  for examining content of progmem sections (default is progmem1)
 #
 #
 # Input files:
 # Input files:
-#  Firmware.ino.elf
-#  *.o (all object files)
+#  $OUTDIR/Firmware.ino.elf
+#  $OUTDIR/sketch/*.o (all object files)
 #
 #
 # Output files:
 # Output files:
 #  text.sym
 #  text.sym
@@ -34,11 +25,28 @@ OUTELF="$OUTDIR/Firmware.ino.elf"
 #
 #
 # AVR gcc tools used:
 # AVR gcc tools used:
 OBJDUMP=C:/arduino-1.6.8/hardware/tools/avr/bin/avr-objdump.exe
 OBJDUMP=C:/arduino-1.6.8/hardware/tools/avr/bin/avr-objdump.exe
-#READELF=C:/arduino-1.6.8/hardware/tools/avr/bin/avr-readelf.exe
+#
+#
+# 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. list symbol table of section '.$PROGMEM' from all output object files to $PROGMEM.sym
+#  4. filter only $PROGMEM symbols from text.sym and store it back to $PROGMEM.sym with absolute address
+#  5. calculate start and stop address of section '.$PROGMEM'
+#  6. extract string data from elf file to $PROGMEM.dat
+#  7. prepare string data for character check and conversion (output to $PROGMEM.chr)
+#  8. perform character check and conversion (output to $PROGMEM.var and $PROGMEM.txt)
+#
 
 
+echo "progmem.sh started" >&2
 
 
 # (0)
 # (0)
-echo "step 0 - removing output files"
+echo " progmem.sh (0) - checking input files" >&2
+if [ ! -e $OUTDIR ]; then echo "progmem.sh - file '$OUTELF' not found!" >&2; exit 1; fi
+
+# (1)
+echo " progmem.sh (1) - removing output files" >&2
 #remove output files if exists
 #remove output files if exists
 if [ -e text.sym ]; then rm text.sym; fi
 if [ -e text.sym ]; then rm text.sym; fi
 if [ -e $PROGMEM.sym ]; then rm $PROGMEM.sym; fi
 if [ -e $PROGMEM.sym ]; then rm $PROGMEM.sym; fi
@@ -49,21 +57,21 @@ if [ -e $PROGMEM.var ]; then rm $PROGMEM.var; fi
 if [ -e $PROGMEM.txt ]; then rm $PROGMEM.txt; fi
 if [ -e $PROGMEM.txt ]; then rm $PROGMEM.txt; fi
 
 
 # (1)
 # (1)
-echo "step 1 - listing symbol table of section '.text'"
+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)
 #list symbols from section '.text' into file text.sym (only address, size and name)
 $OBJDUMP -t -j ".text" $OUTELF | tail -n +5 | grep -E "^[0-9a-f]{8} [gl]     O" | cut -c1-9,28-36,37- | sed "/^$/d" | sort >> text.sym
 $OBJDUMP -t -j ".text" $OUTELF | tail -n +5 | grep -E "^[0-9a-f]{8} [gl]     O" | cut -c1-9,28-36,37- | sed "/^$/d" | sort >> text.sym
 
 
 # (2)
 # (2)
-echo "step 2 - listing symbol table of section '.$PROGMEM'"
+echo " progmem.sh (3) - listing symbol table of section '.$PROGMEM'" >&2
 #loop over all object files
 #loop over all object files
 ls "$OUTDIR"/sketch/*.o | while read fn; do
 ls "$OUTDIR"/sketch/*.o | while read fn; do
- echo " processing $fn"
+ echo "  processing $fn" >&2
  #list symbols from section $PROGMEM (only address, size and name)
  #list symbols from section $PROGMEM (only address, size and name)
- $OBJDUMP -t -j ".$PROGMEM" $fn | tail -n +5 | cut -c1-9,28-36,37- | sed "/^$/d" | sort >> $PROGMEM.sym
-done 2>/dev/null
+ $OBJDUMP -t -j ".$PROGMEM" $fn 2>/dev/null | tail -n +5 | cut -c1-9,28-36,37- | sed "/^$/d" | sort >> $PROGMEM.sym
+done
 #exit
 #exit
 # (3)
 # (3)
-echo "step 3 - filtering $PROGMEM symbols"
+echo " progmem.sh (4) - filtering $PROGMEM symbols" >&2
 #create list of $PROGMEM symbol names separated by '\|'
 #create list of $PROGMEM symbol names separated by '\|'
 progmem=$(cut -c19- $PROGMEM.sym)
 progmem=$(cut -c19- $PROGMEM.sym)
 progmem=$(echo $progmem | sed "s/ /\\\b\\\|\\\b/g")
 progmem=$(echo $progmem | sed "s/ /\\\b\\\|\\\b/g")
@@ -72,16 +80,16 @@ progmem='\b'$progmem'\b'
 cat text.sym | grep $progmem > $PROGMEM.sym
 cat text.sym | grep $progmem > $PROGMEM.sym
 
 
 # (4)
 # (4)
-echo "step 4 - calculating start and stop address"
+echo " progmem.sh (5) - calculating start and stop address" >&2
 #calculate start addres of section ".$PROGMEM"
 #calculate start addres of section ".$PROGMEM"
 PROGMEM_BEG=$(head -n1 $PROGMEM.sym | while read offs size name; do echo "0x"$offs; done)
 PROGMEM_BEG=$(head -n1 $PROGMEM.sym | while read offs size name; do echo "0x"$offs; done)
 #calculate stop addres of section ".$PROGMEM"
 #calculate stop addres of section ".$PROGMEM"
 PROGMEM_END=$(tail -n1 $PROGMEM.sym | while read offs size name; do printf "0x%x" $(("0x"$offs + "0x"$size)); done)
 PROGMEM_END=$(tail -n1 $PROGMEM.sym | while read offs size name; do printf "0x%x" $(("0x"$offs + "0x"$size)); done)
-echo " START address = "$PROGMEM_BEG
-echo " STOP address  = "$PROGMEM_END
+echo "  START address = "$PROGMEM_BEG >&2
+echo "  STOP  address = "$PROGMEM_END >&2
 
 
 # (5)
 # (5)
-echo "step 5 - extracting string data from elf"
+echo " progmem.sh (6) - extracting string data from elf" >&2
 #dump $PROGMEM data in hex format, cut textual data (keep hex data only)
 #dump $PROGMEM data in hex format, cut textual data (keep hex data only)
 $OBJDUMP -d -j ".text" -w -z --start-address=$PROGMEM_BEG --stop-address=$PROGMEM_END $OUTELF | cut -c1-57 > $PROGMEM.lss
 $OBJDUMP -d -j ".text" -w -z --start-address=$PROGMEM_BEG --stop-address=$PROGMEM_END $OUTELF | cut -c1-57 > $PROGMEM.lss
 #convert $PROGMEM.lss to $PROGMEM.dat:
 #convert $PROGMEM.lss to $PROGMEM.dat:
@@ -94,7 +102,7 @@ cat $PROGMEM.lss | tail -n +7 | sed -E 's/^$/|/;s/^........:\t/ /;s/<//g;s/>:/ /
  tr -d '\n' | sed "s/[|]/\n/g" | grep $progmem > $PROGMEM.dat
  tr -d '\n' | sed "s/[|]/\n/g" | grep $progmem > $PROGMEM.dat
 
 
 # (6)
 # (6)
-echo "step 6 - preparing string data"
+echo " progmem.sh (7) - preparing string data" >&2
 #convert $PROGMEM.dat to $PROGMEM.chr (prepare string data for character check and conversion) 
 #convert $PROGMEM.dat to $PROGMEM.chr (prepare string data for character check and conversion) 
 # replace first space with tab
 # replace first space with tab
 # replace second space with tab and space
 # replace second space with tab and space
@@ -104,6 +112,7 @@ cat $PROGMEM.dat | sed 's/ /\t/;s/ /\t /;s/ /\\x/g;s/\t/ /g' > $PROGMEM.chr
 
 
 # (7)
 # (7)
 #convert $PROGMEM.chr to $PROGMEM.var (convert data to text)
 #convert $PROGMEM.chr to $PROGMEM.var (convert data to text)
+echo " progmem.sh (8) - converting string data" >&2
 cat $PROGMEM.chr | \
 cat $PROGMEM.chr | \
  sed 's/ \\xff\\xff/ /;' | \
  sed 's/ \\xff\\xff/ /;' | \
  sed 's/\\x22/\\\\\\x22/g;' | \
  sed 's/\\x22/\\\\\\x22/g;' | \
@@ -113,4 +122,6 @@ cat $PROGMEM.chr | \
  sed 's/\\x00$/\\x0a/;s/^/printf "/;s/$/"/' | sh > $PROGMEM.var
  sed 's/\\x00$/\\x0a/;s/^/printf "/;s/$/"/' | sh > $PROGMEM.var
 cat $PROGMEM.var | sed 's/\r/\n/g' |sed -E 's/^[0-9a-f]{8} [^ ]* //' >$PROGMEM.txt
 cat $PROGMEM.var | sed 's/\r/\n/g' |sed -E 's/^[0-9a-f]{8} [^ ]* //' >$PROGMEM.txt
 
 
-read
+echo "progmem.sh finished" >&2
+
+exit 0

+ 68 - 0
lang/textaddr.sh

@@ -0,0 +1,68 @@
+#!/bin/sh
+# textaddr.sh - multi-language support low level script
+#  for compiling 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
+   echo "TEXT NF $num $txt"
+  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
+    echo "TEXT NF $num $txt"
+   fi
+  fi
+ fi
+done > textaddr.txt
+
+echo "textaddr.sh finished" >&2
+
+exit 0

+ 68 - 0
lang/update_lang.sh

@@ -0,0 +1,68 @@
+#!/bin/sh
+# update_lang.sh - multi-language support low level script
+#  for updating secondary language in binary file
+#
+# AVR gcc tools used:
+OBJCOPY=C:/arduino-1.6.8/hardware/tools/avr/bin/avr-objcopy.exe
+#
+# Selected language:
+LANG=$1
+if [ -z "$LANG" ]; then LANG='cz'; fi
+#
+
+function finish
+{
+ echo
+ if [ "$1" == "0" ]; then
+  echo "update_lang.sh finished with success" >&2
+ else
+  echo "update_lang.sh finished with errors!" >&2
+ fi
+ case "$-" in
+  *i*) echo "press enter key"; read ;;
+ esac
+ exit $1
+}
+
+echo "update_lang.sh started" >&2
+echo "selected language=$LANG" >&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_$LANG.bin ]; then echo "NG!  file lang_$LANG.bin not found!" >&2; finish 1; fi
+if [ ! -e firmware.bin ]; then echo "NG!  file firmware.bin not found!" >&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
+echo "OK" >&2
+
+echo " calculating vars:" >&2
+#get addres and size
+sec_lang_addr='0x'$(echo $sec_lang | cut -f1 -d' ')
+sec_lang_size='0x'$(echo $sec_lang | cut -f2 -d' ')
+echo "  sec_lang_addr   =$sec_lang_addr" >&2
+echo "  sec_lang_size   =$sec_lang_size" >&2
+#calculate lang_table_addr (aligned to 256byte page)
+lang_table_addr=$((256*$((($sec_lang_addr + 255) / 256))))
+printf "  lang_table_addr =0x%04x\n" $lang_table_addr >&2
+#calculate lang_table_size
+lang_table_size=$((256*$((($sec_lang_size - ($lang_table_addr - $sec_lang_addr))/256))))
+printf "  lang_table_size =0x%04x (=%d bytes)\n" $lang_table_size $lang_table_size >&2
+
+#get lang_cz.bin file size
+lang_file_size=$(wc -c lang_cz.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!"; finish 1; fi
+
+echo "updating 'firmware.bin'..." >&2
+dd if=lang_cz.bin of=firmware.bin bs=1 seek=$lang_table_addr conv=notrunc 2>/dev/null
+
+#convert bin to hex
+echo "converting to hex..." >&2
+$OBJCOPY -I binary -O ihex ./firmware.bin ./firmware.hex
+
+finish 0