G4 Alarm Keypad

rjandsam

Member
Hi, I would like to know if the picaxe is capable of 9 bit serial and if so could someone help or advise me on how to achieve this.
I have a G4 panel and keypad and the ability to logic analyse the data should it be required.
this is a link to a site where I have found the information, I have hooked the comms up to a ttl serial port at 1200 baud and I receive all of the data fine but I cannot send anything to the panel as it requires 9 bit data.

Thank you in advance

Rich
 

hippy

Technical Support
Staff member
I recall it is possible to send 9-bit data with HSEROUT. The trick is to configure with HSERSETUP for 1200 baud and appropriate polarity.

Then, before the HSEROUT, set the "TX9" bit in the TXSTA register to enable 9-bit, and set "TX9D" to the level that ninth bit should be. Untested, choose one or the other TXSTA definitions -
Code:
Symbol TXSTA      = $7E  ; $19E for M2
Symbol TXSTA      = $AC  ; $FAC for X2
Symbol TXSTA_TX9  = bit6
Symbol TXSTA_TX9D = bit0

HSerSetup B1200_4, %000 ; _8 for X2
Do
  PeekSfr TXSTA, b0
  TXSTA_TX9  = 1        ; Enable 9-bit
  TXSTA_TX9D = 1        ; Set 9th bit value
  PokeSfr TXSTA, b0
  HSerOut 0, ( "X" )
  Pause 1000
Loop
I cannot recall if one needs to explicitly clear the "TX9" bit to get back to 8-bit or if the firmware automatically clears that after each send. I recall it might. If it does auto-clear you would have to send each 9-bit byte separately, one per HSEROUT.

An easy way is to send each byte separately anyway, create macros for sending bytes as 8-bit or 9-bit. It's more code but the main program will be more readable. Again untested ...
Code:
Symbol TXSTA      = $7E  ; $19E for M2
Symbol TXSTA      = $AC  ; $FAC for X2
Symbol TXSTA_TX9  = bit6
Symbol TXSTA_TX9D = bit0

#Macro SendXBit( byteValue, ninthBitUsed, ninthBit )
  PeekSfr TXSTA, b0
  TXSTA_TX9  = ninthBitUsed
  TXSTA_TX9D = ninthBit
  PokeSfr TXSTA, b0
  HSerOut 0, ( byteValue )
  Pause 12                                   ; <-- See notes below
#EndMacro

#Macro Send9Bit( byteValue, ninthBit )
  SendXBit( byteValue, 1, ninthBit )
#EndMacro

#Macro Send8Bit( byteValue )
  SendXBit( byteValue, 0, 0 )
#EndMacro

HSerSetup B1200_4, %000 ; _8 for X2
Do
  Send9Bit( "K", 1 )
  Send8Bit( 123    )
  Send8Bit( 0      )
  Pause 1000
Loop
If HSEROUT isn't putting out 9-bit data, is clearing the "TX9" bit, then one can POKESFR directly to the transmit register, check that it's safe to send.

Actually that might be a good idea anyway as there is a possibility the above may alter an 8-bit transmission to be a 9-bit transmission and vice versa if it executes before the last byte has been fully sent -- Putting a "PAUSE 12" after each HSEROUT should prevent that.
 
Last edited:

rjandsam

Member
Hi Hippy,

Thank you for the reply, I will set a rig up tomorrow and let you know the results.

this should be a great starting point, the protocol itself is un encrypted and very basic as it is a hardwired standalone system so this helps me greatly.

The aim is to get my alarm panel to be more modern by creating a touch interface keypad to deal with the front end, then when i have more time i will be able to pass this information on through the picaxe into my network and finally to my MQTT server..

thanks

Rich
 

rjandsam

Member
Hi Hippy,
just tried you code and the result on the analyser looks good needs a little tweak so should be able to test on the panel later.
Code:
Symbol TXSTA      = $7E  ; $19E for M2
'Symbol TXSTA      = $AC  ; $FAC for X2
Symbol TX9  = bit6
Symbol TX9D = bit0

HSerSetup B1200_8, %000 ; _8 for X2
PeekSfr TXSTA, b0
TX9  = 1
PokeSfr TXSTA, b0

Do
    PeekSfr TXSTA, b0
    TX9D = 1
    PokeSfr TXSTA, b0
    HSerOut 0, ( "K" )
    pause 16
    PeekSfr TXSTA, b0
   let TX9D = 0
    PokeSfr TXSTA, b0
    HSerOut 0, ( "1",$7c)
   pause 5000
Loop
1566293610114.png
 
Last edited:

hippy

Technical Support
Staff member
Excellent news. It wasn't clear to me from reading the link if only the first byte is 9-bit so there might be some tweaking required.

I note you have selected the SFR for an M2 but used B1200_8 which would require a SETFREQ to have 8MHz operation on an M2. The bit times on your image appear to be about 1ms which would be in the correct ballpark for 1200 so I'm a bit confused there.
 

