// SC2262 Emulator / Controller for radio-controlled sockets
//
// This project aims at computer controlling the power to devices around my home.
//
// Kit list:
// 1x Arduino Duemilanove ATMege328
// 1x AM Radio Transmitter Module: Quasar UK, "QAM-TX1" 433MHz,
http://www.quasaruk.co.uk/acatalog/AM_Transmitter_-_TX1.html// 1x "smj electrical" "remote control socket" [Maplin Order Code: N79FN]
// Connect Arduino Digital pin13 to Transmitter "Data"
// Connect Arduino Power "5v" to Transmitter "VCC"
// Connect Arduino Power "Gnd" to Transmitter "GND"
//
// Windows "bat" file relays arguments to my Arduino: argument: "smj[A|B|C|D][1|2|3][on|off]" eg. "smjA1on"
//@echo off
//mode com3 baud=9600 data=8 parity=n stop=1 xon=on odsr=off octs=off rts=off dtr=off
//echo %* > com3
// -- Use "Splinterware" "System Scheduler" to automate operation of the Arduino via the above ".bat" file.
// V3 Date: 2011 05 01
// Copyright (C) 2011 Ian Craig, Tithby Hill Limited. tithby<dot>hill<at>ifcraig.com.
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// A copy of the GNU General Public License is available at:
http://www.gnu.org/licenses/.#define TRANSMITTER 13 // The Arduino output pin 13 is used to drive 433 MHz AM transmitter
#define SC2262Clock 100 // SC2262 internal clock is run at 10KHz for "smj" transmitter device (3.3MOhm timing resistor), therefore 100 microSecond wavelength
// sc2262pins is an array that indicates the voltage applied to the simulated SC2262 chip pins
char sc2262pins[] = "FFFFFFFFFFFF"; // H=High, L=Low or F=Floating for 12 pins
// These globals are defaults, for different devices they are changed by "SetSC2262Clock()".
// 16 cycles per bit, 2 bits per SC2262 tri-state address/data pin, 12 address/data pins on SC2262
int DurationShort;
int DurationLong;
int DurationSyncShort;
int DurationSyncLong;
// -----------------------------------------------------------------------------
// Basic SC2262 output emulation
// Input wavelength of SC2262 internal clock in micro-seconds to get revised timings for basic components of packet that simulates SC2262 output
void setSC2262Clock (int sc2262Clock)
{ // One bit of two-bit tri-state pin state takes 16 cycles
DurationShort = sc2262Clock * 4; // 4 clock cycles for short part of bit
DurationLong = sc2262Clock * (16-4); // 12 clock cycles for long part of bit
DurationSyncShort = sc2262Clock * 4; // Sync bit has a 4 cycle/short "high", followed by 124 bit "low"
DurationSyncLong = sc2262Clock * (128-4); // Sync bit has a 4 cycle/short "high", followed by 124 bit "low"
}
void longShort ()
{ digitalWrite (TRANSMITTER, HIGH);
delayMicroseconds (DurationLong);
digitalWrite (TRANSMITTER, LOW);
delayMicroseconds (DurationShort);
}
void shortLong ()
{ digitalWrite (TRANSMITTER, HIGH);
delayMicroseconds (DurationShort);
digitalWrite (TRANSMITTER, LOW);
delayMicroseconds (DurationLong);
}
// Sync has a long pause after packet sent
void sync ()
{ digitalWrite (TRANSMITTER, HIGH);
delayMicroseconds (DurationSyncShort);
digitalWrite (TRANSMITTER, LOW);
delayMicroseconds (DurationSyncLong);
}
// Tri-state logic on/off/float of signals emulated here
void pinLow ()
{ shortLong ();
shortLong ();
}
void pinHigh ()
{ longShort ();
longShort ();
}
void pinFloat ()
{ shortLong ();
longShort ();
}
// Packet terminated with on of these
void syncBit ()
{ sync ();
}
// -----------------------------------------------------------------------------
// Send SC2262 packet
// Send repeat of packets - to be sure (min 2 times - 6 is good)
void sendSC2262Packet ()
{ // Send packet, repeated in blocks - overkill is OK, underkill is a disaster
for (int i=0; i < 10; i++)
{ sendOneSC2262Packet();
sendOneSC2262Packet();
sendOneSC2262Packet();
sendOneSC2262Packet();
sendOneSC2262Packet();
sendOneSC2262Packet();
delay (100);
}
}
// This will send one packet to receivers - not enough!
void sendOneSC2262Packet ()
{ noInterrupts();
for (int i=0; i<12; i++)
{ switch (sc2262pins
)
{ case 'H':
pinHigh();
break;
case 'L':
pinLow();
break;
case 'F':
pinFloat();
break;
}
}
syncBit ();
interrupts();
}
// -----------------------------------------------------------------------------
// Serial port / PC communication
void serialRx_waitForSMJ () // Looking for "smj"
{ boolean gotS = false;
boolean gotM = false;
while (true)
{ if (Serial.available() > 0)
{ switch (Serial.read())
{ case 's':
case 'S':
gotS = true;
gotM = false;
continue;
case 'm':
case 'M':
if (gotS == true && gotM == false)
{ gotM = true; }
else
{ gotS = false;
gotM = false;
}
continue;
case 'j':
case 'J':
if (gotS == true && gotM == true)
{
return;
}
else
{ gotS = false;
gotM = false;
}
continue;
default:
gotS = false;
gotM = false;
}
}
else
{ delay (100);
}
}
}
boolean serialRx_getABCD() // Looking for "A,B,C or D"
{ if (Serial.available() > 0)
{ switch (Serial.read())
{ case 'A':
case 'a':
sc2262pins[0] = 'L';
return true;
case 'B':
case 'b':
sc2262pins[1] = 'L';
return true;
case 'C':
case 'c':
sc2262pins[2] = 'L';
return true;
case 'D':
case 'd':
sc2262pins[3] = 'L';
return true;
}
}
// Give up
return false;
}
boolean serialRx_get123 () // Looking for "1,2 or 3"
{ if (Serial.available() > 0)
{ switch (Serial.read())
{ case '1':
sc2262pins[4] = 'L';
return true;
case '2':
sc2262pins[5] = 'L';
return true;
case '3':
sc2262pins[6] = 'L';
return true;
}
}
// Give up
return false;
}
boolean serialRx_getOnOrOff () // Looking for "on or off"
{ if (Serial.available() > 1)
{ if (Serial.read() == 'o')
{ switch (Serial.read())
{ case 'n':
sc2262pins[11] = 'H';
return true;
case 'f':
sc2262pins[11] = 'L';
if (Serial.available()) Serial.read(); // Don't really care about 2nd 'f' in "off"
return true;
}
}
}
// Give up
return false;
}
// -----------------------------------------------------------------------------
// Main bit
void setup ()
{ // Wait for bootloader to get out of the way
delay (2000);
// initialize the serial communication:
Serial.begin (9600);
// Tell Arduino which pin used for output to 433MHz transmitter
pinMode (TRANSMITTER, OUTPUT);
// Initialise output to low
digitalWrite (TRANSMITTER, LOW);
// Set frequency of encoded packet [for "smj" socket device 3M3 ohms/(1MHz, 32 cycles per word)]
setSC2262Clock (SC2262Clock);
}
void loop ()
{ // Looking for: "smj[A|B|C|D][1|2|3][on|off]" from computer
// Step 1: Wait for "smj" to be sent to Arduino. Ignore everything else.
serialRx_waitForSMJ ();
// Reset pattern to simulate the pins of an SC2262 packet
for (int i=0; i<12; i++) sc2262pins = 'F';
// If the rest of the string isn't here (after the delay) then give up
delay (500);
if (serialRx_getABCD ()) // Looking for "A,B,C or D"
{ if (serialRx_get123 ()) // Looking for "1,2 or 3"
{ if (serialRx_getOnOrOff ()) // Looking for "on" or "off"
{ // Serial.print ("SC2262 pins: ");
// Serial.println (sc2262pins);
sendSC2262Packet ();
}
}
}
}