Wednesday, February 05, 2014

wicket session cookie path and nginx

i found that wicket was setting cookies something like this:

Set-Cookie:JSESSIONID=CK_iXXR-Sj11WxeJjPz2R8VI; path=

where the path wasn't set. if the page that set the cookie was in /foo/bar/MyPage then resources at /myservlet were not getting the cookie passed. this caused a problem when i deep linked users and the cookie was being set from a deeper path and not the home page. it looked like others had similar problems and couldn't find a setting in wicket so i looked to nginx to deal with it. the fix was quite simple:

 proxy_cookie_path '' /;

here's the page i used for reference:

Wednesday, November 27, 2013

most useless machine ever

I saw this funny video awhile ago and I thought it'd make a good gift.

https://www.youtube.com/watch?v=Z86V_ICUCD4

If anybody gets the courage to build one, here's a neat game I wrote based on that idea:


/**
 * my dumbox game:
 * 
 * 3 leds, 1 button, 1 servo to reset game
 * leds on pins 2, 3, 4
 * switch on pin 5
 * servo on pin 9
 * 
 * init:
 * toggle switch lights up each of the 3 lights, then begins game.
 * if game is lost, lights turn off and box resets
 * 
 * game:
 * first led blinks random times at some rate then goes to second
 * and third led, user must flip switch between last 2 leds to
 * continue to faster rate, losing resets game
 * 
 * inspired by the most useless machine ever:
 * https://www.youtube.com/watch?v=Z86V_ICUCD4
 */

#include <Servo.h> 

Servo myservo;

bool inGame;
int initStep;
bool gameInitted;
int gameRate;

const int INIT_STEP_COUNT = 3;
const int PRE_DELAY = 1000;
const int SWITCH_PIN = 5;
const int SERVO_DELAY = 700;
const int SERVO_MIN = 3;
const int SERVO_MAX = 118;
const int MIN_RANDOM = 2;
const int MAX_RANDOM = 10;
const int GAME_DELAY = 300;
const int GAME_RATE_SLOW = 1000;
const int GAME_RATE_FAST = 200;
const int GAME_SPEEDUP = 200;

void setup() 

pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, INPUT);

myservo.attach(9);
reset();  
}

void reset() {
inGame = false;
initStep = 0;
gameInitted = false;
gameRate = GAME_RATE_SLOW;

myservo.write(SERVO_MIN);
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
}

void doPreGame() {
if (digitalRead(SWITCH_PIN) == LOW) {
delay(random(PRE_DELAY));

myservo.write(SERVO_MAX);
delay(SERVO_DELAY);
myservo.write(SERVO_MIN);

if (initStep >= 0 && initStep < INIT_STEP_COUNT) {
digitalWrite(initStep + 2, HIGH);
}
initStep++;

if (initStep >= INIT_STEP_COUNT) {
inGame = true;
}
}
}

/**
 * flash lights a bit to let player know game is about to start
 */
void initGame() {
for (int i=0; i<10; i++) {
for (int j=2; j<5; j++) {
digitalWrite(j, HIGH);
delay(25);
digitalWrite(j, LOW);
delay(25);
}
}
gameInitted = true;
}

void playGame() {
//first blink random times
int rand = random(MIN_RANDOM, MAX_RANDOM);
for (int i=0; i<rand; i++) {
digitalWrite(2, HIGH);
delay(gameRate);
digitalWrite(2, LOW);
delay(gameRate);
}
if (digitalRead(SWITCH_PIN) == LOW) {
delay(GAME_DELAY);
reset();
return;
}

digitalWrite(3, HIGH);
delay(gameRate);
digitalWrite(3, LOW);
delay(gameRate);

if (digitalRead(SWITCH_PIN) != LOW) {
delay(GAME_DELAY);
reset();
return;
}

digitalWrite(4, HIGH);
delay(gameRate);
digitalWrite(4, LOW);
delay(gameRate);

gameAdvance();
}