hippy

Technical Support
Staff member
Brilliant. So that means you can have a PICAXE being controlled by the keypad panel, acting as an alarm unit, or use a PICAXE as the keypad panel.

Of course the PICAXE controlled by the keypad panel doesn't need to be an alarm unit, could be a calculator, music player or anything. The panel can even be used as a simple serial display.

That made me wonder if other units use the same protocol and it seems some may. In my search I also came across this which is a bit more detailed than the original link -


That page better describes the Zone LED byte, and also describes the keypad panel hardware output pins. I would guess the SOS bit maps to PA (Panic) output, and the other four outputs map to the unidentified Zone LED bits.

So it might be worth trying various Zone LED settings to see if you can control the keypad panel output pins.

If that does work (and even if not) it would seem that a keypad panel would know about the complete state of the system so one could attach a PICAXE or similar, to the serial bus, as an additional monitoring only keypad panel, receive the K status, flash lights send SMS messages or emails when the alarm triggers.
 

hippy

Technical Support
Staff member
A belated thought, given it is 1200 baud and that is relatively slow; the 9-bit serial could probably be entirely bit-banged if one wanted to use some other pin, wanted to use HSEROUT for something else.
 

rjandsam

Member
If only I was at your level, I would fully understand what you where talking about and possibly implement it :ROFLMAO:.
Thank you for the help so far i am now going to try and send keypad codes to the main panel and use the very useful information you linked above to help reduce the amount of tinkering needed.

Rich.
 

hippy

Technical Support
Staff member
Here's an example of bit-banged code. Untested and needs some tweaking described, below -
Code:
#Picaxe 14M2
#No_Data

Symbol TX     = B.0
Symbol TX_PIN = outpinB.0

Goto PowerOnReset

SendByte:
  bPtr     = 100
  @bPtrInc = 0    ; 100 - Start bit
  @bPtrInc = bit0 ; 101 - Data bit 0 - 1st bit
  @bPtrInc = bit1 ; 102 - Data bit 1
  @bPtrInc = bit2 ; 103 - Data bit 2
  @bPtrInc = bit3 ; 104 - Data bit 3
  @bPtrInc = bit4 ; 105 - Data bit 4
  @bPtrInc = bit5 ; 106 - Data bit 5
  @bPtrInc = bit6 ; 107 - Data bit 6
  @bPtrInc = bit7 ; 108 - Data bit 7
  @bPtrInc = bit9 ; 109 - Data bit 8 - 9th bit
  @bPtrInc = 1    ; 110 - Stop bit
  For bPtr = 100 To 110
    TX_PIN = @bPtr
    PauseUs 83
  Next
  Return

PowerOnReset:
  High TX
  
MainLoop:
  Do
    b0 = "X" : bit9 = 1 : Gosub SendByte
    Pause 100
  Loop
This fills RAM locations with the 9 bits one wishes to send, including start and stop bits, then churns those bits out one at a time. The "PAUSEUS 83" (83x10us=830us) will likely need tweaking to show the correct 1200 baud bit-time on the logic analyser.

The SendByte routine is at the start of code, with a jump around it to the PowerOnReset, so that any changes later in the code do not affect the timing of the SendByte routine once the PAUSEUS has been tweaked.

One can get better accuracy on the bit timing by running at 8MHz or faster, each PAUSEUS unit falls to 5us at 8MHz etc.

Added : Note that "bit9" is used as the ninth bit of data, which is actually bit 8 in the serial datastream so that's a little confusing. Which is why the code slightly changed from the original !
 
Last edited:

AllyCat

Senior Member
Hi,
For bPtr = 100 To 110
TX_PIN = @bPtr
PauseUs 83
Next
Hmm, You almost had me convinced, until I double-checked the maths. 1200 baud is indeed 833 us/bit, but I think few execution times might have gone adrift :

From my spreadsheet, I "guess" that the FOR .. NEXT loop executes in about 1,600 PIC instruction cycles (per bit), the TX_PIN= in 400 and the additional "overhead" on PAUSEUS is just under 700, making a grand total of about 3,500 instruction cycles, or 3.5 ms @ 4 MHz. My estimate is that at SETFREQ m16, then around a PAUSEUS 65 might do it, give or take 20.

For m4, a block of linear code might be possible, perhaps (eleven) TX_PIN=s interleaved with a carefully selected "NoOP" delay, such as PAUSE 0, b0 = b0 or a HIGH/LOW/TOGGLE to an unused/test pin, combined with a trim of CALIBFREQ (+/- 31).

Cheers, Alan.
 

hippy

Technical Support
Staff member
You almost had me convinced, until I double-checked the maths
I did say it would have to be tweaked :)

You're right it's too slow at 4MHz, at least on an 18M2 I had to hand. With a PAUSEUS 83 it's 3460us per bit, 2060us without. Well over.

