INPUT MY OUTPUT
RESEARCH & EXPERIMENTS
I’m currently learning node.js and was super excited to get a chat server to work. In this example I’m using telnet to connect to my server 3 times which generates three sockets where data is transfered in realtime between all parties. Below is the code:

var net = require('net') //TCP Server 
 
var sockets = [] //empty array for ppl who connect to server
 
var server = net.createServer(function(socket){
	sockets.push(socket); //add person to socket
 
	socket.on('data', function(data){
		for(var i = 0; i<sockets.length; i++){
			if(sockets[i] == socket) continue; //dont broadcast your own echo
			sockets[i].write(data); //when data is received write
		}
	});
 
	//remove socket from arary
	socket.on('end', function(){
		var i = sockets.indexOf(socket);
		sockets.splice(i,1); //remove person from array
		//could also do-- delete socket.[0]
	});
});
 
server.listen(8000);
Through my research on emotional computers I’ve stumbled upon the thesis for my journal article: Can a human ever love a computer? It’s very clear to me that we’ll eventually be able to create computers that can genuinely love a human, but my real question is if a human can reciprocate these emotions knowing that they are coming from a machine?

This week I started reading Wired for Speech by Clifford Nass and Scott Brave. They discuss the human-computer relationship in regards to speech and have conducted many interesting tests to prove theories. Based on their studies humans have affiliations with computers that can speak which directly affects how they judge them and feel about them. For instance, a computer with a feminine voice who is teaching a lesson is more likely to be thought of as emotional and less strict than a computer with a male voice (who teaches the exact same lesson). Personalities are also generated based on how feminine or masculine a computers voice is even when synthetic.

Regarding the reciprocation of love to a computer – in December 2009 – a human for the first time attempted to marry a fictitious character from a video game. The character married was from a Nintendo DS game called “Love Plus.” Sal, the human, stated “I love this character, not a machine”…”I understand 100 percent that this is a game.” But does this love come from an addiction and are these feelings as ‘authentic’ as the love one feels for a human? Hiroshi Ashizaki, an author on internet and game addiction thinks that Sal’s relation is healthy and that the youth is feeling more and more comfortable expressing their true selves through virtual worlds rather than the real world.

Overall, there are a lot of mixed perceptions on this topic. With an experiment of my own I’m looking to help shed some more light on the topic (experiment to be announced when results are collected).

The Arduino code is as follows:

#define FORWARD 10
#define REVERSE 20
#define STOPPED 30
 
#define forwardPin 6
#define reversePin 7
#define leftPin  8
#define rightPin 9
 
#define pulseDuration 500
#include <SPI.h>
#include <Ethernet.h>
//setup          10    A5    DA    00    85    70
byte mac[] = { 0x10, 0xA5, 0xDA, 0x00, 0x85, 0x70 };
IPAddress server (XXX,XXX,XXX,XX);  // my server
int port = 12002;
EthernetClient client;
 
unsigned long startPulseTime = 0;
int drivingState = STOPPED;
int inByte = 0;         // incoming serial byte
// The setup() method runs once, when the sketch starts
 
void setup()   { 
  // initialize the digital pin as an output:
  pinMode(forwardPin, OUTPUT);
  pinMode(reversePin, OUTPUT);
  pinMode(leftPin, OUTPUT);
  pinMode(rightPin, OUTPUT);
 
  Ethernet.begin(mac);
  Serial.begin(9600);
  delay(1000);
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  } 
  Serial.println("Ethernet reday");
  serverConnect();
}
void serverConnect(){
  Serial.println("connecting to remote server...");
  if (client.connect(server, port)) {
    Serial.println("connected to remote server");
    client.println('A');
  } 
  else {
    Serial.println("remote connection failed");
  }
}
 
// the loop() method runs over and over again,
// as long as the Arduino has power
 
void loop() {
  // if we get a valid byte, read analog ins:
  if (client.available()) {
    // get incoming byte:
    inByte = client.read();
    //Serial.print(inByte);
    switch(inByte){
    case '2': 
      Serial.println("forward"); 
      forward(); 
      break;
    case '8': 
      Serial.println("reverse"); 
      reverse(); 
      break;
    case '4': 
      Serial.println("left"); 
      turnLeft(); 
      break;
    case '6': 
      Serial.println("right"); 
      turnRight(); 
      break;
    }
  } else {
    if (drivingState != STOPPED){
      if ((millis() - startPulseTime) > pulseDuration){
        Serial.println("pulse ended");
        powerStop(); 
      }
    }
  }
}
 
