Thursday, November 17, 2011

Gnuplot: splot data rows conditionally depending upon a column value

Gnuplot will easily plot data from a file having several rows but only using columns of data specified. A command like this:

splot "data.csv" using 2:3:4 with lines

...will plot data from the file using X,Y,Z values from columns 2,3,4 and ignoring all others. Sometimes however, it's helpful to plot rows based upon a condition within the data for a column, and it's easy to perform simple numeric comparisons on column values:

splot "data.csv" using ($5==1?$2:NaN):3:4 with lines

Note: the value for X (of the X,Y,Z coord) being NaN (not a number) causes gnuplot to ignore the row.

This will result in gnuplot only plotting the values for rows where the numeric value in column 5 is equal to 1 (or 1.00000 in the case I was using).

Similarly, one recent need was to ignore data (rows) if a column value contained a '?' character in the 16'th position. The data looks like:

291:20:04:59.410,-7872470.049126,-15084862.45306,12185551.690250
291:20:04:59.51?,-7872470.049126,-15084862.45306,12185551.690250

The '?' character means the data is "bad" and should be ignored (probably?) so when the plot is done, that row should be ignored. Gnuplot has a "substr" command that will extract a substring from the value for comparison, however the column is numeric and it must be converted into a string first via "strcol" and since it is a string the "eq" or "ne" operator must be used (instead of "==" or "!="). The command is like so:

splot "data.txt" using ((substr(strcol(1),16,16) ne "?") ? $2 : NaN):3:4 with lines

...will plot only the rows where the 16th character of column 1 doesn't conain a '?' character.

Saturday, October 29, 2011

Linux: Flash: Sound doesn't work because a USB webcam is default playback device