Straight in at 32MHz, feeling a need for speed, without PAUSEUS it's 260us, with a PAUSEUS 400 near bang-on at 840us.

Back to 16MHz, and 510us without a PAUSEUS, about 840us with a PAUSEUS 75.

So your estimates were pretty good.
 

rjandsam

Member
Hi Hippy, Allycat,

thank you for the lesson in bit banging, it works a treat I just had to try it.

Thank you.


23106
Code:
#picaxe 14m2
setfreq m16

Symbol TX     = B.0
Symbol TX_PIN = outpinB.0
Goto PowerOnReset

SendByte:
  bPtr     = 100
  @bPtrInc = 0    ; 100 - Start bit
  @bPtrInc = bit0 ; 101 - Data bit 0 - 1st bit
  @bPtrInc = bit1 ; 102 - Data bit 1
  @bPtrInc = bit2 ; 103 - Data bit 2
  @bPtrInc = bit3 ; 104 - Data bit 3
  @bPtrInc = bit4 ; 105 - Data bit 4
  @bPtrInc = bit5 ; 106 - Data bit 5
  @bPtrInc = bit6 ; 107 - Data bit 6
  @bPtrInc = bit7 ; 108 - Data bit 7
  @bPtrInc = bit9 ; 109 - Data bit 8 - 9th bit
  @bPtrInc = 1    ; 110 - Stop bit
  For bPtr = 100 To 110
    TX_PIN = @bPtr
    PauseUs 65
  Next
  Return

PowerOnReset:
  High TX
 
MainLoop:
  Do
    b0 = "K" : bit9 = 1 : Gosub SendByte   
       b0 = "1" : bit9 = 0 : Gosub SendByte
         b0 = $7c  : Gosub SendByte
     Loop
 

rjandsam

Member
Hi,
I have just linked he keypad upto the alarm along with my picaxe and test code and the picaxe can spoof the keypad data no problem so this is a great result and a huge step forward for my modern panel.
It seems that the main panel controls everything including the messages sent to the keypad these can be read easily at 1200 baud into my serial software the problem I now face is that these messages come in at various different times with varying lengths and the only way to determine it is destined for the LCD keypad is that the message starts with "L", is there a way to receive different lengths of messages into a buffer and then play them back out at a higher baud rate to my other LCD screen?

here is an example few messages that I received at T1200 into my PC.
LEnter your Code
4C 11 0C 45 6E 74 65 72 20 79 6F 75 72 20 43 6F 64 65



Code:
K0{LEnter your Code
ûL*wK1|L*wK2}L*wK3~L*wL   12345678  TP
  Â00000000  0F†P
]P    YP]LUser Restore
Press [X]YP    YP
]PYL   12345678  TP
  Â00000000  0F†P
]P    YP
]LUser Restore
Press [X]YPYP
]PYL   12345678  TP
  Â00000000  0F†P
]P    YP
]LUser Restore
Press [X]YP    YPPYL   12345678  TP
  Â00000000  0F†PP    YP
]LUser Restore
Press [X]YPYK<‡L Restored By
UserwLzL* SYSTEM UNSET *‘LzL* SYSTEM UNSET *
4B 30 7B 4C 11 0C 45 6E 74 65 72 20 79 6F 75 72 20 43 6F 64 65 0A FB 4C 01 2A 77 4B 31 7C 4C 01 2A 77 4B 32 7D 4C 01 2A 77 4B 33 7E 4C 01 2A 77 4C 20 0C 20 20 31 32 33 34 35 36 37 38 20 20 54 50 0A 20 20 04 C2 30 30 30 30 30 30 30 30 20 20 30 46 86 50 00 0D 5D 50 00 09 59 50 00 0D 5D 4C 17 0C 55 73 65 72 20 52 65 73 74 6F 72 65 0A 50 72 65 73 73 20 5B 58 5D 59 50 00 09 59 50 00 0D 5D 50 00 09 59 4C 20 0C 20 20 31 32 33 34 35 36 37 38 20 20 54 50 0A 20 20 04 C2 30 30 30 30 30 30 30 30 20 20 30 46 86 50 00 0D 5D 50 00 09 59 50 00 0D 5D 4C 17 0C 55 73 65 72 20 52 65 73 74 6F 72 65 0A 50 72 65 73 73 20 5B 58 5D 59 50 00 09 59 50 00 0D 5D 50 00 09 59 4C 20 0C 20 20 31 32 33 34 35 36 37 38 20 20 54 50 0A 20 20 04 C2 30 30 30 30 30 30 30 30 20 20 30 46 86 50 00 0D 5D 50 00 09 59 50 00 0D 5D 4C 17 0C 55 73 65 72 20 52 65 73 74 6F 72 65 0A 50 72 65 73 73 20 5B 58 5D 59 50 00 09 59 50 00 0D 5D 50 00 09 59 4C 20 0C 20 20 31 32 33 34 35 36 37 38 20 20 54 50 0A 20 20 04 C2 30 30 30 30 30 30 30 30 20 20 30 46 86 50 00 0D 5D 50 00 09 59 50 00 0D 5D 4C 17 0C 55 73 65 72 20 52 65 73 74 6F 72 65 0A 50 72 65 73 73 20 5B 58 5D 59 50 00 09 59 4B 3C 87 4C 13 0C 20 52 65 73 74 6F 72 65 64 20 42 79 0A 20 55 73 65 72 77 4C 03 16 05 10 7A 4C 11 0C 2A 20 53 59 53 54 45 4D 20 55 4E 53 45 54 20 2A 91 4C 03 16 05 10 7A 4C 11 0C 2A 20 53 59 53 54 45 4D 20 55 4E 53 45 54 20 2A 91
Thanks
Rich
 