void forward(){
  drivingState = FORWARD;
  startPulseTime = millis();
  digitalWrite(reversePin, LOW);
  digitalWrite(forwardPin,HIGH);
}
 
void reverse(){
  drivingState = REVERSE;
  startPulseTime = millis();
  digitalWrite(forwardPin, LOW);
  digitalWrite(reversePin, HIGH);
}
 
void turnLeft(){
  digitalWrite(rightPin,LOW);
  digitalWrite(leftPin, HIGH);
}
 
void turnRight(){
  digitalWrite(leftPin, LOW);
  digitalWrite(rightPin,HIGH);
}
This week for my telephony class we experimented with Node.js to create a socket where information could be passed on a Rackspace Ubuntu web server. The socket essentially opened up two ports on my server to be able to transfer data to each other. I used Arduino and an Ethernet shield to connect to the socket and read the numbers my phone pressed. The phone presses got pushed into the open port via an AGI call.

The node code is as follows:

var agi_net = require('net');
var remote_net = require('net');
 
var REMOTE_PORT=12002;
 
var AGI_HOST = '127.0.0.1';
var AGI_PORT = 12001;
 
/**
 * AGI will only send key presses, and that's it.
 * There's no identifying characteristics, just raw press events.
*/
 
/** Remote clients send no info to this server.
 * all they do is receive byte representations of digits.
 * (0-9, #, *) on the phone's keypad as ascii bytes*/
 
//remote screens or physical objects
var remoteClients = [];
remote_net.createServer(function(sock){
  console.log('CONNECTED REMOTE CLIENT: ' + sock.remoteAddress +':'+ sock.remotePort);
  remoteClients.push(sock); //add client
      // Add a 'close' event handler to this instance of socket
    sock.on('close', function() {
        for(var i = 0; i < remoteClients.length; i++) {
            if(remoteClients[i] == sock) { //remove client
                remoteClients.splice(i,1);
                break;
            }
        }
        console.log('DISCONNECTED REMOTE CLIENT: ' + sock.remoteAddress +':'+ sock.remotePort);
    });
 
    // Add a 'data' event handler to this instance of socket
    sock.on('data', function(data) {
        for ( var i = 0; i < data.length; i++){
            handleByte(data[i]);
        }
        function handleByte(buf){
         console.log(buf);   
        }
 
    });
}).listen(REMOTE_PORT);
console.log('Server listening for remote connections on ' + REMOTE_PORT);
 
agi_net.createServer(function(sock){
  console.log('CONNECTED AGI CLIENT: ' + sock.remoteAddress +':'+ sock.remotePort);
      // Add a 'close' event handler to this instance of socket
    sock.on('close', function(data) {
        console.log('CLOSED AGI CLIENT: ' + sock.remoteAddress +':'+ sock.remotePort);
    });
 
    // Add a 'data' event handler to this instance of socket
    sock.on('data', function(data) {
        console.log(data);
        //broadcast data to all remote clients
        for (var i = 0; i < remoteClients.length; i++){
            var client = remoteClients[i];
            client.write(data);
        }
    });
}).listen(AGI_PORT, AGI_HOST);
 
console.log('Server listening for AGI connections on ' + AGI_HOST +':'+ AGI_PORT);

The AGI script is as follows:

#!/usr/bin/ruby
 
#very simple implementation of asterisk -> server -> client stack
#only sends the digit and the caller id.
#designed for very simple control, like arduino or web page
 
require 'rubygems'
require 'ruby-agi'
require 'socket' 
 
agi = AGI.new
host = 'localhost'
port = 12001
looping = true
s = TCPSocket.open(host, port)
agi.stream_file("vm-extension")
while looping
    result = agi.wait_for_digit(-1) # wait forever
	if result.digit
        s.write "#{result.digit}"
	else #hangup broke the pending AGI request
        looping = false
    end
end

The asterisk dialplan is as follows:

