Skip to content

Commit

Permalink
added camera commands encoding/decoding (send/receive)
Browse files Browse the repository at this point in the history
  • Loading branch information
genemars committed Dec 6, 2018
1 parent 963d9ee commit d957353
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 32 deletions.
60 changes: 54 additions & 6 deletions CM19Lib/Cm19Manager.cs
Expand Up @@ -115,6 +115,11 @@ public class Cm19Manager
/// </summary>
public event X10SecurityReceivedEventHandler RfSecurityReceived;

/// <summary>
/// Occurs when x10 PTZ camera command is received.
/// </summary>
public event X10CommandReceivedEventHandler RfCameraReceived;

#endregion

#region Instance Management
Expand Down Expand Up @@ -253,6 +258,32 @@ public void AllUnitsOff(HouseCode houseCode)
SendCommand(houseCode, 0x00, Command.AllUnitsOff);
}

/// <summary>
/// Sends a Camera command.
/// </summary>
/// <param name="houseCode">House code.</param>
/// <param name="command">Camera command.</param>
/// <returns></returns>
public bool SendCameraCommand(HouseCode houseCode, Command command)
{
try
{
SendMessage(new[]
{
(byte) RfCommandType.Camera,
(byte) (((int)command >> 8) | Utility.HouseCodeToCamera(houseCode)),
(byte) ((int)command & 0xFF),
(byte) houseCode
});
}
catch (Exception e)
{
logger.Error(e);
return false;
}
return true;
}

/// <summary>
/// Turn off the specified module (houseCode, unitCode).
/// </summary>
Expand Down Expand Up @@ -420,10 +451,12 @@ private void ReaderTask()
bool isSecurityCode = (message[0] == (byte)RfCommandType.Security) &&
(message.Length == 7 && ((message[2] ^ message[1]) == 0x0F) &&
((message[4] ^ message[3]) == 0xFF));
bool isCodeValid = isSecurityCode || (message[0] == (byte)RfCommandType.Standard) &&
(message.Length == 5 &&
((message[2] & ~message[1]) == message[2] &&
(message[4] & ~message[3]) == message[4]));
bool isCameraCode = (message[0] == (byte) RfCommandType.Security);
bool isStandardCode = (message[0] == (byte) RfCommandType.Standard) &&
(message.Length == 5 &&
((message[2] & ~message[1]) == message[2] &&
(message[4] & ~message[3]) == message[4]));
bool isCodeValid = isStandardCode || isCameraCode || isSecurityCode;

// Repeated messages check
if (isCodeValid)
Expand Down Expand Up @@ -455,8 +488,13 @@ private void ReaderTask()
logger.Warn("Could not parse security event");
}
}
// TODO: implement code for type RfCommandType.Camera
else if (isCodeValid)
else if (isCameraCode)
{
var houseCode = (HouseCode) (message[1] & 0xF0);
var command = (RfFunction)(((message[1] & 0xF) << 8) | message[2]);
OnRfCameraReceived(new RfCommandReceivedEventArgs(command, houseCode, UnitCode.Unit_1));
}
else if (isStandardCode)
{
// Decode received 32 bit message
// house code + 4th bit of unit code
Expand Down Expand Up @@ -626,6 +664,16 @@ protected virtual void OnRfSecurityReceived(RfSecurityReceivedEventArgs args)
RfSecurityReceived(this, args);
}

/// <summary>
/// Raises the RF camera command received event.
/// </summary>
/// <param name="args"></param>
protected virtual void OnRfCameraReceived(RfCommandReceivedEventArgs args)
{
if (RfCameraReceived != null)
RfCameraReceived(this, args);
}

#endregion

#endregion
Expand Down
24 changes: 24 additions & 0 deletions CM19Lib/Utility.cs
Expand Up @@ -186,6 +186,30 @@ public static UnitCode UnitCodeFromString(string s)
return unitCode;
}

public static byte HouseCodeToCamera(HouseCode houseCode)
{
// Translate house code to octet necessary for 2nd byte in Pan'n'Tilt commands
switch (houseCode) {
case HouseCode.A: return 0x90;
case HouseCode.B: return 0xA0;
case HouseCode.C: return 0x70;
case HouseCode.D: return 0x80;
case HouseCode.E: return 0xB0;
case HouseCode.F: return 0xC0;
case HouseCode.G: return 0xD0;
case HouseCode.H: return 0xE0;
case HouseCode.I: return 0x10;
case HouseCode.J: return 0x20;
case HouseCode.K: return 0xF0;
case HouseCode.L: return 0x00;
case HouseCode.M: return 0x30;
case HouseCode.N: return 0x40;
case HouseCode.O: return 0x50;
case HouseCode.P: return 0x60;
default: return 0x90; /* default to A if bad houseCode */
}
}

