Private Sub SerialPLM_DataReceived(ByVal
sender As Object,
ByVal e As
System.IO.Ports.SerialDataReceivedEventArgs) Handles
SerialPLM.DataReceived
       
' this is the
serial port data received event on a secondary thread
       
Dim
handler As New
mySerialDelegate(AddressOf
PLM)
       
Do Until
SerialPLM.BytesToRead = 0
           
x(x_LastWrite + 1) =
SerialPLM.ReadByte
           
x(x_LastWrite + 10) = 0
           
If
x_LastWrite < 30 Then
x(x_LastWrite + 1001)
= x(x_LastWrite + 1) 
'
the ends overlap so no message breaks over the
limit of the array
           
x_LastWrite = x_LastWrite + 1 
'
increment only after the data is written, in
case PLM() is running at same time
           
If
x_LastWrite > 1000 Then
x_LastWrite = 1
       
       
' invoke
delegate on primary UI thread 
       
Me.BeginInvoke(handler)
    End Sub
    Public Delegate Sub
mySerialDelegate()
    Public Sub PLM()
       
' This
routine handles the serial data on the primary thread
       
Dim i
As Short
       
Dim
X10House As Byte
       
Dim
X10Code As Byte
       
Dim
X10Address As String
       
Dim
FromAddress As String
       
Dim
ToAddress As String
       
Dim
IAddress As Short
' Insteon index number
       
Dim
Flags As Byte
       
Dim
Command1 As Byte
       
Dim
Command2 As Byte
       
Dim
ms As Short         
' Position
of start of message ( = x_Start + 1)
       