/** game advance animation */
void gameAdvance() {
delay(GAME_DELAY);
myservo.write(SERVO_MAX);
delay(SERVO_DELAY);
myservo.write(SERVO_MIN);

gameRate -= GAME_SPEEDUP;
if (gameRate < GAME_RATE_FAST) {
gameRate = GAME_RATE_FAST;
}

for (int i=0; i<10; i++) {
for (int j=2; j<5; j++) {
digitalWrite(j, HIGH);
delay(50);
digitalWrite(j, LOW);
delay(50);
}
}
}

void loop() 
{
if (!inGame) {
doPreGame();
} else if (!gameInitted) {
initGame();
} else {
playGame();
}



Tuesday, August 27, 2013

how to fix ubuntu's dns settings

i typically use slackware and dns settings just work. whenever i try out an ubuntu vm, my dhcp-configured local dns server always partially works. for example:
$ cat /etc/resolve.conf
nameserver 192.168.1.1
search local
$ ping svnserver
PING svnserver.local (192.168.1.100) 56(84) bytes of data.
64 bytes from svn.thedeanda.com (192.168.1.100): icmp_req=1 ttl=64 time=0.627 ms
$ ping svnserver.local
ping: unknown host svnserver.local
now edit /etc/nsswitch.conf and so the hosts line looks like:
hosts: files dns
$ ping svnserver.local
PING svnserver.local (192.168.1.100) 56(84) bytes of data.
64 bytes from svnserver.local (192.168.1.100): icmp_req=1 ttl=64 time=0.271 ms
all the extra entries and the "[NOTFOUND=return]" in the middle of the line makes it give up before trying dns. i'm not sure why ubuntu does it this way. its a tricky one to find so i thought i'd share.

Thursday, June 07, 2012

Ubuntu Startup Script for Jboss as Non-root User

So ever since I started using Ubuntu I have been trying to figure out startup scripts. I think I finally cracked the code. Below is a startup script (saved in /etc/init.d/jboss ) that I use to start/stop a jboss instance on my ubuntu vm. To actually install I had to run this:

sudo update-rc.d jboss defaults

Notice that my jboss does NOT run as root and its just installed in my users home directory. I'm not a fan of running services as root. Here is the startup script:

#!/bin/sh

### BEGIN INIT INFO
# Provides:             jboss
# Required-Start:       $local_fs $remote_fs $network $syslog
# Required-Stop:        $local_fs $remote_fs $network $syslog
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    JBoss Server
# Description:          JBoss Application Server
### END INIT INFO

#
# this is a basic start stop script that can be run as
# $0 start or $0 stop or $0 restart
#

JBOSS_HOME=/home/mdeanda/install/jboss
JBOSS_SCRIPT=./bin/standalone.sh
USER=mdeanda

set -e

. /lib/lsb/init-functions


start()
{
 cd ${JBOSS_HOME}
 rm -f /var/log/jboss.out
 touch /var/log/jboss.out
 chown ${USER} /var/log/jboss.out
 su ${USER} -c ${JBOSS_SCRIPT} > /var/log/jboss.out &
}

stop()
{
 #ps ax | grep java | grep jboss | cut -d' ' -f2 | xargs kill
 su ${USER} -c "${JBOSS_HOME}/bin/jboss-cli.sh --connect command=:shutdown"
}

case "$1" in
start)
 start
 ;;
stop)
 stop
 ;;
restart)
 stop
 start
 ;;
*)
 echo "Usage: $0 {start|stop|restart}"
 exit 1
esac

Wednesday, June 06, 2012

Control Arduino Sensor through your Browser!

