2009-05-04

Shell History Stats

Inspired by reading an old thread on my local Linux user group mailing list:

$ history | awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}' | sort -rn | head

94 povray
58 source
55 ./wacdump
32 l
31 cd
25 dcraw
22 cp
21 gimp
20 less
19 gvim

:) I should run that more often. Maybe feed to Twitter. Or not.

2009-05-02

Arduino mouse control for Pure Data using Expect

Here’s a little Expect script for getting a control stream into Pure Data, in my case from a butchered Genius serial mouse that I wrote an interrupt-driven Arduino driver for. The driver sends a “+” or “-” down the serial line each time the optical rotary encoder in the mouse guts moves a click. This assumes the Arduino is connected on /dev/ttyUSB0 (e.g. on Linux). Use a [netreceive 3000] (or whatever port you like) in Pure Data to receive.

Note: this only uses one mouse axis, requiring two interrupts. Apparntley the Arduino Mega has six interrupt lines externally available, so I'll be adding another axis of control soon.

#!/usr/bin/expect

# Take Arduino mouse '+'/'-' stream and convert into Pure Data FUDI format, without buffering.

# To run:
# expect mouse-pd.expect | pdsend 3000

# TODO: this should probably use Expect's stty command to set the serial port up to match the Arduino program.

eval spawn -noecho cat /dev/ttyUSB0
log_user 0
while (true) {
 expect {
  + {send_user "1;\n"}
  -- {-} {send_user -- "-1;\n"}
 }
}

Here’s the Arduino code:

// Simple interrupt-driven driver for quadrature encoder input (e.g. from a disassembled photoelectric ball mouse).
// Many Arduino boards provide only two interrupts, I believe: INT0 (on pin 2) and INT1 (on pin 3):
const int intA = 0, intAPin = 2;
const int intB = 1, intBPin = 3;

volatile int A = 0, B = 0;  // For storing the pin states for future reference to determine rotation direction
int A_Prev = 0, B_Prev = 0;  // Should these be volatile, too?



void setup()
{
  // Configure digital input pins for interrupt-driven timing:
  pinMode(intAPin, INPUT); digitalWrite(intAPin, LOW);
  pinMode(intBPin, INPUT); digitalWrite(intBPin, LOW);
  
  Serial.begin(115200);
  
  // Read initial state of the pins:
  A_Prev = digitalRead(intAPin);
  B_Prev = digitalRead(intBPin);
  A = digitalRead(intAPin);
  B = digitalRead(intBPin);

  attachInterrupt(intA, changeA, CHANGE);
  attachInterrupt(intB, changeB, CHANGE);
}


void changeA()
{
  A = !A;
  output();
  A_Prev = A;
}


void changeB()
{
  B = !B;
  output();
  B_Prev = B;
}


void output()
{
  if (A == B_Prev)
    Serial.print("+");
  else if (B == A_Prev)
    Serial.print("-");
  else
    Serial.print('?');
}


void loop() {}

Microcontroller programming is fun, BTW! I’d never written a driver or an interrupt handler until two days ago.