#!/bin/sh # shellcheck disable=SC2034,SC2317 # Скрипт преобразования hex в fw. # В качестве параметра принимает путь к файлу hex. # https://srecord.sourceforge.net/ # https://manpages.ubuntu.com/manpages/xenial/man1/srec_cat.1.html # https://manpages.ubuntu.com/manpages/xenial/man1/srec_examples.1.html # echo -e "\033[0;32m~~~ Hex to FW ~~~\033[0m"; PATH=$(pwd)/$(dirname "$0")/srecord:$PATH PATH="C:/Program Files/Git/usr/bin/":$PATH #========================== Functions ========================== # ByteString - ascii string with bytes separated by spaces like "00 11 22 33" HexStringToByteString() { printf "%s" "$1" | od -An -t x1 | tr -d '\n' | tr 'a-f' 'A-F' | awk '{$1=$1};1' | tr -d '\n'; } GetRandomByteString() { openssl rand "$1" | od -An -t x1 | tr -d '\n' | tr 'a-f' 'A-F' | awk '{$1=$1};1' | tr -d '\n'; } IntelHexFileToByteString() { T=$(srec_cat "$1" -intel -fill 0xFF -over "$1" -intel -address-length=4 -o - -ascii_hex) res1=0x$(echo "$T" | head -n 1 | cut -f1 -d , | sed "s/.*\$A//") # Output: start addr T=$(echo "$T" | tr -d '\r' | tr '\n' ' ' | tr '\002\003' ',') T=$(echo "$T" | cut -f3 -d , | awk '{$1=$1};1') # (awk '{$1=$1};1' - remove leading, trailing and extra spaces between fields) res2=$(echo "$T" | wc -w) # Output: size in bytes res3=$T # Output: byte string } # parmeters: addr fieldsnum string GetFieldsFromByteString() { echo "$3" | cut -d ' ' -f "$1"-$(($1 + $2 - 1)); } # parmeters: addr fieldsnum string GetHexFromByteString() { printf 0x; GetFieldsFromByteString "$1" "$2" "$3" | awk '{print $4,$3,$2,$1}' | tr -d ' '; } # parmeters: addr fieldsnum string GetStringFromByteString() { GetFieldsFromByteString "$1" "$2" "$3" | xxd -r -p | tr -d '\000'; } ByteStringToAsciiHex() { printf "\002 \$A%08X,\n" "$1" # Start and Address echo "$2" | fold -s -w48 | awk '{$1=$1};1' # Data (awk '{$1=$1};1' - remove leading, trailing and extra spaces between fields) printf "\003" # The End } CRC32_FromByteString() { # CAN прошивка использует кривой MPEG2 CRC32 по историческим причинам # В будущем надо исправить на нормальный CRC32 от STM32 T=$(ByteStringToAsciiHex 0x10000000 "$1") T=$(echo "$T" | srec_cat - -ascii_hex -Bit_Reverse 4 -stm32 0 -Bit_Reverse 4 -xor 0xFF -o -ascii_hex) echo "$T" | tr -d '\002\003' | head -n 2 | tail -n 1 | cut -d ' ' -f1-4 } HexToByteString() { echo "$1" | sed 's/^0x//' | fold -w2 | tac | tr '\n' ' ' | sed 's/ $//'; } #========================== Main code ========================== IntelHexFileToByteString "$1" fw_start_addr=$res1 # echo "fw_start_addr $fw_start_addr" fw_size=$res2 # echo "fw_size $fw_size" fw_data=$res3 # echo "fw_data: $fw_data" # выкидываем последние 4 байта и дописываем наше CRC fw_data=$(GetFieldsFromByteString 1 $((fw_size - 4)) "$fw_data") crc=$(CRC32_FromByteString "$fw_data") fw_data="$fw_data $crc" # echo "fw_data: $fw_data" struct_addr=$(GetHexFromByteString 1 4 "$fw_data") # echo "struct_addr $struct_addr" struct_offset=$(( struct_addr - fw_start_addr )) # echo "struct_offset $struct_offset" # // Структура массива информации о CAN-прошивке # struct TCanFwInfo { # TVersion Version; // Версия ПО # uint32_t Build; // Хеш коммита в репозитории git # uint32_t const * pCRC32; // Адрес, где расположена CRC32 # uint32_t reserved2; # uint8_t TextInfo[64]; // Текстовая информация # } __attribute__((packed, aligned(4))); # // описание прошивки # const TCanFwInfo gCanFwInfo = # { # (CAN_FW_VERSION << 24) | BUILD_DATE, // Version - Версия ПО # GIT_BUILD, // Хеш коммита в репозитории git # &CanChksum, // *pCRC32 - Адрес, где расположена CRC32 # 0, // reserved2 # M_NAME CAN_FW_DESCRIPTION "_" GIT_VERSION // TextInfo[64] - Текстовая информация # }; index=$(( struct_offset + 1 )) day=$(GetFieldsFromByteString "$index" 1 "$fw_data") # echo "day: $day" index=$(( index + 1 )) mounth=$(GetFieldsFromByteString "$index" 1 "$fw_data") # echo "mounth: $mounth" index=$(( index + 1 )) year=$(GetFieldsFromByteString "$index" 1 "$fw_data") # echo "year: $year" index=$(( index + 1 )) can_fw_version=$(GetFieldsFromByteString "$index" 1 "$fw_data") # echo "can_fw_version: $can_fw_version" index=$(( index + 1 )) git_build=$(GetFieldsFromByteString "$index" 4 "$fw_data") # echo "git_build: $git_build" index=$(( index + 4 )) CRC_addr=$(GetHexFromByteString "$index" 4 "$fw_data") # echo "CRC_addr: $CRC_addr" index=$(( index + 8 )) text_info=$(GetStringFromByteString "$index" 64 "$fw_data") # echo "text_info: $text_info" # Версия git в последнем поле после '_' git_version=$(echo "$text_info" | awk -F '_' '{print $NF}') # echo "git_version: $git_version" # struct TFirmwareHdr { # uint32_t ChckSum; // вычисляется по всем нижеследующим полям и данным # uint32_t Type; // тип прошивки # uint32_t Version; // версия/дата # uint32_t Build; // Билд прошивки # uint32_t Len; // длина данных # uint32_t Offset; // смещение прошивки во flash # uint8_t InitVect[8]; // Случайное число, используется при дешифровании # }; // sizeof() = 32 # struct TFirmwareFileHdr { # uint8_t Sign[8]; // fixed to 'MOBICAR ' # uint8_t Desc[64]; // текстовое описание # uint8_t pad1[24]; // дополнение до 96 байт # TFirmwareHdr bin_hdr; # }; // sizeof() = 128 # hdr1 - заголовок до CRC hdr1="MOBICAR version $can_fw_version$year$mounth$day, $day.$mounth.$year, GIT = $git_version" # echo "hdr1: $hdr1" length=$(( ${#hdr1} )) # echo "length: $length" hdr1=$(HexStringToByteString "$hdr1") # Добиваем остаток до TFirmwarehdr (8+64+24=96) for i in $(seq $(( length + 1 )) 96); do hdr1="$hdr1 00" done # printf "hdr1:\n%s\n" "$hdr1" # hdr2 - заголовок после CRC hdr2="02 00 00 00" # тип прошивки (CAN) hdr2="$hdr2 $day $mounth $year $can_fw_version" # версия/дата hdr2="$hdr2 $git_build" # Хеш коммита в репозитории git len=$(printf "%08X" "$fw_size") # Len (Длина данных) len=$(HexToByteString "$len") hdr2="$hdr2 $len" offset=$(printf "%08X" "$fw_start_addr") # offset (смещение прошивки во flash) offset=$(HexToByteString "$offset") hdr2="$hdr2 $offset" rand=$(GetRandomByteString 8) # echo "rand: $rand" hdr2="$hdr2 $rand" # printf "hdr2:\n%s\n" "$hdr2" crc=$(CRC32_FromByteString "$hdr2 $fw_data") # printf "crc:\n%s\n" "$crc" fw="$hdr1 $crc $hdr2 $fw_data" # printf "fw:\n%s\n" "$fw" | fold -w48 fw_path="$(dirname "$1")/$text_info.fw" printf "Generate \033[0;32m%s\033[0m\n" "$fw_path" ByteStringToAsciiHex 0 "$fw" | srec_cat - -ascii_hex -o "$fw_path" -binary