Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the complete ebus arbitration protocol #40

Merged

Conversation

guido4096
Copy link
Contributor

  1. Only allowed to participate when the bus is in state "Received First Syn"
  2. Participate in second arbitration round when priority class matches

1) Only allowed to participate when the bus is in state "First Syn"
2) Participate in second arbitration round when priority class matches
@guido4096
Copy link
Contributor Author

guido4096 commented Apr 13, 2023

P.S. the code became quite a bit more complex. I didn't find a reasonable way to do it easier. The ebus protocol is interesting for arbitration, you really need to monitor the bus continuously to assess the state and to find out who won.

Without these changes , you run the risk of disturbing the good working of the ebus:

  • you might start an arbitration when the second round arbitration is ongoing
  • or if you don't participate in the second round arbitration you waste bus cycles

@danielkucera
Copy link
Owner

Thank you for this. I
just took the naive approach: send address after received syn but it seems to be more complicated. Would you be willing to support this feature in case someone reports an issue with it? May I tag you for help?

@guido4096
Copy link
Contributor Author

of course; I'm still testing here and keep debugging

@danielkucera
Copy link
Owner

@brozikcz maybe you want to test this one?

@guido4096
Copy link
Contributor Author

After lots of testing, I added an additional change that improved the interaction with ebusd significantly. as much as I can tell, ebusd expects to receive the starting SYN symbol when starting the arbitration.

@guido4096
Copy link
Contributor Author

I’m still having unpredictable behavior. There is at least one bug present with the priority class. Better to wait until i finished all testing.

Add DEBUG_LOG statements
Make sure no WIFI communication during arbitration
Avoid lockup during arbitration loop
Handle unexpected state during arbitration
@guido4096
Copy link
Contributor Author

Had a rough day yesterday evening, ebusd was just not interacting well with the adapter at all. This morning, same code, all works more or less flawless. Either related to my devices on the ebus, or to the wifi.

Anyways, this state is at this moment working well for me. Also added DEBUG_LOG statements that are removed using a #define

@guido4096
Copy link
Contributor Author

guido4096 commented Apr 15, 2023

Below is a nice example of the arbitration working.

  • I'm writing from master 0xf3 and another device on the bus is writing with master 0x17.
  • The resulting address on the bus is then 0x13.
  • 0xf3, my master, is the same priority class and participates in the second round.
  • 0x17, the other device, is not participating, since it was not in the same priority class.
  • The second round is started on AUTO-SYN, about 48 miliseconds after the previous SYN was received.
  • And now my master 0xf3 is winning.

CMD_START 0xf3
ARB START 0009 0xf3 9 us
ARB MASTER1 0xf3 148 us
ARB SYMBOL 0x13 4235 us
ARB PARTICIPATE SECOND 0xf3 0x13
ARB SYMBOL 0xaa 48641 us
ARB MASTER2 0xf3 1 us
ARB SYMBOL 0xf3 4028 us
ARB WON2 0xf3 4048 us
ARB SEND WON 0xf3 4069 us

@guido4096
Copy link
Contributor Author

guido4096 commented Apr 16, 2023

By now I observe only the following problems:

  1. Sometimes ebusd is not responsing fast enough to a "WON" status. This is likely wifi overhead. Nothing much we can do. Ebusd will retry the arbitration. [CORRECTION] this is not a WIFI problem. Instead, ebusd expects the SYN before starting the abitration. [/CORRECTION]
  2. On my ebus network, (a)some masters don't participate in the second round arbitration, where they should and if they would, they would have won; or (b)they believe they lost in the 1st round. This means nobody will send data on the bus and AUTOSYN will kick in to recover. Nothing much the code can do, except handle the recovery graceful.
  3. Sometimes the symbol received after arbitration is not valid, for example 0x0e; if all participants have correct timing, the symbol should always be following the pattern of a valid master address. This is I think a timing problem with retrieving the SYN from the bus and when to send our master address on the bus.
  4. Sometimes the ESP is just completely too late and another symbol is already on the bus.

The third item is the most difficult one to resolve. I think with the Arduino framework it is not possible:

  • The loop does a lot of work, for example with the wifi clients
  • In the loop, a symbol is retrieved from the bus. When the symbol is a SYN, typically an arbitration is allowed to start
  • However there is no guarantee about the delay between "when the SYN was available in the recv buffer" and "when the code retrieves the SYN". The code can only check that there was not yet another symbol available on the bus; meaning the arbitration can start halfway instead of at the exact beginning of the first bit after SYN is received.

I believe this problem can only be solved when handling the arbitration in an interrupt, which is not supported by the Arduino framework - to my knowledge.

Fortunately it doesn't happen too often.

