Sunday, April 25, 2010

Working with named pipes in tcl

Today I wanted to pipe lines of output from a C program into a TCL program using a named pipe, so that I didn't have to start them up at the same time. First I created the pipe with mkfifo:

$ mkfifo foo

Then here's the magic incantation in TCL to open the pipe and run a function every time something comes in:

set fifo [open "foo" {RDWR NONBLOCK}]
fconfigure $fifo -blocking 1
proc read_fifo {} {
global fifo

gets $fifo x
puts "x is $x"
}
fileevent $fifo readable read_fifo

Then when I write to the fifo, my program prints them:

$ echo "asdf" > foo

Make sure you write newlines when you write to the fifo so that gets doesn't block (or use read instead).

Saturday, April 24, 2010

Chicken tortilla casserole

Quick and easy.

1 can cream of mushroom soup
1 can cream of celery soup
1 onion, chopped
3 boneless chicken breasts, diced
1 can chopped tomatoes (or use fresh tomatoes)
1 small can green chiles (or fresh)
1 small can olives
4 or more corn tortillas, cut into strips
8-16 ounces grated mozzarella or cheddar cheese
1 cup salsa

Mix up all the liquid and small stuff in a glass 9x13" casserole dish, then mix in the tortillas and chicken. Top with cheese. 350F for one hour.

Sunday, April 18, 2010

v4l2 example

Update: Updated the sample code to spit out a grayscale ASCII PGM on stdout so you can actually see what it's
capturing.

Looks like the video4linux project could use a convenience library for people who want to do simple things. But at least they have good example code.

The official v4l2 example worked pretty well for me. It worked fine with my capture card, but I got "VIDIOC_S_FMT error 22, Invalid argument" errors when I tried it with my webcam. Switching to "V4L2_PIX_FMT_YUV420" from "V4L2_PIX_FMT_YUYV" fixed it. I also simplified it a bit, taking out the command line options, MMAP code and the USERP (which didn't work for me anyway). It gets the example down from 675 lines to a little under 300, and makes it a little closer to my purposes.


/*
* V4L2 video capture example
*
* This program can be used and distributed without restrictions.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <asm/types.h> /* for videodev2.h */

#include <linux/videodev2.h>

#define CLEAR(x) memset (&(x), 0, sizeof (x))

struct buffer {
void *start;
size_t length;
};

static int fd = -1;
struct buffer *buffers = NULL;
static unsigned int n_buffers = 0;

static void errno_exit(const char *s) {
fprintf (stderr, "%s error %d, %s\n", s, errno, strerror (errno));

exit (EXIT_FAILURE);
}

static int xioctl(int fd, int request, void * arg) {
int r;

do r = ioctl (fd, request, arg);
while (-1 == r && EINTR == errno);

return r;
}

static void process_image(const void *p) {
fputc ('.', stdout);
fflush (stdout);
}

static int read_frame(void) {
struct v4l2_buffer buf;
unsigned int i;

if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
switch (errno) {
case EAGAIN:
return 0;

case EIO:
/* Could ignore EIO, see spec. */
/* fall through */

default:
errno_exit ("read");
}
}

process_image (buffers[0].start);

return 1;
}

static void mainloop(void) {
unsigned int count;

count = 100;

while (count-- > 0) {
for (;;) {
fd_set fds;
struct timeval tv;
int r;

FD_ZERO (&fds);
FD_SET (fd, &fds);

/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;

r = select (fd + 1, &fds, NULL, NULL, &tv);

if (-1 == r) {
if (EINTR == errno)
continue;

errno_exit ("select");
}

if (0 == r) {
fprintf (stderr, "select timeout\n");
exit (EXIT_FAILURE);
}

if (read_frame ())
break;

/* EAGAIN - continue select loop. */
}
}
}

static void uninit_device(void) {
unsigned int i;

free (buffers[0].start);
free (buffers);
}

static void init_read(unsigned int buffer_size) {
buffers = calloc (1, sizeof (*buffers));

if (!buffers) {
fprintf (stderr, "Out of memory\n");
exit (EXIT_FAILURE);
}

buffers[0].length = buffer_size;
buffers[0].start = malloc (buffer_size);

if (!buffers[0].start) {
fprintf (stderr, "Out of memory\n");
exit (EXIT_FAILURE);
}
}

static void init_device(char *dev_name) {
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
unsigned int min;

if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
if (EINVAL == errno) {
fprintf (stderr, "%s is no V4L2 device\n",
dev_name);
exit (EXIT_FAILURE);
} else {
errno_exit ("VIDIOC_QUERYCAP");
}
}

if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf (stderr, "%s is no video capture device\n",
dev_name);
exit (EXIT_FAILURE);
}

if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
fprintf (stderr, "%s does not support read i/o\n",
dev_name);
exit (EXIT_FAILURE);
}

/* Select video input, video standard and tune here. */

CLEAR (cropcap);

cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; /* reset to default */

if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
switch (errno) {
case EINVAL:
/* Cropping not supported. */
break;
default:
/* Errors ignored. */
break;
}
}
} else {
/* Errors ignored. */
}


CLEAR (fmt);

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;

// This worked with my capture card, but bombed with
// "VIDIOC_S_FMT error 22, Invalid argument" on my Logitech QuickCam Pro 4000
// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
// This worked on the logitech:
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;

fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
errno_exit("VIDIOC_S_FMT");

/* Note VIDIOC_S_FMT may change width and height. */

