/** * * 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(); }