hippy

Technical Support
Staff member
I optimised the SendByte routine to put the RAM buffer at the top of RAM so, having sent the last bit, the bPtr will have incremented to 0. This allows the FOR-NEXT to be replaced by a faster DO-LOOP. Setting "bPtr = -11" allows the code to work no matter how many bytes of RAM there actually are.
Code:
SendByte:
  bPtr     = -11
  @bPtrInc = 0    ; -11 $F5 - Start bit
  @bPtrInc = bit0 ; -10 $F6 - Data bit 0 - 1st bit
  @bPtrInc = bit1 ; -9  $F7 - Data bit 1
  @bPtrInc = bit2 ; -8  $F8 - Data bit 2
  @bPtrInc = bit3 ; -7  $F9 - Data bit 3
  @bPtrInc = bit4 ; -6  $FA - Data bit 4
  @bPtrInc = bit5 ; -5  $FB - Data bit 5
  @bPtrInc = bit6 ; -4  $FC - Data bit 6
  @bPtrInc = bit7 ; -3  $FD - Data bit 7
  @bPtrInc = bit9 ; -2  $FE - Data bit 8 - 9th bit
  @bPtrInc = 1    ; -1  $FF - Stop bit
  bPtr     = -11
  Do
    TX_PIN = @bPtrInc
    PauseUs ?
  Loop Until bPtr = 0
  Return
Without the PAUSEUS on an 18M2 pin C.0, a rather serendipitous result ...
Code:
M32   208us   4807.7   4800
M16   415us   2409.6   2400
M8    831us   1203.4   1200
M4   1663us    601.3    600
So it looks like bit-banged send should be good enough up to 4800 baud on an M2, probably 9600 on a 20X2. The M2's other than the 18M2 do have port pin mapping so the actual usable baud rate may be one lower on those.

The nice thing about this bit-banged technique is that the RAM buffer can be filled at leisure so one can use FOR-NEXT etc to convert any number of words, bytes and bits to a bit-stream. This can be useful for generating infra red output streams to simulate remote controls.
 

hippy

Technical Support
Staff member
is there a way to receive different lengths of messages into a buffer and then play them back out at a higher baud rate to my other LCD screen?
The best way to do it is to use a PICAXE X2 which can automatically put received serial bytes into its background buffer which can then be processed at leisure to determine what the data means.

For example, something like this should be able to pull the LCD messages from the stream and send them to an LCD -
Code:
#Picaxe 20X2

PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %001

Main:
  Do
    Gosub ReadByte        ; Command
    Select Case b0
      Case "L" : Gosub HandleL
      Case "K" : Gosub HandleK
      Case "P" : Gosub HandleP
    End Select
  Loop

HandleL:
  Gosub ReadByte          ; Length
  b2 = b0
  Do
    Gosub ReadByte        ; Data byte
    Gosub SendByteToLcd
    b2 = b2 - 1
  Loop Until b2 = 0
  Gosub ReadByte          ; Checksum
  Return

HandleK:
  Gosub ReadByte          ; Key code
  Gosub ReadByte          ; Checksum
  Return

HandleP:
  Gosub ReadByte          ; Zone info
  Gosub ReadByte          ; General info
  Gosub ReadByte          ; Checksum
  Return

ReadByte:
  Do : Loop While ptr = hSerInPtr
  b0 = @ptrInc
  Return
One needs to handle all possible commands and discard the data related to those so an "L" in the data of one of those is not accidentally treated as an actual LCD command when it isn't.

That 1200 baud is quite slow, one byte arriving every 8.3ms so it should be possible to handle one byte on an M2 before the next arrives with -
Code:
ReadByte:
  w0 = -1
  Do
    HSerIn w0
  Loop Until b1 = 0
  Return
The SendToLcd could buffer the data into RAM and keep track of the checksum and, when the checksum arrives, send those out, but it would be easier to just pass them out as they arrive and ignore the checksum, assume nothing will ever be corrupted.

