Embedded Goes to Shell
Last time I showed you how I have been using shell scripts to orchestrate some simple embedded systems on small Linux platforms like the Raspberry Pi. By manipulating the PATH, the prompt, and providing some custom scripts, I converted the standard Linux shell (bash) into a specialized programming language that can control a serial I/O board.
The reality is, I should have made at least some of the custom scripts actual C programs. I wanted to try to do it all in bash script just to see if I could. The shell isn't all that great at handling the serial port. In particular, you can have trouble receiving data. You might also have trouble sending or receiving a character with a value of 0 (a NULL byte). However, for the purposes of what I wanted to do, these limitations weren't a problem.
The simplest case is when the script sends some characters to the board with no feedback. Remember, the startup script used sty
to set the serial port's baud rate and other parameters. So the only issue is sending a very specific sequence of hex bytes to the serial port. Here's the ledon
script:
#!/bin/bash echo –en '\xd' >$PORT
The echo
command is a common fixture in scripts. However, normally the echo
command issues a new line at the end of what you want to send. In this case, though, you don't want anything except exactly the bytes you specify. That's what the –n
option does. It suppresses the normal newline. The PORT
variable is set by the startup script and all the command scripts assume it is set.
The -e
option causes echo
to interpret special escape characters. There are several recognized (you can look them up), but the one we care about is the \x
escape character, which allows you to specify a hex byte. In this case, 0D hex is the command to turn the board's built-in LED on.
Many of the other scripts look about the same, but have different bytes to send. But what about data coming the other way? The board accepts a command to read one of 8 input bits and — conveniently — returns an ASCII 0 or 1 based on the input's state.
The trick is that you have to have the port open for reading before you send the command or else the system will toss the input to the closed port. That takes a bit of bizarre scripting:
#!/bin/bash BITS=$(( (16+$1)*2+1)) # compute command HBITS=$(printf %x $BITS) # convert to hex # Here's the tricky part ( sleep .2 ; printf \\x $HBITS >$PORT ) & read –rn 1 <$PORT IBTYE echo $IBYTE
This is a bit of a hack. The script detaches a subshell (the &
at the end of the tricky line) and makes it wait 200 milliseconds. By then the read on the next line should be running and waiting for input. If you had a very slow computer, you might need to adjust that time. The read
is waiting for a single byte and the printf
(an alternative to echo) sends out the hex byte to the port. When the board responds, the read completes and IBYTE should have an ASCII 0 or 1 in it.
Truthfully, I don't mean to suggest resorting to this kind of a hack. But it does demonstrate that the shell can do a lot of things you might not guess. If you aren't convinced, take a look on GitHub. However, many (or all) of the commands could have been C programs. There's still plenty of value in using the shell to orchestrate those commands into their final task.