//------------------------------------------------------------------
// qfixI2CSlave.h
//
// This is a convenience class for writing I2C slave programs
// (like slaveBoard.cc).
// This class supports the qfix I2C protocol.
//
// Copyright 2005 by KTB mechatronics GmbH
// Author: Stefan Enderle
//------------------------------------------------------------------


#ifndef qfixI2CSlave_h
#define qfixI2CSlave_h

#include "qfixI2C.h"
#include "qfixI2CDefs.h"
#include "qfixI2CMaster.h" // Only for constants


//---------------------------------------------------------------

class I2CSlave
{
public:
  I2C i2c;

  uint8_t brdID;  // board ID (what board)
  uint8_t logID;  // logical ID (which one of these boards)
  
  void (*commandPtr)(uint8_t cmd, uint8_t* params, uint8_t len);
  void (*requestPtr)(uint8_t cmd, uint8_t* params, uint8_t len);


  uint8_t params[100];
  uint8_t data[100];

public:
  /** boardID denotes the board (BobbyBoard, LCD, ...) that 
  *   shall be used. The logical ID is set to 0.
  */
  I2CSlave(uint8_t boardID);

  /** boardID denotes the board (BobbyBoard, LCD, ...) that 
  *   shall be used. logicalID is the sub-ID (e.g. which LCD).
  */
  I2CSlave(uint8_t boardID, uint8_t logicalID);

  void setLogicalID(uint8_t logicalID);
  
  void run();
};


I2CSlave::I2CSlave(uint8_t boardID)
: i2c(), brdID(boardID), logID(0)
{
  i2c.setSlaveAdress(boardID);
}


I2CSlave::I2CSlave(uint8_t boardID, uint8_t logicalID)
: i2c(), brdID(boardID), logID(logicalID)
{
  i2c.setSlaveAdress(boardID);
}


void I2CSlave::setLogicalID(uint8_t logicalID)
{
  logID = logicalID;
}

void I2CSlave::run()
{
  while (1) {
  
    // wait for action on the I2C bus //
    while (!i2c.isAction())   { }

    // was it a command (send) //
    if (i2c.isActionSend()) { 
	
	  // receive bytes: 0=logical ID, 1=command, 2..n=params
      int len = i2c.receive(data);

	  // if logical ID matches (or 255) -> execute //
      if ( (data[0] == logID) || (data[0]==255) ) {
	  
	    // is it the first part of a request ? -> save params //
        if (data[1] == CMD_PARAMS) {
          for (int i=0; i<len; i++) {
            params[i] = data[i];
          }
        }

        // it is a command -> call the given command function //
	    else commandPtr(data[1], data+2, len-2);
	  }
    }

    // or was it a request (get) //
    else if (i2c.isActionGet()) { 
	  requestPtr(params[2], params+3, 0);  // call given rqs function
    }

    // else ERROR !
  }
}


#endif

