/**
*
* Copyright (c) 2006 Henrik Sundts and Petr Svarovsky
*
* This code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* More information about GNU Lesser General Public License
* can be obtained from the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
* @authors Henrik Sundt and Petr Svarovsky
*/
// Code for sensing physical proximity of another phone through bluetooth.
// The range of each phone's bluetooth antenna should be jammed with aluminium foil.
// Experimental code, not working perfectly. Works somehow with 2-4 phones.
// On startup, number of each phone must be set to a different number (1,2,3, etc)
// This code is written for Mobile Processing ( http://mobile.processing.org )
// and Java j2me
// Written by Petr Svarovsky (petrsvar at khio.no)
// and Henrik Sundt (hsundt at notam02.no)
// October 2006
// for Trolley Singers Project (see http://silver.avu.cz/trolley_singers )
import processing.sound.*; // Sound library import
import processing.bluetooth.*; // Bluetooth library import
PFont font;
Bluetooth bt;
Service[] services;
Device[] devices;
Sound sound1;
Sound sound2;
Sound sound3;
Sound sound4;
Sound sound5;
Sound sound6;
Sound sound7;
Sound sound8;
Sound sound9;
Sound sound10;
String info1 = ""; // status information
String info2 = ""; // status information
String info3 = ""; // status information
String info4 = ""; // status information
String info5 = ""; // status information
String info6 = ""; // status information
boolean startIt = false; // true for start connection
int l = 0; // number of visible services
int loudness = 50; // sound volume
int[] phone1_client_of = { 2, 3, 4, 5, 6, 7 }; int[] phone1_serves = { 8, 9,10,11,12, 0 };
int[] phone2_client_of = { 3, 4, 5, 6, 7, 8 }; int[] phone2_serves = { 1, 9,10,11,12, 0 };
int[] phone3_client_of = { 4, 5, 6, 7, 8, 9 }; int[] phone3_serves = { 1, 2,10,11,12, 0 };
int[] phone4_client_of = { 5, 6, 7, 8, 9,10 }; int[] phone4_serves = { 1, 2, 3,11,12, 0 };
int[] phone5_client_of = { 6, 7, 8, 9,10,11 }; int[] phone5_serves = { 1, 2, 3, 4,12, 0 };
int[] phone6_client_of = { 7, 8, 9,10,11,12 }; int[] phone6_serves = { 1, 2, 3, 4, 5, 0 };
int[] phone7_client_of = { 8, 9,10,11,12, 0 }; int[] phone7_serves = { 1, 2, 3, 4, 5, 6 };
int[] phone8_client_of = { 9,10,11,12, 1, 0 }; int[] phone8_serves = { 2, 3, 4, 5, 6, 7 };
int[] phone9_client_of = { 10,11,12, 1, 2, 0 }; int[] phone9_serves = { 3, 4, 5, 6, 7, 8 };
int[] phone10_client_of = { 11,12, 1, 2, 3, 0 }; int[] phone10_serves = { 4, 5, 6, 7, 8, 9 };
int[] phone11_client_of = { 12, 1, 2, 3, 4, 0 }; int[] phone11_serves = { 5, 6, 7, 8, 9,10 };
int[] phone12_client_of = { 1, 2, 3, 4, 5, 0 }; int[] phone12_serves = { 6, 7, 8, 9,10,11 };
int[] i_am_client_of; int[] i_serve;
int my_phone_nr=0;
// Client and service thread:
// see the file "connectService" for some documentation on ConnectThread
class ConnectThread implements Runnable {
public int service_nr;
private int my_array_nr;
public boolean conn_success;
private int action;
public Client cref;
// actions:
private int DO_NOTHING=0;
private int DO_CONNLOOP=1;
ConnectThread(int a) {
this.my_array_nr = a;
this.service_nr = -1;
this.conn_success=false;
this.action=DO_NOTHING;
this.cref=null;
}
private void reset_action() { // called from while-loop to make each action only happen once
this.action=DO_NOTHING;
}
public void start_connloop() {
action=DO_CONNLOOP;
}
public void run() {
// wait for start signal
while(action==DO_NOTHING)
msleep(100);
// ---------- infinte loop -------------------------------------------------------------
while(true) {
if(action==DO_CONNLOOP) {
// try to connect:
try {
info2="try to connect in thread";
this.cref = services[service_nr].connect(); // try to connect to service, will get exception if can't connect
if(this.cref!=null) {
this.conn_success=true;
info2="connect succeeded in thread "+my_array_nr;
} else {
this.conn_success=false;
info2="connect nullpointer in thread";
}
} catch (RuntimeException re) { // if could not connect
this.conn_success=false;
info2="did not connect in thread";
}
// sleep for a while
msleep(6000+my_random_threadpause); // must be random to avoid sync
// disconnect
if(this.conn_success) {
try {
this.cref.stop();
this.cref=null;
} catch(PException pe) {
info6="exception i cref.stop()";
}
}
msleep(1000); // wait a bit before trying to connect again
}
}
// ---------- end of loop -------------------------------------------------------------
}
private void msleep(int sleepDelay) {
try {
Thread.currentThread().sleep(sleepDelay);
}
catch (InterruptedException ie) {}
}
}
int max_nr_threads=13; // max number of possible threads (phones numbered 1 to 12, 0 is a dummy)
ConnectThread[] service_connect_thread = new ConnectThread[max_nr_threads]; // possible threads, not yet active.
int my_service_thread_nr;
int my_random_threadpause;
boolean bt_running=false; // whether bluetooth is running
boolean searching=false; // whether is searching
boolean initiated=false;
boolean do_play_sound; // if a sound is going to be played
void setup() {
background(255); // Set background color to white
stroke(0); // Set line drawing color to black
fill(0); // Set fill drawing color to black
font = loadFont(FACE_MONOSPACE, STYLE_PLAIN, SIZE_SMALL); // Font adjustment
textFont(font); // Font adjustment
bt = new Bluetooth(this); // Instantiate a new bluetooth object;
//... should check if sounds are in directory, otherwise gets NullPointerExeption !
sound1 = new Sound("1.wav", "audio/x-wav"); // Instantiate sounds
sound2 = new Sound("2.wav", "audio/x-wav");
sound3 = new Sound("3.wav", "audio/x-wav");
sound4 = new Sound("4.wav", "audio/x-wav");
sound5 = new Sound("5.wav", "audio/x-wav");
sound6 = new Sound("6.wav", "audio/x-wav");
sound7 = new Sound("7.wav", "audio/x-wav");
sound8 = new Sound("8.wav", "audio/x-wav");
sound9 = new Sound("9.wav", "audio/x-wav");
sound10 = new Sound("10.wav", "audio/x-wav");
// create service threads:
int i;
for(i=0; i< max_nr_threads; i++)
service_connect_thread[i] = new ConnectThread(i); // create the threads (but not run yet)
my_random_threadpause=random(2000);
}
Thread mythread;
boolean newthread=true;
boolean play_alert_sound=false;
void draw()
{
// this code prevents second thread generated by keypress to run
Thread thisthread=Thread.currentThread();
if(newthread) {
mythread=thisthread;
newthread=false;
}
else if(thisthread != mythread) {
try {
Thread.currentThread().sleep(10000); // unneeded thread sleeps for 10 secs
} catch(InterruptedException ie)
{}
return;
}
// -- end ----------------------------------------------------
if(play_alert_sound) {
play_alert_sound=false;
playSound(1);
sleep(2000);
}
background(255);
text("Key 0 : Change phone nr (now "+my_phone_nr+")", 2, 10);
text("Key 1 : Start", 2, 20);
text("Key 2 : Search service", 2, 30);
text("Key 3 : Start communication", 2, 40);
text("Key 4 : Stop service", 2, 50);
text("Key * : Volume down (now "+loudness+")", 2, 60);
text("Key # : Volume up", 2, 70);
if(!startIt)
info6="obs: Communication not started";
else info6="";
text(info1, 2, 70+12);
text(info2, 2, 70+12*2);
text(info3, 2, 70+12*3);
text(info4, 2, 70+12*4);
text(info5, 2, 70+12*5);
text(info6, 2, 70+12*6);
sleep(200); // sleep at least 40 ms every draw - because of Java sound playback bug on N70
// control ----------------------------------------------------->
int i;
if(startIt && !initiated) {
for(i=0; i< max_nr_threads; i++) {
if(service_connect_thread[i].service_nr!=-1) { // if the service exists
service_connect_thread[i].start_connloop(); // start the connect/disconnect-loop in the thread
sleep(1000); // 1 second gap between each start of thread
}
}
initiated=true;
}
// if had success in last connect to any services, play sound
if(startIt) {
for(i=0; i< max_nr_threads; i++) {
if(service_connect_thread[i].conn_success) {
do_play_sound=true;
break;
}
}
}
// PLAY SOUND
if(do_play_sound) {
info4="do play sound";
do_play_sound=false;
//... now playing only random sounds
playSound(1+random(9)); // start playing a new sound
sleep(2000);
}
else
info4="dont play sound"; // info to be displayed on next draw()
sleep(500); // not stress the phone too much //..... sleep longer to save power ?
//--- end of control ------------------------------------------------------------
}
void keyPressed() {
switch (key){
case '0': // change my phone number
if(startIt)
info1 = "cannot change, comm started";
else {
my_phone_nr++;
if(my_phone_nr>12)
my_phone_nr=1;
set_my_phone_ref();
info1 = "Phone number "+my_phone_nr;
}
break;
case '1': // start service
if(my_phone_nr==0)
info1 = "Set phone number first! (key 0)";
else if(bt_running)
info1 = "service already started !";
else {
try {
bt.start("trolley"+str(my_phone_nr));
bt_running=true;
info1 = "service start ok";
}
catch(RuntimeException re) {
info1 = "service start failed";
}
}
break;
case '2': // search service
if(!bt_running)
info1 = "start bluetooth first! (key 1)";
else if(searching)
info1 = "already searching !";
else {
searching=true;
services = null;
bt.find();
info1 = "searching for service...";
}
break;
case '3': // start communication
if(searching)
info1 = "cannot start before done search.. please wait.";
else if(l<=0)
info1 = "cannot start before search (key 2)";
else if(startIt)
info1 = "comm already started";
else { // puh..., can start communication
info1 = "communication started";
start_service_threads();
startIt = true;
}
break;
case '4': // stop service
if(!bt_running)
info1 = "already stopped";
else if(startIt)
info1 = "cannot stop, comm already started";
else {
try {
bt.stop();
bt_running=false;
startIt=false;
info1 = "service stop ok";
}
catch(RuntimeException re) {
info1 = "service stop failed";
}
}
break;
case '*': // volume down
loudness-=10;
if(loudness< 0) loudness=0;
set_volume_all(loudness);
info1 = "Volume "+loudness;
break;
case '#': // volume up
loudness+=10;
if(loudness>100) loudness=100;
set_volume_all(loudness);
info1 = "Volume "+loudness;
break;
}
}
void sleep(int sleepDelay) {
try {
Thread.currentThread().sleep(sleepDelay);
}
catch (InterruptedException ie) {
}
}
void libraryEvent(Object library, int event, Object data) {
Client tmpclient;
int client_phone_nr;
boolean success;
if (library == bt) {
switch (event) {
case Bluetooth.EVENT_DISCOVER_DEVICE:
info2 = "still searching...";
break;
case Bluetooth.EVENT_DISCOVER_DEVICE_COMPLETED:
devices = (Device[]) data;
info2 = length(devices) + " devices found";
break;
case Bluetooth.EVENT_DISCOVER_SERVICE:
info2 = "still searching...";
break;
case Bluetooth.EVENT_DISCOVER_SERVICE_COMPLETED:
searching=false; // done searching
services = (Service[]) data;
l = length(services);
info2 = l + " services found";
play_alert_sound=true;
break;
case Bluetooth.EVENT_CLIENT_CONNECTED: // event generated by client trying to connect to my service
tmpclient = (Client) data;
info3 = "client connected";
do_play_sound=true;
break;
}
}
}
void playSound(int x) {
switch(x) {
case 1:
sound1.play();
break;
case 2:
sound2.play();
break;
case 3:
sound3.play();
break;
case 4:
sound4.play();
break;
case 5:
sound5.play();
break;
case 6:
sound6.play();
break;
case 7:
sound7.play();
break;
case 8:
sound8.play();
break;
case 9:
sound9.play();
break;
case 10:
sound10.play();
break;
}
}
void set_volume_all(int l)
{
sound1.volume(l);
sound2.volume(l);
sound3.volume(l);
sound4.volume(l);
sound5.volume(l);
sound6.volume(l);
sound7.volume(l);
sound8.volume(l);
sound9.volume(l);
sound10.volume(l);
}
// ServiceConnectThread:
// - service_connect_thread[i] goes from 0 to 12
// - phone numbers 1 to 12 (0 is a dummy)
// - each thread keeps track of connection to every phone i'm a client of
// - each thread knows it's service number
// - phones that dont connect will never be active threads
void start_service_threads()
{
// thread setup and start:
int service_nr,phone_nr;
String sname;
// connect to services
for(service_nr=0; service_nr< l; service_nr++) {
sname = services[service_nr].name;
// if is one of our phones
if(sname.equals("trolley1") || sname.equals("trolley2") || sname.equals("trolley3") || sname.equals("trolley4") ||
sname.equals("trolley5") || sname.equals("trolley6") || sname.equals("trolley7") || sname.equals("trolley8") ||
sname.equals("trolley9") || sname.equals("trolley10") || sname.equals("trolley11") || sname.equals("trolley12"))
{
phone_nr = Integer.parseInt(sname.substring(7)); // convert phone name string to int
if(phone_nr==i_am_client_of[0] || phone_nr==i_am_client_of[1] || phone_nr==i_am_client_of[2] || // if we are going to be a client,
phone_nr==i_am_client_of[3] || phone_nr==i_am_client_of[4] || phone_nr==i_am_client_of[5]) // according to the array
{
if(service_connect_thread[phone_nr].service_nr == -1) { // if not already started
service_connect_thread[phone_nr].service_nr = service_nr; // reference to service nr
new Thread(service_connect_thread[phone_nr]).start(); // start the thread (which will start in wait-modus)
}
else info1="error: service to connect twice on same";
}
// else
// println("i am not client of phone_nr "+phone_nr);
}
}
}
void set_my_phone_ref()
{
switch(my_phone_nr) {
case 0:
info1 = "error: tried with phone nr 0";
break;
case 1:
i_am_client_of = phone1_client_of; i_serve = phone1_serves; break;
case 2:
i_am_client_of = phone2_client_of; i_serve = phone2_serves; break;
case 3:
i_am_client_of = phone3_client_of; i_serve = phone3_serves; break;
case 4:
i_am_client_of = phone4_client_of; i_serve = phone4_serves; break;
case 5:
i_am_client_of = phone5_client_of; i_serve = phone5_serves; break;
case 6:
i_am_client_of = phone6_client_of; i_serve = phone6_serves; break;
case 7:
i_am_client_of = phone7_client_of; i_serve = phone7_serves; break;
case 8:
i_am_client_of = phone8_client_of; i_serve = phone8_serves; break;
case 9:
i_am_client_of = phone9_client_of; i_serve = phone9_serves; break;
case 10:
i_am_client_of = phone10_client_of; i_serve = phone10_serves; break;
case 11:
i_am_client_of = phone11_client_of; i_serve = phone11_serves; break;
case 12:
i_am_client_of = phone12_client_of; i_serve = phone12_serves; break;
}
}
void destroy()
{
// for now, just try to stop bluetooth
bt.stop();
}