Sunday, 20 February 2011

Arduino X10 temperature library

Time to release the temperature library I have been working on... ( there has to be a better way )

It turns out that what is required is a response to a status request to send back the temperature using preset dim commands. The results are a rcs type sensor


/*
  x10.cpp - X10 transmission library for Arduino version 0.3
 
  Original library                              (0.1) by Tom Igoe.
  Timing bug fixes                              (0.2) "   "   "
  #include bug fixes for 0012                   (0.3) "   "   "
  Temperature Sensing                           (0.4) by Jason Cox

  Zero crossing algorithms borrowed from David Mellis' shiftOut command
  for Arduino.
 
  The circuits can be found at

http://www.arduino.cc/en/Tutorial/x10


 */

#include
#include "WProgram.h"
#include "x10.h"
#include "x10constants.h"


/*
 Constructor.

 Sets the pins and sets their I/O modes.

 */
x10::x10(int zeroCrossingPin, int dataPin)
{
  this->zeroCrossingPin = zeroCrossingPin;      // the zero crossing pin
  this->dataPin = dataPin;                                      // the output data pin
 
  // Set I/O modes:
  pinMode(this->zeroCrossingPin, INPUT);
  pinMode(this->dataPin, OUTPUT);
}



/*
        Writes an X10 command out to the X10 modem
*/
void x10::write(byte houseCode, byte numberCode, int numRepeats) {
  byte startCode = B1110;               // every X10 command starts with this

        // repeat as many times as requested:
        for (int i = 0; i < numRepeats; i++) {
                // send the three parts of the command:
                sendBits(startCode, 4, true);
                sendBits(houseCode, 4, false);
                sendBits(numberCode, 5, false);
        }
        // if this isn't a bright or dim command, it should be followed by
        // a delay of 3 power cycles (or 6 zero crossings):
        if ((numberCode != BRIGHT) && (numberCode != DIM)) {
                waitForZeroCross(this->zeroCrossingPin, 6);
        }
}
/*
        Writes a sequence of bits out.  If the sequence is not a start code,
        it repeats the bits, inverting them.
*/

void x10::sendBits(byte cmd, byte numBits, byte isStartCode) {
  byte thisBit;         // copy of command so we can shift bits
 
        // iterate the number of bits to be shifted:
        for(int i=1; i<=numBits; i++) {
                // wait for a zero crossing change:
                waitForZeroCross(this->zeroCrossingPin, 1);
                // shift off the last bit of the command:
                thisBit = !!(cmd & (1 << (numBits - i)));

                // repeat once for each phase:
                for (int phase = 0; phase < 3; phase++) {
                        // set the data Pin:
                        digitalWrite(this->dataPin, thisBit);
                        delayMicroseconds(BIT_LENGTH);
                        // clear the data pin:
                        digitalWrite(this->dataPin, LOW);
                        delayMicroseconds(BIT_DELAY);
                }

                // if this command is a start code, don't
                // send its complement.  Otherwise do:
                if(!isStartCode) {
                        // wait for zero crossing:
                        waitForZeroCross(zeroCrossingPin, 1);
                        for (int phase = 0; phase < 3; phase++) {
                                // set the data pin:
                                digitalWrite(this->dataPin, !thisBit);
                                delayMicroseconds(BIT_LENGTH);
                                // clear the data pin:
                                digitalWrite(dataPin, LOW);
                                delayMicroseconds(BIT_DELAY);
                        }
                }
        }
}


/*
  waits for a the zero crossing pin to cross zero

*/
void x10::waitForZeroCross(int pin, int howManyTimes) {
        unsigned long cycleTime = 0;

        // cache the port and bit of the pin in order to speed up the
        // pulse width measuring loop and achieve finer resolution.  calling
        // digitalRead() instead yields much coarser resolution.
        uint8_t bit = digitalPinToBitMask(pin);
        uint8_t port = digitalPinToPort(pin);

        for (int i = 0; i < howManyTimes; i++) {
                // wait for pin to change:
        if((*portInputRegister(port) & bit))
                while((*portInputRegister(port) & bit))
                        cycleTime++;
        else
                while(!(*portInputRegister(port) & bit))
                        cycleTime++;
                }
}


/*
  version() returns the version of the library:
*/
int x10::version(void)
{
  return 3;
}

