1 /* 2 * Copyright (c) 2007 Sun Microsystems, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 package org.sunspotworld; 26 27 import com.sun.spot.sensorboard.EDemoBoard; 28 import com.sun.spot.sensorboard.peripheral.ISwitch; 29 import com.sun.spot.sensorboard.peripheral.ITriColorLED; 30 import com.sun.spot.io.j2me.radiostream.*; 31 import com.sun.spot.io.j2me.radiogram.*; 32 import com.sun.spot.sensorboard.peripheral.ISwitchListener; 33 import com.sun.spot.sensorboard.peripheral.Servo; 34 import com.sun.spot.util.*; 35 import java.io.*; 36 import javax.microedition.io.*; 37 import javax.microedition.midlet.MIDlet; 38 import javax.microedition.midlet.MIDletStateChangeException; 39 40 /** 41 * The startApp method of this class is called by the VM to start the 42 * application. 43 * 44 * The manifest specifies this class as MIDlet-1, which means it will 45 * be selected for execution. 46 * 47 * This class controls the actual Servo, and reads from another class which 48 * controls the Radio. 49 */ 50 public class ServoMover extends MIDlet implements ISwitchListener{ 51 52 private ITriColorLED[] leds = EDemoBoard.getInstance().getLEDs(); 53 private static final int CENTER = 1500; 54 private static final int MAX = 2500; 55 private static final int MIN = 500; 56 private ISwitch[] switches = EDemoBoard.getInstance().getSwitches(); 57 private ServoReceiver snw; 58 private Servo serv; 59 60 /** 61 * This is the main method called to start the MIDlet application. 62 * @throws javax.microedition.midlet.MIDletStateChangeException Throw exception if the MIDLet fails 63 */ 64 protected void startApp() throws MIDletStateChangeException { 65 new BootloaderListener().start(); // monitor the USB (if connected) and recognize commands from host 66 switches[0].addISwitchListener(this); 67 switches[1].addISwitchListener(this); 68 serv = new Servo(EDemoBoard.getInstance().getOutputPins()[EDemoBoard.H0]); 69 serv.setValue(CENTER); 70 Utils.sleep(500); 71 while (serv.getValue() < MAX) { 72 int cur = serv.getValue(); 73 serv.setValue(cur + 100); 74 Utils.sleep(250); 75 } 76 while (serv.getValue() > MIN) { 77 int cur = serv.getValue(); 78 serv.setValue(cur - 100); 79 Utils.sleep(250); 80 } 81 // snw = new ServoReceiver(this); 82 // System.out.println("Waiting for calibration data..."); 83 // snw.connect(); 84 // Thread t = new Thread(snw); 85 // t.start(); 86 } 87 88 /** 89 * Move the servo the specified amount. 90 * @param bendValue Value of the sensor read. Must be converted to a servo-position before use. 91 */ 92 public void moveServo(int bendValue) { 93 /* 94 * the formula is, roughly: 1000 * cube-root[(value-min)/60] + 500, but since we 95 * only do *integer* cube roots, we make the value *really* big first (10^3), then 96 * reduce it again ( /10 ) later. It's not perfect, but it's pretty close 97 */ 98 int sMove = (icbrt((int) ((((double) bendValue - (double) snw.getMin()) / 60) * 1000000)) * 10) + 500; 99 System.out.println("Read sensor value: " + bendValue + " Moving Servo to: " + sMove); 100 serv.setValue(sMove); 101 102 } 103 104 /** 105 * Handler called when a watched switch is pressed. 106 * @param sw the switch that was pressed 107 */ 108 public void switchPressed(ISwitch sw) { 109 int switchNum = (sw == switches[0]) ? 1 : 2; 110 System.out.println("Switch " + switchNum + " closed."); 111 manualMove(switchNum); 112 } 113 114 /** 115 * Handler called when a switch is released 116 * @param sw the switch that was released 117 */ 118 public void switchReleased(ISwitch sw) { 119 int switchNum = (sw == switches[0]) ? 1 : 2; 120 System.out.println("Switch " + switchNum + " opened."); 121 manualMove(switchNum); 122 } 123 124 /** 125 * Move a servo based on a value for direction 126 * @param dir 1 or 2, corresponds to switch 1 or 2 to move the servo 127 */ 128 private void manualMove (int dir) { 129 final int move = 25; 130 int servPos = serv.getValue(); 131 if(dir == 1){ 132 if(servPos - move > MIN){ 133 serv.setValue(servPos - move); 134 } else { 135 serv.setValue(MIN); 136 } 137 } else { 138 if(servPos + move < MAX ){ 139 serv.setValue(servPos + move); 140 } else { 141 serv.setValue(MAX); 142 } 143 } 144 } 145 146 147 148 /** 149 * This is ugly code, found on the internet, for doing, basically, integer cube roots. 150 * nasty stuff, but it comes astonishingly close, so it's 'good enough' 151 * Squawk doesn't have built-in cube-root, so this is our only hope. 152 * @return Integer cube-root 153 * @param x The integer to reduce to cube-root 154 */ 155 private int icbrt(int x) { 156 int s = 30; 157 int y, b; 158 y = 0; 159 while (s >= 0) { 160 y = 2 * y; 161 b = (3 * y * (y + 1) + 1) << s; 162 s = s - 3; 163 if (x >= b) { 164 x = x - b; 165 y = y + 1; 166 } 167 } 168 return y; 169 } 170 171 protected void pauseApp() { 172 // This is not currently called by the Squawk VM 173 } 174 175 /** 176 * Called if the MIDlet is terminated by the system. 177 * I.e. if startApp throws any exception other than MIDletStateChangeException, 178 * if the isolate running the MIDlet is killed with Isolate.exit(), or 179 * if VM.stopVM() is called. 180 * 181 * It is not called if MIDlet.notifyDestroyed() was called. 182 * @param unconditional If true when this method is called, the MIDlet must 183 * cleanup and release all resources. If false the MIDlet may throw 184 * MIDletStateChangeException to indicate it does not want to be destroyed 185 * at this time. 186 * @throws javax.microedition.midlet.MIDletStateChangeException Thrown when the state of the MIDLet is changed. 187 */ 188 protected void destroyApp(boolean unconditional) throws MIDletStateChangeException { 189 for (int i = 0; i < 8; i++) { 190 leds[i].setOff(); 191 } 192 } 193 194 195 196 }