Thursday, March 1, 2012

Damn Small Linux + Led Matrix Scrolling Message Board = RSS News Headlines Prompter


It's been a long time. Taking a little rest from MKHBC-8-R1 project and in the meantime I purchased Mini ITX motherboard for my electronic projects that may require standalone embedded PC compatible computer controller. I wanted to build quiet, fanless, diskless computer system. I have been a Damn Small Linux distro fan for a long time. So I decided that I'd put together something cool out of that motherboard and DSL. Remember my Led Matrix Scrolling Message Board project? (the first post on this blog). It comes in handy. I imagined I'd like to have a RSS news headlines prompter in my room. What's a better OS to automate such a task than Linux and small solid state computer system that uses little power? For the cost of less than $150 (including parts for my Led Matrix Board, RAM for mobo and flash drive for DSL boot) I achieved my goal. This thing has no case and wires are sticking out, but it is just the way I like it :-).

Let me describe step by step how I built that system.

  • I downloaded ISO image of DSL and burned a CD ROM.
  • I put 1 GB RAM in the mobo and connected it to the power (it only needs 4-pin ATX power, like the one that goes to HDD).
  • I connected keyboard, mouse and monitor and booted up computer to the BIOS.
  • Setup boot devices scan sequence to CD ROM, flash, HDD.
  • I put DSL CD in external DVD drive connected to mobo via USB and restarted system.
  • After DSL boot prompt appeared, I pressed ENTER. System automatically booted to X windows.
  • Used DSL wiki page (opened on another computer) to figure out how to install DSL to flash drive.
  • In the meantime I realized that DSL does not support mobo's on board ethernet adapter. So, no network (yet).
  • Rebooted the system (DSL asked to remove CD so it could boot from flash). System booted from flash, automatically created RAM drive and loaded kernel image and necessary file systems to it. I have now a diskless computer system running entirely from RAM with graphical interface.
  • Found old PCI network adapter, compatible with DSL. Shutdown the system, inserted network card in single available PCI slot and booted the system. DSL automatically recognized the network adapter and used DHCP protocol to get IP address from my router. Now I have OS with graphical interface, firefox browser and internet running entirely from RAM, most of it still free for applications.
  • I downloaded some extra packages from internet to expand my DSL: GCC compiler, java JDK, samba (file server).
  • I read DSL wiki again to figure how to make my extensions stick (persistence, remember, this is OS running from RAM, no permanent storage except USB flash drive).
  • I downloaded source code of kernel and follow instructions how to compile it. I stored the code on compact flash drive (not USB stick) attached to IDE flash drive slot that mobo is equipped with.
  • I downloaded source code of linux ethernet driver for my mobo from realtec's web page. I follow instructions included with package to compile driver module.
  • I figured out how to automatically load network adapter driver module at system startup and make it go up and seek IP via DHCP.  Solution: two lines in /opt/bootlocal.sh script:

cd /home/dsl/src/r1000_v1.04 && sudo make install && sudo depmod -a && sudo modprobe r1000 && cd -
/sbin/pump

I shutdown the system, unplug external PCI ethernet adapter and plug ethernet cable to on-board adapter. Reboot the system...it worked!

So, now all I needed to do was to create set of scripts that would download and display RSS Headlines on my Led Matrix Board.

First, I needed to implement basic communication with Led Matrix Board via serial port. Linux makes it so easy. No need to write programs, all can be done with scripting. The serial protocol can only take text via wire this fast, so to upload commands from text file via serial port I had to create this little script with delay loops for characters and lines made with awk:

dsl@box:~/microcom/scripts/ledmtrx$ cat loader!
cat $1|awk '{for (i=1;i<=length($0);i++){printf substr($0,i,1); for(j=0;j<10000;j++){}; }; print ""; for(j=0;j<100000;j++){};}' > /dev/$2

Script takes 2 arguments: $1 - file name with commands for Led Matrix Board and $2 - serial device name (e.g: ttyS0).

Now, script to send single command to the board:

dsl@box:~/microcom/scripts/ledmtrx$ cat ldmtrxcmd!
printf "$1\n" | loader! - $2

Board can be in script execution mode. It is a default mode after power up. I needed a script that would terminate that mode and enter board into command accepting mode. Script should also be able to recognize if the board is responding (present, ON) or not:

dsl@box:~/microcom/scripts/ledmtrx$ cat ldmtrxendscript!
#!/bin/bash

let "count=20"
rm /tmp/ldmtrxbrd_undetected.tmp

DN=$1
if [[ $DN = "" ]]
then
   DN=ttyS0
fi

IsScriptMode()
{
   ldmtrxcmd! conf $DN
   sleep 1
   M=`cat /tmp/ldmtrxendscript_$DN_$$.tmp|grep OK|tail -n 1 | awk -vFS="|" '{print $3;}'`
   if [[ $M = "4" || ($M != "0" && $M != "1" && $M != "2" && $M != "3" && $M != "4") ]]
   then
      echo "true"
   else
      echo "false"
   fi
}

