For the last few weeks, I’ve been designing an embedded system for voice verification. The embedded microcomputer will sit near a door and determine whether a user should gain entry to the building or not. Such a system is very different from a normal PC; the microcomputer is dedicated entirely to one specific function. Its sole purpose is to perform its assigned task. In other words, it will be embedded into a system. There will be no keyboard and no display. It must boot and start performing its assigned function automatically.
In this Daily Drill Down, I’m going to show you how you can design an embedded system of your own. You can use this information to convert one of your old 386 or 486 machines into a dedicated robot controller, a complete home appliance/lighting/sprinkler controller, or even a router! Specifically, I’ll use FreeBSD for my example, but almost anything that’s done in FreeBSD also can be done in Linux or in any other UNIX-like operating system.
My clients purchased a large number of 133-MHz Pentium PC-104 boards and sound cards. For those of you who aren’t familiar with the PC-104 standard, they are very small PCs that can fit in the same space that a 3 1/2 inch floppy does. The computer has an onboard semiconductor flash disk that emulates a 24 MB hard drive, too. Quite simply, it’s a full PC with BIOS, a 24 MB hard drive, and a sound card.
I expected this job to be very easy. All I had to do was get the OS working on the board, make sure that I could read and write to the sound card and the COM port, and make sure that the voice verification software worked. I figured that all I’d have to do was write some control logic to make the unit perform the appropriate tasks in the proper sequence. Of course, anything that involves computers (especially PCs) never works as planned. The client already had voice verification software and a nice operating system. This operating system simulated Windows in almost every way, but it lacked support for the sound card. The maker of the sound card provided device drivers, but the drivers only supported playing samples—not recording them.
At this point, I realized I was in trouble! Either I had to convince the operating system company or the board manufacturer to produce a working device driver that could support the sound card. I was unsuccessful in my endeavors, and I began to consider my alternatives. By the way, this type of situation is why I hate software that isn’t open source. If it doesn't work, you have no other recourse than choosing not to use it. This experience just increased my faith in open source software.
First, I studied the flash hard drive emulator chip to see if Linux or FreeBSD supported it. I found Linux support on their Web site, which meant that FreeBSD also might support the chip. I went to a FreeBSD chat room and talked with several FreeBSD developers. They told me that support for the chip did indeed exist. Next, I examined the kernel configuration file. In the Lint file, which is the FreeBSD kernel documentation for all supported features, I found a line that explained how I could add support for the DiskOnChip 2000.
If I were more familiar with the current Linux kernel, I might have considered using it for this project instead of FreeBSD. To support this chip in Linux, I would have had to apply a patch to the Linux kernel, which I think is a bit sloppy. I didn't want this patch in my normal system kernel, and I would have had to copy everything to a safe location. Therefore, I decided to use FreeBSD.
FreeBSD kernel configuration
FreeBSD kernel configuration is unbelievably painless and easy. Instead of answering a lot of questions (which I used to do when I configured a Linux kernel), I just copied the Generic file to a new name. Then, I chose additional features from the Lint file and added them to my new file. The specific lines that I wanted from Lint were:
# M-systems DiskOnChip products see src/sys/contrib/dev/fla/README
device fla0 at isa?
# For non-pnp sound cards with no bridge drivers only:
device pcm0 at isa? irq 10 drq 1 flags 0x0
# For PnP/PCI sound cards
By putting these lines into my new kernel configuration file, I created a new specification for a kernel that includes additional support for the DiskOnChip and most of the sound cards. I also provided permanent documentation for the kernel. That means that I can mail this configuration file to other people who have FreeBSD 4.0 systems and they can build the same identical kernel. If someone lacks the necessary resources for building a kernel, that user can send specifications to another FreeBSD user (like me), who could create the desired kernel and return it.
Once you have the configuration file, all you do to create a kernel is run:
config <Kernel Configuration File Name>
This command builds the kernel directory and makes the appropriate changes within the makefile and other important files. When this procedure finishes, your machine will remind you to change the directory to the one that was just created, and it will tell you to run the make depend and the make kernel commands.
The following command places you in the correct directory for building the kernel:
cd ../../compile/<Kernel Configuration File Name>
The next step determines which object files need to be recompiled and which ones can be reused from previous compiles. The appropriate command is:
This command actually builds the kernel:
Normally, I would follow this step by typing make install, which causes the new kernel to replace the kernel that the system normally boots. I didn't want to use this kernel on my workstation, so I omitted the install step.
I had a kernel that I thought would work on my target platform. My next step was to create a custom boot floppy that would include this new kernel. My first effort to create a special boot floppy was to replace the kernel file on the floppies. (There are two: the first is kern.flp, and the other is mfsroot.flp.) Then, I was able to watch the floppy boot and recognize both the sound card and the DiskOnChip 2000. As FreeBSD boots, it lists which devices were detected. Watching the kernel detect both of these devices was like finding the Holy Grail of this project.
The custom boot floppies managed to detect the devices, but they didn't actually boot the system. As it turns out, making boot floppy images isn’t an easy chore. It’s very difficult, and I strongly recommend that you leave this task to the experts. Of course, I could have avoided the entire situation if I had obtained an IDE cable for this PC-104 board. For some reason, the manufacturers gave me all kinds of grief when I tried to persuade them to sell me their special IDE cable. I asked them to send it to me via overnight delivery, but I still hadn’t received it after a week. If they had been nicer to me, I would give them a fantastic recommendation. It’s too bad, too, because the main computer board and the accompanying documentation were excellent.
The right way…d’oh!
The right way to build a new FreeBSD system on the PC-104 platform is as follows:
- Build a normal FreeBSD system on a hard drive
- Connect the hard drive to the PC-104 system
- Build the kernel with support for sound card and flash disk
- Reboot the system with the new kernel on the hard drive
The new kernel uses device drivers to support the flash disk. Now, you can use the fdisk, disklabel, and newfs utilities to create a file system on the flash disk.
Once you’ve built your file system on the flash disk, you can copy all of the required files, change the rc file in the /etc directory so that it runs only those processes that you want to run on this mini-system, and change the /etc/fstab file so that it mounts only the flash disk. And you’re pretty much done! There’s one more important procedure: You must install a boot loader on the flash disk. You should accomplish that task with the /stand/sysinstall utility, though you also can use the sysinstall program to perform the fdisk, disklabel, and newfs operations.
If you set everything up correctly, you can remove the hard drive, and the system will run off of the flash disk. The FreeBSD boot loader is very nice. It probes all of the available boot devices dynamically. It presents you with a menu that offers something like:
F1 – FreeBSD
F5 - disk 2
Each line of the menu represents a bootable partition that’s found on the current disk. Pressing [F5] forces the boot loader to probe the second disk for bootable partitions. It should probe every disk in the series until you find the partition that you want. The best aspect of the boot loader is that it remembers your last choice and automatically selects that choice after a timeout period. Thus, if you press [F1] the first time, the system always boots the flash disk FreeBSD partition.
Booting and initializing
My next challenge was to make sure that the embedded FreeBSD system would boot and run my application program immediately. I thought about changing the boot loader to run my program instead of ini; fortunately, better sense prevailed. Instead, I invoked my application in the last line of /etc/rc, and I threw it into the background with the “&” after the command. The initialization program brought up the system like usual, and my application ran just like initialization does when it starts up all the daemons. I like this solution because ini also causes getty to offer the login prompt at all specified ports. Since the PC-104 board has two COM ports, I made one a console, which allowed me to debug the system over the COM port.
Sans video, sans keyboard
The only real question at this point was how the system would operate without a video card. It’s very easy to make the system function while the console sits there. The target platform wouldn't have a VGA card or a keyboard, but that’s unimportant to FreeBSD. You can reroute the console to any device in your /etc/ttys file that you want. All I had to do was change the following line:
ttyd0 "/usr/libexec/getty std.9600" dialup off secure
I changed it to:
ttyd0 "/usr/libexec/getty std.9600" dialup on secure
You can reroute the console during boot by editing the /boot/defaults/loader.conf file and adding this line:
In reality, FreeBSD is smart enough to find a COM port that will display console information if it can’t find the normal VGA device. This way, however, you can force FreeBSD to a serial port. After making these changes, I had an embedded system that sent all console information to COM1 and that allowed for login either at the normal console or at COM1.
The only other question about proper operation that might arise is whether or not BIOS allows booting without a keyboard or video card. Fortunately, this specific brand of BIOS had an option that, when selected, disabled the function that checks these devices. Before you choose a PC for embedded use, you definitely need to consider its design. If you’re turning an old 386 into a router, you don't want to have to attach a VGA card and a keyboard just to appease the BIOS.
So, what other projects might you try?
Let’s say that you have an old 486 lying around and you want a router for your home network. You could fill all the ISA slots with Ethernet adapters and run a minimal distribution of FreeBSD on the system. You could get along with a leftover 100-MB hard drive. Normally, I don't like to use old hard drives because they’re prone to failure. Since this would be a router, however, all of the important information would be maintained on another host anyway. In this system, the hard drive would exist exclusively for retaining code and data for operation. The worst thing that could happen would be the loss of some valuable log file information.
Is a home appliance control center more your style? Well, let’s add a voice modem/sound card to the system, and we’ll buy some remote control equipment. X10 offers remote control light switches that respond to FM signals that are sent over the power wires in your home. Of course, you have to install these switches and remove the existing light switches, but then you can control the whole network from a central location. You could design a parallel port interface card that would latch the parallel data and control any number of relays. Then, you could use the relays to switch electrical circuits on and off.
Without the sound card and modem, you could use your computer to respond to timed events or network commands. If you add the sound card and modem and write a little software, you could create a dial-in menu system that would allow you to call home and make your computer respond to the DTMF (dual tone multi-frequency) tones on your telephone keyboard.
Last column's UNIX challenge results
Before we begin this week's topic, I want to congratulate two readers who offered correct solutions to my last UNIX challenge question. Mr. Jeff Wohltman found a valid way to create a filename that consists of nothing but blank spaces. His solution was to type the following line at the shell prompt:
> " "
This line will work in the sh shell and the bash shell, but it won't work under csh or tcsh because they don't use the same syntax. (But it’s still an excellent solution to that half of the challenge.) I was thinking of methods like:
vi " "
touch " "
[your choice of command] > " "
Almost every command in UNIX allows you to create a file with all white space names.
Mr. Antonio Pozza had the exact same solution for creating the aforementioned filenames, but he also offered a valid solution for fixing the problem. His solution is:
mv \ * new_name
It’s an elegant solution that uses the backslash to remove the special properties of a blank character and then moves any filename that begins with a blank into the filename "new_name." It works perfectly—as long as there is only one filename that begins with a blank space (which he pointed out). That was all I was thinking of when I posed the problem, but it brings up a good question that ought to be addressed. What if we had two files in a directory: one with a name of " " and one with name of " "? How could we recover both of them?
The above solution won't work because the wild card would expand to all files that begin with a blank, and you would have three arguments on the command line for mv, which won't work. A slow solution would be:
mv \ ? new_name1
mv \ ?? new_name2
mv \ ??? new_name3
and so on until you find all of the files. Each line adds one additional wild card character. As you follow this procedure, you’ll get an error message that declares "no match" each time that you guess a filename that doesn’t match. This method is the safest way to deal with the possibility of multiple filenames that begin with blank characters. Anyway, I appreciate the great responses from both readers.
New UNIX challenge
Well, I’m just about out of interesting challenges that involve filenames. Is anybody up for trying to think of some diabolical ways to cause problems in UNIX? Let’s say that you’re not the root user on your system (because there’s no fun in crashing your own system). As a normal user, what can you do to prevent somebody else from running a new process? Acceptable answers can be either in UNIX shell script or in C-language. I wrote my prototype in C, but I expect that many people will come up with very innovative answers without writing a single line of code. Mail your answers to Jack Wallen, Jr.
Ed Gold grew up in Louisville, Kentucky, and he received his master’s degree in electrical engineering at the University of Louisville. Ed owns a small engineering consulting firm in Orlando, Florida, and he is working on the electro-optic subsystem for Lockheed Martin's Joint Strike Fighter proposal. Although his primary computing interests are in image processing and artificial intelligence, Ed is a dedicated FreeBSD/Linux enthusiast. He is currently working to improve the FreeBSD system install utility.The authors and editors have taken care in preparation of the content contained herein, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for any damages. Always have a verified backup before making any changes.