Dim
MessageEnd As Short 
' Position of
expected end of message (start + length, - 1000 if it's looping) 
       
Dim
DataAvailable As Short
' how many bytes of data
available between x_Start
and X_LastWrite?
       
Dim
data(2) As Byte
       
Dim
Group As Byte
       
Dim
FromName As String
       
Dim
DataString As String
       
Dim
HasName As Boolean
       
If
x_Start = x_LastWrite Then
Exit Sub ' reached end of data, get out of sub
       
' x_Start =
the last byte that was read and processed here
       
' Each time
this sub is executed, one command will be processed (if enough data has
arrived)
       
' This sub
may be called while it is still running, under some circumstances (e.g.
if it
calls a slow macro)
       
' Find the
beginning of the next command (always starts with 0x02)
       
Do Until (x(x_Start + 1) = 2)
Or
(x_Start = x_LastWrite) Or
(x_Start + 1 =
x_LastWrite)
           
x_Start = x_Start + 1
           
If
x_Start > 1000 Then
x_Start = 1 ' Loop according
to the same looping rule as x_LastWrite
       
       
ms = x_Start + 1  ' ms = the actual 1st
byte of data (which must = 0x02), whereas x_Start is the byte before it
       
If
x(ms) <> 2 Then
Exit
Sub ' reached the end
of usable data, reset starting position, get out of sub
       
' How many
bytes of data are available to process? (not counting the leading 0x02
of each
message)
       
If
x_Start <= x_LastWrite Then
           
DataAvailable = x_LastWrite - ms
       
Else
           
DataAvailable = 1000 + x_LastWrite
- ms
       
End If
       
If
DataAvailable < 1 Then
Exit Sub ' not enough for a full message of any
type
       
' Interpret
the message and handle it
       
Select
Case x(ms + 1)
           
Case
96 ' 0x060 response to Get IM
Info
               
MessageEnd = ms + 8
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 8 Then
               
    x_Start
= MessageEnd
                   
'
Display message
                   
WriteEvent(Gray, "PLM
response to Get IM Info: PLM ID: ")
                   
PLM_Address = GetHex(x(ms +
2)) & "."
& GetHex(x(ms +
3)) & "."
& GetHex(x(ms +
4))
          
         WriteEvent(White,
PLM_Address)
                   
WriteEvent(Gray, "
Device Category: ")
                   
WriteEvent(White,
GetHex(x(ms + 5)))
                   
WriteEvent(Gray, "
Subcategory: ")
                   
WriteEvent(White, GetHex(x(ms
+ 6)))
                   
WriteEvent(Gray, "
Firmware: ")
                   
WriteEvent(White,
GetHex(x(ms + 7)))
                   
WriteEvent(Gray, "
ACK/NAK: ")
                   
WriteEvent(White,
GetHex(x(ms + 8)) & vbCrLf)
                
   ' Set the PLM as
the controller
                   
'
--> I use this to verify the PLM is connected, disable some menu
options,
enable others, etc
               
End
If
           
Case
80 ' 0x050 Insteon Standard
message received
               
' next
three bytes = address of device sending message
               
'
next three bytes = address of PLM
               
'
next byte = flags
               
'
next byte = command1   if
status was
requested, this = link delta (increments each time link database
changes)
               
'                       
if device level was
changed, this = command that was sent
               
'
next byte = command2   if
status was
requested, this = on level (00-FF)
               
'                       
if device level was
changed, this also = on level (00-FF)
               
MessageEnd = ms + 10
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 10 Then
                   
x_Start = MessageEnd
                
   FromAddress
= GetHex(x(ms + 2)) & "."
& GetHex(x(ms + 3)) & "." &
GetHex(x(ms + 4))
                   
ToAddress = GetHex(x(ms +
5)) & "."
& GetHex(x(ms +
6)) & "."
& GetHex(x(ms +
7))
                   
Flags = x(ms + 8)
                   
Command1 = x(ms + 9)
                   
Command2 = x(ms + 10)
                   
'
Check if FromAddress is in device database, if not add it (ToAddress
will
generally = PLM)
                   
If
InsteonNum(FromAddress) = 0 And
FromAddress
<> PLM_Address Then
                        AddInsteonDevice(FromAddress)
                       
SortInsteon()
                   
End
If
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
Insteon Received: From: ")
                 
      WriteEvent(White,
FromAddress)
                       
WriteEvent(White, " (" &
DeviceNameInsteon(FromAddress) & ")")
                       
WriteEvent(Gray, "
To: ")
                       
WriteEvent(White,
ToAddress)
                       
If
ToAddress = PLM_Address Then
                           
WriteEvent(White, " (PLM)")
                       
Else
                           
WriteEvent(White, " (" &
DeviceNameInsteon(ToAddress)
& ")")
                       
End If
                       
WriteEvent(Gray, "
Flags: ")
                       
WriteEvent(White,
GetHex(Flags))
                       
Select
Case Flags And 224
                           
Case
0 ' 000 Direct message
                               
WriteEvent(White, " (direct) ")
                           
Case
32 ' 001 ACK direct
message
                               
WriteEvent(White, " (ACK direct) ")
                           
Case
64 ' 010 Group cleanup
direct message
                               
WriteEvent(White, " (Group cleanup
direct) ")
                           
Case
96 ' 011 ACK group
cleanup direct message
                               
WriteEvent(White, " (ACK Group cleanup
direct) ")
                           
Case
128 ' 100 Broadcast
message
               
                WriteEvent(White,
" (Broadcast) ")
                           
Case
160 ' 101 NAK direct
message
                               
WriteEvent(Red,
" (NAK direct) ")
                           
Case
192 ' 110 Group
broadcast message
         
                      WriteEvent(White,
" (Group broadcast)
")
                           
Case
224 ' 111 NAK group
cleanup direct message
                               
WriteEvent(White, " (NAK Group cleanup
direct) ")
                       
End Select
                       
WriteEvent(Gray, "
Command1: ")
                       
WriteEvent(White,
GetHex(Command1) & "
(" &
CommandsInsteon(Command1) & ")")
                       
WriteEvent(Gray, "
Command2: ")
                       
WriteEvent(White, GetHex(Command2)
+ vbCrLf)
                   
End
If
                   
'
Update the status of the sending device
                   
IAddress =
InsteonNum(FromAddress)  ' already checked to make sure it was
in list
                   
FromName = Insteon(IAddress).Name
                   
If
FromName = ""
Then FromName =
Insteon(IAddress).Address
                   
If
(Flags And 160)
<> 160 Then
                       
' Not a NAK
response, could be an ACK or a new message coming in
                    
   ' Either way,
update the sending device
                       
Select
Case Command1
                           
Case
17, 18 ' On, Fast On
                               
Insteon(IAddress).Device_On = True
                               
If
(Flags And 64) =
64 Then
                                   
' Group message
(broadcast or cleanup)
                                   
Insteon(IAddress).Level = 100 
' the real level
is the preset for the link, but...
                               
Else
           
                        ' Direct message
                                   
Insteon(IAddress).Level = Command2 / 2.55 
' change to scale
of 0-100
                               
End If
                           
Case
19, 20 ' Off, Fast Off
             
                  Insteon(IAddress).Device_On
=
False
                               
Insteon(IAddress).Level = 0
                           
Case
21 ' Bright
                               
Insteon(IAddress).Device_On = True
                             
  If
Insteon(IAddress).Level > 100 Then
Insteon(IAddress).Level = 100
                               
Insteon(IAddress).Level = Insteon(IAddress).Level + 3
                           
Case
22 ' Dim
                               
Insteon(IAddress).Level = Insteon(IAddress).Level - 3
                               
If
Insteon(IAddress).Level < 0 Then
Insteon(IAddress).Level = 0
                               
If
Insteon(IAddress).Level = 0 Then
Insteon(IAddress).Device_On = False
                       
End Select
                       
' Check whether
this was a response to a Status Request
                       
If
(Flags And 224) =
32 Then
                           
' ACK Direct
message
                           
If
Insteon(IAddress).Checking = True
Then
                               
Insteon(IAddress).Level = Command2 / 2.55
                               
If
Insteon(IAddress).Level > 0 Then
                                   
Insteon(IAddress).Device_On = True
                               
Else
                                    Insteon(IAddress).Device_On
= False
                               
End If
                           
End If
                       
End If
                       
' --> At
this point I update a grid display, but you can do whatever
you want...
                   
End
If
                   
'
Now actually respond to events...
                   
If
Insteon(IAddress).Checking = True
Then
                       
' It was a Status
Request response, don't treat it as an event
                       
Insteon(IAddress).Checking = False
                       
Insteon(IAddress).LastCommand = 0
                       
Insteon(IAddress).LastFlags = Flags And
224
                       
Insteon(IAddress).LastTime = Now
             
          Insteon(IAddress).LastGroup
= 0
                   
Else
                       
' It wasn't a
Status Request, process it
                       
Select
Case Flags And 224
                           
Case
128 ' 100 Broadcast
message
            
                   '
Button-press linking, etc. Just display a message.
                               
' Message format:
FromAddress, DevCat, SubCat, Firmware,
Flags, Cmd1, Cmd2 (=Device Attributes)
                               
' Time stamp in
blue
                                WriteEvent(Blue,
VB6.Format(TimeOfDay) & " ")
                               
If
Command1 = 1 Then
                                   
WriteEvent(Green, FromName & "
broadcast 'Set Button Pressed'")
                           
    Else
                                   
WriteEvent(Green, FromName & "
broadcast command " & GetHex(Command1))
                               
End If
                               
Insteon(IAddress).LastCommand = Command1
                           
    Insteon(IAddress).LastFlags
= Flags And 224
                               
Insteon(IAddress).LastTime = Now
                               
Insteon(IAddress).LastGroup = 0
                           
Case
0, 64, 192 ' 000
Direct, 010 Group cleanup direct, 110 Group broadcast message
                               
' Message sent to
PLM by another device - trigger sounds,
macro, etc
                               
If
Flags And 64 Then
                                   
' Group message
               
                    If
Flags And 128 Then
                                       
' Group broadcast
- group number is third byte of ToAddress
                                       
Group =
x(ms + 7)
                                       
If
Command1 = Insteon(IAddress).LastCommand And
(Group = Insteon(IAddress).LastGroup) Then
                                           
' This is the
same command we last received from this
device
                                           
' Is this a
repeat? (Some devices, like the RemoteLinc,
seem to double their group broadcasts)
                                           
If
(Flags And 224) =
(Insteon(IAddress).LastFlags) Then
                                               
If
DateDiff(DateInterval.Second,
Insteon(IAddress).LastTime, Now) < 1 Then
                                                   
' Same command,
same flags, within the last
second....
                                                   
Exit Select ' So skip out of here without doing
anything else
                                                End If
                                           
End If
                                       
End If
                                   
Else
                                       
' Group cleanup
direct - group number is Command2
                                       
Group =
Command2
                                       
If
Command1 = Insteon(IAddress).LastCommand And
(Group = Insteon(IAddress).LastGroup) Then
                                           
' This is the
same command we last received from this
device
                                           
' Is this a Group
Cleanup Direct message we already got a
Group Broadcast for?
                                           
If
(Insteon(IAddress).LastFlags And
224) = 192 Then
                                               
' Last message
was, in fact, a Group Broadcast
                                               
If
DateDiff(DateInterval.Second,
Insteon(IAddress).LastTime, Now) < 3 Then
              
                                     ' Within the last 3 seconds....
                                                   
Exit Select ' So skip out of here without doing
anything else
                                               
End If
                 
                          End If
                                       
End If
                                   
End If
                               
Else
                                   
' Direct message
                                   
Group = 0
                               
End If
                               
Insteon(IAddress).LastCommand = Command1
                               
Insteon(IAddress).LastFlags = Flags And
224
                               
Insteon(IAddress).LastTime = Now
                               
Insteon(IAddress).LastGroup = Group
                               
' Time stamp in
blue
                               
WriteEvent(Blue, VB6.Format(TimeOfDay) & "
")
 
                               
' Write command
to event log
                               
If
Group > 0 Then
                                   
WriteEvent(Green, FromName & "
" & CommandsInsteon(Command1) & "
(Group " & VB6.Format(Group) & ")"
& vbCrLf)
                               
Else
               
                    WriteEvent(Green,
FromName
& " "
&
CommandsInsteon(Command1) & vbCrLf)
                               
End If
                               
' Handle incoming
event and play sounds
                               
' --> at
this point I play a WAV file and run any macro
associated with the device
                           
Case
32, 96 ' 001 ACK
direct message, 011 ACK group cleanup direct message
                               
' Command
received and acknowledged by another device - update
device status is already done (above).
                               
' Nothing left to
do here.
                               
Insteon(IAddress).LastCommand = Command1
                               
Insteon(IAddress).LastFlags = Flags And
224
                                Insteon(IAddress).LastTime
= Now
                               
Insteon(IAddress).LastGroup = 0
                           
Case
160, 224 ' 101 NAK
direct message, 111 NAK group cleanup direct message
                         
      ' Command
received by another device but failed - display message in log
                               
' Time stamp in
blue
                               
WriteEvent(Blue, VB6.Format(TimeOfDay) & "
")
                               
WriteEvent(Green,
DeviceNameInsteon(FromAddress) & " NAK to
command " & GetHex(Command1) & "
(" & CommandsInsteon(Command1) & ")")
                               
Insteon(IAddress).LastCommand = Command1
                               
Insteon(IAddress).LastFlags = Flags And
224
                               
Insteon(IAddress).LastTime = Now
                               
Insteon(IAddress).LastGroup = 0
                       
End Select
                   
End
If
               
End
If
           
Case
81 ' 0x051 Insteon Extended
message received - 23
byte message
               
MessageEnd = ms + 24
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 24 Then
                   
x_Start = MessageEnd
            
       FromAddress
= GetHex(x(ms + 2)) & "."
& GetHex(x(ms + 3)) & "." &
GetHex(x(ms + 4))
                   
ToAddress = GetHex(x(ms +
5)) & "."
& GetHex(x(ms +
6)) & "."
& GetHex(x(ms +
7))
                   
Flags = x(ms + 8)
                   
Command1 = x(ms + 9)
                   
Command2 = x(ms + 10)
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
Insteon Extended Received: From: ")
                       
WriteEvent(White,
FromAddress)
            
           WriteEvent(White,
" ("
&
DeviceNameInsteon(FromAddress) & ")")
                       
WriteEvent(Gray, "
To: ")
                       
WriteEvent(White,
ToAddress)
                       
If
ToAddress = PLM_Address Then
                      
     WriteEvent(White,
"
(PLM)")
                       
Else
                           
WriteEvent(White, " (" &
DeviceNameInsteon(ToAddress)
& ")")
                       
End If
                       
WriteEvent(Gray, "
Flags: ")
                    
   WriteEvent(White,
GetHex(Flags))
                       
Select
Case Flags And 224
                           
Case
0 ' 000 Direct message
                               
WriteEvent(White, " (direct) ")
                           
Case
32 ' 001 ACK direct
message
                               
WriteEvent(White, " (ACK direct) ")
                           
Case
64 ' 010 Group cleanup
direct message
                               
WriteEvent(White, " (Group cleanup
direct) ")
                           
Case
96 ' 011 ACK group
cleanup direct message
                               
WriteEvent(White, " (ACK Group cleanup
direct) ")
                           
Case
128 ' 100 Broadcast
message
                               
WriteEvent(White, " (Broadcast) ")
                           
Case
160 ' 101 NAK direct
message
                               
WriteEvent(Red,
" (NAK direct) ")
                           
Case
192 ' 110 Group
broadcast message
                               
WriteEvent(White, " (Group broadcast)
")
                           
Case
224 ' 111 NAK group
cleanup direct message
                               
WriteEvent(White, " (NAK Group cleanup
direct) ")
                       
End Select
                       
WriteEvent(Gray, "
Command1: ")
                       
WriteEvent(White,
GetHex(Command1) & "
(" &
CommandsInsteon(Command1) & ")")
                       
WriteEvent(Gray, "
Command2: ")
                       
WriteEvent(White,
GetHex(Command2))
                       
If
Command1 = 3 Then
                           
' Product Data
Response
                           
Select
Case Command2
                               
Case
0 ' Product Data
Response
                                   
WriteEvent(White, " Product Data
Response")
                                   
WriteEvent(Gray, "
Data: ")
                                   
For i
= 11 To 24
                                       
WriteEvent(White, GetHex(x(ms + i)) & "
")
                                   
Next
              
                     WriteEvent(White,
"--> Product
Key " & GetHex(x(ms
+ 12)) & GetHex(x(ms + 13)) & GetHex(x(ms + 14)))
                                   
WriteEvent(White, " DevCat: "
& GetHex(x(ms + 15)))
                                   
WriteEvent(White,
" SubCat: "
& GetHex(x(ms +
16)))
                                   
WriteEvent(White, " Firmware: "
& GetHex(x(ms + 17)))
                               
Case
1 ' FX Username
Response
                                   
WriteEvent(White, " FX Username
Response")
                                   
WriteEvent(Gray, "
D1-D8 FX Command
Username: ")
                                   
For i
= 11 To 18
                                       
WriteEvent(White, GetHex(x(ms + i)) & "
")
                 
                  Next
                                   
WriteEvent(Gray, "
D9-D14: ")
                                   
For i
= 19 To 24
                                       
WriteEvent(White, GetHex(x(ms + i)) & "
")
                              
     Next
                               
Case
2 ' Device Text String
                                   
WriteEvent(White, " Device Text String
Response")
                                   
WriteEvent(Gray, "
D1-D8 FX Command
Username: ")
              
                     DataString
= ""
                                   
For i
= 11 To 24
                                       
WriteEvent(White, GetHex(x(ms + i)) & "
")
                                   
Next
                                   
For i
= 11 To 24
                                       
If
x(ms + i) = 0 Then
Exit For
                                       
DataString = DataString + Chr(x(ms + i))
                                   
Next
                                   
WriteEvent(White, Quote & DataString &
Quote)
                               
Case
3 ' Set Device Text
String
                                   
WriteEvent(White, " Set Device Text
String")
                                   
WriteEvent(Gray, "
D1-D8 FX Command
Username: ")
                                   
DataString
= ""
                                   
For i
= 11 To 24
                                       
WriteEvent(White, GetHex(x(ms + i)) & "
")
                                   
Next
                      
             For
i = 11 To 24
                                       
If
x(ms + i) = 0 Then
Exit For
                                       
DataString = DataString + Chr(x(ms + i))
                                   
Next
                                
   WriteEvent(White,
Quote & DataString
& Quote)
                               
Case
4 ' Set ALL-Link
Command Alias
                                   
WriteEvent(White, " Set ALL-Link
Command Alias")
                                   
WriteEvent(Gray, "
Data: ")
                                   
For i
= 11 To 24
                                       
WriteEvent(White, GetHex(x(ms + i)) & "
")
                                   
Next
                               
Case
5 ' Set ALL-Link
Command Alias Extended Data
                                   
WriteEvent(White, " Set ALL-Link
Command Alias Extended Data")
                                   
WriteEvent(Gray, "
Data: ")
                                   
For i
= 11 To 24
                          
             WriteEvent(White,
GetHex(x(ms +
i)) & " ")
                                   
Next
                               
Case Else
                                   
WriteEvent(White, " (unrecognized
product data response)")
                     
              WriteEvent(Gray,
" Data: ")
                                   
For i
= 11 To 24
                                       
WriteEvent(White, GetHex(x(ms + i)) & "
")
                                   
Next
                           
End Select
                       
Else
                           
' Anything other
than a product data response
                           
WriteEvent(Gray, "
Data: ")
                           
For i
= 11 To 24
                               
WriteEvent(White, GetHex(x(ms + i)) & "
")
                           
Next
                       
End If
                       
WriteEvent(White,
vbCrLf)
                   
End
If
               
End
If
               
' I’m
not planning on actually doing anything with this data, just displayed
if
mnuShowPLC.Checked
           
Case
82 ' 0x052 X10 Received
               
'
next byte: raw X10   x(MsStart
+ 2)
               
'
next byte: x10 flag  x(MsStart
+ 3)
               
MessageEnd = ms + 3
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 3 Then
                   
x_Start = MessageEnd
                   
If
mnuShowPLC.Checked Then
WriteEvent(Gray, "PLM:
X10 Received: ")
                   
X10House = X10House_from_PLM(x(ms
+ 2) And 240)
                   
Select
Case x(ms + 3)
                       
Case
0 ' House + Device
                           
X10Code =
X10Device_from_PLM(x(ms + 2) And
15)
                           
If
mnuShowPLC.Checked Then
WriteEvent(White, Chr(65 + X10House) & (X10Code + 1) &
vbCrLf)
                           
PLM_LastX10Device =
X10Code ' Device Code 0-15
                       
Case
63, 128 ' 0x80 House + Command    63 =
0x3F - should be 0x80 but for some
reason I keep getting 0x3F instead
                           
X10Code = (x(ms +
2) And 15) + 1
                           
X10Address = Chr(65
+ X10House) & (PLM_LastX10Device + 1)
                           
If
mnuShowPLC.Checked Then
WriteEvent(White, Chr(65 + X10House) & "
" & Commands(X10Code) & vbCrLf)
                           
' Now actually
process the event
                           
' Does it have a
name?
                           
If
DeviceName(X10Address) = X10Address Then
HasName = False Else HasName = True
                           
' Time stamp in
blue
                           
WriteEvent(Blue,
VB6.Format(TimeOfDay) & " ")
                           
If
LoggedIn And
HasName Then
frmHack.WriteWebtrix(Blue,
VB6.Format(TimeOfDay) & " ")
                  
         ' Write
command to event log
                           
WriteEvent(Green,
DeviceName(X10Address) + "
" +
Commands(X10Code) + vbCrLf)
                           
' Handle incoming
event
                           
Select
Case X10Code
           
                    Case
3 ' On
                               
' --> at
this point I play a WAV file and run any macro
associated with the device
                               
Case
4 ' Off
                               
' --> at
this point I play a WAV file and run any macro
associated with the device
                               
Case
5 ' Dim
                               
' --> at
this point I play a WAV file and run any macro
associated with the device
                               
Case
6 ' Bright
                               
' --> at
this point I play a WAV file and run any macro
associated with the device
                           
End Select
                       
Case Else '
invalid data
                           
If
mnuShowPLC.Checked Then
WriteEvent(White, "Unrecognized
X10: "
& GetHex(x(ms + 2)) & " "
& GetHex(x(ms + 3)) & vbCrLf)
                   
End
Select
               
End
If
           
Case
98 ' 0x062 Send Insteon
standard OR extended message
               
' PLM
is just echoing the last command sent, discard this: 7 or 21 bytes
               
MessageEnd = ms + 8
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 8 Then
                   
If
(x(ms + 5) And
16) = 16 Then
                       
' Extended message
                       
MessageEnd = x_Start +
1 + 22
                       
If
MessageEnd > 1000 Then
MessageEnd = MessageEnd - 1000
                       
If
DataAvailable >= 22 Then
                
           x_Start
= MessageEnd
                           
If
mnuShowPLC.Checked Then
                               
WriteEvent(Gray, "PLM:
Sent Insteon
message (extended): ")
                               
For i
= 0 To 22
                             
      WriteEvent(White,
GetHex(x(ms + i)) &
" ")
                               
Next
                               
WriteEvent(White, vbCrLf)
                           
End If
                       
End If
                   
Else
                    
   ' Standard message
                       
x_Start = MessageEnd
                       
If
mnuShowPLC.Checked Then
                           
WriteEvent(Gray, "PLM:
Sent Insteon message (standard): ")
                           
For i
= 0 To 8
       
                        WriteEvent(White,
GetHex(x(ms + i)) & "
")
                           
Next
                           
WriteEvent(White,
vbCrLf)
                       
End If
                   
End
If
               
End
If
           
Case
99 ' 0x063 Sent X10
               
' PLM
is just echoing the command we last sent, discard: 3 bytes --- although
could
error check this for NAKs...
               
MessageEnd = ms + 4
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
                If
DataAvailable >= 4 Then
                   
x_Start = MessageEnd
                   
WriteEvent(Gray, "PLM:
X10 Sent: ")
                   
X10House =
X10House_from_PLM(x(ms + 2) And
240)
                   
Select
Case x(ms + 3)
       
                Case
0 ' House + Device
                           
X10Code =
X10Device_from_PLM(x(ms + 2) And
15)
                           
WriteEvent(White,
Chr(65 + X10House) & (X10Code + 1))
                       
Case
63, 128 ' 0x80 House + Command    63 =
0x3F - should be 0x80 but for some
reason I keep getting 0x3F instead
                           
X10Code = (x(ms +
2) And 15) + 1
                           
If
X10Code > -1 And
X10Code < 17 Then
                               
WriteEvent(White, Chr(65 + X10House) & "
" & Commands(X10Code))
                           
Else
                               
WriteEvent(White, Chr(65 + X10House) & "
unrecognized command " & GetHex(x(ms + 2) And 15))
                           
End If
                 
      Case Else ' invalid data
                           
WriteEvent(White, "Unrecognized X10: "
& GetHex(x(ms +
2)) & " "
& GetHex(x(ms +
3)))
                   
End
Select
                   
WriteEvent(Gray, "
ACK/NAK: ")
                   
Select
Case x(ms + 4)
                       
Case 6
                           
WriteEvent(White, "06 (sent)" +
vbCrLf)
                       
Case
21
                           
WriteEvent(White, "15 (failed)"
+ vbCrLf)
                       
Case Else
       
                    WriteEvent(White,
GetHex(x(ms + 4)) & "
(?)" +
vbCrLf)
                   
End
Select
               
End
If
           
Case
83 ' 0x053 ALL-Linking
complete - 8 bytes of data
               
MessageEnd = ms + 9
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 9 Then
                   
x_Start = MessageEnd
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
ALL-Linking Complete: 0x53 Link Code: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                       
Select
Case x(ms + 2)
                           
Case 0
                               
WriteEvent(White, " (responder)")
                           
Case 1
                               
WriteEvent(White, " (controller)")
                           
Case
244
                               
WriteEvent(White, " (deleted)")
                       
End Select
                       
WriteEvent(Gray, "
Group: ")
                       
WriteEvent(White,
GetHex(x(ms + 3)))
                       
WriteEvent(Gray, "
ID: ")
                       
FromAddress =
GetHex(x(ms + 4)) & "."
&
GetHex(x(ms + 5)) & "."
&
GetHex(x(ms + 6))
                       
WriteEvent(White,
FromAddress)
                       
WriteEvent(White, " (" &
DeviceNameInsteon(FromAddress) & ")")
                       
WriteEvent(Gray, "
DevCat: ")
                       
WriteEvent(White,
GetHex(x(ms + 7)))
                       
WriteEvent(Gray, "
SubCat: ")
                       
WriteEvent(White,
GetHex(x(ms + 8)))
                       
WriteEvent(Gray, "
Firmware: ")
                       
WriteEvent(White,
GetHex(x(ms + 9)))
                       
If
x(ms + 9) = 255 Then
WriteEvent(White, "
(all newer devices =
FF)")
                       
WriteEvent(White,
vbCrLf)
                   
End
If
               
End
If
           
Case
87 ' 0x057 ALL-Link record
response - 8 bytes of data
               
MessageEnd = ms + 9
              
 If MessageEnd
> 1000 Then
MessageEnd = MessageEnd - 1000
               
If
DataAvailable >= 9 Then
                   
x_Start = MessageEnd
                   
FromAddress = GetHex(x(ms +
4)) & "."
& GetHex(x(ms +
5)) & "."
& GetHex(x(ms +
6))
         
          ' Check if
FromAddress is in device database, if not add it
                   
If
InsteonNum(FromAddress) = 0 Then
                       
AddInsteonDevice(FromAddress)
                       
SortInsteon()
                   
End
If
          
         If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
ALL-Link Record response: 0x57 Flags: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                       
WriteEvent(Gray, "
Group: ")
                 
      WriteEvent(White,
GetHex(x(ms + 3)))
                       
WriteEvent(Gray, "
Address: ")
                       
WriteEvent(White,
FromAddress)
                       
WriteEvent(White, " (" &
DeviceNameInsteon(FromAddress) & ")")
               
        WriteEvent(Gray,
" Data: ")
                       
WriteEvent(White,
GetHex(x(ms + 7)) & "
" &
GetHex(x(ms + 8)) & "
" &
GetHex(x(ms + 9)) & vbCrLf)
                   
End
If
                   
'
--> I assume this happened because I requested the data, and
want the rest
of it. So now
                   
'
Send 02 6A to get next record (e.g. continue reading link database from
PLM)
                   
data(0) = 2  ' all commands
start with 2
                   
data(1) = 106 '
0x06A = Get Next ALL-Link Record
                   
SerialPLM.Write(data, 0, 2)
               
End
If
           
Case
85 ' 0x055 User reset the PLM
- 0 bytes of data, not
possible for this to be a partial message
               
MessageEnd = ms + 1
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
x_Start = MessageEnd
               
WriteEvent(Gray, "PLM:
User Reset 0x55" + vbCrLf)
           
Case
86 ' 0x056 ALL-Link cleanup
failure report - 5 bytes
of data
               
MessageEnd = ms + 6
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 6 Then
                   
x_Start = MessageEnd
                   
ToAddress = GetHex(x(ms +
4)) & "."
& GetHex(x(ms +
5)) & "."
& GetHex(x(ms +
6))
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
ALL-Link (Group Broadcast) Cleanup Failure
Report 0x56 Data: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                       
WriteEvent(Gray, "
Group: ")
                       
WriteEvent(White,
GetHex(x(ms + 3)))
                       
WriteEvent(Gray, "
Address: ")
                       
WriteEvent(White,
ToAddress & "
(" &
DeviceNameInsteon(ToAddress) & ")"
& vbCrLf)
                    End
If
               
End
If
           
Case
97 ' 0x061 Sent ALL-Link
(Group Broadcast) command -
4 bytes
               
MessageEnd = ms + 5
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 5 Then
                   
x_Start = MessageEnd
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
Sent Group Broadcast: 0x61 Group: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                        WriteEvent(Gray,
" Command1: ")
                       
WriteEvent(White,
GetHex(x(ms + 3)))
                       
WriteEvent(Gray, "
Command2 (Group): ")
                       
WriteEvent(White,
GetHex(x(ms + 4)))
                 
      WriteEvent(Gray,
"
ACK/NAK: ")
                       
Select
Case x(ms + 5)
                           
Case 6
                               
WriteEvent(White, "06 (sent)"
+ vbCrLf)
                           
Case
21
                             
  WriteEvent(White,
"15
(failed)" + vbCrLf)
                           
Case Else
                               
WriteEvent(White, GetHex(x(ms + 5)) & "
(?)" + vbCrLf)
                       
End Select
                   
End
If
               
End
If
            Case
102 ' 0x066 Set Host Device
Category - 4 bytes
               
MessageEnd = ms + 5
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 5 Then
                   
x_Start = MessageEnd
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
Set Host Device Category: 0x66 DevCat: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                       
WriteEvent(Gray, "
SubCat: ")
                        WriteEvent(White,
GetHex(x(ms
+ 3)))
                       
WriteEvent(Gray, "
Firmware: ")
                       
WriteEvent(White,
GetHex(x(ms + 4)))
                       
If
x(ms + 4) = 255 Then
WriteEvent(White, "
(all newer devices =
FF)")
                       
WriteEvent(Gray, "
ACK/NAK: ")
                       
Select
Case x(ms + 5)
                           
Case 6
                               
WriteEvent(White, "06 (executed
correctly)" + vbCrLf)
                      
     Case 21
                               
WriteEvent(White, "15 (failed)"
+ vbCrLf)
                           
Case Else
                               
WriteEvent(White, GetHex(x(ms + 5)) & "
(?)" + vbCrLf)
                       
End Select
        
           End If
               
End
If
           
Case
115 ' 0x073 Get IM
Configuration - 4 bytes
               
MessageEnd = ms + 5
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 5 Then
                    x_Start
= MessageEnd
                   
WriteEvent(Gray, "PLM:
Get IM Configuration: 0x73 Flags: ")
                   
WriteEvent(White,
GetHex(x(ms + 2)))
                   
If
x(ms + 2) And 128
Then
WriteEvent(White, "
(no button linking)")
                   
If
x(ms + 2) And 64 Then
WriteEvent(White, "
(monitor mode)")
                   
If
x(ms + 2) And 32 Then
WriteEvent(White, "
(manual LED control)")
                   
If
x(ms + 2) And 16 Then
WriteEvent(White, "
(disable deadman comm
feature)")
                   
If
x(ms + 2) And
(128 + 64 + 32 + 16) Then
WriteEvent(White, "
(default)")
                   
WriteEvent(Gray, "
Data: ")
                   
WriteEvent(White,
GetHex(x(ms + 3)) & "
" &
GetHex(x(ms + 4)))
          
         WriteEvent(Gray,
" ACK: ")
                   
WriteEvent(White,
GetHex(x(ms + 5)) + vbCrLf)
               
End
If
           
Case
100 ' 0x064 Start
ALL-Linking, echoed - 3 bytes
               
MessageEnd = ms + 4
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 4 Then
                   
x_Start = MessageEnd
                   
WriteEvent(Gray, "PLM:
Start ALL-Linking 0x64 Code: ")
                   
WriteEvent(White,
GetHex(x(ms + 2)))
                   
Select
Case x(ms + 2)
                       
Case 0
                           
WriteEvent(White, " (PLM is responder)")
                       
Case 1
                           
WriteEvent(White, " (PLM is controller)")
         
              Case
3
                           
WriteEvent(White, " (initiator is controller)")
                       
Case
244
                           
WriteEvent(White, " (deleted)")
                   
End
Select
                   
WriteEvent(Gray, "
Group: ")
                   
WriteEvent(White,
GetHex(x(ms + 3)))
                   
WriteEvent(Gray, "
ACK/NAK: ")
                   
Select
Case x(ms + 4)
                       
Case 6
                           
WriteEvent(White, "06 (executed correctly)"
+ vbCrLf)
                       
Case
21
                           
WriteEvent(White, "15 (failed)"
+ vbCrLf)
                       
Case Else
                           
WriteEvent(White,
GetHex(x(ms + 4)) & "
(?)" +
vbCrLf)
               
    End Select
               
End
If
           
Case
113 ' 0x071 Set Insteon ACK
message two bytes - 3
bytes
               
MessageEnd = ms + 4
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 4 Then
                   
x_Start = MessageEnd
                   
WriteEvent(Gray, "PLM:
Set Insteon ACK message 0x71 ")
                   
For
i = 2 To 4
                       
WriteEvent(White,
GetHex(x(ms + i)) & "
")
                   
Next
                    WriteEvent(White,
vbCrLf)
               
End
If
           
Case
104, 107, 112 ' 0x068 Set
Insteon ACK message byte,
0x06B Set IM Configuration, 0x070 Set Insteon NAK message byte
               
' 2
bytes
               
MessageEnd = ms + 3
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 3 Then
                   
x_Start = MessageEnd
                   
WriteEvent(Gray, "PLM:
")
                   
For
i = 0 To 3
                
       WriteEvent(White,
GetHex(x(ms + i))
& " ")
                   
Next
                   
WriteEvent(White, vbCrLf)
               
End
If
           
Case
88 ' 0x058 ALL-Link cleanup
status report - 1 byte
               
MessageEnd = ms + 2
       
        If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 2 Then
                   
x_Start = MessageEnd
                   
WriteEvent(Gray, "PLM:
ALL-Link (Group Broadcast) Cleanup Status
Report 0x58 ACK/NAK: ")
                   
Select
Case x(ms + 2)
                       
Case 6
                           
WriteEvent(White, "06 (completed)"
+ vbCrLf)
                       
Case
21
                           
WriteEvent(White, "15 (interrupted)"
+ vbCrLf)
                       
Case
Else
                           
WriteEvent(White,
GetHex(x(ms + 2)) & "
(?)" +
vbCrLf)
                   
End
Select
               
End
If
           
Case
84, 103, 108, 109, 110, 114
               
'
0x054 Button (on PLM) event, 0x067 Reset the IM, 0x06C Get ALL-Link
record for
sender, 0x06D LED On, 0x06E LED Off, 0x072 RF Sleep
               
'
discard: 1 byte
               
MessageEnd = ms + 2
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
                If
DataAvailable >= 2 Then
                   
x_Start = MessageEnd
                   
WriteEvent(Gray, "PLM:
")
                   
For
i = 0 To 2
                       
WriteEvent(White,
GetHex(x(ms + i)) & "
")
                   
Next
                    WriteEvent(White,
vbCrLf)
               
End
If
           
Case
101 ' 0x065 Cancel
ALL-Linking - 1 byte
               
MessageEnd = ms + 2
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 2 Then
                   
x_Start = MessageEnd
                   
WriteEvent(Gray, "PLM:
Cancel ALL-Linking 0x65 ACK/NAK: ")
                   
Select
Case x(ms + 2)
                       
Case 6
                           
WriteEvent(White, "06 (success)"
+ vbCrLf)
                       
Case
21
                           
WriteEvent(White, "15 (failed)"
+ vbCrLf)
                       
Case Else
                           
WriteEvent(White,
GetHex(x(ms + 2)) & "
(?)" +
vbCrLf)
          
         End Select
               
End
If
           
Case
105 ' 0x069 Get First
ALL-Link record
               
MessageEnd = ms + 2
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 2 Then
                    x_Start
= MessageEnd
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
0x69 Get First ALL-Link record: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                       
Select
Case x(ms + 2)
                           
Case 6
                               
WriteEvent(White, " (ACK)")
                           
Case
21
                               
WriteEvent(White, " (NAK - no links in
database)")
                       
End Select
                       
WriteEvent(White,
vbCrLf)
                   
End
If
               
End
If
           
Case
106 ' 0x06A Get Next ALL-Link
record
               
MessageEnd = ms + 2
               
If
MessageEnd > 1000 Then
MessageEnd = MessageEnd
- 1000
               
If
DataAvailable >= 2 Then
                   
x_Start = MessageEnd
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
0x6A Get Next ALL-Link record: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                       
Select
Case x(ms + 2)
                           
Case 6
                               
WriteEvent(White, " (ACK)")
                           
Case
21
                               
WriteEvent(White,
" (NAK - no more
links in database)")
                       
End Select
                       
WriteEvent(White,
vbCrLf)
                   
End
If
               
End
If
           
Case
111 ' 0x06F Manage ALL-Link
record - 10 bytes
               
MessageEnd = ms + 11
               
If
MessageEnd > 1000 Then
MessageEnd =
MessageEnd - 1000
               
If
DataAvailable >= 11 Then
                   
x_Start = MessageEnd
                   
ToAddress = GetHex(x(ms +
5)) & "."
& GetHex(x(ms +
6)) & "."
& GetHex(x(ms +
7))
                   
If
mnuShowPLC.Checked Then
                       
WriteEvent(Gray, "PLM:
Manage ALL-Link Record 0x6F: Code: ")
                       
WriteEvent(White,
GetHex(x(ms + 2)))
                       
Select
Case x(ms + 2)
                           
Case
0 ' 0x00
                               
WriteEvent(White, " (Check for
record)")
                           
Case
1 ' 0x01
                               
WriteEvent(White, " (Next record
for...)")
                
           Case
32 ' 0x20
                               
WriteEvent(White, " (Update or
add)")
                           
Case
64 ' 0x40
                               
WriteEvent(White, " (Update or add as
controller)")
                           
Case
65 ' 0x41
                               
WriteEvent(White, " (Update or add as
responder)")
                           
Case
128 ' 0x80
                               
WriteEvent(White, " (Delete)")
                           
Case Else ' ?
             
                  WriteEvent(White,
" (?)")
                       
End Select
                       
WriteEvent(Gray, "
Link Flags: ")
                       
WriteEvent(White,
GetHex(x(ms + 3)))
                       
WriteEvent(Gray, "
Group: ")
                        WriteEvent(White,
GetHex(x(ms + 4)))
                       
WriteEvent(Gray, "
Address: ")
                       
WriteEvent(White,
ToAddress & "
(" &
DeviceNameInsteon(ToAddress) & ")")
                       
WriteEvent(Gray, "
Link Data: ")
                       
WriteEvent(White,
GetHex(x(ms + 8)) & "
" &
GetHex(x(ms + 9)) & "
" &
GetHex(x(ms + 10)))
                       
WriteEvent(Gray, "
ACK/NAK: ")
                       
Select
Case x(ms + 11)
                           
Case 6
                               
WriteEvent(White, "06 (executed
correctly)" + vbCrLf)
                           
Case
21
                               
WriteEvent(White, "15 (failed)"
+ vbCrLf)
                           
Case Else
                 
              WriteEvent(White,
GetHex(x(ms +
11)) & "
(?)" + vbCrLf)
                       
End Select
                   
End
If
               
End
If
           
Case
Else
               
' in
principle this shouldn't happen... unless there are undocumented PLM
messages
(probably!)
               
x_Start = x_Start + 1 
' just skip over
this and hope to hit a real command next time through the loop
               
If
x_Start > 1000 Then
x_Start = x_Start - 1000
               
WriteEvent(Gray, "PLM:
Unrecognized command received: ")
               
Debug.WriteLine("Unrecognized
command received " &
GetHex(x(ms)) & "
" &
GetHex(x(ms + 1)) & "
" &
GetHex(x(ms + 2)))
               
For
i = 0 To
DataAvailable
                   
WriteEvent(White, GetHex(x(ms
+ DataAvailable)))
               
Next
       
End Select
       
Debug.WriteLine("PLM
finished: ms = " & ms & " MessageEnd = "
& MessageEnd & " X_Start = "
& x_Start)
       
Exit Sub
    End Sub
   Public Sub WriteEvent(ByRef
Color As Integer,
ByRef
NewText As String)
       
Dim
last As Short
       
' WriteEvent(Color, Text) prints Text to the rtbEvent
box, in Color
       
' --> Obviously
this will only work if you have a rich text box named rtbEvent.
       
' Colors:
       
'  
Blue: time
        '  
Green: events
(macros)
       
'  
Yellow: commands sent
       
'  
Red: errors (also debug info: gives info
about Play and If/Then/Else/Endif
macro commands)
       
last = Len(rtbEvent.Text)
       
rtbEvent.SelectionStart
= last
       
rtbEvent.SelectedText
= NewText
       
rtbEvent.SelectionStart
= last
       
rtbEvent.SelectionLength
= Len(NewText)
       
rtbEvent.SelectionColor
= System.Drawing.ColorTranslator.FromOle(Color)
       
rtbEvent.SelectionStart
= Len(rtbEvent.Text)
       
rtbEvent.ScrollToCaret()
    End Sub
    Public Function InsteonNum(ByVal
Address As String)
As Short
       
' return the array
index for this insteon
device based on the address
       
' or 0 if address
is not found
       
Dim i As
Short
       
Address = UCase(Address)
       
i = 1
       
Do Until UCase(Insteon(i).Address)
= Address Or i >= NumInsteon
           
i = i + 1
       
       
If UCase(Insteon(i).Address) = Address Then
           
InsteonNum
= i
       
Else
           
InsteonNum
= 0
       
End If
    End Function
    Public Function X10House_from_PLM(ByVal Index As Byte) As Short
       
Dim i As
Short
       
' Given the MSB
from the PLM, return the House (0-15). If
not found, return
-1.
       
i = 1
       
Do Until PLM_X10_House(i)
= Index Or i = 16
           
i = i + 1
       
       
If
PLM_X10_House(i) = Index Then
           
X10House_from_PLM = i
- 1
       
Else
           
X10House_from_PLM = -1
       
End If
    End Function
    Public Function X10Device_from_PLM(ByVal Index As Byte) As Short
       
Dim i As
Short
       
' Given the LSB
from the PLM, return the Device (0-15). (Also works for commands.) If not found, return -1.
       
i = 1
       
Do Until PLM_X10_Device(i)
= Index Or i = 16
           
i = i + 1
       
       
If
PLM_X10_Device(i) = Index Then
           
X10Device_from_PLM = i
- 1
       
Else
           
X10Device_from_PLM = -1
       
End If
    End Function