cat /dev/$DN > /tmp/ldmtrxendscript_$DN_$$.tmp 2>/dev/null &
CPID=`ps|grep cat|grep dev|grep $DN|awk '{print $1}' 2>/dev/null`
while [[ `IsScriptMode` = "true" && $count -gt 0 ]]
do
#   ldmtrxcmd! "\n\n\n" $DN
   ldmtrxcmd! endscript $DN
   let "count=count-1"
done
kill $CPID
rm /tmp/ldmtrxendscript_$DN_$$.tmp
if [[ $count -eq 0 ]]
then
   echo "Unable to disable script mode."
   echo "Possibly Led Matrix Scrolling Message Board device is not present."
   touch /tmp/ldmtrxbrd_undetected.tmp
else
   echo "Script mode disabled."
fi

Script that turns Led Matrix Board into clock ($1 - serial device, e.g: /dev/ttyS0):

dsl@box:~/microcom/scripts/ledmtrx$ cat ldmtrxsettime!
echo "mclk`date +%H%M%S`" > $1

And finally a script that would monitor contents of certain directory in a loop and if files detected, upload their contents to the board, otherwise just display current date and time:

dsl@box:~/microcom/scripts/ledmtrx$ cat ldmtrxmsgbrd!
#!/bin/bash
# Monitor ./tmp subdirectory for files by t* pattern.
# If none, send date and time to Led Matrix Scrolling Board every 15 seconds.
# If files found, upload texts from the file to the Board in MAUTO mode and sleep
# for 10 minutes. Remove file and send the contents of the next file until all
# are processed.

function ShowDate()
{
   DS=`date | awk '{print substr($0,0,16);}'`
   ldmtrxcmd! mext ttyS0
   ldmtrxcmd! stext ttyS0
   ldmtrxcmd! "$DS" ttyS0
}

ldmtrxendscript! ttyS0
if [[ ! -f /tmp/ldmtrxbrd_undetected.tmp ]]
then
        while true
        do
           for F in `ls ./tmp/t* 2>/dev/null`
           do
              if [[ -s $F ]]
              then
                 ldmtrxcmd! mauto ttyS0
                 ldmtrxcmd! upl ttyS0
                 loader! $F ttyS0
                 ldmtrxcmd! @EOT ttyS0
                 rm $F
                 sleep 600
              else
                 rm $F
              fi
           done
           ShowDate
           sleep 15
        done
else
   echo "Led Matrix Scrolling Message Board device is not present."
   echo "Exiting."
fi

All that is missing now is a script that'd download and parse RSS feed:

dsl@box:~/microcom/scripts/ledmtrx$ cat getnews!
#!/bin/bash
# Download RSS feed from BBC every 30 minutes,
# Parse headlines out to plain text file, split it up
# to 30 lines per file and feed to to ldmtrxmsgbrd! script.

let "count=1"

cd ~dsl/microcom/scripts/ledmtrx

while true
do
   wget -O rss.xml http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml
   rssparse! rss.xml > /tmp/headlines_$count.tmp
   cd ./tmp
   split --lines=30 /tmp/headlines_$count.tmp t
   cd -
   sleep 1800
   rm /tmp/headlines_$count.tmp
   let "count=count+1"
done

dsl@box:~/microcom/scripts/ledmtrx$ cat rssparse!
#!/bin/bash

cat $1 | awk '

START
{
   pos=1;
   xml=$0
   len=length(xml);
   endp=1
}

{
   while(pos <= len)
   {
      if(substr(xml,pos,7) == "<title>")
      {
         pos=pos+7;
         endp=pos;
         while((substr(xml,endp,8) != "</title>") && (endp < len))
         {
            endp++;
         }
         print substr(xml,pos,endp-pos);
         pos=endp+7;
      }
      pos++;
   }
}'

and I was done.

What's left is to add these scripts at system startup so they'd automatically start working after system boots up. Added to /opt/bootlocal.sh:

cd ~dsl/microcom/scripts/ledmtrx
bash ldmtrxmsgbrd! >/tmp/ldmtrxmsgbrd.trc 2>&1 &
bash getnews! >/tmp/getnews.trc 2>&1 &

Rebooted the system and... voila!

Some pictures and screenshots:

Pic.1 - The MSI Fuzzy CX700D mobo. Flash drive with DSL image and extensions in USB port, on-board ethernet used, serial port connects the computer to my Led Matrix Scrolling Message Board. Keyboard, mouse and monitor are not connected as I access the system entirely via network (SSH, samba). I disabled X windows at start up. Ribbon cable is connected but no HDD is in use - just left the cable in the slot since it is a tight fit.

Pic. 2 - No RSS feed available, script ldmtrxmsgbrd! just sends current date and time to the board in 15 seconds intervals.

Pic. 3 - RSS feed arrived, headlines are uploaded to board and displayed in a loop for 10 minutes, then script will scan for the available processed RSS headlines and if not found, will return to displaying date/time.

Pic. 4 - Two x-term ssh sessions opened to the DSL system. On the left I sent command to the led matrix board, on the right is the output from serial port connected to the board.

Pic. 5 - Output from serial port shows that ldmtrxmsgbrd! script sends date and time to the led matrix board.

Pic. 6 - Output from serial port shows script ldmtrxmsgbrd! sending headlines to the led matrix board.

Isn't computing great? I just love this stuff.
Thank you for reading.

Marek Karcz