[rtt233_socketIO_arduino]
exten => 1,1,Answer();
exten => 1,n,AGI(/home/rtilton1/asterisk_agi/socketIO_arduino.rb);
exten => 1,n,Hangup();

All code examples and knowledge are curtesy to our awesome professor Chris Kairalla! I’m excited to continue on node and download the free book/pdf found here: http://visionmedia.github.com/masteringnode/

My Ruby/Sinatra code is as noted below:

require 'sinatra'
 
#generates a call file that will connect to the arduino context
def gencallfile(numbertocall)
  time = (Time.now.to_f * 1000).to_i #current timestamp
  temp_dir = "/tmp/"
  callfile = "call_" + time.to_s + ".call"
  startcallfile = temp_dir + callfile
  end_dir = "/var/spool/asterisk/outgoing/"
  endcallfile = end_dir + callfile
  #write file to disk
  file = File.open(startcallfile,"w")
  file.puts("Channel: SIP/#{numbertocall}@flowroute\n")
  file.puts("MaxRetries: 1\n")
  file.puts("RetryTime: 60\n")
  file.puts("WaitTime: 30\n")
  file.puts("CallerID: Arduino <2122738466>\n")
  file.puts("Context: rtt233_arduinocall\n")
  file.puts("Extension: s\n")
  file.close
  #change file permission
  File.chmod(0777, startcallfile)
  FileUtils.chown(ENV['USER'],'asterisk',startcallfile)
  #move file to /var/spool/outgoing
  FileUtils.mv(startcallfile,endcallfile)
end
 
# Main route  - this is the form where we take the input
get '/' do
	call_number=params[:callnumber]
	if call_number
		gencallfile(call_number)
  		# params[:callnumber] will be used to generate a call file
  		# which will play back a message from the "Arduino".
  		"Called #{call_number}"
  else
  		"missing \"callnumber\" param"
  end
end
For my telephony class we experimented with creating a asterisk connection through an Arduino. I used sinatra/ruby to create a webpage on my server that generates a call file in my /var/spool/asterisk/outgoing directory. With asterisk installed on my rackspace ubuntu server – any file within my outgoing directory will automatically be routed for a call. I also signed up with ipKall for my inbound calls and FlowRoute for my outbound calls (which is being used in this example).

My Arduino code is noted below:

//state constants
#define HTTP_ACTIVE 10
#define HTTP_IDLE 20
#include <SPI.h>
#include <Ethernet.h>fa
 
//setup          70    A5    DA    00    85    70
byte mac[] = { 0x70, 0xA5, 0xDA, 0x00, 0x85, 0x70 };
IPAddress server (XXX,XXX,XXX,XX);  // my server
//client stuff
char httpCommand[] = "GET /~rtilton1/sinatra/arduinocall/?callnumber=19174365310 HTTP/1.0";
EthernetClient client;
byte httpState = HTTP_IDLE;
int httpDelay = 5000; //wait at least this long in millis before sending another request
unsigned long connectTime = 0;
 
//button stuff
const int buttonPin = 2;
int buttonState = 0;
 
void setup() {
    Serial.begin(9600);
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("ready.");
}
 
void loop() {
  //read input from server, if any.
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
  //check button, only read if there are no active http connections and we're past minimum delay
  if (httpState == HTTP_IDLE && pastHttpDelay()) {
    buttonState = digitalRead(buttonPin);
    if (buttonState == HIGH) {
      serverConnect();
    }
 
  }
  //close client if disconnected
  if (!client.connected() && httpState == HTTP_ACTIVE) {
    client.stop();
    httpState = HTTP_IDLE;
    Serial.println();
    Serial.println("disconnected.");
  }
}
 
boolean pastHttpDelay(){
  if ((millis() - connectTime) > httpDelay) {
    return true;
  }
  else {
    return false;
  }
}
 
void serverConnect(){
  Serial.println("connecting to stu.itp.nyu.edu");
  if (client.connect(server, 80)) {
    httpState = HTTP_ACTIVE;
    connectTime = millis(); //when did we connect?
    Serial.println("connected");
    client.println(httpCommand);
    client.println();
  }
  else {
    httpState = HTTP_IDLE;
    Serial.println("connection failed");
  }
}