public static byte ReverseByte(byte originalByte)
{
int result = 0;
Expand Down
10 changes: 9 additions & 1 deletion CM19Lib/x10/RfFunction.cs
Expand Up @@ -28,12 +28,20 @@ namespace CM19Lib.X10
public enum RfFunction
{
NotSet = 0xFF,

/* Standard 5-byte commands: */
On = 0x00,
Off = 0x01,
AllLightsOff = 0x80,
AllLightsOn = 0x90,
Dim = 0x98,
Bright = 0x88
Bright = 0x88,

/* Pan'n'Tilt 4-byte commands: */
CameraUp = 0x762,
CameraRight = 0x661,
CameraDown = 0x863,
CameraLeft = 0x560,
}
}

Expand Down
7 changes: 6 additions & 1 deletion Examples/cm19recv/Program.cs
Expand Up @@ -41,7 +41,7 @@ public static void Main(string[] args)
cm19.RfDataReceived += cm19_RfDataReceived;
cm19.RfCommandReceived += cm19_RfCommandReceived;
cm19.RfSecurityReceived += cm19_RfSecurityReceived;
// TODO: cm19.RfCameraReceived += cm19_RfCameraReceived;
cm19.RfCameraReceived += cm19_RfCameraReceived;
// Connect to the interface
cm19.Connect();

Expand Down Expand Up @@ -71,5 +71,10 @@ private static void cm19_RfSecurityReceived(object sender, RfSecurityReceivedEve
{
Console.WriteLine("Received RF Security event {0} from address {1}", args.Event, args.Address.ToString("X3"));
}

private static void cm19_RfCameraReceived(object sender, RfCommandReceivedEventArgs args)
{
Console.WriteLine("Received RF camera command {0} House Code {1} Unit {2}", args.Command, args.HouseCode, args.UnitCode.ToString().Replace("Unit_", ""));
}
}
}
75 changes: 58 additions & 17 deletions Examples/cm19send/Program.cs
Expand Up @@ -40,10 +40,15 @@ public static void Main(string[] args)
commands = args;
if (commands.Length == 0)
{
Console.WriteLine("Usage: mono cm19send.exe <command_1> [<command_2>...<command_n>]");
Console.WriteLine("Example: mono cm19send.exe +A1 +A2 -A3 -A +A");
Console.WriteLine(" Will turn ON A1 and A2, OFF A3 and then it will");
Console.WriteLine(" send a DIM and BRIGHT command (to house code A)");
Console.WriteLine("Usage: mono cm19send.exe <command_1> [<command_2>...<command_n>]\n");
Console.WriteLine("Example of sending standard commands:\n");
Console.WriteLine(" mono cm19send.exe A1+ A2+ A3- A- A+\n");
Console.WriteLine(" Will turn ON A1 and A2, OFF A3 and then it will");
Console.WriteLine(" send a DIM and BRIGHT command (to house code A).\n");
Console.WriteLine("Example of sending PTZ camera commands:\n");
Console.WriteLine(" mono cm19send.exe AU AL BD BR\n");
Console.WriteLine(" Will move camera with house code A UP and LEFT");
Console.WriteLine(" and the camera with house code B DOWN and RIGHT.\n");
return;
}
var cm19 = new Cm19Manager();
Expand All @@ -70,50 +75,86 @@ private static void sendCommands(Cm19Manager cm19)
HouseCode houseCode = HouseCode.NotSet;
UnitCode unitCode = UnitCode.UnitNotSet;
Command command = Command.NotSet;
bool isCameraCommand = false;
for (int i = 0; i < commands.Length; i++)
{
string cmd = commands[i].ToUpper();
if (cmd.Length == 2)
{
if (!Enum.TryParse(cmd[1].ToString(), out houseCode))
if (!Enum.TryParse(cmd[0].ToString(), out houseCode))
{
Console.WriteLine("Invalid house code.");
return;
}
switch (cmd[0])
if (cmd[1] == '+' || cmd[1] == '-')
{
case '+':
command = Command.Bright;
break;
case '-':
command = Command.Dim;
break;
switch (cmd[1])
{
case '+':
command = Command.Bright;
break;
case '-':
command = Command.Dim;
break;
}
}
else
{
isCameraCommand = true;
switch (cmd[1])
{
case 'U':
command = Command.CameraUp;
break;
case 'D':
command = Command.CameraDown;
break;
case 'L':
command = Command.CameraLeft;
break;
case 'R':
command = Command.CameraRight;
break;
}
}
}
else if (cmd.Length > 2)
{
if (!Enum.TryParse(cmd[1].ToString(), out houseCode))
if (!Enum.TryParse(cmd[0].ToString(), out houseCode))
{
Console.WriteLine("Invalid house code.");
return;
}
if (!Enum.TryParse("Unit_"+cmd.Substring(2), out unitCode))
if (!Enum.TryParse("Unit_"+cmd.Substring(1, cmd.Length - 2), out unitCode))
{
Console.WriteLine("Invalid unit number.");
return;
}
switch (cmd[0])
switch (cmd[cmd.Length-1])
{
case '+':
command = Command.On;
break;
case '-':
command = Command.Off;
break;
default:
Console.WriteLine("Invalid command.");
return;
}
}
Console.WriteLine("Sending X10 command '{0}' HouseCode '{1}' Unit '{2}'", command, houseCode, unitCode);
cm19.SendCommand(houseCode, unitCode, command);
if (isCameraCommand)
{
Console.WriteLine("Sending X10 camera command '{0}' HouseCode '{1}'", command, houseCode);
cm19.SendCameraCommand(houseCode, command);
isCameraCommand = false;
}
else
{
Console.WriteLine("Sending X10 command '{0}' HouseCode '{1}' Unit '{2}'", command, houseCode, unitCode);
cm19.SendCommand(houseCode, unitCode, command);
}
// pause 1 second between each command
if (i < commands.Length - 1) Thread.Sleep(1000);
}
}
Expand Down
30 changes: 23 additions & 7 deletions README.md
Expand Up @@ -64,15 +64,20 @@ cm19recv.exe
**cm19send** is a program to send X10 command.
Example usage:
```bash
cm19send.exe +A1 +A5 -A7 -A -A +C2
# X10 standard commands
# and camera commands (the last two)
cm19send.exe A1+ A5+ A7- A- A- C2+ AU BD
```
The program can send one ore more X10 commands (separated by a white space).
An X10 command starts with the **+** (**ON**) or **-** (**OFF**) symbol followed by
the house code and the unit code.
An X10 standard command starts with the house code followed by the unit code and
the **+** (**ON**) or **-** (**OFF**) symbol.