Otherwise the issue will be in sending the data to LCD while ensuring no incoming data is missed. On an X2 that's not so problematic, the background buffer will simply fill while sending, but on the M2 you would probably need to buffer the received bytes, put those in another send buffer when checksum matches, and then send that out in the ReadByte loop. Not impossible but it would be more complicated code.
 

rjandsam

Member
Hi Hippy,

I have setup a 20x2 with the quick demo code you put together and it works first time I transmit data into it but then includes more data second time around like it is not returning to the main point or I am missing something, I would love to fully understand your code but I don't as yet but I am slowly getting there and I really appreciate your help.
im sending: 4B 3E 89 4B 3E 89 4B 3C 87 4B 3F 8A 4C 15 0C 53 65 74 74 69 6E 67 20 46 61 75 6C 74
and in the display first run I receive: Setting Fault
if I send again I receive: K>‰K>‰KSetting Fault
if I restart the chip all good for one receive then the unfiltered result.


Code:
#Picaxe 20X2

PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %001

Main:
  Do
    Gosub ReadByte        ; Command
    Select Case b0
      Case "L" : Gosub HandleL
      Case "K" : Gosub HandleK
      Case "P" : Gosub HandleP
    End Select
  Loop

HandleL:
  Gosub ReadByte          ; Length
  b2 = b0
  Do
    Gosub ReadByte        ; Data byte
    Gosub SendByteToLcd
    b2 = b2 - 1
  Loop Until b2 = 0
  Gosub ReadByte          ; Checksum
  Return

HandleK:
  Gosub ReadByte          ; Key code
  Gosub ReadByte          ; Checksum
  Return

HandleP:
  Gosub ReadByte          ; Zone info
  Gosub ReadByte          ; General info
  Gosub ReadByte          ; Checksum
  Return

ReadByte:
  Do : Loop While ptr = hSerInPtr
  b0 = @ptrInc
  Return

  SendByteToLcd:
  if b0<$20 then return
  endif
  sertxd (b0)
  return
 

hippy

Technical Support
Staff member
im sending: 4B 3E 89 4B 3E 89 4B 3C 87 4B 3F 8A 4C 15 0C 53 65 74 74 69 6E 67 20 46 61 75 6C 74
What you are sending is badly formed. You have four K then an L command -
Code:
K  .. .. K  .. .. K  .. .. K  .. .. L  .. ..
4B 3E 89 4B 3E 89 4B 3C 87 4B 3F 8A 4C 15 ..
If we look at that L command -
Code:
L  21 .. S  e  t  t  i  n  g     F  a  u  l  t 
4C 15 0C 53 65 74 74 69 6E 67 20 46 61 75 6C 74
      1  2  3  4  5  6  7  8  9  10 11 12 13 14
The byte after the L is $15 which indicates 21 bytes are being sent, but you only send 14 bytes.

The code is therefore waiting for more bytes to be displayed. When you send the same again it takes K commands as bytes to display, displays them, and hence the odd characters you are seeing -
Code:
L  21 .. S  e  t  t  i  n  g     F  a  u  l  t  K  >  ?  K  >  ?  K  ..
4C 15 0C 53 65 74 74 69 6E 67 20 46 61 75 6C 74 4B 3E 89 4B 3E 89 4B 3E
      1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21
I'm guessing the $15 should actually be 14, which is $0E, and there should be a checksum 'xx' on the end as well. Not sure what value that should be but the existing code doesn't care -
Code:
L  14 .. S  e  t  t  i  n  g     F  a  u  l  t  ..
4C 0E 0C 53 65 74 74 69 6E 67 20 46 61 75 6C 74 xx
      1  2  3  4  5  6  7  8  9  10 11 12 13 14
I don't know about that $0C - If a 'clear screen' or 'goto line 1' command you would need to make sure whatever is sent to the LCD achieves that. That would depend on what LCD hardware you have. Otherwise it would show as some sort of random character.
 

rjandsam

Member
Changing this seems to fix it ???

Code:
HandleL:
  Gosub ReadByte          ; Length
  b2 = b0
  Do
    Gosub ReadByte        ; Data byte
    Gosub SendByteToLcd
    b2 = b2 - 1
  Loop Until b2 = 1
  'Gosub ReadByte          ; Checksum
  Return
 

rjandsam

Member
Hi,
sorry problems on the serial line as it is a single comms line things where getting lost ive separated the comms to just receive the panel data and this is the hex and you where right it now works with the checksum of 22 bytes.
4C 15 0C 53 65 74 74 69 6E 67 20 46 61 75 6C 74 0A 32 3A 48 61 6C 6C 5E
 

hippy

Technical Support
Staff member
I was wondering what happens with multiple units attached on the single wire multi-drop bus, how they would avoid collisions etc. I guess the 9-bit scheme and command bytes having that set allows commands to be nested within other commands.

That makes sense because the alarm unit won't want to lock the keypads out for a third of a second while it is sending a long message to the LCD panels.

