Wednesday 18 July 2007

UPDATE: Fix status timeout: status=0xd0 { Busy }

I got a nice Acer laptop for not much from PC World, but it has a sucky TSSTcorpCD/DVDW TS-L632D, ATAPI  CD/DVD-ROM drive. The manufacturers have released a firmware update, but not for my OEM. Bah!

Gareth and Gareth have explained how to do a firmware update which (as it works for me) is a better solution:


My own solution below is buggy and prone to calling the atapi reset TWICE (hanging the machine). I have a fix (not with me as I edit this now) which prevents the atapi reset being called twice in one minute, but I think the better solution is the firmware update.

As a consequence if the moon shakes a bit too much or one of the electrons gets a bit too hot, the CDROM drive stops responding. For windows users it disappears from My Computer altogether and they have to reboot.

Linux users are both better and worse off. Worse because the system hangs 4 seconds out of 5 and the syslog fills up with messages like "/dev/hdc: status timeout: status=0xd0 { Busy }"

If you can bear to slowly get a command window, a bit of "sudo hdparm -w /dev/hdc" will fix it, but thats too painful.

So, this script will fix it. You need to modify /etc/syslog.conf to add this line "kern.* /var/log/kern.fifo" to log kernel messages to a named pipe from which the script will read.

Install the script in /usr/local/sbin/fixhdc, and run it from /etc/rc.local with: "setsid /usr/local/sbin/fixhdc &"

#! /bin/bash
# /usr/local/sbin/fixhdc
# by Sam Liddicott
# Monitor kernel messages to see if the cdrom is jiggered
# If so do an atapi reset
# First add this line to /etc/syslog.conf
# kern.* /var/log/kern.fifo
# Then run this script from /etc/rc.local with:
# setsid /usr/local/sbin/fixhdc &



daemon() {
  while read logline
    case "$logline" in
      *"$CDROM: status timeout: status=0xd0 { Busy }"*)
        hdparm -w "$CDROM_NODE"
        logger -t ‘kern.crit’ — "$0 reset $CDROM"
      *) echo "Ignore $logline";;

while :
  if test -p "$KERNFIFO" || mkfifo "$KERNFIFO"
  then daemon < "$KERNFIFO" &
       # restart syslog now we have the pipe open
       /etc/init.d/sysklogd reload
       # it probably won’t finish till syslog does
       logger — "Restarting $0"
  else echo "Can’t make fifo $KERNFIFO"
       exit 1

Thursday 12 July 2007

Windows-only IP camera on linux

I got a nice panning VGA camera for £69.00, but it’s one of those cameras from hell that only supports internet explorer on windows and crashes windows a lot.

As far as I can tell generically it is an SQ IP Cam or a GP-280 IP Camera.

I want to use it on linux, so out comes ethereal to do some packet sniffing and here is what I get:

I can get a video stream (special header and concatenated JPEG’s) with this URL:

Possibly the RootCookies bit is important, perhaps related to a login that occurred earlier.

I can move the camera wth:

For horizontal and vertical centre

Full centre

To stop

The special header on the video stream is a 40 byte header. I’m expecting certain values so they were easy to find:

Stream Header
Offset Format Data
0×16-0×17 16 bit integer LSB size of jpeg in bytes, or in other words, the number of bytes to read after this header before the start of the next header
0×1a-0×1b 16 bit integer LSB jpeg width in pixels
0×1c-0×1d 16 bit integer LSB jpeg height in pixels
0×28- Start of JPEG header

So stripping off the first 40 byte with
dd if=stream of=1.jpeg bs=1 skip=40

leaves me a jpeg (with loads more jpegs on the end, ech prefixed by the same 28 byte header).

So I can control the camera and rip video from it, now to make it like zoneminder.


I can watch a video stream with VLC using:

wget -O /dev/stdout |dd  skip=40 bs=1 | vlc -

I modified axmjpeg so it can split images from my camera too.

Update: 20 Sept 2007
This patch has been reworked applied to the standard axmjpeg project. (a while ago!)

This script can be used to control the camera from zoneminder:

#! /bin/bash
presets="nothing motor_control_auto_h motor_control_auto_v motor_control_stop motor_control_center"

while test -n "$1"
  case "$1" in
    --address=*) address="${1##--address=}";;
    --address)   address="$2"; shift;;
    --command=*) command="${1##--command=}";;
    --command)   command="$2"; shift;;
    --preset=*)  preset="${1##--command=}";;
    --preset)    preset="$2"; shift;;


case "$command" in
  # home goto
  preset_home) url_command="motor_control_center";;
  preset_goto) set $presets; shift "$preset"; url_command="$1";;
  # right left down up
  move_rel_*) url_command="motor_control_${command##move_rel_}" ;;

wget -O /dev/null "$url" 2>/dev/null

UPDATE snapshot

I found a URL that can be used for a single snapshot (based on this

Also related source code here:

UPDATE streaming

I can play the stream like this:

ffplay -f mjpeg -probesize 40 -i ''

tip from

but it seems more reliable to use axmjpeg to remove the extra data and output just a concatenation of jpegs:

axmjpeg -N -o /dev/stdout  '' | ffplay -f mjpeg /dev/stdin