Note: all these problems are gracefully handled, ebusd reports on them and retries as needed. Typically the command will pass. Most of the time the command passes without any hiccups at all, you have to do stress tests to see the issues. But of course, the system should behave well in stress tests....

Example of problem 1

CMD_START 0xf3
ARB START 0080 0xf3 7 us
ARB MASTER1 0xf3 59 us
ARB SYMBOL 0xf3 4101 us
ARB WON1 0xf3 4128 us
ARB SEND WON 0xf3 4151 us
unexpected SYN on bus while state is eReceivedSecondSYN, setting state to eReceivedFirstSYN m=0xf3, b=0xaa 44879 us

Example of problem 2b

CMD_START 0xf3
ARB START 0261 0xf3 9 us
ARB MASTER1 0xf3 65 us
ARB SYMBOL 0x70 4108 us
ARB LOST1 0x70 4139 us <- 0x70 won, but is not starting the transmission, leading to AUTOSYN
ARB SYMBOL 0xaa 48943 us
ARB SYMBOL 0xaa 44882 us
unexpected SYN on bus while state is eReceivedSecondSYN, setting state to eReceivedFirstSYN m=0x70, b=0xaa 44924 us
ARB ERROR 0xaa 0xaa

Example of problem 3

CMD_START 0xf3
ARB START 0311 0xf3 10 us
ARB MASTER1 0xf3 69 us
ARB SYMBOL 0x02 4113 us <- this should not happen, wrong timing, will lead to AUTOSYN
ARB LOST1 0x02 4142 us
ARB SYMBOL 0xaa 49043 us
ARB SYMBOL 0xaa 44747 us
unexpected SYN on bus while state is eReceivedSecondSYN, setting state to eReceivedFirstSYN m=0x02, b=0xaa 44780 us
ARB ERROR 0xaa 0xaa

Example of problem 4

CMD_START 0xf3
ARB START 0594 0xf3 7 us
ARB LATE 0xaa 145 us
ARB START 0595 0xf3 8 us
ARB LATE 0xaa 709 us
ARB START 0596 0xf3 8 us
ARB LATE 0xaa 145 us
ARB START 0597 0xf3 7 us
ARB LATE 0xaa 792 us
ARB START 0598 0xf3 9 us
ARB LATE 0xaa 137 us
CMD_START REPEAT 0xf3
ARB START 0599 0xf3 7 us
ARB LATE 0xaa 56 us
ARB START 0600 0xf3 8 us
ARB LATE 0x70 144 us
CMD_START REPEAT 0xf3
ARB START 0601 0xf3 4 us
ARB MASTER1 0xf3 153 us
ARB SYMBOL 0xf3 4240 us
ARB WON1 0xf3 4323 us
ARB SEND WON 0xf3 4350 us
unexpected SYN on bus while state is eReceivedSecondSYN, setting state to eReceivedFirstSYN m=0xf3, b=0xaa 44937 us
CMD_START 0xf3
ARB START 0602 0xf3 10 us
ARB MASTER1 0xf3 69 us
ARB SYMBOL 0xf3 4110 us
ARB WON1 0xf3 4147 us
ARB SEND WON 0xf3 4172 us

Example of lost arbitration and retry

CMD_START 0xf3
ARB START 0645 0xf3 10 us
ARB MASTER1 0xf3 71 us
ARB SYMBOL 0xf0 4115 us
ARB LOST1 0xf0 4151 us
ARB SYMBOL 0xaa 49817 us
ARB SYMBOL 0xf0 4366 us
ARB LOST2 0xf0 4386 us
ARB SYMBOL 0xf1 8502 us
ARB SEND LOST 0xf0 0xf1 8522 us
CMD_START 0xf3
ARB START 0646 0xf3 10 us
ARB MASTER1 0xf3 156 us
ARB SYMBOL 0xf3 4202 us
ARB WON1 0xf3 4229 us
ARB SEND WON 0xf3 4252 us

