(This post is an updated version from a post I made a long time ago elsewhere on this forum)

What is the difference between controller generated vs externally originated X10 commands, as far as the controller receiving them is concerned? There is a difference in what the controller receives (or doesn't) depending on whether the X10 command was generated by the controller itself or by an external device, and knowing what to expect can only help in writing more predictable code.

For testing, I used two Leopards running identical programs, aimed at showing the contents of the X10 input buffer on the screen as embedded variables. The "%x" text formatting option was particularily handy for displaying the data in hex! I then used one of the Leopards to send individual X10 commands using the C-Max "Send X10" utility and observed what each one was receiving. I could thus observe the transmitting Leopard to see how controller generated commands were received, and the other Leopard received the same commands as externally originated.

Before going any furthur, I want to recap how the X10 protocol allows for multiple units to be addressed and then controlled together with a common X10 command. For example, you can send A/1, A/2, A/3 to address all three modules, and then A/ON to turn them all on simultaneously, then A/DIM to dim them all together, etc. Any commands sent to the same house code will be executed by all three until a new address is transmitted. When that happens, the three modules will now ignore commands until they see their address(es) again. Since an ADI controller receives X10 like any other module, it also mimicks this address selection scheme when receiving X10, which is important in understanding some of the explanations below.

In C-Max, there are two different commands to work with incoming X10 data. The "IF Receive Single X10" command looks for raw X10 addresses and commands, and these are put in the X10 input queue as they are received. The other instruction; "IF X10 Status/Cmnd Pair" is looking for interpreted X10 commands (and also the contents of the status table, which we are not concerned with here at this time). The X10 input queue is encoded in such a way as to allow both raw and interpreted X10 commands to use the same queue, and each of the two instructions just discussed looks for its own type of data. As detailed in the Ocelot and Leopard manuals, here are the values that the queue stores for each type of command. The input queue stores 16 bit values with the house code in the high byte and the raw or interpreted command in the low byte. These are shown in hex to make them easier to understand:

Highest 8 bits = House code.
00 = House code A
01 = House code B
...
0F = House code P

Lowest 8 bits = Command/Unit Code:
(raw X10)
00 = unit code 1
01 = unit code 2
...
0F = unit code 16

10 = All Units OFF
11 = All Lights ON
12 = ON
13 = OFF
14 = Dim
15 = Bright
16 = All Lights OFF
17 = Extended Code
18 = Hail Req.
19 = Hail Ack.
1A = Preset Dim 0
1B = Ext. Data
1C = Status ON
1D = Status OFF
1E = Status REQUEST
1F = Preset Dim 1

(interpreted X10)
40 = unit 1 OFF
41 = unit 2 OFF
...
4F = unit 16 OFF
80 = unit 1 ON
81 = unit 2 ON
...
8F = unit 16 ON

Externally Generated X10

When X10 commands are received from an external source, the controller will queue the raw addresses and commands received, and also any interpreted X10 commands. When a command produces an interpretation, the interpretation is queued first, followed by the raw command itself. For example, If an B/1 ON command pair is received, the queue contents will be (oldest ones first):

(when the B/1 is received)
01 00 (B/1)
(When the B/ON is received)
01 80 (B unit 1 ON)
01 12 (B/ON)

If the external X10 signal source transmits B/1, B/2, B/3, B/ON (for example, using a maxi controller):

(when the B/1 is received)
01 00 (B/1)
(when the B/2 is received)
01 01 (B/2)
(when the B/3 is received)
01 02 (B/3)
(When the B/ON is received)
01 80 (B unit 1 ON)
01 81 (B unit 2 ON)
01 82 (B unit 3 ON)
01 12 (B/ON)

If you then followed the above B/ON command with a raw B/OFF:

(When the B/OFF is received)
01 40 (B unit 1 OFF)
01 41 (B unit 2 OFF)
01 42 (B unit 3 OFF)
01 13 (B/OFF)

Also, the interpreted commands update the controller's X10 status table too, so you would see all 3 addresses go on and off together.

Lastly, if the controller gets a new address on the house code (eg. B/4) then the three addresses become "unselected" and a new command (eg. B/ON) will only affect that address:

(when the B/4 is received)
01 03 (B/4)
(When the B/ON is received)
01 83 (B unit 4 ON)
01 12 (B/ON)

However, for the unselection of previous addresses to occur, one of the commands that preceeds any new address(es) must be an ON or OFF command. A Bright or Dim command will not cause unselection of previously addressed modules. So if we are using our maxi controller in a room where we can see that the lights are already on and we only want to dim them, we could send the following:

(when the B/1 is received)
01 00 (B/1)
(when the B/2 is received)
01 01 (B/2)
(when the B/3 is received)
01 02 (B/3)
(When the B/Dim is received)
01 14 (B/Dim)

But then someone uses another controller to turn off the light at address B/4:

(When the B/4 is received)
01 03 (B/4)
(when the B/OFF is received)
01 40 (B unit 1 OFF)
01 41 (B unit 2 OFF)
01 42 (B unit 3 OFF)
01 43 (B unit 4 OFF)
01 13 (B/OFF)

Surprise: the controller "thinks" you selected all four addresses for turning off and interprets it that way (and any instructions in your program looking for those command pairs will fire). This is the condition that several people were observing following macros that were sending either dim/bright commands or extended commands (eg. Leviton preset dims).

Controller Generated X10

Things are a bit different when the controller receives X10 data that it sent itself. The main difference is that the raw commands will not appear in the X10 input queue, only the interpreted commands, with the exception of the bright and dim commands (these will appear). Going back to the same examples as above:

If an B/1 ON command pair is sent by the controller, the queue contents will be (oldest ones first):

(when the B/1 is sent)
...nothing
(When the B/ON is sent)
01 80 (B unit 1 ON)

If the controller transmits B/1, B/2, B/3, B/ON:

(when the B/1 is sent)
...nothing
(when the B/2 is sent)
...nothing
(when the B/3 is sent)
...nothing
(When the B/ON is sent)
01 80 (B unit 1 ON)
01 81 (B unit 2 ON)
01 82 (B unit 3 ON)

If you then followed the above B/ON command with a raw B/OFF:

(When the B/OFF is received)
01 40 (B unit 1 OFF)
01 41 (B unit 2 OFF)
01 42 (B unit 3 OFF)

The address unselection that occurs when a new address follows an ON or OFF command follows the exact same rules as for externally generated commands. Once again: bright, dim, extended, etc. do not cause address unselection.

Finally, only controller generated dim or bright commands will also be received as raw commands:

(when the B/1 is sent)
...nothing
(when the B/2 is sent)
...nothing
(when the B/3 is sent)
...nothing
(When the B/Dim is sent)
01 14 (B/Dim)