Project

General

Profile

Submit #3044 » convert.sh

Anonymous, 06/23/2017 03:51 AM

 
#!/bin/sh

# Copyright (c) 2017 The DragonFly Project. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of The DragonFly Project nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific, prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS
# IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.

# Prefixes for a files generated by parsing ISP driver C header file
# with firmware. For their meaning see the parse_isp_firmware_header()
# function info.
license_file="license"
name_file="name_"
info_file="info_"
data_file="data_"
# Prefix for a binary file for firmware binary data. The binary file
# contains output of sh execution of printf commands in "data_N" file.
binary_file="binary_"
# Suffix for output files which this script produces
firmware_suffix=".fw.uu"
# This string (and a number) will be added to the names of the other
# variants of one firmware to form a unique filenames for the script
# output files
variant_string=".variant_"

# Function usage: parse_isp_firmware_header FILE
#
# FILE - Path to ISP driver C header file with firmware data.
#
# Result of this function are files containing parts of the header
# file and generated sh commands. One header file can contain multiple
# firmware images. Because of that, each file which contains image
# specific info has a number N appended to its name. N is integer
# number starting from 0. Files with the same N belongs to the same
# firmware image.
#
# license - Firmware license.
# name_N - Image name. This will be the name of the final firmware .uu file.
# info_N - Comment blocks with info about firmware image.
# data_N - Printf calls that convert image words hex numbers to their
# values. This file is intended to be executed by sh and the stdout
# to be redirected to a file.
#
# NOTE: Resulting image words values will be in little-endian format.
parse_isp_firmware_header()
{
awk '
# This function converts chars from "a" to "f" to decimal numbers from
# 10 to 15 respectively. Every other character is returned as is.
# Parameters "chars" and "char_array" are local variables.
function hex_alpha_to_dec(a, chars, char_array) {
chars = "a,b,c,d,e,f"
split(chars, char_array, ",")
if (a ~ /[abcdef]/) {
for (j = 1; ; ++j) {
if (char_array[j] == a) {
return (10 + j - 1)
}
}
} else {
return a
}
}

# This function converts two-digit hex number to decimal number.
# The input hex number is without "0x" prefix and "h" suffix.
# Parameters "a" and "b" are local variables.
function hex_to_dec(h, a, b) {
h = tolower(h)
a = hex_alpha_to_dec(substr(h, 1, 1))
b = hex_alpha_to_dec(substr(h, 2, 1))
return ((a * 16) + b)
}

BEGIN {
state = "license"
license_file = "'"${license_file}"'"
name_file = "'"${name_file}"'"
info_file = "'"${info_file}"'"
data_file = "'"${data_file}"'"
image_number = 0
}

# Filter out file information line(s) (file path, version, date, author, ...)
/^\/\* \$.*\$ \*\// {
next
}

# Print the first line of the license contained in one comment block
(state == "license") && /\/\*/ {
print $0 > license_file
state = "inside_license"
next
}

# Print the last line of the license contained in one comment block
(state == "inside_license") && /\*\// {
print $0 > license_file
# License has been read, process comment blocks which contains info
# about the next firmware
state = "info"
next
}

# Print lines inside the license comment block
(state == "inside_license") {
print $0 > license_file
next
}

# Print info text of the next firmware contained in one comment block
(state == "info") && /\/\*/,/\*\// {
out = sprintf("%s%s", info_file, image_number);
print $0 > out
next
}

# Process array declaration line, get the name of the firmware and data type of
# array values
/\[\] = \{/ {
state = "array"
split($0, decl)
split(decl[4], name, "_risc_code")
array_name = name[1]
array_type = decl[3]
if (array_type ~ /int16/) {
# Data type of the array values is 16-bit
state = "data16"
} else {
# Data type of the array values is 32-bit
state = "data32"
}
# Save the firmware name
out = sprintf("%s%s", name_file, image_number);
printf "%s", array_name > out
next
}

# Current array has ended, process the next one
((state == "data16") || ((state == "data32"))) && /\}/ {
state = "info"
image_number++
next
}

# Process one line of array content definition
# Generate shell printf calls for the array values
(state == "data16") || (state == "data32") {
gsub("[ \t]", "", $0)
split($0, values, ",")

for (i = 1; length(values[i]) > 0; ++i) {
# Get the single bytes
a = substr(values[i], 3, 2)
b = substr(values[i], 5, 2)
if (state == "data32") {
c = substr(values[i], 7, 2)
d = substr(values[i], 9, 2)
}
# POSIX printf needs the number to be in octal format in the escape
# sequence
# Swap the bytes to be in little-endian format
v = ""
if (state == "data32") {
v = "\\" sprintf("%o", hex_to_dec(d)) "\\" sprintf("%o", hex_to_dec(c))
}
v = v "\\" sprintf("%o", hex_to_dec(b)) "\\" sprintf("%o", hex_to_dec(a))
out = sprintf("%s%s", data_file, image_number);
printf "printf \"%s\"\n", v > out
}
next
}
' "$1"
}

# Check input file and its existence
if [ $# -ne 1 ]; then
printf "Usage: $0 HEADER_FILE\n" >&2
exit 1
elif [ ! -f "$1" ]; then
printf "Error: file '$1' does not exists\n" >&2
exit 1
fi

parse_isp_firmware_header "$1"

# Concatenate the files to form a firmware .uu files
image_number=0

while [ -f "${name_file}${image_number}" ]; do
output_file="$(cat ${name_file}${image_number})"
# Some ISP firmware header files (asm_2100.h) contains more
# variants of the same firmware image. Append _var_M to the second
# and the following image's names, where 1 <= M. Name of the first
# image in the header file will get nothing appended.
if [ -f "${output_file}${firmware_suffix}" ]; then
# Find unused variant number
variant_number=1
tmp_name="${output_file}${variant_string}${variant_number}"
while [ -f "$tmp_name" ];do
variant_number=$((variant_number + 1))
tmp_name="${output_file}${variant_string}${variant_number}"
done
# Add the suffix
output_file="$tmp_name"
fi
output_file="${output_file}${firmware_suffix}"
# Add the license
cat "$license_file" > "$output_file"
# Add the firmware information if it exists
[ -f "${info_file}${image_number}" ] && \
cat "${info_file}${image_number}" >> "$output_file"
# Generate firmware binary data
cat "${data_file}${image_number}" | sh > "${binary_file}${image_number}"
# uuencode the data and add it to the output file
uuencode "${binary_file}${image_number}" \
"${binary_file}${image_number}" >> "$output_file"
image_number=$((image_number + 1))
done

# Remove temporary files generated by parsing the ISP driver C header
# file with firmware data
eval rm -f \"${license_file}\"\* \
\"${name_file}\"\* \
\"${info_file}\"\* \
\"${data_file}\"\* \
\"${binary_file}\"\*
(3-3/7)