/* Buggy driver paranoia. */
min = fmt.fmt.pix.width * 2;
if (fmt.fmt.pix.bytesperline < min)
fmt.fmt.pix.bytesperline = min;
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
if (fmt.fmt.pix.sizeimage < min)
fmt.fmt.pix.sizeimage = min;

init_read (fmt.fmt.pix.sizeimage);
}

static void close_device(void) {
if (-1 == close (fd))
errno_exit ("close");

fd = -1;
}

static void open_device(char *dev_name) {
struct stat st;

if (-1 == stat (dev_name, &st)) {
fprintf (stderr, "Cannot identify '%s': %d, %s\n",
dev_name, errno, strerror (errno));
exit (EXIT_FAILURE);
}

if (!S_ISCHR (st.st_mode)) {
fprintf (stderr, "%s is no device\n", dev_name);
exit (EXIT_FAILURE);
}

fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

if (-1 == fd) {
fprintf (stderr, "Cannot open '%s': %d, %s\n",
dev_name, errno, strerror (errno));
exit (EXIT_FAILURE);
}
}

int main(int argc, char **argv) {
char *dev_name = "/dev/video1";

open_device(dev_name);
init_device(dev_name);
mainloop();
uninit_device();
close_device();

exit(EXIT_SUCCESS);
return 0;
}

Friday, April 16, 2010

ubuntu karmic grub error: "no such device" uuid/search nonsense

After cloning my recent karmic koala (9.10) install to another machine, I was annoyed that it wouldn't boot. It said:


error: no such device: ....

Failed to boot default entries.


Karmic now locates disk by UUID instead of the more traditional /dev/sda notation, which sucks when you want to clone a disk. But it's easy enough to fix.

To get it to boot once, use "e" from the grub menu to edit the command line. Remove the entire line that says:


search --no-floppy --fs-uuid --set ...


Then change the root= option in the next line to use /dev/sda1 instead of mounting by UUID:


/libux/boot/vmlinuz-... root=/dev/sda1 ro quiet splash


Then hit control-x to boot with those settings.

To fix it for good once the system boots, sudo gedit /etc/default/grub and uncomment this line:


# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
GRUB_DISABLE_LINUX_UUID=true


Next, sudo gedit /etc/fstab and replace the UUID=... with /dev/sda1 for the / partition and /dev/sda5 for the swap partition (assuming you had ubuntu use the whole disk during install).

Finally, sudo gedit /usr/lib/grub/grub-mkconfig_lib and find this line (line 174 for me):


echo "search --no-floppy --fs-uuid --set ${fs_uuid}"


Change it to:


echo ""


Finally, sudo update-grub2 to write the changes to disk. Then cross your fingers and reboot.

Wednesday, April 14, 2010

Running gnome applications over ssh

If you "ssh -X" into some machine and can run X apps fine, but can't run some gnome apps, and get errors about dbus sockets, run "export `dbus-launch`" from your ssh session to set up the environment variables you need.

Sunday, April 11, 2010

Ubuntu Linux Sketchup using Wine

Update2: I found a much more general solution to the redraw problem.

Update: I'm not sure if that worked or not. I think it improved the situation, but didn't fix the refresh problems entirely.

I've been using Sketchup successfully for quite a while now in Ubuntu linux. The trick was to install the wine PPA in order to get a more recent version of wine than Ubuntu distributes by default.

However, at home I had screen update problems: for instance, when I'd mouse over a face with the push/pull tool, it wouldn't draw in the crosshatching until I left the face.

But today I figured out how to solve the refresh problems, thanks to a comment in the wine appdb entry for sketchup 7. I ran nvidia-settings, then set:

NVIDIA X Server Settings manager checked
Antialiasing Settings - Override Application - Off
Anisotropic Filtering - Override Application - 1x

The next time I started up sketchup, it worked fine.

Saturday, April 10, 2010

balancethebudget.com

This is a pretty neat site that shows how the federal budget breaks down and lets you try your hand at balancing the budget:

http://balancethebudget.com/#

Seems to be unbiased. I was recently surprised by these numbers about state and local spending, which show, for instance, that we actually spend more on education tha...n defense. So it'd be interesting to see state and local budgets represented as well:

http://www.usgovernmentspending.com/year2006_0.html

I'd also like it to break down my own tax burden, since it's hard to contextualize billions and trillions. I'd rather see it as: "you spent $17 this year on farm subsidies, $7313 on defense, $7819 on public schools..."

I also think it'd be neat to let people see what would happen if individual tax checks went directly to specific programs, until those programs filled up. That is, I could enter my approximate income or how much my total tax burden was. Then a roulette wheel would spin, and it'd have a N percent chance of landing in the "defense" category, since defense uses N% of the budget. Then it'd drill down into the defense budget, making weighted-random choices until it tells me that my entire burden went to buying 8% of a single missile, for example.

Friday, April 09, 2010

Android Scripting Environment: launch a script from adb

ASE is pretty slick; makes it very easy to do simple things in Android. Here's how to launch a script from the command line after using "adb shell" to get a shell prompt:


# Launch an activity in the background:
$ am start -a com.google.ase.action.LAUNCH_SCRIPT -n com.google.ase/.activity.AseServiceLauncher -e com.google.ase.extra.SCRIPT_NAME test.py

# Launch an activity in a new terminal:
$ am start -a com.google.ase.action.LAUNCH_TERMINAL -n com.google.ase/.activity.AseServiceLauncher -e com.google.ase.extra.SCRIPT_NAME test.py


And here's the java file where they name all the intents in ASE.