corresponding ebusd messages
2023-04-16 21:23:05.944 [main notice] hex cmd: f308070400
2023-04-16 21:23:05.944 [bus info] send message: f308070400
2023-04-16 21:23:05.986 [bus debug] start request f3
2023-04-16 21:23:05.987 [bus debug] arbitration start with f3
2023-04-16 21:23:06.091 [bus debug] arbitration lost
2023-04-16 21:23:06.091 [bus debug] ERR: arbitration lost during ready, retry
2023-04-16 21:23:06.150 [update notice] received update-read hc3 Set: hotwaterinheating;-;29.69;-;-;-;-
2023-04-16 21:23:06.151 [bus debug] start request f3
2023-04-16 21:23:06.151 [bus debug] arbitration start with f3
2023-04-16 21:23:06.156 [bus notice] >f3<f0f1050709bbffdb010080ffffff2400
2023-04-16 21:23:06.203 [bus debug] arbitration won
2023-04-16 21:23:06.203 [bus debug] arbitration delay 2 micros
2023-04-16 21:23:06.203 [bus debug] switching from ready to send command
2023-04-16 21:23:06.213 [bus debug] send/receive symbol latency 10 ms
2023-04-16 21:23:06.230 [bus debug] send/receive symbol latency 16 ms
2023-04-16 21:23:06.240 [bus debug] send/receive symbol latency 10 ms
2023-04-16 21:23:06.251 [bus debug] send/receive symbol latency 10 ms
2023-04-16 21:23:06.251 [bus debug] switching from send command to send command CRC
2023-04-16 21:23:06.262 [bus debug] send/receive symbol latency 10 ms
2023-04-16 21:23:06.262 [bus debug] switching from send command CRC to receive command ACK
2023-04-16 21:23:06.268 [bus debug] switching from receive command ACK to receive response
2023-04-16 21:23:06.313 [bus debug] switching from receive response to receive response CRC
2023-04-16 21:23:06.318 [bus debug] switching from receive response CRC to send response ACK
2023-04-16 21:23:06.334 [bus debug] send/receive symbol latency 16 ms
2023-04-16 21:23:06.334 [update notice] sent scan-read scan.08 QQ=f3: Kromschroeder;W<;1200;0401
2023-04-16 21:23:06.334 [bus debug] notify request: done
2023-04-16 21:23:06.334 [bus debug] read res: 0a50573c003cb512000401
2023-04-16 21:23:06.334 [bus debug] switching from send response ACK to send SYN
2023-04-16 21:23:06.334 [bus notice] >f30807040079<000a50573c003cb51200040169>00
2023-04-16 21:23:06.344 [bus debug] send/receive symbol latency 9 ms
2023-04-16 21:23:06.344 [bus debug] switching from send SYN to ready

@PiotrHab
Copy link

Hi guido4096
Just a thought to try out,
put a Wifi handling on a low priority RTOS task (xTaskCreate).
Should be possible within Arduino framework and does not use interrupts which are time sensitive and might cause MCU reset.

@guido4096
Copy link
Contributor Author

guido4096 commented Apr 16, 2023

@PiotrHab, Thanks for suggestion. I expect that would cause more occurrences of item 1. To fix the remaining issues, I still think there are two things needed:

  1. Put the arbitration handling in an interrupt, so we can fully control the timing. This is something with no dependency to ebusd
  2. To fix the issues with wifi, the Enhanced protocol needs to be extended to not just ask for arbitration, but instead to ask for full message to be sent. Dependency to ebusd

@danielkucera
Copy link
Owner

@guido4096 , could something like SoftwareSerial help with 1.?

For 2. I was long asking for this but without any reply:
john30/ebusd#857
john30/ebusd#124

@guido4096
Copy link
Contributor Author

guido4096 commented Apr 16, 2023

@guido4096 , could something like SoftwareSerial help with 1.?

I don't see how SoftwareSerial can help. What is happening:

  1. arbitration is finished on ESP side and the code sends "WON" to ebusd.
  2. now ebusd needs to take over and send a character back

The ESP needs to receive the character from ebusd and put it on the bus within about 45 ms. If not done in time, the AUTOSYN will detect that the bus is idle for 45 ms and will send a SYN.

@danielkucera
Copy link
Owner

Sorry, I meant it as solution for this one:

Sometimes the symbol received after arbitration is not valid, for example 0x0e; if all participants have correct timing, the symbol should always be following the pattern of a valid master address. This is I think a timing problem with retrieving the SYN from the bus and when to send our master address on the bus.

@guido4096
Copy link
Contributor Author

guido4096 commented Apr 16, 2023

For 2. I was long asking for this but without any reply: john30/ebusd#857 john30/ebusd#124

ebusd looks like it has grown over time and It now has many different responsibilities mixed in one code base that is difficult to understand and to maintain in a predictable way.

  • Responsibilities in one code base that don't belong together
  • And a single responsibility split over multiple devices (with the enh protocol)

Maybe better to just create something new, without all the overhead of ebusd. Something that is only able to understand the lowest layer of the protocol and leaves all the interpretation to somebody else. The lowest layer should be implemented completely on the ESP. It should forward what it reads - like it already does - and support a full message protocol for writing and including sending the reply of the message to the requester. So something like what you described here: john30/ebusd#124

@guido4096
Copy link
Contributor Author

Sorry, I meant it as solution for this one:

