2

I'm working on a CAN bus project, and trying to send a message to set the time and date. I've worked out how the message needs to be formatted, grabbed the date/time and stored in variables. I've converted them to hex just fine, but I need to add leading 0s to pad to the required space required by the message.

I've tried methods seen online for a bash script, but I have a problem: The year 2019 is 7E3 in hex. I need this displayed as 07E3. When using awk to add the leading 0s, the E3 is being interpreted as Engineering notation *10^3, and therefore printing as 7000. My script is below, along with an image showing the CAN bus message format. Any help is appreciated.

#!/bin/bash

#Store Date/Time in Variables
Year=`date '+%Y'`
Month=`date '+%m'`
Day=`date '+%d'`
Hour=`date '+%H'`
Minute=`date '+%M'`
Second=`date '+%S'`

#Convert Date/Time to Hexadecimel
HexYear=`echo "ibase=10;obase=16;$Year"| bc | awk '{ printf("%04d\n", $1) }'`
HexMonth=`echo "ibase=10;obase=16;$Month"| bc | awk '{ printf("%02d\n", $1) }'`
HexDay=`echo "ibase=10;obase=16;$Day"| bc | awk '{ printf("%02d\n", $1) }'`
HexHour=`echo "ibase=10;obase=16;$Hour"| bc | awk '{ printf("%02d\n", $1) }'`
HexMinute=`echo "ibase=10;obase=16;$Minute"| bc | awk '{ printf("%02d\n", $1) }'`
HexSecond=`echo "ibase=10;obase=16;$Second"| bc | awk '{ printf("%02d\n", $1) }'`

echo "The following is Decimel > Hex"
echo "$Year > $HexYear"
echo "$Month > $HexMonth"
echo "$Day > $HexDay"
echo "$Hour > $HexHour"
echo "$Minute > $HexMinute"
echo "$Second > $HexSecond"

CAN bus message format

JPToadstool
  • 45
  • 1
  • 3

3 Answers3

2

The answer in awk, as in other printf formatting, is %0X, e.g.:

$ echo 2019 01 04 | awk '{ printf("%02X%02X%04X\n", $2, $3, $1) }'
010407E3

The x is for heXadecimal, case of the digits A-F matches that of the letter, and the 0 is for leading zeroes, after which you can specify the desired width (e.g., pad to four digits with leading zeroes in uppercase: %04X).

And if you don't need awk for anything else (such as to process multiple lines), just use printf directly:

$ printf "%02X%02X%04X\n" `date '+%m %d %Y'`
010407E3
Arkku
  • 41,011
  • 10
  • 62
  • 84
  • Thank you, this helped me get there. Simplified my code to the following: HexYear=$( printf "%04X\n" $Year ) HexMonth=$( printf "%02X\n" $Month ) – JPToadstool Jan 04 '19 at 23:17
1

All that echo|bc|awk could be boiled down to

$: HexYear=$( printf "%04X\n" $Year )
$: echo "$Year > $HexYear"
2019 > 07E3

X > x, as it doesn't require the var to be declared uppercased.

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
  • I tried that approach, but I get the following response: ./DateSet.sh: line 13: declare: -u: invalid option declare: usage: declare [-afFirtx] [-p] [name[=value] ...] The following is Decimel > Hex 2019 > 01 > 01 04 > 04 22 > 16 55 > 37 35 > 23 – JPToadstool Jan 04 '19 at 22:56
  • Sorry, not sure why this hasn't formatted correctly. This printed as 2019 > ____ (just blank space). Unsure as to why. Yours and the answer below helped solve this, thank you. – JPToadstool Jan 04 '19 at 23:16
  • Edited - skipped the uppercased declaration of the var in favor of using X vs x. Sorry you had trouble, and you're welcome. – Paul Hodges Jan 07 '19 at 15:16
0

You must realize how immensely ineffecient it is to call date 6 times when you could call it once and then call bc + awk to do something awk could do alone and then do THAT 6 times as well. Take a second to really think about what your script is doing.

Look at this with date plus any awk:

$ awk -v dec="$(date '+%Y %m %d %H %M %S')" 'BEGIN {
    split(dec,a)
    hex = sprintf("%X %X %X %X %X %X",a[1],a[2],a[3],a[4],a[5],a[5])
    print dec, "->", hex
}'
2019 01 05 08 22 06 -> 7E3 1 5 8 16 16

or with GNU awk for time functions:

$ awk 'BEGIN {
    dec = strftime("%Y %m %d %H %M %S") 
    split(dec,a)
    hex = sprintf("%X %X %X %X %X %X",a[1],a[2],a[3],a[4],a[5],a[5])
    print dec, "->", hex
}'
2019 01 05 08 18 54 -> 7E3 1 5 8 12 12

and to get the result back into shell:

$ hex=( $(awk 'BEGIN{dec=strftime("%Y %m %d %H %M %S"); split(dec,a); hex=sprintf("%X %X %X %X %X %X",a[1],a[2],a[3],a[4],a[5],a[5]); print hex}') )
$ declare -p hex
declare -a hex=([0]="7E3" [1]="1" [2]="5" [3]="8" [4]="1F" [5]="1F")
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • 1
    Thanks for the advice. Not worried about inefficiency at the moment, as this is just me testing theories to make sure they’re correct. The project will be either written in python or C, this is just my first steps in testing. – JPToadstool Jan 05 '19 at 23:22
  • Calling date 6 times, etc., makes it immediately apparent to me (a human) what the code is trying to do. Humans have to read code too, and (hu)man-hours are far more expensive than CPU-hours. – user187557 May 14 '20 at 17:58