
/*---------------------------------------------------------------------------
 * Copyright (C) 1999,2000 Dallas Semiconductor Corporation, All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Dallas Semiconductor
 * shall not be used except as stated in the Dallas Semiconductor
 * Branding Policy.
 *---------------------------------------------------------------------------
 */

package com.dalsemi.onewire.container;

// imports
import com.dalsemi.onewire.adapter.DSPortAdapter;
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.OneWireException;


/**
 * DS2405 container class with part specific commands.
 *
 *  @version    0.00, 28 Aug 2000
 *  @author     KLA,DSS
 */
public class OneWireContainer05
   extends OneWireContainer
   implements SwitchContainer
{

   //--------
   //-------- Constructors
   //--------

   /**
    * Default constructor
    */
   public OneWireContainer05 ()
   {
      super();
   }

   /**
    * Create a container with a provided adapter object
    * and the address of the iButton or 1-Wire device.
    *
    * @param  sourceAdapter     adapter object required to communicate with
    * this iButton.
    * @param  newAddress        address of this 1-Wire device
    */
   public OneWireContainer05 (DSPortAdapter sourceAdapter, byte[] newAddress)
   {
      super(sourceAdapter, newAddress);
   }

   /**
    * Create a container with a provided adapter object
    * and the address of the iButton or 1-Wire device.
    *
    * @param  sourceAdapter     adapter object required to communicate with
    * this iButton.
    * @param  newAddress        address of this 1-Wire device
    */
   public OneWireContainer05 (DSPortAdapter sourceAdapter, long newAddress)
   {
      super(sourceAdapter, newAddress);
   }

   /**
    * Create a container with a provided adapter object
    * and the address of the iButton or 1-Wire device.
    *
    * @param  sourceAdapter     adapter object required to communicate with
    * this iButton.
    * @param  newAddress        address of this 1-Wire device
    */
   public OneWireContainer05 (DSPortAdapter sourceAdapter, String newAddress)
   {
      super(sourceAdapter, newAddress);
   }

   //--------
   //-------- Methods
   //--------

   /**
    * Retrieve the Dallas Semiconductor part number of the iButton
    * as a string.  For example 'Crypto iButton' or 'DS1992'.
    *
    * @return  string represetation of the iButton name.
    */
   public String getName ()
   {
      return "DS2405";
   }

   /**
    * Retrieve the alternate Dallas Semiconductor part numbers or names.
    * A 'family' of MicroLAN devices may have more than one part number
    * depending on packaging.  There can also be nicknames such as
    * 'Crypto iButton'.
    *
    * @return  <code>String</code> representation of the alternate names.
    */
   public String getAlternateNames ()
   {
      return "Addressable Switch";
   }

   /**
    * Retrieve a short description of the function of the iButton type.
    * Plagerized from the Auto ID Data Book.
    *
    * @return  <code>String</code> representation of the function description.
    */
   public String getDescription ()
   {
      return "Addressable Switch with controlled open drain PIO "
             + "pin. PIO pin sink capability is greater than 4mA "
             + "at 0.4V.";
   }

   //--------
   //-------- Switch Feature methods
   //--------

   /**
    * Query to get the number of channels supported by this switch.
    * Channel specific methods will use a channel number specified
    * by an integer from [0 to (getNumberChannels() - 1)].
    *
    *
    * @param state
    * @return int containing the number of channels
    */
   public int getNumberChannels (byte[] state)
   {

      //we ignore the state, DS2405 can only have one channel
      return 1;
   }

   /**
    * Query to see if the channels of this switch are 'high side'
    * switches.  This indicates that when 'on' or TRUE, the switch output is
    * connect to the 1-Wire data.  If this method returns  FALSE
    * then when the switch is 'on' or TRUE, the switch is connected
    * to ground.
    *
    * @return boolean, true if switch is a 'high side' switch.  false
    *                  if switch is a 'low side' switch.
    */
   public boolean isHighSideSwitch ()
   {
      return false;
   }

   /**
    * Query to see if the channels of this switch support
    * activity sensing.  If this method returns true then the
    * method 'getActivity()' can be used.
    *
    * @return boolean, true if channels support activity sensing
    */
   public boolean hasActivitySensing ()
   {
      return false;
   }

   /**
    * Query to see if the channels of this switch support
    * level sensing.  If this method returns true then the
    * method 'getLevel()' can be used.
    *
    * @return boolean, true if channels support level sensing
    */
   public boolean hasLevelSensing ()
   {
      return true;
   }

   /**
    * Query to see if the channels of this switch support
    * smart on. Smart on is the ability to turn on a channel
    * such that only 1-Wire device on this channel are awake
    * and ready to do an operation.  This greatly reduces the
    * the time to discover the device down a branch.
    * If this method returns true then the
    * method 'setSwitch()' can be used with the 'doSmart' parameter
    * true.
    *
    * @return boolean, true if channels support smart on
    */
   public boolean hasSmartOn ()
   {
      return false;
   }

   /**
    * Query to see if the channels of this switch require that only
    * channel is on at any one time.  If this method returns true then the
    * method 'setSwitch(channel)' will effect the state of the given
    * channel but may effect the state of the other channels as well
    * to insure that only one channel is on at a time.
    *
    * @return boolean, true if only 1 channel can be on at a time.
    */
   public boolean onlySingleChannelOn ()
   {
      return true;
   }

   //--------
   //-------- Switch 'get' Methods
   //--------

   /**
    * This method checks the sensed level on the indicated channel
    * from the provided state data retrieved from the
    * 'readDevice()' method.  Note, to avoid an exception, verify
    * the features of this switch with the method 'hasLevelSensing()'.
    *
    *
    * @param channel
    * @param  state - byte array of device state
    *
    * @return <code>boolean<\code> true if level sensed is 'high'
    * and false if level sensed is 'low'.
    */
   public boolean getLevel (int channel, byte[] state)
   {
      return ((state [0] & 0x02) == 0x02);
   }

   /**
    * This method checks the latch state of the indicated channel
    * from the provided state data retrieved from the
    * 'readDevice()' method.
    *
    *
    * @param channel
    * @param  state - byte array of device state
    *
    * @return <code>boolean<\code> true if channel latch is 'on'
    * or conducting and false if channel latch is 'off' and not
    * conducting.  Note that the actual output then the latch is 'on'
    * is returned from the 'isHighSideSwitch()' method.
    */
   public boolean getLatchState (int channel, byte[] state)
   {
      return ((state [0] & 0x01) == 0x01);
   }

   /**
    * This method checks if the indicated channel had activity
    * from the provided state data retrieved from the
    * 'readDevice()' method.   Note, to avoid an exception, verify
    * the features of this switch with the method 'hasActivitySensing()'.
    *
    *
    * @param channel
    * @param  state - byte array of device state
    *
    * @return <code>boolean<\code> true if activity was detected
    * and false if no activity was detected.
    */
   public boolean getSensedActivity (int channel, byte[] state)
      throws OneWireException
   {

      //i don't do this
      throw new OneWireException("Sense Activity not supported");
   }

   /**
    * Clears the activity latches the next time possible.  For
    * example, on a DS2406/07, this happens the next time the
    * status is read.
    */
   public void clearActivity ()
      throws OneWireException
   {

      //i don't do this
      throw new OneWireException("Sense Activity not supported");
   }

   //--------
   //-------- Switch 'set' Methods
   //--------

   /**
    * This method sets the latch state of the indicated channel in the
    * state data.  Use the method 'writeDevice()' with
    * this data to finalize the change to the device.
    *
    * @param channel - integer indicated channel to do operation on
    *                  in the range [0 to (getNumberChannels() - 1)]
    * @param latchState
    * @param doSmart - if latchState is 'on'/true then doSmart indicates
    *                  if a 'smart on' is to be done.  To avoid an exception
    *                  check the cababilities of the device using the
    *                  'hasSmartOn()' method.
    * @param state - byte array of device state
    */
   public void setLatchState (int channel, boolean latchState,
                              boolean doSmart, byte[] state)
   {
      if (latchState)
         state [0] = ( byte ) (state [0] | 0x01);
      else
         state [0] = ( byte ) (state [0] & 0xfe);
   }

   /**
    * This method retrieves the 1-Wire device sensor state.  This state is
    * returned as a byte array.  Pass this byte array to the static query
    * and set methods.  If the device state needs to be changed then call
    * the 'writeDevice' to finalize the one or more change.
    *
    * @return <code>byte[]<\code> 1-Wire device sensor state    *
    *
    * @throws OneWireIOException
    * @throws OneWireException
    */
   public byte[] readDevice ()
      throws OneWireIOException, OneWireException
   {

      //first let's make sure we can talk to the part
      //speed is not critical with the 2405 so i'll just call doSpeed()
      doSpeed();

      //this ain't a hard part--it's only gonna take 1 byte
      byte[] state = new byte [1];

      //here's the 'bitmap'
      //bit 0 :   switch state (0 for conducting, 1 for non-conducting)
      //bit 1 :   sensed level (0 for low, 1 for high)
      state [0] = ( byte ) 0;

      if (isPresent())
      {
         if (isAlarming())
            state [0] = 1;
      }
      else
         throw new OneWireIOException("Device not present");

      if (isPresent())
      {

         // Byte after 'search' indicates level
         if (adapter.getByte() != 0)
            state [0] = ( byte ) (state [0] | 0x02);
      }
      else
         throw new OneWireIOException("Device not present");

      return state;
   }

   /**
    * This method write the 1-Wire device sensor state that
    * have been changed by the 'set' methods.  It knows which registers have
    * changed by looking at the bitmap fields appended to the state
    * data.
    *
    * @param  state - byte array of clock register page contents
    *
    * @throws OneWireIOException
    * @throws OneWireException
    */
   public void writeDevice (byte[] state)
      throws OneWireIOException, OneWireException
   {
      doSpeed();

      boolean value   = ((state [0] & 0x01) == 0x01);
      boolean compare = isAlarming();

      // check to see if already in the correct state
      if (compare == value)
         return;

         // incorrect state so toggle
      else if (adapter.select(address))
      {

         // verify 
         compare = isAlarming();

         if (compare == value)
            return;
      }

      throw new OneWireIOException("Failure to change DS2405 latch state");
   }
}