Sometimes the symbol received after arbitration is not valid, for example 0x0e; if all participants have correct timing, the symbol should always be following the pattern of a valid master address. This is I think a timing problem with retrieving the SYN from the bus and when to send our master address on the bus.

I don't know enough how SoftwareSerial works. Does it allow bit precise interaction with the signal? If you get signaled per bit, at least you know better the exact timing. But still if you don't have interrupts you cannot guarantee that you can reply in the right time.

@guido4096
Copy link
Contributor Author

guido4096 commented Apr 16, 2023

P.S. with the changes on this branch, I think you are close to what ebusd-esp is doing. I think ebusd-esp will have the same problems with wifi as the code on this branch. Of course if they connect to a dedicated raspberry pi, the problem should not occur as latency is more predictable. But that is just not a right solution, it spreads a single responsibility over two different devices. I think the only good solution is what you already requested here john30/ebusd#124.

Still then, to get everything in shape, the arbitration protocol itself needs to be closer to the hardware than it is now, ... my opinion based on all the testing and timing problems I observed.

@guido4096
Copy link
Contributor Author

@danielkucera I believe the current code is good for esp32, using SoftwareSerial and ASYNC mode. There is maybe a slightly more tweaking possible on timing delays with arbitration, there is a fudge factor of 700 micros in the code, which I derived by testing ... a lot.

The current code uses SoftwareSerial to get the exact flange of the start of the startbit. It requires a specially adapted version of that software though.

The included statistics, available using the status webservice, should give feedback how things work for other users.

The code builds for esp8266, using SoftwareSerial and SYNCHRONOUS mode. This setup also works on esp32 and testing it gives quite ok results, although ASYNCHRONOUS works better for the esp32.

Code is documented on the non-obvious parts, quite a number of them available dealing with SoftwareSerial and vTaskDelay.

Maybe there is still some cleanup possible with the debug messages, might still do that.

I would be really interested in experiences from other users...

@danielkucera
Copy link
Owner

Hi @guido4096 , was your order number 2748?

@guido4096
Copy link
Contributor Author

Yep

@guido4096
Copy link
Contributor Author

guido4096 commented May 10, 2023

Hi @danielkucera , I received two modules, thanks! I just finished testing the esp8266 - version v4. With the original code I had quite some errors icw ebusd, the new code behaves much better, at least for me, icw SoftwareSerial and plain synchronous mode.

The three main high-level improvements in the code are:

  1. using SoftwareSerial we have better control over the timing for the arbitration
  2. sticking to the ebus spec when you can and cannot participate in the arbitration
  3. pure state machine design avoids a byte long wait in the main loop

I think the item 3) helps to keep the wifi connection more responsive.

Note that the esp8266 has less memory than esp32 and SoftwareSerial uses more memory because it needs to store the timestamp. To avoid heap exhaustion, I needed to reduce the receive buffer size to 512. This is more than 2 seconds, so this should be more than enough. I think even 256 should be enough.

@@ -48,6 +49,9 @@ platform = espressif32
board = esp32-c3-devkitm-1
build_flags =
-DRESET_PIN=20
lib_deps =
https://github.com/tzapu/WiFiManager
https://github.com/guido4096/espsoftwareserial.git#add-startbit-timestamp
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guido4096 , did you consider creating pull request to the original library?

@guido4096
Copy link
Contributor Author

I did ask: plerup/espsoftwareserial#287

P.S. still testing. The ebus of my heating system crashed a few time with the esp8266, now testing with the original firmware.

@danielkucera
Copy link
Owner

Hi @guido4096 ,

can we merge this? Is it running fine?

@danielkucera
Copy link
Owner

Hi @guido4096 ,

do you have any update?

@guido4096
Copy link
Contributor Author

Hi Daniel,

sorry for the late reply. The code itself is running fine, however i see with the esp8266 that my heating system goes faster into error mode. Like once every two days instead of once every 5 days. I think this means the code uses more power?

This is reduced if i use hardwareserial for the rsp8266, i cant say if it is the same as with the original code.

Ill upload the current code in the evening to have all settings I use depending on chip type. And then ill start another test with the esp8266 while connected with external power, so see if that indeed fixes the bus.

Guid

@danielkucera
Copy link
Owner

Thank you for the update. Let's merge this one with what you have and then if you wish, you can optimize for esp8266 (but you don't need to invest much time into this honestly).

I am thinking about putting the bus handling into a separate task (outside of loop() ) and I don't want to refactor everything again after this is merged :)

@guido4096
Copy link
Contributor Author

I just pushed the latest changes, they are small. Shall I return the two adapters that you gave me for testing back to you?

@danielkucera
Copy link
Owner

No, you can keep them, thank you for all that work.

@danielkucera danielkucera merged commit 5f9b72a into danielkucera:master Aug 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants