001 /*----------------------------------------------------------------------------*/ 002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */ 003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 004 /* must be accompanied by the FIRST BSD license file in the root directory of */ 005 /* the project. */ 006 /*----------------------------------------------------------------------------*/ 007 008 package edu.wpi.first.wpilibj; 009 010 import edu.wpi.first.wpilibj.communication.UsageReporting; 011 import edu.wpi.first.wpilibj.livewindow.LiveWindow; 012 import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable; 013 import edu.wpi.first.wpilibj.networktables2.type.NumberArray; 014 import edu.wpi.first.wpilibj.parsing.ISensor; 015 import edu.wpi.first.wpilibj.tables.ITable; 016 017 /** 018 * HiTechnic NXT Color Sensor. 019 * 020 * This class allows access to a HiTechnic NXT Color Sensor on an I2C bus. 021 * These sensors do not allow changing addresses so you cannot have more 022 * than one on a single bus. 023 * 024 * Details on the sensor can be found here: 025 * http://www.hitechnic.com/index.html?lang=en-us&target=d17.html 026 * 027 */ 028 public class HiTechnicColorSensor extends SensorBase implements ISensor, LiveWindowSendable { 029 030 /** 031 * An exception dealing with connecting to and communicating with the 032 * HiTechnicCompass 033 */ 034 public class ColorSensorException extends RuntimeException { 035 036 /** 037 * Create a new exception with the given message 038 * @param message the message to pass with the exception 039 */ 040 public ColorSensorException(String message) { 041 super(message); 042 } 043 044 } 045 046 /** 047 * A set of three color values bundled into one object 048 */ 049 public class RGB { 050 public double red, green, blue; 051 052 public double getRed() {return red;} 053 public double getGreen() {return green;} 054 public double getBlue() {return blue;} 055 } 056 057 public static class tColorSensorMode { 058 public final int value; 059 static final int kActive_val = 0; 060 static final int kPassive_val = 1; 061 static final int kRaw_val = 3; 062 public static final tColorSensorMode kActive = new tColorSensorMode(kActive_val); 063 public static final tColorSensorMode kPassive = new tColorSensorMode(kPassive_val); 064 public static final tColorSensorMode kRaw = new tColorSensorMode(kRaw_val); 065 066 private tColorSensorMode(int value) { 067 this.value = value; 068 } 069 } 070 071 private static final byte kAddress = 0x02; 072 private static final byte kManufacturerBaseRegister = 0x08; 073 private static final byte kManufacturerSize = 0x08; 074 private static final byte kSensorTypeBaseRegister = 0x10; 075 private static final byte kSensorTypeSize = 0x08; 076 private static final byte kModeRegister = 0x41; 077 private static final byte kColorRegister = 0x42; 078 private static final byte kRedRegister = 0x43; 079 private static final byte kGreenRegister = 0x44; 080 private static final byte kBlueRegister = 0x45; 081 private static final byte kRawRedRegister = 0x43; 082 private static final byte kRawGreenRegister = 0x45; 083 private static final byte kRawBlueRegister = 0x47; 084 private I2C m_i2c; 085 private int m_mode = tColorSensorMode.kActive.value; 086 087 /** 088 * Constructor. 089 * 090 * @param slot The slot of the digital module that the sensor is plugged into. 091 */ 092 public HiTechnicColorSensor(int slot) { 093 DigitalModule module = DigitalModule.getInstance(slot); 094 m_i2c = module.getI2C(kAddress); 095 096 // Verify Sensor 097 final byte[] kExpectedManufacturer = "HiTechnc".getBytes(); 098 final byte[] kExpectedSensorType = "ColorPD ".getBytes(); 099 if (!m_i2c.verifySensor(kManufacturerBaseRegister, kManufacturerSize, kExpectedManufacturer)) { 100 throw new ColorSensorException("Invalid Color Sensor Manufacturer"); 101 } 102 if (!m_i2c.verifySensor(kSensorTypeBaseRegister, kSensorTypeSize, kExpectedSensorType)) { 103 throw new ColorSensorException("Invalid Sensor type"); 104 } 105 106 LiveWindow.addSensor("HiTechnicColorSensor", slot, 0, this); 107 UsageReporting.report(UsageReporting.kResourceType_HiTechnicColorSensor, module.getModuleNumber()-1); 108 } 109 110 /** 111 * Destructor. 112 */ 113 public void free() { 114 if (m_i2c != null) { 115 m_i2c.free(); 116 } 117 m_i2c = null; 118 } 119 120 /** 121 * Get the estimated color. 122 * 123 * Gets a color estimate from the sensor corresponding to the 124 * table found with the sensor or at the following site: 125 * http://www.hitechnic.com/cgi-bin/commerce.cgi?preadd=action&key=NCO1038 126 * 127 * @return The estimated color. 128 */ 129 public byte getColor() { 130 byte[] color = new byte[1]; 131 if(m_mode != tColorSensorMode.kActive.value) 132 { 133 setMode(tColorSensorMode.kActive); 134 } 135 m_i2c.read(kColorRegister, (byte) color.length, color); 136 137 return color[0]; 138 } 139 140 /** 141 * Get the value of all three colors from a single sensor reading. 142 * Using this method ensures that all three values come from the 143 * same sensor reading, using the individual color methods provides 144 * no such guarantee. 145 * 146 * The sensor must be in active mode to access the regular RGB data 147 * if the sensor is not in active mode, it will be placed into active 148 * mode by this method. 149 * 150 * @return RGB object with the three color values 151 */ 152 public RGB getRGB() { 153 byte[] colors = new byte[3]; 154 RGB result = new RGB(); 155 if(m_mode != tColorSensorMode.kActive.value) 156 { 157 setMode(tColorSensorMode.kActive); 158 } 159 m_i2c.read(kRedRegister, (byte) colors.length, colors); 160 161 result.red = (colors[0]&0xFFFF); 162 result.green = (colors[1]&0xFFFF); 163 result.blue = (colors[2]&0xFFFF); 164 return result; 165 } 166 167 /** 168 * Get the Red value. 169 * 170 * Gets the (0-255) red value from the sensor. 171 * 172 * The sensor must be in active mode to access the regular RGB data 173 * if the sensor is not in active mode, it will be placed into active 174 * mode by this method. 175 * 176 * @return The Red sensor value. 177 */ 178 public int getRed() { 179 byte[] red = new byte[1]; 180 if(m_mode != tColorSensorMode.kActive.value) 181 { 182 setMode(tColorSensorMode.kActive); 183 } 184 m_i2c.read(kRedRegister, (byte) red.length, red); 185 186 return (red[0]&0xFF); 187 } 188 189 /** 190 * Get the Green value. 191 * 192 * Gets the(0-255) green value from the sensor. 193 * 194 * The sensor must be in active mode to access the regular RGB data 195 * if the sensor is not in active mode, it will be placed into active 196 * mode by this method. 197 * 198 * @return The Green sensor value. 199 */ 200 public int getGreen() { 201 byte[] green = new byte[1]; 202 if(m_mode != tColorSensorMode.kActive.value) 203 { 204 setMode(tColorSensorMode.kActive); 205 } 206 m_i2c.read(kGreenRegister, (byte) green.length, green); 207 208 return (green[0]&0xFF); 209 } 210 211 /** 212 * Get the Blue value. 213 * 214 * Gets the raw (0-255) blue value from the sensor. 215 * 216 * The sensor must be in active mode to access the regular RGB data 217 * if the sensor is not in active mode, it will be placed into active 218 * mode by this method. 219 * 220 * @return The Blue sensor value. 221 */ 222 public int getBlue() { 223 byte[] blue = new byte[1]; 224 if(m_mode != tColorSensorMode.kActive.value) 225 { 226 setMode(tColorSensorMode.kActive); 227 } 228 m_i2c.read(kBlueRegister, (byte) blue.length, blue); 229 230 return (blue[0]&0xFF); 231 } 232 233 /** 234 * Get the Raw Red value. 235 * 236 * Gets the (0-65536) raw red value from the sensor. 237 * 238 * The sensor must be in raw or passive mode to access the regular RGB data 239 * if the sensor is not in raw or passive mode, it will be placed into raw 240 * mode by this method. 241 * 242 * @return The Raw Red sensor value. 243 */ 244 public double getRawRed() { 245 byte[] rawRed = new byte[2]; 246 if(m_mode == tColorSensorMode.kActive.value) 247 { 248 setMode(tColorSensorMode.kRaw); 249 } 250 m_i2c.read(kRawRedRegister, (byte) rawRed.length, rawRed); 251 252 return (((int)rawRed[0]&0xFF) * (int) (1 << 8) + ((int)rawRed[1]&0xFF)); 253 } 254 255 /** 256 * Get the Raw Green value. 257 * 258 * Gets the (0-65536) raw green value from the sensor. 259 * 260 * The sensor must be in raw or passive mode to access the regular RGB data 261 * if the sensor is not in raw or passive mode, it will be placed into raw 262 * mode by this method. 263 * 264 * @return The Raw Green sensor value. 265 */ 266 public double getRawGreen() { 267 byte[] rawGreen = new byte[2]; 268 if(m_mode == tColorSensorMode.kActive.value) 269 { 270 setMode(tColorSensorMode.kRaw); 271 } 272 m_i2c.read(kRawGreenRegister, (byte) rawGreen.length, rawGreen); 273 274 return (((int)rawGreen[0]&0xFF) * (int) (1 << 8) + ((int)rawGreen[1]&0xFF)); 275 } 276 277 /** 278 * Get the Raw Blue value. 279 * 280 * Gets the (0-65536) raw blue value from the sensor. 281 * 282 * The sensor must be in raw or passive mode to access the regular RGB data 283 * if the sensor is not in raw or passive mode, it will be placed into raw 284 * mode by this method. 285 * 286 * @return The Raw Blue sensor value. 287 */ 288 public double getRawBlue() { 289 byte[] rawBlue = new byte[2]; 290 if(m_mode == tColorSensorMode.kActive.value) 291 { 292 setMode(tColorSensorMode.kRaw); 293 } 294 m_i2c.read(kRawBlueRegister, (byte) rawBlue.length, rawBlue); 295 296 return (((int)rawBlue[0]&0xFF) * (int) (1 << 8) + ((int)rawBlue[1]&0xFF)); 297 } 298 299 /** 300 * Get the raw value of all three colors from a single sensor reading. 301 * Using this method ensures that all three values come from the 302 * same sensor reading, using the individual color methods provides 303 * no such guarantee. 304 * 305 * Gets the (0-65536) raw color values from the sensor. 306 * 307 * The sensor must be in raw or passive mode to access the regular RGB data 308 * if the sensor is not in raw or passive mode, it will be placed into raw 309 * mode by this method. 310 * 311 * @return An RGB object with the raw sensor values. 312 */ 313 public RGB getRawRGB() { 314 byte[] colors = new byte[6]; 315 RGB result = new RGB(); 316 if(m_mode == tColorSensorMode.kActive.value) 317 { 318 setMode(tColorSensorMode.kRaw); 319 } 320 m_i2c.read(kRawRedRegister, (byte) colors.length, colors); 321 322 result.red = (((int)colors[0]&0xFF) * (int) (1 << 8) + ((int)colors[1]&0xFF)); 323 result.green = (((int)colors[2]&0xFF) * (int) (1 << 8) + ((int)colors[3]&0xFF)); 324 result.blue = (((int)colors[4]&0xFF) * (int) (1 << 8) + ((int)colors[5]&0xFF)); 325 return result; 326 } 327 328 /** 329 * Set the Mode of the color sensor 330 * This method is used to set the color sensor to one of the three modes, 331 * active, passive or raw. The sensor defaults to active mode which uses the 332 * internal LED and returns an interpreted color value and 3 8-bit RGB channel 333 * values. Raw mode uses the internal LED and returns 3 16-bit RGB channel values. 334 * Passive mode disables the internal LED and returns 3 16-bit RGB channel values. 335 * @param mode The mode to set 336 */ 337 public void setMode(tColorSensorMode mode) { 338 m_i2c.write(kModeRegister, mode.value); 339 m_mode = mode.value; 340 } 341 342 /* 343 * Live Window code, only does anything if live window is activated. 344 * TODO: Should this have its own type? 345 */ 346 public String getSmartDashboardType(){ 347 return "Counter"; 348 } 349 private ITable m_table; 350 351 /** 352 * {@inheritDoc} 353 */ 354 public void initTable(ITable subtable) { 355 m_table = subtable; 356 updateTable(); 357 } 358 359 /** 360 * {@inheritDoc} 361 */ 362 public ITable getTable(){ 363 return m_table; 364 } 365 366 private NumberArray rgbArray = new NumberArray(); 367 /** 368 * {@inheritDoc} 369 */ 370 public void updateTable() { 371 if (m_table != null) { 372 if(rgbArray.size() == 0) { 373 rgbArray.setSize(3); 374 } 375 if(m_mode == tColorSensorMode.kActive.value) 376 { 377 m_table.putNumber("Color", getColor()); 378 rgbArray.set(0, getRed()); 379 rgbArray.set(1, getGreen()); 380 rgbArray.set(2, getBlue()); 381 m_table.putValue("RGB", rgbArray); 382 } 383 else 384 { 385 m_table.putNumber("Color", 99); 386 m_table.putValue("RGB", rgbArray); 387 } 388 } 389 } 390 391 /** 392 * {@inheritDoc} 393 */ 394 public void startLiveWindowMode() {} 395 396 /** 397 * {@inheritDoc} 398 */ 399 public void stopLiveWindowMode() {} 400 }