void x10::x10temp (byte temp_houseCode, byte tmep_Unit, int count, int RPT_SEND){
        detachInterrupt(0);                  // must detach interrupt before sending
          x10::write(temp_houseCode ,tmep_Unit ,RPT_SEND); 
          x10::write(temp_houseCode ,UNIT_13 ,RPT_SEND);
          switch (count) {
            case 0:
              x10::write(M,PRE_SET_DIM,RPT_SEND);
              break;
            case 1:
              x10::write(N,PRE_SET_DIM,RPT_SEND);
              break;
            case 2:
              x10::write(O,PRE_SET_DIM,RPT_SEND);
              break;
            case 3:
              x10::write(P,PRE_SET_DIM,RPT_SEND);
              break;
            case 4:
              x10::write(C,PRE_SET_DIM,RPT_SEND);
              break;
            case 5:
              x10::write(D,PRE_SET_DIM,RPT_SEND);
              break;
            case 6:
              x10::write(A,PRE_SET_DIM,RPT_SEND);
              break;
            case 7:
              x10::write(B,PRE_SET_DIM,RPT_SEND);
              break;
            case 8:
              x10::write(E,PRE_SET_DIM,RPT_SEND);
              break;
            case 9:
              x10::write(F,PRE_SET_DIM,RPT_SEND);
              break;
            case 10:
              x10::write(G,PRE_SET_DIM,RPT_SEND);
              break;
            case 11:
              x10::write(H,PRE_SET_DIM,RPT_SEND);
              break;
            case 12:
              x10::write(K,PRE_SET_DIM,RPT_SEND);
              break;
            case 13:
              x10::write(L,PRE_SET_DIM,RPT_SEND);
              break;
            case 14:
              x10::write(I,PRE_SET_DIM,RPT_SEND);
              break;
            case 15:
              x10::write(J,PRE_SET_DIM,RPT_SEND);
              break;
            case 16:
              x10::write(M,PRE_SET_DIM2,RPT_SEND);
              break;
            case 17:
              x10::write(N,PRE_SET_DIM2,RPT_SEND);
              break;
            case 18:
              x10::write(O,PRE_SET_DIM2,RPT_SEND);
              break;
            case 19:
              x10::write(P,PRE_SET_DIM2,RPT_SEND);
              break;
            case 20:
              x10::write(C,PRE_SET_DIM2,RPT_SEND);
              break;
            case 21:
              x10::write(D,PRE_SET_DIM2,RPT_SEND);
              break;
            case 22:
              x10::write(A,PRE_SET_DIM2,RPT_SEND);
              break;
            case 23:
              x10::write(B,PRE_SET_DIM2,RPT_SEND);
              break;
            case 24:
              x10::write(E,PRE_SET_DIM2,RPT_SEND);
              break;
            case 25:
              x10::write(F,PRE_SET_DIM2,RPT_SEND);
              break;
            case 26:
              x10::write(G,PRE_SET_DIM2,RPT_SEND);
              break;
            case 27:
              x10::write(H,PRE_SET_DIM2,RPT_SEND);
              break;
            case 28:
              x10::write(K,PRE_SET_DIM2,RPT_SEND);
              break;
            case 29:
              x10::write(L,PRE_SET_DIM2,RPT_SEND);
              break;
            case 30:
              x10::write(I,PRE_SET_DIM2,RPT_SEND);
              break;
            case 31:
              x10::write(J,PRE_SET_DIM2,RPT_SEND);
              break;
         
          }
}


and x10.h
/*
 
  Original library              (0.1) by Tom Igoe.
  Timing bug fixes              (0.2) "   "   "
  Temperature                   (0.3) by Jason Cox
        Sends X10 commands.

*/

// ensure this library description is only included once
#ifndef x10_h
#define x10_h

// include types & constants of Wiring core API
#include
#include "WProgram.h"
#include "pins_arduino.h"

// library interface description
class x10 {
  public:
    // constructors:
    x10(int zeroCrossingPin, int dataPin);

    // write command method:
        void write(byte houseCode, byte numberCode, int numRepeats);
    // returns the version number:
    int version(void);
    void x10temp(byte tmep_houseCode, byte temp_Unit , int count, int RPT_SEND);

  private:
        int zeroCrossingPin;    // AC zero crossing pin
        int dataPin;                    // data out pin
        // sends the individual bits of the commands:
    void sendBits(byte cmd, byte numBits, byte isStartCode);
    // checks for AC zero crossing
    void waitForZeroCross(int pin, int howManyTimes);
};

#endif

Lastly the constants file (added preset dim2)


#define HIGH 0x1
#define LOW  0x0
#define BIT_DELAY 2133          // 1778 us between bit repeats in a half-cycle
#define BIT_LENGTH 900          // each bit is slightly less than 1ms long

#define A       B0110
#define B       B1110
#define C       B0010
#define D       B1010
#define E       B0001
#define F       B1001
#define G       B0101
#define H       B1101
#define I       B0111
#define J       B1111
#define K       B0011
#define L       B1011
#define M       B0000
#define N       B1000
#define O       B0100
#define P       B1100

#define UNIT_1  B01100
#define UNIT_2  B11100
#define UNIT_3  B00100
#define UNIT_4  B10100
#define UNIT_5  B00010
#define UNIT_6  B10010
#define UNIT_7  B01010
#define UNIT_8  B11010
#define UNIT_9  B01110
#define UNIT_10 B11110
#define UNIT_11 B00110
#define UNIT_12 B10110
#define UNIT_13 B00000
#define UNIT_14 B10000
#define UNIT_15 B01000
#define UNIT_16 B11000

#define ALL_UNITS_OFF                   B00001
#define ALL_LIGHTS_ON                   B00011
#define ON                              B00101
#define OFF                             B00111
#define DIM                             B01001
#define BRIGHT                          B01011
#define ALL_LIGHTS_OFF                  B01101
#define EXTENDED_CODE                   B01111
#define HAIL_REQUEST                    B10001
#define HAIL_ACKNOWLEDGE                B10011
#define PRE_SET_DIM                     B10101
#define PRE_SET_DIM2                    B10111
#define EXTENDED_DATA                   B11001
#define STATUS_ON                       B11011
#define STATUS_OFF                      B11101
#define STATUS_REQUEST                  B11111