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.parsing.ISensor;
014    import edu.wpi.first.wpilibj.tables.ITable;
015    
016    /**
017     * HiTechnic NXT Compass.
018     *
019     * This class alows access to a HiTechnic NXT Compass on an I2C bus.
020     * These sensors to not allow changing addresses so you cannot have more
021     *   than one on a single bus.
022     *
023     * Details on the sensor can be found here:
024     *   http://www.hitechnic.com/index.html?lang=en-us&target=d17.html
025     *
026     */
027    public class HiTechnicCompass extends SensorBase implements ISensor, LiveWindowSendable, PIDSource {
028    
029        /**
030         * An exception dealing with connecting to and communicating with the
031         * HiTechnicCompass
032         */
033        public class CompassException extends RuntimeException {
034    
035            /**
036             * Create a new exception with the given message
037             * @param message the message to pass with the exception
038             */
039            public CompassException(String message) {
040                super(message);
041            }
042           
043        }
044    
045        private static final byte kAddress = 0x02;
046        private static final byte kManufacturerBaseRegister = 0x08;
047        private static final byte kManufacturerSize = 0x08;
048        private static final byte kSensorTypeBaseRegister = 0x10;
049        private static final byte kSensorTypeSize = 0x08;
050        private static final byte kHeadingRegister = 0x44;
051        private I2C m_i2c;
052    
053        /**
054         * Constructor.
055         *
056         * @param slot The slot of the digital module that the sensor is plugged into.
057         */
058        public HiTechnicCompass(int slot) {
059            DigitalModule module = DigitalModule.getInstance(slot);
060            m_i2c = module.getI2C(kAddress);
061    
062            // Verify Sensor
063            final byte[] kExpectedManufacturer = "HiTechnc".getBytes();
064            final byte[] kExpectedSensorType = "Compass ".getBytes();
065            if (!m_i2c.verifySensor(kManufacturerBaseRegister, kManufacturerSize, kExpectedManufacturer)) {
066                throw new CompassException("Invalid Compass Manufacturer");
067            }
068            if (!m_i2c.verifySensor(kSensorTypeBaseRegister, kSensorTypeSize, kExpectedSensorType)) {
069                throw new CompassException("Invalid Sensor type");
070            }
071            
072            UsageReporting.report(UsageReporting.kResourceType_HiTechnicCompass, module.getModuleNumber()-1);
073            LiveWindow.addSensor("HiTechnicCompass", slot, 0, this);
074        }
075    
076        /**
077         * Destructor.
078         */
079        public void free() {
080            if (m_i2c != null) {
081                m_i2c.free();
082            }
083            m_i2c = null;
084        }
085    
086        /**
087         * Get the compass angle in degrees.
088         *
089         * The resolution of this reading is 1 degree.
090         *
091         * @return Angle of the compass in degrees.
092         */
093        public double getAngle() {
094            byte[] heading = new byte[2];
095            m_i2c.read(kHeadingRegister, (byte) heading.length, heading);
096    
097            return ((int) heading[0] + (int) heading[1] * (int) (1 << 8));
098        }
099        
100        public double pidGet() {
101            return getAngle();
102        }
103    
104        /*
105         * Live Window code, only does anything if live window is activated.
106         */
107        public String getSmartDashboardType(){
108            return "Compass";
109        }
110        private ITable m_table;
111        
112        /**
113         * {@inheritDoc}
114         */
115        public void initTable(ITable subtable) {
116            m_table = subtable;
117            updateTable();
118        }
119        
120        /**
121         * {@inheritDoc}
122         */
123        public ITable getTable(){
124            return m_table;
125        }
126        
127        /**
128         * {@inheritDoc}
129         */
130        public void updateTable() {
131            if (m_table != null) {
132                m_table.putNumber("Value", getAngle());
133            }
134        }
135        
136        /**
137         * {@inheritDoc}
138         */
139        public void startLiveWindowMode() {}
140        
141        /**
142         * {@inheritDoc}
143         */
144        public void stopLiveWindowMode() {}
145    }