I would guess there is also some protocol whereby everything on the system can determine whether it can send the next command or byte or whether it must wait.

Those nested commands make things difficult. The ninth bit would let a receiver determine if it's a command or a nested command, but the X2's don't retain that ninth bit. It may be back to the M2, using byte at a time HSERIN, peeking the RX9 bit having enabled 9-bit data reception.

But the whole notion of using a PICAXE to interface into this alarm system other than to just display the LCD messages may be a non-starter because we don't know the full protocol being used. Just throwing data out on the bus probably wouldn't work unless we were lucky with the timing, could potentially lock up the entire system which is not what one wants from an alarm.
 

rjandsam

Member
Hi,
Just to let you know that your code works great with the tests so far.
I have found your help invaluable and it has been a great learning curve for me especially the communications side of things as I sit here trying to get my head around your code.
the following works with the tests so far communicating with a small touch screen, at the moment I am using 2 picaxe chips to deal with incoming and out going until I finalise all of my testing.
Code:
#Picaxe 20X2
Symbol LCD_DATA_OUT=b.7
PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %001

Main:
  Do
    Gosub ReadByte        ; Command
    Select Case b0
      Case "L" : Gosub HandleL
      Case "K" : Gosub HandleK
      Case "P" : Gosub HandleP
    End Select
  Loop

HandleL:
  Gosub ReadByte          ; Length
  b2 = b0
  SerOut LCD_data_out,t19200_32,("t0.txt=",$22)
  Do
    Gosub ReadByte        ; Data byte
    Gosub SendByteToLcd
    b2 = b2 - 1
  Loop Until b2 = 0
  Gosub ReadByte          ; Checksum
  Return

HandleK:
  Gosub ReadByte          ; Key code
  Gosub ReadByte          ; Checksum
  Return

HandleP:
  Gosub ReadByte          ; Zone info
  Gosub ReadByte          ; General info
  Gosub ReadByte          ; Checksum
  Return

ReadByte:
  Do : Loop While ptr = hSerInPtr
  b0 = @ptrInc
  Return
 
  SendByteToLcd:
  if b0<$20 or b0>$7f then return
  endif
 SerOut LCD_data_out,t19200_32,(b0)
   if b2=1 then
       SerOut LCD_data_out,t19200_32,($22)
      gosub terminate
      endif
  return

terminate:
SerOut LCD_data_out,t19200_32,($ff,$ff,$ff)
return
 

rjandsam

Member
With regards to the panel I only want to receive the LCD data by sniffing the traffic the only time I am going to inject anything into the comms is when I use the touch screen keypad and that will use the 14m2 to send 9bit data key commands so hopefully it will work without issue as I only have 1 LCD keypad on the bus.

ill keep playing as im enjoying it and learning a great deal at the same time, I could use the repeated every 60 seconds LCD time update command that the panel sends out as some kind of watch dog so that if it stops my backend system can alert me.
 

hippy

Technical Support
Staff member
It would be interesting to know if this M2 code will capture the bit9 status of received bytes -
Code:
#Picaxe 14M2
#Terminal 38400
#No_Data

Symbol RCSTA      = $7D  ; $19D
Symbol RCSTA_RX9  = bit6
Symbol RCSTA_RX9D = bit0

PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %01000
  PeekSfr RCSTA, b0
  RCSTA_RX9 = 1
  PokeSfr RCSTA, b0