If no unit code is provided the **+** will perform a **BRIGHT** command or a **DIM**
command in case the **-** symbol is used (eg. *+A* or -*A-*).

An X10 PTZ camera command starts with the house code followed by one of the following:
**U** for up, **L** for left, **D** for down and **R** for right.

## Example code

```csharp
Expand All @@ -87,6 +92,7 @@ cm19.ConnectionStatusChanged += cm19_ConnectionStatusChanged;
cm19.RfDataReceived += cm19_RfDataReceived;
cm19.RfCommandReceived += cm19_RfCommandReceived;
cm19.RfSecurityReceived += cm19_RfSecurityReceived;
cm19.RfCameraReceived += cm19_RfCameraReceived;

//...
Expand All @@ -95,20 +101,24 @@ cm19.Connect();

//...
// Examples of sending X10 commands
// Examples of sending standard X10 commands
cm19.UnitOff(HouseCode.C, UnitCode.Unit_7);
cm19.UnitOn(HouseCode.A, UnitCode.Unit_4);
cm19.Dim(HouseCode.A);
cm19.Bright(HouseCode.A);
cm19.AllLightsOn(HouseCode.A);
cm19.AllUnitsOff(HouseCode.A);
// Alternative way of sending X10 commands

// Alternative way of sending standard X10 commands
cm19.SendCommand(HouseCode.E, UnitCode.Unit_12, Command.On);

// Sending PTZ camera commands
cm19.SendCameraCommand(HouseCode.A, Command.CameraDown);
cm19.SendCameraCommand(HouseCode.A, Command.CameraLeft);

// Raw send X10 command (Security Disarm)
cm19.SendMessage(new byte[]{0x29, 0x66, 0x69, 0x86, 0x79, 0x4A, 0x80});

//...
// Disconnect the interface
cm19.Disconnect();

Expand All @@ -135,6 +145,12 @@ void Cm19_RfSecurityReceived(object sender, RfSecurityReceivedEventArgs args)
Console.WriteLine("Received RF Security event {0} from address {1}",
args.Event, args.Address.ToString("X3"));
}

private static void cm19_RfCameraReceived(object sender, RfCommandReceivedEventArgs args)
{
Console.WriteLine("Received RF camera command {0} House Code {1} Unit {2}",
args.Command, args.HouseCode, args.UnitCode.ToString().Replace("Unit_", ""));
}
```

## License
Expand Down

0 comments on commit d957353

Please sign in to comment.