I modified the basic Web Server example from the Arduino IDE to allow my arduino to control digital pins and report values of all available pins. I'm eventually going to use this to read the temperature of my server closet and control fans and turn computers on and off. I'll write a separate desktop program to actually control the device.
/*
  Web Enabled Sensor and Switch

 A simple web server that shows the value of the analog input pins and
 digits pins using an Arduino Wiznet Ethernet shield. Special URLs can
 drive the pins 0-9 (since 10-13 are used by ethernet shield).

 Use http://192.168.0.177/ to read the current state.
 Use http://192.168.0.177/01234 to toggle pints 0-4.
 Use http://192.168.0.177/2-3+ to turn off 2, turn on 3.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 * Digital outputs attached to pins D0 through D9 (optional)

 created 6 June 2012
 by Miguel De Anda
 based on Web Server example included in arduino package

 */

#include 
#include 
#include 
#include 

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,0, 177);
int pinState[10];

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup()
{
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
  for (int i=0; i<10; i++) {
    pinState[i] = LOW;
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
}

void loop()
{
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    int position = 0;
    boolean isFirstLine = true;
    char line[200];
    char firstLine[200];
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          interpret(firstLine);
          respond(firstLine, client);
          break;
        }
        if (c == '\n') {
          line[position] = '\0';
          // you're starting a new line
          currentLineIsBlank = true;
          position = 0;
          //now check if this line was a request line
          if (isFirstLine) {
            strcpy(firstLine, line);
            isFirstLine = false;
          }
        } else if (c != '\r') {
          line[position] = c;
          position++;
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }

    //serial_out(line);
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}

void respond(char * request, EthernetClient & client)
{
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/plain");
  client.println();

  // output the value of each analog input pin

  for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
    client.print("A");
    client.print(analogChannel);
    client.print("=");
    client.print(analogRead(analogChannel));
    client.println("");
  }
  for (int i=0; i<10; i++) {
    client.print("D");
    client.print(i);
    client.print("=");
    client.println(pinState[i]);
  }

  client.println(request);
}

void interpret(char * request)
{
  //only chars between first and second space are interpretted
  //digit means toggle that pin
  //later: digit followed by + means turn it on, - means off.
  int size = strlen(request);
  boolean started = false;
  int lastDigit = -1;
  for (int i=0; i= '0' && c <= '9') {
        int digit = c - '0';
        if (lastDigit != -1) {
          toggle(lastDigit);
        }
        lastDigit = digit;
      }
    }
  }
  if (lastDigit != -1) {
    toggle(lastDigit);
  }
}

void toggle(int lastDigit) {
  int state = pinState[lastDigit] == HIGH ? LOW : HIGH;
  pinState[lastDigit] = state;
  digitalWrite(lastDigit, state);
}

Sunday, December 11, 2011

Arduino + Rotary Encoders, rev2

This version of the rotary encoder code handles the random misreading and also has a 2 stage debouncer to help minimize the annoyance of the big debounce time. Here's the code:

/* 
   read a rotary encoder with interrupts
   Encoder hooked up with common to GROUND,
   encoderPinA to pin 2, encoderPinB to pin 3
   it doesn't matter which encoder pin you use for A or B  

   uses Arduino pullups on A & B channel outputs
   turning on the pullups saves having to hook up resistors 
   to the A & B channel outputs
   
   initially based on http://www.arduino.cc/playground/Main/RotaryEncoders
*/ 

#define encoderPinA 2
#define encoderPinB 3
#define interruptPin 0

const long encoderDebounce = 175;
const long encoderDebounceFast = 10;
const long encoderFastTimeout = 200;
const int encoderStepsTilFast = 2;
long nextEncoderTime = 0;
boolean encoderActive = false;
int encoderLastDirection = 0;