MainLoop:
  Do
    Gosub ReadByte
    SerTxd( #bit9, " ", #b0, TAB, b0, CR, LF )
  Loop

ReadByte:
  w0 = -1
  Do
    HSerIn w0
  Loop Until b1 = 0
  PeekSfr RCSTA, bit9
  Return
Updated Code : Changed HSERSETUP - See Post #31 below.
 
Last edited:

rjandsam

Member
That looks good.
I'm picking up an old panel tomorrow to make life easier bench testing as its a pain going into the loft to do real tests so once I'm setup with it ill give it a try and will probably have less issues, unfortunately my step and stair count will drop significantly on my Fitbit.

Thank you
 

hippy

Technical Support
Staff member
Ah, yes; I had forgotten about that. I used a typical HSERSETUP which enables both input and output, and when output is enabled, when that shares the pin used for SERTXD, it overrides the use of that pin for SERTXD.

Data is probably arriving, SERTXD is likely executing, but nothing it sends makes its way out of the chip.

Replacing the HSERSETUP should resolve thar issue, allow HSERIN use and SERTXD -

HSerSetup B1200_32, %01000

I have updated the code in Post #27.
 

rjandsam

Member
As received:
Code:
1 75    K
0 60    <
0 135    ‡
1 76    L
0 3    
0 22    
0 5    
0 16    
0 122    z
1 76    L
0 17    
0 12   
0 42    *
0 32     
0 83    S
0 89    Y
0 83    S
0 84    T
0 69    E
0 77    M
0 32     
0 85    U
0 78    N
0 83    S
0 69    E
0 84    T
0 32     
0 42    *
0 145    ‘
 

hippy

Technical Support
Staff member
Do
Gosub ReadByte
HSerOut 0, ( #bit9, " ", #b0, TAB, b0, CR, LF )
Loop
There can be problems with that. Because of the way the on-chip silicon works, the firmware within the PICAXE manipulates internal status bits to avoid HSERIN lock-up but that can cause corruption or loss of data if there is incoming serial at the time those bits are updated.

It should works fine in half-duplex where there will be no overlap in sent and received data but it can cause some issues when trying to do full-duplex asynchronous communications.
 

rjandsam

Member
Was thinking of something like the following with my limited coding abilities to mark beginning and end of LCD transmittable data:

Code:
PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %01000
  PeekSfr RCSTA, b0
  RCSTA_RX9 = 1
  PokeSfr RCSTA, b0
let b12=255
MainLoop:
  Do     
    Gosub ReadByte
     if b11=1 then
        let b10=b0
        SerTxd("*",b10,"*",cr,lf)
        let b11=2
        endif
    'SerTxd( #bit9, " ", #b0, TAB, b0, CR, LF )
    if b11=0 and b0="L" then
        let b11=1
endif
   if b11=2 then
       inc b12
endif
 
    SerTxd(b0)
     if b12=b10 then
       SerTxd("Finished",cr,lf)
       endif
     Loop
ReadByte:
  w0 = -1
  Do
    HSerIn w0
  Loop Until b1 = 0
  PeekSfr RCSTA, bit9
  Return
 

rjandsam

Member
The following code replicates all LCD data on the bus perfectly without missing a beat, I know my code is probably clunky and inefficient but its still work in progress.
thank you for your valuable help so far Hippy.
Code:
#Picaxe 14M2
'#Terminal 38400
#No_Data
Symbol LCD_DATA_OUT=c.4
Symbol RCSTA      = $7D  ; $19D
Symbol RCSTA_RX9  = bit6
Symbol RCSTA_RX9D = bit0

PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %01000
  PeekSfr RCSTA, b0
  RCSTA_RX9 = 1
  PokeSfr RCSTA, b0
let b12=255
MainLoop:
  Do     
    Gosub ReadByte
     if b11=1 then
        let b10=b0
        SerOut LCD_data_out,t19200_32,("g0.txt=",$22)
        'SerTxd("*",b10,"*",cr,lf)
        let b11=2
        endif
    'SerTxd( #bit9, " ", #b0, TAB, b0, CR, LF )
    if b11=0 and b0="L" then         
        let b11=1
endif
   if b11=2 then
       inc b12
endif
  if b0=$0a or b0=$04 then
      let b0=$20
  elseif b0<$20 or b0>$7f then
      goto skip
  endif
 if b11=2 then
     SerOut LCD_data_out,t19200_32,(b0)
     endif
 skip:
     if b12=b10 then
         let b12=255 b11=0
       SerOut LCD_data_out,t19200_32,($22)
      gosub terminate
       endif
     Loop
ReadByte:
  w0 = -1
  Do
    HSerIn w0
  Loop Until b1 = 0
  PeekSfr RCSTA, bit9
  Return
 
terminate:
SerOut LCD_data_out,t19200_32,($ff,$ff,$ff)
return
 

hippy

Technical Support
Staff member
Something like this should handle nested K and P packets within L packets.
Code:
#Picaxe 14M2
#Terminal 38400
#No_Data

Symbol RCSTA      = $7D  ; $19D
Symbol RCSTA_RX9  = bit6
Symbol RCSTA_RX9D = bit0

PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %01000
  PeekSfr RCSTA, b0
  RCSTA_RX9 = 1
  PokeSfr RCSTA, b0

MainLoop:
  Do
    Gosub ReadByte
  Loop

HandleL:
  Gosub ReadByte          ; Length
  b2 = b0
  SerTxd( "{" )
  Do
    Gosub ReadByte        ; Data byte
    SerTxd( b0 )
    b2 = b2 - 1
  Loop Until b2 = 0
  Gosub ReadByte          ; Checksum
  SerTxd( "}", CR, LF )
  Return

HandleK:
  Gosub ReadByte          ; Key code
  Gosub ReadByte          ; Checksum
  Return

HandleP:
  Gosub ReadByte          ; Zone info
  Gosub ReadByte          ; General info
  Gosub ReadByte          ; Checksum
  Return

ReadByte:
  Do
    w0 = -1
    Do
      HSerIn w0
    Loop Until b1 = 0
    PeekSfr RCSTA, bit9
    If bit9 = 1 Then
      Select Case b0
        Case "L" : Gosub HandleL
        Case "K" : Gosub HandleK
        Case "P" : Gosub HandleP
      End Select
    Else
      Return
    End If
  Loop
 

rjandsam

Member
Once again Hippy you have shown me how to program so much more efficiently, basically the code below is all yours with my LCD interfacing bits bolted on😂 .
it works really well and im very happy with the end result code wise, I'm just going to start building up the hardware now that the whole thing can be ran from a very cost effective 14m2. the next stage will be to link the final board into node-red and home assistant with the help of a Wi-Fi module so that the touch screen and the web interfaces can operate the main panel.

Thank you its great to know that guys like you and a forum like this with vast amounts of experience are willing to take time out and help guide those of us who are still learning, once again helped me bring an idea to life.

Rich

Code:
#Picaxe 14M2
'#Terminal 38400
#No_Data
Symbol LCD_DATA_OUT=c.4
Symbol LCD_DATA_IN=c.0
Symbol Bus_Out=b.3
Symbol Alarm_Bus_Out=outpinb.3
Symbol Data_CMD1=b20
Symbol Data_CMD2=b21
Symbol Data_CMD3=b22
Symbol Data_CMD4=b23
Symbol Data_CMD5=b24
Symbol Data_CMD6=b25
Symbol Data_CMD7=b26
Symbol Data_CMD8=b27
Symbol TXSTA      = $7E
Symbol RCSTA      = $7D  ; $19D
Symbol RCSTA_RX9  = bit6
Symbol RCSTA_RX9D = bit0
Symbol TX9  = bit6
Symbol TX9D = bit0
pullup %0000000100000000
setint %00000000,%00000001
high Bus_Out
PowerOnReset:
  SetFreq M32
  HSerSetup B1200_32, %01000
  PeekSfr RCSTA, b0
  RCSTA_RX9 = 1
  PokeSfr RCSTA, b0

MainLoop:
  Do
    Gosub ReadByte
  Loop

HandleL:
  Gosub ReadByte          ; Length
  b2 = b0
  SerOut LCD_data_out,t19200_32,("g0.txt=",$22)
  Do
    Gosub ReadByte        ; Data byte
     if b0=$0a or b0=$04 then
      let b0=$20
  elseif b0<$20 or b0>$7f then
      goto skip
  endif
      SerOut LCD_data_out,t19200_32,(b0)
     skip:
    b2 = b2 - 1
  Loop Until b2 = 0
  Gosub ReadByte          ; Checksum
  SerOut LCD_data_out,t19200_32,($22)
  gosub terminate
  Return

HandleK:
  Gosub ReadByte          ; Key code
  Gosub ReadByte          ; Checksum
  Return

HandleP:
  Gosub ReadByte          ; Zone info
  Gosub ReadByte          ; General info
  Gosub ReadByte          ; Checksum
  Return

ReadByte:
  Do
    w0 = -1
    Do
      HSerIn w0
    Loop Until b1 = 0
    PeekSfr RCSTA, bit9
    If bit9 = 1 Then
      Select Case b0
        Case "L" : Gosub HandleL
        Case "K" : Gosub HandleK
        Case "P" : Gosub HandleP
      End Select
    Else
      Return
    End If
  Loop

terminate:
SerOut LCD_data_out,t19200_32,($ff,$ff,$ff)
return

Interrupt:
serin [3000,LCD_IN],LCD_data_in,t19200_32,("XIOM"),Data_CMD1,Data_CMD2,Data_CMD3,Data_CMD4,Data_CMD5

let Data_CMD1=Data_CMD1-48 
let Data_CMD8=Data_CMD1+75   
gosub keypad_out
LCD_IN:
setint %00000000,%00000001
return


SendByte:
  bPtr     = -11
  @bPtrInc = 0    ; -11 $F5 - Start bit
  @bPtrInc = bit0 ; -10 $F6 - Data bit 0 - 1st bit
  @bPtrInc = bit1 ; -9  $F7 - Data bit 1
  @bPtrInc = bit2 ; -8  $F8 - Data bit 2
  @bPtrInc = bit3 ; -7  $F9 - Data bit 3
  @bPtrInc = bit4 ; -6  $FA - Data bit 4
  @bPtrInc = bit5 ; -5  $FB - Data bit 5
  @bPtrInc = bit6 ; -4  $FC - Data bit 6
  @bPtrInc = bit7 ; -3  $FD - Data bit 7
  @bPtrInc = bit9 ; -2  $FE - Data bit 8 - 9th bit
  @bPtrInc = 1    ; -1  $FF - Stop bit
  bPtr     = -11
  Do
    Alarm_Bus_Out=@bPtrInc
    PauseUs 400
  Loop Until bPtr = 0
  Return
 
  Keypad_out:
   b0 = "K" : bit9 = 1 : Gosub SendByte   
       b0 = Data_CMD1 : bit9 = 0 : Gosub SendByte
         b0 = Data_CMD8  : Gosub SendByte
              return
23109
 
Top