/* x10.cpp - X10 transmission library for Arduino version 0.4 Original library (0.1) by Tom Igoe. Timing bug fixes (0.2) " " " #include bug fixes for 0012 (0.3) " " " use pullup, minor tweaks (0.4) Paul Stoffregen 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 "x10.h" /* Constructor. Sets the pins and sets their I/O modes. */ x10::x10(uint8_t zeroCrossingPin, uint8_t dataPin) { this->dataPin = dataPin; // the output data pin zeroCrossingReg = portInputRegister(digitalPinToPort(zeroCrossingPin)); zeroCrossingBit = digitalPinToBitMask(zeroCrossingPin); // Set I/O modes: #ifdef INPUT_PULLUP pinMode(zeroCrossingPin, INPUT_PULLUP); #else pinMode(zeroCrossingPin, INPUT); digitalWrite(zeroCrossingPin, HIGH); #endif pinMode(dataPin, OUTPUT); } /* Writes an X10 command out to the X10 modem */ void x10::write(byte houseCode, byte numberCode, byte numRepeats) { byte startCode = B1110; // every X10 command starts with this // repeat as many times as requested: for (uint8_t 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)) { for (uint8_t i = 0; i < 6; i++) { waitForZeroCross(); } } } /* 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 (uint8_t i=1; i<=numBits; i++) { // wait for a zero crossing change: waitForZeroCross(); // shift off the last bit of the command: thisBit = !!(cmd & (1 << (numBits - i))); // repeat once for each phase: for (uint8_t 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(); for (uint8_t 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(uint8_t howManyTimes) void x10::waitForZeroCross(void) { // wait for pin to change: if (*zeroCrossingReg & zeroCrossingBit) { while (*zeroCrossingReg & zeroCrossingBit) /* wait */ ; } else { while (!(*zeroCrossingReg & zeroCrossingBit)) /* wait */ ; } } /* version() returns the version of the library: */ int x10::version(void) { return 3; }