Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
A draft implementation of a multi-master strategy over RS485 "auto-tx" PHY for PJON protocol stack
/* ThroughHardwareSerialRs485AutoTx enables PJON multi-master communication through the Serial port with auto-tx RS485 PHY.
Work based on ThroughHardwareSerial by Giovanni Blu Mitolo and Fred Larsen
Copyright (c) 2016 by Zbigniew Zasieczny All rights reserved.
With rs485 "auto-tx" PHY the hardware serial port reads everything sent to the bus
The "self-reading" property could be used in this strategy to detect colisions at a byte-level in a similar way the CAN network works on a bit-level to silelntly drop-off lower priority nodes; feature not implemented yet
A naive timeout-based collision avoidance is used: bus is assumed clear for tx within specified time window after empty rx buffer was detected. The receive(<timeout_us>) function must be called often - transimission would occur only within 1ms after last receive call on empty rx buffer; within this time window the update() function must be called to transmit packets.
#include <Arduino.h>
#define THROUGH_HARDWARE_SERIAL_MAX_TIME 500 // Wait up to 5 ms to receive a byte
#define THROUGH_HARDWARE_SERIAL_MIN_CHANNEL_SILELNCE_WINDOW 100 // min 1 ms silence to start sending
class ThroughHardwareSerialRs485AutoTx {
HardwareSerial *serial;
/* Pass the Serial port where you want to operate with */
void set_serial(HardwareSerial *serial_port) {
serial = serial_port;
/* Returns the Serial object value i.e. if(Serial) */
boolean can_start(uint8_t input_pin, uint8_t output_pin) {
if (micros() - _last_clear_channel_ts < THROUGH_HARDWARE_SERIAL_MIN_CHANNEL_SILELNCE_WINDOW ) return false;
return (serial != NULL) && *serial; // Check if pointer
/* Send a byte and wait for its transmission end */
void send_byte(uint8_t b, uint8_t input_pin, uint8_t output_pin) {
//if (receive_byte(input_pin, output_pin) != b) return FAIL; // needs additional work with logic analyzer; sent byte should be avaialbe in rx buffer immediatelly but isn't
//return 0;
/* Try to receive a byte with a maximum waiting time */
uint16_t receive_byte(uint8_t input_pin, uint8_t output_pin) {
uint32_t time = micros();
while(micros() - time < THROUGH_HARDWARE_SERIAL_MAX_TIME)
if(serial->available() > 0)
return (uint8_t)serial->read();
_last_clear_channel_ts = micros();
return FAIL;
/* Receive byte response */
uint16_t receive_response(uint8_t input_pin, uint8_t output_pin) {
return receive_byte(input_pin, output_pin);
/* Send byte response to the packet's transmitter */
void send_response(uint8_t response, uint8_t input_pin, uint8_t output_pin) {
send_byte(response, input_pin, output_pin);
long _last_clear_channel_ts;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment