Embedded Systems Software, Computer Networking and Geeky Fun

nerd1951.com

June 11, 2008

Adivce to a new software engineer

Filed under: Rants — Harvey @ 7:57 pm

My nephew just graduated with a degree in computer science and I was thinking about what advice I would give him to help insure his success.  You can measure my experience as a software engineer in decades and it’s not easy to remain a respected and successful programmer for that long.  Since this is the time of year when many new computer science graduates start out their careers, I thought I’d share my thoughts.

First and foremost, like all businesses, the computer business is a people business. Work on your people skills. You don’t have to be a slick marketing type but learn to listen to people. Stay in touch with people who you connect with, especially people you admire; teachers, managers, colleagues, and classmates.

Learn to write well. At some point, coding is no longer as challenging and creative. The most creative work is in the design, specification and architecture of a system. Much of this needs to be communicated to others using the written word. Unless you took a double major in English, you haven’t really learned to write well in school. Like coding, the best way to learn to write is to write. There are often opportunities on and off the job to write. I’ve volunteered to write user manuals, advertising copy, news letters, and white papers over the years. This blog is a way for me to work on my writing.

Never stop learning. Take on difficult assignments – not easy ones that you already know how to do. Read articles on the ‘net and technical books about subjects that interest you.  Play with new technologies on your own time so that when that opportunity comes along to do something new, you already know about the technology. When I first started out as a software engineer, C, C++, the Internet Protocols, and personal computers did not exist. Unix was still pretty much in the lab. Since then I have mastered these technologies and have become an expert in some. Nearly all of this was accomplished through self study.

Finally, take on every assignment as though it was the most important thing you have ever worked on. Do a better job than what is expected and don’t settle for doing anything just good enough. You will be more satisfied with your job and will have more confidence in your product. The quality of your work may not always be appreciated but you’ll know you did your best and that is satisfaction enough.

Congratulations, welcome to the field, and good luck!

• • •
 

June 7, 2008

Encapsulating Shared Resource Access In C++

Filed under: Programming — Harvey @ 5:22 pm

One of the most common uses of threads in embedded systems is to serialize usage of shared resource such as data, I/O ports, sockets, or files. A typical implementation is to use a queue and a thread. Threads accessing the shared resource place requests or operations on the queue. A thread waits on the queue, dequeuing requests and performing the operations on the shared resource. Structurally, it looks something like this:

Usually it’s best to hide all of this complexity from the resource users. I usually place the thread, the queue and their related components in a single class. The resource user sees only one public function; queueRequest(Request&). This helps insure that users only access the resource through the access queue/thread. The name of the function reminds the user that the request may not be executed immediately. Now let’s look at an implementation in C++ using POSIX threads:

First the class declaration:

class SharedResource
{
public:
    SharedReasouce(Resource& resource);
    ~SharedResource();

    queueRequest(Request&);

private:
    static void* accessThread(void* params);

    Resource&             _resource;
    std::queue<request&>  _requestQueue;
    pthread_t             _accessThreadId;
    pthread_cond_t     _queueSignal;
    pthread_mutex_t       _queueMutex;  // Required to use pthread condition code
};

We pass a reference to the resource to the constructor. This way if we have several resources of the same type, we can create an object using this class for each of the resources.

The thread function must be static in order to use it with the POSIX create_thread function. Thread functions take a single parameter, a void pointer. We will use this pointer to pass the this pointer to the thread.

The queueSignal condition code is used to signal accessThread when a request has been placed on the queue. Pthreads requires that you use a mutex to signal a condition code and this is what queueMutex is used for.

Now let’s look at the constructor:

SharedResource::SharedResource(Resource& resource)
{
    _resource = resource;
    pthread_mutex_init(&_queueMutex, 0);
    pthread_cond_init(&_queueSignal, 0);
    pthread_create(&_accessThreadId, 0, SharedResource::accessThread, this);
}

The constructor makes a copy of the resource reference and creates the pthread condition code and mutex.  Then the access thread is created.  This starts execution of the function  SharedResources::accessThread.  A pointer of this instance of class SharedResource, the this pointer, is passed to the thread function as a parameter.

The queueRequest function is streight-forward.  It simply places a request reference in the queue then signals the accessThread that a request is in the queue:

void SharedResource::queueRequest(Request& request)
{
    _commandQueue.push(request);
    pthread_cond_signal(&_queueSignal);
}

Finally let’s take a look at the thread itself:

void* SharedResource::accessThread(void* param)
{
    // Convert the void* parameter back to a SharedResource reference
    SharedResource& sharedResource = reinterpret_cast<SharedResource&>(param);
    while(1)
    {
        // Wait on the request queue
        pthread_mutex_lock(&sharedResource._queueMutex);
        pthread_cond_wait(&sharedResource._queueSignal,
            &sharedResource._queueMutex);

        // Dequeue any requests and process them
        while(sharedResource._requestQueue.size() > 0)
        {
            request = sharedResource._requestQueue.front();
            sharedResource._requestQueue.pop();

            // process the request on resource
        }
    }
}

A couple of things to note.  In an actual program, you would check the return codes of each of the function calls in the constructor that allocate resources.  If one of these functions fails you need to clean up any allocated resources and probably throw an exception.

• • •
 

June 2, 2008

Installing rpm packages on Ubuntu Linux

Filed under: Tools, Programming — Harvey @ 9:02 pm

I’ve become a big Ubuntu Linux fan. It’s not that I hate Red Hat Linux. I used Fedora Core Linux all the time until it wouldn’t run on my shiny new computer.  After that I found the Ubuntu package manager to be a real joy to use. I also like the fact that Ubuntu doesn’t install hundreds of extra packages when you install it.

But, what impressed me most was the last major Ubuntu upgrade. The update manager showed a button one day indicating that I could upgrade from version 7.10 to 8.04. I carefully backed up all my critical files and then clicked on the upgrade button. About a half hour later, I was running Ubuntu 8.04 without having to configure anything or restore any of my files.

There are some software packages though that are not available as Debian packages, which is what Ubuntu uses. This is especially true for cross development versions of GCC which we commonly use in the embedded systems world. Often our choices are an rpm file or a tar file. While tar files are usually fine, the rpm files, like Debian deb files contain some additional configuration information. If you simply use the tar files then you have to figure out where the files should reside and what environment variables you need to define. Both rpm and deb package managers take care of these details for you when you install from the package files. The problem arises when you are using a Debian based Linux such as Ubuntu and the package you want is only available as an rpm. The rpm packages are designed to be installed on Red Hat or Fedora Linux and can’t be natively installed on Ubuntu.

This is where the alien command comes in. The alien command converts rpm packages to deb packages. If you invoke alien with the -i option it will then install the deb package. Also remember that you need super user privileges to install software packages so the command to install an rpm on Ubuntu would be something like this:

$ sudo alien -i blackfin-toolchain-08r1-8.i386.rpm

In this case, installing a GNU tool chain for Analog Devices’ Blackfin processor.

Most likely, alien is not installed on your computer but it is easy to get using apt-get:

$ sudo apt-get install alien

• • •