void setup() { 
  pinMode(encoderPinA, INPUT); 
  digitalWrite(encoderPinA, HIGH);
  pinMode(encoderPinB, INPUT); 
  digitalWrite(encoderPinB, HIGH);
  attachInterrupt(interruptPin, startEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2
  Serial.begin (9600);
  Serial.println("start");
} 

void loop() {
  if (encoderActive) {
    encoderActive = false;
    long now = millis();
    if (now > nextEncoderTime) {
      //reset fast debounce since there was a pause
      if (now > nextEncoderTime + encoderFastTimeout) {
        encoderLastDirection = 0;
      }
      int a = digitalRead(encoderPinA);
      int b = digitalRead(encoderPinB);
      int encoderDirection = 0;
      if (a == b && a == HIGH) {
        encoderDirection = 1;
      } else if (a != b && b == HIGH) {
        encoderDirection = -1;
      } else {
        encoderDirection = 0;
      }
      boolean fastMode = abs(encoderLastDirection) > encoderStepsTilFast;
      //if we get a random direction change while fast, ignore it
      if (fastMode
            && (encoderLastDirection > 0 && encoderDirection < 0
            || encoderLastDirection < 0 && encoderLastDirection > 0)) {
        encoderDirection = 0;
      }
      encoderLastDirection += encoderDirection;

      if (encoderDirection != 0) {
        nextEncoderTime = now + (fastMode ? encoderDebounceFast : encoderDebounce);
        Serial.println(encoderDirection);
      }
    }
  }

}

void startEncoder() {
  encoderActive = true;
}

Arduino + Rotary Encoders, rev1

After a few days of reading forums of how people can't get accurate results from a rotary encoder from an arduino, I finally figured out a way to make it work for me. In my application, its ok to drop a few "ticks" of the encoder but I really wanted to avoid over-counter and much worse, count in wrong direction. Other solutions often cause both when rotating at slow speeds. Attached is my 1st implementation that only uses the interrupt to notify the arduino that it should look at the encoder pins and instead uses the program loop to read the values. This may not be optimal for code that uses excessive delays but it works well for my application.

/* 
   read a rotary encoder with interrupts
   Encoder hooked up with common to GROUND,
   encoderPinA to pin 2, encoderPinB to pin 3
   it doesn't matter which encoder pin you use for A or B  

   uses Arduino pullups on A & B channel outputs
   turning on the pullups saves having to hook up resistors 
   to the A & B channel outputs
   
   initially based on http://www.arduino.cc/playground/Main/RotaryEncoders
*/ 

#define encoderPinA 2
#define encoderPinB 3
#define interruptPin 0

// we can probably have 2 stage debounce where 2nd stage 
// debounce lower when a few ticks in same direction
const long encoderDebounce = 150;
long nextEncoderTime = 0;
boolean encoderActive = false;

void setup() { 
  pinMode(encoderPinA, INPUT); 
  digitalWrite(encoderPinA, HIGH);
  pinMode(encoderPinB, INPUT); 
  digitalWrite(encoderPinB, HIGH);
  attachInterrupt(interruptPin, startEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2
  Serial.begin (9600);
  Serial.println("start");
} 

void loop() {
  if (encoderActive) {
    encoderActive = false;
    long now = millis();
    if (now > nextEncoderTime) {
      int a = digitalRead(encoderPinA);
      int b = digitalRead(encoderPinB);
      int encoderDirection = 0;
      if (a == b && a == HIGH) {
        encoderDirection = 1;
      } else if (a != b && b == HIGH) {
        encoderDirection = -1;
      } else {
        encoderDirection = 0;    
      }
      if (encoderDirection != 0) {
        Serial.println(encoderDirection);
        nextEncoderTime = now + encoderDebounce;
      }
    }
  }

}

void startEncoder() {
  encoderActive = true;
}

As you can see if relies heavily on a high debounce time. If I reduce the debounce time to less than 50, I get lots of double-counts on slow rotations so I just played it safe and set it really high. I'll address the limited count speed in my next post.

Friday, December 02, 2011

JavaJson

http://javajson.thedeanda.com is a great little open source JSON parser I wrote a few years ago. I've used it in lots of little projects including Android development. The project is hosted at sourceforge.