A new USB webcam appears as the default audio playback device, this makes sound stop working for everything. Initially tried adding a ~/.asoundrc file like described here but this doesn't work because nothing can share the sound device anymore once the first program that uses sound places a lock on the device. There seems to be some variations (using dmix) of this thought as well, but they don't work either (or I couldn't get them to).

When you cat the sound device modules as so:

$ cat /proc/asound/modules
 0 snd_usb_audio
 1 snd_hda_intel
 2 snd_hda_intel


Then one can see that the USB device is the default, or at least the first, and changing the order might be helpful. This comment from here provided the solution:


Chuck Ebbert 2007-06-06 15:07:16 EDT
One thing to try is adding the line:

 options snd-usb-audio index=1

to /etc/modprobe.conf

The comment is old, probably, as there is no modprobe.conf in Slackware (or Redhat uses a different init standard?), but there is a modprobe.d/ folder with a collection of .conf files, so I added a snd-usb-audio.conf with the single line:

options snd-usb-audio index=2

Reboot and then the list of sound modules now looks like:

$ cat /proc/asound/modules
 0 snd_hda_intel
 1 snd_hda_intel
 2 snd_usb_audio 

Which makes audio work again, and it can be shared among several applications at once.

Wednesday, October 19, 2011

Old and large programming projects don't go away easily

You never know how long code you write might be around. In this case, almost 20 years.

Here is the "prototype" of the "toolbox" being shown in the "ITouch" program that I wrote in 1993 (yes, that "i-everything" was popular back then). The concept was around a idea by a friend who had an idea to develop a kind of digital brochure (sort of before the Internet). The brochure could be run off of a disk (yes, a floppy disk) or from a kiosk. It involved the use of a editor that would allow you to create several screens with buttons (e.g. "links") and text and pictures (which for 1992, weren't very good I'm afraid. This code is running from dosbox (yes, the code is that old) and using the MetaGraphics driver (you could compile for either Metagraphics or the BGI).


The dialog with the blue buttons is the "screen" being edited by using the iTouch editor. The snapshot is from the initial work on a point of sale system called "Alliance" (no longer in business) when I was recasting the idea towards the design of order entry screens (with more editing capability) where you could place objects from a library of POS functions on any number of screens. I don't know how unique the idea was at the time. Most of the systems, including RapidFire that I worked on as well, used a fixed-grid kind of arrangement of function placement, and limited the user on how many or what size buttons they could have.

And now, almost 20 years later, the code is still running in a point-of-sale system I helped write in 1994-2000 on Youtube here. (Note, the system was sold, so it's not the same company anymore).


The way the narrator stumbled around making the icon actually display makes me cringe though, but icons weren't something I really supported beyond a simple array of colored pixels, so I suppose it's something of an improvement to support PNGs.

In 1992 when I started writing the code, I hadn't heard of the Internet, and of course "Youtube" wasn't something anyone had thought of either. It's interesting to see it still being used though, almost 20 years later.

I suspect the copyright notice in the code has been removed though:

//------------------------------------------------------------------------//
// Code Name: "Panthera" (tm)                                             //
// Copyright (c) 1994 by C.I.A., All rights reserved.                     //
//                                                                        //
// GXL Graphical Interface Library                                        //
// Copyright (c) 1992-1994 by Kevin Hise, All rights reserved.            //
//                                                                        //
// GXL Streamable Objects Editor Components                               //
// Copyright (c) 1994 by Kevin Hise, All rights reserved.                 //
//                                                                        //
// *** Unauthorized possession or duplication of source or executable is  //
// *** strictly prohibited by the authors!                                //
//                                                                        //
//------------------------------------------------------------------------//


So you might have written the code, but don't count on getting any credit. Just look for the "JMJ" initials. *sigh*

Thursday, September 29, 2011

C++ template: Last Recently Used Cache

A last-recently-used cache implemented as a C++ template. Define the cache with the desired data and key type, then instantiate with the size. Items added or gotten are pushed towards the front (most recent) while those which have not been used in a while fall off the back as new items are added.

The cache is implemented via 2 STL structures, the first being a std::list of a std::pair of Data and Key, and the second structure being a std::map of Key and std::list iterator where the data is stored. The fact that the std::list contains a copy of the key may not be necessary, but makes dumping the cache for debug purposes convenient. A rather involved hierarchy of typedefs help ease the pain of using the data structures in the code.

/// @brief Typedef the cache item pair of 'data' and 'key' types.
typedef std::pair< Key, Data > Item;
/// @brief Typedef a list of Item(s).
typedef std::list< Item > Items;
/// @brief Typedef an iterator of the list of items.
typedef typename Items::iterator Items_iterator;
/// @brief Declare our cache to be a list of the Item(s).
Items m_Cache;
/// @brief Typedef an index of keys, and iterators to cache items.
typedef std::map< Key, Items_iterator > Index;
/// @brief Typedef an iterator to the index is helpful.
typedef typename Index::iterator Index_iterator;
/// @brief Typedef the insert to index result (iterator / bool pair).
typedef typename std::pair< Index_iterator, bool > Index_insert;
/// @brief An index instance.
Index m_Index;


Calling put(data,key) will add items to the cache.

/// @brief Put an item in the cache.
/// @note It is assumed that the key was searched for previously, and could
/// not be found, so the search is not done here.
/// @param[in] item The item that should be placed in the cache.
/// @param[in] key A key associated with the item.
/// @param True is returned if the item is added.
bool put( const Data &in, const Key &key ) {
    bool result = false;
    Items_iterator ix = m_Cache.insert( m_Cache.begin(), Item( key, in ) );
    Index_insert ii = m_Index.insert( 
        std::pair< Key, Items_iterator >( key, ix ) 
    );
    if ( !(result = ii.second) ) {
        m_Cache.erase( ix );
    } else {
        result = true;
        if ( m_Cache.size() > m_Size ) {
            Items_iterator ee = --m_Cache.end();
            if ( ee != m_Cache.end() ) {
                Index_iterator ii = m_Index.find( ee->first );
                m_Cache.erase( ee );
                if ( ii != m_Index.end() ) {
                    m_Index.erase( ii );
                }
            }
        }
    }
    return result;
}


And calling get(data,key) will return a copy if the cache has one.

/// @brief Get an item from the cache, if it exists.
/// @param[out] out Where the found item is copied to.
/// @param[in] key The key representing the item.
/// @return A true is returned if the item was in the cache.
bool get( Data &out, const Key &key ) {

    bool result = false;
    Index::iterator ii = m_Index.find( key );
    if ( ii != m_Index.end() ) {
        Items_iterator ix = ii->second;
        out = ix->second;
        m_Cache.splice( m_Cache.begin(), m_Cache, ix );
        result = true;
    }
    return result;
}


A link to the working (and tested) code can be found here: lru_cache.h Since I didn't give credit in the code for where I scrounged the idea, you don't either.

Wednesday, July 27, 2011

Slackware, xorg: Three montors with radeon dual-head and displaylink

The xorg.conf changes for the displaylink driver and a radeon video card. In my setup I had a old HP zd8000 laptop with a X600 card, and was able to use this configuration for a while until the laptop finally bit the dust (probably 7 years old, so it was "time" probably). Since the hardware where this configuration worked has died, this is sort of a postmortem review of what it took to get it running. Much of the information to get things working was taken from Mulchman's blog posting which can be found here.
 
The Slackware 13.37 install shipped with kernel 2.6.37.6, and in order to get the udlfb driver working properly, I needed to (which I discovered by accident) upgrade to the kernel in "testing" (e.g. 2.6.38.4).

The displaylink screen has to be the left-most screen for some reason.  The configuration would drive the displaylink screen on the left, the LVDS (laptop) screen in the center, and a 3rd monitor connected to the VGA output of the laptop as well, for a total of 3 screens.

The displaylink driver doesn't seem to know anything about "sleep" or "suspend to ram", so it must be restarted each time. "Restart" means killing off X, unplugging the displaylink USB cable, waiting for 10 seconds, then plugging it back in, waiting until the display that is being driven by the displaylink adapter turns green, then restarting X. I thought about experimenting with a powered USB hub that might keep the displaylink adapter powered while the machine was sleeping, but never got that far to see if it would work.

The udlfb driver is part of later kernels now (since 2.6.35?), so I don't think that the steps outlined by Mulchman or the Plugable site are required to install it. Mulchman references the xf86-video-displaylink driver, and Plugable makes use of a xf-video-udlfb driver, they seem to be almost equivalent, but not quite for some reason. In either case, the display driver must be downloaded via git, built, and then placed somewhere where X can find it.

The xorg ServerLayout section changes are like so:


Section "ServerLayout"
    Identifier   "X.org Configured"
      
    Screen       "DisplayLinkScreen"
    Screen       "Screen0" RightOf "DisplayLinkScreen"
    Screen       "Screen1" RightOF "Screen0"

    InputDevice  "Mouse0" "CorePointer"
    InputDevice  "Keyboard0" "CoreKeyboard"
    Option       "Xinerama" "on"
EndSection


The other sections relevant to the displaylink device, monitor, and screen:

Section "Device"
    Identifier "DisplayLinkDevice"
    Driver "displaylink"
    Option "fbdev" "/dev/fb1"
EndSection

Section "Monitor"
    Identifier "DisplayLinkMonitor"
EndSection


Section "Screen"
    Identifier "DisplayLinkScreen"
    Device "DisplayLinkDevice"
    Monitor "DisplayLinkMonitor"
    DefaultDepth 16
EndSection


Note: The displaylink driver only supports 16 bit color depth so all screens must have their depth fixed at 16.

The radeon device driver sections contain:


Section "Device"
    Option      "ZaphodHeads" "LVDS"
    Identifier  "Card0"
    Driver      "radeon"
    BusID       "PCI:1:0:0"
    Screen      0
EndSection



Section "Screen"
    Identifier   "Screen0"
    Device       "Card0"
    Monitor      "Monitor0"
    DefaultDepth 16
EndSection


Section "Device"
    Option     "ZaphodHeads" "VGA-0"
    Identifier "Card1"
    Driver     "radeon"
    BusID      "PCI:1:0:0"
    Screen     1
EndSection

Section "Screen"
    Identifier   "Screen1"
    Device       "Card1"
    Monitor      "Monitor1"
    DefaultDepth 16
EndSection

A screen capture would be nice here. Too bad I never thought to do that.