diff --git a/LICENSE.md b/LICENSE.md index 7c67cd6df8..68d4263ced 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ -All the software included in this project is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. All specifications, all related software implementations and documentation released as a part of this repository are and will always remain free for personal, educational, experimental and commercial purposes. +All the software included in this project is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Giovanni Blu Mitolo (gioscarab@gmail.com) Copyright 2010-2020 +Giovanni Blu Mitolo (gioscarab@gmail.com) Copyright 2010-2025 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/README.md b/README.md index 61ac521b31..0708bc136c 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,40 @@ +PJON -![PJON](http://www.gioblu.com/PJON/PJON-github-header-tiny.png) -## PJON 12.1 -PJON® (Padded Jittering Operative Network) is an arduino-compatible, multi-master, multi-media network protocol. It proposes a new Open Standard, it is designed as a framework and implements a totally software-defined network protocol stack that can be easily cross-compiled on many MCUs and architectures like ATtiny, ATmega, SAMD, ESP8266, ESP32, STM32, Teensy, Raspberry Pi, Linux, Windows x86, Apple and Android. PJON operates on a wide range of media and protocols like TCP, UDP, MQTT, ESPNOW, USB, Serial, RS485, LoRa, PJDL, PJDLR and PJDLS. +## PJON 13.1 + +PJON (Padded Jittering Operative Network) is an experimental, multi-master, software-defined network protocol that can be easily cross-compiled for many microcontrollers and real-time operating systems such as ATtiny, ATmega, SAMD, ESP8266, ESP32, STM32, Teensy, Raspberry Pi, Zephyr, Linux, Windows x86, Apple, and Android. PJON operates over a wide range of media, data links, and existing protocols like PJDL, PJDLR, PJDLS, Serial, RS485, USB, ASK/FSK, LoRa, UDP, TCP, MQTT, and ESPNOW. For more information, visit the [documentation](documentation/README.md), the [specification](specification/PJON-protocol-specification-v4.0.md), or the [wiki](https://github.com/gioblu/PJON/wiki). -[![Get PJON bus id](https://img.shields.io/badge/get-PJON%20bus%20id-lightgrey.svg)](http://www.pjon.org/get-bus-id.php) [![Join the chat at https://gitter.im/gioblu/PJON](https://badges.gitter.im/gioblu/PJON.svg)](https://gitter.im/gioblu/PJON?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -PJON is used in thousands of devices and its community has spread worldwide because of the following 5 key factors: -- **New technology**: [PJON](specification/PJON-protocol-specification-v3.2.md) is an experimental network protocol stack crafted in 10 years of research and experimentation. It was originally developed as an open-source alternative to i2c and 1-Wire but during development its scope and features have been extended to cover use cases where IP is generally applied. PJON has been engineered to have a variable footprint (4.2-8.2 kB program memory) and overhead (5-22 bytes per packet) depending on its configuration. -- **Multi-media support**: PJON operates on a wide range of media and protocols like TCP, UDP, MQTT, ESPNOW, USB, Serial, RS485 and LoRa. The PJON network protocol stack specifies and implements also [PJDL](src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) able to communicate data over a single wire shared by up to 255 devices, [PJDLR](src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) able to operate with many ASK/FSK/OOK radio modules and also [PJDLS](src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md), able to communicate wirelessly with light pulses using off the shelf LEDs and laser diodes. -- **Increased reliability**: Many protocols massively applied worldwide expose dangerous vulnerabilities, have weak error detection algorithms and are not resilient to interference. PJON is based on years of analysis and study not to make the same mistakes present in most alternatives and provide with a set of simpler and more efficient solutions. -- **High flexibility**: PJON is totally software-defined and its implementation is designed to be easily extensible. it builds out-of-the-box in all supported devices and operates transparently on top of any supported protocol or medium. -- **Low cost**: Without any additional hardware needed to operate, minimal network wiring requirements and direct pin-to-pin or LED-to-LED communication, PJON is extremely energy efficient, cheap to be implemented and maintained. This implementation is kept updated and meticulously tested thanks to the strong commitment of its growing community of end users, testers and developers. +### Why PJON? +- **New technology**: [PJON](specification/PJON-protocol-specification-v4.0.md) is an experimental network protocol stack crafted through 10 years of research and experimentation. It was originally developed as an open-source alternative to i2c and 1-Wire, but during development, its scope and features were extended to cover use cases where IP is generally applied. PJON has been engineered to have a variable footprint (4.2–8.2 kB program memory) and overhead (5–35 bytes per packet) depending on its configuration. +- **Multi-media support**: PJON operates over a wide range of protocols including TCP, UDP, MQTT, ESPNOW, USB, Serial, RS485, and LoRa. The PJON network protocol stack also specifies and implements [PJDL](src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) that operates over a single wire of up to 2000m shared by up to 255 devices, [PJDLR](src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) that operates with many ASK/FSK/OOK radio modules and [PJDLS](src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) that operates wirelessly with light pulses using off-the-shelf LEDs and laser diodes. +- **Increased reliability**: Many widely applied protocols expose significant vulnerabilities, have weak error detection algorithms, and are not resilient to interference. PJON is based on years of analysis and study to avoid the mistakes present in most alternatives and provide with a simpler and more efficient solution. +- **High flexibility**: PJON is fully software-defined and designed to be easily extensible. It builds out-of-the-box on all supported devices and operates transparently on top of any supported protocol or medium. +- **Low cost**: With no additional hardware needed to operate, minimal network wiring requirements, and direct pin-to-pin or LED-to-LED communication, PJON is extremely energy-efficient, inexpensive to implement, and maintain. This experimental reference implementation is kept up to date thanks to the strong commitment of its growing community. ### Features -- Cross-compilation support with the [interfaces](src/interfaces) system calls abstraction -- Multi-media support with the [strategies](src/strategies) data link layer abstraction -- Hot-swap support, no need of system reset or shut down when replacing or adding devices -- Configurable synchronous and/or asynchronous [acknowledgement](specification/PJON-protocol-acknowledge-specification-v1.0.md) -- Configurable 2 level addressing (device and bus id) for scalable applications -- Configurable 1 or 2 bytes packet length (max 255 or 65535 bytes) -- Configurable CRC8 or CRC32 table-less cyclic redundancy check -- Packet manager to handle, track and if necessary retransmit a packet sending in background -- Error handling - -### Specifications -- [PJON v3.2](specification/PJON-protocol-specification-v3.2.md) -- [PJON Acknowledge v1.0](specification/PJON-protocol-acknowledge-specification-v1.0.md) -- [PJDL v4.1](src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) - [PJDLR v3.0](src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) - [PJDLS v2.0](src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) - [TSDL v2.1](src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) - -### Publications -- [PJON protocol handbook](https://www.pjon-technologies.com/collections/frontpage/products/pjon-protocol-hand-book) by Giovanni Blu Mitolo - Distributed by [PJON Technologies srl](https://www.pjon-technologies.com) -- [PJON 12.0 big box](https://www.pjon-technologies.com/collections/frontpage/products/pjon-protocol-12-0-big-box) by Giovanni Blu Mitolo - Distributed by [PJON Technologies srl](https://www.pjon-technologies.com) +- Cross-compilation support with the [interfaces](src/interfaces) system calls abstraction. +- Multi-media support with the [strategies](src/strategies) data link layer abstraction. +- Modular packet format that includes only the fields used (overhead 5–35 bytes). +- Hot-swap support, no need for a system reset or shutdown when replacing or adding devices. +- Flexible local (device ID) and shared (bus ID) network identification. +- Safe error detection using modern CRC8 and CRC32 polynomials. +- Optional inclusion of MAC addresses. +- Optional acknowledgement. +- Error handling. ### Academic studies -Researchers are active in many universities worldwide using PJON in different environments. The following list contains all the known published academic studies about PJON: -- [Definition and Application of PJON-PLC for sensor networks](https://repositorio.unican.es/xmlui/bitstream/handle/10902/14012/408952.pdf?sequence=1) by Jorge Gómez Segurola, Ingeniería de Tecnologías de -Telecomunicación - [Universidad de Cantabria](https://web.unican.es/) (ES) -- [Biomimetic electronics](http://c.harl.ie/biomimetic.html) by Charlie Williams with scientific input from researchers Vítor Martins dos Santos, Diana Machado de Sousa and Sabine Vreeburg - Artist in Residency at [Wageningen University](https://www.wur.nl/en.htm) (NL) +Researchers are active in many universities worldwide using PJON in different environments. The following list contains known published academic studies about PJON: +- [Definition and Application of PJON-PLC for sensor networks](https://repositorio.unican.es/xmlui/bitstream/handle/10902/14012/408952.pdf?sequence=1) by Jorge Gómez Segurola, Ingeniería de Tecnologías de Telecomunicación - [Universidad de Cantabria](https://web.unican.es/) (ES). +- [Biomimetic electronics](https://charliewilliams.org/portfolio/biomimetic/) by Charlie Williams with scientific input from researchers Vítor Martins dos Santos, Diana Machado de Sousa, and Sabine Vreeburg - Artist in Residency at [Wageningen University](https://www.wur.nl/en.htm) (NL). +- [LANC Video Camera Control](http://jda.tel/pdf/lanc_video_camera_control.pdf) by [Jack Anderson](https://github.com/jdaandersj) - Department of Computer Science [Loughborough University](https://www.lboro.ac.uk/departments/compsci/) (UK). +- [Implementation of a PJON hardware peripheral for the Croc SoC](https://github.com/piussieber/pjon_on_croc) by [Pius Sieber](https://github.com/piussieber/) - [ETH Zurich](https://ethz.ch/) (CH) ### Contribute Feel free to send a pull request sharing something you have made that could help, if you want to support this project you can also try to solve an [issue](https://github.com/gioblu/PJON/issues). Thanks to support, expertise, kindness and talent of the following contributors, the protocol's documentation, specification and implementation have been strongly tested, enhanced and verified: -[Fred Larsen](https://github.com/fredilarsen), [Zbigniew Zasieczny](https://github.com/girgitt), [Matheus Garbelini](https://github.com/Matheus-Garbelini), [sticilface](https://github.com/sticilface), [Felix Barbalet](https://github.com/xlfe), [Oleh Halitskiy](https://github.com/Halytskyi), [fabpolli](https://github.com/fabpolli), [Adrian Sławiński](https://github.com/4ib3r), [Osman Selçuk Aktepe](https://github.com/osman-aktepe), [Jorgen-VikingGod](https://github.com/Jorgen-VikingGod), [drtrigon](https://github.com/drtrigon), [Endre Karlson](https://github.com/ekarlso), [Wilfried Klaas](https://github.com/willie68), [budaics](https://github.com/budaics), [ibantxo](https://github.com/ibantxo), [gonnavis](https://github.com/gonnavis), [maxidroms83](https://github.com/maxidroms83), [Evgeny Dontsov](https://github.com/dontsovcmc), [zcattacz](https://github.com/zcattacz), [Valerii Koval](https://github.com/valeros), [Ivan Kravets](https://github.com/ivankravets), [Esben Soeltoft](https://github.com/EsbenSoeltoft), [Alex Grishin](https://github.com/240974a), [Andrew Grande](https://github.com/aperepel), [Michael Teeww](https://github.com/MichMich), [Paolo Paolucci](https://github.com/PaoloP74), [per1234](https://github.com/per1234), [Santiago Castro](https://github.com/bryant1410), [pacproduct](https://github.com/pacproduct), [elusive-code](https://github.com/elusive-code), [Emanuele Iannone](https://github.com/eiannone), [Christian Pointner](https://github.com/equinox0815), [Fabian Gärtner](https://github.com/TeeTrizZz), [Mauro Mombelli](https://github.com/MauroMombelli), [Remo Kallio](https://github.com/shacal), [hyndruide](https://github.com/hyndruide), [sigmaeo](https://github.com/sigmaeo), [filogranaf](https://github.com/filogranaf), [Maximiliano Duarte](https://github.com/domonetic), [Viktor Szépe](https://github.com/szepeviktor), [Shachar Limor](), [Pantovich](), [Mauro Zancarlin](), [Franketto](), [jzobac](), [DanRoad](), [fcastrovilli](https://github.com/fcastrovilli), [Andrei Volkau](https://github.com/andrei-volkau), [maniekq](https://github.com/maniekq), [DetAtHome](https://github.com/DetAtHome), [Michael Branson](https://github.com/mxbranson), [chestwood96](https://github.com/chestwood96), [Mattze96](https://github.com/Mattze96), [Steven Bense](https://github.com/justoke), [Jack Anderson](https://github.com/jdaandersj) and [callalilychen](https://github.com/callalilychen). +[Fred Larsen](https://github.com/fredilarsen), [Zbigniew Zasieczny](https://github.com/girgitt), [Matheus Garbelini](https://github.com/Matheus-Garbelini), [sticilface](https://github.com/sticilface), [Felix Barbalet](https://github.com/xlfe), [Oleh Halitskiy](https://github.com/Halytskyi), [fotosettore](https://github.com/fotosettore), [fabpolli](https://github.com/fabpolli), [Adrian Sławiński](https://github.com/4ib3r), [Osman Selçuk Aktepe](https://github.com/osman-aktepe), [Jorgen-VikingGod](https://github.com/Jorgen-VikingGod), [drtrigon](https://github.com/drtrigon), [Endre Karlson](https://github.com/ekarlso), [Wilfried Klaas](https://github.com/willie68), [budaics](https://github.com/budaics), [ibantxo](https://github.com/ibantxo), [gonnavis](https://github.com/gonnavis), [maxidroms83](https://github.com/maxidroms83), [Evgeny Dontsov](https://github.com/dontsovcmc), [zcattacz](https://github.com/zcattacz), [Valerii Koval](https://github.com/valeros), [Ivan Kravets](https://github.com/ivankravets), [Esben Soeltoft](https://github.com/EsbenSoeltoft), [Alex Grishin](https://github.com/240974a), [Andrew Grande](https://github.com/aperepel), [Michael Teeww](https://github.com/MichMich), [Paolo Paolucci](https://github.com/PaoloP74), [per1234](https://github.com/per1234), [Santiago Castro](https://github.com/bryant1410), [pacproduct](https://github.com/pacproduct), [elusive-code](https://github.com/elusive-code), [Emanuele Iannone](https://github.com/eiannone), [Christian Pointner](https://github.com/equinox0815), [Fabian Gärtner](https://github.com/TeeTrizZz), [Mauro Mombelli](https://github.com/MauroMombelli), [Remo Kallio](https://github.com/shacal), [hyndruide](https://github.com/hyndruide), [sigmaeo](https://github.com/sigmaeo), [filogranaf](https://github.com/filogranaf), [Maximiliano Duarte](https://github.com/domonetic), [Viktor Szépe](https://github.com/szepeviktor), [Shachar Limor](), [Pantovich](), [Mauro Zancarlin](), [Franketto](), [jzobac](), [DanRoad](), [fcastrovilli](https://github.com/fcastrovilli), [Andrei Volkau](https://github.com/andrei-volkau), [maniekq](https://github.com/maniekq), [DetAtHome](https://github.com/DetAtHome), [Michael Branson](https://github.com/mxbranson), [chestwood96](https://github.com/chestwood96), [Mattze96](https://github.com/Mattze96), [Steven Bense](https://github.com/justoke), [Jack Anderson](https://github.com/jdaandersj), [callalilychen](https://github.com/callalilychen), [Julio Aguirre](https://github.com/jcallano), [Cimex97](https://github.com/Cimex97), [der-schne](https://github.com/der-schne), [porkyneal](https://github.com/porkyneal), [der-schne](https://github.com/der-schne), [Rainer Schoenberger](https://github.com/rainerschoe), [jgOhYeah](https://github.com/jgOhYeah) and [kuchendieb](https://github.com/kuchendieb). ### Compliant tools - [ModuleInterface](https://github.com/fredilarsen/ModuleInterface) - easy config and value sync between IoT modules by Fred Larsen @@ -50,9 +42,10 @@ Feel free to send a pull request sharing something you have made that could help - [PJON-piper](https://github.com/Girgitt/PJON-piper) - command line wrapper by Zbigniew Zasieczny - [PJON-python](https://github.com/Girgitt/PJON-python) - python interface by Zbigniew Zasieczny - [PJON-gRPC](https://github.com/Halytskyi/PJON-gRPC) - gRPC server-client by Oleh Halytskyi +- [PjonHL](https://github.com/rainerschoe/PjonHL) - PjonHL is a highlevel wrapper around PJON ### License -All the software included in this project is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. [Licensed](https://github.com/gioblu/PJON/blob/master/LICENSE.md) under the Apache License, Version 2.0. PJON® and its brand are registered trademarks, property of Giovanni Blu Mitolo gioscarab@gmail.com +All the software included in this project is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. [Licensed](https://github.com/gioblu/PJON/blob/master/LICENSE.md) under the Apache License, Version 2.0. ### Safety warning -When installing or maintaining a PJON network, extreme care must be taken to avoid any danger. If devices are connected to AC power you are exposed to a high chance of being electrocuted if hardware is not installed carefully and properly. If you are not experienced enough ask the support of a skilled technician and consider that many countries prohibit uncertified installations. When a [SoftwareBitBang](/src/strategies/SoftwareBitBang) bus is installed [interference mitigation](https://github.com/gioblu/PJON/wiki/Mitigate-interference) and [protective circuitry](https://github.com/gioblu/PJON/wiki/Protective-circuitry) guidelines must be followed. When working with an [AnalogSampling](/src/strategies/AnalogSampling) LED or laser based setup safety glasses must be worn and transceivers must be operated cautiously to avoid potential eye injuries. Before any practical test or a hardware purchase for a wireless [OverSampling](/src/strategies/OverSampling), [ThroughSerial](/src/strategies/ThroughSerial) or [ThroughLoRa](/src/strategies/ThroughLoRa) radio setup, compliance with government requirements and regulations must be ensured. When connecting a local bus to the internet all devices must be considered potentially compromised, manipulated or remotely actuated against your will. It should be considered a good practice not to connect to the internet systems that may create a damage (fire, flood, data-leak) if hacked. +When testing PJON, take extreme care to avoid any danger. The implementation is experimental and may not behave as expected; use it at your own risk. If devices are connected to AC power, you face a high risk of electrocution unless the hardware is installed carefully and correctly. If you lack sufficient experience, seek assistance from a qualified technician, and be aware that many countries prohibit uncertified installations. When testing a [SoftwareBitBang](/src/strategies/SoftwareBitBang) bus follow [interference-mitigation](https://github.com/gioblu/PJON/wiki/Mitigate-interference) and [protective-circuitry](https://github.com/gioblu/PJON/wiki/Protective-circuitry) guidelines. When experimenting with an AnalogSampling setup, wear safety glasses and operate transceivers cautiously to prevent eye injuries. Before testing [OverSampling](/src/strategies/OverSampling), [ThroughSerial](/src/strategies/ThroughSerial) or [ThroughLoRa](/src/strategies/ThroughLoRa) radio communication, ensure that the frequency, power, and hardware comply with local regulations. When connecting a local bus to the Internet, treat all devices as potentially compromised, manipulated, or remotely actuated against your will. As a best practice, avoid connecting to the internet systems that could cause damage (fire, flood, data leakage) if hacked. diff --git a/SECURITY.md b/SECURITY.md index 9054f1c040..c0823f531e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ PJON is still in experimental phase and it distributed "AS IS" without any warra The security of a system that uses PJON for communication mostly depends on the vulnerabilities exposed by the hardware and by the physical layer used. Consider that **only air-gapped wired local buses are undoubtely secure**. When connecting a local bus to the internet using [ESPNOW](/src/strategies/ESPNOW), [EthernetTCP](/src/strategies/EthernetTCP) or [LocalUDP](/src/strategies/LocalUDP), [GlobalUDP](/src/strategies/GlobalUDP) or [DualUDP](/src/strategies/DualUDP), all connected devices must be considered potentially compromised. It should be considered a good practice not to connect to the internet systems that may cause damage (fire, flood, data-leak) if hacked. ### Safety warning -When installing or maintaining a PJON network, extreme care must be taken to avoid any danger. If devices are connected to AC power you are exposed to a high chance of being electrocuted if hardware is not installed carefully and properly. If you are not experienced enough ask the support of a skilled technician and consider that many countries prohibit uncertified installations. When a [SoftwareBitBang](/src/strategies/SoftwareBitBang) bus is installed [interference mitigation](https://github.com/gioblu/PJON/wiki/Mitigate-interference) and [protective circuitry](https://github.com/gioblu/PJON/wiki/Protective-circuitry) guidelines must be followed. When working with an [AnalogSampling](/src/strategies/AnalogSampling) LED or laser based setup safety glasses must be worn and transceivers must be operated cautiously to avoid potential eye injuries. Before any practical test or a hardware purchase for a wireless [OverSampling](/src/strategies/OverSampling), [ThroughSerial](/src/strategies/ThroughSerial) or [ThroughLoRa](/src/strategies/ThroughLoRa) radio setup, compliance with government requirements and regulations must be ensured. +When testing PJON, take extreme care to avoid any danger. The implementation is experimental and may not behave as expected; use it at your own risk. If devices are connected to AC power, you face a high risk of electrocution unless the hardware is installed carefully and correctly. If you lack sufficient experience, seek assistance from a qualified technician, and be aware that many countries prohibit uncertified installations. When testing a [SoftwareBitBang](/src/strategies/SoftwareBitBang) bus follow [interference-mitigation](https://github.com/gioblu/PJON/wiki/Mitigate-interference) and [protective-circuitry](https://github.com/gioblu/PJON/wiki/Protective-circuitry) guidelines. When experimenting with an AnalogSampling setup, wear safety glasses and operate transceivers cautiously to prevent eye injuries. Before testing [OverSampling](/src/strategies/OverSampling), [ThroughSerial](/src/strategies/ThroughSerial) or [ThroughLoRa](/src/strategies/ThroughLoRa) radio communication, ensure that the frequency, power, and hardware comply with local regulations. When connecting a local bus to the Internet, treat all devices as potentially compromised, manipulated, or remotely actuated against your will. As a best practice, avoid connecting to the internet systems that could cause damage (fire, flood, data leakage) if hacked. ### Reporting a Vulnerability If you discover a vulnerability in the specification or in the implementation please report it as soon as possible opening an [issue](https://github.com/gioblu/PJON/issues). If you have developed a fix, feel free to open a [pull request](https://github.com/gioblu/PJON/pulls). diff --git a/devices/sensors/LEDAR/README.md b/devices/sensors/LEDAR/README.md index 92f9bca418..ed0bbde058 100644 --- a/devices/sensors/LEDAR/README.md +++ b/devices/sensors/LEDAR/README.md @@ -18,7 +18,7 @@ Many LEDARs can be connected to the same [SoftwareBitBang](/src/strategies/Softw Its detection method is based on two interesting characteristics of LEDs: - If hit by light, LEDs produce a tiny amount of electricity, thanks to the photo-electric effect -- LEDs used as detectors are generally more sensitive to the frequency they emit if used as emitters, making a couple of identical LEDs generally used for lighting, in two extremely efficient wireless transceivers that can be used for reflectometry or also for wireless communication using the [AnalogSampling](/src/strategies/AnalogSampling/README.md) strategy +- LEDs used as detectors are generally more sensitive to the frequency they emit if used as emitters, so a couple of identical LEDs generally used for lighting can be used successfully as wireless transceivers for reflectometry or optical wireless communication using the [AnalogSampling](/src/strategies/AnalogSampling/README.md) strategy Its sampling method is based on two different samples: - Background noise or ambient light sample `B` @@ -79,6 +79,6 @@ The case is made by two elements and it has been printed using a customized Prus Once crafted, ATtiny85 has to be flashed with the [LEDAR](software/LEDAR/LEDAR.ino) sketch using an ISP programmer, see [ATtiny85 interfacing](https://github.com/gioblu/PJON/wiki/ATtiny-interfacing) -LEDAR has been engineered with the strong feeling that, in the future, "smart houses" will not necessarily host a multitude of inefficient and convoluted embedded real-time operative systems, in whatever "thing", consuming a lot of power running Ethernet over WiFi and exposing vulnerabilities also out of the physical boundaries of houses. Otherwise, more probably, will host many dedicated microcontrollers connected to a wired, common, open-source, lightweight and less power consuming communication bus, unhackable without direct physical access to its wiring. +LEDAR has been engineered with the strong feeling that, in the future, "smart houses" will not necessarily host a multitude of inefficient embedded real-time operating systems in whatever "thing" while exposing vulnerabilities out of the physical boundaries of houses. Otherwise, more probably, will host many simple, less power-hungy microcontrollers, connected to a wired communication bus, unhackable without direct physical access to its wiring. LEDAR should be considered as a general "guideline" on how PJON compatible devices can be published and shared with other PJON users through the [devices](../../README.md) directory. Feel free to make a pull request proposing a new device you have engineered. diff --git a/documentation/README.md b/documentation/README.md index 302d10532a..0ef24a499a 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -1,13 +1,21 @@ ### Documentation index - [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - [Error handling](/documentation/error-handling.md) -- [IO setup](/documentation/io-setup.md) + - [`set_error`](/documentation/error-handling.md#error-handling) - [Routing](/documentation/routing.md) - + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## Documentation diff --git a/documentation/addressing.md b/documentation/addressing.md index b84d5f9269..312a64392f 100644 --- a/documentation/addressing.md +++ b/documentation/addressing.md @@ -1,27 +1,36 @@ ### Documentation index - **[Addressing](/documentation/addressing.md)** + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - [Error handling](/documentation/error-handling.md) -- [IO setup](/documentation/io-setup.md) + - [`set_error`](/documentation/error-handling.md#error-handling) - [Routing](/documentation/routing.md) + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## Addressing -PJON objects can operate in local or shared mode. The PJON protocol v3.2 in [local](/specification/PJON-protocol-specification-v3.2.md#local-mode) mode supports connectivity for up to 254 devices using a 8bits device identifier, in [shared](/specification/PJON-protocol-specification-v3.2.md#shared-mode) mode supports connectivity for up to 4.294.967.295 buses (groups of devices) and up to 1.090.921.692.930 devices using a 32bits bus identifier and a 8bits device identifier. +PJON objects can operate in local or shared mode. The PJON protocol v4.0 in [local](/specification/PJON-protocol-specification-v4.0.md#local-mode) mode supports connectivity for up to 254 devices using a 8bits device identifier, in [shared](/specification/PJON-protocol-specification-v4.0.md#shared-mode) mode supports connectivity for up to 4.294.967.295 buses (groups of devices) and up to 1.090.921.692.930 devices using a 32bits bus identifier and a 8bits device identifier. ### Local mode -The simples way to instantiate PJON in local mode is the following: +The simplest way to instantiate PJON in local mode is as follows: ```cpp - PJON bus; + PJONSoftwareBitBang bus; ``` When the object is instantiated without passing parameters it operates in local mode and the device identifier is set to 255 or `PJON_NOT_ASSIGNED`. PJON objects can be instantiated passing the device identifier: ```cpp - PJON bus(44); + PJONSoftwareBitBang bus(44); ``` `bus` receives packets for device identifier 44 and ignores all others. @@ -39,21 +48,60 @@ The device identifier of an object can be read after instantiation using `device ```cpp uint8_t id = bus.device_id(); // Get device id ``` -`device_id` returns 255 or `PJON_NOT_ASSIGNED` if the instance is initialised without configuring its device identifier. +`device_id` returns `PJON_NOT_ASSIGNED` or 255 if the instance is initialised without configuring its device identifier. ### Shared mode -if the medium used is private and not accessible from the outside world (wired network in home, business, industry) any bus indexing scheme can be used without worrying about bus id collision; if instead the network uses a shared medium, such as commonly used radio frequencies like LoRa, it is strongly suggested to request a unique PJON bus id [here](http://www.pjon.org/get-bus-id.php) to avoid collisions. +if the medium used is private and not accessible from the outside world (wired network in home, business, industry), bus ids can be used arbitrarily without any risk of collision; if instead the network uses a shared medium, for example on unlicensed radio frequencies with [ThroughLoRa](/src/strategies/ThroughLoRa). Instantiation in shared mode: ```cpp uint8_t bus_id[4] = {1, 2, 3, 4}; -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); // Device id 44, bus id 1.2.3.4 in shared mode ``` ### Get or set bus identifier -The bus id can be read and set after initialisation using `bus_id`: +Use `get_bus_id` to get a pointer to the bus id used by the instance: +```cpp + uint8_t bus_id[4]; + memcpy(bus_id, bus.get_bus_id(bus_id), 4); // Copy bus id in bus_id +``` + +The bus id can be set after initialisation using `set_bus_id`: +```cpp + uint8_t bus_id[4] = {0, 0, 0, 1}; + bus.set_bus_id(bus_id); // Set bus id +``` + +### Hardware identifier + +PJON can optionally operate using the MAC address of the device: +```cpp +// Include MAC address feature +#define PJON_INCLUDE_MAC + +// MAC address of the device +uint8_t mac[6] = {1, 2, 3, 4, 5, 6}; + +PJONSoftwareBitBang bus(mac); +// Local mode, device id PJON_NOT_ASSIGNED +``` +This instantiation sets the MAC address, the device id set to `PJON_NOT_ASSIGNED` or 255 but can be changed afterwards as required. Packets containing a recipient's MAC address that is not equal to the one configured are discarded. PJON can operate in both local and shared mode while including MAC addresses. The feature can be disabled using `include_mac`: + +```cpp +bus.include_mac(false); +``` +### Get or set hardware identifier + +Use `get_mac` to get a pointer to the mac address used by the instance: +```cpp + uint8_t mac[6]; + memcpy(mac, bus.get_mac(mac), 6); // Copy mac in variable +``` + +The mac address can be set after initialisation using `set_mac`: ```cpp - bus.bus_id; // Get or set bus id + uint8_t mac[6] = {0, 0, 0, 0, 0, 1}; + bus.set_mac(mac); // Set mac ``` diff --git a/documentation/configuration.md b/documentation/configuration.md index d64233da6c..dab04a7431 100644 --- a/documentation/configuration.md +++ b/documentation/configuration.md @@ -1,89 +1,85 @@ ### Documentation index - [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - **[Configuration](/documentation/configuration.md)** + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - [Error handling](/documentation/error-handling.md) -- [IO setup](/documentation/io-setup.md) + - [`set_error`](/documentation/error-handling.md#error-handling) - [Routing](/documentation/routing.md) - + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## Configuration PJON uses predefined constants, setters and getters to support features and constraints configuration. ### Buffers configuration -Before instantiating PJON it is possible to define the length of its buffers. Predefining `PJON_MAX_PACKETS` and `PJON_PACKET_MAX_LENGTH` it is possible to configure this constraints to reach the project memory requirements. Obviously, the less memory is dedicated to buffers, the more memory can be used for something else: +Before including the library, it is possible to define the length of its buffers by defining the `PJON_MAX_PACKETS` and `PJON_PACKET_MAX_LENGTH` constants: ```cpp -#define PJON_MAX_PACKETS 1 -#define PJON_PACKET_MAX_LENGTH 20 -#include -/* PJON can store up to 1 packet of up to - 20 bytes - packet overhead - (from 5 to 22 bytes depending by configuration) */ + #define PJON_MAX_PACKETS 1 + #define PJON_PACKET_MAX_LENGTH 20 + /* PJON can dispatch up to 1 packet with a payload of up to + 20 bytes - packet overhead (5-35 bytes depending on configuration) */ ``` -### Data link configuration -PJON is instantiated passing a [strategy](/src/strategies/README.md) template parameter: -```cpp - PJON bus; +### Strategy configuration +Strategies are classes that abstract the physical transmission of data. `PJON` uses [strategies](/src/strategies/README.md) as template parameters although since version 13.0 that complexity is hidden behind a [macro](../src/PJONSoftwareBitBang.h): +```cpp + #include + PJONSoftwareBitBang bus; +``` +In the example above, the PJON object is instantiated using the [SoftwareBitBang](/src/strategies/SoftwareBitBang/README.md) strategy. It is possible to instantiate more than one PJON object using different strategies in the same program: +```cpp +#include +#include + +PJONSoftwareBitBang wiredBus; +PJONEthernetTCP tcpBus; +``` + +The table below lists the strategies available: + +| Strategy | Physical layer | Protocol | Inclusion | +| ------------- | -------------- | -------- | --------- | +| [AnalogSampling](/src/strategies/AnalogSampling) | Light | [PJDLS](../src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) | `#include ` | +| [Any](/src/strategies/Any) | Virtual inheritance | Any | `#include ` | +| [DualUDP](/src/strategies/DualUDP) | Ethernet/WiFi | [UDP](https://tools.ietf.org/html/rfc768) | `#include ` | +| [ESPNOW](/src/strategies/ESPNOW) | WiFi | [ESPNOW](https://www.espressif.com/en/products/software/esp-now/overview) | `#include ` | +| [EthernetTCP](/src/strategies/EthernetTCP) | Ethernet/WiFi | [TCP](https://tools.ietf.org/html/rfc793) | `#include ` | +| [GlobalUDP](/src/strategies/GlobalUDP) | Ethernet/WiFi | [UDP](https://tools.ietf.org/html/rfc768) | `#include ` | +| [LocalFile](/src/strategies/LocalFile) | File system | None | `#include ` | +| [LocalUDP](/src/strategies/LocalUDP) | Ethernet/WiFi | [UDP](https://tools.ietf.org/html/rfc768) | `#include ` | +| [MQTTTranslate](/src/strategies/MQTTTranslate) | Ethernet/WiFi | [MQTT](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf) | `#include ` | +| [OverSampling](/src/strategies/OverSampling) | Radio | [PJDLR](../src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) | `#include ` | +| [SoftwareBitBang](/src/strategies/SoftwareBitBang) | Wire | [PJDL](../src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) | `#include ` | +| [ThroughLoRa](/src/strategies/ThroughLoRa) | Radio | [LoRa](https://lora-alliance.org/sites/default/files/2018-07/lorawan1.0.3.pdf) | `#include ` | +| [ThroughSerial](/src/strategies/ThroughSerial) | Wire | [TSDL](../src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) | `#include ` | + +Before using `ThroughLoRa` be sure to have [arduino-LoRa](https://github.com/sandeepmistry/arduino-LoRa) library available. Before using `ESPNOW` be sure to have installed the required tools as described [here](/src/strategies/ESPNOW/README.md). Before using `MQTTTranslate` be sure to have the [ReconnectingMqttClient](https://github.com/fredilarsen/ReconnectingMqttClient) library available. + +### Random seed +When `begin` is called an analog pin is used to sample the seed for the random generator. By default PJON uses pin `A0` to sample the seed, if you need to use another pin call `set_random_seed` as shown below: +```cpp + bus.set_random_seed(A1); // A1 is used to sample the seed + bus.begin(); // Seed sampling occurs ``` -In the example above the PJON object is instantiated passing [SoftwareBitBang](/src/strategies/SoftwareBitBang/README.md) strategy. Strategies are classes abstracting the data link layer, making PJON easy to be used on different media. It is possible to instantiate more than one PJON object using different strategies in the same program: -```cpp - PJON wiredBus; - PJON tcpBus; -``` - -| Strategy | Physical layer | Protocol | Pins needed | -| ------------- | -------------- | -------- | ------------- | -| [SoftwareBitBang](/src/strategies/SoftwareBitBang) | Electrical impulses over wire | [PJDL](../src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) | 1 or 2 | -| [OverSampling](/src/strategies/OverSampling) | Electrical/radio impulses over wire/air | [PJDLR](../src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) | 1 or 2 | -| [AnalogSampling](/src/strategies/AnalogSampling) | Light pulses over air or optic fiber | [PJDLS](../src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) | 1 or 2 | -| [ThroughSerial](/src/strategies/ThroughSerial) | Electrical/radio impulses over wire/air | [TSDL](../src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) | 1 or 2 | -| [ThroughSerialAsync](/src/strategies/ThroughSerialAsync) | Electrical/radio impulses over wire/air | [TSDL](../src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) | 1 or 2 | -| [ThroughLoRa](/src/strategies/ThroughLoRa) | Radio impulses over air | [LoRa](https://lora-alliance.org/sites/default/files/2018-07/lorawan1.0.3.pdf) | 3 or 4 | -| [EthernetTCP](/src/strategies/EthernetTCP) | Electrical/radio impulses over wire/air | [TCP](https://tools.ietf.org/html/rfc793) | Ethernet or WiFi | -| [LocalUDP](/src/strategies/LocalUDP) | Electrical/radio impulses over wire/air | [UDP](https://tools.ietf.org/html/rfc768) | Ethernet or WiFi | -| [GlobalUDP](/src/strategies/GlobalUDP) | Electrical/radio impulses over wire/air | [UDP](https://tools.ietf.org/html/rfc768) | Ethernet or WiFi | -| [DualUDP](/src/strategies/DualUDP) | Electrical/radio impulses over wire/air | [UDP](https://tools.ietf.org/html/rfc768) | Ethernet or WiFi | -| [MQTTTranslate](/src/strategies/MQTTTranslate) | Electrical/radio impulses over wire/air | [MQTT](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf) | Ethernet or WiFi | -| [ESPNOW](/src/strategies/ESPNOW) | Radio impulses over air | [ESPNOW](https://www.espressif.com/en/products/software/esp-now/overview) | WiFi link | -| [LocalFile](/src/strategies/LocalFile) | Shared file system in memory | None | None | -| [Any](/src/strategies/Any) | Virtual inheritance, any of the above | Any of the above | Any of the above | - -By default all strategies are included except `MQTTTranslate`, `LocalFile`, `ThroughLoRa` and `ESPNOW`. To reduce memory footprint add for example `#define PJON_INCLUDE_SWBB` before including the library to select only the `SoftwareBitBang` strategy. More than one strategy related constants can defined in the same program if that is required. - -Supported definitions: -- `PJON_INCLUDE_SWBB` includes `SoftwareBitBang` -- `PJON_INCLUDE_AS` includes `AnalogSampling` -- `PJON_INCLUDE_ETCP` includes `EthernetTCP` -- `PJON_INCLUDE_LUDP` includes `LocalUDP` -- `PJON_INCLUDE_GUDP` includes `GlobalUDP` -- `PJON_INCLUDE_OS` includes `OverSampling` -- `PJON_INCLUDE_TS` includes `ThroughSerial` -- `PJON_INCLUDE_TSA` includes `ThroughSerialAsync` -- `PJON_INCLUDE_TL` includes `ThroughLoRa` -- `PJON_INCLUDE_MQTT` includes `MQTTTranslate` -- `PJON_INCLUDE_EN` includes `ESPNOW` -- `PJON_INCLUDE_ANY` includes `Any` -- `PJON_INCLUDE_LF` includes `LocalFile` -- `PJON_INCLUDE_NONE` does not include any strategy - -Before using `ThroughLoRa` be sure to have [arduino-LoRa](https://github.com/sandeepmistry/arduino-LoRa) library available and to have defined the `PJON_INCLUDE_TL` constant before including `PJON.h`. - -Before using `ESPNOW` be sure to have installed the required tools as described [here](/src/strategies/ESPNOW/README.md) and to have defined the `PJON_INCLUDE_EN` constant before including `PJON.h`. - -Before using `MQTTTranslate` be sure to have the [ReconnectingMqttClient](https://github.com/fredilarsen/ReconnectingMqttClient) library available and to have defined the `PJON_INCLUDE_MQTT` constant before including `PJON.h`. ### Network mode -The network mode can be changed with `set_shared_network` during runtime, for example moving from [local](/specification/PJON-protocol-specification-v3.2.md#local-mode) to [shared](https://github.com/gioblu/PJON/blob/master/specification/PJON-protocol-specification-v3.2.md#shared-mode) mode: +The network mode can be changed with `set_shared_network` during runtime, for example moving from [local](/specification/PJON-protocol-specification-v4.0.md#local-mode) to [shared](https://github.com/gioblu/PJON/blob/master/specification/PJON-protocol-specification-v4.0.md#shared-mode) mode: ```cpp bus.set_shared_network(true); ``` ### Communication mode -The communication mode can be configured using the `set_communication_mode` passing `PJON_SIMPLEX` for simplex or mono-directional mode or `PJON_HALF_DUPLEX` for half-duplex or bidirectional mode: +The communication mode can be configured using `set_communication_mode` passing `PJON_SIMPLEX` for simplex or mono-directional mode or `PJON_HALF_DUPLEX` for half-duplex or bidirectional mode: ```cpp // Run in mono-directional PJON_SIMPLEX mode bus.set_communication_mode(PJON_SIMPLEX); @@ -92,7 +88,7 @@ The communication mode can be configured using the `set_communication_mode` pass ``` ### Router mode -Use `set_router` to configure the device in router mode, simply receiving all the incoming packets: +When an instance is configured in router mode it is able to receive all incoming packets without any bus or device id filtering. Use `set_router` to configure the router mode: ```cpp bus.set_router(true); ``` @@ -116,47 +112,56 @@ If manual packet handling is required, packet automatic deletion can be avoided ``` ### Acknowledgement -The [synchronous acknowledgement](/specification/PJON-protocol-acknowledge-specification-v1.0.md#synchronous-acknowledge) is by default enabled but can be disabled if required: +With the acknowledgement enabled the transmitter has reception certainty. It is by default enabled but can be disabled: ```cpp - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); ``` -If the [asynchronous acknowledgement](/specification/PJON-protocol-acknowledge-specification-v1.0.md#asynchronous-acknowledge) feature is required you need to define the `PJON_INCLUDE_ASYNC_ACK` as following. The use of a constant has been chosen to save more than 1kB on sketches where this feature is not used (the packet id is used by the asynchronous acknowledgement process, so if necessary, play with that responsibly): -```cpp -#define PJON_INCLUDE_ASYNC_ACK true -// Max number of old packet ids stored to avoid duplication -#define PJON_MAX_RECENT_PACKET_IDS 10 // by default 10 -// If packet duplication occurs, higher PJON_MAX_RECENT_PACKET_IDS -#include -``` -Use `set_asynchronous_acknowledge` to enable the asynchronous acknowledgement: +### Packet identification +The instance can be configured to include a 16 bits [packet identifier](/specification/PJON-protocol-specification-v4.0.md#packet-identification) to guarantee packet uniqueness. Define `PJON_INCLUDE_PACKET_ID` as described below, if this constant is not present the feature is not included and around 300 bytes of program memory and 80 bytes of RAM are spared: ```cpp - // Enable async ack - bus.set_asynchronous_acknowledge(true); -``` -See the [AsyncAck](/examples/ARDUINO/Network/SoftwareBitBang/AsyncAck) example to see more in detail how the asynchronous acknowledgement can be used. + // Include the packet id feature + #define PJON_INCLUDE_PACKET_ID + // Max number of old packet ids stored to avoid duplication + // If packet duplication occurs, higher PJON_MAX_RECENT_PACKET_IDS + #define PJON_MAX_RECENT_PACKET_IDS 10 // By default 10 -### Packet identification -If packet duplication avoidance is required it is possible to add a 2 bytes [packet identifier](/specification/PJON-protocol-specification-v3.2.md#packet-identification) to guarantee uniqueness. -define the `PJON_INCLUDE_PACKET_ID` as following. The use of a constant has been chosen to save more than 1kB on sketches where this feature is not used: -```cpp -#define PJON_INCLUDE_PACKET_ID true -// Max number of old packet ids stored to avoid duplication -#define PJON_MAX_RECENT_PACKET_IDS 10 // by default 10 -// If packet duplication occurs, higher PJON_MAX_RECENT_PACKET_IDS -#include + #include ``` -Use `set_packet_id` to enable the packet identification feature: +Use `set_packet_id` to enable the packet identification: ```cpp bus.set_packet_id(true); ``` See the [UsePacketId](/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId) example to see more in detail how the packet id can be used. ### Network service identification -Configure the instance to include a [network service identifier](/specification/PJON-protocol-specification-v3.2.md#network-services) in the packet. Ports from 0 to 8000 are reserved to known network services which index is present in the [known network services list](/specification/PJON-network-services-list.md), ports from 8001 to 65535 are free for custom use cases: +The instance can be configured to include a [network service identifier](/specification/PJON-protocol-specification-v4.0.md#network-services) in the packet. Ports from 0 to 8000 are reserved to known network services which index is present in the [known network services list](/specification/PJON-network-services-list.md), ports from 8001 to 65535 are free for custom use cases. Define `PJON_INCLUDE_PORT` as described below, if this constant is not present the feature is not used and around 100 bytes of program memory and 2 bytes of RAM are spared: +```cpp + // Include the port id feature + #define PJON_INCLUDE_PORT + #include +``` +Use `include_port` to enable the network service identification: +```cpp + bus.include_port(false); // Avoid port inclusion (default) + bus.include_port(8001); // Include a port +``` +When a port is configured, packets that contain a different port are discarded. See the [PortsUseExample](/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample) to see more in detail how the port feature can be used. + +### Hardware identification +The instance can be configured to include the [hardware identification](/specification/PJON-protocol-specification-v4.0.md#hardware-identification). If the feature is used both recipient's and sender's MAC addresses are included in the packet. Define `PJON_INCLUDE_MAC` as described below, if this constant is not present the feature is not included and around 200 bytes of program memory and 20 bytes of RAM are spared: +```cpp + // Include the port id feature + #define PJON_INCLUDE_MAC + #include + + // Device's MAC address + uint8_t mac[6] = {0, 0, 0, 0, 0, 0}; + PJONSoftwareBitBang bus(mac); +``` +Use `include_mac` to enable the network service identification by default: ```cpp - bus.include_port(false); // Avoid port inclusion (default) - bus.include_port(true, 8001); // Include custom port + bus.include_mac(true); // Include MAC address by default ``` -See the [PortsUseExample](/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample) example to see more in detail how the port feature can be used. +See the [BlinkTestMAC](/examples/ARDUINO/Local/SoftwareBitBang/BlinkTestMAC) example to see more in detail how the MAC feature can be used. diff --git a/documentation/data-reception.md b/documentation/data-reception.md index 3dcc182811..ab0c45e256 100644 --- a/documentation/data-reception.md +++ b/documentation/data-reception.md @@ -1,65 +1,86 @@ ### Documentation index - [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - **[Data reception](/documentation/data-reception.md)** + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - [Error handling](/documentation/error-handling.md) -- [IO setup](/documentation/io-setup.md) + - [`set_error`](/documentation/error-handling.md#error-handling) - [Routing](/documentation/routing.md) - + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## Data reception -A function of type `void` can be defined and register to be called by the PJON object when a packet is received. This function receives 3 parameters: the received payload of type `uint8_t *`, its length of type `uint16_t` and a pointer to a data structure of type `const PJON_Packet_Info` that contains all packet's metadata: +A function of type `void` is called by the PJON object when a packet is received. This function receives 3 parameters: the received payload of type `uint8_t *`, its length of type `uint16_t` and a pointer to a data structure of type [`const PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) that contains all packet's metadata: + ```cpp -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ +void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &info) { + // Print received data in the serial monitor + for(uint16_t i = 0; i < length; i++) + Serial.print(payload[i]); +}; +``` + +Register the `receiver_function` as the receiver callback: +```cpp +PJONSoftwareBitBang bus; +bus.set_receiver(receiver_function); +``` + +Within `receiver_function` it is possible to process data and meta-data when a packet is received. The [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) struct contains all the protocol fields present in the packet: + +The code below is part of the Arduino compatible [PortsUseExample](/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Receiver/Receiver.ino). When the `receiver_function` is called meta-data present in the `info` parameter is printed in the serial monitor: +```cpp +void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &info) { Serial.print("Header: "); - Serial.print(packet_info.header, BIN); + Serial.print(info.header, BIN); // If packet formatted for a shared medium - if(packet_info.header & PJON_MODE_BIT) { + if(info.header & PJON_MODE_BIT) { Serial.print(" Receiver bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(info.rx.bus_id[0]); + Serial.print(info.rx.bus_id[1]); + Serial.print(info.rx.bus_id[2]); + Serial.print(info.rx.bus_id[3]); Serial.print(" Receiver id: "); - Serial.print(packet_info.receiver_id); + Serial.print(info.rx.id); // If sender info is included - if(packet_info.header & PJON_TX_INFO_BIT) { + if(info.header & PJON_TX_INFO_BIT) { Serial.print(" Sender bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(info.tx.bus_id[0]); + Serial.print(info.tx.bus_id[1]); + Serial.print(info.tx.bus_id[2]); + Serial.print(info.tx.bus_id[3]); } } // If sender device id is included - if(packet_info.header & PJON_TX_INFO_BIT) { + if(info.header & PJON_TX_INFO_BIT) { Serial.print(" Sender id: "); - Serial.print(packet_info.sender_id); + Serial.print(info.tx.id); } // Payload Length Serial.print(" Length: "); Serial.print(length); // If port id is included - if(packet_info.header & PJON_PORT_BIT) { + if(info.header & PJON_PORT_BIT) { Serial.print(" Port bit: "); - Serial.print(packet_info.port); + Serial.print(info.port); } Serial.println(); -} -``` -Register the `receiver_function` as the receiver callback: -```cpp -bus.set_receiver(receiver_function); +}; ``` +Use `payload` before any transmission, the buffer where `payload` points to is overwritten when a new packet is dispatched. -To pass custom data to the receiver callback function, se the [ClassMemberCallback](../examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback) example. This feature can be used for a lot of different use cases. Could be used to let multiple PJON objects call the same callback function, passing an `int` specifying which PJON instance has to be called, or a pointer to the PJON object, or an `enum` or whatever. +To understand how to pass custom data to the receiver callback function, see the [ClassMemberCallback](../examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback) example. This feature can be used to link other classes or instances passing any sort of data structure. -To receive the `receive` function must be called at least once per loop cycle: +To receive data the `receive` function must be called as often as possible: ```cpp uint16_t response = bus.receive(); ``` @@ -69,8 +90,8 @@ uint16_t response = bus.receive(); - `PJON_BUSY` (666) if a transmission for other devices is occurring - `PJON_FAIL` (65535) if no data is received -If you want to dedicate a certain timeframe to reception call the `receive` function passing the maximum reception time in microseconds: +If it is required to dedicate a certain time to reception call the `receive` function passing the maximum reception time in microseconds: ```cpp uint16_t response = bus.receive(1000); ``` -Consider that SoftwareBitBang, OverSampling or AnalogSampling are strategies able receive data only while `bus.receive` is being executed, otherwise data is lost and transmitter will try again in future. In this particular case it is mandatory to dedicate a certain timeframe, depending on the duration of the other tasks, to efficiently receive data and avoid repetitions. +Consider that SoftwareBitBang, OverSampling or AnalogSampling are strategies able to receive data only while `bus.receive` is being executed, otherwise data is lost and transmitter will try again in future. In this particular case it is mandatory to dedicate a certain timeframe, depending on the duration of the other tasks, to efficiently receive data and avoid repetitions. diff --git a/documentation/data-structures.md b/documentation/data-structures.md new file mode 100644 index 0000000000..0d309bfc5e --- /dev/null +++ b/documentation/data-structures.md @@ -0,0 +1,50 @@ + +### Documentation index +- [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) +- [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) +- [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- **[Data structures](/documentation/data-structures.md)** + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) +- [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) +- [Error handling](/documentation/error-handling.md) + - [`set_error`](/documentation/error-handling.md#error-handling) +- [Routing](/documentation/routing.md) + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) +--- + +## Data structures + +### `PJON_Endpoint` +`PJON_Endpoint` contains the device id, bus id and MAC address of a device: +```cpp +struct PJON_Endpoint { + uint8_t id = PJON_NOT_ASSIGNED; + uint8_t bus_id[4] = {0, 0, 0, 0}; + uint8_t mac[6] = {0, 0, 0, 0, 0, 0}; +}; +``` +`PJON_Endpoint` contains `mac` if [`PJON_INCLUDE_MAC`](/documentation/configuration.md#hardware-identification) is defined. The conditional inclusion is present to reduce the footprint of programs where the MAC address is not used. + +### `PJON_Packet_Info` +`PJON_Packet_Info` contains all meta-data supported by the PJON packet format. The `tx` and `rx` data structures of type `PJON_Endpoint` contain the transmitter and receiver information. + +```cpp +struct PJON_Packet_Info { + PJON_Endpoint tx; + PJON_Endpoint rx; + void *custom_pointer; + uint8_t header = PJON_NO_HEADER; + uint8_t hops = 0; + uint16_t id = 0; + uint16_t port = PJON_BROADCAST; +}; +``` +`PJON_Packet_Info` contains `port` if [`PJON_INCLUDE_PORT`](/documentation/configuration.md#network-service-identification) is defined and `id` if [`PJON_INCLUDE_PACKET_ID`](/documentation/configuration.md#packet-identification) is defined. The conditional inclusion is present to reduce the footprint of programs where the port and the packet id are not used. + +The `custom_pointer` can be used to link other classes or instances passing any sort of data structure. To understand how to use it see the [ClassMemberCallback](../examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback) example. diff --git a/documentation/data-transmission.md b/documentation/data-transmission.md index ac40cc2f9d..2c7cc76e5d 100644 --- a/documentation/data-transmission.md +++ b/documentation/data-transmission.md @@ -1,125 +1,218 @@ ### Documentation index - [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - **[Data transmission](/documentation/data-transmission.md)** + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - [Error handling](/documentation/error-handling.md) -- [IO setup](/documentation/io-setup.md) + - [`set_error`](/documentation/error-handling.md#error-handling) - [Routing](/documentation/routing.md) - + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## Data transmission -The begin function must be called before starting communication, the lack of this call can lead to collisions after boot, so be sure to call it before making use of the instance. + +### `begin` +The `begin` method must be called before starting communication, the lack of this call can lead to collisions so be sure not to forget it: ```cpp bus.begin(); ``` -The simplest way to send data is to use `send_packet`, this method composes the packet and tries to send it once. The first parameter is the device id of the recipient of type `uint8_t`, optionally you can pass the bus id of type `uint8_t *`, then follows the payload of type `const void *` and its length of type `uint16_t`. This call implies a single attempt and has no guarantee of success, but logs the result of the attempted transmission: -```cpp -// Local +### `send_packet` + +| Buffered | Blocking | Attempts | +| -------- | -------- | -------- | +| No | Yes | 1 | + +The simplest way to send data is to use `send_packet`, this method composes the packet and tries to send it once. Consider that if the bus is busy or interference is present the transmission may not be attempted. The method returns the result of its operation. The first parameter is the device id of the recipient of type `uint8_t`, the second is the payload of type `const void *` and the third is the length of type `uint16_t`. This call implies a single attempt and has no guarantee of success, but logs the result of the attempted transmission: +```cpp // Send to device id 10 the string "Hi!" bus.send_packet(10, "Hi!", 3); - +``` + The `send_packet` method can receive 3 optional parameters, the header of type `uint8_t`, a packet id of type `uint16_t` (pass 0 if you want to avoid the packet id inclusion) and a port of type `uint16_t`. In the example below a packet containing the payload "Hello" is sent to device id 10 using the actual instance's header configuration, without including the packet id and including the port `8002`. +```cpp // All optional parameters available bus.send_packet( 10, // Device id (uint8_t) "Hello", // Payload (const void *) - 12, // Length (uint16_t) + 5, // Length (uint16_t) bus.config, // Header (uint8_t) - Use default config 0, // Packet id (uint16_t) - Don't include packet id 8002 // Port (uint16_t) ); +``` + +The `send_packet` method accepts any kind of data, in the example below a custom `struct` is sent to device id 1: +```cpp +// Define a custom data type +struct voltage_record { uint16_t v1; uint16_t v2; }; +// Fill it with information +voltage_record record; +record.v1 = analogRead(A1); +record.v2 = analogRead(A2); +// Send to device id 1 the record struct +bus.send_packet(1, &record, sizeof(record)); +``` + +`send_packet` returns the following values: +- `PJON_ACK` (6) if transmission occurred and acknowledgement is received if requested +- `PJON_BUSY` (666) if bus is busy +- `PJON_FAIL` (65535) if transmission failed + +The `send_packet` return value, of type `uint16_t`, can be used to determine if the transmission occurred successfully or not: +```cpp +uint16_t result = bus.send_packet(10, "All is ok?!", 11); + +if(result == PJON_ACK) Serial.println("10 is ok!"); +``` + +To broadcast a message to all connected devices, use the `PJON_BROADCAST` constant as recipient ID: +```cpp +bus.send_packet(PJON_BROADCAST, "Message for all connected devices.", 34); +``` + +If you need to transmit in shared mode or configure other protocol fields you can use `send_packet` passing a struct of type [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info), the payload of type `const void *` and the length of type `uint16_t`: +```cpp +uint8_t bus_id[4] = {0, 0, 0, 1}; +PJON_Packet_Info info; +info.rx.id = 10; // The recipient's device id is 10 +info.rx.port = 8000; // The packet includes the port 8000 +memcpy(info.rx.bus_id, bus_id, 4); // Copy recipient's bus id in info +bus.send_packet(info, "Ciao!", 5); +``` -// Shared or using bus indexing +### `send_packet_blocking` -// Send to bus id 0.0.0.1 - device id 10 the string "Hi!" -uint8_t bus_id[] = {0, 0, 0, 1}; -bus.send_packet(10, bus_id, "Hi!", 3); +| Buffered | Blocking | Attempts | +| -------- | -------- | ----------------------------- | +| No | Yes | `strategy.get_max_attempts()` | +Use `send_packet_blocking` if it is necessary to try until the packet is effectively received by the recipient or a maximum amount of retries is reached. Consider that the method may block the operation of the program for up to 4 seconds in case of transmission failure. + +```cpp +// Send to device id 10 the string "Hi!" +bus.send_packet_blocking(10, "Hi!", 3); +``` +The `send_packet_blocking` method can receive 4 optional parameters, the header of type `uint8_t`, a packet id of type `uint16_t` (pass 0 if you want to avoid the packet id inclusion), a port of type `uint16_t` and a timeout of type `uint32_t`. In the example below a packet containing the payload "Hello" is sent to device id 10 using the actual instance's header configuration, without including the packet id, including the port `8002` and passing a maximum timeout of 1 second: +```cpp // All optional parameters available -bus.send_packet( +bus.send_packet_blocking( 10, // Device id (uint8_t) - bus_id, // Bus id (uint8_t *) "Hello", // Payload (const void *) - 12, // Length (uint16_t) + 5, // Length (uint16_t) bus.config, // Header (uint8_t) - Use default config 0, // Packet id (uint16_t) - Don't include packet id - 8002 // Port (uint16_t) + 8002, // Port (uint16_t) + 1000000 // Timeout (uint32_t) - 1 second ); ``` -The sending is executed as soon as the method is called and it returns the following values: +The `send_packet_blocking` method accepts any type of data, in the example below a custom `struct` is sent to device id 1: +```cpp +// Define a custom data type +struct voltage_record { uint16_t v1; uint16_t v2; }; +// Fill it with information +voltage_record record; +record.v1 = analogRead(A1); +record.v2 = analogRead(A2); +// Send to device id 1 the record struct +bus.send_packet_blocking(1, &record, sizeof(record)); +``` + +`send_packet_blocking` returns the following values: - `PJON_ACK` (6) if transmission occurred and acknowledgement is received if requested - `PJON_BUSY` (666) if bus is busy - `PJON_FAIL` (65535) if transmission failed +The `send_packet_blocking` return value, of type `uint16_t`, can be used to determine if the transmission occurred successfully or not: ```cpp -// Use the value returned by send_packet to determine transmission result - -// Local -if(bus.send_packet(10, "All is ok?!", 11) == PJON_ACK) - Serial.println("10 is ok!"); +uint16_t result = bus.send_packet_blocking(10, "All is ok?!", 11); -// Shared or using bus indexing -if(bus.send_packet(10, bus_id, "All is ok?!", 11) == PJON_ACK) - Serial.println("10 is ok!"); +if(result == PJON_ACK) Serial.println("10 is ok!"); ``` -To broadcast a message to all connected devices, use the `PJON_BROADCAST` constant as recipient ID: +If you need to transmit in shared mode or configure other protocol fields you can use `send_packet_blocking` passing a struct of type [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info), the payload of type `const void *` and the length of type `uint16_t`: ```cpp -bus.send_packet(PJON_BROADCAST, "Message for all connected devices.", 34); +uint8_t bus_id[4] = {0, 0, 0, 1}; +PJON_Packet_Info info; +info.rx.id = 10; // The recipient's device id is 10 +info.rx.port = 8000; // The packet includes the port 8000 +memcpy(info.rx.bus_id, bus_id, 4); // Copy recipient's bus id in info +bus.send_packet_blocking(info, "Ciao!", 5); ``` -Use `send_packet_blocking` if it is necessary to try until the packet is effectively received by the recipient and so comply with the specified back-off. -```cpp -// Send to device id 10 the string "Hi!" -bus.send_packet_blocking(10, "Hi!", 3); +### `send` -// Use the value returned by send_packet to determine transmission result -if(bus.send_packet_blocking(10, "All is ok?!", 11) == PJON_ACK) - Serial.println("10 is ok!"); -``` -`send_packet_blocking` returns the result of transmission as `send_packet` does. +| Buffered | Blocking | Attempts | +| -------- | -------- | ----------------------------- | +| Yes | No | `strategy.get_max_attempts()` | -PJON can also optionally handle packets for you, although a little more memory is required. The first thing to do and never forget is to call the `update()` function once per loop cycle: +When using the `send` method, PJON operates using its internal buffer, although a little more memory is required, this call is non-blocking and automatically handles back-off. The first thing to do and never forget is to call the `update` method once per loop cycle: ```cpp bus.update(); ``` -To send data to another device connected to the bus simply call `send` passing the recipient's id (and its bus id if necessary), the payload you want to send and its length: +Every time `update` is called the transmission is attempted for each packet present in the buffer. + +To send data to another device connected to the bus simply call `send` passing the device id of the recipient of type `uint8_t` then the payload of type `const void *` and its length of type `uint16_t`. The return value of `send` of type `uint16_t` is the index of the packet in the `packets` buffer or `PJON_FAIL` in case of error. ```cpp -// Local bus.send(100, "Ciao, this is a test!", 21); - -// Shared or using bus indexing -uint8_t bus_id[] = {0, 0, 0, 1}; -bus.send(100, bus_id, "Ciao, this is a test!", 21); - -// All optional parameters available - -// Local mode -bus.send( - 100, // (uint8_t) Recipient device id - "Test port id", // (const void *) Payload - 23, // (uint16_t) Length - bus.config, // (uint8_t) Packet header - 1, // (uint16_t) Packet id - 8002 // (uint16_t) Port identification -); - +``` +`send` can receive 3 optional parameters, the header of type `uint8_t`, a packet id of type `uint16_t` (pass 0 if you want to avoid the packet id inclusion) and a port of type `uint16_t`. In the example below a packet containing the payload "Hello" is sent to device id 2 using the actual instance's header configuration, without including the packet id and including the port `8002`: +```cpp // Shared mode or using bus indexing bus.send( - 100, // (uint8_t) Recipient device id - bus_id, // (uint8_t *) Recipient bus id - "Test port id", // (const void *) Payload - 23, // (uint16_t) Length - bus.config, // (uint8_t) Packet header - 1, // (uint16_t) Packet id - 8002 // (uint16_t) Port identification + 2, // (uint8_t) Recipient device id + "Hello", // (const void *) Payload + 5, // (uint16_t) Length + bus.config, // (uint8_t) Packet header + 0, // (uint16_t) Packet id + 8002 // (uint16_t) Port identification ); +``` + +The `send` method accepts any type of data, in the example below a custom `struct` is sent to device id 1: +```cpp +// Define a custom data type +struct voltage_record { uint16_t v1; uint16_t v2; }; +// Fill it with information +voltage_record record; +record.v1 = analogRead(A1); +record.v2 = analogRead(A2); +// Send to device id 1 the record struct +bus.send(1, &record, sizeof(record)); +``` + +To use the return value of `send` just save it in a variable of type `uint16_t`: +```cpp +uint16_t packet = bus.send(100, "Ciao, this is a test!", 21); +if(packet == PJON_FAIL) Serial.print("Something went wrong"); ``` -Payload length is boring to be added but is there to prevent buffer overflow. If sending arbitrary values `NULL` terminator strategy based on `strlen` is not safe to detect the end of a string. The `send` call returns an id, that is the reference to the packet you have dispatched. To send a value repeatedly simply call `send_repeatedly` and pass as last parameter the interval in microseconds you want between every sending: + +If you need to transmit in shared mode or configure other protocol fields you can use `send` passing a struct of type [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info), the payload of type `const void *` and the length of type `uint16_t`: +```cpp +uint8_t bus_id[4] = {0, 0, 0, 1}; +PJON_Packet_Info info; +info.rx.id = 10; // The recipient's device id is 10 +info.rx.port = 8000; // The packet includes the port 8000 +memcpy(info.rx.bus_id, bus_id, 4); // Copy recipient's bus id in info +bus.send(info, "Ciao!", 5); +``` + +### `send_repeatedly` + +| Buffered | Blocking | Attempts | +| -------- | -------- | ----------------------------- | +| Yes | No | `strategy.get_max_attempts()` | + +The `send_repeatedly` method can be used when it is required to schedule a repeated transmission. The first parameter is the device id of the recipient of type `uint8_t` then follows the payload of type `const void *`, its length of type `uint16_t` and the interval of type `uint32_t`: ```cpp // Local sending example uint16_t one_second_test = @@ -127,20 +220,138 @@ uint16_t one_second_test = /* IMPORTANT: maximum interval supported is 4293014170 microseconds or 71.55 minutes */ -// Shared sending example including all optional parameters -uint16_t one_second_test_shared = - bus.send_repeatedly( - 100, // (uint8_t) Recipient device id - bus_id, // (uint8_t *) Recipient bus id - "Test port id", // (const void *) Payload - 23, // (uint16_t) Length - 1000000, // (uint32_t) Interval in microseconds - bus.config, // (uint8_t) Packet header - 1, // (uint16_t) Packet id - 8002 // (uint16_t) Port identification - ); -``` -`send_repeatedly` returns the id of the packet in the packet's buffer as `send` does, to remove this repeated transmission simply: +``` +`send_repeatedly` returns the index of the packet in the `packets` buffer as `send` does, to remove the repeated transmission simply call: ```cpp bus.remove(one_second_test); ``` +`send_repeatedly` can receive 3 optional parameters: the header of type `uint8_t`, a packet id of type `uint16_t` (pass 0 if you want to avoid the packet id inclusion) and a port of type `uint16_t`. In the example below a packet containing the payload "Hello" is sent to device id 2 every second using the actual instance's header configuration, without including the packet id and including the port `8002`: +```cpp +// Shared mode or using bus indexing +bus.send_repeatedly( + 2, // (uint8_t) Recipient device id + "Hello", // (const void *) Payload + 5, // (uint16_t) Length + 1000000 // (uint32_t) Interval + bus.config, // (uint8_t) Packet header + 0, // (uint16_t) Packet id + 8002 // (uint16_t) Port identification +); +``` +The `send_repeatedly` method accepts any type of data, in the example below a custom `struct` is sent to device id 1: +```cpp +// Define a custom data type +struct voltage_record { uint16_t v1; uint16_t v2; }; +// Fill it with information +voltage_record record; +record.v1 = analogRead(A1); +record.v2 = analogRead(A2); +// Send to device id 1 the record struct +bus.send_repeatedly(1, &record, sizeof(record)); +``` + +If you need to transmit in shared mode or configure other protocol fields you can use `send_repeatedly` passing a struct of type [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info), the payload of type `const void *`, the length of type `uint16_t` and the interval of type `uint32_t`: +```cpp +uint8_t bus_id[4] = {0, 0, 0, 1}; +PJON_Packet_Info info; +info.rx.id = 10; // The recipient's device id is 10 +info.rx.port = 8000; // The packet includes the port 8000 +memcpy(info.rx.bus_id, bus_id, 4); // Copy recipient's bus id in info +bus.send_repeatedly(info, "Ciao!", 5, 1000000); // Send "Ciao!" every second +``` + +### `reply` + +| Buffered | Blocking | Attempts | +| -------- | -------- | ----------------------------- | +| Yes | No | `strategy.get_max_attempts()` | + +The `reply` method can be called within the [receiver function](/documentation/data-reception.md#data-reception) to reply to a packet received previously: +```cpp +bus.reply("All fine!", 9); +``` +Consider that `reply` dispatches a packet in the buffer like `send` or `send_repeatedly`. To use the return value of `send` just save it in a variable of type `uint16_t`: +```cpp +uint16_t packet = bus.reply("Ciao, this is a test!", 21); +if(packet == PJON_FAIL) Serial.print("Something went wrong"); +``` +The `reply` method accepts any type of data, in the example below a custom struct is sent to device id 1: +```cpp +// Define a custom data type +struct voltage_record { uint16_t v1; uint16_t v2; }; +// Fill it with information +voltage_record record; +record.v1 = analogRead(A1); +record.v2 = analogRead(A2); +// Reply with the record struct +bus.reply(&record, sizeof(record)); +``` + +### `reply_blocking` + +| Buffered | Blocking | Attempts | +| -------- | -------- | ----------------------------- | +| No | Yes | `strategy.get_max_attempts()` | + +The `reply_blocking` method can be called within the [receiver function](/documentation/data-reception.md#data-reception) to reply to a packet received previously: +```cpp +bus.reply_blocking("All fine!", 9); +``` +Consider that `reply_blocking` is a blocking procedure that in case of failure can last a considerable amount of time. The `reply_blocking` result, of type `uint16_t`, can be used to determine if the transmission occurred successfully or not: +```cpp +uint16_t result = bus.reply_blocking("All is ok!", 11); +if(result == PJON_ACK) Serial.println("Responded successfully!"); +``` +The `reply_blocking` method accepts any type of data, in the example below a custom `struct` is sent to device id 1: +```cpp +// Define a custom data type +struct voltage_record { uint16_t v1; uint16_t v2; }; +// Fill it with information +voltage_record record; +record.v1 = analogRead(A1); +record.v2 = analogRead(A2); +// Reply with the record struct +bus.reply_blocking(&record, sizeof(record)); +``` + +### `forward` + +| Buffered | Blocking | Attempts | +| -------- | -------- | ----------------------------- | +| Yes | No | `strategy.get_max_attempts()` | + +The `forward` method can retransmit a packet received previously to another device using its original sender's identification. It is useful to implement switching or routing features: +```cpp +void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &info) { + bus.forward(info, payload, length); + // Forward each packet is received +}; +``` + +Consider that `forward` dispatches a packet in the buffer like `send` or `send_repeatedly`. To use the return value of `forward` just save it in a variable of type `uint16_t`: +```cpp +uint16_t packet = bus.forward(info, payload, length); +if(packet == PJON_FAIL) Serial.print("Something went wrong"); +``` +The `forward` method accepts any type of data like `send` or `send_repeatedly`. + +### `forward_blocking` + +| Buffered | Blocking | Attempts | +| -------- | -------- | ----------------------------- | +| No | Yes | `strategy.get_max_attempts()` | + +The `forward_blocking` method can retransmit a packet received previously to another device using its original sender's identification. It is useful to implement switching or routing features: +```cpp +void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &info) { + bus.forward_blocking(info, payload, length); + // Forward each packet is received +}; +``` + +Consider that `forward_blocking` is a blocking procedure that in case of failure can last a considerable amount of time. The `forward_blocking` result, of type `uint16_t`, can be used to determine if the transmission occurred successfully or not: +```cpp +uint16_t result = bus.forward_blocking(info, payload, length); +if(result == PJON_ACK) Serial.println("Responded successfully!"); +``` +The `forward_blocking` method accepts any type of data like `send` or `send_repeatedly`. diff --git a/documentation/error-handling.md b/documentation/error-handling.md index f3e9f122d5..54e6d528b3 100644 --- a/documentation/error-handling.md +++ b/documentation/error-handling.md @@ -1,22 +1,30 @@ ### Documentation index - [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - **[Error handling](/documentation/error-handling.md)** -- [IO setup](/documentation/io-setup.md) + - [`set_error`](/documentation/error-handling.md#error-handling) - [Routing](/documentation/routing.md) - + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## Error handling PJON is designed to inform the user if an error is detected. A function of type `void` can be defined and registered to be called by the PJON object in case of error; it receives 3 parameters, the first is the error code of type `uint8_t`, the second is additional data related to the error of type `uint16_t` and the third is a general purpose custom pointer of type `void *`. Error types: -- `PJON_CONNECTION_LOST` (value 101), `data` parameter contains lost packet's index in the packets buffer. -- `PJON_PACKETS_BUFFER_FULL` (value 102), `data` parameter contains buffer length. -- `PJON_CONTENT_TOO_LONG` (value 104), `data` parameter contains content length. +- `PJON_CONNECTION_LOST` or 101, `data` parameter contains lost packet's index in the buffer. +- `PJON_PACKETS_BUFFER_FULL` or 102, `data` parameter contains buffer length. +- `PJON_CONTENT_TOO_LONG` or 104, `data` parameter contains content length. ```cpp void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { diff --git a/documentation/io-setup.md b/documentation/io-setup.md index 911c3dfa0e..f4fe9f822b 100644 --- a/documentation/io-setup.md +++ b/documentation/io-setup.md @@ -1,31 +1,39 @@ ### Documentation index - [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - [Error handling](/documentation/error-handling.md) -- **[IO setup](/documentation/io-setup.md)** + - [`set_error`](/documentation/error-handling.md#error-handling) - [Routing](/documentation/routing.md) - + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- **[IO setup](/documentation/io-setup.md)** + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## IO setup The physical layer configuration is handled by the [strategy](/src/strategies/README.md) entity, if you want to communicate bi-directionally on a single pin with [SoftwareBitBang](/src/strategies/SoftwareBitBang) or [AnalogSampling](/src/strategies/AnalogSampling) use: ```cpp - PJON bus; + PJONSoftwareBitBang bus; bus.strategy.set_pin(12); ``` With this setup it is possible to communicate in `PJON_HALF_DUPLEX` mode with up to 254 different devices on the same physical pin. If for some reason you need to keep separate the two lines, for example if using [OverSampling](/src/strategies/OverSampling) with separate radio transmitter and receiver modules, you can pass 2 separate pins: ```cpp - PJON bus; + PJONOverSampling bus; bus.strategy.set_pins(11, 12); ``` If you don't need bidirectional communication and you have only the transmitter on one side and the receiver on the other side you can use the `PJON_NOT_ASSIGNED` constant: ```cpp - PJON bus; + PJONOverSampling bus; // Operate in simplex mode bus.set_communication_mode(PJON_SIMPLEX); // Use only receiver pin diff --git a/documentation/routing.md b/documentation/routing.md index 1f88ac6252..e366af1186 100644 --- a/documentation/routing.md +++ b/documentation/routing.md @@ -1,89 +1,67 @@ ### Documentation index - [Addressing](/documentation/addressing.md) + - [`set_id`](/documentation/addressing.md#local-mode) [`device_id`](/documentation/addressing.md#local-mode) [`get_bus_id`](/documentation/addressing.md#shared-mode) [`set_bus_id`](/documentation/addressing.md#shared-mode) [`get_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) [`set_mac`](/documentation/addressing.md#get-or-set-hardware-identifier) - [Configuration](/documentation/configuration.md) + - [`set_communication_mode`](/documentation/configuration.md#communication-mode) [`set_shared_network`](/documentation/configuration.md#network-mode) [`set_router`](/documentation/configuration.md#router-mode) [`include_sender_info`](/documentation/configuration.md#sender-information) [`set_crc_32`](/documentation/configuration.md#crc-configuration) [`set_packet_auto_deletion`](/documentation/configuration.md#packet-handling) [`set_acknowledge`](/documentation/configuration.md#acknowledgement) [`set_packet_id`](/documentation/configuration.md#packet-identification) [`include_port`](/documentation/configuration.md#network-service-identification) [`include_mac`](/documentation/configuration.md#hardware-identification) - [Data reception](/documentation/data-reception.md) + - [`set_receiver`](/documentation/data-reception.md#data-reception) [`receive`](/documentation/data-reception.md#data-reception) +- [Data structures](/documentation/data-structures.md) + - [`PJON_Endpoint`](/documentation/data-structures.md#pjon_endpoint) [`PJON_Packet_Info`](/documentation/data-structures.md#pjon_packet_info) - [Data transmission](/documentation/data-transmission.md) + - [`begin`](/documentation/data-transmission.md#begin) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`send`](/documentation/data-transmission.md#send) [`send_packet`](/documentation/data-transmission.md#send_packet) [`send_packet_blocking`](/documentation/data-transmission.md#send_packet_blocking) [`send_repeatedly`](/documentation/data-transmission.md#send_repeatedly) [`reply`](/documentation/data-transmission.md#reply) [`reply_blocking`](/documentation/data-transmission.md#reply_blocking) [`forward`](/documentation/data-transmission.md#forward) [`forward_blocking`](/documentation/data-transmission.md#forward_blocking) - [Error handling](/documentation/error-handling.md) -- [IO setup](/documentation/io-setup.md) + - [`set_error`](/documentation/error-handling.md#error-handling) - **[Routing](/documentation/routing.md)** + - [`PJONSimpleSwitch`](/documentation/routing.md#simpleswitch) [`PJONSwitch`](/documentation/routing.md#switch) [`PJONRouter`](/documentation/routing.md#router) [`PJONDynamicRouter`](/documentation/routing.md#dynamicrouter) [`PJONInteractiveRouter`](/documentation/routing.md#interactiverouter) +- [IO setup](/documentation/io-setup.md) + - [`strategy`](/documentation/io-setup.md#io-setup) --- ## Routing -Transparent routing based on a tree topology has been implemented by Fred Larsen with the [PJONSimpleSwitch](#simpleswitch), [PJONSwitch](#switch), [PJONRouter](#router), [PJONDynamicRouter](#dynamicrouter), [PJONInteractiveRouter](#interactiverouter) and [PJONVirtualBusRouter](#virtual-bus). +Transparent routing based on a tree topology that may include loops has been implemented by Fred Larsen with the [PJONSimpleSwitch](#simpleswitch), [PJONSwitch](#switch), [PJONRouter](#router), [PJONDynamicRouter](#dynamicrouter), [PJONInteractiveRouter](#interactiverouter) and [PJONVirtualBusRouter](#virtual-bus). ### SimpleSwitch -The [PJONSimpleSwitch](/examples/ARDUINO/Local/SoftwareBitBang/Switch/SimpleSwitch) class connects two buses using the same strategy. In this example a `SoftwareBitBang` <=> `SoftwareBitBang` switch is created. It can be used to amplify signals and so extend the maximum range or in more complex setups selectively switch packets as requested by its configuration. It can be used instead of `PJONSwitch` to save memory when the same strategy is used in all buses. It avoids virtual inheritance so it is faster and has a smaller footprint. +The [PJONSimpleSwitch](/examples/routing/ARDUINO/Network/Switch/SimpleSwitch/SimpleSwitch.ino) class connects two or more buses using the same strategy. In this example a `SoftwareBitBang` <=> `SoftwareBitBang` switch is created. It can be used to amplify signals and so extend the maximum range or in more complex setups selectively switch packets as requested by its configuration. It can be used instead of `PJONSwitch` to save memory when the same strategy is used in all buses. It avoids virtual inheritance so it is faster and has a smaller footprint. ```cpp - __________ ________ __________ -| | SWBB bus | | SWBB bus | | -| DEVICE 1 |___________| SWITCH |____________| DEVICE 2 | -|__________| |________| |__________| +/* __________ ________ __________ + | | Pin 7 | | Pin 12 | | + | DEVICE 1 |_______________| SWITCH |_______________| DEVICE 2 | + |__________| Bus 0.0.0.1 |________| Bus 0.0.0.2 |__________| */ + ``` -The first thing to do is to include the `PJONSimpleSwitch` class: +The first thing to do is to include `PJONSimpleSwitch` and the required strategy: ```cpp #include +#include ``` -The `SimpleSwitch` class provides with configurable transparent packet switching between buses using the same strategy. `SimpleSwitch` requires a tree topology (it does not contain any loop detection procedure). The `SimpleSwitch` class receives as a parameter the length and the array of 2 or more `PJONBus` instances: -```cpp -/* In both cases the switch does not have an assigned id it is - transparently switching packets in both directions */ -PJONBus bus1(PJON_NOT_ASSIGNED); -PJONBus bus2(PJON_NOT_ASSIGNED); -``` -Polling time can be optionally configured: -```cpp -PJONBus bus2( - PJON_NOT_ASSIGNED, // Switch device id - 1000 // Polling time in microseconds -); -``` -Device id ranges can be optionally configured: -```cpp -PJONBus bus2( - PJON_NOT_ASSIGNED, // Switch device id - 1000, // Polling time in microseconds - 2, // 2 ranges present (1-127, 128-254) - 0, // range 1 in use here (1-127) -); -``` -After the `PJONBus` definitions, a `PJONSimpleSwitch` instance can be created: +The `SimpleSwitch` class provides with configurable transparent packet switching between buses using the same strategy: ```cpp -// PJONSimpleSwitch definition: -PJONSimpleSwitch router( - 2, // Length of the bus array - (PJONBus*[2]){&bus1,&bus2} // Bus array -); -``` -A default gateway can be optionally configured: -```cpp -PJONSimpleSwitch router( - 2, // Length of the bus array - (PJONBus*[2]){&bus1,&bus2}, // Bus array - 122 // Statically defined default gateway device id -); +PJON bus1((const uint8_t[4]){0, 0, 0, 1}, PJON_NOT_ASSIGNED), + bus2((const uint8_t[4]){0, 0, 0, 2}, PJON_NOT_ASSIGNED); + +PJONSimpleSwitch router(bus1, bus2); + ``` -Configure each strategy and the `router` instance as required: +In the example above two PJON instances using SoftwareBitBang, operating in shared mode, with bus id `0.0.0.1` and `0.0.0.2` are merged with the `SimpleSwitch` instance. Packets are switched between the two buses. In the `setup` just include strategy related configuration, for example the pin used for communication: + ```cpp void setup() { - // Set each SoftwareBitBang bus pin connection bus1.strategy.set_pin(7); bus2.strategy.set_pin(12); router.begin(); } -``` -Call the `loop` function as often as possible to achieve optimal performance: -```cpp void loop() { router.loop(); -}; +} ``` +Then the `PJONSimpleSwitch` should work transparently. `PJONSimpleSwitch` can be used also in local mode, although, because the hop count field is not included, the network topology cannot include loops. ### Switch -The [PJONSwitch](/examples/ARDUINO/Local/SoftwareBitBang/Switch/Switch) class transparently switches packets between locally attached buses also if different strategies or media are in use. It supports a default gateway to be able to act as a leaf in a larger network setup. Thanks to the `PJONSwitch` class, with few lines of code, a switch that operates multiple strategies can be created. In this example a `SoftwareBitBang` <=> `AnalogSampling` switch is created: +[PJONSwitch](/examples/routing/ARDUINO/Network/Switch/Switch) transparently switches packets between locally attached buses also if different strategies or media are in use. It supports a default gateway to be able to act as a leaf in a larger network setup. Thanks to the `PJONSwitch` class, with few lines of code, a switch that operates multiple strategies can be created. In this example a `SoftwareBitBang` <=> `AnalogSampling` switch is created: ```cpp /* Connect SoftwareBitBang bus with an AnalogSampling bus: @@ -92,51 +70,25 @@ The [PJONSwitch](/examples/ARDUINO/Local/SoftwareBitBang/Switch/Switch) class tr |DEVICE1|_______________|SWITCH| _ _ _ _ _ _ _|DEVICE2| |_______|BUS ID 0.0.0.1 |______|BUS ID 0.0.0.2|_______| */ ``` -The first thing to do is to include the `PJONSwitch` class: +First include the `PJONSwitch` class and the strategies used: ```cpp #include +#include +#include ``` -Create `StrategyLink` instances with the selected strategies: -```cpp -StrategyLink link1; -StrategyLink link2; -``` -Create `PJONAny` instances configuring the bus id: +The simplest way to use the `PJONSwitch` class is to use `PJONSwitch2` that is able to handle up to 2 buses: ```cpp -PJONAny bus1(&link1, (uint8_t[4]){0, 0, 0, 1}); -PJONAny bus2(&link2, (uint8_t[4]){0, 0, 0, 2}); +PJONSwitch2 router; ``` -Polling time can be optionally configured: +Use `get_strategy_0` and `get_strategy_1` to access one of the two strategies: ```cpp -PJONAny bus1( - &link1, - (uint8_t[4]){0,0,0,1}, - PJON_NOT_ASSIGNED, // Switch device id - 1000 // Polling in microseconds -); +router.get_strategy_0().set_pin(12); // SoftwareBitBang pin used is 12 +router.get_strategy_1().set_pin(A0); // AnalogSampling pin used is A0 ``` -Device id ranges can be optionally configured: +Use `get_bus` to access one of the two instances: ```cpp -PJONAny bus1( - &link1, - (uint8_t[4]){0,0,0,1}, - PJON_NOT_ASSIGNED, // Switch device id - 1000, // Polling in microseconds - 2, // 2 ranges present (1-127, 128-254) - 0 // Range 1 in use (1-127) -); -``` -Create the `PJONSwitch` instance passing the `PJONAny` instances: -```cpp -PJONSwitch router(2, (PJONAny*[2]){&bus1, &bus2}); -``` -Configure each strategy and the `router` instance as required: -```cpp -void setup() { - link1.strategy.set_pin(12); - link2.strategy.set_pin(A0); - router.begin(); -} +router.get_bus(0).set_bus_id((const uint8_t[4]){0, 0, 0, 1}); +router.get_bus(1).set_bus_id((const uint8_t[4]){0, 0, 0, 2}); ``` Call the `loop` function as often as possible to achieve optimal performance: ```cpp @@ -144,8 +96,11 @@ void loop() { router.loop(); } ``` + +Consider that there is also `PJONSwitch3` able to handle up to 3 buses, and `PJONSwitch` able to handle an array of buses. `PJONSwitch` can be used also in local mode, although, because the hop count field is not included, the network topology cannot include loops. + ### Router -The [PJONRouter](/examples/ARDUINO/Network/SoftwareBitBang/Router) class routes between both locally attached buses also if different strategies or media are in use, and remote buses reachable through the locally attached buses. In this example simple a router is created: +The [PJONRouter](/examples/routing/ARDUINO/Network/Router/Router) class routes between both locally attached buses also if different strategies or media are in use, and remote buses reachable through the locally attached buses using a static routing table. In this example simple a router is created: ```cpp ________ Bus 0.0.0.3 | | Bus 0.0.0.4 @@ -158,33 +113,20 @@ ________________| ROUTER |________________ | DEVICE 1 | | DEVICE 2 | |__________| |__________| ``` -The first thing to do is to include the `PJONRouter` class: +The first thing to do is to include the `PJONRouter` class and include the required strategy: ```cpp #include +#include ``` -Create `StrategyLink` instances with the selected strategies: -```cpp -StrategyLink link1; -StrategyLink link2; -``` -Create `PJONAny` instances configuring the bus id: +The simplest way to use the `PJONRouter` class is to use `PJONRouter2` that is able to handle up to 2 buses: ```cpp -PJONAny bus1(&link1, (uint8_t[4]){0, 0, 0, 3}); -PJONAny bus2(&link2, (uint8_t[4]){0, 0, 0, 4}); -``` -Create the `PJONRouter` instance passing the `PJONAny` instances: -```cpp -PJONRouter router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONRouter2 router; ``` Configure each strategy and the `router` instance as required: ```cpp void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); - - router.add((const uint8_t[4]){0,0,0,1}, 0); - router.add((const uint8_t[4]){0,0,0,2}, 1); - + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); router.begin(); } ``` @@ -198,8 +140,10 @@ void loop() { router.loop(); } ``` +Consider that there is also `PJONRouter3` able to handle up to 3 buses, and `PJONRouter` able to handle an array of buses. `PJONRouter` can be used also in local mode, although, because the hop count field is not included, the network topology cannot include loops. + ### DynamicRouter -The [PJONDynamicRouter](/examples/ARDUINO/Network/SoftwareBitBang/Router/DynamicRouter) is a router that also populates a routing table of remote (not directly attached) buses observing traffic. It can offer the same features provided by the `PJONRouter` class with no need of manual configuration. To do so, the `PJONDynamicRouter` class uses a routing table that is dynamically updated, for this reason uses more memory if compared with `PJONRouter`. Use the `PJON_ROUTER_TABLE_SIZE` constant to configure the number of entries that are `100` by default. +The [PJONDynamicRouter](/examples/routing/ARDUINO/Network/DynamicRouter/DynamicRouter.ino) is a router that also populates a routing table of remote (not directly attached) buses observing traffic. It can offer the same features provided by the `PJONRouter` class with no need of manual configuration. To do so, the `PJONDynamicRouter` class uses a routing table that is dynamically updated, for this reason uses more memory if compared with `PJONRouter`. Use the `PJON_ROUTER_TABLE_SIZE` constant to configure the number of entries that are `100` by default. ```cpp ________ Bus 0.0.0.3 | | Bus 0.0.0.4 @@ -212,29 +156,21 @@ ________________| ROUTER |________________ | DEVICE 1 | | DEVICE 2 | |__________| |__________| ``` -The first thing to do is to include the `PJONDynamicRouter` class: +The first thing to do is to include the `PJONDynamicRouter` class and the required strategies: ```cpp #include +#include +#include ``` -Create `StrategyLink` instances with the selected strategies: -```cpp -StrategyLink link1; -StrategyLink link2; -``` -Create `PJONAny` instances configuring the bus id: -```cpp -PJONAny bus1(&link1, (uint8_t[4]){0, 0, 0, 3}); -PJONAny bus2(&link2, (uint8_t[4]){0, 0, 0, 4}); -``` -Create the `PJONRouter` instance passing the `PJONAny` instances: +The simplest way to use the `PJONDynamicRouter` class is to use `PJONDynamicRouter2` that is able to handle up to 2 buses: ```cpp -PJONDynamicRouter router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONDynamicRouter2 router; ``` Configure each strategy and the `router` instance as required: ```cpp void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); router.begin(); } ``` @@ -245,8 +181,17 @@ void loop() { } ``` +Consider that there is also `PJONDynamicRouter3` able to handle up to 3 buses, and `PJONDynamicRouter` able to handle an array of buses. `PJONDynamicRouter` can be used also in local mode, although, because the hop count field is not included, the network topology cannot include loops. + ### InteractiveRouter -[Interactive router](/examples/ARDUINO/Network/SoftwareBitBang/Switch/BlinkingSwitch) routes packets as a switch or router but it is also able to act as a device and have user-defined receive and error call-back. +[Interactive router](/examples/routing/ARDUINO/Network/Switch/BlinkingSwitch) routes packets as a switch or router but it is also able to act as a device and have user-defined receive and error call-back. + +This class implements functionality that can be added to any of the routing classes except PJONSimpleSwitch. Adding the functionality to PJONDynamicRouter can be done as: +```cpp +PJONInteractiveRouter> router; +``` ### Virtual bus -[Virtual bus](/examples/ARDUINO/Local/SoftwareBitBang/Tunneler) is a bus where multiple buses using potentially different media or strategies, connected through a router, have the same bus id (including the local bus case), and where the location of each device is automatically registered observing traffic. +[Virtual bus](/examples/routing/ARDUINO/Local/Tunneler) is a bus where multiple buses using potentially different media or strategies, connected through a router, have the same bus id (including the local bus case), and where the location of each device is automatically registered observing traffic. Just like `PJONInteractiveRouter`, this class implements functionality that can be added to any of the routing classes except `PJONSimpleSwitch`. It can also be combined with the functionality added by `PJONInteractiveRouter`. + +This class makes it easy to create a bus that consists of multiple physical buses using one or more strategies. It can for example connect several clusters of SWBB local buses together through another strategy like DualUDP, to form one larger local bus. also including DualUDP devices. diff --git a/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Receiver/Receiver.ino index 28c771a724..817ca115c0 100644 --- a/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Receiver/Receiver.ino @@ -1,11 +1,11 @@ -#include +#include /* Use a couple of visible light / IR / UV LEDs as wireless bidirectional transceivers To know how to wire up the circuit see the AnalogSampling README: https://github.com/gioblu/PJON/tree/master/src/strategies/AnalogSampling */ -// bus(selected device id) -PJON bus(44); + +PJONAnalogSampling bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Transmitter/Transmitter.ino index c970c61979..071fe3c817 100644 --- a/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/AnalogSampling/BlinkTest/Transmitter/Transmitter.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONAnalogSampling bus(45); void setup() { pinMode(LED_BUILTIN, OUTPUT); diff --git a/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Receiver/Receiver.ino index 96ca6b86d7..53a01e1284 100644 --- a/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Receiver/Receiver.ino @@ -3,10 +3,10 @@ To know how to wire up the circuit see the AnalogSampling README: https://github.com/gioblu/PJON/tree/master/src/strategies/AnalogSampling */ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONAnalogSampling bus(44); void setup() { pinMode(LED_BUILTIN, OUTPUT); diff --git a/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Transmitter/Transmitter.ino index 2bff1ccd0f..b061fc9cd1 100644 --- a/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/AnalogSampling/NetworkAnalysis/Transmitter/Transmitter.ino @@ -6,15 +6,15 @@ Try different resistor values to find the optimal to maximize range Higher resistance can higher the range but can also higher background noise. */ -#include +#include float test; float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(45); + +PJONAnalogSampling bus(45); int packet; uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/Any/MultiStrategyLink/Receiver/Receiver.ino b/examples/ARDUINO/Local/Any/MultiStrategyLink/Receiver/Receiver.ino index 00f0a37eaa..95bc5444ba 100644 --- a/examples/ARDUINO/Local/Any/MultiStrategyLink/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/Any/MultiStrategyLink/Receiver/Receiver.ino @@ -1,4 +1,4 @@ -#include +#include /* Defining strategies using StrategyLink template class it is possible to leverage of virtual inheritance to handle PJON instances dynamically, for @@ -7,10 +7,10 @@ StrategyLink link1; StrategyLink link2; -PJON bus1(44), bus2(45); +PJONAny bus1(44), bus2(45); const uint8_t bus_count = 2; -PJON *buses[] = { &bus1, &bus2 }; +PJONAny *buses[] = { &bus1, &bus2 }; void setup() { pinMode(LED_BUILTIN, OUTPUT); diff --git a/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter1/Transmitter1.ino b/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter1/Transmitter1.ino index 77dd0ae64a..fa328f64dd 100644 --- a/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter1/Transmitter1.ino +++ b/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter1/Transmitter1.ino @@ -1,20 +1,13 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Transmission speed modes (see Timing.h) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ +#include -//#define SWBB_RESPONSE_TIMEOUT 1000 -#include - -// bus(selected device id) PJON bus(1); void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { diff --git a/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter2/Transmitter2.ino b/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter2/Transmitter2.ino index 72b5706876..0ec637a37f 100644 --- a/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter2/Transmitter2.ino +++ b/examples/ARDUINO/Local/Any/MultiStrategyLink/Transmitter2/Transmitter2.ino @@ -1,20 +1,13 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Transmission speed modes (see Timing.h) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ +#include -//#define SWBB_RESPONSE_TIMEOUT 1000 -#include - -// bus(selected device id) PJON bus(1); void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { diff --git a/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Receiver/Receiver.ino index e1ce1e65c5..8738606b92 100644 --- a/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Receiver/Receiver.ino @@ -1,4 +1,4 @@ -#include +#include /* Defining strategies using StrategyLink template class it is possible to leverage of virtual inheritance to handle PJON instances dynamically, for @@ -6,7 +6,7 @@ StrategyLink link; -PJON bus(44); +PJONAny bus(44); void setup() { link.strategy.set_pin(12); diff --git a/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Transmitter/Transmitter.ino index 0428463830..4f84e840de 100644 --- a/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/Any/StrategyLinkNetworkAnalysis/Transmitter/Transmitter.ino @@ -1,17 +1,11 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Transmission speed modes (see Timing.h) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 - -#include +#include float test; float mistakes; @@ -20,7 +14,7 @@ int fail; StrategyLink link; -PJON bus(44); +PJONAny bus(44); int packet; uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/DualUDP/PingPong/Receiver/Receiver.ino b/examples/ARDUINO/Local/DualUDP/PingPong/Receiver/Receiver.ino index 84cfa298d7..4d600baa16 100644 --- a/examples/ARDUINO/Local/DualUDP/PingPong/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/DualUDP/PingPong/Receiver/Receiver.ino @@ -1,10 +1,10 @@ -#include +#include // Ethernet configuration for this device byte mac[] = {0xDA, 0x5A, 0x4E, 0xEF, 0xAE, 0xED}; -// bus(selected device id) -PJON bus(44); + +PJONDualUDP bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/DualUDP/PingPong/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/DualUDP/PingPong/Transmitter/Transmitter.ino index 64810133e5..d62bca99a2 100644 --- a/examples/ARDUINO/Local/DualUDP/PingPong/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/DualUDP/PingPong/Transmitter/Transmitter.ino @@ -1,10 +1,10 @@ -#include +#include // Ethernet configuration for this device byte mac[] = {0xDA, 0xCA, 0x7E, 0xEF, 0xFE, 0x5D}; -// bus(selected device id) -PJON bus(45); + +PJONDualUDP bus(45); uint32_t cnt = 0, wait_for_reply = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/EthernetTCP/PingPong/Receiver/Receiver.ino b/examples/ARDUINO/Local/EthernetTCP/PingPong/Receiver/Receiver.ino index 682d5718c3..3880b4a92b 100644 --- a/examples/ARDUINO/Local/EthernetTCP/PingPong/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/EthernetTCP/PingPong/Receiver/Receiver.ino @@ -1,4 +1,4 @@ -#include +#include // Ethernet configuration for this device byte gateway[] = { 192, 1, 1, 1 }; @@ -7,8 +7,8 @@ byte mac[] = {0xDE, 0x5D, 0x4E, 0xEF, 0xAE, 0xED}; uint8_t local_ip[] = { 192, 1, 1, 144 }, remote_ip[] = { 192, 1, 1, 145 }; -// bus(selected device id) -PJON bus(44); + +PJONEthernetTCP bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/EthernetTCP/PingPong/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/EthernetTCP/PingPong/Transmitter/Transmitter.ino index bb64946980..138651700a 100644 --- a/examples/ARDUINO/Local/EthernetTCP/PingPong/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/EthernetTCP/PingPong/Transmitter/Transmitter.ino @@ -1,4 +1,4 @@ -#include +#include // Ethernet configuration for this device byte gateway[] = { 192, 1, 1, 1 }; @@ -7,8 +7,8 @@ byte mac[] = {0xDE, 0xCD, 0x7E, 0xEF, 0xFE, 0x5D}; uint8_t local_ip[] = { 192, 1, 1, 145 }, remote_ip[] = { 192, 1, 1, 144 }; -// bus(selected device id) -PJON bus(45); + +PJONEthernetTCP bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/RemoteWorker/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/RemoteWorker/Transmitter/Transmitter.ino index e18243c6b6..815259b7ef 100644 --- a/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/RemoteWorker/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/RemoteWorker/Transmitter/Transmitter.ino @@ -25,10 +25,10 @@ #define ETCP_SINGLE_DIRECTION //#define ETCP_SINGLE_SOCKET_WITH_ACK -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONEthernetTCP bus(45); // Ethernet configuration for this device uint8_t gateway[] = { 192, 1, 1, 1 }; diff --git a/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino b/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino index dd27c61cab..20b35258f3 100644 --- a/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino +++ b/examples/ARDUINO/Local/EthernetTCP/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino @@ -14,14 +14,14 @@ #define ETCP_SINGLE_DIRECTION //#define ETCP_SINGLE_SOCKET_WITH_ACK -#include +#include +#include const uint8_t DEVICE_ID = 45; // SWBB Device ID for this device and the RemoteWorker -// bus(selected device id) -PJON busA(DEVICE_ID); -PJON busB(1); +PJONSoftwareBitBang busA(DEVICE_ID); +PJONEthernetTCP busB(1); // Ethernet configuration for this device uint8_t gateway[] = { 192, 1, 1, 1 }; @@ -55,38 +55,22 @@ void setup() { void receiver_functionA(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // Forward packet to RemoteWorker on bus B, preserving the original sender id - busB.send_from_id( - packet_info.sender_id, - packet_info.sender_bus_id, - DEVICE_ID, - PJONTools::localhost(), - (uint8_t *)payload, - length, - packet_info.header, - packet_info.id, - packet_info.port - ); -} + PJON_Packet_Info p = packet_info; + p.rx.id = DEVICE_ID; + busB.forward(p, (uint8_t *)payload, length); +}; void receiver_functionB(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // All packets sent by the RemoteWorker is delivered to this device, when in the // single_initiate_direction listening mode. // Forward packet to specified target device on bus A - busA.send_packet_blocking( - packet_info.receiver_id, - packet_info.receiver_bus_id, - (uint8_t *)payload, - length, - packet_info.header, - packet_info.id, - packet_info.port - ); + busA.send_packet_blocking(packet_info, (uint8_t *)payload, length); } void loop() { busA.receive(1000); busB.update(); - busB.receive(1000); + busB.receive(); busA.update(); // Show the number of sockets created after startup @@ -97,4 +81,4 @@ void loop() { Serial.print(F("CONNECT COUNT: ")); Serial.println(busB.strategy.link.get_connection_count()); } -}; \ No newline at end of file +}; diff --git a/examples/ARDUINO/Local/GlobalUDP/PingPong/Receiver/Receiver.ino b/examples/ARDUINO/Local/GlobalUDP/PingPong/Receiver/Receiver.ino index 43d9b88813..14e5aaa765 100644 --- a/examples/ARDUINO/Local/GlobalUDP/PingPong/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/GlobalUDP/PingPong/Receiver/Receiver.ino @@ -1,4 +1,4 @@ -#include +#include // Ethernet configuration for this device byte gateway[] = { 192, 1, 1, 1 }; @@ -9,8 +9,8 @@ uint8_t local_ip[] = { 192, 1, 1, 151 }; // Address of remote device uint8_t remote_ip[] = { 192, 1, 1, 150 }; -// bus(selected device id) -PJON bus(44); + +PJONGlobalUDP bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino index 055f4c9423..9812b1c17b 100644 --- a/examples/ARDUINO/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino @@ -1,4 +1,4 @@ -#include +#include // Ethernet configuration for this device byte gateway[] = { 192, 1, 1, 1 }; @@ -9,8 +9,8 @@ uint8_t local_ip[] = { 192, 1, 1, 150 }; // Address of remote device uint8_t remote_ip[] = { 192, 1, 1, 151 }; -// bus(selected device id) -PJON bus(45); + +PJONGlobalUDP bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/LocalUDP/PingPong/Receiver/Receiver.ino b/examples/ARDUINO/Local/LocalUDP/PingPong/Receiver/Receiver.ino index 4940e4113f..5782ad0a3b 100644 --- a/examples/ARDUINO/Local/LocalUDP/PingPong/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/LocalUDP/PingPong/Receiver/Receiver.ino @@ -1,4 +1,4 @@ -#include +#include // Ethernet configuration for this device byte gateway[] = { 192, 1, 1, 1 }; @@ -6,8 +6,8 @@ byte subnet[] = { 255, 255, 255, 0 }; byte mac[] = {0xDA, 0x5A, 0x4E, 0xEF, 0xAE, 0xED}; uint8_t local_ip[] = { 192, 1, 1, 151 }; -// bus(selected device id) -PJON bus(44); + +PJONLocalUDP bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/LocalUDP/PingPong/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/LocalUDP/PingPong/Transmitter/Transmitter.ino index e82a56db93..dda176f7f4 100644 --- a/examples/ARDUINO/Local/LocalUDP/PingPong/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/LocalUDP/PingPong/Transmitter/Transmitter.ino @@ -1,4 +1,4 @@ -#include +#include // Ethernet configuration for this device byte gateway[] = { 192, 1, 1, 1 }; @@ -6,8 +6,8 @@ byte subnet[] = { 255, 255, 255, 0 }; byte mac[] = {0xDA, 0xCA, 0x7E, 0xEF, 0xFE, 0x5D}; uint8_t local_ip[] = { 192, 1, 1, 150 }; -// bus(selected device id) -PJON bus(45); + +PJONLocalUDP bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/MQTTTranslate/PingPong/Receiver/Receiver.ino b/examples/ARDUINO/Local/MQTTTranslate/PingPong/Receiver/Receiver.ino index 804812720b..a570ee0ec6 100644 --- a/examples/ARDUINO/Local/MQTTTranslate/PingPong/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/MQTTTranslate/PingPong/Receiver/Receiver.ino @@ -1,12 +1,12 @@ -#define PJON_INCLUDE_MQTT -#include + +#include // Ethernet configuration for this device byte mac[] = {0xDE, 0x5A, 0x4E, 0xEF, 0xAE, 0xED}; uint8_t broker_ip[] = { 192, 1, 1, 71 }; -// bus(selected device id) -PJON bus(44); + +PJONMQTTTranslate bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.ino index ed9dff6bc8..2f44de591a 100644 --- a/examples/ARDUINO/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.ino @@ -1,12 +1,12 @@ -#define PJON_INCLUDE_MQTT -#include + +#include // Ethernet configuration for this device byte mac[] = {0xDA, 0xCA, 0x7E, 0xEF, 0xFE, 0x5D}; uint8_t broker_ip[] = { 192, 1, 1, 71 }; -// bus(selected device id) -PJON bus(45); + +PJONMQTTTranslate bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/Gateway/Gateway.ino b/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/Gateway/Gateway.ino index fd852c995c..dc6f556714 100644 --- a/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/Gateway/Gateway.ino +++ b/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/Gateway/Gateway.ino @@ -1,17 +1,18 @@ -#define PJON_INCLUDE_MQTT + #define MQTTT_MODE MQTTT_MODE_MIRROR_DIRECT -#define PJON_INCLUDE_SWBB + #define PJON_MAX_PACKETS 2 -#include +#include +#include // Ethernet configuration for this device byte mac[] = {0xDA, 0xCA, 0x7E, 0xEF, 0xFE, 0x5D}; uint8_t broker_ip[] = { 192, 168, 1, 71 }; -// bus(selected device id) + #define PJON_GATEWAY_ID 254 -PJON bus(PJON_GATEWAY_ID); -PJON mqtt; +PJONSoftwareBitBang bus(PJON_GATEWAY_ID); +PJONMQTTTranslate mqtt; uint32_t cnt_to_mqtt = 0, cnt_from_mqtt = 0; uint32_t start = millis(); @@ -23,15 +24,13 @@ bool router = false; void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { const char *msg = (const char *)payload; // Forward to MQTT topic pjon/device45/output if from device 45 - mqtt.send_from_id(packet_info.sender_id, PJONTools::localhost(), - packet_info.receiver_id, PJONTools::localhost(), - payload, length, packet_info.header, packet_info.id, packet_info.port); - cnt_to_mqtt++; + mqtt.forward(packet_info, payload, length); + cnt_to_mqtt++; }; void receiver_function_mqtt(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // Send to device 45 if source topic is pjon/device45/input - bus.send(packet_info.receiver_id, payload, length); + bus.send(packet_info.rx.id, payload, length); cnt_from_mqtt++; }; @@ -64,8 +63,8 @@ void loop() { if(millis() - start > 1000) { start = millis(); - Serial.print("Routed packets to MQTT: "); Serial.print(cnt_to_mqtt); + Serial.print("Routed packets to MQTT: "); Serial.print(cnt_to_mqtt); Serial.print(", from MQTT: "); Serial.println(cnt_from_mqtt); cnt_from_mqtt = cnt_to_mqtt = 0; } -}; \ No newline at end of file +}; diff --git a/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/SomeDevice/SomeDevice.ino b/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/SomeDevice/SomeDevice.ino index 06e9a5f874..8eaf356b06 100644 --- a/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/SomeDevice/SomeDevice.ino +++ b/examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway/SomeDevice/SomeDevice.ino @@ -1,24 +1,23 @@ // This PJON device is a simulated environmental controller, trying to change -// temperature so that measurement is equal to the target that can be set +// temperature so that measurement is equal to the target that can be set // from other devices. In this case we will let it send messages to and receive // messages from another device which is this setup is an MQTT gateway. -// Using the free MQTT Explorer or similar, publish the value "temperature=24" +// Using the free MQTT Explorer or similar, publish the value "temperature=24" // to the topic pjon/device42/input. Observe the value of the topic // pjon/device42/output change gradually from "temperature=20" to "temperature=24". // NOTE: The gateway used in this setup is using MIRROR_DIRECT mode, just forwarding // packets both ways without trying to locate or translate variable names, -// therefore packets are sent to pjon/device42/output instead of -// pjon/device42/output/temperature as would have been the case with +// therefore packets are sent to pjon/device42/output instead of +// pjon/device42/output/temperature as would have been the case with // the MIRROR_TRANSLATE mode. -#include +#include #define PJON_GATEWAY_ID 254 -// bus(selected device id) -PJON bus(42); +PJONSoftwareBitBang bus(42); float temperature = 20.0; // "Measurement" float temperature_target = 20.0; // "Target" @@ -31,7 +30,8 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info strncpy(buf, (const char *)payload, len); buf[len -1] = 0; Serial.print("Received from broker: "); Serial.println(buf); - if (strncmp("temperature=", buf, 12)==0) temperature_target = atof(&buf[12]); + if(strncmp("temperature=", buf, 12) == 0) + temperature_target = atof(&buf[12]); } } @@ -58,4 +58,4 @@ void loop() { // Adjust to get closer to target, simulate a regulator temperature += (temperature_target - temperature) / 20; } -}; \ No newline at end of file +}; diff --git a/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device1/Device1.ino b/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device1/Device1.ino index 7b9bf66102..ec95f5c3fe 100644 --- a/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device1/Device1.ino +++ b/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device1/Device1.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONOverSampling bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device2/Device2.ino b/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device2/Device2.ino index db103c94d4..dee08b91b4 100644 --- a/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device2/Device2.ino +++ b/examples/ARDUINO/Local/OverSampling/HalfDuplex/Device2/Device2.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONOverSampling bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino b/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino index 8769d7adab..ae54176c86 100644 --- a/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino +++ b/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONOverSampling bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -24,7 +24,7 @@ void setup() { a different port group to avoid cross-talk. */ bus.strategy.set_pins(7, 12); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino b/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino index d5f5831460..a75fda6674 100644 --- a/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino +++ b/examples/ARDUINO/Local/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONOverSampling bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -24,7 +24,7 @@ void setup() { a different port group to avoid cross-talk. */ bus.strategy.set_pins(7, 12); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Receiver/Receiver.ino index fa8e50c7dc..bb3aeccf27 100644 --- a/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Receiver/Receiver.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONOverSampling bus(44); void setup() { /* When using more than one pin always use pins connected to diff --git a/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino index 670254bff8..9318e1f2f3 100644 --- a/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino @@ -1,12 +1,12 @@ -#include +#include float test; float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(45); + +PJONOverSampling bus(45); int packet; uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/OverSampling/Simplex/Receiver/Receiver.ino b/examples/ARDUINO/Local/OverSampling/Simplex/Receiver/Receiver.ino index a404782ff4..3d32bfcbf6 100644 --- a/examples/ARDUINO/Local/OverSampling/Simplex/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/OverSampling/Simplex/Receiver/Receiver.ino @@ -1,5 +1,5 @@ -#include +#include float test; float mistakes; @@ -7,8 +7,8 @@ int busy; int fail; -// bus(selected device id) -PJON bus(44); + +PJONOverSampling bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // Do nothing to avoid affecting speed analysis diff --git a/examples/ARDUINO/Local/OverSampling/Simplex/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/OverSampling/Simplex/Transmitter/Transmitter.ino index 10c7dbb86d..1b13596aef 100644 --- a/examples/ARDUINO/Local/OverSampling/Simplex/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/OverSampling/Simplex/Transmitter/Transmitter.ino @@ -1,8 +1,8 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONOverSampling bus(45); uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino index 7db2f3a433..f6457aa152 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONSoftwareBitBang bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino index 2778f9ac16..f774ed0d16 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONSoftwareBitBang bus(45); void setup() { bus.strategy.set_pin(12); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/AsyncAck/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTestMAC/Receiver/Receiver.ino similarity index 61% rename from examples/ARDUINO/Network/SoftwareBitBang/AsyncAck/Receiver/Receiver.ino rename to examples/ARDUINO/Local/SoftwareBitBang/BlinkTestMAC/Receiver/Receiver.ino index 7e4148f3cb..0e839025d5 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/AsyncAck/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTestMAC/Receiver/Receiver.ino @@ -1,35 +1,34 @@ -/* Include Async ACK code setting PJON_INCLUDE_ASYNC_ACK as true before including PJON.h */ -#define PJON_INCLUDE_ASYNC_ACK true +#define PJON_INCLUDE_MAC +#include -#include - -uint8_t bus_id[] = {0, 0, 0, 1}; - -// bus(selected device id) -PJON bus(bus_id, 44); +// bus(mac address of the network interface) +const uint8_t mac[6] = {1, 2, 3, 4, 5, 6}; +PJONSoftwareBitBang bus(mac); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is overwritten when a new message is dispatched */ if(payload[0] == 'B') { + Serial.print("BLINK sent by MAC "); + for(uint8_t i = 0; i < 6; i++) + Serial.print(packet_info.tx.mac[i], DEC); + Serial.println(); digitalWrite(LED_BUILTIN, HIGH); - delay(3); + delay(30); digitalWrite(LED_BUILTIN, LOW); - delay(3); } }; void setup() { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // Initialize LED 13 to be off - bus.strategy.set_pin(12); bus.begin(); bus.set_receiver(receiver_function); + Serial.begin(115200); }; void loop() { - bus.update(); bus.receive(1000); }; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/BlinkTestMAC/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTestMAC/Transmitter/Transmitter.ino new file mode 100644 index 0000000000..9fa75cce71 --- /dev/null +++ b/examples/ARDUINO/Local/SoftwareBitBang/BlinkTestMAC/Transmitter/Transmitter.ino @@ -0,0 +1,20 @@ +#define PJON_INCLUDE_MAC +#include + +// bus(mac address of the network interface) +const uint8_t mac[6] = {2, 3, 4, 5, 6, 7}; +const uint8_t rx_mac[6] = {1, 2, 3, 4, 5, 6}; +PJONSoftwareBitBang bus(mac); + +void setup() { + bus.strategy.set_pin(12); + bus.begin(); + PJON_Packet_Info info; + info.header = bus.config | PJON_MAC_BIT; + memcpy(info.rx.mac, rx_mac, 6); + bus.send_repeatedly(info, "B", 1, 1000000); // Send B to MAC 1,2,3,4,5,6 every second +} + +void loop() { + bus.update(); +}; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Receiver/Receiver.ino index efe013f2e6..490ebd7b59 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Receiver/Receiver.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONSoftwareBitBang bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Transmitter/Transmitter.ino index faed57ceaf..09616ccec9 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/BlinkWithResponse/Transmitter/Transmitter.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONSoftwareBitBang bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Receiver/Receiver.ino index f5963244b7..894fb2868f 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Receiver/Receiver.ino @@ -1,20 +1,14 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 - -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 - -#include - -// bus(selected device id) -PJON bus(44); +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +#include + + +PJONSoftwareBitBang bus(44); // Custom class class MyClass { diff --git a/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Transmitter/Transmitter.ino index 8732e49d4f..a2e6fb81fa 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/ClassMemberCallback/Transmitter/Transmitter.ino @@ -1,20 +1,14 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 - -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 - -#include - -// bus(selected device id) -PJON bus(45); +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +#include + + +PJONSoftwareBitBang bus(45); int packet; uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/README.md b/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/README.md index ec62477834..eab3fc58f3 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/README.md +++ b/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/README.md @@ -21,10 +21,10 @@ The test result can be evaluated thanks to the following terms: * `Mistakes` or how many errors detected with CRC * `Fail` or number of transmission failures occurred in the test window * `Busy` or how many times the channel is found busy -* `Accuracy` or ratio between correct packets and packets that contain mistakes +* `Delivery success rate` or ratio between packets sent successfully and transmission failures The result can be interpreted as follows: -- Many `Fail` and or `Mistakes` may mean that the maximum communication range between devices has been reached -- Many `Busy` and or `Mistakes` and or low `Bandwidth` may mean that interference is present, see [mitigate interference](https://github.com/gioblu/PJON/wiki/Mitigate-interference) -- Many `Fail` and or `Mistakes` and or low `Bandwidth` may indicate a bad timing configuration, if you are porting a new MCU/architecture to [SoftwareBitBang](/src/strategies/SoftwareBitBang) consider that a different timing configuration may be required because of system discrepancies. Try tweaking `SWBB_BIT_WIDTH`, `SWBB_BIT_SPACER`, `SWBB_READ_DELAY` and `SWBB_ACCEPTANCE` in [src/strategies/SoftwareBitBang/Timing.h](/src/strategies/SoftwareBitBang/Timing.h) +- If the success rate is low that may mean that the maximum range between devices has been reached +- If the channel is found many times `busy` and or the bandwidth is low, that may mean that interference is present, see [mitigate interference](https://github.com/gioblu/PJON/wiki/Mitigate-interference) +- A low success rate and or low bandwidth may indicate a bad timing configuration, if you are porting a new MCU/architecture to [SoftwareBitBang](/src/strategies/SoftwareBitBang) consider that a different timing configuration may be required because of system discrepancies. Try tweaking `SWBB_BIT_WIDTH`, `SWBB_BIT_SPACER`, `SWBB_READ_DELAY` and `SWBB_ACCEPTANCE` in [src/strategies/SoftwareBitBang/Timing.h](/src/strategies/SoftwareBitBang/Timing.h) - Low performance also after painstaking timing tweaks may indicate that the new MCU/architecture may not be fast enough to run SoftwareBitBang at the mode you are working with, try using a faster clock or optimize digital I/O perfomance or choosing a slower mode. diff --git a/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino index f2d9a3e554..fa29611400 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino @@ -1,20 +1,14 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 +#include -#include -// bus(selected device id) -PJON bus(44); +PJONSoftwareBitBang bus(44); void setup() { bus.strategy.set_pin(12); diff --git a/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino index 9b0377c30f..b0500cb7b7 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino @@ -1,25 +1,18 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 - -#include +#include float test; -float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(45); + +PJONSoftwareBitBang bus(45); int packet; uint8_t content[] = "01234567890123456789"; @@ -44,8 +37,6 @@ void loop() { unsigned int response = bus.send_packet(44, content, 20); if(response == PJON_ACK) test++; - if(response == PJON_NAK) - mistakes++; if(response == PJON_BUSY) busy++; if(response == PJON_FAIL) @@ -65,21 +56,18 @@ void loop() { Serial.println("B/s"); Serial.print("Packets sent: "); Serial.println((unsigned int)test); - Serial.print("Mistakes (error found with CRC): "); - Serial.println((unsigned int)mistakes); Serial.print("Fail (no acknowledge from receiver): "); Serial.println(fail); Serial.print("Busy (Channel is busy or affected by interference): "); Serial.println(busy); - Serial.print("Accuracy: "); - Serial.print(100 - (100 / (test / mistakes))); + Serial.print("Delivery success rate: "); + Serial.print(100 - (100 / (test / fail))); Serial.println(" %"); Serial.println("---------------------"); // Avoid Serial interference during test flushing Serial.flush(); test = 0; - mistakes = 0; busy = 0; fail = 0; }; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Receiver/Receiver.ino index 6efb630b2f..1ed39160e8 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Receiver/Receiver.ino @@ -1,11 +1,10 @@ -// Include only SoftwareBitBang -#define PJON_INCLUDE_SWBB // Set maximum packet length #define PJON_PACKET_MAX_LENGTH 10 -// Include PJONLocal -#include -// bus(selected device id) + +#include // Include PJONLocal +#include // Include only SoftwareBitBang + PJONLocal bus(44); uint8_t data[PJON_PACKET_MAX_LENGTH]; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Transmitter/Transmitter.ino index bad8ab65bb..b764612121 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/BlinkTest/Transmitter/Transmitter.ino @@ -1,10 +1,8 @@ -// Include only SoftwareBitBang -#define PJON_INCLUDE_SWBB -// Set maximum packet length -#define PJON_PACKET_MAX_LENGTH 10 -// Include PJONLocal -#include +#define PJON_PACKET_MAX_LENGTH 10 // Set maximum packet length + +#include // Include PJONLocal +#include // Include only SoftwareBitBang /* Create PJONLocal object: Class name instance name ( device id ) */ diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Receiver/Receiver.ino index abf9b513c9..a73e0d83dd 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Receiver/Receiver.ino @@ -1,9 +1,15 @@ +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + // Include only SoftwareBitBang -#define PJON_INCLUDE_SWBB -// Include PJONLocal -#include -// bus(selected device id) + +#include // Include PJONLocal +#include // Include only SoftwareBitBang + PJONLocal bus(44); uint8_t data[PJON_PACKET_MAX_LENGTH]; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Transmitter/Transmitter.ino index 53bf65fc43..d878ba29f0 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/NetworkAnalysis/Transmitter/Transmitter.ino @@ -1,21 +1,12 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ - -//#define SWBB_RESPONSE_TIMEOUT 1000 - -// Include only SoftwareBitBang -#define PJON_INCLUDE_SWBB -// Include PJONLocal -#include +#include // Include PJONLocal +#include // Include only SoftwareBitBang /* Create PJONLocal object: Class name instance name ( device id ) */ diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Receiver/Receiver.ino index 9b45ae532e..ea20b87e42 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Receiver/Receiver.ino @@ -2,11 +2,9 @@ This sketch contains the receiver side. In the Serial monitor is printed the record transmitted by the other device. */ -// Include only SoftwareBitBang -#define PJON_INCLUDE_SWBB -// Include PJONLocal -#include -// bus(selected device id) +#include // Include PJONLocal +#include // Include only SoftwareBitBang + PJONLocal bus(44); uint8_t data[PJON_PACKET_MAX_LENGTH]; @@ -36,9 +34,9 @@ void loop() { if(length) { uint8_t *payload = bus.get_payload(data); Serial.print("Receiver device id: "); - Serial.print(info.receiver_id); + Serial.print(info.rx.id); Serial.print(" | Transmitter device id: "); - Serial.println(info.sender_id); + Serial.println(info.tx.id); /* Copy received data in buffer */ memcpy(&r, payload, sizeof(r)); diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Transmitter/Transmitter.ino index ac880b218e..a392e192ab 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PJONLocal/SendArbitraryDataType/Transmitter/Transmitter.ino @@ -1,10 +1,8 @@ /* ARBITRARY DATA TYPE TRANSMISSION EXAMPLE This sketch contains the transmitter side. */ -// Include only SoftwareBitBang -#define PJON_INCLUDE_SWBB -// Include PJONLocal -#include +#include // Include PJONLocal +#include // Include only SoftwareBitBang /* Create PJONLocal object: Class name instance name ( device id ) */ diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Receiver/Receiver.ino index f4825eff5c..0aa6e5d06a 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Receiver/Receiver.ino @@ -6,12 +6,13 @@ transmits a continuous random byte stream. If an incoming packet is detected a false positive occurred. */ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Transmission speed modes (see Timing.h) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -#include +#include SoftwareBitBang swbb; uint32_t attempts = 100000; // Number of random string reception attempts @@ -55,6 +56,7 @@ void loop() { Serial.println(" __________________________________________________ "); Serial.println("[0% 50% 100%]"); Serial.print(" "); + Serial.flush(); test = 0, fail = 0, percent = 0; time = millis(); while(test < attempts) { @@ -63,6 +65,7 @@ void loop() { test++; if(!(test % (attempts / 50))) { Serial.print("-"); + Serial.flush(); percent++; } } diff --git a/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Transmitter/Transmitter.ino index 2c6409b0e7..b8fd0077ce 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/PacketSeparationTest/Transmitter/Transmitter.ino @@ -6,12 +6,13 @@ The receiver device attempts to receive packets from pin 12. If an incoming packet is detected a false positive occurred. */ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Transmission speed modes (see Timing.h) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -#include +#include SoftwareBitBang swbb; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device1/Device1.ino b/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device1/Device1.ino index e3e8c923a3..7a6b4e7686 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device1/Device1.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device1/Device1.ino @@ -1,7 +1,14 @@ -#include -// bus(selected device id) -PJON bus(44); +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +#include + + +PJONSoftwareBitBang bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device2/Device2.ino b/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device2/Device2.ino index fe3e57d9c6..806404c124 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device2/Device2.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SendAndReceive/Device2/Device2.ino @@ -1,7 +1,14 @@ -#include -// bus(selected device id) -PJON bus(45); +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +#include + + +PJONSoftwareBitBang bus(45); void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { if(code == PJON_CONNECTION_LOST) { diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Receiver/Receiver.ino index 0bddba7584..87919e2818 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Receiver/Receiver.ino @@ -1,10 +1,10 @@ -#include +#include /* ARBITRARY DATA TYPE RECEPTION EXAMPLE This sketch contains the receiver side. In the Serial monitor is printed the record transmitted by the other device. */ // PJON object -PJON bus(44); +PJONSoftwareBitBang bus(44); /* A custom struct is defined just to clarify that any kind of custom data type can be easily transmitted using the PJON send functions. */ @@ -20,9 +20,9 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info /* Make use of the payload before sending something, the buffer where payload points to is overwritten when a new message is dispatched */ Serial.print("Receiver device id: "); - Serial.print(packet_info.receiver_id); + Serial.print(packet_info.rx.id); Serial.print(" | Transmitter device id: "); - Serial.println(packet_info.sender_id); + Serial.println(packet_info.tx.id); /* Copy received data in buffer */ memcpy(&r, payload, sizeof(r)); diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Transmitter/Transmitter.ino index f2d12f606a..8a8d78a637 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryDataType/Transmitter/Transmitter.ino @@ -1,10 +1,10 @@ -#include +#include /* ARBITRARY DATA TYPE TRANSMISSION EXAMPLE This sketch contains the transmitter side. */ -// bus(selected device id) -PJON bus(45); + +PJONSoftwareBitBang bus(45); int packet; int voltage; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino index a8ba65c515..42555944b9 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino @@ -1,4 +1,4 @@ -#include +#include /* VOLTAGE TESTER DEVICE This is a basic example to show how PJON can be used practically. Lets print in the Serial monitor the voltage detected by the analog @@ -8,17 +8,17 @@ is printed the voltage detected and transmitted by the other device. */ // PJON object -PJON bus(44); +PJONSoftwareBitBang bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is overwritten when a new message is dispatched */ Serial.print("RX:"); Serial.print(" Device id: "); - Serial.print(packet_info.receiver_id); + Serial.print(packet_info.rx.id); Serial.print(" | TX: "); Serial.print(" Device id: "); - Serial.print(packet_info.sender_id); + Serial.print(packet_info.tx.id); if((char)payload[0] == 'V') { Serial.print(" | Voltage: "); diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino index a8adef9430..e52f1c8fc8 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino @@ -1,5 +1,5 @@ -#include +#include /* VOLTAGE TESTER DEVICE This is a basic example to show how PJON can be used practically. Lets print in the Serial monitor the voltage detected by the analog @@ -9,8 +9,8 @@ is printed transmitted data, exchange duration and transmission speed for easy benchmarking and nominal functionality assessment. */ -// bus(selected device id) -PJON bus(45); + +PJONSoftwareBitBang bus(45); uint32_t myTime; int packet; int voltage; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino index 99afacffe9..5429f5c6c0 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino @@ -1,25 +1,19 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 - -#include +#include float test; float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(44); + +PJONSoftwareBitBang bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // Do nothing to avoid affecting speed analysis diff --git a/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino index 4b98dcfdf8..b41ad29428 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino @@ -1,20 +1,14 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 - -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 - -#include - -// bus(selected device id) -PJON bus(45); +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +#include + + +PJONSoftwareBitBang bus(45); uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Switch/DynamicSwitch/DynamicSwitch.ino b/examples/ARDUINO/Local/SoftwareBitBang/Switch/DynamicSwitch/DynamicSwitch.ino deleted file mode 100644 index 9b2608b5e7..0000000000 --- a/examples/ARDUINO/Local/SoftwareBitBang/Switch/DynamicSwitch/DynamicSwitch.ino +++ /dev/null @@ -1,33 +0,0 @@ -#include - -/* This sketch does the same as the Switch example, routing between two local - buses to form one larger local bus. But instead of requiring the device ids - to be in a fixed range in each of the buses, this will discover which - attached bus each device is connected to, and route packets dynamically. - So devices can be placed on any of the attached buses as long as device - ids are unique, forming a "virtual bus". - - // SWITCH forwarding from bus 1 to bus 2 and vice versa - __________ ________ __________ - | | Bus 1 Pin 7 | | Pin 12 Bus 2 | | - | DEVICE 1 |_______________| SWITCH |_______________| DEVICE 2 | - |__________| |________| |__________| */ - -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1); -PJONAny bus2(&link2); - -PJONVirtualBusRouter router(2, (PJONAny*[2]){&bus1, &bus2}); - -void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); - router.set_virtual_bus(0); - router.begin(); -}; - -void loop() { - router.loop(); -}; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Switch/SimpleSwitch/SimpleSwitch.ino b/examples/ARDUINO/Local/SoftwareBitBang/Switch/SimpleSwitch/SimpleSwitch.ino deleted file mode 100644 index c6e7774b28..0000000000 --- a/examples/ARDUINO/Local/SoftwareBitBang/Switch/SimpleSwitch/SimpleSwitch.ino +++ /dev/null @@ -1,28 +0,0 @@ -#define PJON_INCLUDE_SWBB - -#include - -/* Route packets between a collection of buses with the same strategy. - SimpleSwitch operates as Switch but is limited to one strategy although - uses less memory. - - // SWITCH forwarding from bus 1 to bus 2 and vice versa - __________ ________ __________ - | | Bus 1 Pin 7 | | Pin 12 Bus 2 | | - | DEVICE 1 | ______________| SWITCH |_______________| DEVICE 2 | - |__________| Range 1-127 |________| Range 128-253 |__________| */ - -PJONBus bus1(PJON_NOT_ASSIGNED, 1000, 2, 0), // Devices with id 1-127 - bus2(PJON_NOT_ASSIGNED, 1000, 2, 1); // Devices with id 128-253 - -PJONSimpleSwitch router(2, (PJONBus*[2]){&bus1,&bus2}); - -void setup() { - bus1.strategy.set_pin(7); - bus2.strategy.set_pin(12); - router.begin(); -} - -void loop() { - router.loop(); -}; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Switch/Switch/Switch.ino b/examples/ARDUINO/Local/SoftwareBitBang/Switch/Switch/Switch.ino deleted file mode 100644 index 40f761e0ca..0000000000 --- a/examples/ARDUINO/Local/SoftwareBitBang/Switch/Switch/Switch.ino +++ /dev/null @@ -1,29 +0,0 @@ -#include - -/* Route packets between a collection of buses with the same - or different strategies or media. All physical buses are taking part - of the same local bus, with the device id range being segmented. - - // SWITCH forwarding from bus 1 to bus 2 and vice versa - __________ ________ __________ - | | Bus 1 Pin 7 | | Pin 12 Bus 2 | | - | DEVICE 1 |_______________| SWITCH |_______________| DEVICE 2 | - |__________| Range 1-127 |________| Range 128-253 |__________| */ - -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1, PJON_NOT_ASSIGNED, 1000, 2, 0); // Devices with id 1-127 -PJONAny bus2(&link2, PJON_NOT_ASSIGNED, 1000, 2, 1); // Devices with id 128-253 - -PJONSwitch router(2, (PJONAny*[2]){&bus1, &bus2}); - -void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); - router.begin(); -}; - -void loop() { - router.loop(); -}; diff --git a/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Receiver/Receiver.ino b/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Receiver/Receiver.ino index b9ceb77405..42d4cdaf54 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Receiver/Receiver.ino @@ -1,20 +1,22 @@ -// Include packet id feature -#define PJON_INCLUDE_PACKET_ID true -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +// Include packet id feature +#define PJON_INCLUDE_PACKET_ID -#include +#include float test; float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(44); + +PJONSoftwareBitBang bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { Serial.print("Packet id: "); diff --git a/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Transmitter/Transmitter.ino index 21cb9b9920..2186748b43 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/SoftwareBitBang/UsePacketId/Transmitter/Transmitter.ino @@ -1,15 +1,17 @@ + +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + // Include packet id feature -#define PJON_INCLUDE_PACKET_ID true +#define PJON_INCLUDE_PACKET_ID -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +#include -#include -// bus(selected device id) -PJON bus(45); +PJONSoftwareBitBang bus(45); int packet; uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Receiver/Receiver.ino index 9a78a13587..7af7bb2f1c 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Receiver/Receiver.ino @@ -1,13 +1,13 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ -// bus(selected device id) -PJON bus(44); + +PJONThroughLora bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -23,7 +23,7 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // Initialize LED 13 to be off // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Transmitter/Transmitter.ino index 66dd0996df..6e8a786061 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/BlinkTest/Transmitter/Transmitter.ino @@ -1,16 +1,16 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ -// bus(selected device id) -PJON bus(45); + +PJONThroughLora bus(45); void setup() { // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device1/Device1.ino b/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device1/Device1.ino index 28a6922875..e5f05c7b63 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device1/Device1.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device1/Device1.ino @@ -1,13 +1,13 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ -// bus(selected device id) -PJON bus(44); + +PJONThroughLora bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -40,7 +40,7 @@ void setup() { bus.set_receiver(receiver_function); bus.set_error(error_handler); // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device2/Device2.ino b/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device2/Device2.ino index c1ab33db99..8577944a0a 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device2/Device2.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/HalfDuplex/Device2/Device2.ino @@ -1,13 +1,13 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ -// bus(selected device id) -PJON bus(45); + +PJONThroughLora bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -40,7 +40,7 @@ void setup() { bus.set_error(error_handler); bus.set_receiver(receiver_function); // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/JSON/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughLoRa/JSON/Receiver/Receiver.ino index e0454bf699..0842f2e318 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/JSON/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/JSON/Receiver/Receiver.ino @@ -1,20 +1,20 @@ -#define PJON_INCLUDE_TL -#include + +#include #include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ and JSON library from https://github.com/bblanchon/ArduinoJson */ -PJON LoraPJON(44); +PJONThroughLora LoraPJON(44); void setup() { Serial.begin(115200); Serial.println("LoRa Receiver"); // Synchronous acknowledgement is not supported - LoraPJON.set_synchronous_acknowledge(false); + LoraPJON.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency LoraPJON.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/JSON/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughLoRa/JSON/Transmitter/Transmitter.ino index 00a6c36c37..c8a773cfc4 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/JSON/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/JSON/Transmitter/Transmitter.ino @@ -1,8 +1,8 @@ -#define PJON_INCLUDE_TL + #include -#include +#include #include /* To use this example, please download the LoRa third party Library @@ -11,13 +11,13 @@ #define EVENT_TIME 1000 //1 message every 1 second -PJON LoraPJON(45); +PJONThroughLora LoraPJON(45); void setup() { Serial.begin(115200); Serial.println("LoRa Transmitter"); // Synchronous acknowledgement is not supported - LoraPJON.set_synchronous_acknowledge(false); + LoraPJON.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency LoraPJON.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Receiver/Receiver.ino index 06d4779f18..4eeb37a0e1 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Receiver/Receiver.ino @@ -1,17 +1,17 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ -// bus(selected device id) -PJON bus(44); + +PJONThroughLora bus(44); void setup() { // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Transmitter/Transmitter.ino index 27c9962acd..e6922245cd 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/NetworkAnalysis/Transmitter/Transmitter.ino @@ -1,7 +1,7 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ @@ -11,8 +11,8 @@ float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(45); + +PJONThroughLora bus(45); int packet; uint8_t content[] = "01234567890123456789"; @@ -32,7 +32,7 @@ void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { void setup() { // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); // Optional diff --git a/examples/ARDUINO/Local/ThroughLoRa/Simplex/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughLoRa/Simplex/Receiver/Receiver.ino index 89cbd68498..fba15857ec 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/Simplex/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/Simplex/Receiver/Receiver.ino @@ -1,7 +1,7 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ @@ -10,8 +10,8 @@ float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(44); + +PJONThroughLora bus(44); void setup() { // Obligatory to initialize Radio with correct frequency diff --git a/examples/ARDUINO/Local/ThroughLoRa/Simplex/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughLoRa/Simplex/Transmitter/Transmitter.ino index f68f39b105..1dce59865e 100644 --- a/examples/ARDUINO/Local/ThroughLoRa/Simplex/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughLoRa/Simplex/Transmitter/Transmitter.ino @@ -1,7 +1,7 @@ -#define PJON_INCLUDE_TL -#include + +#include /* To use this example, please download the LoRa third party Library from https://github.com/sandeepmistry/arduino-LoRa/ */ @@ -11,8 +11,8 @@ float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(45); + +PJONThroughLora bus(45); int packet; uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Receiver/Receiver.ino index 0fe2186c4a..54872ae39d 100644 --- a/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Receiver/Receiver.ino @@ -1,15 +1,11 @@ -/* If you need non-blocking asynchronous operation include the - ThroughSerialAsync strategy using: - #define PJON_INCLUDE_TSA true */ -#include -PJON bus(44); -/* Use PJON bus(44); - instead if non-blocking asynchronous operation is required */ +#include + +PJONThroughSerial bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ + /* Make use of the payload before sending something, the buffer where payload points to is + overwritten when a new message is dispatched */ if(payload[0] == 'B') { digitalWrite(LED_BUILTIN, HIGH); delay(30); @@ -20,12 +16,10 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info void setup() { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // Initialize LED 13 to be off - Serial.begin(9600); bus.strategy.set_serial(&Serial); - bus.begin(); - bus.set_receiver(receiver_function); + bus.begin(); }; void loop() { diff --git a/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.ino index f67c555248..753df3288c 100644 --- a/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.ino @@ -1,12 +1,7 @@ -/* If you need non-blocking asynchronous operation include the - ThroughSerialAsync strategy using: - #define PJON_INCLUDE_TSA true */ -#include +#include -PJON bus(45); -/* Use PJON bus(45); - instead if non-blocking asynchronous operation is required */ +PJONThroughSerial bus(45); void setup() { Serial.begin(9600); diff --git a/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.ino index e42ce2d1e7..7f0fe5343b 100644 --- a/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.ino @@ -1,11 +1,7 @@ -/* If you need non-blocking asynchronous operation include the - ThroughSerialAsync strategy using: - #define PJON_INCLUDE_TSA true */ -#include -PJON bus(44); -/* Use PJON bus(45); - instead if non-blocking asynchronous operation is required */ +#include + +PJONThroughSerial bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -14,7 +10,7 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info digitalWrite(LED_BUILTIN, HIGH); delay(30); digitalWrite(LED_BUILTIN, LOW); - bus.reply("B", 1); + if(!bus.update()) bus.reply("B", 1); } }; diff --git a/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.ino index 37da630821..49964ad217 100644 --- a/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.ino @@ -1,12 +1,7 @@ -/* If you need non-blocking asynchronous operation include the - ThroughSerialAsync strategy using: - #define PJON_INCLUDE_TSA true */ -#include +#include -PJON bus(45); -/* Use PJON bus(45); - instead if non-blocking asynchronous operation is required */ +PJONThroughSerial bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck/Receiver/Receiver.ino deleted file mode 100644 index b70c86bed5..0000000000 --- a/examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck/Receiver/Receiver.ino +++ /dev/null @@ -1,40 +0,0 @@ - -// Include asynchronous acknowledgement feature -#define PJON_INCLUDE_ASYNC_ACK true - -#include -#include - -SoftwareSerial HC12(2, 3); - -uint8_t bus_id[] = {0, 0, 0, 1}; -// bus(selected device id) -PJON bus(bus_id, 44); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); // Initialize LED 13 to be off - - // Set HC12 baudrate (you must use the one configured in HC12, default 9600) - HC12.begin(9600); - - bus.strategy.set_serial(&HC12); - bus.begin(); - bus.set_receiver(receiver_function); -}; - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - digitalWrite(LED_BUILTIN, HIGH); - delay(3); - digitalWrite(LED_BUILTIN, LOW); - delay(3); - } -} - -void loop() { - bus.update(); - bus.receive(1000); -}; diff --git a/examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck/Transmitter/Transmitter.ino deleted file mode 100644 index 000902353b..0000000000 --- a/examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck/Transmitter/Transmitter.ino +++ /dev/null @@ -1,51 +0,0 @@ - -// Include asynchronous acknowledgement feature -#define PJON_INCLUDE_ASYNC_ACK true - -#include -#include - -SoftwareSerial HC12(2, 3); - -uint8_t bus_id[] = {0, 0, 0, 1}; -// bus(selected device id) -PJON bus(bus_id, 45); - -int latency = 1000; -/* 1 millisecond maximum expected latency having modules in close proximity - higher latency if communication fails when modules are physically distant */ - -void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { - if(code == PJON_CONNECTION_LOST) - digitalWrite(LED_BUILTIN, HIGH); // Light up LED 13 if a packet transmission failed -} - -void setup() { - // Initialize LED 13 to be off - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - - // Set HC12 baudrate (you must use the one configured in HC12, default 9600) - HC12.begin(9600); - - bus.strategy.set_serial(&HC12); - - /* Set configuration to send packet disabling synchronous and - enabling asynchronous acknowledgement response */ - bus.set_synchronous_acknowledge(false); - bus.set_asynchronous_acknowledge(true); - - bus.set_error(error_handler); - bus.begin(); - - // Send B to device 44 every 1.5s - bus.send_repeatedly(44, "B", 1, 1500000); -}; - -void loop() { - bus.update(); - bus.receive(TS_TIME_IN + latency); - /* Receive for, at least, the minumum timeframe necessary - for receiver to respond back an acknowledgement packet - (Avoid unnecessary retransmissions) */ -}; diff --git a/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Receiver/Receiver.ino index 9a662bddbf..836d57cdc6 100644 --- a/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Receiver/Receiver.ino @@ -4,13 +4,13 @@ emulated Serial port is used on pin 2 and 3 to communicate with HC12. The receiver device should blink every second.*/ -#include +#include #include SoftwareSerial HC12(2, 3); -// bus(selected device id) -PJON bus(44); + +PJONThroughSerial bus(44); void setup() { // Initialize LED 13 to be off diff --git a/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Transmitter/Transmitter.ino index 649910eec3..e30e53dcfb 100644 --- a/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughSerial/HC-12-Blink/Transmitter/Transmitter.ino @@ -4,13 +4,13 @@ emulated Serial port is used on pin 2 and 3 to communicate with HC12. The receiver device should blink every second. */ -#include +#include #include SoftwareSerial HC12(2, 3); -// bus(selected device id) -PJON bus(45); + +PJONThroughSerial bus(45); void setup() { // Set HC12 baudrate (you must use the one configured in HC12, default 9600) @@ -19,8 +19,8 @@ void setup() { // Pass the HC12 Serial instance you want to use for PJON communication bus.strategy.set_serial(&HC12); - // Avoid synchronous acknowledgement - bus.set_synchronous_acknowledge(false); + // Avoid acknowledgement + bus.set_acknowledge(false); bus.begin(); diff --git a/examples/ARDUINO/Local/ThroughSerial/HC-12-LocalChat/HC-12-LocalChat.ino b/examples/ARDUINO/Local/ThroughSerial/HC-12-LocalChat/HC-12-LocalChat.ino index 6621d40c2f..10a13dbe4e 100644 --- a/examples/ARDUINO/Local/ThroughSerial/HC-12-LocalChat/HC-12-LocalChat.ino +++ b/examples/ARDUINO/Local/ThroughSerial/HC-12-LocalChat/HC-12-LocalChat.ino @@ -22,7 +22,7 @@ Giovanni Blu Mitolo 2018 */ -/* Set synchronous response timeout to 100 milliseconds. +/* Set synchronous response timeout to 200 milliseconds. If operating at less than 9600Bd TS_RESPONSE_TIME_OUT should be longer */ #define TS_RESPONSE_TIME_OUT 200000 @@ -32,20 +32,20 @@ user 1: Ciao! user 1: Ciao! user 1: Ciao! */ -#define PJON_INCLUDE_PACKET_ID true +#define PJON_INCLUDE_PACKET_ID /* Use 63 characters maximum packet length. HC-12 has two 64-byte Rx and Tx FIFO memories built into the chip, supporting up to 64 bytes maximum packet length */ #define PJON_PACKET_MAX_LENGTH 63 -#include +#include #include SoftwareSerial HC12(2, 3); -// bus(selected device id) -PJON bus; + +PJONThroughSerial bus; uint8_t packet[100]; String string_number; @@ -56,10 +56,10 @@ uint8_t recipient = 0; void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // Received messages sender id and content are printed here - if(packet_info.sender_id == recipient || packet_info.sender_id == PJON_BROADCAST) { + if(packet_info.tx.id == recipient || packet_info.tx.id == PJON_BROADCAST) { Serial.print("user "); - Serial.print(packet_info.sender_id); - Serial.print((packet_info.receiver_id == PJON_BROADCAST) ? " " : ": "); + Serial.print(packet_info.tx.id); + Serial.print((packet_info.rx.id == PJON_BROADCAST) ? " " : ": "); for(uint16_t i = 0; i < length; i++) Serial.print((char)payload[i]); Serial.println(); diff --git a/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Receiver/Receiver.ino index a5b5f80832..7c36536684 100644 --- a/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Receiver/Receiver.ino @@ -9,13 +9,13 @@ If operating at less than 9600Bd TS_RESPONSE_TIME_OUT should be longer */ #define TS_RESPONSE_TIME_OUT 100000 -#include +#include #include SoftwareSerial HC12(2, 3); -// bus(selected device id) -PJON bus(44); + +PJONThroughSerial bus(44); void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { if(code == PJON_CONNECTION_LOST) { diff --git a/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Transmitter/Transmitter.ino index 51026294dc..500a93cf59 100644 --- a/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive/Transmitter/Transmitter.ino @@ -9,13 +9,13 @@ If operating at less than 9600Bd TS_RESPONSE_TIME_OUT should be longer */ #define TS_RESPONSE_TIME_OUT 100000 -#include +#include #include SoftwareSerial HC12(2, 3); -// bus(selected device id) -PJON bus(45); + +PJONThroughSerial bus(45); void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { if(code == PJON_CONNECTION_LOST) { diff --git a/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Receiver/Receiver.ino index fc11713114..019571bb2c 100644 --- a/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Receiver/Receiver.ino @@ -1,12 +1,12 @@ /* Include only ThroughSerial (not all data-link are still compatible with STM32 microcontrollers) */ -#define PJON_INCLUDE_TS true -#include -// bus(selected device id) -PJON bus(44); +#include + + +PJONThroughSerial bus(44); void setup() { pinMode(LED_BUILTIN, OUTPUT); diff --git a/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Transmitter/Transmitter.ino index 83e28a0e44..8ddfe9859d 100644 --- a/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughSerial/NucleoBlinkTest/Transmitter/Transmitter.ino @@ -1,12 +1,12 @@ /* Include only ThroughSerial (not all data-link are still compatible with STM32 microcontrollers) */ -#define PJON_INCLUDE_TS true -#include -// bus(selected device id) -PJON bus(45); +#include + + +PJONThroughSerial bus(45); void setup() { // Serial1 or pin 2 and 8 on F401RE and L053R8 diff --git a/examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck/Receiver/Receiver.ino deleted file mode 100644 index eecab8d3dc..0000000000 --- a/examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck/Receiver/Receiver.ino +++ /dev/null @@ -1,44 +0,0 @@ - -/* PJON MAX485 serial modules RS485 communication example */ - -// Include async ack defining PJON_INCLUDE_ASYNC_ACK before including PJON.h -#define PJON_INCLUDE_ASYNC_ACK true -// Synchronous acknowledgement is not used, set TS_RESPONSE_TIME_OUT to 0 -#define TS_RESPONSE_TIME_OUT 0 - -#include - -// bus(selected device id) -PJON bus(44); - -void setup() { - // Initialize LED 13 to be off - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - // Initialize Serial instance used for PJON communication - Serial.begin(9600); - bus.strategy.set_serial(&Serial); - // Avoid default sync ack - bus.set_synchronous_acknowledge(false); - // Set enable pins - bus.strategy.set_RS485_rxe_pin(3); - bus.strategy.set_RS485_txe_pin(2); - bus.begin(); - bus.set_receiver(receiver_function); -}; - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - digitalWrite(LED_BUILTIN, HIGH); - delay(3); - digitalWrite(LED_BUILTIN, LOW); - delay(3); - } -} - -void loop() { - bus.update(); - bus.receive(); -}; diff --git a/examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck/Transmitter/Transmitter.ino deleted file mode 100644 index b01cf68e29..0000000000 --- a/examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck/Transmitter/Transmitter.ino +++ /dev/null @@ -1,47 +0,0 @@ - -/* PJON MAX485 serial modules RS485 communication example */ - -// Include async ack defining PJON_INCLUDE_ASYNC_ACK before including PJON.h -#define PJON_INCLUDE_ASYNC_ACK true -// Synchronous acknowledgement is not used, set TS_RESPONSE_TIME_OUT to 0 -#define TS_RESPONSE_TIME_OUT 0 - -#include - -// bus(selected device id) -PJON bus(45); - -// 5 milliseconds maximum expected latency, higher if necessary -uint32_t latency = 5000; - -void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { - if(code == PJON_CONNECTION_LOST) - digitalWrite(LED_BUILTIN, HIGH); // Light up LED 13 if a packet transmission failed -}; - -void setup() { - // Initialize LED 13 to be off - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - // Initialize Serial instance used for PJON communication - Serial.begin(9600); - bus.strategy.set_serial(&Serial); - // Set asynchronous acknowledgement response, avoid sync - bus.set_synchronous_acknowledge(false); - bus.set_asynchronous_acknowledge(true); - // Set enable pins - bus.strategy.set_RS485_rxe_pin(3); - bus.strategy.set_RS485_txe_pin(2); - bus.set_error(error_handler); - bus.begin(); - // Send B to device 44 every 1.5s - bus.send_repeatedly(44, "B", 1, 1500000); -}; - -void loop() { - bus.update(); - bus.receive(TS_TIME_IN + latency); - /* Receive for, at least, the minumum timeframe necessary - for receiver to respond back an acknowledgement packet - (Avoid unnecessary retransmissions) */ -}; diff --git a/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Receiver/Receiver.ino index 4be8ae2450..5f4d6a9cf2 100644 --- a/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Receiver/Receiver.ino @@ -1,10 +1,10 @@ /* PJON MAX485 serial modules RS485 communication example */ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONThroughSerial bus(44); void setup() { // Initialize LED 13 to be off diff --git a/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Transmitter/Transmitter.ino index 64df10f62f..e8e53531b8 100644 --- a/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughSerial/RS485-Blink/Transmitter/Transmitter.ino @@ -1,10 +1,10 @@ /* PJON MAX485 serial modules RS485 communication example */ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONThroughSerial bus(45); void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { if(code == PJON_CONNECTION_LOST) diff --git a/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Receiver/Receiver.ino index b483c19870..99e263ef3c 100644 --- a/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Receiver/Receiver.ino +++ b/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Receiver/Receiver.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONThroughSerial bus(44); void setup() { pinMode(13, OUTPUT); @@ -12,7 +12,7 @@ void setup() { bus.strategy.set_serial(&Serial); bus.strategy.set_enable_RS485_pin(2); bus.set_receiver(receiver_function); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.begin(); }; diff --git a/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter/Transmitter.ino index 356db121a2..826f11e797 100644 --- a/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter/Transmitter.ino @@ -1,10 +1,10 @@ /* PJON MAX485 serial modules RS485 communication example */ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONThroughSerial bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -26,7 +26,7 @@ void setup() { bus.strategy.set_serial(&Serial); bus.strategy.set_enable_RS485_pin(2); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/ARDUINO/Local/ThroughSerial/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino b/examples/ARDUINO/Local/ThroughSerial/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino index f6171e7417..74725640d8 100644 --- a/examples/ARDUINO/Local/ThroughSerial/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino +++ b/examples/ARDUINO/Local/ThroughSerial/SoftwareBitBangSurrogate/Surrogate/Surrogate.ino @@ -10,50 +10,51 @@ #define PJON_PACKET_MAX_LENGTH 50 #define PJON_MAX_PACKETS 3 -//// Define one of these modes -//#define ETCP_SINGLE_DIRECTION -////#define ETCP_SINGLE_SOCKET_WITH_ACK +// Define one of these modes +// #define ETCP_SINGLE_DIRECTION +// #define ETCP_SINGLE_SOCKET_WITH_ACK +// #include -#include +#include +#include const uint8_t DEVICE_ID = 45; // SWBB Device ID for this device and the RemoteWorker -// bus(selected device id) -PJON busA(DEVICE_ID); -//PJON busB(1); -PJON busB(1); -//// Ethernet configuration for this device -//uint8_t gateway[] = { 192, 1, 1, 1 }; -//uint8_t subnet[] = { 255, 255, 255, 0 }; -//uint8_t mac[] = {0xDE, 0x5D, 0x4E, 0xEF, 0xAE, 0xED}; -//uint8_t ip[] = { 192, 1, 1, 144 }; +PJONSoftwareBitBang busA(DEVICE_ID); +PJONThroughSerial busB(1); -//// Ethernet configuration for remote device -//const uint8_t remote_ip[] = { 192, 1, 1, 70 }; +// PJONEthernetTCP busB(1); +// Ethernet configuration for this device +// uint8_t gateway[] = { 192, 1, 1, 1 }; +// uint8_t subnet[] = { 255, 255, 255, 0 }; +// uint8_t mac[] = {0xDE, 0x5D, 0x4E, 0xEF, 0xAE, 0xED}; +// uint8_t ip[] = { 192, 1, 1, 144 }; + +// Ethernet configuration for remote device +// const uint8_t remote_ip[] = { 192, 1, 1, 70 }; void setup() { pinMode(13, OUTPUT); digitalWrite(13, LOW); // Initialize LED 13 to be off -// digitalWrite(13, HIGH); // Initialize LED 13 to be on - -// Serial.begin(115200); -// Serial.println("Welcome to Surrogate 1"); -// Ethernet.begin(mac, ip, gateway, gateway, subnet); + // digitalWrite(13, HIGH); // Initialize LED 13 to be on + // Serial.begin(115200); + // Serial.println("Welcome to Surrogate 1"); + // Ethernet.begin(mac, ip, gateway, gateway, subnet); Serial.begin(9600); busA.strategy.set_pin(7); busA.set_receiver(receiver_functionA); busA.begin(); -// busB.strategy.link.set_id(busB.device_id()); -// busB.strategy.link.add_node(DEVICE_ID, remote_ip); -// #ifdef ETCP_SINGLE_DIRECTION -// busB.strategy.link.single_initiate_direction(true); -// #elif ETCP_SINGLE_SOCKET_WITH_ACK -// busB.strategy.link.single_socket(true); -// #endif + // busB.strategy.link.set_id(busB.device_id());` + // busB.strategy.link.add_node(DEVICE_ID, remote_ip); + // #ifdef ETCP_SINGLE_DIRECTION + // busB.strategy.link.single_initiate_direction(true); + // #elif ETCP_SINGLE_SOCKET_WITH_ACK + // busB.strategy.link.single_socket(true); + // #endif` busB.strategy.set_serial(&Serial); busB.set_router(true); busB.set_receiver(receiver_functionB); @@ -62,17 +63,9 @@ void setup() { void receiver_functionA(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // Forward packet to RemoteWorker on bus B, preserving the original sender id - busB.send_from_id( - packet_info.sender_id, - packet_info.sender_bus_id, - DEVICE_ID, - PJONTools::localhost(), - (uint8_t *)payload, - length, - packet_info.header, - packet_info.id, - packet_info.port - ); + PJON_Packet_Info p = packet_info; + p.rx.id = DEVICE_ID; + busB.forward(p, (uint8_t *)payload, length); digitalWrite(13, HIGH); } @@ -80,15 +73,7 @@ void receiver_functionB(uint8_t *payload, uint16_t length, const PJON_Packet_Inf // All packets sent by the RemoteWorker is delivered to this device, when in the // single_initiate_direction listening mode. // Forward packet to specified target device on bus A - busA.send_packet_blocking( - packet_info.receiver_id, - packet_info.receiver_bus_id, - (uint8_t *)payload, - length, - packet_info.header, - packet_info.id, - packet_info.port - ); + busA.send_packet_blocking(packet_info, payload, length); digitalWrite(13, LOW); } @@ -98,12 +83,12 @@ void loop() { busB.receive(1000); busA.update(); -// // Show the number of sockets created after startup -// // (Try disconnecting the Ethernet cable for a while to see it increase when reconnected.) -// static uint32_t last = millis(); -// if (millis() - last > 5000) { -// last = millis(); -// Serial.print(F("CONNECT COUNT: ")); -// Serial.println(busB.strategy.link.get_connection_count()); -// } + // // Show the number of sockets created after startup + // // (Try disconnecting the Ethernet cable for a while to see it increase when reconnected.) + // static uint32_t last = millis(); + // if (millis() - last > 5000) { + // last = millis(); + // Serial.print(F("CONNECT COUNT: ")); + // Serial.println(busB.strategy.link.get_connection_count()); + // } }; diff --git a/examples/ARDUINO/Local/ThroughSerialAsync/Blink/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerialAsync/Blink/Receiver/Receiver.ino deleted file mode 100644 index 1330141bf1..0000000000 --- a/examples/ARDUINO/Local/ThroughSerialAsync/Blink/Receiver/Receiver.ino +++ /dev/null @@ -1,32 +0,0 @@ - -// Include the ThroughSerialAsync strategy -#define PJON_INCLUDE_TSA true -#include - -// Use ThroughSerialAsync as a PJON Strategy -PJON bus(44); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - // Initialize LED 13 to be off - - Serial.begin(9600); - bus.set_receiver(receiver_function); - bus.strategy.set_serial(&Serial); - bus.begin(); -}; - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - digitalWrite(LED_BUILTIN, HIGH); - delay(30); - digitalWrite(LED_BUILTIN, LOW); - } -}; - -void loop() { - bus.receive(1000); -}; diff --git a/examples/ARDUINO/Local/ThroughSerialAsync/Blink/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerialAsync/Blink/Transmitter/Transmitter.ino deleted file mode 100644 index d4237590c3..0000000000 --- a/examples/ARDUINO/Local/ThroughSerialAsync/Blink/Transmitter/Transmitter.ino +++ /dev/null @@ -1,21 +0,0 @@ - -// Include the ThroughSerialAsync strategy -#define PJON_INCLUDE_TSA true - -#include - -// Use ThroughSerialAsync as a PJON Strategy -PJON bus(45); - -void setup() { - Serial.begin(9600); - - bus.strategy.set_serial(&Serial); - bus.begin(); - // Send B to device 44 every second - bus.send_repeatedly(44, "B", 1, 1000000); -}; - -void loop() { - bus.update(); -}; diff --git a/examples/ARDUINO/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Receiver.ino b/examples/ARDUINO/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Receiver.ino deleted file mode 100644 index 95a2027dc1..0000000000 --- a/examples/ARDUINO/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Receiver.ino +++ /dev/null @@ -1,32 +0,0 @@ -#define PJON_INCLUDE_TSA true -#include - -// bus(selected device id) -PJON bus(44); - -void setup() { - pinMode(13, OUTPUT); - digitalWrite(13, LOW); // Initialize LED 13 to be off - - Serial.begin(9600); - - bus.strategy.set_serial(&Serial); - bus.set_receiver(receiver_function); - bus.begin(); -}; - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - digitalWrite(13, HIGH); - delay(30); - digitalWrite(13, LOW); - bus.reply("B", 1); - } -}; - -void loop() { - bus.update(); - bus.receive(); -}; diff --git a/examples/ARDUINO/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.ino b/examples/ARDUINO/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.ino deleted file mode 100644 index d1cc0d3222..0000000000 --- a/examples/ARDUINO/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.ino +++ /dev/null @@ -1,31 +0,0 @@ -#define PJON_INCLUDE_TSA true -#include - -// bus(selected device id) -PJON bus(45); - -void setup() { - pinMode(13, OUTPUT); - digitalWrite(13, LOW); - // Initialize LED 13 to be off - Serial.begin(9600); - bus.set_receiver(receiver_function); - bus.strategy.set_serial(&Serial); // Pass the Serial object you want to use for communication - bus.begin(); - bus.send_repeatedly(44, "B", 1, 1000000); // Send B to device id 44 every second -}; - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - digitalWrite(13, HIGH); - delay(30); - digitalWrite(13, LOW); - } -}; - -void loop() { - bus.update(); - bus.receive(); -}; diff --git a/examples/ARDUINO/Network/OverSampling/HalfDuplex/Receiver/Receiver.ino b/examples/ARDUINO/Network/OverSampling/HalfDuplex/Receiver/Receiver.ino index 2bbff67603..9186c15902 100644 --- a/examples/ARDUINO/Network/OverSampling/HalfDuplex/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/OverSampling/HalfDuplex/Receiver/Receiver.ino @@ -1,13 +1,10 @@ -/* Include Async ACK code setting PJON_INCLUDE_ASYNC_ACK as true before including PJON.h */ -#define PJON_INCLUDE_ASYNC_ACK true - -#include +#include uint8_t bus_id[] = {0, 0, 0, 1}; -// bus(selected device id) -PJON bus(bus_id, 44); + +PJONOverSampling bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -27,9 +24,7 @@ void setup() { /* When using more than one pin always use pins connected to a different port group to avoid cross-talk. */ bus.strategy.set_pins(7, 12); - bus.set_receiver(receiver_function); - bus.set_synchronous_acknowledge(false); bus.begin(); }; diff --git a/examples/ARDUINO/Network/OverSampling/HalfDuplex/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/OverSampling/HalfDuplex/Transmitter/Transmitter.ino index 8b25e61d57..ebd8357570 100644 --- a/examples/ARDUINO/Network/OverSampling/HalfDuplex/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/OverSampling/HalfDuplex/Transmitter/Transmitter.ino @@ -1,13 +1,10 @@ -/* Include Async ACK code setting PJON_INCLUDE_ASYNC_ACK as true before including PJON.h */ -#define PJON_INCLUDE_ASYNC_ACK true - -#include +#include uint16_t packet; uint8_t bus_id[] = {0, 0, 0, 1}; -// bus(selected device id) -PJON bus(bus_id, 45); + +PJONOverSampling bus(bus_id, 45); void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { if(code == PJON_CONNECTION_LOST) { @@ -37,12 +34,6 @@ void setup() { /* When using more than one pin always use pins connected to a different port group to avoid cross-talk. */ bus.strategy.set_pins(7, 12); - - /* A packet containing the id of every packet received will be sent back - by this device to the packet's sender to acknowledge packet reception. - (With this setup you can avoid sending packet duplicates) */ - bus.set_asynchronous_acknowledge(true); - bus.set_synchronous_acknowledge(false); bus.set_error(error_handler); bus.begin(); diff --git a/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino b/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino index 5c7ba17ac2..7e8b59ff5e 100644 --- a/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino +++ b/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device1/Device1.ino @@ -1,29 +1,29 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONOverSampling bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is overwritten when a new message is dispatched */ Serial.print("Receiver bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(packet_info.rx.bus_id[0]); + Serial.print(packet_info.rx.bus_id[1]); + Serial.print(packet_info.rx.bus_id[2]); + Serial.print(packet_info.rx.bus_id[3]); Serial.print(" - device id: "); - Serial.println(packet_info.receiver_id); + Serial.println(packet_info.rx.id); Serial.print("Sender bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(packet_info.tx.bus_id[0]); + Serial.print(packet_info.tx.bus_id[1]); + Serial.print(packet_info.tx.bus_id[2]); + Serial.print(packet_info.tx.bus_id[3]); Serial.print(" - device id: "); - Serial.println(packet_info.sender_id); + Serial.println(packet_info.tx.id); if((char)payload[0] == 'B') { digitalWrite(LED_BUILTIN, HIGH); @@ -41,7 +41,7 @@ void setup() { a different port group to avoid cross-talk. */ bus.strategy.set_pins(7, 12); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino b/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino index 0a05e8afa3..2abc9e9c1e 100644 --- a/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino +++ b/examples/ARDUINO/Network/OverSampling/HalfDuplexNoAcknowledge/Device2/Device2.ino @@ -1,29 +1,29 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONOverSampling bus(bus_id, 45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is overwritten when a new message is dispatched */ Serial.print("Receiver bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(packet_info.rx.bus_id[0]); + Serial.print(packet_info.rx.bus_id[1]); + Serial.print(packet_info.rx.bus_id[2]); + Serial.print(packet_info.rx.bus_id[3]); Serial.print(" - device id: "); - Serial.println(packet_info.receiver_id); + Serial.println(packet_info.rx.id); Serial.print("Sender bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(packet_info.tx.bus_id[0]); + Serial.print(packet_info.tx.bus_id[1]); + Serial.print(packet_info.tx.bus_id[2]); + Serial.print(packet_info.tx.bus_id[3]); Serial.print(" - device id: "); - Serial.println(packet_info.sender_id); + Serial.println(packet_info.tx.id); if((char)payload[0] == 'B') { digitalWrite(LED_BUILTIN, HIGH); @@ -41,7 +41,7 @@ void setup() { a different port group to avoid cross-talk. */ bus.strategy.set_pins(7, 12); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Receiver/Receiver.ino index 7e29fb9366..4d485400f2 100644 --- a/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Receiver/Receiver.ino @@ -1,10 +1,10 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONOverSampling bus(bus_id, 44); void setup() { /* When using more than one pin always use pins connected to diff --git a/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino index 0875310999..c2c38ad59d 100644 --- a/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/OverSampling/NetworkAnalysis/Transmitter/Transmitter.ino @@ -1,4 +1,4 @@ -#include +#include float test; float mistakes; @@ -9,7 +9,7 @@ int fail; uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONOverSampling bus(bus_id, 44); int packet; uint8_t content[] = "01234567890123456789"; // First 4 bytes left empty for bus id @@ -33,8 +33,10 @@ void loop() { /* Here send_packet low level function is used to be able to catch every single sending result. */ - - unsigned int response = bus.send_packet(44, bus_id, content, 20); + PJON_Packet_Info info; + info.rx.id = 44; + memcpy(info.rx.bus_id, bus_id); + unsigned int response = bus.send_packet(info, content, 20); if(response == PJON_ACK) test++; if(response == PJON_NAK) diff --git a/examples/ARDUINO/Network/OverSampling/Simplex/Receiver/Receiver.ino b/examples/ARDUINO/Network/OverSampling/Simplex/Receiver/Receiver.ino index 3d340aec62..b66f522961 100644 --- a/examples/ARDUINO/Network/OverSampling/Simplex/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/OverSampling/Simplex/Receiver/Receiver.ino @@ -1,5 +1,5 @@ -#include +#include float test; float mistakes; @@ -10,7 +10,7 @@ int fail; uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONOverSampling bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { // Do nothing to avoid affecting speed analysis diff --git a/examples/ARDUINO/Network/OverSampling/Simplex/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/OverSampling/Simplex/Transmitter/Transmitter.ino index 914553a5b8..3f684c1c1a 100644 --- a/examples/ARDUINO/Network/OverSampling/Simplex/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/OverSampling/Simplex/Transmitter/Transmitter.ino @@ -1,11 +1,11 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONOverSampling bus(bus_id, 45); uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/AsyncAck/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/SoftwareBitBang/AsyncAck/Transmitter/Transmitter.ino deleted file mode 100644 index 6e3b6121d1..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/AsyncAck/Transmitter/Transmitter.ino +++ /dev/null @@ -1,31 +0,0 @@ - -/* Include Async ACK code setting PJON_INCLUDE_ASYNC_ACK as true before including PJON.h */ -#define PJON_INCLUDE_ASYNC_ACK true - -#include - -uint8_t bus_id[] = {0, 0, 0, 1}; - -// 1 milliseconds maximum expected latency, higher if necessary -uint32_t latency = 1000; - -// bus(selected device id) -PJON bus(bus_id, 45); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); // Initialize LED 13 to be off - - bus.strategy.set_pin(12); - /* A packet containing the id of every packet received will be sent back - by this device to the packet's sender to acknowledge packet reception. */ - bus.set_asynchronous_acknowledge(true); - bus.begin(); - - bus.send_repeatedly(44, "B", 1, 1000000); // Send B to device 44 every second -} - -void loop() { - bus.update(); - bus.receive(latency); -}; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino b/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino index 05932278e6..01f424f2d4 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Receiver/Receiver.ino @@ -1,29 +1,29 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is overwritten when a new message is dispatched */ Serial.print("Receiver bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(packet_info.rx.bus_id[0]); + Serial.print(packet_info.rx.bus_id[1]); + Serial.print(packet_info.rx.bus_id[2]); + Serial.print(packet_info.rx.bus_id[3]); Serial.print(" - device id: "); - Serial.println(packet_info.receiver_id); + Serial.println(packet_info.rx.id); Serial.print("Sender bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(packet_info.tx.bus_id[0]); + Serial.print(packet_info.tx.bus_id[1]); + Serial.print(packet_info.tx.bus_id[2]); + Serial.print(packet_info.tx.bus_id[3]); Serial.print(" - device id: "); - Serial.println(packet_info.sender_id); + Serial.println(packet_info.tx.id); if(payload[0] == 'B') { Serial.println(" BLINK!"); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino index a2c8a566bf..40dbbaf894 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/BlinkTest/Transmitter/Transmitter.ino @@ -1,10 +1,10 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); void setup() { bus.strategy.set_pin(12); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Receiver/Receiver.ino b/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Receiver/Receiver.ino index 2a29ce1ab8..cf4e24f09f 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Receiver/Receiver.ino @@ -2,14 +2,7 @@ #define PJON_PACKET_MAX_LENGTH 325 // Make the buffer big enough #define PJON_MAX_PACKETS 2 // Reduce number of packets not to empty memory -/* Response timeout duration duration (1500 microseconds default). - SWBB_RESPONSE_TIMEOUT duration must be long enough for the receiver to have the - time to compute the CRC and to respond with a synchronous acknowledgement. - Below SWBB_RESPONSE_TIMEOUT is set to 4 milliseconds to give enough time to - the receiver to compute CRC32 of a 300 bytes string. */ -#define SWBB_RESPONSE_TIMEOUT 4000 - -#include +#include float test; float mistakes; @@ -25,7 +18,7 @@ uint8_t bus_id[] = {0, 0, 0, 1}; bool debug = true; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -36,25 +29,25 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info // If packet formatted for a shared medium if(packet_info.header & PJON_MODE_BIT) { Serial.print(" Receiver bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(packet_info.rx.bus_id[0]); + Serial.print(packet_info.rx.bus_id[1]); + Serial.print(packet_info.rx.bus_id[2]); + Serial.print(packet_info.rx.bus_id[3]); Serial.print(" Device id: "); - Serial.print(packet_info.receiver_id); + Serial.print(packet_info.rx.id); // If sender info is included if((packet_info.header & PJON_TX_INFO_BIT) != 0) { Serial.print(" Sender bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(packet_info.tx.bus_id[0]); + Serial.print(packet_info.tx.bus_id[1]); + Serial.print(packet_info.tx.bus_id[2]); + Serial.print(packet_info.tx.bus_id[3]); Serial.print(" device id: "); - Serial.print(packet_info.sender_id);\ + Serial.print(packet_info.tx.id);\ // If local format and sender info included } else if(packet_info.header & PJON_TX_INFO_BIT) { Serial.print(" Sender id: "); - Serial.print(packet_info.sender_id); + Serial.print(packet_info.tx.id); } } diff --git a/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Transmitter/Transmitter.ino index 6d30961dac..bbaa5f3396 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/LongPacketCRC32/Transmitter/Transmitter.ino @@ -2,20 +2,13 @@ #define PJON_PACKET_MAX_LENGTH 325 // Make the buffer big enough #define PJON_MAX_PACKETS 2 // Reduce number of packets not to empty memory -/* Response timeout duration duration (1500 microseconds default). - SWBB_RESPONSE_TIMEOUT duration must be long enough for the receiver to have the - time to compute the CRC and to respond with a synchronous acknowledgement. - Below SWBB_RESPONSE_TIMEOUT is set to 4 milliseconds to give enough time to - the receiver to compute CRC32 of a 300 bytes string. */ -#define SWBB_RESPONSE_TIMEOUT 4000 - -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); uint8_t content[] = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino b/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino index 8d8e581122..82f7c3cc8b 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Receiver/Receiver.ino @@ -1,23 +1,17 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_SYNC_ACK_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_SYNC_ACK_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_SYNC_ACK_TIMEOUT 1000 - -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void setup() { bus.strategy.set_pin(12); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino index 939e34f316..f1502f61e8 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/NetworkAnalysis/Transmitter/Transmitter.ino @@ -1,29 +1,21 @@ -// Uncomment to run SoftwareBitBang in MODE 2 -// #define SWBB_MODE 2 -// Uncomment to run SoftwareBitBang in MODE 3 -// #define SWBB_MODE 3 +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd -/* Acknowledge Latency maximum duration (1000 microseconds default). - Can be necessary to higher SWBB_RESPONSE_TIMEOUT to leave enough time to - receiver to compute the CRC and to respond with a synchronous acknowledgement - SWBB_RESPONSE_TIMEOUT can be reduced to higher communication speed if - devices are near and able to compute CRC fast enough. */ -//#define SWBB_RESPONSE_TIMEOUT 1000 - -#include +#include float test; -float mistakes; int busy; int fail; -uint8_t header; // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); int packet; uint8_t content[] = "01234567890123456789"; // First 10 bytes left empty for bus id @@ -31,7 +23,6 @@ uint8_t content[] = "01234567890123456789"; // First 10 bytes left empty for bus void setup() { bus.strategy.set_pin(12); bus.begin(); - header = bus.config | PJON_CRC_BIT; // Force CRC32 Serial.begin(115200); Serial.println("PJON - Network analysis"); Serial.println("Starting a 1 second communication test.."); @@ -45,11 +36,13 @@ void loop() { /* Here send_packet low level function is used to be able to catch every single sending result. */ - unsigned int response = bus.send_packet(44, bus_id, content, 20, header); + PJON_Packet_Info info; + info.rx.id = 44; + memcpy(info.rx.bus_id, bus_id); + unsigned int response = bus.send_packet(info, content, 20); + if(response == PJON_ACK) test++; - if(response == PJON_NAK) - mistakes++; if(response == PJON_BUSY) busy++; if(response == PJON_FAIL) @@ -70,21 +63,18 @@ void loop() { Serial.println("B/s"); Serial.print("Packets sent: "); Serial.println((unsigned int)test); - Serial.print("Mistakes (error found with CRC): "); - Serial.println((unsigned int)mistakes); Serial.print("Fail (no acknowledge from receiver): "); Serial.println(fail); Serial.print("Busy (Channel is busy or affected by interference): "); Serial.println(busy); - Serial.print("Accuracy: "); - Serial.print(100 - (100 / (test / mistakes))); + Serial.print("Delivery success rate: "); + Serial.print(100 - (100 / (test / fail))); Serial.println(" %"); Serial.println("---------------------"); // Avoid Serial interference during test flushing Serial.flush(); test = 0; - mistakes = 0; busy = 0; fail = 0; }; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Receiver/Receiver.ino b/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Receiver/Receiver.ino index 67a209a40c..ac18a154f2 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Receiver/Receiver.ino @@ -1,4 +1,5 @@ -#include +#define PJON_INCLUDE_PORT +#include int busy; bool debug = true; @@ -10,7 +11,7 @@ float test; uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -21,25 +22,25 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info // If packet formatted for a shared medium if(packet_info.header & PJON_MODE_BIT) { Serial.print(" Receiver bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(packet_info.rx.bus_id[0]); + Serial.print(packet_info.rx.bus_id[1]); + Serial.print(packet_info.rx.bus_id[2]); + Serial.print(packet_info.rx.bus_id[3]); Serial.print(" Receiver id: "); - Serial.print(packet_info.receiver_id); + Serial.print(packet_info.rx.id); // If sender info is included if(packet_info.header & PJON_TX_INFO_BIT) { Serial.print(" Sender bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(packet_info.tx.bus_id[0]); + Serial.print(packet_info.tx.bus_id[1]); + Serial.print(packet_info.tx.bus_id[2]); + Serial.print(packet_info.tx.bus_id[3]); } } // If sender device id is included if(packet_info.header & PJON_TX_INFO_BIT) { Serial.print(" Sender id: "); - Serial.print(packet_info.sender_id); + Serial.print(packet_info.tx.id); } // Payload Length Serial.print(" Length: "); @@ -56,7 +57,7 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info void setup() { /* Include a custom port, only packet including port 8001 are received others are filtered out. */ - bus.include_port(true, 8001); + bus.include_port(8001); bus.strategy.set_pin(12); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Transmitter/Transmitter.ino index b4edbf5286..96f3cf03eb 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/PortsUseExample/Transmitter/Transmitter.ino @@ -1,10 +1,10 @@ - -#include +#define PJON_INCLUDE_PORT +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); int packet; uint8_t content[] = "01234567890123456789"; @@ -19,7 +19,7 @@ void setup() { bus.begin(); /* Include a custom port, only packet including port 8001 are received others are filtered out. */ - bus.include_port(true, 8001); + bus.include_port(8001); bus.strategy.set_pin(12); bus.set_error(error_handler); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Device1/Device1.ino b/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Device1/Device1.ino deleted file mode 100644 index b969fd4bb3..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Device1/Device1.ino +++ /dev/null @@ -1,39 +0,0 @@ - -#define PJON_INCLUDE_ASYNC_ACK true -#include - -// Maximum expected latency or response time, higher if necessary -uint32_t latency = 6000; - -// Bus id definition -uint8_t bus_id_A[] = {0, 0, 0, 1}; -uint8_t bus_id_B[] = {0, 0, 0, 2}; - -// bus(selected device id) -PJON bus(bus_id_A, 1); - -void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { - if(code == PJON_CONNECTION_LOST) - digitalWrite(LED_BUILTIN, HIGH); - // Light up LED 13 if a packet transmission failed -} - -void setup() { - // Initialize LED 13 to be off - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - - bus.set_error(error_handler); - bus.set_synchronous_acknowledge(true); - bus.set_asynchronous_acknowledge(true); - bus.strategy.set_pin(12); - bus.begin(); - - // Send B to device 44 every 1.5s - bus.send_repeatedly(2, bus_id_B, "B", 1, 1000000); -} - -void loop() { - bus.update(); - bus.receive(latency); -}; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Device2/Device2.ino b/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Device2/Device2.ino deleted file mode 100644 index 30d9ea9b10..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Device2/Device2.ino +++ /dev/null @@ -1,45 +0,0 @@ - -#define PJON_INCLUDE_ASYNC_ACK true -#include - -// Maximum expected latency or response time, higher if necessary -uint32_t latency = 6000; - -// Bus id definition -uint8_t bus_id_A[] = {0, 0, 0, 1}; -uint8_t bus_id_B[] = {0, 0, 0, 2}; - -// bus(selected device id) -PJON bus(bus_id_B, 2); - -void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { - if(code == PJON_CONNECTION_LOST) - digitalWrite(LED_BUILTIN, HIGH); - // Light up LED 13 if a packet transmission failed -} - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - if(payload[0] == 'B') { - digitalWrite(LED_BUILTIN, HIGH); - delay(30); - digitalWrite(LED_BUILTIN, LOW); - } -} - -void setup() { - // Initialize LED 13 to be off - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - - bus.set_error(error_handler); - bus.set_receiver(receiver_function); - bus.set_synchronous_acknowledge(true); - bus.set_asynchronous_acknowledge(true); - bus.strategy.set_pin(12); - bus.begin(); -} - -void loop() { - bus.update(); - bus.receive(latency); -}; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/README.md b/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/README.md deleted file mode 100644 index 73e11aa6ab..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/README.md +++ /dev/null @@ -1,22 +0,0 @@ -## RecursiveAcknowledge example -This example implements the [recursive acknowledgement ](/specification/PJON-protocol-acknowledge-specification-v1.0.md#pjon-recursive-acknowledgement-pattern) pattern. The setup is made by 2 buses: -- `0.0.0.1` that connects device `1` to the router -- `0.0.0.2` that connects device `2` to the router - -Device `1` and device `2` are indirectly connected by the router. - -```cpp - DEVICE 1 0.0.0.1 ROUTER 0.0.0.2 DEVICE 2 - _________ _________ _________ - | || |_||___ | | ___| || |_|| - || P12|| | || || | ||P12 || - || || | P11|| ||P12 | || || - || || |____|| ||____| || || - |_________| |_|_|__||_| |_________| - -- Devices must share common ground -``` -When running device `2` LED should blink (pin 13) every second. If LED (pin 13) of device `1` or `2` lights up an error occurred. -If the example is run removing the router and physically connecting bus `0.0.0.1` and `0.0.0.2`, the end result is the same. The router is trasparently handling the synchronous acknowledgement and forwarding data in both directions. - -The asynchronous acknowledgement used along with the synchronous acknowledgement can be useful to send information if absolute certainty of delivery and duplication avoidance is required, although it consumes more bandwidth than using only the synchronous acknowledgement. It can be a solution (also in a local bus) in critical cases like door lock control. diff --git a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Router/Router.ino b/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Router/Router.ino deleted file mode 100644 index d5bf8f47b9..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/RecursiveAcknowledge/Router/Router.ino +++ /dev/null @@ -1,76 +0,0 @@ - -#define PJON_INCLUDE_ASYNC_ACK true -#include - -// Bus id definition -uint8_t bus_id_A[] = {0, 0, 0, 1}; -uint8_t bus_id_B[] = {0, 0, 0, 2}; -// Tunneler is trasparently forwarding data, does not need a device id -PJON busA(bus_id_A, PJON_NOT_ASSIGNED); -PJON busB(bus_id_B, PJON_NOT_ASSIGNED); -// Maximum expected latency or response time, higher if necessary -uint32_t latency = 6000; - -void receiver_functionA(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - if(!PJONTools::bus_id_equality(packet_info.receiver_bus_id, bus_id_B)) return; - // Forward packet to bus 0.0.0.2 - if(packet_info.header & PJON_ACK_REQ_BIT) - busA.strategy.send_response(PJON_ACK); - busB.send_from_id( - packet_info.sender_id, - packet_info.sender_bus_id, - packet_info.receiver_id, - packet_info.receiver_bus_id, - (uint8_t *)payload, - length, - packet_info.header, - packet_info.id - ); -} - -void receiver_functionB(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - if(!PJONTools::bus_id_equality(packet_info.receiver_bus_id, bus_id_A)) return; - // Forward packet to bus 0.0.0.1 - if(packet_info.header & PJON_ACK_REQ_BIT) - busB.strategy.send_response(PJON_ACK); - busA.send_from_id( - packet_info.sender_id, - packet_info.sender_bus_id, - packet_info.receiver_id, - packet_info.receiver_bus_id, - (uint8_t *)payload, - length, - packet_info.header, - packet_info.id - ); -} - -void setup() { - // Initialize LED 13 to be off - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - // Bus 0.0.0.1 configuration - busA.set_synchronous_acknowledge(true); - busA.set_asynchronous_acknowledge(true); - busA.set_receiver(receiver_functionA); - busA.set_router(true); - busA.strategy.set_pin(11); - busA.begin(); - // Bus 0.0.0.2 configuration - busB.set_synchronous_acknowledge(true); - busB.set_asynchronous_acknowledge(true); - busB.set_receiver(receiver_functionB); - busB.set_router(true); - busB.strategy.set_pin(12); - busB.begin(); -} - -void loop() { - busB.update(); - busA.update(); - long time = micros(); - while((micros() - time) < latency) { - busA.receive(); - busB.receive(); - } -} diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Device1/Device1.ino b/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Device1/Device1.ino deleted file mode 100644 index 89b9efd6bf..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Device1/Device1.ino +++ /dev/null @@ -1,41 +0,0 @@ - -/* This example illustrates how to route packets between devices sharing the - same bus id although potentially using different strategies or media to - be connected. - - PJONSwitch routing between two separate SoftwareBitBang buses - __________ ________ __________ - | | 0.0.0.1 | | 0.0.0.1 | | - | DEVICE 1 |_________| SWITCH |_________| DEVICE 2 | - |__________| Pin 7 |________| Pin 12 |__________| */ - -#include - -// Bus id definition -uint8_t bus_id[] = {0, 0, 0, 1}; -uint8_t remote_bus_id[] = {0, 0, 0, 1}; - -// PJON object -PJON bus(bus_id, 100); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); // Initialize LED to be off - bus.strategy.set_pin(7); - bus.set_receiver(receiver_function); - bus.begin(); - bus.send_repeatedly(200, remote_bus_id, "B", 1, 250000); -} - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - if((char)payload[0] == 'B') { - static bool led_on = false; - digitalWrite(LED_BUILTIN, led_on ? HIGH : LOW); - led_on = !led_on; - } -} - -void loop() { - bus.receive(1000); - bus.update(); -} diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Device2/Device2.ino b/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Device2/Device2.ino deleted file mode 100644 index f4a8f58ff6..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Device2/Device2.ino +++ /dev/null @@ -1,43 +0,0 @@ - -/* This example illustrates how to route packets between devices sharing the - same bus id although potentially using different strategies or media to - be connected. - - PJONSwitch routing between two separate SoftwareBitBang buses - __________ ________ __________ - | | 0.0.0.1 | | 0.0.0.1 | | - | DEVICE 1 |_________| SWITCH |_________| DEVICE 2 | - |__________| Pin 7 |________| Pin 12 |__________| */ - -#include - -// Bus id definition -uint8_t bus_id[] = {0, 0, 0, 1}; -uint8_t remote_bus_id[] = {0, 0, 0, 1}; - -// PJON object -PJON bus(bus_id, 200); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); // Initialize LED to be off - - bus.strategy.set_pin(12); - bus.set_receiver(receiver_function); - bus.begin(); - bus.send(100, remote_bus_id, "B", 1); -} - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - if((char)payload[0] == 'B') { - bus.reply("B", 1); - static bool led_on = false; - digitalWrite(LED_BUILTIN, led_on ? HIGH : LOW); - led_on = !led_on; - } -} - -void loop() { - bus.receive(1000); - bus.update(); -} diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Switch/Switch.ino b/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Switch/Switch.ino deleted file mode 100644 index 8cead9ef7f..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/SegmentedSwitch/Switch/Switch.ino +++ /dev/null @@ -1,30 +0,0 @@ - -/* This example illustrates how to route packets between devices sharing the - same bus id although potentially using different strategies or media to - be connected. - - PJONSwitch routing between two separate SoftwareBitBang buses - __________ ________ __________ - | | 0.0.0.1 | | 0.0.0.1 | | - | DEVICE 1 |_________| SWITCH |_________| DEVICE 2 | - |__________| Pin 7 |________| Pin 12 |__________| */ - -#include - -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1, (uint8_t[4]){0,0,0,1}, PJON_NOT_ASSIGNED, 1000, 2, 0); -PJONAny bus2(&link2, (uint8_t[4]){0,0,0,1}, PJON_NOT_ASSIGNED, 1000, 2, 1); - -PJONSwitch router(2, (PJONAny*[2]){&bus1, &bus2}, PJON_NOT_ASSIGNED); - -void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); - router.begin(); -} - -void loop() { - router.loop(); -} diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device1/Device1.ino b/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device1/Device1.ino index 0c97acba1f..245ba65206 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device1/Device1.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device1/Device1.ino @@ -1,10 +1,10 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device2/Device2.ino b/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device2/Device2.ino index a2ce9d789c..41ecdfca0c 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device2/Device2.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/SendAndReceive/Device2/Device2.ino @@ -1,10 +1,10 @@ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino b/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino index f539b7b9e4..01836c1502 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Receiver/Receiver.ino @@ -1,4 +1,4 @@ -#include +#include /* VOLTAGE TESTER DEVICE This is a basic example to show how PJON can be used practically. Lets print in the Serial monitor the voltage detected by the analog @@ -11,28 +11,28 @@ uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is overwritten when a new message is dispatched */ Serial.print("RX:"); Serial.print(" Bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(packet_info.rx.bus_id[0]); + Serial.print(packet_info.rx.bus_id[1]); + Serial.print(packet_info.rx.bus_id[2]); + Serial.print(packet_info.rx.bus_id[3]); Serial.print(" Device id: "); - Serial.print(packet_info.receiver_id); + Serial.print(packet_info.rx.id); Serial.print(" | TX: "); Serial.print("Bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(packet_info.tx.bus_id[0]); + Serial.print(packet_info.tx.bus_id[1]); + Serial.print(packet_info.tx.bus_id[2]); + Serial.print(packet_info.tx.bus_id[3]); Serial.print(" Device id: "); - Serial.print(packet_info.sender_id); + Serial.print(packet_info.tx.id); if((char)payload[0] == 'V') { Serial.print(" | Voltage: "); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino index a7f26e1b87..fcd4ed0bfe 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/SendArbitraryValues/Transmitter/Transmitter.ino @@ -1,4 +1,4 @@ -#include +#include /* VOLTAGE TESTER DEVICE This is a basic example to show how PJON can be used practically. Lets print in the Serial monitor the voltage detected by the analog @@ -15,7 +15,7 @@ int packet; int voltage; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); void setup() { bus.strategy.set_pin(12); @@ -43,7 +43,10 @@ void loop() { unsigned long send_time = micros(); /* Use a blocking version of send. */ - packet = bus.send_packet_blocking(44, bus_id, content, 3); + PJON_Packet_Info info; + info.rx.id = 44; + memcpy(info.rx.bus_id, bus_id); + packet = bus.send_packet_blocking(info, content, 3); /* Determine communication result and duration */ send_time = micros() - send_time; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino b/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino index b3958fc398..c16c4b69ea 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino @@ -1,4 +1,11 @@ -#include + +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +#include float test; float mistakes; @@ -10,7 +17,7 @@ bool debug = false; uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -21,25 +28,25 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info // If packet formatted for a shared medium if(packet_info.header & PJON_MODE_BIT) { Serial.print(" Receiver bus id: "); - Serial.print(packet_info.receiver_bus_id[0]); - Serial.print(packet_info.receiver_bus_id[1]); - Serial.print(packet_info.receiver_bus_id[2]); - Serial.print(packet_info.receiver_bus_id[3]); + Serial.print(packet_info.rx.bus_id[0]); + Serial.print(packet_info.rx.bus_id[1]); + Serial.print(packet_info.rx.bus_id[2]); + Serial.print(packet_info.rx.bus_id[3]); Serial.print(" Device id: "); - Serial.print(packet_info.receiver_id); + Serial.print(packet_info.rx.id); // If sender info is included if((packet_info.header & PJON_TX_INFO_BIT) != 0) { Serial.print(" Sender bus id: "); - Serial.print(packet_info.sender_bus_id[0]); - Serial.print(packet_info.sender_bus_id[1]); - Serial.print(packet_info.sender_bus_id[2]); - Serial.print(packet_info.sender_bus_id[3]); + Serial.print(packet_info.tx.bus_id[0]); + Serial.print(packet_info.tx.bus_id[1]); + Serial.print(packet_info.tx.bus_id[2]); + Serial.print(packet_info.tx.bus_id[3]); Serial.print(" device id: "); - Serial.print(packet_info.sender_id);\ + Serial.print(packet_info.tx.id);\ // If local format and sender info included } else if(packet_info.header & PJON_TX_INFO_BIT) { Serial.print(" Sender id: "); - Serial.print(packet_info.sender_id); + Serial.print(packet_info.tx.id); } Serial.print(" Length: "); Serial.println(length); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino index 75993c8492..479506b270 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino +++ b/examples/ARDUINO/Network/SoftwareBitBang/SpeedTest/Transmitter/Transmitter.ino @@ -1,10 +1,17 @@ -#include + +// Uncomment to use the mode you prefer (default SWBB_MODE 1) +// #define SWBB_MODE 1 // 1.95kB/s - 15625Bd +// #define SWBB_MODE 2 // 2.21kB/s - 17696Bd +// #define SWBB_MODE 3 // 2.94kB/s - 23529Bd +// #define SWBB_MODE 4 // 3.40kB/s - 27210Bd + +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); uint8_t content[] = "01234567890123456789"; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/Switch/BlinkingSwitch/BlinkingSwitch.ino b/examples/ARDUINO/Network/SoftwareBitBang/Switch/BlinkingSwitch/BlinkingSwitch.ino deleted file mode 100644 index 34b2efa337..0000000000 --- a/examples/ARDUINO/Network/SoftwareBitBang/Switch/BlinkingSwitch/BlinkingSwitch.ino +++ /dev/null @@ -1,37 +0,0 @@ - -/* This sketch is just the Router example with a user defined receive callback. - It demonstrates how to spy on the packets being routed by a switch or router object. - In this case it just makes the on-board LED blink for every packet that passes. */ - -#include - -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1, (const uint8_t[4]){0,0,0,1}); -PJONAny bus2(&link2, (const uint8_t[4]){0,0,0,2}); - -PJONInteractiveRouter router(2, (PJONAny*[2]) {&bus1, &bus2}); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); - router.set_receiver(receiver_function); - router.set_router(true); // Pick up every packet passing - router.begin(); -} - -void loop() { - router.loop(); -} - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - toggle_led(); -} - -void toggle_led() { - static bool led_is_on = false; - led_is_on = !led_is_on; - digitalWrite(LED_BUILTIN, led_is_on ? HIGH : LOW); -} diff --git a/examples/ARDUINO/Network/ThroughSerial/AsyncAck/Receiver/Receiver.ino b/examples/ARDUINO/Network/ThroughSerial/AsyncAck/Receiver/Receiver.ino deleted file mode 100644 index 03d55773c8..0000000000 --- a/examples/ARDUINO/Network/ThroughSerial/AsyncAck/Receiver/Receiver.ino +++ /dev/null @@ -1,35 +0,0 @@ - -/* Include Async ACK code setting PJON_INCLUDE_ASYNC_ACK as true before including PJON.h */ -#define PJON_INCLUDE_ASYNC_ACK true -#include - -uint8_t bus_id[] = {0, 0, 0, 1}; -// bus(selected device id) -PJON bus(bus_id, 44); - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - digitalWrite(LED_BUILTIN, HIGH); - delay(3); - digitalWrite(LED_BUILTIN, LOW); - delay(3); - } -}; - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); // Initialize LED 13 to be off - - Serial.begin(9600); - bus.strategy.set_serial(&Serial); - bus.set_synchronous_acknowledge(false); - bus.begin(); - bus.set_receiver(receiver_function); -}; - -void loop() { - bus.update(); - bus.receive(); -}; diff --git a/examples/ARDUINO/Network/ThroughSerial/AsyncAck/Transmitter/Transmitter.ino b/examples/ARDUINO/Network/ThroughSerial/AsyncAck/Transmitter/Transmitter.ino deleted file mode 100644 index c07d21a1af..0000000000 --- a/examples/ARDUINO/Network/ThroughSerial/AsyncAck/Transmitter/Transmitter.ino +++ /dev/null @@ -1,42 +0,0 @@ -/* Include Async ACK code setting PJON_INCLUDE_ASYNC_ACK as true before including PJON.h */ -#define PJON_INCLUDE_ASYNC_ACK true - -#include - -uint8_t bus_id[] = {0, 0, 0, 1}; -// bus(selected device id) -PJON bus(bus_id, 45); - -void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { - if(code == PJON_CONNECTION_LOST) - digitalWrite(LED_BUILTIN, HIGH); // Light up LED 13 if a packet transmission failed -}; - -void setup() { - // Initialize LED 13 to be off - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - - /* Initialize the Serial instance used for communication - and pass it to PJON's ThroughSerial strategy */ - Serial.begin(9600); - bus.strategy.set_serial(&Serial); - - /* Set configuration to send packet requesting - asynchronous acknowledgement response */ - bus.set_synchronous_acknowledge(false); - bus.set_asynchronous_acknowledge(true); - - bus.set_error(error_handler); - bus.begin(); - - // Send B to device 44 every 1.5s - bus.send_repeatedly(44, "B", 1, 1500000); -}; - -void loop() { - bus.update(); - bus.receive(TS_TIME_IN + TS_BYTE_TIME_OUT); - /* Do not retransmit for the duration of the reception timeout - (Avoid unnecessary retransmissions) */ -}; diff --git a/examples/ESP32/DualUDP/PingPong/Receiver/Receiver.ino b/examples/ESP32/DualUDP/PingPong/Receiver/Receiver.ino index 11f4428214..7750046329 100644 --- a/examples/ESP32/DualUDP/PingPong/Receiver/Receiver.ino +++ b/examples/ESP32/DualUDP/PingPong/Receiver/Receiver.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONDualUDP bus(44); const char* ssid = "MyNetworkSSID"; const char* password = "MyNetworkPassword"; diff --git a/examples/ESP32/DualUDP/PingPong/Transmitter/Transmitter.ino b/examples/ESP32/DualUDP/PingPong/Transmitter/Transmitter.ino index a5499ecbe7..a5dc9cedd3 100644 --- a/examples/ESP32/DualUDP/PingPong/Transmitter/Transmitter.ino +++ b/examples/ESP32/DualUDP/PingPong/Transmitter/Transmitter.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONDualUDP bus(45); const char* ssid = "MyNetworkSSID"; const char* password = "MyNetworkPassword"; diff --git a/examples/ESP32/ESPNOW/PingPong-esp-idf/Receiver/main/main.cpp b/examples/ESP32/ESPNOW/PingPong-esp-idf/Receiver/main/main.cpp index 16223e7c71..e239ced267 100644 --- a/examples/ESP32/ESPNOW/PingPong-esp-idf/Receiver/main/main.cpp +++ b/examples/ESP32/ESPNOW/PingPong-esp-idf/Receiver/main/main.cpp @@ -13,11 +13,9 @@ static wifi_country_t wifi_country = { #include "Arduino.h" -#define PJON_INCLUDE_EN -#include +#include -// bus(selected device id) -PJON bus(44); +PJONESPNOW bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ESP32/ESPNOW/PingPong-esp-idf/Transmitter/main/main.cpp b/examples/ESP32/ESPNOW/PingPong-esp-idf/Transmitter/main/main.cpp index 28268760a9..c8e30f06b7 100644 --- a/examples/ESP32/ESPNOW/PingPong-esp-idf/Transmitter/main/main.cpp +++ b/examples/ESP32/ESPNOW/PingPong-esp-idf/Transmitter/main/main.cpp @@ -13,11 +13,9 @@ static wifi_country_t wifi_country = { #include "Arduino.h" -#define PJON_INCLUDE_EN -#include +#include -// bus(selected device id) -PJON bus(45); +PJONESPNOW bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device1/Device1.ino b/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device1/Device1.ino index 23ccfca88e..753a7ca49a 100644 --- a/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device1/Device1.ino +++ b/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device1/Device1.ino @@ -13,13 +13,9 @@ static wifi_country_t wifi_country = { policy: WIFI_COUNTRY_POLICY_MANUAL }; -// Use the PJON_INCLUDE_EN to include the ESPNOW strategy -#define PJON_INCLUDE_EN +#include -#include - -// bus(selected device id) -PJON bus(44); +PJONESPNOW bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device2/Device2.ino b/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device2/Device2.ino index cdcbacf70c..8c1e578e40 100644 --- a/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device2/Device2.ino +++ b/examples/ESP32/ESPNOW/PingPongArduinoIDE/Device2/Device2.ino @@ -14,13 +14,9 @@ static wifi_country_t wifi_country = { policy: WIFI_COUNTRY_POLICY_MANUAL }; -// Use the PJON_INCLUDE_EN to include the ESPNOW strategy -#define PJON_INCLUDE_EN +#include -#include - -// bus(selected device id) -PJON bus(45); +PJONESPNOW bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ESP32/ESPNOW/PlatformIO/Device1/src/main.cpp b/examples/ESP32/ESPNOW/PlatformIO/Device1/src/main.cpp index b0dacf781e..c6f020b7a8 100644 --- a/examples/ESP32/ESPNOW/PlatformIO/Device1/src/main.cpp +++ b/examples/ESP32/ESPNOW/PlatformIO/Device1/src/main.cpp @@ -15,13 +15,9 @@ static wifi_country_t wifi_country = { policy : WIFI_COUNTRY_POLICY_MANUAL }; -// Use the PJON_INCLUDE_EN to include the ESPNOW strategy -#define PJON_INCLUDE_EN +#include -#include - -// bus(selected device id) -PJON bus(44); +PJONESPNOW bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/ESP32/ESPNOW/PlatformIO/Device2/src/main.cpp b/examples/ESP32/ESPNOW/PlatformIO/Device2/src/main.cpp index ee23b89a66..4f253bc920 100644 --- a/examples/ESP32/ESPNOW/PlatformIO/Device2/src/main.cpp +++ b/examples/ESP32/ESPNOW/PlatformIO/Device2/src/main.cpp @@ -14,13 +14,9 @@ static wifi_country_t wifi_country = { policy : WIFI_COUNTRY_POLICY_MANUAL }; -// Use the PJON_INCLUDE_EN to include the ESPNOW strategy -#define PJON_INCLUDE_EN +#include -#include - -// bus(selected device id) -PJON bus(45); +PJONESPNOW bus(45); uint32_t cnt = 0; uint32_t start = millis(); @@ -55,4 +51,4 @@ void loop() start = millis(); cnt = 0; } -}; \ No newline at end of file +}; diff --git a/examples/ESP8266/Local/DualUDP/PingPong/Receiver/Receiver.ino b/examples/ESP8266/Local/DualUDP/PingPong/Receiver/Receiver.ino index 11f4428214..7750046329 100644 --- a/examples/ESP8266/Local/DualUDP/PingPong/Receiver/Receiver.ino +++ b/examples/ESP8266/Local/DualUDP/PingPong/Receiver/Receiver.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(44); + +PJONDualUDP bus(44); const char* ssid = "MyNetworkSSID"; const char* password = "MyNetworkPassword"; diff --git a/examples/ESP8266/Local/DualUDP/PingPong/Transmitter/Transmitter.ino b/examples/ESP8266/Local/DualUDP/PingPong/Transmitter/Transmitter.ino index a5499ecbe7..a5dc9cedd3 100644 --- a/examples/ESP8266/Local/DualUDP/PingPong/Transmitter/Transmitter.ino +++ b/examples/ESP8266/Local/DualUDP/PingPong/Transmitter/Transmitter.ino @@ -1,7 +1,7 @@ -#include +#include -// bus(selected device id) -PJON bus(45); + +PJONDualUDP bus(45); const char* ssid = "MyNetworkSSID"; const char* password = "MyNetworkPassword"; diff --git a/examples/ESP8266/Local/GlobalUDP/PingPong/Receiver/Receiver.ino b/examples/ESP8266/Local/GlobalUDP/PingPong/Receiver/Receiver.ino index d5f7bd543e..6cfefe8a8e 100644 --- a/examples/ESP8266/Local/GlobalUDP/PingPong/Receiver/Receiver.ino +++ b/examples/ESP8266/Local/GlobalUDP/PingPong/Receiver/Receiver.ino @@ -1,12 +1,12 @@ -#include +#include // Ethernet configuration for this device IPAddress gateway = { 192, 1, 1, 1 }; IPAddress subnet = { 255, 255, 255, 0 }; IPAddress local_ip = { 192, 1, 1, 163 }; -// bus(selected device id) -PJON bus(44); + +PJONGlobalUDP bus(44); const char* ssid = "MyNetworkSSID"; const char* password = "MyNetworkPassword"; diff --git a/examples/ESP8266/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino b/examples/ESP8266/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino index c7eb7d413b..539d4438b0 100644 --- a/examples/ESP8266/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino +++ b/examples/ESP8266/Local/GlobalUDP/PingPong/Transmitter/Transmitter.ino @@ -1,10 +1,10 @@ -#include +#include // Address of remote device uint8_t remote_ip[] = { 192, 1, 1, 163 }; -// bus(selected device id) -PJON bus(45); + +PJONGlobalUDP bus(45); const char* ssid = "MyNetworkSSID"; const char* password = "MyNetworkPassword"; diff --git a/examples/ESP8266/Local/MQTTTranslate/EnvironmentController/EnvironmentController.ino b/examples/ESP8266/Local/MQTTTranslate/EnvironmentController/EnvironmentController.ino index 1dc3264159..bb84b4aff3 100644 --- a/examples/ESP8266/Local/MQTTTranslate/EnvironmentController/EnvironmentController.ino +++ b/examples/ESP8266/Local/MQTTTranslate/EnvironmentController/EnvironmentController.ino @@ -1,5 +1,5 @@ // This PJON device is a simulated environmental controller, trying to change -// temperature and pressure so that measurements are equal to targets that +// temperature and pressure so that measurements are equal to targets that // can be set from external systems through an MQTT broker. // Using the free MQTT Explorer or similar, publish the value "24" to the @@ -11,13 +11,12 @@ // a device id does not need to be set. This can be useful to produce a // series of identical devices without flashing with individual ids. -#define PJON_INCLUDE_MQTT + #define MQTTT_MODE MQTTT_MODE_MIRROR_TRANSLATE //#define MQTTT_USE_MAC -#include +#include -// bus(selected device id) -PJON bus(45); +PJONMQTTTranslate bus(45); // Use device id 45 // WiFi network to connect to const char* ssid = "MyNetworkSSID"; @@ -71,4 +70,4 @@ void loop() { pressure += (pressure_target - pressure) / 10; temperature += (temperature_target - temperature) / 20; } -}; \ No newline at end of file +}; diff --git a/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/Arduino/Arduino.ino b/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/Arduino/Arduino.ino index 343ea0864a..b7d90765b9 100644 --- a/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/Arduino/Arduino.ino +++ b/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/Arduino/Arduino.ino @@ -1,4 +1,4 @@ -#include +#include /* In this example it is demonstrated how to connect an ESP8266 module and an Arduino compatible device exchanging the character "B" in both directions @@ -16,8 +16,7 @@ character "B" is received. The string "BLINK" is printed in the ESP866 Serial monitor each time the character "B" is received. */ -// bus(selected device id) -PJON bus(45); +PJONSoftwareBitBang bus(45); // Use device id 45 void setup() { Serial.begin(115200); diff --git a/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/ESP8266/ESP8266.ino b/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/ESP8266/ESP8266.ino index 8dcc46e920..7292000ec9 100644 --- a/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/ESP8266/ESP8266.ino +++ b/examples/ESP8266/Local/SoftwareBitBang/SendAndReceive/ESP8266/ESP8266.ino @@ -1,8 +1,6 @@ // Include only SoftwareBitBang strategy -#define PJON_INCLUDE_SWBB - -#include +#include /* In this example it is demonstrated how to connect an ESP8266 module and an Arduino compatible device exchanging the character "B" in both directions @@ -20,8 +18,7 @@ character "B" is received. The string "BLINK" is printed in the ESP866 Serial monitor each time the character "B" is received. */ -// bus(selected device id) -PJON bus(44); +PJONSoftwareBitBang bus(44); // Use device id 44 void setup() { Serial.begin(115200); diff --git a/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/ESPTransmitter/ESPTransmitter.ino b/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/ESPTransmitter/ESPTransmitter.ino index 39db8f8c80..29ccd740f5 100644 --- a/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/ESPTransmitter/ESPTransmitter.ino +++ b/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/ESPTransmitter/ESPTransmitter.ino @@ -2,13 +2,10 @@ /* ESP8266 - Node MCU side Devices can be wired directly being ESP8266 5v tolerant */ - // Include only SoftwareBitBang strategy - #define PJON_INCLUDE_SWBB +// Include only SoftwareBitBang strategy +#include -#include - -// bus(selected device id) -PJON bus(45); +PJONSoftwareBitBang bus(45); // Use device id 45 uint8_t content[] = "01234567890123456789"; diff --git a/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino b/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino index 43dc8fb38e..943075da27 100644 --- a/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino +++ b/examples/ESP8266/Local/SoftwareBitBang/SpeedTest/Receiver/Receiver.ino @@ -2,15 +2,14 @@ /* Arduino compatible device Devices can be wired directly being ESP8266 5v tolerant */ -#include +#include float test; float mistakes; int busy; int fail; -// bus(selected device id) -PJON bus(44); +PJONSoftwareBitBang bus(44); // Use device id 44 void setup() { bus.strategy.set_pin(12); diff --git a/examples/LINUX/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp b/examples/LINUX/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp index 192798fef4..c18d88cbee 100644 --- a/examples/LINUX/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp +++ b/examples/LINUX/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp @@ -1,10 +1,10 @@ -#define PJON_INCLUDE_ETCP -#include + +#include uint8_t remote_ip[] = { 192, 1, 1, 161 }; -// bus(selected device id) -PJON bus(44); + +PJONEthernetTCP bus(44); uint32_t cnt = 0; diff --git a/examples/LINUX/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp b/examples/LINUX/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp index da650b1957..9eb605e179 100644 --- a/examples/LINUX/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp +++ b/examples/LINUX/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp @@ -1,11 +1,11 @@ -#define PJON_INCLUDE_ETCP -#include + +#include // Address of remote device uint8_t remote_ip[] = { 192, 1, 1, 161 }; -// bus(selected device id) -PJON bus(45); + +PJONEthernetTCP bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/LINUX/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp b/examples/LINUX/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp index a454d913ec..edffd00159 100644 --- a/examples/LINUX/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp +++ b/examples/LINUX/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp @@ -1,8 +1,8 @@ -#define PJON_INCLUDE_GUDP -#include -// bus(selected device id) -PJON bus(44); +#include + + +PJONGlobalUDP bus(44); //uint32_t millis() { return PJON_MICROS()/1000; } // TODO: Move to interface diff --git a/examples/LINUX/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp b/examples/LINUX/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp index 8162408cd1..dbba94b932 100644 --- a/examples/LINUX/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp +++ b/examples/LINUX/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp @@ -1,8 +1,8 @@ -#define PJON_INCLUDE_GUDP -#include -// bus(selected device id) -PJON bus(45); +#include + + +PJONGlobalUDP bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/LINUX/Local/LocalFile/PingPong/Receiver/Receiver.cpp b/examples/LINUX/Local/LocalFile/PingPong/Receiver/Receiver.cpp index 24a42819a6..9ea9b6d2b6 100644 --- a/examples/LINUX/Local/LocalFile/PingPong/Receiver/Receiver.cpp +++ b/examples/LINUX/Local/LocalFile/PingPong/Receiver/Receiver.cpp @@ -1,9 +1,9 @@ //#define PJON_MAX_PACKETS 1 -#define PJON_INCLUDE_LF -#include -// bus(selected device id) -PJON bus(44); +#include + + +PJONLocalFile bus(44); uint32_t cnt = 0, cnt2 = 1; uint32_t start = millis(); diff --git a/examples/LINUX/Local/LocalFile/PingPong/Transmitter/Transmitter.cpp b/examples/LINUX/Local/LocalFile/PingPong/Transmitter/Transmitter.cpp index eeff39c6ca..a5080b23d2 100644 --- a/examples/LINUX/Local/LocalFile/PingPong/Transmitter/Transmitter.cpp +++ b/examples/LINUX/Local/LocalFile/PingPong/Transmitter/Transmitter.cpp @@ -1,8 +1,8 @@ -#define PJON_INCLUDE_LF -#include -// bus(selected device id) -PJON bus(45); +#include + + +PJONLocalFile bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/LINUX/Local/LocalUDP/PingPong/Receiver/Receiver.cpp b/examples/LINUX/Local/LocalUDP/PingPong/Receiver/Receiver.cpp index 01a8975606..adf763323c 100644 --- a/examples/LINUX/Local/LocalUDP/PingPong/Receiver/Receiver.cpp +++ b/examples/LINUX/Local/LocalUDP/PingPong/Receiver/Receiver.cpp @@ -1,8 +1,8 @@ -#define PJON_INCLUDE_LUDP -#include -// bus(selected device id) -PJON bus(44); +#include + + +PJONLocalUDP bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/LINUX/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp b/examples/LINUX/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp index cf91b5f745..1985dcc55a 100644 --- a/examples/LINUX/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp +++ b/examples/LINUX/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp @@ -1,8 +1,8 @@ -#define PJON_INCLUDE_LUDP -#include -// bus(selected device id) -PJON bus(45); +#include + + +PJONLocalUDP bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/LINUX/Local/ThroughSerial/BlinkTest/Receiver/Receiver.cpp b/examples/LINUX/Local/ThroughSerial/BlinkTest/Receiver/Receiver.cpp index 135e4a573c..77083c6d1e 100644 --- a/examples/LINUX/Local/ThroughSerial/BlinkTest/Receiver/Receiver.cpp +++ b/examples/LINUX/Local/ThroughSerial/BlinkTest/Receiver/Receiver.cpp @@ -6,14 +6,8 @@ #include #include -#define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include + // Include only ThroughSerial +#include void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -25,7 +19,7 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info int main() { printf("PJON instantiation... \n"); - PJON bus(44); + PJONThroughSerial bus(44); bus.set_receiver(receiver_function); uint32_t baud_rate = 9600; printf("Opening serial... \n"); diff --git a/examples/LINUX/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp b/examples/LINUX/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp index d721b9ac11..33c6e2693e 100644 --- a/examples/LINUX/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp +++ b/examples/LINUX/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp @@ -6,18 +6,12 @@ #include #include -#define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include + // Include only ThroughSerial +#include int main() { printf("PJON instantiation... \n"); - PJON bus(45); + PJONThroughSerial bus(45); uint32_t baud_rate = 9600; printf("Opening serial... \n"); diff --git a/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Receiver/Receiver.cpp b/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Receiver/Receiver.cpp index 4fc98cdc22..b6b27804ab 100644 --- a/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Receiver/Receiver.cpp +++ b/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Receiver/Receiver.cpp @@ -7,13 +7,9 @@ #include #define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include + // Include only ThroughSerial +#include void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -25,7 +21,7 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info int main() { printf("PJON instantiation... \n"); - PJON bus(44); + PJONThroughSerial bus(44); bus.set_receiver(receiver_function); uint32_t baud_rate = 9600; printf("Opening serial... \n"); diff --git a/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Transmitter/Transmitter.cpp b/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Transmitter/Transmitter.cpp index 390da1c950..b76abac457 100644 --- a/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Transmitter/Transmitter.cpp +++ b/examples/LINUX/Local/ThroughSerial/BlinkWithAck/Transmitter/Transmitter.cpp @@ -7,19 +7,15 @@ #include #define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include + // Include only ThroughSerial +#include #define BLINK_FREQUENCY 1000000 // 1 Blink per second int main() { printf("PJON instantiation... \n"); - PJON bus(45); + PJONThroughSerial bus(45); uint32_t baud_rate = 9600; printf("Opening serial... \n"); diff --git a/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.cpp b/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.cpp index 098e336d85..ec0be94723 100644 --- a/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.cpp +++ b/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Receiver/Receiver.cpp @@ -6,15 +6,9 @@ #include #include -#define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include -PJON bus(44); + // Include only ThroughSerial +#include +PJONThroughSerial bus(44); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.cpp b/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.cpp index e487d5060b..53204414f2 100644 --- a/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.cpp +++ b/examples/LINUX/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.cpp @@ -6,14 +6,8 @@ #include #include -#define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include + // Include only ThroughSerial +#include void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -25,7 +19,7 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info int main() { printf("PJON instantiation... \n"); - PJON bus(45); + PJONThroughSerial bus(45); uint32_t baud_rate = 9600; printf("Opening serial... \n"); diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Receiver/Makefile b/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Receiver/Makefile deleted file mode 100644 index eb8134529a..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Receiver/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - g++ -DLINUX -I. -I ../../../../../../src -std=gnu++11 Receiver.cpp -o Receiver -lpthread -lcrypt -lm -lrt diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Receiver/Receiver.cpp b/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Receiver/Receiver.cpp deleted file mode 100644 index 3f0b710b74..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Receiver/Receiver.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -// For printf used below -#include -// PJON library -#include -#include -#include - -#define TSA_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TSA true // Include only ThroughSerialAsync -#include - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - printf("BLINK... \n"); - fflush(stdout); -}; - - -int main() { - printf("PJON instantiation... \n"); - PJON bus(44); - bus.set_receiver(receiver_function); - uint32_t baud_rate = 9600; - printf("Opening serial... \n"); - - // The name of the serial port may need to be edited - int s = serialOpen("/dev/ttyUSB0", baud_rate); - - if(int(s) < 0) printf("Serial open fail!"); - printf("Setting serial... \n"); - bus.strategy.set_serial(s); - bus.strategy.set_baud_rate(baud_rate); - - printf("Opening bus... \n"); - bus.begin(); - printf("Attempting to roll bus... \n"); - bus.update(); - printf("Attempting to receive from bus... \n"); - bus.receive(); - printf("Success! \n"); - - while(true) { - bus.update(); - bus.receive(); - } - - return 0; -}; diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Transmitter/Makefile b/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Transmitter/Makefile deleted file mode 100644 index 80dc51b6c3..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Transmitter/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - g++ -DLINUX -I. -I ../../../../../../src -std=gnu++11 Transmitter.cpp -o Transmitter -lpthread -lcrypt -lm -lrt diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Transmitter/Transmitter.cpp b/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Transmitter/Transmitter.cpp deleted file mode 100644 index 5e2a959a89..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkTest/Transmitter/Transmitter.cpp +++ /dev/null @@ -1,48 +0,0 @@ - -// For printf used below -#include -// PJON library -#include -#include -#include - -#define TSA_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TSA true // Include only ThroughSerialAsync -#include - -int main() { - printf("PJON instantiation... \n"); - PJON bus(45); - uint32_t baud_rate = 9600; - printf("Opening serial... \n"); - - // The name of the serial port may need to be edited - int s = serialOpen("/dev/ttyUSB0", baud_rate); - - if(int(s) < 0) printf("Serial open fail!"); - printf("Setting serial... \n"); - bus.strategy.set_serial(s); - bus.strategy.set_baud_rate(baud_rate); - - printf("Opening bus... \n"); - bus.begin(); - printf("Attempting to send B every second... \n"); - bus.send_repeatedly(44, "B", 1, 1000000); - printf("Attempting to roll bus... \n"); - bus.update(); - printf("Attempting to receive from bus... \n"); - bus.receive(); - printf("Success! \n"); - - while(true) { - bus.update(); - bus.receive(); - } - - return 0; -}; diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Receiver/Makefile b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Receiver/Makefile deleted file mode 100644 index eb8134529a..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Receiver/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - g++ -DLINUX -I. -I ../../../../../../src -std=gnu++11 Receiver.cpp -o Receiver -lpthread -lcrypt -lm -lrt diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Receiver/Receiver.cpp b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Receiver/Receiver.cpp deleted file mode 100644 index 3f0b710b74..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Receiver/Receiver.cpp +++ /dev/null @@ -1,55 +0,0 @@ - -// For printf used below -#include -// PJON library -#include -#include -#include - -#define TSA_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TSA true // Include only ThroughSerialAsync -#include - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - printf("BLINK... \n"); - fflush(stdout); -}; - - -int main() { - printf("PJON instantiation... \n"); - PJON bus(44); - bus.set_receiver(receiver_function); - uint32_t baud_rate = 9600; - printf("Opening serial... \n"); - - // The name of the serial port may need to be edited - int s = serialOpen("/dev/ttyUSB0", baud_rate); - - if(int(s) < 0) printf("Serial open fail!"); - printf("Setting serial... \n"); - bus.strategy.set_serial(s); - bus.strategy.set_baud_rate(baud_rate); - - printf("Opening bus... \n"); - bus.begin(); - printf("Attempting to roll bus... \n"); - bus.update(); - printf("Attempting to receive from bus... \n"); - bus.receive(); - printf("Success! \n"); - - while(true) { - bus.update(); - bus.receive(); - } - - return 0; -}; diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Transmitter/Makefile b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Transmitter/Makefile deleted file mode 100644 index 80dc51b6c3..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Transmitter/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - g++ -DLINUX -I. -I ../../../../../../src -std=gnu++11 Transmitter.cpp -o Transmitter -lpthread -lcrypt -lm -lrt diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Transmitter/Transmitter.cpp b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Transmitter/Transmitter.cpp deleted file mode 100644 index 384baf02b3..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithAck/Transmitter/Transmitter.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// For printf used below -#include -// PJON library -#include -#include -#include -#include - -#define TSA_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TSA true // Include only ThroughSerialAsync -#include - -#define BLINK_FREQUENCY 1000000 // 1 Blink per second - -int main() { - printf("PJON instantiation... \n"); - PJON bus(45); - uint32_t baud_rate = 9600; - printf("Opening serial... \n"); - - // The name of the serial port may need to be edited - int s = serialOpen("/dev/ttyUSB0", baud_rate); - - if(int(s) < 0) printf("Serial open fail!"); - printf("Setting serial... \n"); - bus.strategy.set_serial(s); - bus.strategy.set_baud_rate(baud_rate); - - printf("Opening bus... \n"); - bus.begin(); - printf("Success, initiating BlinkTest repeated transmission... \n"); - uint32_t myTime = PJON_MICROS(); - while(true) { - if((uint32_t)(PJON_MICROS() - myTime) > BLINK_FREQUENCY) { - uint16_t result = bus.send_packet(44, "B", 1); - if(result == PJON_ACK) - printf("Packet transmission successful! \n"); - else printf("Packet transmission unsuccessful! Result: %d \n", result); - myTime = PJON_MICROS(); - } - bus.update(); - bus.receive(); - } -}; diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Makefile b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Makefile deleted file mode 100644 index eb8134529a..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - g++ -DLINUX -I. -I ../../../../../../src -std=gnu++11 Receiver.cpp -o Receiver -lpthread -lcrypt -lm -lrt diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Receiver.cpp b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Receiver.cpp deleted file mode 100644 index d5a5bf30c5..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Receiver/Receiver.cpp +++ /dev/null @@ -1,50 +0,0 @@ - -// For printf used below -#include -// PJON library -#include -#include -#include - -#define TSA_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TSA true // Include only ThroughSerialAsync -#include -PJON bus(44); - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - printf("BLINK\n"); - bus.reply("B", 1); // Reply B to 45 - } -} - -int main() { - printf("PJON instantiation... \n"); - uint32_t baud_rate = 9600; - printf("Opening serial... \n"); - - // The name of the serial port may need to be edited - int s = serialOpen("/dev/ttyUSB0", baud_rate); - - if(int(s) < 0) printf("Serial open fail!"); - printf("Setting serial... \n"); - bus.strategy.set_serial(s); - bus.strategy.set_baud_rate(baud_rate); - bus.set_receiver(receiver_function); - - printf("Opening bus... \n"); - bus.begin(); - printf("Success, initiating BlinkTest Receiver example... \n"); - - while(true) { - bus.update(); - bus.receive(1000); - } -}; diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Makefile b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Makefile deleted file mode 100644 index 80dc51b6c3..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - g++ -DLINUX -I. -I ../../../../../../src -std=gnu++11 Transmitter.cpp -o Transmitter -lpthread -lcrypt -lm -lrt diff --git a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.cpp b/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.cpp deleted file mode 100644 index d28a680e7e..0000000000 --- a/examples/LINUX/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.cpp +++ /dev/null @@ -1,50 +0,0 @@ - -// For printf used below -#include -// PJON library -#include -#include -#include - -#define TSA_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define PJON_INCLUDE_TSA true // Include only ThroughSerialAsync -#include - -void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { - /* Make use of the payload before sending something, the buffer where payload points to is - overwritten when a new message is dispatched */ - if(payload[0] == 'B') { - printf("BLINK\n"); - } -} - -int main() { - printf("PJON instantiation... \n"); - PJON bus(45); - uint32_t baud_rate = 9600; - printf("Opening serial... \n"); - - // The name of the serial port may need to be edited - int s = serialOpen("/dev/ttyUSB0", baud_rate); - - if(int(s) < 0) printf("Serial open fail!"); - printf("Setting serial... \n"); - bus.strategy.set_serial(s); - bus.strategy.set_baud_rate(baud_rate); - bus.set_receiver(receiver_function); - - printf("Opening bus... \n"); - bus.begin(); - printf("Success, initiating BlinkTest repeated transmission... \n"); - bus.send_repeatedly(44, "B", 1, 1000000); // Send B to device 44 every second - - while(true) { - bus.update(); - bus.receive(1000); - } -}; diff --git a/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/README.md b/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/README.md index d94d59f0b2..4cf08d3d9e 100644 --- a/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/README.md +++ b/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/README.md @@ -4,8 +4,6 @@ If in your case it is missing, type `sudo apt-get install wiringPi` Connect the Serial GPIO TX and RX of your Raspberry Pi with an Arduino compatible device (crossing the channels) through a level shifter not to damage the 3v3 rpi serial port. -![image](http://www.pjon.org/assets/images/PJON-RPI-UNO-level-shifter.jpg) - To correctly receive data on Raspberry Pi it may be necessary to disable the serial console, accessing as root to `boot/cmdline.txt` and removing `console=ttyAMA0, 115200` or `console=serial0, 115200` if present. To compile the program it is necessary to reach in the terminal the `PJON/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/` directory and type `make`. Once the program is compiled you should see a new file called `Receiver`. Typing `sudo ./Receiver` the program is executed and some logging info should appear. diff --git a/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/Receiver.cpp b/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/Receiver.cpp index 22b12bba4a..e6ab1b30a6 100644 --- a/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/Receiver.cpp +++ b/examples/RPI/Local/ThroughSerial/BlinkTestReceiver/Receiver.cpp @@ -14,13 +14,13 @@ #endif #define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ +/* Maximum accepted duration between transmission and acknowledgement. + May be necessary to set a higher value if devices are separated by a long + physical distance and or if long packets are transmitted. */ -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include + + // Include only ThroughSerial +#include void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -33,7 +33,7 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info int main() { printf("PJON instantiation... \n"); - PJON bus(44); + PJONThroughSerial bus(44); uint32_t baud_rate = 9600; printf("Opening serial... \n"); int s = serialOpen("/dev/ttyAMA0", baud_rate); diff --git a/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/README.md b/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/README.md index 5b89811c35..c34e48ecae 100644 --- a/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/README.md +++ b/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/README.md @@ -4,8 +4,6 @@ If in your case it is missing, type `sudo apt-get install wiringPi` Connect the Serial GPIO TX and RX of your Raspberry Pi with an Arduino compatible device (crossing the channels) through a level shifter not to damage the 3v3 rpi serial port. -![image](http://www.pjon.org/assets/images/PJON-RPI-UNO-level-shifter.jpg) - To correctly receive data on Raspberry Pi it may be necessary to disable the serial console, accessing as root to `boot/cmdline.txt` and removing `console=ttyAMA0, 115200` or `console=serial0, 115200` if present. To compile the program it is necessary to reach with the terminal the `PJON/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/` directory and type `make`. Once the program is compiled you should see a new file called `Transmitter`. Typing `sudo ./Transmitter` the program is executed and some logging info should appear. diff --git a/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/Transmitter.cpp b/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/Transmitter.cpp index 622b0b5bb2..80afa77006 100644 --- a/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/Transmitter.cpp +++ b/examples/RPI/Local/ThroughSerial/BlinkTestTransmitter/Transmitter.cpp @@ -14,17 +14,17 @@ #endif #define TS_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ +/* Maximum accepted duration between transmission and acknowledgement. + May be necessary to set a higher value if devices are separated by a long + physical distance and or if long packets are transmitted. */ -#define PJON_INCLUDE_TS true // Include only ThroughSerial -#include + + // Include only ThroughSerial +#include int main() { printf("PJON instantiation... \n"); - PJON bus(45); + PJONThroughSerial bus(45); uint32_t baud_rate = 9600; printf("Opening serial... \n"); int s = serialOpen("/dev/ttyAMA0", baud_rate); diff --git a/examples/RPI/Local/ThroughSerial/BlinkWithResponse/README.md b/examples/RPI/Local/ThroughSerial/BlinkWithResponse/README.md index 6aeef65c4e..39e00707a6 100644 --- a/examples/RPI/Local/ThroughSerial/BlinkWithResponse/README.md +++ b/examples/RPI/Local/ThroughSerial/BlinkWithResponse/README.md @@ -7,8 +7,6 @@ To correctly receive data on Raspberry Pi it may be necessary to disable the ser Connect the Serial GPIO TX and RX of your Raspberry Pi with an Arduino compatible device (crossing the channels) through a level shifter not to damage the 3v3 rpi serial port. -![image](http://www.pjon.org/assets/images/PJON-RPI-UNO-level-shifter.jpg) - To compile the program it is necessary to reach with the terminal the `PJON/examples/RPI/Local/ThroughSerial/BlinkWithResponse/` directory and type `make`. Once the program is compiled you should see a new file called `Transmitter`. Typing `sudo ./Transmitter` the program is executed and some logging info should appear. diff --git a/examples/RPI/Local/ThroughSerial/BlinkWithResponse/Transmitter.cpp b/examples/RPI/Local/ThroughSerial/BlinkWithResponse/Transmitter.cpp index 193cc26a39..342a467d2c 100644 --- a/examples/RPI/Local/ThroughSerial/BlinkWithResponse/Transmitter.cpp +++ b/examples/RPI/Local/ThroughSerial/BlinkWithResponse/Transmitter.cpp @@ -13,11 +13,11 @@ #define RPI true #endif -#define PJON_INCLUDE_TS true // Include only ThroughSerial + // Include only ThroughSerial -#include +#include -PJON bus(45); +PJONThroughSerial bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -56,7 +56,7 @@ int main() { bus.strategy.set_baud_rate(baud_rate); printf("Bus initialization \n"); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/RPI/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter.cpp b/examples/RPI/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter.cpp index fe8d361e33..3073d88e04 100644 --- a/examples/RPI/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter.cpp +++ b/examples/RPI/Local/ThroughSerial/RS485-BlinkWithResponse/Transmitter.cpp @@ -13,11 +13,11 @@ #define RPI true #endif -#define PJON_INCLUDE_TS true // Include only ThroughSerial + // Include only ThroughSerial -#include +#include -PJON bus(45); +PJONThroughSerial bus(45); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is @@ -57,7 +57,7 @@ int main() { bus.strategy.set_enable_RS485_pin(1); // GPIO pin 18 = WiringPi pin 1 printf("Bus initialization \n"); - bus.set_synchronous_acknowledge(false); + bus.set_acknowledge(false); bus.set_receiver(receiver_function); bus.begin(); diff --git a/examples/WINX86/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp b/examples/WINX86/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp index 7d4434234d..3846b4bcbd 100644 --- a/examples/WINX86/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp +++ b/examples/WINX86/Local/EthernetTCP/PingPong/Receiver/Receiver.cpp @@ -1,10 +1,10 @@ -#define PJON_INCLUDE_ETCP -#include + +#include // Address of remote device uint8_t remote_ip[] = {127, 0, 0, 1}; -PJON bus(44); +PJONEthernetTCP bus(44); uint32_t count = 0; diff --git a/examples/WINX86/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp b/examples/WINX86/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp index 1fabce1414..3faded59ad 100644 --- a/examples/WINX86/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp +++ b/examples/WINX86/Local/EthernetTCP/PingPong/Transmitter/Transmitter.cpp @@ -1,11 +1,11 @@ -#define PJON_INCLUDE_ETCP + #define _WIN32 -#include +#include // Address of remote device uint8_t remote_ip[] = {127, 0, 0, 1}; -PJON bus(45); +PJONEthernetTCP bus(45); uint32_t count = 0; diff --git a/examples/WINX86/Local/EthernetTCP/RemoteWorker/Transmitter/Transmitter.cpp b/examples/WINX86/Local/EthernetTCP/RemoteWorker/Transmitter/Transmitter.cpp index 65c4ed5a36..6388356519 100644 --- a/examples/WINX86/Local/EthernetTCP/RemoteWorker/Transmitter/Transmitter.cpp +++ b/examples/WINX86/Local/EthernetTCP/RemoteWorker/Transmitter/Transmitter.cpp @@ -24,10 +24,10 @@ Ethernet strategies and related concepts are contributed by Fred Larsen. */ #define ETCP_SINGLE_DIRECTION //#define ETCP_SINGLE_SOCKET_WITH_ACK -#define PJON_INCLUDE_ETCP -#include -PJON bus(45); +#include + +PJONEthernetTCP bus(45); static void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { printf("BLINK\n"); diff --git a/examples/WINX86/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp b/examples/WINX86/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp index b50e841f65..6635aebe11 100644 --- a/examples/WINX86/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp +++ b/examples/WINX86/Local/GlobalUDP/PingPong/Receiver/Receiver.cpp @@ -1,10 +1,10 @@ -#define PJON_INCLUDE_GUDP -#include + +#include // IP Address of the receiver uint8_t remote_ip[] = {127, 0, 0, 1}; -PJON bus(44); +PJONGlobalUDP bus(44); uint32_t count = 0; diff --git a/examples/WINX86/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp b/examples/WINX86/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp index e2417034e4..3b582aad0a 100644 --- a/examples/WINX86/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp +++ b/examples/WINX86/Local/GlobalUDP/PingPong/Transmitter/Transmitter.cpp @@ -1,10 +1,10 @@ -#define PJON_INCLUDE_GUDP -#include + +#include // Address of remote device uint8_t remote_ip[] = {127, 0, 0, 1}; -PJON bus(45); +PJONGlobalUDP bus(45); uint32_t count = 0; diff --git a/examples/WINX86/Local/LocalUDP/PingPong/Receiver/Receiver.cpp b/examples/WINX86/Local/LocalUDP/PingPong/Receiver/Receiver.cpp index cd63eba410..12e5c88436 100644 --- a/examples/WINX86/Local/LocalUDP/PingPong/Receiver/Receiver.cpp +++ b/examples/WINX86/Local/LocalUDP/PingPong/Receiver/Receiver.cpp @@ -1,7 +1,7 @@ -#define PJON_INCLUDE_LUDP -#include -PJON bus(44); +#include + +PJONLocalUDP bus(44); uint32_t count = 0; diff --git a/examples/WINX86/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp b/examples/WINX86/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp index f8571a90fa..78a6eb10ce 100644 --- a/examples/WINX86/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp +++ b/examples/WINX86/Local/LocalUDP/PingPong/Transmitter/Transmitter.cpp @@ -1,7 +1,7 @@ -#define PJON_INCLUDE_LUDP -#include -PJON bus(45); +#include + +PJONLocalUDP bus(45); uint32_t count = 0; diff --git a/examples/WINX86/Local/MQTTTranslate/PingPong/Receiver/Receiver.cpp b/examples/WINX86/Local/MQTTTranslate/PingPong/Receiver/Receiver.cpp index c5e084e6be..c966d5eda2 100644 --- a/examples/WINX86/Local/MQTTTranslate/PingPong/Receiver/Receiver.cpp +++ b/examples/WINX86/Local/MQTTTranslate/PingPong/Receiver/Receiver.cpp @@ -1,15 +1,15 @@ // Use the following define to activate debug // #define MQTT_DEBUGPRINT -#define PJON_INCLUDE_ETCP -#define PJON_INCLUDE_MQTT -#include + + +#include // Ethernet address of the broker uint8_t broker_ip[] = { 127, 0, 0, 1 }; -// bus(selected device id) -PJON bus(44); + +PJONMQTTTranslate bus(44); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/WINX86/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.cpp b/examples/WINX86/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.cpp index ff0366f134..5bf501a570 100644 --- a/examples/WINX86/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.cpp +++ b/examples/WINX86/Local/MQTTTranslate/PingPong/Transmitter/Transmitter.cpp @@ -1,15 +1,15 @@ // Use the following define to activate debug // #define MQTT_DEBUGPRINT -#define PJON_INCLUDE_ETCP -#define PJON_INCLUDE_MQTT -#include + + +#include // Ethernet address of the broker uint8_t broker_ip[] = { 127, 0, 0, 1 }; -// bus(selected device id) -PJON bus(45); + +PJONMQTTTranslate bus(45); uint32_t cnt = 0; uint32_t start = millis(); diff --git a/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/README.md b/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/README.md index 5b48a98cb8..72074e0191 100644 --- a/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/README.md +++ b/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/README.md @@ -7,7 +7,7 @@ Visual Studio 2017 Community is used to compile the program on the Windows x86 m - Click on `file` top menu option, `open` and then `folder...` - Select the `PJON\examples\WINX86\Local\ThroughSerial\BlinkTest\Transmitter` directory - Double click on `Transmitter.cpp` in the solution explorer (panel on right) -- Edit the COM port number (at line 40) inserting the one assigned to the receiver device and save the file +- Edit the COM port number (at line 23) inserting the one assigned to the receiver device and save the file - Click on `Build` top menu option and then click `Build Solution` - If the building process ended positively, you should find the executable in `PJON\examples\WINX86\Local\ThroughSerial\BlinkTest\Transmitter\Debug`, execute `Transmitter.exe` double clicking on it diff --git a/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp b/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp index 86969df23a..8905e58e19 100644 --- a/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp +++ b/examples/WINX86/Local/ThroughSerial/BlinkTest/Transmitter/Transmitter.cpp @@ -1,71 +1,82 @@ + +// This example shows how to send and receive packets over the serial port + +/* WINX86 constant may not be defined + used by PJON to detect windows */ +#ifndef WINX86 + #define WINX86 true +#endif + #include #include + // PJON library #include #include #include #include -#ifndef WINX86 - #define WINX86 true -#endif +// Set the preferred baudrate +#define BAUDRATE 9600 -#define TS_RESPONSE_TIME_OUT 60000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#define TS_COLLISION_DELAY 3000 - -#define PJON_INCLUDE_TS true -#include - -static void receiver_function( - uint8_t *payload, - uint16_t length, - const PJON_Packet_Info &packet_info -) { - for (uint32_t i = 0; i != length; i++) - std::cout << payload[i]; - std::cout << std::endl; +// Set the USB COM port used +#define COM_PORT "COM9" + +// Include PJON library with the ThroughSerial strategy +#include +// Instantiate PJON over ThroughSerial +PJONThroughSerial bus(45); + +// Error handler called when something goes wrong + +void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { + if(code == PJON_CONNECTION_LOST) { + printf("Packet transmission for device id "); + printf("%d", bus.packets[data].content[0]); + printf(" failed, some error occurred. \n"); + } + if(code == PJON_PACKETS_BUFFER_FULL) { + printf("Packet buffer is full with a length of "); + std::cout << data; + printf("\ndefine PJON_MAX_PACKETS setting a higher value. \n"); + } + if(code == PJON_CONTENT_TOO_LONG) { + printf("Packet is too long, length: "); + printf(" %d \n", data); + } + fflush(stdout); }; int main() { printf("PJON instantiation... \n"); - PJON bus(45); - bus.set_receiver(receiver_function); + bus.set_error(error_handler); // Set here the COM port assigned to the device you want to communicate with - tstring commPortName(TEXT("COM9")); - int bitRate = 9600; + tstring com_port(TEXT(COM_PORT)); try { printf("Opening serial... \n"); - Serial serial_handle( - commPortName, - bitRate, - false, - false - ); + Serial serial_handle(com_port, BAUDRATE); printf("Setting serial... \n"); bus.strategy.set_serial(&serial_handle); + printf("Opening bus... \n"); bus.begin(); - printf("Success, initiating BlinkTest repeated transmission... \n"); - while(true) - if(bus.send_packet(44, "B", 1) == PJON_ACK) { - bus.receive(1000000); - printf("Device blinked as requested! \n"); - } else printf("Failure! \n"); - } - catch (const char* msg) { + printf("Success, initiating BlinkTest 1s repeated transmission... \n"); + bus.send_repeatedly(44, "B", 1, 1000000); + + while(true) { + bus.update(); + bus.receive(); + // This line helps to reduce the CPU's usage + PJON_DELAY_MICROSECONDS(10); + } + } catch (const char* msg) { printf("exc: "); printf(msg); printf("\n"); return 1; } - }; diff --git a/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/README.md b/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/README.md new file mode 100644 index 0000000000..ed9f3e1b81 --- /dev/null +++ b/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/README.md @@ -0,0 +1,14 @@ +In this example is described how to connect a Windows x86 machine with an Arduino compatible device using the `ThroughSerial` strategy. Connect the USB port of the windows computer/laptop to the Arduino compatible device used as a receiver. + +Program the Arduino with the `PJON\examples\ARDUINO\Local\ThroughSerial\BlinkWithResponse\Receiver.cpp` sketch and remember the device COM port assigned to that particular Arduino board (the COM selected to program the device in the Arduino IDE) because will be useful later. + +Visual Studio 2017 Community is used to compile the program on the Windows x86 machine: + +- Click on `file` top menu option, `open` and then `folder...` +- Select the `PJON\examples\WINX86\Local\ThroughSerial\BlinkWithResponse\Transmitter` directory +- Double click on `Transmitter.cpp` in the solution explorer (panel on right) +- Edit the COM port number (at line 23) inserting the one assigned to the receiver device and save the file +- Click on `Build` top menu option and then click `Build Solution` +- If the building process ended positively, you should find the executable in `PJON\examples\WINX86\Local\ThroughSerial\BlinkWithResponse\Transmitter\Debug`, execute `Transmitter.exe` double clicking on it + +You should see the Arduino blinking every second and at the same time see a `B` logged in the console (that is the response coming from the Arduino). diff --git a/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.cpp b/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.cpp new file mode 100644 index 0000000000..126ae261b0 --- /dev/null +++ b/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.cpp @@ -0,0 +1,97 @@ + +// This example shows how to send and receive packets over the serial port + +/* WINX86 constant may not be defined + used by PJON to detect windows */ +#ifndef WINX86 + #define WINX86 true +#endif + +#include +#include + +// PJON library +#include +#include +#include +#include + +// Set the preferred baudrate +#define BAUDRATE 9600 + +// Set the USB COM port used +#define COM_PORT "COM9" + +// Include PJON library with ThroughSerial +#include +// Instantiate PJON over ThroughSerial +PJONThroughSerial bus(45); + +// The function called when data is received + +static void receiver_function( + uint8_t *payload, + uint16_t length, + const PJON_Packet_Info &packet_info +) { + // Print data received + for (uint32_t i = 0; i != length; i++) + std::cout << payload[i]; + std::cout << std::endl; + fflush(stdout); +}; + +// Error handler called when something goes wrong + +void error_handler(uint8_t code, uint16_t data, void *custom_pointer) { + if(code == PJON_CONNECTION_LOST) { + printf("Packet transmission for device id "); + printf("%d", bus.packets[data].content[0]); + printf(" failed, some error occurred. \n"); + } + if(code == PJON_PACKETS_BUFFER_FULL) { + printf("Packet buffer is full with a length of "); + std::cout << data; + printf("\ndefine PJON_MAX_PACKETS setting a higher value. \n"); + } + if(code == PJON_CONTENT_TOO_LONG) { + printf("Packet is too long, length: "); + printf(" %d \n", data); + } + fflush(stdout); +}; + +int main() { + printf("PJON instantiation... \n"); + bus.set_receiver(receiver_function); + bus.set_error(error_handler); + + // Set here the COM port assigned to the device you want to communicate with + tstring com_port(TEXT(COM_PORT)); + + try { + printf("Opening serial... \n"); + Serial serial_handle(com_port, BAUDRATE); + + printf("Setting serial... \n"); + bus.strategy.set_serial(&serial_handle); + + printf("Opening bus... \n"); + bus.begin(); + + printf("Success, initiating BlinkTest 1s repeated transmission... \n"); + bus.send_repeatedly(44, "B", 1, 1000000); + + while(true) { + bus.update(); + bus.receive(); + // This line helps to reduce the CPU's usage + PJON_DELAY_MICROSECONDS(10); + } + } catch (const char* msg) { + printf("exc: "); + printf(msg); + printf("\n"); + return 1; + } +}; diff --git a/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.vcxproj b/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.vcxproj similarity index 100% rename from examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.vcxproj rename to examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.vcxproj diff --git a/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.vcxproj.filters b/examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.vcxproj.filters similarity index 100% rename from examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.vcxproj.filters rename to examples/WINX86/Local/ThroughSerial/BlinkWithResponse/Transmitter/Transmitter.vcxproj.filters diff --git a/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/README.md b/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/README.md deleted file mode 100644 index fd3fe797bb..0000000000 --- a/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/README.md +++ /dev/null @@ -1,14 +0,0 @@ -In this example is described how to connect a Windows x86 machine with an Arduino compatible device using the `ThroughSerialAsync` strategy. Connect the USB port of the windows computer/laptop to the Arduino compatible device used as a receiver. - -Program the Arduino with the `PJON\examples\ARDUINO\Local\ThroughSerialAsync\BlinkWithResponse\Receiver.cpp` sketch and remember the device COM port assigned to that particular Arduino board (the COM selected to program the device in the Arduino IDE) because will be useful later. - -Visual Studio 2017 Community is used to compile the program on the Windows x86 machine: - -- Click on `file` top menu option, `open` and then `folder...` -- Select the `PJON\examples\WINX86\Local\ThroughSerialAsync\BlinkWithResponse\Transmitter` directory -- Double click on `Transmitter.cpp` in the solution explorer (panel on right) -- Edit the COM port number (at line 40) inserting the one assigned to the receiver device and save the file -- Click on `Build` top menu option and then click `Build Solution` -- If the building process ended positively, you should find the executable in `PJON\examples\WINX86\Local\ThroughSerialAsync\BlinkWithResponse\Transmitter\Debug`, execute `Transmitter.exe` double clicking on it - -You should see the Arduino blinking every second and at the same time see a `B` logged in the console (that is the response coming from the Arduino). diff --git a/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.cpp b/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.cpp deleted file mode 100644 index 047392e8d6..0000000000 --- a/examples/WINX86/Local/ThroughSerialAsync/BlinkWithResponse/Transmitter/Transmitter.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -// PJON library -#include -#include -#include -#include - -#ifndef WINX86 - #define WINX86 true -#endif - -#define PJON_INCLUDE_TSA true - -#define TSA_RESPONSE_TIME_OUT 35000 -/* Maximum accepted timeframe between transmission and synchronous - acknowledgement. This timeframe is affected by latency and CRC computation. - Could be necessary to higher this value if devices are separated by long - physical distance and or if transmitting long packets. */ - -#include - -static void receiver_function( - uint8_t *payload, - uint16_t length, - const PJON_Packet_Info &packet_info -) { - for (uint32_t i = 0; i != length; i++) - std::cout << payload[i]; - std::cout << std::endl; - fflush(stdout); -}; - -int main() { - printf("PJON instantiation... \n"); - PJON bus(45); - bus.set_receiver(receiver_function); - - // Set here the COM port assigned to the device you want to communicate with - tstring commPortName(TEXT("COM5")); - uint32_t bitRate = 9600; - - try { - printf("Opening serial... \n"); - Serial serial_handle( - commPortName, - bitRate, - false, - false - ); - - printf("Setting serial... \n"); - bus.strategy.set_serial(&serial_handle); - printf("Opening bus... \n"); - bus.begin(); - bus.send_repeatedly(44, "B", 1, 1000000); - printf("Success, initiating BlinkTest repeated transmission... \n"); - - while(true) { - bus.update(); - bus.receive(); - } - } - - catch (const char* msg) { - printf("exc: "); - printf(msg); - printf("\n"); - return 1; - } - -}; diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/.west/config b/examples/ZEPHYR/local/DualUDP/PingPong/.west/config new file mode 100644 index 0000000000..c87176d59c --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/.west/config @@ -0,0 +1,8 @@ +[manifest] +path = Transmitter + +[zephyr] +base = zephyr + +[build] +cmake-args = -DCMAKE_EXPORT_COMPILE_COMMANDS=ON diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/README.md b/examples/ZEPHYR/local/DualUDP/PingPong/README.md new file mode 100644 index 0000000000..54b5b655d5 --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/README.md @@ -0,0 +1,20 @@ +# Zephyr PingPong example +This setup consists of a Transmitter and a Receiver. The Transmitter will regularly send a small packet to the Receiver, and the +Receiver will reply back every time. + + +This example is tested with the [nucleo_f429zi](https://docs.zephyrproject.org/latest/boards/arm/nucleo_f429zi/doc/index.html) board. +You need a command-line Zephyr development environment. Follow [this](https://docs.zephyrproject.org/latest/boards/arm/nucleo_f429zi/doc/index.html) +to install it. + +# Build the example +To build the *Receiver* or the *Transmitter* type the following commands in the shell: + +``` +#> west update +#> source zephyr/zephyr-env.sh +#> west build -b nucleo_f429zi Transmitter -d build_transmitter +#> west build -b nucleo_f429zi Receiver -d build_receiver +#> west flash -d [build_receiver|build_transmitter] +``` + diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/CMakeLists.txt b/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/CMakeLists.txt new file mode 100644 index 0000000000..c590215810 --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.13.1) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(zephyr-sample) + +file(GLOB app_sources src/*.c src/*.cpp) + +include_directories(src) + +target_sources(app PRIVATE ${app_sources} ${smp_srv_sources}) diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/prj.conf b/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/prj.conf new file mode 100644 index 0000000000..d2b69a1f6a --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/prj.conf @@ -0,0 +1,27 @@ +CONFIG_SERIAL=y +CONFIG_GPIO=y + +CONFIG_PJON=y +CONFIG_PJON_DEVICE_ID=44 +CONFIG_NET_L2_ETHERNET_MGMT=y + +CONFIG_CPLUSPLUS=y +CONFIG_STD_CPP17=y +CONFIG_LIB_CPLUSPLUS=y +CONFIG_NEWLIB_LIBC=y +CONFIG_NEWLIB_LIBC_NANO=y + +# CONFIG_TINYCRYPT=y +# CONFIG_LEGACY_DEVICETREE_MACROS=y + +#nucleo +CONFIG_POSIX_API=y + +CONFIG_NETWORKING=y +CONFIG_NET_MGMT=y +CONFIG_NET_IPV4=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_UDP=y +CONFIG_NET_DHCPV4=y + +CONFIG_PJON_STRATEGY_DUALUDP=y diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/src/main.cpp b/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/src/main.cpp new file mode 100644 index 0000000000..8b71ac664b --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/Receiver/src/main.cpp @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include + +/* 1000 msec = 1 sec */ +#define SLEEP_TIME_MS 1000 + +/* The devicetree node identifier for the "led0" alias. */ +#define LED0_NODE DT_ALIAS(led0) + +#if DT_NODE_HAS_STATUS(LED0_NODE, okay) +#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios) +#define PIN DT_GPIO_PIN(LED0_NODE, gpios) +#if DT_PHA_HAS_CELL(LED0_NODE, gpios, flags) +#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios) +#endif +#else +/* A build error here means your board isn't set up to blink an LED. */ +#error "Unsupported board: led0 devicetree alias is not defined" +#define LED0 "" +#define PIN 0 +#endif + +#ifndef FLAGS +#define FLAGS 0 +#endif + +#include "PJONDualUDP.h" + +PJONDualUDP bus(CONFIG_PJON_DEVICE_ID); + +static int cnt = 0; +static struct net_mgmt_event_callback mgmt_cb; + +static void pjon_receive_cb(uint8_t* payload, uint16_t length, const PJON_Packet_Info& packet_info) +{ + if (payload[0] == 'P') { + cnt++; + bus.reply("P", 1); + } +} + + +void pjon_thread(void) +{ + bus.set_receiver(pjon_receive_cb); + bus.begin(); + + printk("PJON Bus started!\n"); + + while (true) { + bus.update(); + bus.receive(); + k_usleep(1); + } +} + +K_THREAD_DEFINE(router_thread, 1024, pjon_thread, NULL, NULL, NULL, 12, 0, 0); + +/* + * print a IP addresse assigned by DHCP + */ +static void handler(struct net_mgmt_event_callback* cb, u32_t mgmt_event, struct net_if* iface) +{ + printk("dhcp handler called!"); + + if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { + return; + } + + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + char buf[NET_IPV4_ADDR_LEN]; + + if (iface->config.ip.ipv4->unicast[i].addr_type != NET_ADDR_DHCP) { + continue; + } + printk("Your address: %s\n", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].address.in_addr, buf, sizeof(buf))); + } +} + +void main(void) +{ + printk("Hello World from Receiver: %s!\n", CONFIG_BOARD); + + struct device *dev; + bool led_is_on = true; + int ret; + + dev = device_get_binding(LED0); + if (dev == NULL) { + return; + } + + ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS); + if (ret < 0) { + return; + } + + // starting dhcpv4 on iface and add handler to print the IP + struct net_if* iface; + net_mgmt_init_event_callback(&mgmt_cb, handler, NET_EVENT_IPV4_ADDR_ADD); + net_mgmt_add_event_callback(&mgmt_cb); + iface = net_if_get_default(); + net_dhcpv4_start(iface); + + while (1) { + gpio_pin_set(dev, PIN, (int)led_is_on); + led_is_on = !led_is_on; + k_msleep(SLEEP_TIME_MS); + printk("PING/s: %d\n", cnt); + cnt = 0; + } +} diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/CMakeLists.txt b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/CMakeLists.txt new file mode 100644 index 0000000000..c590215810 --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.13.1) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(zephyr-sample) + +file(GLOB app_sources src/*.c src/*.cpp) + +include_directories(src) + +target_sources(app PRIVATE ${app_sources} ${smp_srv_sources}) diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/prj.conf b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/prj.conf new file mode 100644 index 0000000000..535e69249e --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/prj.conf @@ -0,0 +1,27 @@ +CONFIG_SERIAL=y +CONFIG_GPIO=y + +CONFIG_PJON=y +CONFIG_PJON_DEVICE_ID=45 +CONFIG_NET_L2_ETHERNET_MGMT=y + +CONFIG_CPLUSPLUS=y +CONFIG_STD_CPP17=y +CONFIG_LIB_CPLUSPLUS=y +CONFIG_NEWLIB_LIBC=y +CONFIG_NEWLIB_LIBC_NANO=y + +# CONFIG_TINYCRYPT=y +# CONFIG_LEGACY_DEVICETREE_MACROS=y + +#nucleo +CONFIG_POSIX_API=y + +CONFIG_NETWORKING=y +CONFIG_NET_MGMT=y +CONFIG_NET_IPV4=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_UDP=y +CONFIG_NET_DHCPV4=y + +CONFIG_PJON_STRATEGY_DUALUDP=y diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/src/main.cpp b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/src/main.cpp new file mode 100644 index 0000000000..6cb9557601 --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/src/main.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +/* 1000 msec = 1 sec */ +#define SLEEP_TIME_MS 1000 + +/* The devicetree node identifier for the "led0" alias. */ +#define LED0_NODE DT_ALIAS(led0) + +#if DT_NODE_HAS_STATUS(LED0_NODE, okay) +#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios) +#define PIN DT_GPIO_PIN(LED0_NODE, gpios) +#if DT_PHA_HAS_CELL(LED0_NODE, gpios, flags) +#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios) +#endif +#else +/* A build error here means your board isn't set up to blink an LED. */ +#error "Unsupported board: led0 devicetree alias is not defined" +#define LED0 "" +#define PIN 0 +#endif + +#ifndef FLAGS +#define FLAGS 0 +#endif + +#include "PJONDualUDP.h" + +PJONDualUDP bus(CONFIG_PJON_DEVICE_ID); + +static int cnt = 0; +static struct net_mgmt_event_callback mgmt_cb; + +static void pjon_receive_cb(uint8_t* payload, uint16_t length, const PJON_Packet_Info& packet_info) +{ + if (payload[0] == 'P') cnt++; +} + + +void pjon_thread(void) +{ + bus.set_receiver(pjon_receive_cb); + + bus.begin(); + printk("PJON Bus started!\n"); + + bus.send_repeatedly(44, "P", 1, 20000); + + while (true) { + bus.update(); + bus.receive(); + k_usleep(10); + } +} + +K_THREAD_DEFINE(router_thread, 1024, pjon_thread, NULL, NULL, NULL, 12, 0, 0); + +/* + * print a IP addresse assigned by DHCP + */ +static void handler(struct net_mgmt_event_callback* cb, u32_t mgmt_event, struct net_if* iface) +{ + printk("dhcp handler called!"); + + if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { + return; + } + + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + char buf[NET_IPV4_ADDR_LEN]; + + if (iface->config.ip.ipv4->unicast[i].addr_type != NET_ADDR_DHCP) { + continue; + } + printk("Your address: %s", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->unicast[i].address.in_addr, buf, sizeof(buf))); + } +} + +void main(void) +{ + printk("Hello World from Transmitter: %s!\n", CONFIG_BOARD); + + struct device *dev; + bool led_is_on = true; + int ret; + + dev = device_get_binding(LED0); + if (dev == NULL) { + return; + } + + ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS); + if (ret < 0) { + return; + } + + // starting dhcpv4 on iface and add handler to print the IP + struct net_if* iface; + net_mgmt_init_event_callback(&mgmt_cb, handler, NET_EVENT_IPV4_ADDR_ADD); + net_mgmt_add_event_callback(&mgmt_cb); + iface = net_if_get_default(); + net_dhcpv4_start(iface); + + while (1) { + gpio_pin_set(dev, PIN, (int)led_is_on); + led_is_on = !led_is_on; + k_msleep(SLEEP_TIME_MS); + printk("PONG/s: %d\n", cnt); + cnt = 0; + } +} diff --git a/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/west.yml b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/west.yml new file mode 100644 index 0000000000..89ba81c591 --- /dev/null +++ b/examples/ZEPHYR/local/DualUDP/PingPong/Transmitter/west.yml @@ -0,0 +1,33 @@ +manifest: + defaults: + remote: zephyr-upstream + + remotes: + - name: zephyr-upstream + url-base: https://github.com/zephyrproject-rtos + + projects: + - name: zephyr + path: zephyr + west-commands: scripts/west-commands.yml + remote: zephyr-upstream + revision: v2.3.0 + + # anything beyond this line is meant to define zephyr modules that use the default remote. + # please have a look into the zephyr/west.yml for available modules + - name: cmsis + path: modules/hal/cmsis + revision: 542b2296e6d515b265e25c6b7208e8fea3014f90 + + - name: tinycrypt + path: modules/crypto/tinycrypt + revision: 3e9a49d2672ec01435ffbf0d788db6d95ef28de0 + + - name: hal_stm32 + revision: d1bc80d021f4ebc31f6e8b36f14b738cc26c7b03 + path: modules/hal/stm32 + + - name: pjon + url: git@github.com:gioblu/PJON.git + revision: master + path: modules/pjon diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.fzz b/examples/routing/ARDUINO/Local/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.fzz similarity index 100% rename from examples/ARDUINO/Local/SoftwareBitBang/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.fzz rename to examples/routing/ARDUINO/Local/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.fzz diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.ino b/examples/routing/ARDUINO/Local/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.ino similarity index 80% rename from examples/ARDUINO/Local/SoftwareBitBang/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.ino rename to examples/routing/ARDUINO/Local/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.ino index 8008342772..2f61aadd4d 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.ino +++ b/examples/routing/ARDUINO/Local/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch.ino @@ -1,20 +1,19 @@ /* Similar to the Switch but with a blinking RGB led indicating each packet that is forwarded with blue and green for each direction respectively, - plus errors in red. */ + plus errors in red. + + This demonstrates how the PJONInteractiveRouter class supports user hooks + for error handling and to catch every packet being forwarded. */ #define PJON_MAX_PACKETS 3 #include +#include +#include // Ethernet configuration for this device, MAC must be unique! byte mac[] = {0xDE, 0x34, 0x4E, 0xEF, 0xFE, 0xE1}; -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1); -PJONAny bus2(&link2); - -PJONInteractiveRouter> router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONInteractiveRouter> router; // Pins for blinking RGB LED for showing traffic in each direction // (Use resistors approximately R:3.3k G:33k, B:8.2k) @@ -25,14 +24,14 @@ uint32_t error_on_time = 0, swbb_on_time = 0, ludp_on_time = 0; void error_handler(uint8_t code, uint16_t data, void *custom_ptr) { digitalWrite(ERROR_LED_PIN, HIGH); - error_on_time = millis(); + error_on_time = millis(); } void setup() { while (Ethernet.begin(mac) == 0) delay(5000); // Wait for DHCP response - link1.strategy.set_pin(7); - link2.strategy.set_port(7200); // Use a "private" UDP port - router.set_sendnotification(sendnotification_function); + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_port(7200); // Use a "private" UDP port + router.set_send_notification(sendnotification_function); router.set_error(error_handler); router.set_virtual_bus(0); // Enable virtual bus router.begin(); diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch_bb.png b/examples/routing/ARDUINO/Local/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch_bb.png similarity index 100% rename from examples/ARDUINO/Local/SoftwareBitBang/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch_bb.png rename to examples/routing/ARDUINO/Local/Tunneler/BlinkingRGBSwitch/BlinkingRGBSwitch_bb.png diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/README.md b/examples/routing/ARDUINO/Local/Tunneler/README.md similarity index 72% rename from examples/ARDUINO/Local/SoftwareBitBang/Tunneler/README.md rename to examples/routing/ARDUINO/Local/Tunneler/README.md index 0994d1c9fa..290d6440f1 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/README.md +++ b/examples/routing/ARDUINO/Local/Tunneler/README.md @@ -2,27 +2,27 @@ You can connect multiple routers, or in this case switches with virtual bus support, in series, with or without devices connected to the buses between the switches. -This pair of examples, `SwitchA` and `SwitchB`, is named `Tunneler` because without changes it allows a collection of `SoftwareBitBang` devices to be connected to another collection of `SoftwareBitBang` devices through two switches connected via a LAN using the `LocalUDP` strategy. +This pair of examples, `SwitchA` and `SwitchB`, is named `Tunneler` because without changes it allows a collection of `SoftwareBitBang` devices to be connected to another collection of `SoftwareBitBang` devices through two switches connected via a LAN using the `DualUDP` strategy. The `SoftwareBitBang` traffic is "tunnelled" through another bus and medium. This is not limited to two groups of devices. You can add another 'SwitchC' and a third group of devices connected with the other two groups by just copying SwitchA.ino and modifying the MAC address so that it is unique on the network. -You can also have a switch or other program using the LocalUDP strategy and the same UDP port running on +You can also have a switch or other program using the DualUDP strategy and the same UDP port running on a Windows or Linux computer. This enables easy connectivity to programs running on a computer, and with the outside world. This setup is running in local mode, not using any bus ids, so all device ids involved must be unique. The switches themselves work in router mode and do not have device ids. -These sketches do not use the default LocalUDP port. Instead they use port 7200 (randomly selected) to have a "private" connection, not mixing with any other LocalUDP setups sharing the same LAN. +These sketches do not use the default DualUDP port. Instead they use port 7200 (randomly selected) to have a "private" or "tunneled" connection, not mixing with any other DualUDP setups sharing the same LAN. ## SwitchA The device is a switch with virtual bus support, meaning that multiple attached buses can use the same bus id or local mode, with the switch adapting to where devices are located. The user does not have to manually assign a specific device range to each attached bus. -It has two buses, a `SoftwareBitBang` bus named `A` and a `LocalUDP` bus named `B`. +It has two buses, a `SoftwareBitBang` bus named `A` and a `DualUDP` bus named `B`. The Ethernet setup is using DHCP to avoid manually configured IP addresses in the skethes. This means that you need to connect both devices to your LAN, not just connect a cable betwen them. -But because LocalUDP is based on UDP broadcasts, it will actually start working with a direct Ethernet cable between `SwitchA` and `SwitchB` after the attempt to get an IP address times out after 60 seconds. +But because DualUDP is based on UDP broadcasts, it will actually start working with a direct Ethernet cable between `SwitchA` and `SwitchB` after the attempt to get an IP address times out after 60 seconds. ## SwitchB diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/SwitchA/SwitchA.ino b/examples/routing/ARDUINO/Local/Tunneler/SwitchA/SwitchA.ino similarity index 53% rename from examples/ARDUINO/Local/SoftwareBitBang/Tunneler/SwitchA/SwitchA.ino rename to examples/routing/ARDUINO/Local/Tunneler/SwitchA/SwitchA.ino index 68c8594c37..a46518956a 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/SwitchA/SwitchA.ino +++ b/examples/routing/ARDUINO/Local/Tunneler/SwitchA/SwitchA.ino @@ -1,26 +1,24 @@ -/* Tunnel packets through another medium using one switch on each end. +/* Tunnel packets through another medium using one switch on each end. / For example, two SoftwareBitBang buses that are far from each other -/ can be joined transparently through a LAN using the LocalUDP strategy, or -/ through a WAN or Internet using the EthernetTCP strategy. */ +/ can be joined transparently through a LAN/WAN using the DualUDP strategy +/ or the EthernetTCP strategy. +/ In this case, use a non-default UDP port to isolate the "tunnel" from +/ potential other DualUDP communication on the same network. */ #define PJON_MAX_PACKETS 3 #include +#include +#include // Ethernet configuration for this device, MAC must be unique! byte mac[] = {0xDE, 0x34, 0x4E, 0xEF, 0xFE, 0xE1}; -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1); -PJONAny bus2(&link2); - -PJONVirtualBusRouter router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONVirtualBusRouter2 router; void setup() { while (Ethernet.begin(mac) == 0) delay(5000); // Wait for DHCP response - link1.strategy.set_pin(7); - link2.strategy.set_port(7200); // Use a "private" UDP port + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_port(7200); // Use a "private" UDP port router.set_virtual_bus(0); // Enable virtual bus router.begin(); } diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/SwitchB/SwitchB.ino b/examples/routing/ARDUINO/Local/Tunneler/SwitchB/SwitchB.ino similarity index 53% rename from examples/ARDUINO/Local/SoftwareBitBang/Tunneler/SwitchB/SwitchB.ino rename to examples/routing/ARDUINO/Local/Tunneler/SwitchB/SwitchB.ino index 367da6cb63..34960c685a 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/Tunneler/SwitchB/SwitchB.ino +++ b/examples/routing/ARDUINO/Local/Tunneler/SwitchB/SwitchB.ino @@ -1,26 +1,24 @@ -/* Tunnel packets through another medium using one switch on each end. +/* Tunnel packets through another medium using one switch on each end. / For example, two SoftwareBitBang buses that are far from each other -/ can be joined transparently through a LAN using the LocalUDP strategy, or -/ through a WAN or Internet using the EthernetTCP strategy. */ +/ can be joined transparently through a LAN/WAN using the DualUDP strategy +/ or the EthernetTCP strategy. +/ In this case, use a non-default UDP port to isolate the "tunnel" from +/ potential other DualUDP communication on the same network. */ #define PJON_MAX_PACKETS 3 #include +#include +#include // Ethernet configuration for this device, MAC must be unique! byte mac[] = {0xEE, 0x79, 0x4E, 0xEF, 0xFE, 0x6D}; -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1); -PJONAny bus2(&link2); - -PJONVirtualBusRouter router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONVirtualBusRouter2 router; void setup() { while (Ethernet.begin(mac) == 0) delay(5000); // Wait for DHCP response - link1.strategy.set_pin(7); - link2.strategy.set_port(7200); // Use a "private" UDP port + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_port(7200); // Use a "private" UDP port router.set_virtual_bus(0); // Enable virtual bus router.begin(); } diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Switch/Device1/Device1.ino b/examples/routing/ARDUINO/Local/VirtualBusRouter/Device1/Device1.ino similarity index 89% rename from examples/ARDUINO/Local/SoftwareBitBang/Switch/Device1/Device1.ino rename to examples/routing/ARDUINO/Local/VirtualBusRouter/Device1/Device1.ino index 1dcf6229af..e179779618 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/Switch/Device1/Device1.ino +++ b/examples/routing/ARDUINO/Local/VirtualBusRouter/Device1/Device1.ino @@ -1,6 +1,6 @@ -#include +#include -PJON bus(100); +PJONSoftwareBitBang bus(100); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { if((char)payload[0] == 'B') { diff --git a/examples/ARDUINO/Local/SoftwareBitBang/Switch/Device2/Device2.ino b/examples/routing/ARDUINO/Local/VirtualBusRouter/Device2/Device2.ino similarity index 91% rename from examples/ARDUINO/Local/SoftwareBitBang/Switch/Device2/Device2.ino rename to examples/routing/ARDUINO/Local/VirtualBusRouter/Device2/Device2.ino index d06e0a0e0f..b90d0769d0 100644 --- a/examples/ARDUINO/Local/SoftwareBitBang/Switch/Device2/Device2.ino +++ b/examples/routing/ARDUINO/Local/VirtualBusRouter/Device2/Device2.ino @@ -1,6 +1,6 @@ -#include +#include -PJON bus(200); +PJONSoftwareBitBang bus(200); void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { /* Make use of the payload before sending something, the buffer where payload points to is diff --git a/examples/routing/ARDUINO/Local/VirtualBusRouter/VirtualBusRouter/VirtualBusRouter.ino b/examples/routing/ARDUINO/Local/VirtualBusRouter/VirtualBusRouter/VirtualBusRouter.ino new file mode 100644 index 0000000000..80a7c560c0 --- /dev/null +++ b/examples/routing/ARDUINO/Local/VirtualBusRouter/VirtualBusRouter/VirtualBusRouter.ino @@ -0,0 +1,39 @@ +#include + +/* This sketch is routing between two local buses to form one larger local bus. + It will discover which attached bus each device is connected to, and route + packets dynamically. + Devices can be placed on any of the attached buses as long as device + ids are unique, forming a "virtual bus". + Using this router class, two or more physical buses can be merged. + It can also be used as a range extender. + + Note that this example demonstrates the general way which allows any + number of buses to be connected. For the simple two-bus case there is + a specialized class allowing for less code. See the example + VirtualBusRouter2.ino for this. + + // ROUTER forwarding from bus 1 to bus 2 and vice versa + __________ ________ __________ + | | Bus 1 Pin 7 | | Pin 12 Bus 2 | | + | DEVICE 1 |_______________| ROUTER |_______________| DEVICE 2 | + |__________| |________| |__________| */ + +StrategyLink link1; +StrategyLink link2; + +PJONAny bus1(&link1); +PJONAny bus2(&link2); + +PJONVirtualBusRouter router(2, (PJONAny*[2]){&bus1, &bus2}); + +void setup() { + link1.strategy.set_pin(7); + link2.strategy.set_pin(12); + router.set_virtual_bus(0); + router.begin(); +}; + +void loop() { + router.loop(); +}; diff --git a/examples/routing/ARDUINO/Local/VirtualBusRouter/VirtualBusRouter2/VirtualBusRouter2.ino b/examples/routing/ARDUINO/Local/VirtualBusRouter/VirtualBusRouter2/VirtualBusRouter2.ino new file mode 100644 index 0000000000..b3115ab106 --- /dev/null +++ b/examples/routing/ARDUINO/Local/VirtualBusRouter/VirtualBusRouter2/VirtualBusRouter2.ino @@ -0,0 +1,27 @@ +#include +#include +#include + +/* This sketch is routing between two local buses to form one larger local bus, + just like the VirtualBusRouter example, but it uses the class + PJONVirtualBusRouter2 which is specialized to using two buses to provide + a simpler declaration. + + // ROUTER forwarding from bus 1 to bus 2 and vice versa + __________ ________ __________ + | | Bus 1 Pin 7 | | Pin 12 Bus 2 | | + | DEVICE 1 |_______________| ROUTER |_______________| DEVICE 2 | + |__________| |________| |__________| */ + +PJONVirtualBusRouter2 router; + +void setup() { + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); + router.set_virtual_bus(0); + router.begin(); +}; + +void loop() { + router.loop(); +}; diff --git a/examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/LocalDevice/LocalDevice.ino b/examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/LocalDevice/LocalDevice.ino similarity index 88% rename from examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/LocalDevice/LocalDevice.ino rename to examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/LocalDevice/LocalDevice.ino index b4e6daf8c6..6e6924753b 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/LocalDevice/LocalDevice.ino +++ b/examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/LocalDevice/LocalDevice.ino @@ -1,21 +1,20 @@ /* Route packets between a local bus and a network bus in both directions, using a switch that supports NAT (network address translation). - - A device on the local bus can send to a device on a network buse by + + A device on the local bus can send to a device on a network bus by specifying the bus id. If the switch has configured a public bus id (a NAT bus id) for this local bus, the remote devices can also reply. __________ ________ __________ | LOCAL | Pin 7 | NAT | Pin 12 | NETWORK | | DEVICE |_______________| SWITCH |_______________| DEVICE | - |__________| Local bus |________| Bus 0.0.0.2 |__________| */ - -#include + |__________| Local bus |________| Bus 0.0.0.2 |__________| + (NAT 0.0.0.1) +*/ -// Bus id definition for the network device -uint8_t remote_bus_id[] = {0, 0, 0, 2}; +#include // PJON object for a local bus -PJON bus(44); +PJONSoftwareBitBang bus(44); void setup() { pinMode(LED_BUILTIN, OUTPUT); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/NATSwitch/NATSwitch.ino b/examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/NATSwitch/NATSwitch.ino similarity index 69% rename from examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/NATSwitch/NATSwitch.ino rename to examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/NATSwitch/NATSwitch.ino index 620969c1b8..9f61b10c58 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/NATSwitch/NATSwitch.ino +++ b/examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/NATSwitch/NATSwitch.ino @@ -1,31 +1,28 @@ /* Route packets between a local bus and a network bus in both directions, using a switch that supports NAT (network address translation). - + The first bus is a local bus, but we still specify a bus id for it. - This will be the "public" bus id for the local bus, allowing it to + This will be the "public" bus id for the local bus, allowing it to be reached from the network bus through NAT (network address translation). __________ ________ __________ | LOCAL | Pin 7 | NAT | Pin 12 | NETWORK | | DEVICE |_______________| SWITCH |_______________| DEVICE | |__________| Local bus |________| Bus 0.0.0.2 |__________| */ -#include - -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1, (uint8_t[4]){0,0,0,1}); // This is a local bus -PJONAny bus2(&link2, (uint8_t[4]){0,0,0,2}); +#include +#include -PJONSwitch router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONSwitch2 router; void setup() { + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); + router.get_bus(0).set_bus_id((const uint8_t[4]){0, 0, 0, 1}); + router.get_bus(1).set_bus_id((const uint8_t[4]){0, 0, 0, 2}); + // We did specify a bus id for the first bus, so it will be in network mode. // Switch it to local mode before starting, activating NAT. - bus1.set_shared_network(false); - - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); + router.get_bus(0).set_shared_network(false); router.begin(); } diff --git a/examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/NetworkDevice/NetworkDevice.ino b/examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/NetworkDevice/NetworkDevice.ino similarity index 91% rename from examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/NetworkDevice/NetworkDevice.ino rename to examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/NetworkDevice/NetworkDevice.ino index c8619fbd18..7460e41382 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/LocalBusViaNATSwitch/NetworkDevice/NetworkDevice.ino +++ b/examples/routing/ARDUINO/Network/LocalBusViaNATSwitch/NetworkDevice/NetworkDevice.ino @@ -1,21 +1,23 @@ /* Route packets between a local bus and a network bus in both directions, using a switch that supports NAT (network address translation). - - The local bus is assigned a public address 0.0.0.1 in the switch, and that + + The local bus is assigned a public address 0.0.0.1 in the switch, and that bus id can be used to reach devices within the local bus. __________ ________ __________ | LOCAL | Pin 7 | NAT | Pin 12 | NETWORK | | DEVICE |_______________| SWITCH |_______________| DEVICE | - |__________| Local bus |________| Bus 0.0.0.2 |__________| */ + |__________| Local bus |________| Bus 0.0.0.2 |__________| + (NAT 0.0.0.1) +*/ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 2}; uint8_t remote_bus_id[] = {0, 0, 0, 1}; // PJON object for a network bus -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); void setup() { pinMode(LED_BUILTIN, OUTPUT); diff --git a/examples/ARDUINO/Network/SoftwareBitBang/Router/DynamicRouter/DynamicRouter.ino b/examples/routing/ARDUINO/Network/Router/DynamicRouter/DynamicRouter.ino similarity index 78% rename from examples/ARDUINO/Network/SoftwareBitBang/Router/DynamicRouter/DynamicRouter.ino rename to examples/routing/ARDUINO/Network/Router/DynamicRouter/DynamicRouter.ino index 4b7d131414..788db715cc 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/Router/DynamicRouter/DynamicRouter.ino +++ b/examples/routing/ARDUINO/Network/Router/DynamicRouter/DynamicRouter.ino @@ -1,4 +1,5 @@ #include +#include /* Route packets between a collection of buses with the same or if required different strategies or media. Packets are routed transparently using a @@ -23,17 +24,13 @@ You may need to restart Device2 so that the packet it sends at startup will be registered and the reverse route established. */ -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1, (const uint8_t[4]){0,0,0,3}); -PJONAny bus2(&link2, (const uint8_t[4]){0,0,0,4}); - -PJONDynamicRouter router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONDynamicRouter2 router; void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); + router.get_bus(0).set_bus_id((const uint8_t[4]){0, 0, 0, 3}); + router.get_bus(1).set_bus_id((const uint8_t[4]){0, 0, 0, 4}); router.begin(); } diff --git a/examples/ARDUINO/Network/SoftwareBitBang/Router/Router/Router.ino b/examples/routing/ARDUINO/Network/Router/Router/Router.ino similarity index 73% rename from examples/ARDUINO/Network/SoftwareBitBang/Router/Router/Router.ino rename to examples/routing/ARDUINO/Network/Router/Router/Router.ino index 3d21da19f4..f54c9026ba 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/Router/Router/Router.ino +++ b/examples/routing/ARDUINO/Network/Router/Router/Router.ino @@ -1,4 +1,5 @@ #include +#include /* Route packets between a collection of buses with the same or if required different strategies or media. @@ -23,18 +24,17 @@ Use Device1 and Device2 from the Switch example */ -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1, (const uint8_t[4]){0,0,0,3}); -PJONAny bus2(&link2, (const uint8_t[4]){0,0,0,4}); - -PJONRouter router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONRouter2 router; void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); + + // Set bus ids + router.get_bus(0).set_bus_id((const uint8_t[4]){0, 0, 0, 3}); + router.get_bus(1).set_bus_id((const uint8_t[4]){0, 0, 0, 4}); + // Populate routing table (which physical bus to use to reach remote bus) router.add((const uint8_t[4]){0,0,0,1}, 0); router.add((const uint8_t[4]){0,0,0,2}, 1); diff --git a/examples/routing/ARDUINO/Network/Switch/BlinkingSwitch/BlinkingSwitch.ino b/examples/routing/ARDUINO/Network/Switch/BlinkingSwitch/BlinkingSwitch.ino new file mode 100644 index 0000000000..27f9faccc3 --- /dev/null +++ b/examples/routing/ARDUINO/Network/Switch/BlinkingSwitch/BlinkingSwitch.ino @@ -0,0 +1,40 @@ + +/* This sketch is just the Switch example with a user defined receive callback. + It demonstrates how to spy on the packets being routed by a switch or router object. + In this case it just makes the on-board LED blink for every packet that passes. + + Note that the default basis for the PJONInteractiveRouter is PJONSwitch, + but that you can specify to use PJONRouter, PJONDynamicRouter or + PJONVirtualBusRouter instead by adding the class as an additional + template parameter, to get additional functionality. + */ + +#include +#include + +PJONInteractiveRouter2 router; + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); + router.get_bus(0).set_bus_id((const uint8_t[4]){0, 0, 0, 1}); + router.get_bus(1).set_bus_id((const uint8_t[4]){0, 0, 0, 2}); + router.set_receiver(receiver_function); + router.set_router(true); // Pick up every packet passing + router.begin(); +} + +void loop() { + router.loop(); +} + +void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { + toggle_led(); +} + +void toggle_led() { + static bool led_is_on = false; + led_is_on = !led_is_on; + digitalWrite(LED_BUILTIN, led_is_on ? HIGH : LOW); +} diff --git a/examples/ARDUINO/Network/SoftwareBitBang/Switch/Device1/Device1.ino b/examples/routing/ARDUINO/Network/Switch/Device1/Device1.ino similarity index 71% rename from examples/ARDUINO/Network/SoftwareBitBang/Switch/Device1/Device1.ino rename to examples/routing/ARDUINO/Network/Switch/Device1/Device1.ino index 6474f95331..7cac7a0280 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/Switch/Device1/Device1.ino +++ b/examples/routing/ARDUINO/Network/Switch/Device1/Device1.ino @@ -6,14 +6,14 @@ | DEVICE 1 |_______________| SWITCH |_______________| DEVICE 2 | |__________| Bus 0.0.0.1 |________| Bus 0.0.0.2 |__________| */ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 1}; uint8_t remote_bus_id[] = {0, 0, 0, 2}; // PJON object -PJON bus(bus_id, 44); +PJONSoftwareBitBang bus(bus_id, 44); void setup() { pinMode(LED_BUILTIN, OUTPUT); @@ -21,11 +21,14 @@ void setup() { bus.strategy.set_pin(7); bus.set_receiver(receiver_function); bus.begin(); - bus.send_repeatedly(45, remote_bus_id, "B", 1, 250000); + bus.send(45, remote_bus_id, "B", 1); } +uint32_t last_incoming = 0; // Time of last incoming packet + void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { if((char)payload[0] == 'B') { + last_incoming = millis(); static bool led_on = false; digitalWrite(LED_BUILTIN, led_on ? HIGH : LOW); led_on = !led_on; @@ -35,4 +38,10 @@ void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info void loop() { bus.receive(1000); bus.update(); + + // Send a reply 1 second after receiving a packet + if (last_incoming != 0 && (uint32_t)(millis() - last_incoming) > 1000) { + bus.reply("B", 1); + last_incoming = 0; + } } diff --git a/examples/ARDUINO/Network/SoftwareBitBang/Switch/Device2/Device2.ino b/examples/routing/ARDUINO/Network/Switch/Device2/Device2.ino similarity index 91% rename from examples/ARDUINO/Network/SoftwareBitBang/Switch/Device2/Device2.ino rename to examples/routing/ARDUINO/Network/Switch/Device2/Device2.ino index d3cca2cf7e..715ecd0f27 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/Switch/Device2/Device2.ino +++ b/examples/routing/ARDUINO/Network/Switch/Device2/Device2.ino @@ -6,14 +6,14 @@ | DEVICE 1 |_______________| SWITCH |_______________| DEVICE 2 | |__________| Bus 0.0.0.1 |________| Bus 0.0.0.2 |__________| */ -#include +#include // Bus id definition uint8_t bus_id[] = {0, 0, 0, 2}; uint8_t remote_bus_id[] = {0, 0, 0, 1}; // PJON object -PJON bus(bus_id, 45); +PJONSoftwareBitBang bus(bus_id, 45); void setup() { pinMode(LED_BUILTIN, OUTPUT); @@ -22,7 +22,6 @@ void setup() { bus.strategy.set_pin(12); bus.set_receiver(receiver_function); bus.begin(); - bus.send(44, remote_bus_id, "B", 1); } void receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { diff --git a/examples/ARDUINO/Network/SoftwareBitBang/Switch/Switch/Switch.ino b/examples/routing/ARDUINO/Network/Switch/SimpleSwitch/SimpleSwitch.ino similarity index 52% rename from examples/ARDUINO/Network/SoftwareBitBang/Switch/Switch/Switch.ino rename to examples/routing/ARDUINO/Network/Switch/SimpleSwitch/SimpleSwitch.ino index a974162d6b..36592d9aa8 100644 --- a/examples/ARDUINO/Network/SoftwareBitBang/Switch/Switch/Switch.ino +++ b/examples/routing/ARDUINO/Network/Switch/SimpleSwitch/SimpleSwitch.ino @@ -1,23 +1,24 @@ #include +#include /* Route packets between a collection of buses with the same or different strategies or media. + + PJONSimpleSwitch routes between buses of the same strategy. + It uses less storage and RAM than the more general PJONSwitch. __________ ________ __________ | | Pin 7 | | Pin 12 | | | DEVICE 1 |_______________| SWITCH |_______________| DEVICE 2 | |__________| Bus 0.0.0.1 |________| Bus 0.0.0.2 |__________| */ -StrategyLink link1; -StrategyLink link2; - -PJONAny bus1(&link1, (uint8_t[4]){0,0,0,1}); -PJONAny bus2(&link2, (uint8_t[4]){0,0,0,2}); +PJONSoftwareBitBang bus1((const uint8_t[4]){0, 0, 0, 1}, PJON_NOT_ASSIGNED), + bus2((const uint8_t[4]){0, 0, 0, 2}, PJON_NOT_ASSIGNED); -PJONSwitch router(2, (PJONAny*[2]){&bus1, &bus2}); +PJONSimpleSwitch router(bus1, bus2); void setup() { - link1.strategy.set_pin(7); - link2.strategy.set_pin(12); + bus1.strategy.set_pin(7); + bus2.strategy.set_pin(12); router.begin(); } diff --git a/examples/routing/ARDUINO/Network/Switch/Switch/Switch.ino b/examples/routing/ARDUINO/Network/Switch/Switch/Switch.ino new file mode 100644 index 0000000000..8a06cb52d1 --- /dev/null +++ b/examples/routing/ARDUINO/Network/Switch/Switch/Switch.ino @@ -0,0 +1,27 @@ +#include +#include + +/* Route packets between a collection of buses with the same + or different strategies or media. + + PJONSwitch can route between buses of different strategies, + though not shown here. If using only one strategy, some + resources can be saved by using PJONSimpleSwitch instead. + __________ ________ __________ + | | Pin 7 | | Pin 12 | | + | DEVICE 1 |_______________| SWITCH |_______________| DEVICE 2 | + |__________| Bus 0.0.0.1 |________| Bus 0.0.0.2 |__________| */ + +PJONSwitch2 router; + +void setup() { + router.get_strategy_0().set_pin(7); + router.get_strategy_1().set_pin(12); + router.get_bus(0).set_bus_id((const uint8_t[4]){0, 0, 0, 1}); + router.get_bus(1).set_bus_id((const uint8_t[4]){0, 0, 0, 2}); + router.begin(); +} + +void loop() { + router.loop(); +} diff --git a/keywords.txt b/keywords.txt index 8b47c64c51..8df241623d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -2,11 +2,10 @@ # Syntax Coloring Map For PJON ####################################### -####################################### # Datatypes (KEYWORD1) -####################################### -Any KEYWORD1 +## PJON classes and data types + StrategyLink KEYWORD1 PJON KEYWORD1 PJONLocal KEYWORD1 @@ -18,47 +17,50 @@ PJONDynamicRouter KEYWORD1 PJONInteractiveRouter KEYWORD1 PJONVirtualBusRouter KEYWORD1 PJONTools KEYWORD1 +PJON_Packet KEYWORD1 +PJON_Endpoint KEYWORD1 +PJON_Packet_Info KEYWORD1 +PJON_Error KEYWORD1 + +## Strategies + AnalogSampling KEYWORD1 -SoftwareBitBang KEYWORD1 -OverSampling KEYWORD1 -ThroughSerial KEYWORD1 -ThroughSerialAsync KEYWORD1 -ThroughLora KEYWORD1 +Any KEYWORD1 +DualUDP KEYWORD1 +ESPNOW KEYWORD1 EthernetTCP KEYWORD1 -LocalUDP KEYWORD1 +GlobalUDP KEYWORD1 LocalFile KEYWORD1 +LocalUDP KEYWORD1 MQTTTranslate KEYWORD1 -GlobalUDP KEYWORD1 -DualUDP KEYWORD1 -ESPNOW KEYWORD1 -PJON_Packet KEYWORD1 -PJON_Packet_Info KEYWORD1 -PJON_Error KEYWORD1 +OverSampling KEYWORD1 +SoftwareBitBang KEYWORD1 +ThroughLora KEYWORD1 +ThroughSerial KEYWORD1 -####################################### # Methods and Functions (KEYWORD2) -####################################### -acquire_id KEYWORD2 begin KEYWORD2 can_start KEYWORD2 device_id KEYWORD2 -discard_device_id KEYWORD2 get_packets_count KEYWORD2 -get_rid KEYWORD2 -include_sender_info KEYWORD2 +get_bus_id KEYWORD2 +get_mac KEYWORD2 +include_mac KEYWORD2 include_port KEYWORD2 +include_sender_info KEYWORD2 receive KEYWORD2 remove KEYWORD2 -remove_all KEYWORD2 +remove_all_packets KEYWORD2 ready_to_send KEYWORD2 reply KEYWORD2 send KEYWORD2 send_repeatedly KEYWORD2 send_packet KEYWORD2 send_packet_blocking KEYWORD2 -set_synchronous_acknowledge KEYWORD2 -set_asynchronous_acknowledge KEYWORD2 +set_acknowledge KEYWORD2 +set_bus_id KEYWORD2 +set_mac KEYWORD2 set_random_seed KEYWORD2 set_communication_mode KEYWORD2 set_error KEYWORD2 @@ -72,63 +74,96 @@ set_packet_id KEYWORD2 strategy KEYWORD2 update KEYWORD2 -####################################### # Instances (KEYWORD2) -####################################### +PJONAnalogSampling +PJONAny KEYWORD2 +PJONDualUDP KEYWORD2 +PJONESPNOW KEYWORD2 +PJONEthernetTCP KEYWORD2 +PJONGlobalUDP KEYWORD2 +PJONLocalUDP KEYWORD2 +PJONMQTTTranslate KEYWORD2 +PJONOverSampling KEYWORD2 +PJONSoftwareBitBang KEYWORD2 +PJONThroughLora KEYWORD2 +PJONThroughSerial KEYWORD2 -####################################### # Constants (LITERAL1) -####################################### -PJON_LOCAL LITERAL1 -PJON_ACK LITERAL1 + +## PJON basic constants + +localhost LITERAL1 +PJON_NOT_ASSIGNED LITERAL1 PJON_BROADCAST LITERAL1 -PJON_BUSY LITERAL1 -COLLISION_MAX_DELAY LITERAL1 -PJON_CONNECTION_LOST LITERAL1 -PJON_CONTENT_TOO_LONG LITERAL1 -PJON_FAIL LITERAL1 -PJON_MAX_PACKETS LITERAL1 -PJON_MASTER_ID LITERAL1 +PJON_ACK LITERAL1 PJON_NAK LITERAL1 -PJON_NOT_ASSIGNED LITERAL1 -PJON_PACKETS_BUFFER_FULL LITERAL1 -PJON_PACKET_MAX_LENGTH LITERAL1 +PJON_FAIL LITERAL1 +PJON_BUSY LITERAL1 PJON_SIMPLEX LITERAL1 PJON_HALF_DUPLEX LITERAL1 PJON_TO_BE_SENT LITERAL1 -localhost LITERAL1 + +## PJON errors + +PJON_PACKETS_BUFFER_FULL LITERAL1 +PJON_CONNECTION_LOST LITERAL1 +PJON_CONTENT_TOO_LONG LITERAL1 + +## Constraints + +PJON_PACKET_MAX_LENGTH LITERAL1 +PJON_MAX_PACKETS LITERAL1 +PJON_MAX_RECENT_PACKET_IDS LITERAL1 + +## Header bits + PJON_MODE_BIT LITERAL1 PJON_TX_INFO_BIT LITERAL1 PJON_ACK_REQ_BIT LITERAL1 -PJON_ACK_MODE_BIT LITERAL1 +PJON_MAC_BIT LITERAL1 PJON_CRC_BIT LITERAL1 PJON_EXT_LEN_BIT LITERAL1 PJON_PORT_BIT LITERAL1 PJON_PACKET_ID_BIT LITERAL1 + +## Conditional feature inclusion + +PJON_LOCAL LITERAL1 PJON_INCLUDE_PACKET_ID LITERAL1 -PJON_INCLUDE_ASYNC_ACK LITERAL1 -PJON_MAX_RECENT_PACKET_IDS LITERAL1 +PJON_INCLUDE_PORT LITERAL1 +PJON_INCLUDE_MAC LITERAL1 + +## AnalogSampling + +AS_BIT_WIDTH LITERAL1 +AS_BIT_SPACER LITERAL1 +AS_READ_DELAY LITERAL1 AS_MODE LITERAL1 -SWBB_MODE LITERAL1 -SWBB_RESPONSE_TIMEOUT LITERAL1 -OS_TIMEOUT LITERAL1 AS_TIMEOUT LITERAL1 +AS_RESPONSE_TIMEOUT LITERAL1 +AS_MAX_ATTEMPTS LITERAL1 + +## MQTTTranslate + MQTTT_MODE_BUS_RAW LITERAL1 MQTTT_MODE_BUS_JSON LITERAL1 MQTTT_MODE_MIRROR_TRANSLATE LITERAL1 MQTTT_MODE_MIRROR_DIRECT LITERAL1 -PJON_INCLUDE_MQTT LITERAL1 -PJON_INCLUDE_SWBB LITERAL1 -PJON_INCLUDE_AS LITERAL1 -PJON_INCLUDE_ETCP LITERAL1 -PJON_INCLUDE_GUDP LITERAL1 -PJON_INCLUDE_LUDP LITERAL1 -PJON_INCLUDE_OS LITERAL1 -PJON_INCLUDE_TS LITERAL1 -PJON_INCLUDE_TSA LITERAL1 -PJON_INCLUDE_TL LITERAL1 -PJON_INCLUDE_EN LITERAL1 -PJON_INCLUDE_ANY LITERAL1 -PJON_INCLUDE_LF LITERAL1 -PJON_INCLUDE_NONE LITERAL1 + +## OverSampling + +OS_TIMEOUT LITERAL1 +OS_BIT_WIDTH LITERAL1 +OS_BIT_SPACER LITERAL1 +OS_ACCEPTANCE LITERAL1 +OS_MAX_ATTEMPTS LITERAL1 + +## SoftwareBitBang +SWBB_BIT_WIDTH LITERAL1 +SWBB_BIT_SPACER LITERAL1 +SWBB_ACCEPTANCE LITERAL1 +SWBB_READ_DELAY LITERAL1 +SWBB_MODE LITERAL1 +SWBB_RESPONSE_TIMEOUT LITERAL1 +SWBB_MAX_ATTEMPTS LITERAL1 diff --git a/library.json b/library.json index e6791d69aa..ca7098ed7d 100644 --- a/library.json +++ b/library.json @@ -1,7 +1,7 @@ { "name": "PJON", "description": "PJON is an open-source, multi-master, multi-media network protocol stack", - "homepage": "https://www.pjon.org", + "homepage": "https://github.com/gioblu/PJON", "keywords": "pjon, communication, bus, protocol, network, multimaster, iot, ethernet, wifi, tcp, udp, usb, rs232, rs485, ask, fsk, ook, pjdl, pjdlr, pjdls, lora, arduino, esp8266, esp32, teensy, attiny, windows, linux, apple, android", "license": "Apache-2.0", "authors": @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/gioblu/PJON.git" }, - "version": "12.1", + "version": "13.1", "examples": [ "examples/*/*/*/*/*.ino", "examples/*/*/*/*/*.h", @@ -26,7 +26,8 @@ ], "frameworks": [ "arduino", - "wiringpi" + "wiringpi", + "zephyr" ], "platforms": [ "atmelavr", diff --git a/library.properties b/library.properties index f9763725ec..21be0ea8bd 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=PJON -version=12.1 +version=13.1 author=Giovanni Blu Mitolo maintainer=Giovanni Blu Mitolo sentence=PJON is an open-source, multi-master, multi-media bus network protocol diff --git a/specification/PJON-network-services-list.md b/specification/PJON-network-services-list.md index 4f2271e860..e1e09b4174 100644 --- a/specification/PJON-network-services-list.md +++ b/specification/PJON-network-services-list.md @@ -1,14 +1,13 @@ ### Specifications index #### Network layer -- [PJON (Padded Jittering Operative Network) v3.2](/specification/PJON-protocol-specification-v3.2.md) -- [Acknowledge specification v1.0](/specification/PJON-protocol-acknowledge-specification-v1.0.md) +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) - **[Network services list](/specification/PJON-network-services-list.md)** #### Data link layer -- [PJDL (Padded Jittering Data Link) v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) +- [PJDL (Padded Jittering Data Link) v5.0](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) - [PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) - [PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) -- [TSDL (Tardy Serial Data Link) v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) +- [TSDL (Tardy Serial Data Link) v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) - [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) --- diff --git a/specification/PJON-protocol-specification-v4.0.md b/specification/PJON-protocol-specification-v4.0.md new file mode 100644 index 0000000000..74bf97c68f --- /dev/null +++ b/specification/PJON-protocol-specification-v4.0.md @@ -0,0 +1,356 @@ +### Specifications index + +#### Network layer +- **[PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md)** +- [Network services list](/specification/PJON-network-services-list.md) +#### Data link layer +- [PJDL (Padded Jittering Data Link) v5.0](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) +- [PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) +- [PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) +- [TSDL (Tardy Serial Data Link) v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) +- [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) + +--- + +## PJON® v4.0 +``` +Invented by Giovanni Blu Mitolo +with the help of Fred Larsen +Originally published: 10/04/2010 +Latest revision: 28/08/2020 +Related work: https://github.com/gioblu/PJON/ +Compliant implementations: PJON v13.0 and following +Released into the public domain + +10/04/2010 0.1 - First local mode draft +19/08/2015 0.2 - First local and shared mode draft +04/09/2016 0.3 - Added header proposed by Fred Larsen +03/10/2016 1.0 - 16 bits length, CRC8 and CRC32 added +28/03/2017 1.1 - Removed NAK, added unacceptable headers +15/10/2017 2.0 - Length corruption vulnerability avoided +14/12/2017 3.0 - Port and packet id added +31/10/2018 3.1 - Model simplified +10/03/2020 3.2 - Missing encoding specification added +28/08/2020 4.0 - MAC and hops added, async-ack removed +``` + +The PJON protocol v4.0 in local mode supports connectivity for up to 254 devices, in shared mode supports connectivity for up to 4.294.967.295 buses (groups of devices) and up to 1.090.921.692.930 devices. The packet format is dynamic therefore meta-data can be optionally included using the header as a bitmap of selected features. It supports interoperability between systems that use a different configuration and provides with high efficiency including only the protocol's features used and the overhead effectively required (5-35 bytes). PJON can be used for low-data-rate applications as an alternative to 1-Wire, i2c or CAN but can also be applied in place of IP to interconnect more complex networks. + +The graph below shows the conceptual model that characterizes and standardizes the communication. Its goal is the interoperability of diverse systems on a wide range of media with the use of a new set of Open Standards. The graph partitions represent abstraction layers. + +``` + ________________________________________________ +| 3 Network layer: PJON | +|- Optional features ----------------------------| +| Routing and switching | +| Hop count (8 bits) | +| Hardware identification (48 bits) | +| Service identification (16 bits) | +| Packet identification (16 bits) | +| Bus identification (32 bits) | +| Sender identification | +| Packet transmission, maximum length 65535B | +|- Core features --------------------------------| +| Congestion control | +| Packet transmission, maximum length 255B | +| Error detection (16 or 40 bits) | +| Device identification (8 bits) | +| Broadcast | +|________________________________________________| +| 2 Data link layer: PJDL, PJDLR, PJDLS, TSDL | +| Acknowledgement | +| Frame transmission | +| Medium access control | +|________________________________________________| +| 1 Physical layer: | +| Electric, radio or light impulses | +|________________________________________________| +``` + +### Basic concepts +* Devices are identified by a unique 8 bits device id +* Buses are identified with a 32 bits bus id +* Devices can be optionally identified with a 48 bits MAC address +* Devices communicate using packets with a maximum length of 255 or 65535 bytes +* Packet transmission is regulated by a 8 bits header +* An acknowledgement can be requested +* Packets can be optionally identified with a 16 bits packet id +* Network services are optionally identified with a 16 bits port id + +### Bus +A bus is a group of up to 254 devices. Devices use packets to communicate with each other. Devices can send packets and optionally request an acknowledgement. Devices can also broadcast packets. When the device id is not known, devices must use id 255. +```cpp + _______ _______ _______ _______ +| | | | | | | | +| ID 1 | | ID 2 | | ID 3 | | ID 4 | +|_______| |_______| |_______| |_______| +____|___________|___________|___________|___ + ___|___ ___|___ ___|___ + | | | | | | + | ID 5 | | ID 6 | | ID 7 | + |_______| |_______| |_______| + +ID 0 = BROADCAST +ID 255 = NOT ASSIGNED +``` + +### Bus network +A bus network is composed by buses present on the same collision domain or interconnected through switches or routers. On a shared medium an additional 32 bits bus id must be used to isolate groups of devices from foreign traffic. +```cpp +TWO BUSES SHARING THE SAME MEDIUM +1 collision domain + + BUS ID 0.0.0.1 BUS ID 0.0.0.2 + _______ _______ _______ _______ +| | | | | | | | +| ID 1 | | ID 2 | | ID 1 | | ID 2 | +|_______| |_______| |_______| |_______| +______|___________|__________|___________|___ + ___|___ ___|___ + | | | | + | ID 3 | | ID 3 | + |_______| |_______| +``` + +### Switch +A switch is a device that forwards packets transparently between connected buses. The switch can operate also if different physical layers are in use and can rely on a default gateway. +```cpp + ______ ________ ______ +| | PJDL bus | | PJDLR bus | | +| ID 1 |__________| SWITCH |___________| ID 2 | +|______| |________| |______| + +ID 254 = DEFAULT GATEWAY +``` + +### Router +A router is a device connected to more than one PJON bus that routes packets from a device, a bus or a medium to another. Packets can be routed between indirectly connected buses if a routing table or a default gateway is used. +```cpp +TWO BUSES CONNECTED THROUGH A ROUTER +2 collision domains + + BUS ID 0.0.0.1 BUS ID 0.0.0.2 + _______ _______ _______ _______ +| | | | | | | | +| ID 1 | | ID 2 | | ID 1 | | ID 2 | +|_______| |_______| ______ |_______| |_______| +_____|___________|____|ROUTER|_____|___________|____ + ___|___ | ID 3 | ___|___ + | | |______| | | + | ID 3 | | ID 3 | + |_______| |_______| +``` + +### Header configuration +The header is a bitmap of the meta-data contained and the configuration required. Unlike other protocols, PJON has a dynamic packet format designed to include in each packet only what is strictly required to carry out the exchange. Depending on the bitmap configuration a variable overhead (5-35 bytes) is added to information. +```cpp +HEADER BITMAP + 8 7 6 5 4 3 2 1 + ______ ______ ____ _____ _____ _____ _____ _____ +|PACKET|EXT. |CRC |PORT | MAC | ACK |TX |MODE | +|ID |LENGTH| | | | |INFO | | +|______|______|____|_____|_____|_____|_____|_____| +``` +1. `MODE` bit informs if the packet is formatted in [shared](/specification/PJON-protocol-specification-v4.0.md#shared-mode) (value 1) or [local](/specification/PJON-protocol-specification-v4.0.md#local-mode) mode (value 0) +2. `TX INFO` bit informs if the sender info are included (value 1) or not (value 0) +3. `ACK` bit informs if the [acknowledgement](/specification/PJON-protocol-specification-v4.0.md#packet-transmission) is requested (value 1) or not (value 0) +4. `MAC` bit informs if sender's and recipient's [hardware identification](/specification/PJON-protocol-specification-v4.0.md#hardware-identification), or MAC address, are included (value 1) or not (value 0) +5. `PORT` bit informs if a 16 bits [network service identifier](/specification/PJON-protocol-specification-v4.0.md#network-services) is included (value 1) or not (value 0) +6. `CRC` bit signals which CRC is used, [CRC8](/specification/PJON-protocol-specification-v4.0.md#crc8-polynomial) (value 0) or [CRC32](/specification/PJON-protocol-specification-v4.0.md#crc32-polynomial) (value 1) +7. `EXT. LENGTH` bit informs if the packet contains 8 (value 0) or 16 bits (value 1) [length](/specification/PJON-protocol-specification-v4.0.md#extended-length) +8. `PACKET ID` bit informs if the packet contains (value 1) or not (value 0) a 16 bits [packet id](/specification/PJON-protocol-specification-v4.0.md#packet-identification) + +Unacceptable header configuration states for standard transmission: +* `-10-----` or `EXT. LENGTH` bit high and `CRC` bit low (forced CRC32 for length > 15) + +Unacceptable header configuration states for a broadcast transmission: +* `-----1--` or `ACK` bit high (acknowledgement not supported if broadcasting) + +`-` symbol means irrelevant bit value + +### Cyclic redundancy check +PJON supports both CRC8 and CRC32 to ensure safety on a wide range of use cases and packet lengths. + +#### CRC8 polynomial +```cpp +0x97 = (x + 1)(x^7 + x^6 + x^5 + x^2 + 1)^2 +``` +`CRC8 C2`, discovered by Tsonka Baicheva, is used (in implicit +1 notation) because it has the longest possible length (119 bits) at which `HD=4` can be achieved with an 8-bit CRC. Other protocols specify the use of polynomials with much lower overall performance like `CRC-8 0xEA` or `DOWCRC 0x8C` used by 1-Wire. + +#### CRC32 polynomial +```cpp +0x82608edb = x^32 + x^26 + x^23 + x^22 + x^16 + + x^12 + x^11 + x^10 + x^8 + x^7 + + x^5 + x^4 + x^2 + x + 1 +``` +`CRC32 IEEE 802.3` bit-reversed polynomial implicit +1 notation, or `0xedb88320`, is selected for its high performance on a wide range of lengths, while also being widely evaluated and accepted as a good polynomial. + +#### Initial meta-data CRC8 +CRC8 is calculated and appended to the initial meta-data (device id, header and length) to ensure consistency and avoid the length corruption vulnerability that affects CAN (Controlled Area Network) and many other protocols. + +#### End CRC8/CRC32 +CRC8 is appended at the end of packets of up to 15 bytes length (overhead included). CRC32 is instead used if the packet's length exceeds 15 bytes but can be optionally applied in shorter packets setting the `CRC` bit high if more secure error detection is required. + +### Packet transmission +A local packet transmission is an optionally bidirectional communication between two devices that can be divided in 3 phases: **medium access**, **transmission** and optional **acknowledgement**. In the medium access phase the medium's state is assessed before starting transmission to avoid collision. If the medium is free for use, the transmission phase starts in which the packet is entirely transmitted in network byte order. The receiving device computes the CRC and starts the acknowledgement phase transmitting `ACK` (decimal 6) in case of correct data reception. If no acknowledgement is received, after an exponential back-off delay, the transmitter retries until the acknowledgement is received or a maximum number of attempts is reached. +```cpp +Medium access Transmission Response + _____ _______________________________________________ _____ +| M-A || ID | HEADER | LENGTH | CRC8 | DATA | CRC8 || ACK | +|-----||----|----------|--------|------|--------|------||-----| +| 0 || 12 | 00000100 | 6 | | 64 | || 6 | +|_____||____|__________|________|______|________|______||_____| + BITS: | 8 | 8 | 8 | 8 | 8 | 8 | + |____|__________|________|______|________|______| +``` +The acknowledgement ensures reliable delivery only when a packet transmission occurs directly without the intermediation of routers or switches. When a packet needs to traverse a network the acknowledegment is transmitted by the nearest intermediary therefore it ensures only best-effort delivery. + +The medium access, collision resolution, transmission and acknowledgement procedures are specified by the underlying layer, which also supplies the maximum number of attempts and the timing required for retransmission. + +#### Local mode +Depending on header's `MODE` bit packets can contain basic or extended support to identification. Local mode required by header's `MODE` bit low supports connectivity for up to 254 devices. In the graph below is represented the simplest local mode packet format sending `@` (decimal 64) to device `12`: + +```cpp + _________________________________ +|ID| HEADER |LENGTH|CRC8|DATA|CRC8| +|--|--------|------|----|----|----| +|12|00000000| 6 | | 64 | | +|__|________|______|____|____|____| +|8 | 8 | 8 | 8 | 8 | 8 | 48 bits +|__|________|______|____|____|____| + +``` + +In local mode a broadcast can be sent to all devices sending to device id `0`. Acknowledgement is not supported therefore any broadcast that requests an acknowledgement is ignored by recipients. + +```cpp + _________________________________ +|ID| HEADER |LENGTH|CRC8|DATA|CRC8| +|--|--------|------|----|----|----| +|0 |00000000| 6 | | 64 | | +|__|________|______|____|____|____| +|8 | 8 | 8 | 8 | 8 | 8 | 48 bits +|__|________|______|____|____|____| + + +``` + +If header's `TX INFO` bit is high the sender's device id is included in the packet. In the example below device id `11` sends `@` to device id `12`. + +```cpp + ____ + | TX | + | ID | + _______________________\__/_________ +|ID| HEADER |LENGTH|CRC8|ID|DATA|CRC8| +|--|--------|------|----|--|----|----| +|12|00000010| 7 | |11| 64 | | +|__|________|______|____|__|____|____| +|8 | 8 | 8 | 8 |8 | 8 | 8 | 56 bits +|__|________|______|____|__|____|____| + + +``` + +#### Shared mode +If header's `MODE` bit is high [bus](/specification/PJON-protocol-specification-v4.0.md#bus) identification is added to the packet. The same local transmission used as an example above is formatted to be sent in shared mode to device id `12` of bus id `0.0.0.1`. The packet's payload is prepended with the bus id of the recipient and the hop count: +```cpp + _____________________________________________ +|ID| HEADER |LENGTH|CRC8|BUS ID|HOP|DATA|CRC8| +|--|--------|------|----|------|---|----|----| +|12|00000001| 11 | | 0001 | 0 | 64 | | +|__|________|______|____|______|___|____|____| +|8 | 8 | 8 | 8 | 32 | 8 | 8 | 8 | 88 bits +|__|________|______|____|______|___|____|____| + +``` + +In shared mode a broadcast can be sent to all devices sharing the same bus id sending to device id `0`. Acknowledgement is not supported therefore any broadcast that requests an acknowledgement is ignored by recipients. + +```cpp + ____________________________________________ +|ID| HEADER |LENGTH|CRC8|BUS ID|HOP|DATA|CRC8| +|--|--------|------|----|------|---|----|----| +|0 |00000001| 11 | | 0001 | 0 | 64 | | +|__|________|______|____|______|___|____|____| +|8 | 8 | 8 | 8 | 32 | 8 | 8 | 8 | 88 bits +|__|________|______|____|______|___|____|____| + +``` + +If header's `TX INFO` bit is high the sender's device and bus id are included in the packet. In the example below device id `11` of bus id `0.0.0.1` sends to device id `12` of bus id `0.0.0.1`. + +```cpp + _________ + | TX INFO | + ______________________________|_________|_____________ +|ID| HEADER |LENGTH|CRC8|BUS ID|BUS ID|ID|HOP|DATA|CRC8| +|--|--------|------|----|------|------|--|---|----|----| +|12|00000011| 16 | | 0001 | 0001 |11| 0 | 64 | | +|__|________|______|____|______|______|__|___|____|____| +|8 | 8 | 8 | 8 | 32 | 32 |8 | 8 | 8 | 8 | 128 bits +|__|________|______|____|______|______|__|___|____|____| +``` + +The hop count must be incremented each time the packet is forwarded and routers must ignore packets when a maximum amount of hops is reached. + +#### Extended length +if the header's `EXT. LENGTH` bit is high the length of the packet is represented with 16 bits supporting a maximum length of up to 65535 bytes. If the `EXT. LENGTH` bit is low the packet length is represented with 8 bits supporting a maximum length of up to 255 bytes. If the extended length feature is used, CRC32 must be applied setting the header's `CRC` bit high. +```cpp + _______________________________________ +|ID| HEADER |LEN 1|LEN 2|CRC8|DATA|CRC32| +|--|--------|-----|-----|----|----|-----| +|12|01100000| 0 | 10 | | 64 | | +|__|________|_____|_____|____|____|_____| +|8 | 8 | 8 | 8 | 8 | 8 | 32 | 80 bits +|__|________|_____|_____|____|____|_____| + +``` + +#### Packet identification +if the header's `PACKET ID` bit is high a 16 bits packet identifier is added to the packet. The graph below shows a packet in which a 16 bits packet identifier is included. This feature is provided to avoid duplications and guarantee packet uniqueness. The receiver discards packets containing a packet identifier and sender information already appeared previously. +```cpp + ____________________________________________ +|ID| HEADER |LENGTH|CRC8|PACKET ID|DATA|CRC32| +|--|--------|------|----|---------|----|-----| +|12|10000000| 11 | | 999 | 64 | | +|__|________|______|____|_________|____|_____| +|8 | 8 | 8 | 8 | 16 | 8 | 32 | 88 bits +|__|________|______|____|_________|____|_____| + +``` + +#### Network services +if the header's `PORT` bit is high a 16 bits port id is added to the packet. Thanks to this feature different services, protocols or formats can coexist and be identified safely. Ports from `0` to `8000` are reserved for the [known network services](/specification/PJON-network-services-list.md), ports from `8001` to `65535` are free for use. The graph below shows a packet transmission where port 8002 is inserted in the packet and header's `PORT` bit is high to signal its presence. +```cpp + _________________________________________ +|ID| HEADER |LENGTH|CRC8|PORT ID|DATA|CRC8| +|--|--------|------|----|-------|----|----| +|12|00010000| 8 | | 8002 | 64 | | +|__|________|______|____|_______|____|____| +|8 | 8 | 8 | 8 | 16 | 8 | 8 | 64 bits +|__|________|______|____|_______|____|____| +``` + +#### Hardware identification +If the header's `MAC` bit is high both recipient's and sender's 48 bits MAC addresses are included in the packet. The recipient's MAC address must match the MAC address of the receiver otherwise the packet is discarded. When the hardware identification is present the packet is received even if the bus id and or the device id don't match. If a packet contains an empty recipient's MAC or `0.0.0.0.0.0` it is not discarded even if the MAC address do not match. The graph below shows a broadcast packet transmission where MAC address `1.1.1.1.1.1` sends to MAC address `2.2.2.2.2.2` the payload 64. +```cpp + ________________________________________________ +|ID| HEADER |LENGTH|CRC8|RX MAC|TX MAC|DATA|CRC32| +|--|--------|------|----|------|------|----|-----| +|0 |00001000| 12 | |222222|111111| 64 | | +|__|________|______|____|______|______|____|_____| +|8 | 8 | 8 | 8 | 48 | 48 | 8 | 32 | 168 bits +|__|________|______|____|______|______|____|_____| +``` +When a device knows its own MAC address but doesn't know its own device id it must use device id 255. To reach another device in the same configuration, it can transmit packets to device id 255 and include the MAC addresses setting the `MAC` bit high. In this case even if many devices could be present using device id 255, only the one with the matching MAC address receives the packet. If the `ACK` bit is high the receiver can send an acknowledge, although also a broadcast can be used if the acknowledgement is not required. + +```cpp + _________________________________________________ ___ +|ID | HEADER |LENGTH|CRC8|RX MAC|TX MAC|DATA|CRC32||ACK| +|---|--------|------|----|------|------|----|-----||---| +|255|00001100| 12 | |222222|111111| 64 | || 6 | +|___|________|______|____|______|______|____|_____||___| +| 8 | 8 | 8 | 8 | 48 | 48 | 8 | 32 | 168 bits +|___|________|______|____|______|______|____|_____| +``` diff --git a/specification/SFSP-frame-separation-specification-v1.0.md b/specification/SFSP-frame-separation-specification-v1.0.md index 7abe425e85..37cdeb2e71 100644 --- a/specification/SFSP-frame-separation-specification-v1.0.md +++ b/specification/SFSP-frame-separation-specification-v1.0.md @@ -1,14 +1,13 @@ ### Specifications index #### Network layer -- [PJON (Padded Jittering Operative Network) v3.2](/specification/PJON-protocol-specification-v3.2.md) -- [Acknowledge specification v1.0](/specification/PJON-protocol-acknowledge-specification-v1.0.md) +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) - [Network services list](/specification/PJON-network-services-list.md) #### Data link layer - [PJDL (Padded Jittering Data Link) v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) - [PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) - [PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) -- [TSDL (Tardy Serial Data Link) v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) +- [TSDL (Tardy Serial Data Link) v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) - **[SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md)** --- diff --git a/specification/obsolete/PJON-dynamic-addressing-specification-v0.1.md b/specification/obsolete/PJON-dynamic-addressing-specification-v0.1.md index 201985edc1..7a6b0c97e7 100644 --- a/specification/obsolete/PJON-dynamic-addressing-specification-v0.1.md +++ b/specification/obsolete/PJON-dynamic-addressing-specification-v0.1.md @@ -4,7 +4,7 @@ Milan, Italy - 02/10/2016 The PJON® dynamic addressing specification is an invention and intellectual property of Giovanni Blu Mitolo -Copyright 2010-2020 All rights reserved +Copyright 2010-2025 All rights reserved Related work: https://github.com/gioblu/PJON/ Compliant implementation versions: PJON 5.2 and following diff --git a/specification/obsolete/PJON-dynamic-addressing-specification-v3.0.md b/specification/obsolete/PJON-dynamic-addressing-specification-v3.0.md index 826def1d1b..c8dd78d773 100644 --- a/specification/obsolete/PJON-dynamic-addressing-specification-v3.0.md +++ b/specification/obsolete/PJON-dynamic-addressing-specification-v3.0.md @@ -36,7 +36,7 @@ _______|________________|___________| BUS ID 0.0.0.1 | | 0.0.8.1.1 | | 0.0.8.121.1 | |_____________| |_____________| ``` -Regardless of the master or the network addresses used by the network layer, slaves remain uniquely identified by their own device address. In an isolated scenario device addresses can be generated and assigned as required. If the application is connected to a shared medium where collisions with other systems may occur, it is strongly suggested to request a unique device address here: [https://www.pjon.org/get-device-address.php](https://www.pjon.org/get-device-address.php). +Regardless of the master or the network addresses used by the network layer, slaves remain uniquely identified by their own device address. In an isolated scenario device addresses can be generated and assigned as required. If the application is connected to a shared medium where collisions with other systems may occur. #### Procedure All communication used to request and assign ids is transmitted using CRC32 on the `PJON_DYNAMIC_ADDRESSING_PORT` port (decimal 1). Masters routinely broadcast a `PJON_ID_DISCOVERY` (decimal 200) advertisement to let slaves be aware of their presence. diff --git a/specification/obsolete/PJON-protocol-acknowledge-specification-v0.1.md b/specification/obsolete/PJON-protocol-acknowledge-specification-v0.1.md index 614851a70b..a438f9bda3 100644 --- a/specification/obsolete/PJON-protocol-acknowledge-specification-v0.1.md +++ b/specification/obsolete/PJON-protocol-acknowledge-specification-v0.1.md @@ -4,7 +4,7 @@ Milan, Italy - 17/10/2016 The PJON® protocol acknowledge specification is an invention and intellectual property of Giovanni Blu Mitolo -Copyright 2010-2020 All rights reserved +Copyright 2010-2025 All rights reserved Related work: https://github.com/gioblu/PJON/ Compliant implementation versions: PJON 6.0 and following diff --git a/specification/PJON-protocol-acknowledge-specification-v1.0.md b/specification/obsolete/PJON-protocol-acknowledge-specification-v1.0.md similarity index 100% rename from specification/PJON-protocol-acknowledge-specification-v1.0.md rename to specification/obsolete/PJON-protocol-acknowledge-specification-v1.0.md diff --git a/specification/obsolete/PJON-protocol-acknowledge-specification-v2.0.md b/specification/obsolete/PJON-protocol-acknowledge-specification-v2.0.md new file mode 100644 index 0000000000..ad7e597fe8 --- /dev/null +++ b/specification/obsolete/PJON-protocol-acknowledge-specification-v2.0.md @@ -0,0 +1,40 @@ +### Specifications index + +#### Network layer +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) +- **[Acknowledge specification v2.0](/specification/PJON-protocol-acknowledge-specification-v2.0.md)** +- [Network services list](/specification/PJON-network-services-list.md) +#### Data link layer +- [PJDL (Padded Jittering Data Link) v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) +- [PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) +- [PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) +- [TSDL (Tardy Serial Data Link) v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) +- [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) + +--- + +## PJON® acknowledge v2.0 +``` +Invented by Giovanni Blu Mitolo +Originally published: 17/10/2016 +Latest revision: 30/04/2020 +Related implementation: https://github.com/gioblu/PJON/ +Compliant versions: PJON v13.0 and following +Released into the public domain +``` +PJON supports the synchronous acknowledgement feature used to have reception certainty. + +### Synchronous acknowledge +When the synchronous acknowledgement is requested, the transmitter has reception certainty. The acknowledgement is composed by a single byte (`ACK` or 6) at the network layer but each strategy may implement it according to their features and limitations. +```cpp +Channel analysis Transmission Response + _____ ____________________________________________ _____ +| C-A || ID | HEADER | LENGTH |CRC8| CONTENT |CRC8|| ACK | +|-----||----|----------|--------|----|---------|----||-----| +| 0 || 12 | 00000100 | 6 | | 64 | || 6 | +|_____||____|__________|________|____|_________|____||_____| +``` + +A receiver device responds `ACK` if transmission occurs correctly, instead does not respond nothing if an error is detected. + +The graph above contains a packet transmission where the character `@` or 64 is sent to device id `12`. As defined by the [PJON protocol layer specification v4.0](/specification/PJON-protocol-specification-v4.0.md), the header's `ACK` bit high requests a synchronous acknowledgement response, see [PJDL v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md), [PJDLR v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md), [PJDLS v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) and [TSDL v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) specification for additional information. diff --git a/specification/obsolete/PJON-protocol-specification-v0.1.md b/specification/obsolete/PJON-protocol-specification-v0.1.md index dfe66d6db0..b828db6af2 100644 --- a/specification/obsolete/PJON-protocol-specification-v0.1.md +++ b/specification/obsolete/PJON-protocol-specification-v0.1.md @@ -3,7 +3,7 @@ /* Milan, Italy - 10/04/2010 The PJON® protocol specification is an invention and intellectual property -of Giovanni Blu Mitolo - Copyright 2010-2020 All rights reserved +of Giovanni Blu Mitolo - Copyright 2010-2025 All rights reserved Related work: https://github.com/gioblu/PJON Compliant implementation versions: PJON 1.0-3.0-beta diff --git a/specification/obsolete/PJON-protocol-specification-v0.2.md b/specification/obsolete/PJON-protocol-specification-v0.2.md index b97e42ea8a..39da02befc 100644 --- a/specification/obsolete/PJON-protocol-specification-v0.2.md +++ b/specification/obsolete/PJON-protocol-specification-v0.2.md @@ -3,7 +3,7 @@ /* Milan, Italy - 19/08/2015 The PJON® protocol specification is an invention and intellectual property -of Giovanni Blu Mitolo - Copyright 2010-2020 All rights reserved +of Giovanni Blu Mitolo - Copyright 2010-2025 All rights reserved Related work: https://github.com/gioblu/PJON/ Compliant implementation versions: PJON 3.0-beta-3.0 diff --git a/specification/obsolete/PJON-protocol-specification-v0.3.md b/specification/obsolete/PJON-protocol-specification-v0.3.md index 44bb8e4a2b..64fa9264bf 100644 --- a/specification/obsolete/PJON-protocol-specification-v0.3.md +++ b/specification/obsolete/PJON-protocol-specification-v0.3.md @@ -3,7 +3,7 @@ /* Milan, Italy - 04/09/2016 The PJON® protocol specification is an invention and intellectual property -of Giovanni Blu Mitolo - Copyright 2010-2020 All rights reserved +of Giovanni Blu Mitolo - Copyright 2010-2025 All rights reserved Related work: https://github.com/gioblu/PJON/ Compliant implementation versions: PJON 4.0-5.0 diff --git a/specification/obsolete/PJON-protocol-specification-v1.0.md b/specification/obsolete/PJON-protocol-specification-v1.0.md index e2d4411b1a..9ef220e4ac 100644 --- a/specification/obsolete/PJON-protocol-specification-v1.0.md +++ b/specification/obsolete/PJON-protocol-specification-v1.0.md @@ -3,7 +3,7 @@ /* Milan, Italy - 3/10/2016 The PJON® protocol layer specification is an invention and intellectual property -of Giovanni Blu Mitolo - Copyright 2010-2020 All rights reserved +of Giovanni Blu Mitolo - Copyright 2010-2025 All rights reserved Related work: https://github.com/gioblu/PJON/ Compliant implementation versions: PJON 6.0 and following @@ -60,7 +60,7 @@ In the graph below is shown the protocol stack model proposed. The differences b * Transmission occurs only if the communication medium is not in use * Devices communicate through packets with a maximum length of 255 or 65535 bytes * Packet transmission is regulated by a 1, 2 or 3 byte header -* Synchronous and or asynchronous acknowledgement can be requested (see [Acknowledge specification v0.1](/specification/PJON-protocol-acknowledge-specification-v0.1.md)) +* A synchronous acknowledgement can be requested (see [Acknowledge specification v0.1](/specification/PJON-protocol-acknowledge-specification-v0.1.md)) The PJON protocol v1.0 handles internal bus connectivity and unique addressing for 254 devices, through bus communication with unique bus addressing for 4.294.967.295 buses and supports up to 1.090.921.692.930 devices. It regulates the exchange of packets with a configurable set of features driven by its header. Depending on the packet configuration a certain overhead is added to information varying from 4 up to 19 bytes. diff --git a/specification/obsolete/PJON-protocol-specification-v1.1.md b/specification/obsolete/PJON-protocol-specification-v1.1.md index 9637b57a2b..b2fb6456b5 100644 --- a/specification/obsolete/PJON-protocol-specification-v1.1.md +++ b/specification/obsolete/PJON-protocol-specification-v1.1.md @@ -4,7 +4,7 @@ Milan, Italy - 28/03/2017 The PJON® protocol layer specification is an invention and intellectual property of Giovanni Blu Mitolo -Copyright 2010-2020 All rights reserved +Copyright 2010-2025 All rights reserved Related work: https://github.com/gioblu/PJON/ Compliant implementation versions: PJON 6.0 and following diff --git a/specification/PJON-protocol-specification-v3.2.md b/specification/obsolete/PJON-protocol-specification-v3.2.md similarity index 100% rename from specification/PJON-protocol-specification-v3.2.md rename to specification/obsolete/PJON-protocol-specification-v3.2.md diff --git a/src/PJON.h b/src/PJON.h index 2d6b69b687..bfda7f90c4 100644 --- a/src/PJON.h +++ b/src/PJON.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -20,7 +20,7 @@ contributors, the protocol's documentation, specification and implementation have been strongly tested, enhanced and verified: Fred Larsen, Zbigniew Zasieczny, Matheus Garbelini, sticilface, - Felix Barbalet, Oleh Halitskiy, fabpolli, Adrian Sławiński, + Felix Barbalet, Oleh Halitskiy, fotosettore, fabpolli, Adrian Sławiński, Osman Selçuk Aktepe, Jorgen-VikingGod, drtrigon, Endre Karlson, Wilfried Klaas, budaics, ibantxo, gonnavis, maxidroms83, Evgeny Dontsov, zcattacz, Valerii Koval, Ivan Kravets, Esben Soeltoft, Alex Grishin, @@ -28,8 +28,8 @@ have been strongly tested, enhanced and verified: pacproduct, elusive-code, Emanuele Iannone, Christian Pointner, Fabian Gärtner, Mauro Mombelli, Remo Kallio, hyndruide, sigmaeo, filogranaf, Maximiliano Duarte, Viktor Szépe, Shachar Limor, Andrei Volkau, maniekq, - DetAtHome, Michael Branson, chestwood96, Mattze96, Steven Bense - and Jack Anderson. + DetAtHome, Michael Branson, chestwood96, Mattze96, Steven Bense, + Jack Anderson, callalilychen and Julio Aguirre. Compatible tools: @@ -43,7 +43,7 @@ Compatible tools: This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -60,7 +60,6 @@ limitations under the License. */ #pragma once #include "interfaces/PJON_Interfaces.h" #include "PJONDefines.h" -#include "strategies/PJON_Strategies.h" static void PJON_dummy_receiver_handler( uint8_t *, // payload @@ -69,9 +68,9 @@ static void PJON_dummy_receiver_handler( ) {}; static void PJON_dummy_error_handler( - uint8_t, // code - uint16_t, // data - void * // custom_pointer + uint8_t, // code + uint16_t, // data + void * // custom_pointer ) {}; template @@ -79,29 +78,29 @@ class PJON { public: Strategy strategy; uint8_t config = PJON_TX_INFO_BIT | PJON_ACK_REQ_BIT; - uint8_t bus_id[4] = {0, 0, 0, 0}; uint8_t data[PJON_PACKET_MAX_LENGTH]; PJON_Packet_Info last_packet_info; PJON_Packet packets[PJON_MAX_PACKETS]; - uint16_t port = PJON_BROADCAST; - uint8_t random_seed = A0; + PJON_Endpoint tx; - #if(PJON_INCLUDE_ASYNC_ACK || PJON_INCLUDE_PACKET_ID) + #if(PJON_INCLUDE_PACKET_ID) PJON_Packet_Record recent_packet_ids[PJON_MAX_RECENT_PACKET_IDS]; #endif + #if(PJON_INCLUDE_PORT) + uint16_t port = PJON_BROADCAST; + #endif + /* PJON initialization with no parameters: State: Local (bus_id: 0.0.0.0) - Synchronous acknowledge: true - Asynchronous acknowledge: false + Acknowledge: true device id: PJON_NOT_ASSIGNED (255) Mode: PJON_HALF_DUPLEX - Sender info: true (Sender info are included in the packet) + Sender info: true (Sender info is included in the packet) PJON bus; */ PJON() : strategy(Strategy()) { - _device_id = PJON_NOT_ASSIGNED; set_default(); }; @@ -109,7 +108,7 @@ class PJON { PJON bus(1); */ PJON(uint8_t device_id) : strategy(Strategy()) { - _device_id = device_id; + tx.id = device_id; set_default(); }; @@ -118,45 +117,62 @@ class PJON { PJON bus(my_bys, 1); */ PJON(const uint8_t *b_id, uint8_t device_id) : strategy(Strategy()) { - PJONTools::copy_bus_id(bus_id, b_id); - _device_id = device_id; + tx.id = device_id; + PJONTools::copy_id(tx.bus_id, b_id, 4); + config |= PJON_MODE_BIT; set_default(); }; + #if(PJON_INCLUDE_MAC) + + /* PJON initialization passing the mac address: + const uint8_t mac[6] = {1, 2, 3, 4, 5, 6}; + PJON bus(mac); */ + + PJON(const uint8_t *mac_addr) : strategy(Strategy()) { + PJONTools::copy_id(tx.mac, mac_addr, 6); + config |= PJON_MAC_BIT; + set_default(); + }; + + #endif + /* Begin function to be called after initialization: */ void begin() { - PJON_RANDOM_SEED(PJON_ANALOG_READ(random_seed) + _device_id); - strategy.begin(_device_id); - #if(PJON_INCLUDE_ASYNC_ACK || PJON_INCLUDE_PACKET_ID) - _packet_id_seed = PJON_RANDOM(65535) + _device_id; + PJON_RANDOM_SEED(PJON_ANALOG_READ(_random_seed) + tx.id); + strategy.begin(tx.id); + #if(PJON_INCLUDE_PACKET_ID) + _packet_id_seed = PJON_RANDOM(65535) + tx.id; #endif }; /* Compose packet in PJON format: */ uint16_t compose_packet( - const uint8_t rx_id, - const uint8_t *rx_bus_id, + PJON_Packet_Info info, uint8_t *destination, const void *source, - uint16_t length, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST + uint16_t length ) { + info.header = (info.header == PJON_NO_HEADER) ? config : info.header; + info.tx = tx; + #if(PJON_INCLUDE_PACKET_ID) + if(!info.id && (info.header & PJON_PACKET_ID_BIT)) + info.id = PJONTools::new_packet_id(_packet_id_seed++); + #endif + #if(PJON_INCLUDE_PORT) + if( + (port != PJON_BROADCAST) && (info.port == PJON_BROADCAST) && + (info.header & PJON_PORT_BIT) + ) info.port = port; + #endif + #if(PJON_INCLUDE_MAC) + if(info.header & PJON_MAC_BIT) + PJONTools::copy_id(info.tx.mac, tx.mac, 6); + #endif uint16_t l = PJONTools::compose_packet( - _device_id, - bus_id, - rx_id, - rx_bus_id, - destination, - source, - length, - (header == PJON_NO_HEADER) ? config : header, - (!packet_id) ? PJONTools::new_packet_id(_packet_id_seed++) : packet_id, - rx_port, - port + info, destination, source, length ); if(l < PJON_PACKET_MAX_LENGTH) return l; _error(PJON_CONTENT_TOO_LONG, l, _custom_pointer); @@ -165,35 +181,22 @@ class PJON { /* Get device id: */ - uint8_t device_id() const { - return _device_id; - }; + uint8_t device_id() const { return tx.id; }; /* Add packet to buffer (delivery attempt by the next update() call): */ uint16_t dispatch( - uint8_t rx_id, - const uint8_t *rx_bus_id, + const PJON_Packet_Info &info, const void *packet, uint16_t length, - uint32_t timing, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST, + uint32_t timing = 0, uint16_t packet_index = PJON_FAIL ) { bool p = (packet_index != PJON_FAIL); for(uint16_t i = ((p) ? packet_index : 0); i < PJON_MAX_PACKETS; i++) if(packets[i].state == 0 || p) { if(!(length = compose_packet( - rx_id, - rx_bus_id, - packets[i].content, - packet, - length, - header, - packet_id, - rx_port + info, packets[i].content, packet, length ))) return PJON_FAIL; packets[i].length = length; packets[i].state = PJON_TO_BE_SENT; @@ -205,30 +208,10 @@ class PJON { return PJON_FAIL; }; - /* Check if a packet id is already dispatched in buffer: */ + /* Returns a pointer to the bus id used by the instance: */ - bool dispatched(PJON_Packet_Info info) { - PJON_Packet_Info actual_info; - for(uint16_t i = 0; i < PJON_MAX_PACKETS; i++) { - parse((uint8_t *)packets[i].content, actual_info); - if( - packets[i].state && packets[i].state != PJON_ACK && - (actual_info.header & PJON_ACK_MODE_BIT) && - (actual_info.header & PJON_TX_INFO_BIT) - ) - if( - actual_info.id == info.id && - info.sender_id == actual_info.receiver_id && - ( - !(info.header & PJON_MODE_BIT) ? true : - PJONTools::bus_id_equality( - info.receiver_bus_id, - actual_info.receiver_bus_id - ) - ) - ) return true; - } - return false; + const uint8_t *get_bus_id() const { + return tx.bus_id; }; /* Get count of packets: @@ -247,6 +230,31 @@ class PJON { return packets_count; }; + /* Fill a PJON_Packet_Info using parameters: */ + + PJON_Packet_Info fill_info( + uint8_t rx_id, + uint8_t header, + uint16_t packet_id, + uint16_t rx_port + ) { + PJON_Packet_Info info; + info.rx.id = rx_id; + info.header = header; + PJONTools::copy_id(info.rx.bus_id, tx.bus_id, 4); + #if(PJON_INCLUDE_PACKET_ID) + info.id = packet_id; + #else + (void)packet_id; + #endif + #if(PJON_INCLUDE_PORT) + info.port = rx_port; + #else + (void)rx_port; + #endif + return info; + }; + /* Calculate packet overhead: */ uint8_t packet_overhead(uint8_t header = PJON_NO_HEADER) const { @@ -268,8 +276,7 @@ class PJON { uint16_t length = PJON_PACKET_MAX_LENGTH; uint16_t batch_length = 0; uint8_t overhead = 0; - bool extended_length = false; - bool async_ack = false; + bool extended_length = false, mac = false, drop = false; for(uint16_t i = 0; i < length; i++) { if(!batch_length) { batch_length = strategy.receive_frame(data + i, length - i); @@ -279,40 +286,35 @@ class PJON { batch_length--; if(i == 0) - if(data[i] != _device_id && data[i] != PJON_BROADCAST && !_router) - return PJON_BUSY; + if((data[i] != tx.id) && (data[i] != PJON_BROADCAST) && !_router) + drop = true; if(i == 1) { + mac = (data[1] & PJON_MAC_BIT); if( ( !_router && ((config & PJON_MODE_BIT) && !(data[1] & PJON_MODE_BIT)) ) || ( - data[0] == PJON_BROADCAST && - ((data[1] & PJON_ACK_MODE_BIT) || (data[1] & PJON_ACK_REQ_BIT)) - ) || ( - (data[1] & PJON_ACK_MODE_BIT) && !(data[1] & PJON_TX_INFO_BIT) + (data[0] == PJON_BROADCAST) && (data[1] & PJON_ACK_REQ_BIT) ) || ( (data[1] & PJON_EXT_LEN_BIT) && !(data[1] & PJON_CRC_BIT) - ) || ( - !PJON_INCLUDE_ASYNC_ACK && (data[1] & PJON_ACK_MODE_BIT) ) || ( !PJON_INCLUDE_PACKET_ID && (data[1] & PJON_PACKET_ID_BIT) - ) + ) || ( + !PJON_INCLUDE_PORT && (data[1] & PJON_PORT_BIT) + ) || ( + (!PJON_INCLUDE_MAC && mac) || (mac && !(data[1] & PJON_CRC_BIT)) + ) || (drop && !mac) ) return PJON_BUSY; extended_length = data[i] & PJON_EXT_LEN_BIT; overhead = packet_overhead(data[i]); - async_ack = ( - PJON_INCLUDE_ASYNC_ACK && - (data[1] & PJON_ACK_MODE_BIT) && - (data[1] & PJON_TX_INFO_BIT) - ); } if((i == 2) && !extended_length) { length = data[i]; if( - length < (uint8_t)(overhead + !async_ack) || + length < (uint8_t)(overhead + 1) || length >= PJON_PACKET_MAX_LENGTH ) return PJON_BUSY; if(length > 15 && !(data[1] & PJON_CRC_BIT)) return PJON_BUSY; @@ -321,19 +323,20 @@ class PJON { if((i == 3) && extended_length) { length = (data[i - 1] << 8) | (data[i] & 0xFF); if( - length < (uint8_t)(overhead + !async_ack) || + length < (uint8_t)(overhead + 1) || length >= PJON_PACKET_MAX_LENGTH ) return PJON_BUSY; if(length > 15 && !(data[1] & PJON_CRC_BIT)) return PJON_BUSY; } if( - ((data[1] & PJON_MODE_BIT) && !_router) && + ((data[1] & PJON_MODE_BIT) && !_router && !mac) && (i > (uint8_t)(3 + extended_length)) && (i < (uint8_t)(8 + extended_length)) ) { if(config & PJON_MODE_BIT) { - if(bus_id[i - 4 - extended_length] != data[i]) return PJON_BUSY; + if(tx.bus_id[i - 4 - extended_length] != data[i]) + return PJON_BUSY; } else if(data[i] != 0) return PJON_BUSY; // Do not reject localhost } } @@ -352,44 +355,35 @@ class PJON { } else if(PJON_crc8::compute(data, length - 1) != data[length - 1]) return PJON_NAK; + #if(PJON_INCLUDE_MAC) + if(mac && (length > 15) && !_router) + if(!PJONTools::id_equality(data + (overhead - 16), tx.mac, 6)) + if(! + PJONTools::id_equality( + data + (overhead - 16), + PJONTools::no_mac(), 6 + ) + ) return PJON_BUSY; + #endif + if(data[1] & PJON_ACK_REQ_BIT && data[0] != PJON_BROADCAST) if((_mode != PJON_SIMPLEX) && !_router) strategy.send_response(PJON_ACK); parse(data, last_packet_info); - #if(PJON_INCLUDE_ASYNC_ACK || PJON_INCLUDE_PACKET_ID) - bool filter = - (last_packet_info.header & PJON_PACKET_ID_BIT) ? true : false; - /* If a packet requesting asynchronous acknowledgement is received - send the acknowledgement packet back to the packet's transmitter */ - if(async_ack && !_router) { - if(_auto_delete && length == overhead) - if(handle_asynchronous_acknowledgment(last_packet_info)) - return PJON_ACK; - if(length > overhead) { - if(!dispatched(last_packet_info)) { - dispatch( - last_packet_info.sender_id, - (uint8_t *)last_packet_info.sender_bus_id, - NULL, - 0, - 0, - config | PJON_ACK_MODE_BIT | PJON_TX_INFO_BIT, - last_packet_info.id, - last_packet_info.port - ); - update(); - } - filter = true; - } - } - if(filter && known_packet_id(last_packet_info) && !_router) - return PJON_ACK; + #if(PJON_INCLUDE_PACKET_ID) + if( + !_router && + (last_packet_info.header & PJON_PACKET_ID_BIT) && + known_packet_id(last_packet_info) + ) return PJON_ACK; #endif - if((port != PJON_BROADCAST) && (port != last_packet_info.port)) - return PJON_BUSY; + #if(PJON_INCLUDE_PORT) + if((port != PJON_BROADCAST) && (port != last_packet_info.port)) + return PJON_BUSY; + #endif _receiver( data + (overhead - PJONTools::crc_overhead(data[1])), @@ -424,46 +418,6 @@ class PJON { } }; - /* Remove a packet from buffer passing its packet id as reference: */ - - bool handle_asynchronous_acknowledgment(PJON_Packet_Info packet_info) { - PJON_Packet_Info actual_info; - for(uint16_t i = 0; i < PJON_MAX_PACKETS; i++) { - parse((uint8_t *)packets[i].content, actual_info); - if(actual_info.id == packet_info.id) - if(actual_info.receiver_id == packet_info.sender_id && ( - (!(actual_info.header & PJON_MODE_BIT) && - !(packet_info.header & PJON_MODE_BIT)) ? true : - PJONTools::bus_id_equality( - actual_info.receiver_bus_id, - packet_info.sender_bus_id - ) - )) { - if(packets[i].timing) { - uint8_t offset = packet_overhead(actual_info.header); - uint8_t crc_offset = - PJONTools::crc_overhead(actual_info.header); - dispatch( - actual_info.receiver_id, - (uint8_t *)actual_info.receiver_bus_id, - packets[i].content + (offset - crc_offset), - packets[i].length - offset, - packets[i].timing, - actual_info.header, - PJONTools::new_packet_id(_packet_id_seed++), - actual_info.port, - i - ); - packets[i].attempts = 0; - return true; - } - remove(i); - return true; - } - } - return false; - }; - /* Remove all packets from the buffer: Don't pass any parameter to delete all packets Pass a device id to delete all it's related packets */ @@ -475,29 +429,46 @@ class PJON { } }; + /* Reset a packet sending present in the buffer: */ + + bool reset_packet(uint16_t id) { + if(!packets[id].timing) { + if(_auto_delete) { + remove(id); + return true; + } + } else { + packets[id].attempts = 0; + packets[id].registration = PJON_MICROS(); + packets[id].state = PJON_TO_BE_SENT; + } + return false; + }; + /* Schedule a packet sending to the sender of the last packet received. This function is typically called within the receive callback to deliver a response to a request. */ - uint16_t reply( - const void *payload, - uint16_t length, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST - ) { - if(last_packet_info.sender_id != PJON_BROADCAST) - return dispatch( - last_packet_info.sender_id, - last_packet_info.sender_bus_id, - payload, - length, - 0, - ((header == PJON_NO_HEADER) ? last_packet_info.header : header), - packet_id, - rx_port - ); - return false; + uint16_t reply(const void *payload, uint16_t length) { + PJON_Packet_Info info; + info = last_packet_info; + info.rx = info.tx; + info.header = config; + #ifndef PJON_LOCAL + info.hops = 0; + #endif + return dispatch(info, payload, length); + }; + + uint16_t reply_blocking(const void *payload, uint16_t length) { + PJON_Packet_Info info; + info = last_packet_info; + info.rx = info.tx; + info.header = config; + #ifndef PJON_LOCAL + info.hops = 0; + #endif + return send_packet_blocking(info, payload, length); }; /* Schedule a packet sending: */ @@ -510,55 +481,49 @@ class PJON { uint16_t packet_id = 0, uint16_t rx_port = PJON_BROADCAST ) { - return dispatch( - rx_id, bus_id, payload, length, 0, header, packet_id, rx_port - ); + PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port); + return dispatch(info, payload, length); }; uint16_t send( - uint8_t rx_id, - const uint8_t *rx_bus_id, + const PJON_Packet_Info &info, const void *payload, - uint16_t length, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST + uint16_t length ) { - return dispatch( - rx_id, rx_bus_id, payload, length, 0, header, packet_id, rx_port - ); + return dispatch(info, payload, length); }; - /* Schedule a packet sending configuring its sender info: */ + /* Forward a packet: */ - uint16_t send_from_id( - uint8_t tx_id, - const uint8_t *tx_bus_id, - uint8_t rx_id, - const uint8_t *rx_bus_id, + uint16_t forward( + PJON_Packet_Info info, const void *payload, - uint16_t length, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST + uint16_t length ) { - uint8_t original_device_id = _device_id; - uint8_t original_bus_id[4]; - PJONTools::copy_bus_id(original_bus_id, bus_id); - set_id(tx_id); - PJONTools::copy_bus_id(bus_id, tx_bus_id); - uint16_t result = PJON_FAIL; - #if(PJON_MAX_PACKETS > 0) - result = dispatch( - rx_id, rx_bus_id, payload, length, 0, header, packet_id, rx_port - ); + PJON_Endpoint original_end_point = tx; + tx = info.tx; + #ifndef PJON_LOCAL + if(++info.hops > PJON_MAX_HOPS) return PJON_FAIL; #endif - if(result == PJON_FAIL) - result = send_packet_blocking( - rx_id, rx_bus_id, payload, length, header, packet_id, rx_port - ); - PJONTools::copy_bus_id(bus_id, original_bus_id); - set_id(original_device_id); + uint16_t result = dispatch(info, payload, length); + tx = original_end_point; + return result; + }; + + /* Forward a packet: */ + + uint16_t forward_blocking( + PJON_Packet_Info info, + const void *payload, + uint16_t length + ) { + PJON_Endpoint original_end_point = tx; + tx = info.tx; + #ifndef PJON_LOCAL + if(++info.hops > PJON_MAX_HOPS) return PJON_FAIL; + #endif + uint16_t result = send_packet_blocking(info, payload, length); + tx = original_end_point; return result; }; @@ -574,27 +539,17 @@ class PJON { uint16_t packet_id = 0, uint16_t rx_port = PJON_BROADCAST ) { - return dispatch( - rx_id, bus_id, payload, length, timing, header, packet_id, rx_port - ); + PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port); + return dispatch(info, payload, length, timing); }; - /* IMPORTANT: send_repeatedly timing maximum - is 4293014170 microseconds or 71.55 minutes */ - uint16_t send_repeatedly( - uint8_t rx_id, - const uint8_t *rx_bus_id, + const PJON_Packet_Info &info, const void *payload, uint16_t length, - uint32_t timing, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST + uint32_t timing ) { - return dispatch( - rx_id, rx_bus_id, payload, length, timing, header, packet_id, rx_port - ); + return dispatch(info, payload, length, timing); }; /* Transmit an already composed packet: */ @@ -608,12 +563,7 @@ class PJON { !(payload[1] & PJON_ACK_REQ_BIT) || _mode == PJON_SIMPLEX ) return PJON_ACK; - uint16_t response = strategy.receive_response(); - if( - response == PJON_ACK || - response == PJON_FAIL - ) return response; - else return PJON_BUSY; + return (strategy.receive_response() == PJON_ACK) ? PJON_ACK : PJON_FAIL; }; /* Compose and transmit a packet passing its info as parameters: */ @@ -626,24 +576,19 @@ class PJON { uint16_t packet_id = 0, uint16_t rx_port = PJON_BROADCAST ) { - if(!(length = compose_packet( - rx_id, bus_id, data, payload, length, header, packet_id, rx_port - ))) return PJON_FAIL; + PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port); + if(!(length = compose_packet(info, data, payload, length))) + return PJON_FAIL; return send_packet(data, length); }; uint16_t send_packet( - uint8_t rx_id, - const uint8_t *rx_bus_id, + const PJON_Packet_Info &info, const void *payload, - uint16_t length, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST + uint16_t length ) { - if(!(length = compose_packet( - rx_id, rx_bus_id, data, payload, length, header, packet_id, rx_port - ))) return PJON_FAIL; + if(!(length = compose_packet(info, data, payload, length))) + return PJON_FAIL; return send_packet(data, length); }; @@ -652,13 +597,9 @@ class PJON { delivered, or timing limit is reached. */ uint16_t send_packet_blocking( - uint8_t rx_id, - const uint8_t *rx_bus_id, + const PJON_Packet_Info &packet_info, const void *payload, uint16_t length, - uint8_t header = PJON_NO_HEADER, - uint16_t packet_id = 0, - uint16_t rx_port = PJON_BROADCAST, uint32_t timeout = 3500000 ) { uint16_t state = PJON_FAIL; @@ -671,16 +612,7 @@ class PJON { (state != PJON_ACK) && (attempts <= strategy.get_max_attempts()) && (uint32_t)(PJON_MICROS() - start) <= timeout ) { - if(!(length = compose_packet( - rx_id, - rx_bus_id, - data, - payload, - old_length, - header, - packet_id, - rx_port - ))) { + if(!(length = compose_packet(packet_info, data, payload, old_length))) { _recursion--; return PJON_FAIL; } @@ -708,17 +640,16 @@ class PJON { uint8_t header = PJON_NO_HEADER, uint16_t packet_id = 0, uint16_t rx_port = PJON_BROADCAST, - uint32_t timeout = 3000000 + uint32_t timeout = 3500000 ) { - return send_packet_blocking( - rx_id, bus_id, payload, length, header, packet_id, rx_port, timeout - ); + PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port); + return send_packet_blocking(info, payload, length, timeout); }; /* In router mode, the receiver function can acknowledge for selected receiver device ids for which the route is known */ - void send_synchronous_acknowledge() { + void send_acknowledge() { strategy.send_response(PJON_ACK); }; @@ -729,44 +660,30 @@ class PJON { else config &= ~bit; }; - /* Configure synchronous acknowledge presence: - TRUE: Send 1 byte synchronous acknowledge when a packet is received - FALSE: Avoid acknowledge transmission */ + /* Configure acknowledge: + state = true -> Request acknowledgement + state = false -> Do not request acknowledgement */ - void set_synchronous_acknowledge(bool state) { + void set_acknowledge(bool state) { set_config_bit(state, PJON_ACK_REQ_BIT); }; - /* Configure asynchronous acknowledge presence: - TRUE: Send back asynchronous acknowledge packet - FALSE: Avoid acknowledge packet transmission */ - - void set_asynchronous_acknowledge(bool state) { - set_config_bit(state, PJON_ACK_MODE_BIT); - }; - /* Configure CRC selected for packet checking: - TRUE: CRC32, FALSE: CRC8 */ + state = true -> Use CRC32 + state = false -> Use CRC8 */ void set_crc_32(bool state) { set_config_bit(state, PJON_CRC_BIT); }; /* Set communication mode: - Passing PJON_SIMPLEX communication is mono-directional - Padding PJON_HALF_DUPLEX communication is bi-directional */ + mode = 0 or PJON_SIMPLEX -> Communication is mono-directional + mode = 1 or PJON_HALF_DUPLEX -> Communication is bi-directional */ - void set_communication_mode(uint8_t mode) { + void set_communication_mode(bool mode) { _mode = mode; }; - /* Configure packet id presence: - TRUE: include packet id, FALSE: Avoid packet id inclusion */ - - void set_packet_id(bool state) { - set_config_bit(state, PJON_PACKET_ID_BIT); - }; - /* Set a custom receiver callback pointer: (Generally needed to call a custom member function) */ @@ -778,15 +695,8 @@ class PJON { void set_default() { _mode = PJON_HALF_DUPLEX; - if(!PJONTools::bus_id_equality(bus_id, PJONTools::localhost())) - set_shared_network(true); set_error(PJON_dummy_error_handler); set_receiver(PJON_dummy_receiver_handler); - for(uint16_t i = 0; i < PJON_MAX_PACKETS; i++) { - packets[i].state = 0; - packets[i].timing = 0; - packets[i].attempts = 0; - } }; /* Pass as a parameter a function you previously defined in the code. @@ -807,19 +717,19 @@ class PJON { /* Set the device id passing a single byte (watch out to id collision): */ void set_id(uint8_t id) { - _device_id = id; + tx.id = id; }; - /* Include the port passing a boolean state and an unsigned integer: */ + /* Setting bus id */ - void include_port(bool state, uint16_t p = PJON_BROADCAST) { - set_config_bit(state, PJON_PORT_BIT); - port = p; + void set_bus_id(const uint8_t *b_id) { + PJONTools::copy_id(tx.bus_id, b_id, 4); }; /* Configure sender's information inclusion in the packet. - TRUE: +1 byte (device id) local, +5 bytes (bus id + device id) shared - FALSE: No inclusion -1 byte overhead in local, -5 in shared + state = true -> +8 bits (device id) in local mode + +40 bits (bus id + device id) in shared mode + state = false -> No overhead added If you don't need the sender info disable the inclusion to reduce overhead and higher communication speed. */ @@ -828,17 +738,42 @@ class PJON { set_config_bit(state, PJON_TX_INFO_BIT); }; + /* Configure network interface identification inclusion in the packet. + state = true -> +96 bits (sender's and recipient's MAC address) + state = false -> No overhead added */ + + void include_mac(bool state) { + set_config_bit(state, PJON_MAC_BIT); + }; + + #if(PJON_INCLUDE_MAC) + + /* Returns a pointer to the mac address used by the instance: */ + + const uint8_t *get_mac() const { + return tx.mac; + }; + + /* Set the mac address used by the instance: + It receives a pointer to the mac address */ + + void set_mac(const uint8_t *mac) { + PJONTools::copy_id(tx.mac, mac, 6); + }; + + #endif + /* Configure the bus network behaviour. - TRUE: Include 4 bytes bus id or group identification. - FALSE: Use only 1 byte local device identification. */ + state = true -> Include 32 bits bus id or group identification. + state = false -> Use only a 8 bits local device identification. */ void set_shared_network(bool state) { set_config_bit(state, PJON_MODE_BIT); }; - /* Set if delivered or undeliverable packets are auto deleted: - TRUE: Automatic deletion - FALSE: No packet deleted from buffer, (deletion from buffer by user) */ + /* Set if packets are automatically deleted in case of success or failure: + state = true -> Packets are deleted automatically + state = false -> Packets are not deleted */ void set_packet_auto_deletion(bool state) { _auto_delete = state; @@ -847,7 +782,7 @@ class PJON { /* Set the analog pin used as a seed for random generation: */ void set_random_seed(uint8_t seed) { - random_seed = seed; + _random_seed = seed; }; /* Pass as a parameter a receiver function you previously defined in your @@ -859,15 +794,15 @@ class PJON { }; /* Configure if device acts as a router: - TRUE: device receives messages only for its bus and device id - FALSE: receiver function is always called if data is received */ + state = true -> All packets are received (acknowledgement not sent) + state = false -> Normal operation */ void set_router(bool state) { _router = state; }; /* Update the state of the send list: - Check if there are packets to be sent or to be erased if correctly + Checks if there are packets to be sent or to be erased if correctly delivered. Returns the actual number of packets to be sent. */ uint16_t update() { @@ -875,9 +810,6 @@ class PJON { for(uint16_t i = 0; i < PJON_MAX_PACKETS; i++) { if(packets[i].state == 0) continue; packets_count++; - bool async_ack = (packets[i].content[1] & PJON_ACK_MODE_BIT) && - (packets[i].content[1] & PJON_TX_INFO_BIT); - bool sync_ack = (packets[i].content[1] & PJON_ACK_REQ_BIT); if( (uint32_t)(PJON_MICROS() - packets[i].registration) > @@ -886,34 +818,16 @@ class PJON { strategy.back_off(packets[i].attempts) ) ) { - if(!(sync_ack && async_ack && packets[i].state == PJON_ACK)) - packets[i].state = // Avoid resending sync-acked async ack packets + if(packets[i].state != PJON_ACK) + packets[i].state = send_packet(packets[i].content, packets[i].length); } else continue; packets[i].attempts++; if(packets[i].state == PJON_ACK) { - if(!packets[i].timing) { - if( - _auto_delete && ( - ( - packets[i].length == packet_overhead(packets[i].content[1]) - && async_ack - ) || !(packets[i].content[1] & PJON_ACK_MODE_BIT) - ) - ) { - remove(i); - packets_count--; - } - } else { - if(!async_ack) { - packets[i].attempts = 0; - packets[i].registration = PJON_MICROS(); - packets[i].state = PJON_TO_BE_SENT; - } - } - if(!async_ack) continue; + packets_count -= reset_packet(i); + continue; } if(packets[i].state != PJON_FAIL && packets[i].state != PJON_ACK) @@ -921,36 +835,29 @@ class PJON { if(packets[i].attempts > strategy.get_max_attempts()) { _error(PJON_CONNECTION_LOST, i, _custom_pointer); - if(!packets[i].timing) { - if(_auto_delete) { - remove(i); - packets_count--; - } - } else { - packets[i].attempts = 0; - packets[i].registration = PJON_MICROS(); - packets[i].state = PJON_TO_BE_SENT; - } + packets_count -= reset_packet(i); } } return packets_count; }; - /* Check if the packet id and its transmitter info are already present in - buffer of recently received packets, if not add it to the buffer. */ + #if(PJON_INCLUDE_PACKET_ID) - bool known_packet_id(PJON_Packet_Info info) { - #if(PJON_INCLUDE_ASYNC_ACK || PJON_INCLUDE_PACKET_ID) + /* Checks if the packet id and its transmitter info are already present + in the known packets buffer, if not add it to the buffer */ + + bool known_packet_id(const PJON_Packet_Info &info) { for(uint8_t i = 0; i < PJON_MAX_RECENT_PACKET_IDS; i++) if( info.id == recent_packet_ids[i].id && - info.sender_id == recent_packet_ids[i].sender_id && ( + info.tx.id == recent_packet_ids[i].sender_id && ( ( (info.header & PJON_MODE_BIT) && (recent_packet_ids[i].header & PJON_MODE_BIT) && - PJONTools::bus_id_equality( - (uint8_t *)info.sender_bus_id, - (uint8_t *)recent_packet_ids[i].sender_bus_id + PJONTools::id_equality( + (uint8_t *)info.tx.bus_id, + (uint8_t *)recent_packet_ids[i].sender_bus_id, + 4 ) ) || ( !(info.header & PJON_MODE_BIT) && @@ -959,35 +866,55 @@ class PJON { ) ) return true; save_packet_id(info); - #endif - return false; - }; + return false; + }; - /* Save packet id in the buffer: */ + /* Save packet id in the buffer: */ - void save_packet_id(PJON_Packet_Info info) { - #if(PJON_INCLUDE_ASYNC_ACK || PJON_INCLUDE_PACKET_ID) + void save_packet_id(const PJON_Packet_Info &info) { for(uint8_t i = PJON_MAX_RECENT_PACKET_IDS - 1; i > 0; i--) recent_packet_ids[i] = recent_packet_ids[i - 1]; recent_packet_ids[0].id = info.id; recent_packet_ids[0].header = info.header; - recent_packet_ids[0].sender_id = info.sender_id; - PJONTools::copy_bus_id( + recent_packet_ids[0].sender_id = info.tx.id; + PJONTools::copy_id( recent_packet_ids[0].sender_bus_id, - info.sender_bus_id + info.tx.bus_id, + 4 ); - #endif - }; + }; + + /* Configure packet id presence: + state = true -> Include 16 bits packet id + state = false -> Avoid packet id inclusion */ + + void set_packet_id(bool state) { + set_config_bit(state, PJON_PACKET_ID_BIT); + }; + + #endif + + #if(PJON_INCLUDE_PORT) + + /* Include the port: + p = 1-65535 -> Include 16 bits port id + p = 0 -> Avoid port id inclusion */ + + void include_port(uint16_t p) { + set_config_bit((p != 0) ? 1 : 0, PJON_PORT_BIT); + port = p; + }; + + #endif private: bool _auto_delete = true; void *_custom_pointer; PJON_Error _error; - uint8_t _mode; + bool _mode; uint16_t _packet_id_seed = 0; + uint8_t _random_seed = A0; PJON_Receiver _receiver; uint8_t _recursion = 0; bool _router = false; - protected: - uint8_t _device_id; }; diff --git a/src/PJONAnalogSampling.h b/src/PJONAnalogSampling.h new file mode 100644 index 0000000000..15353a73ba --- /dev/null +++ b/src/PJONAnalogSampling.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/AnalogSampling/AnalogSampling.h" + +#define PJONAnalogSampling PJON diff --git a/src/PJONAny.h b/src/PJONAny.h new file mode 100644 index 0000000000..53715f3dcf --- /dev/null +++ b/src/PJONAny.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/Any/Any.h" + +#define PJONAny PJON diff --git a/src/PJONDefines.h b/src/PJONDefines.h index a0efeb6f5a..d393a25e3d 100644 --- a/src/PJONDefines.h +++ b/src/PJONDefines.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -20,7 +20,7 @@ contributors, the protocol's documentation, specification and implementation have been strongly tested, enhanced and verified: Fred Larsen, Zbigniew Zasieczny, Matheus Garbelini, sticilface, - Felix Barbalet, Oleh Halitskiy, fabpolli, Adrian Sławiński, + Felix Barbalet, Oleh Halitskiy, fotosettore, fabpolli, Adrian Sławiński, Osman Selçuk Aktepe, Jorgen-VikingGod, drtrigon, Endre Karlson, Wilfried Klaas, budaics, ibantxo, gonnavis, maxidroms83, Evgeny Dontsov, zcattacz, Valerii Koval, Ivan Kravets, Esben Soeltoft, Alex Grishin, @@ -28,8 +28,8 @@ have been strongly tested, enhanced and verified: pacproduct, elusive-code, Emanuele Iannone, Christian Pointner, Fabian Gärtner, Mauro Mombelli, Remo Kallio, hyndruide, sigmaeo, filogranaf, Maximiliano Duarte, Viktor Szépe, Shachar Limor, Andrei Volkau, maniekq, - DetAtHome, Michael Branson, chestwood96, Mattze96, Steven Bense - and Jack Anderson. + DetAtHome, Michael Branson, chestwood96, Mattze96, Steven Bense, + Jack Anderson, callalilychen and Julio Aguirre. Compatible tools: @@ -43,7 +43,7 @@ Compatible tools: This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -76,13 +76,18 @@ limitations under the License. */ #define PJON_NOT_ASSIGNED 255 #endif +/* Device id used by master */ +#ifndef PJON_MASTER_ID + #define PJON_MASTER_ID 254 +#endif + /* Internal constants: */ #define PJON_FAIL 65535 #define PJON_TO_BE_SENT 74 /* Communication modes: */ -#define PJON_SIMPLEX 150 -#define PJON_HALF_DUPLEX 151 +#define PJON_SIMPLEX false +#define PJON_HALF_DUPLEX true /* Header bits definition: */ @@ -92,26 +97,26 @@ limitations under the License. */ 1 - Shared network */ #define PJON_MODE_BIT 0B00000001 /* 0 - No info inclusion - 1 - Local: Sender device id included - Shared: Sender device id + Sender bus id */ + 1 - Local: Sender device id included (+8 bits) + Shared: Sender device id + bus id (+40 bits) */ #define PJON_TX_INFO_BIT 0B00000010 /* 0 - Synchronous acknowledgement disabled 1 - Synchronous acknowledgement enabled */ #define PJON_ACK_REQ_BIT 0B00000100 -/* 0 - Asynchronous acknowledgement disabled - 1 - Asynchronous acknowledgement enabled */ -#define PJON_ACK_MODE_BIT 0B00001000 -/* 0 - No port id contained - 1 - Port id contained (2 bytes integer) */ +/* 0 - MAC address inclusion disabled + 1 - MAC address inclusion enabled (+96 bits) */ +#define PJON_MAC_BIT 0B00001000 +/* 0 - Port id not included + 1 - Port id included (+16 bits) */ #define PJON_PORT_BIT 0B00010000 -/* 0 - CRC8 (1 byte) included at the end of the packet - 1 - CRC32 (4 bytes) included at the end of the packet */ +/* 0 - CRC8 (8 bits) included + 1 - CRC32 (32 bits) included */ #define PJON_CRC_BIT 0B00100000 -/* 0 - 1 byte long (max 255 bytes) - 1 - 2 bytes long (max 65535 bytes) */ +/* 0 - 8 bits length (max packet length 255 bytes) + 1 - 16 bits length (max packet length 65535 bytes) */ #define PJON_EXT_LEN_BIT 0B01000000 -/* 0 - Packet id not present - 1 - Packet id present */ +/* 0 - Packet id not included + 1 - Packet id included (+16 bits) */ #define PJON_PACKET_ID_BIT 0B10000000 /* Errors: */ @@ -122,6 +127,11 @@ limitations under the License. */ /* Constraints: */ +/* Maximum amount of routers a packet can pass before being discarded: */ +#ifndef PJON_MAX_HOPS + #define PJON_MAX_HOPS 15 +#endif + /* Packet buffer length, if full PJON_PACKETS_BUFFER_FULL error is thrown. The packet buffer is preallocated, so its length strongly affects memory consumption */ @@ -136,53 +146,82 @@ limitations under the License. */ #define PJON_PACKET_MAX_LENGTH 50 #endif -/* If set to false async ack feature is not included saving memory - (it saves around 1kB of memory) */ -#ifndef PJON_INCLUDE_ASYNC_ACK - #define PJON_INCLUDE_ASYNC_ACK false +/* Maximum packet ids record kept in memory (to avoid duplicated exchanges) */ +#ifndef PJON_MAX_RECENT_PACKET_IDS + #define PJON_MAX_RECENT_PACKET_IDS 10 #endif -/* If set to false packet id feature is not included saving memory - (it saves around 1kB of memory) */ -#ifndef PJON_INCLUDE_PACKET_ID +/* Optional features: */ + +/* If defined includes the packet id feature */ +#ifdef PJON_INCLUDE_PACKET_ID + #undef PJON_INCLUDE_PACKET_ID + #define PJON_INCLUDE_PACKET_ID true +#else #define PJON_INCLUDE_PACKET_ID false #endif -/* Maximum packet ids record kept in memory (to avoid duplicated exchanges) */ -#ifndef PJON_MAX_RECENT_PACKET_IDS - #define PJON_MAX_RECENT_PACKET_IDS 10 +/* If defined includes the port id feature */ +#ifdef PJON_INCLUDE_PORT + #undef PJON_INCLUDE_PORT + #define PJON_INCLUDE_PORT true +#else + #define PJON_INCLUDE_PORT false +#endif + +/* If defined includes the mac address feature */ +#ifdef PJON_INCLUDE_MAC + #undef PJON_INCLUDE_MAC + #define PJON_INCLUDE_MAC true +#else + #define PJON_INCLUDE_MAC false #endif /* Data structures: */ struct PJON_Packet { - uint8_t attempts; + uint8_t attempts = 0; uint8_t content[PJON_PACKET_MAX_LENGTH]; uint16_t length; uint32_t registration; - uint16_t state; - uint32_t timing; + uint16_t state = 0; + uint32_t timing = 0; }; struct PJON_Packet_Record { - uint16_t id; uint8_t header; uint8_t sender_id; #ifndef PJON_LOCAL uint8_t sender_bus_id[4]; #endif + #if(PJON_INCLUDE_PACKET_ID) + uint16_t id; + #endif +}; + +struct PJON_Endpoint { + uint8_t id = PJON_NOT_ASSIGNED; + #ifndef PJON_LOCAL + uint8_t bus_id[4] = {0, 0, 0, 0}; + #endif + #if(PJON_INCLUDE_MAC) + uint8_t mac[6] = {0, 0, 0, 0, 0, 0}; + #endif }; struct PJON_Packet_Info { - uint8_t header; - uint16_t id; - uint8_t receiver_id; - uint8_t sender_id; - uint16_t port; + PJON_Endpoint tx; + PJON_Endpoint rx; + uint8_t header = PJON_NO_HEADER; #ifndef PJON_LOCAL - uint8_t receiver_bus_id[4]; - uint8_t sender_bus_id[4]; void *custom_pointer; + uint8_t hops = 0; + #endif + #if(PJON_INCLUDE_PACKET_ID) + uint16_t id = 0; + #endif + #if(PJON_INCLUDE_PORT) + uint16_t port = PJON_BROADCAST; #endif }; @@ -208,25 +247,26 @@ struct PJONTools { return lh; }; + /* Unused MAC address value */ + + static const uint8_t* no_mac() { + static const uint8_t lh[6] = {0, 0, 0, 0, 0, 0}; + return lh; + }; + /* Calculates the packet's overhead using the header: */ static uint8_t packet_overhead(uint8_t header) { return ( ( (header & PJON_MODE_BIT) ? - (header & PJON_TX_INFO_BIT ? 10 : 5) : + (header & PJON_TX_INFO_BIT ? 11 : 6) : (header & PJON_TX_INFO_BIT ? 2 : 1) ) + (header & PJON_EXT_LEN_BIT ? 2 : 1) + (header & PJON_CRC_BIT ? 4 : 1) + (header & PJON_PORT_BIT ? 2 : 0) - + ( - ( - ( - (header & PJON_ACK_MODE_BIT) && - (header & PJON_TX_INFO_BIT) - ) || (header & PJON_PACKET_ID_BIT) - ) ? 2 : 0 - ) + + (header & PJON_PACKET_ID_BIT ? 2 : 0) + + (header & PJON_MAC_BIT ? 12 : 0) + 2 // header + header's CRC ); }; @@ -244,16 +284,20 @@ struct PJONTools { return seed; }; - /* Copy a bus id: */ + /* Copy an id: */ - static void copy_bus_id(uint8_t dest[], const uint8_t src[]) { - memcpy(dest, src, 4); + static void copy_id(uint8_t dest[], const uint8_t src[], uint8_t length) { + memcpy(dest, src, length); }; - /* Check equality between two bus ids */ + /* Check equality between two ids: */ - static bool bus_id_equality(const uint8_t *n_one, const uint8_t *n_two) { - for(uint8_t i = 0; i < 4; i++) + static bool id_equality( + const uint8_t *n_one, + const uint8_t *n_two, + uint8_t length + ) { + for(uint8_t i = 0; i < length; i++) if(n_one[i] != n_two[i]) return false; return true; @@ -262,41 +306,32 @@ struct PJONTools { /* Composes a packet in PJON format: */ static uint16_t compose_packet( - const uint8_t sender_id, - const uint8_t *sender_bus_id, - const uint8_t receiver_id, - const uint8_t *receiver_bus_id, + PJON_Packet_Info info, uint8_t *destination, const void *source, - uint16_t length, - uint8_t header = 0, - uint16_t packet_id = 0, - uint16_t destination_port = PJON_BROADCAST, - uint16_t source_port = PJON_BROADCAST + uint16_t length ) { uint8_t index = 0; - if(length > 255) header |= PJON_EXT_LEN_BIT; - if(destination_port != PJON_BROADCAST) header |= PJON_PORT_BIT; - if( - (header & PJON_PORT_BIT) && - (destination_port == PJON_BROADCAST) && - (source_port == PJON_BROADCAST) - ) header &= ~PJON_PORT_BIT; - if(receiver_id == PJON_BROADCAST) - header &= ~(PJON_ACK_REQ_BIT | PJON_ACK_MODE_BIT); - uint16_t new_length = length + packet_overhead(header); - bool extended_length = header & PJON_EXT_LEN_BIT; - if(new_length > 15 && !(header & PJON_CRC_BIT)) { - header |= PJON_CRC_BIT; - new_length = (uint16_t)(length + packet_overhead(header)); + if(length > 255) info.header |= PJON_EXT_LEN_BIT; + #if(PJON_INCLUDE_PORT) + if(info.port != PJON_BROADCAST) info.header |= PJON_PORT_BIT; + if((info.header & PJON_PORT_BIT) && (info.port == PJON_BROADCAST)) + info.header &= ~PJON_PORT_BIT; + #endif + if(info.rx.id == PJON_BROADCAST) info.header &= ~(PJON_ACK_REQ_BIT); + uint16_t new_length = length + packet_overhead(info.header); + bool extended_length = info.header & PJON_EXT_LEN_BIT; + if(new_length > 15 && !(info.header & PJON_CRC_BIT)) { + info.header |= PJON_CRC_BIT; + new_length = (uint16_t)(length + packet_overhead(info.header)); } if(new_length > 255 && !extended_length) { - header |= PJON_EXT_LEN_BIT; - new_length = (uint16_t)(length + packet_overhead(header)); + info.header |= PJON_EXT_LEN_BIT; + new_length = (uint16_t)(length + packet_overhead(info.header)); } if(new_length >= PJON_PACKET_MAX_LENGTH) return new_length; - destination[index++] = receiver_id; - destination[index++] = (uint8_t)header; + destination[index++] = info.rx.id; + destination[index++] = (uint8_t)info.header; if(extended_length) { destination[index++] = (uint8_t)(new_length >> 8); destination[index++] = (uint8_t)new_length; @@ -306,42 +341,41 @@ struct PJONTools { destination[index++] = PJON_crc8::compute((uint8_t *)destination, 3); } #ifndef PJON_LOCAL - if(header & PJON_MODE_BIT) { - PJONTools::copy_bus_id((uint8_t*) &destination[index], receiver_bus_id); + if(info.header & PJON_MODE_BIT) { + copy_id((uint8_t*) &destination[index], info.rx.bus_id, 4); index += 4; - if(header & PJON_TX_INFO_BIT) { - PJONTools::copy_bus_id((uint8_t*) &destination[index], sender_bus_id); + if(info.header & PJON_TX_INFO_BIT) { + copy_id((uint8_t*) &destination[index], info.tx.bus_id, 4); index += 4; } + destination[index++] = info.hops; } - #else - (void)sender_bus_id; - (void)receiver_bus_id; #endif - if(header & PJON_TX_INFO_BIT) destination[index++] = sender_id; - #if(PJON_INCLUDE_ASYNC_ACK || PJON_INCLUDE_PACKET_ID) - if( - (header & PJON_PACKET_ID_BIT) || ( - (header & PJON_ACK_MODE_BIT) && (header & PJON_TX_INFO_BIT) - ) - ) { - destination[index++] = (uint8_t)(packet_id >> 8); - destination[index++] = (uint8_t)packet_id; + if(info.header & PJON_TX_INFO_BIT) destination[index++] = info.tx.id; + #if(PJON_INCLUDE_PACKET_ID) + if(info.header & PJON_PACKET_ID_BIT) { + destination[index++] = (uint8_t)(info.id >> 8); + destination[index++] = (uint8_t)info.id; } - #else - (void)packet_id; // Avoid unused variable compiler warning #endif - if(header & PJON_PORT_BIT) { - if(destination_port != PJON_BROADCAST) { - destination[index++] = (uint8_t)(destination_port >> 8); - destination[index++] = (uint8_t)destination_port; - } else if(source_port != PJON_BROADCAST) { - destination[index++] = (uint8_t)(source_port >> 8); - destination[index++] = (uint8_t)source_port; + #if(PJON_INCLUDE_PORT) + if(info.header & PJON_PORT_BIT) { + if(info.port != PJON_BROADCAST) { + destination[index++] = (uint8_t)(info.port >> 8); + destination[index++] = (uint8_t)info.port; + } } - } + #endif + #if(PJON_INCLUDE_MAC) + if(info.header & PJON_MAC_BIT) { + copy_id(&destination[index], info.rx.mac, 6); + index += 6; + copy_id(&destination[index], info.tx.mac, 6); + index += 6; + } + #endif memcpy(destination + index, source, length); - if(header & PJON_CRC_BIT) { + if(info.header & PJON_CRC_BIT) { uint32_t computed_crc = PJON_crc32::compute((uint8_t *)destination, new_length - 4); destination[new_length - 4] = @@ -360,39 +394,42 @@ struct PJONTools { /* Fills a PJON_Packet_Info struct with data parsing a packet: */ static void parse_header(const uint8_t *packet, PJON_Packet_Info &info) { - memset(&info, 0, sizeof info); uint8_t index = 0; - info.receiver_id = packet[index++]; + info = PJON_Packet_Info{}; + + info.rx.id = packet[index++]; bool extended_length = packet[index] & PJON_EXT_LEN_BIT; info.header = packet[index++]; index += extended_length + 2; // + LENGTH + HEADER CRC #ifndef PJON_LOCAL if(info.header & PJON_MODE_BIT) { - copy_bus_id(info.receiver_bus_id, packet + index); + copy_id(info.rx.bus_id, packet + index, 4); index += 4; if(info.header & PJON_TX_INFO_BIT) { - copy_bus_id(info.sender_bus_id, packet + index); + copy_id(info.tx.bus_id, packet + index, 4); index += 4; - } else copy_bus_id(info.sender_bus_id, localhost()); - } else copy_bus_id(info.receiver_bus_id, localhost()); + } + info.hops = packet[index++]; + } #endif if(info.header & PJON_TX_INFO_BIT) - info.sender_id = packet[index++]; - else info.sender_id = 0; - #if(PJON_INCLUDE_ASYNC_ACK || PJON_INCLUDE_PACKET_ID) - if( - (info.header & PJON_PACKET_ID_BIT) || ( - (info.header & PJON_ACK_MODE_BIT) && (info.header & PJON_TX_INFO_BIT) - ) - ) { + info.tx.id = packet[index++]; + #if(PJON_INCLUDE_PACKET_ID) + if(info.header & PJON_PACKET_ID_BIT) { info.id = (packet[index] << 8) | (packet[index + 1] & 0xFF); index += 2; } - #else - info.id = 0; #endif - if(info.header & PJON_PORT_BIT) - info.port = (packet[index] << 8) | (packet[index + 1] & 0xFF); - else info.port = PJON_BROADCAST; + #if(PJON_INCLUDE_PORT) + if(info.header & PJON_PORT_BIT) { + info.port = (packet[index] << 8) | (packet[index + 1] & 0xFF); + index += 2; + } + #endif + #if(PJON_INCLUDE_MAC) + copy_id(info.rx.mac, packet + index, 6); + index += 6; + copy_id(info.tx.mac, packet + index, 6); + #endif }; }; diff --git a/src/PJONDualUDP.h b/src/PJONDualUDP.h new file mode 100644 index 0000000000..0477c2b692 --- /dev/null +++ b/src/PJONDualUDP.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/DualUDP/DualUDP.h" + +#define PJONDualUDP PJON diff --git a/src/PJONDynamicRouter.h b/src/PJONDynamicRouter.h index 99d0e7c8d2..c2b89ef14d 100644 --- a/src/PJONDynamicRouter.h +++ b/src/PJONDynamicRouter.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -22,7 +22,7 @@ dynamically based on observed packets from remote buses. This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -53,13 +53,13 @@ class PJONDynamicRouter : public PJONRouter { ) { uint8_t start_search = 0; uint8_t found_bus = find_bus_with_id( - packet_info.sender_bus_id, - packet_info.sender_id, + packet_info.tx.bus_id, + packet_info.tx.id, start_search ); // Not found among attached buses or in routing table. Add to table. if(found_bus == PJON_NOT_ASSIGNED) - add(packet_info.sender_bus_id, sender_bus); + add(packet_info.tx.bus_id, sender_bus); }; virtual void dynamic_receiver_function( @@ -77,8 +77,50 @@ class PJONDynamicRouter : public PJONRouter { PJONDynamicRouter( uint8_t bus_count, - PJONAny *buses[], + PJONAny * const buses[], uint8_t default_gateway = PJON_NOT_ASSIGNED ) : PJONRouter(bus_count, buses, default_gateway) { }; +}; + +// Specialized class to simplify declaration when using 2 buses +template +class PJONDynamicRouter2 : public PJONDynamicRouter { + StrategyLink linkA; + StrategyLink linkB; + PJONAny busA, busB; +public: + PJONDynamicRouter2(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON* buses[2] = { &busA, &busB }; + PJONSimpleSwitch::connect_buses(2, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : busB; } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } +}; + +// Specialized class to simplify declaration when using 3 buses +template +class PJONDynamicRouter3 : public PJONDynamicRouter { + StrategyLink linkA; + StrategyLink linkB; + StrategyLink linkC; + PJONAny busA, busB, busC; +public: + PJONDynamicRouter3(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON *buses[3] = { &busA, &busB, &busC }; + PJONSimpleSwitch::connect_buses(3, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + busC.set_link(&linkC); + }; + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : (ix == 1 ? busB : busC); } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } + C &get_strategy_2() { return linkC.strategy; } }; diff --git a/src/PJONESPNOW.h b/src/PJONESPNOW.h new file mode 100644 index 0000000000..44ac766b26 --- /dev/null +++ b/src/PJONESPNOW.h @@ -0,0 +1,15 @@ + +#pragma once + +/* ESPNOW strategy actively uses the PJON's MAC address feature for this reason + it must be included. */ + +#ifndef PJON_INCLUDE_MAC + #define PJON_INCLUDE_MAC +#endif + +#include "PJON.h" + +#include "strategies/ESPNOW/ESPNOW.h" + +#define PJONESPNOW PJON diff --git a/src/PJONEthernetTCP.h b/src/PJONEthernetTCP.h new file mode 100644 index 0000000000..18ebf62b0c --- /dev/null +++ b/src/PJONEthernetTCP.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/EthernetTCP/EthernetTCP.h" + +#define PJONEthernetTCP PJON diff --git a/src/PJONGlobalUDP.h b/src/PJONGlobalUDP.h new file mode 100644 index 0000000000..832eb1b2fa --- /dev/null +++ b/src/PJONGlobalUDP.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/GlobalUDP/GlobalUDP.h" + +#define PJONGlobalUDP PJON diff --git a/src/PJONInteractiveRouter.h b/src/PJONInteractiveRouter.h index fcbbed1b00..5bec67129a 100644 --- a/src/PJONInteractiveRouter.h +++ b/src/PJONInteractiveRouter.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -32,7 +32,7 @@ receiver callback should be really fast. This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -50,7 +50,7 @@ limitations under the License. */ #include #include -typedef void (* PJON_SendNotification)( +typedef void (* PJON_Send_Notification)( const uint8_t * const payload, const uint16_t length, const uint8_t receiver_bus, @@ -58,13 +58,13 @@ typedef void (* PJON_SendNotification)( const PJON_Packet_Info &packet_info ); -template +template class PJONInteractiveRouter : public RouterClass { protected: void *custom_pointer = NULL; PJON_Receiver receiver = NULL; PJON_Error error = NULL; - PJON_SendNotification sendnotification = NULL; + PJON_Send_Notification send_notification = NULL; bool router = false; virtual void dynamic_receiver_function(uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info) { @@ -72,16 +72,16 @@ class PJONInteractiveRouter : public RouterClass { // (If this device has a device id on the source bus, and it is equal to // the packets receiver_id, the packet is for this device.) bool packet_is_for_me = ( - RouterClass::buses[RouterClass::current_bus]->device_id() != PJON_NOT_ASSIGNED && - memcmp(RouterClass::buses[RouterClass::current_bus]->bus_id, packet_info.receiver_bus_id, 4) == 0 && - RouterClass::buses[RouterClass::current_bus]->device_id() == packet_info.receiver_id + RouterClass::buses[RouterClass::current_bus]->tx.id != PJON_NOT_ASSIGNED && + memcmp(RouterClass::buses[RouterClass::current_bus]->tx.bus_id, packet_info.rx.bus_id, 4) == 0 && + RouterClass::buses[RouterClass::current_bus]->tx.id == packet_info.rx.id ); // Take care of other's packets if(!packet_is_for_me) RouterClass::dynamic_receiver_function(payload, length, packet_info); else if(packet_info.header & PJON_ACK_REQ_BIT) - RouterClass::buses[RouterClass::current_bus]->send_synchronous_acknowledge(); + RouterClass::buses[RouterClass::current_bus]->send_acknowledge(); // Call the receive callback _after_ the packet has been delivered if(router || packet_is_for_me) { // The packet is for ME :-) @@ -105,14 +105,14 @@ class PJONInteractiveRouter : public RouterClass { RouterClass::send_packet(payload, length, receiver_bus, sender_bus, ack_sent, packet_info); // Call any user registered send notification function - if (sendnotification) sendnotification(payload, length, receiver_bus, sender_bus, packet_info); + if (send_notification) send_notification(payload, length, receiver_bus, sender_bus, packet_info); } public: PJONInteractiveRouter() : RouterClass() {} PJONInteractiveRouter( uint8_t bus_count, - PJONAny*buses[], + PJONAny* const buses[], uint8_t default_gateway = PJON_NOT_ASSIGNED) : RouterClass(bus_count, buses, default_gateway) {} @@ -120,7 +120,7 @@ class PJONInteractiveRouter : public RouterClass { void set_error(PJON_Error e) { error = e; }; - void set_sendnotification(PJON_SendNotification s) { sendnotification = s; }; + void set_send_notification(PJON_Send_Notification s) { send_notification = s; }; void set_custom_ptr(void *custom_ptr) { custom_pointer = custom_ptr; }; @@ -135,3 +135,46 @@ class PJONInteractiveRouter : public RouterClass { // Deliver every packet to receiver callback, or just for this device? void set_router(bool on) { router = on; }; }; + +// Specialized class to simplify declaration when using 2 buses +template +class PJONInteractiveRouter2 : public PJONInteractiveRouter { + StrategyLink linkA; + StrategyLink linkB; + PJONAny busA, busB; +public: + PJONInteractiveRouter2(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON* buses[2] = { &busA, &busB }; + PJONSimpleSwitch::connect_buses(2, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : busB; } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } +}; + +// Specialized class to simplify declaration when using 3 buses +template +class PJONInteractiveRouter3 : public PJONInteractiveRouter { + StrategyLink linkA; + StrategyLink linkB; + StrategyLink linkC; + PJONAny busA, busB, busC; +public: + PJONInteractiveRouter3(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON* buses[3] = { &busA, &busB, &busC }; + PJONSimpleSwitch::connect_buses(3, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + busC.set_link(&linkC); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : (ix == 1 ? busB : busC); } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } + C &get_strategy_2() { return linkC.strategy; } +}; diff --git a/src/PJONLocal.h b/src/PJONLocal.h index 273d1b99a4..3e68c9aae7 100644 --- a/src/PJONLocal.h +++ b/src/PJONLocal.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -14,9 +14,9 @@ ______-| |-__________________________________________________________________ PJONLocal implements a subset of the PJON protocol's features. It does support -only local mode, does not support the asynchronous acknowledge and packet -queueing, infact it can transmit only one packet at a time without any -buffering, although it conserves interoperability with other classes. +only local mode and does not support packet queueing, infact it can transmit +only one packet at a time without any buffering, although it conserves +interoperability with other classes. This class has been developed to enable PJON networking on very limited microcontrollers, like ATtiny45, ATtiny84 and ATtiny85, where even 1kB @@ -29,7 +29,7 @@ contributors, the protocol's documentation, specification and implementation have been strongly tested, enhanced and verified: Fred Larsen, Zbigniew Zasieczny, Matheus Garbelini, sticilface, - Felix Barbalet, Oleh Halitskiy, fabpolli, Adrian Sławiński, + Felix Barbalet, Oleh Halitskiy, fotosettore, fabpolli, Adrian Sławiński, Osman Selçuk Aktepe, Jorgen-VikingGod, drtrigon, Endre Karlson, Wilfried Klaas, budaics, ibantxo, gonnavis, maxidroms83, Evgeny Dontsov, zcattacz, Valerii Koval, Ivan Kravets, Esben Soeltoft, Alex Grishin, @@ -37,7 +37,8 @@ have been strongly tested, enhanced and verified: pacproduct, elusive-code, Emanuele Iannone, Christian Pointner, Fabian Gärtner, Mauro Mombelli, Remo Kallio, hyndruide, sigmaeo, filogranaf, Maximiliano Duarte, Viktor Szépe, Shachar Limor, Andrei Volkau, maniekq, - DetAtHome, Michael Branson, chestwood96, Mattze96 and Steven Bense. + DetAtHome, Michael Branson, chestwood96, Mattze96 and Steven Bense, + Jack Anderson, callalilychen and Julio Aguirre. Compatible tools: @@ -51,7 +52,7 @@ Compatible tools: This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -67,22 +68,23 @@ limitations under the License. */ #pragma once #define PJON_LOCAL -#define PJON_INCLUDE_NONE #include "interfaces/PJON_Interfaces.h" #include "PJONDefines.h" -#include "strategies/PJON_Strategies.h" template class PJONLocal { public: Strategy strategy; uint8_t config = PJON_TX_INFO_BIT | PJON_ACK_REQ_BIT; - uint16_t port = PJON_BROADCAST; #if(PJON_INCLUDE_PACKET_ID) PJON_Packet_Record recent_packet_ids[PJON_MAX_RECENT_PACKET_IDS]; #endif + #if(PJON_INCLUDE_PORT) + uint16_t port = PJON_BROADCAST; + #endif + /* PJONLocal initialization with no parameters: PJONLocal bus; */ @@ -119,19 +121,24 @@ class PJONLocal { uint16_t packet_id = 0, uint16_t rx_port = PJON_BROADCAST ) { - uint16_t l = PJONTools::compose_packet( - _device_id, - PJONTools::localhost(), - id, - PJONTools::localhost(), - destination, - source, - length, - (header == PJON_NO_HEADER) ? config : header, - (!packet_id) ? PJONTools::new_packet_id(_packet_id_seed++) : packet_id, - rx_port, - port - ); + PJON_Packet_Info info; + info.rx.id = id; + info.tx.id = _device_id; + info.header = (header == PJON_NO_HEADER) ? config : header; + #if(PJON_INCLUDE_PACKET_ID) + if(!packet_id && (info.header & PJON_PACKET_ID_BIT)) + info.id = PJONTools::new_packet_id(_packet_id_seed++); + else info.id = packet_id; + #else + (void)packet_id; + #endif + #if(PJON_INCLUDE_PORT) + info.port = (rx_port == PJON_BROADCAST) ? port : rx_port; + #else + (void)rx_port; + #endif + uint16_t l = + PJONTools::compose_packet(info, destination, source, length); return l; }; @@ -181,15 +188,12 @@ class PJONLocal { if(i == 1) { if( (buffer[1] & PJON_MODE_BIT) || - (buffer[1] & PJON_ACK_MODE_BIT) || ( - (buffer[0] == PJON_BROADCAST) && - (buffer[1] & PJON_ACK_REQ_BIT) + (buffer[1] & PJON_MAC_BIT) || ( + (buffer[0] == PJON_BROADCAST) && (buffer[1] & PJON_ACK_REQ_BIT) ) || ( - (buffer[1] & PJON_EXT_LEN_BIT) && - !(buffer[1] & PJON_CRC_BIT) + (buffer[1] & PJON_EXT_LEN_BIT) && !(buffer[1] & PJON_CRC_BIT) ) || ( - !PJON_INCLUDE_PACKET_ID && - (buffer[1] & PJON_PACKET_ID_BIT) + !PJON_INCLUDE_PACKET_ID && (buffer[1] & PJON_PACKET_ID_BIT) ) ) return 0; extended_length = buffer[i] & PJON_EXT_LEN_BIT; @@ -234,7 +238,9 @@ class PJONLocal { known_packet_id(info) && !_router ) return 0; #endif - if((port != PJON_BROADCAST) && (port != info.port)) return 0; + #if(PJON_INCLUDE_PORT) + if((port != PJON_BROADCAST) && (port != info.port)) return 0; + #endif return length - overhead; }; @@ -295,7 +301,7 @@ class PJONLocal { /* In router mode, the receiver function can acknowledge for selected receiver device ids for which the route is known */ - void send_synchronous_acknowledge() { strategy.send_response(PJON_ACK); }; + void send_acknowledge() { strategy.send_response(PJON_ACK); }; /* Set the config bit state: */ @@ -308,7 +314,7 @@ class PJONLocal { TRUE: Send 8bits synchronous acknowledge when a packet is received FALSE: Avoid acknowledge transmission */ - void set_synchronous_acknowledge(bool state) { + void set_acknowledge(bool state) { set_config_bit(state, PJON_ACK_REQ_BIT); }; @@ -324,12 +330,7 @@ class PJONLocal { void set_communication_mode(uint8_t mode) { _mode = mode; }; - /* Configure packet id presence: - TRUE: include packet id, FALSE: Avoid packet id inclusion */ - - void set_packet_id(bool state) { - set_config_bit(state, PJON_PACKET_ID_BIT); - }; + /* Set default configuration: */ void set_default() { _mode = PJON_HALF_DUPLEX; }; @@ -337,13 +338,6 @@ class PJONLocal { void set_id(uint8_t id) { _device_id = id; }; - /* Include the port passing a boolean state and an unsigned integer: */ - - void include_port(bool state, uint16_t p = PJON_BROADCAST) { - set_config_bit(state, PJON_PORT_BIT); - port = p; - }; - /* Configure sender's information inclusion in the packet. TRUE: sender's device id (+8bits overhead) FALSE: No sender's device id inclusion (-8bits overhead) @@ -386,8 +380,29 @@ class PJONLocal { recent_packet_ids[0].sender_id = info.sender_id; }; + /* Configure packet id presence: + TRUE: include packet id, FALSE: Avoid packet id inclusion */ + + void set_packet_id(bool state) { + set_config_bit(state, PJON_PACKET_ID_BIT); + }; + #endif + #if(PJON_INCLUDE_PORT) + + /* Include the port: + p = 1-65535 -> Include 16 bits port id + p = 0 -> Avoid port id inclusion */ + + void include_port(uint16_t p) { + set_config_bit((p != 0) ? 1 : 0, PJON_PORT_BIT); + port = p; + }; + + #endif + + private: uint32_t _last_send = 0; uint8_t _mode; diff --git a/src/PJONLocalFile.h b/src/PJONLocalFile.h new file mode 100644 index 0000000000..85f5f6dd05 --- /dev/null +++ b/src/PJONLocalFile.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/LocalFile/LocalFile.h" + +#define PJONLocalFile PJON diff --git a/src/PJONLocalUDP.h b/src/PJONLocalUDP.h new file mode 100644 index 0000000000..85632a5ed3 --- /dev/null +++ b/src/PJONLocalUDP.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/LocalUDP/LocalUDP.h" + +#define PJONLocalUDP PJON diff --git a/src/PJONMQTTTranslate.h b/src/PJONMQTTTranslate.h new file mode 100644 index 0000000000..7546d407bf --- /dev/null +++ b/src/PJONMQTTTranslate.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/MQTTTranslate/MQTTTranslate.h" + +#define PJONMQTTTranslate PJON diff --git a/src/PJONOverSampling.h b/src/PJONOverSampling.h new file mode 100644 index 0000000000..d4fd7e8d87 --- /dev/null +++ b/src/PJONOverSampling.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/OverSampling/OverSampling.h" + +#define PJONOverSampling PJON diff --git a/src/PJONRouter.h b/src/PJONRouter.h index 411db0c888..70ece87c3e 100644 --- a/src/PJONRouter.h +++ b/src/PJONRouter.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -23,7 +23,7 @@ buses. This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -56,12 +56,12 @@ class PJONRouter : public PJONSwitch { uint8_t find_bus_in_table( const uint8_t *bus_id, - const uint8_t device_id, + const uint8_t /* device_id */, uint8_t &start_bus ) { uint8_t start = start_bus - bus_count; for(uint8_t i = start; i < table_size; i++) { - if(PJONTools::bus_id_equality(bus_id, remote_bus_ids[i])) { + if(memcmp(bus_id, remote_bus_ids[i], 4) == 0) { start_bus = bus_count + i + 1; // Continue searching for matches return remote_bus_via_attached_bus[i]; // Explicit bus id match } @@ -98,15 +98,59 @@ class PJONRouter : public PJONSwitch { PJONRouter() {}; PJONRouter( uint8_t bus_count, - PJONAny *buses[], + PJONAny * const buses[], uint8_t default_gateway = PJON_NOT_ASSIGNED ) : PJONSwitch(bus_count, buses, default_gateway) { }; void add(const uint8_t bus_id[], uint8_t via_attached_bus) { if(table_size < PJON_ROUTER_TABLE_SIZE) { - PJONTools::copy_bus_id(remote_bus_ids[table_size], bus_id); + memcpy(remote_bus_ids[table_size], bus_id, 4); remote_bus_via_attached_bus[table_size] = via_attached_bus; table_size++; } }; }; + + +// Specialized class to simplify declaration when using 2 buses +template +class PJONRouter2 : public PJONRouter { + StrategyLink linkA; + StrategyLink linkB; + PJONAny busA, busB; +public: + PJONRouter2(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON* buses[2] = { &busA, &busB }; + PJONSimpleSwitch::connect_buses(2, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : busB; } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } +}; + +// Specialized class to simplify declaration when using 3 buses +template +class PJONRouter3 : public PJONRouter { + StrategyLink linkA; + StrategyLink linkB; + StrategyLink linkC; + PJONAny busA, busB, busC; +public: + PJONRouter3(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON *buses[3] = { &busA, &busB, &busC }; + PJONSimpleSwitch::connect_buses(3, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + busC.set_link(&linkC); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : (ix == 1 ? busB : busC); } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } + C &get_strategy_2() { return linkC.strategy; } +}; \ No newline at end of file diff --git a/src/PJONSimpleSwitch.h b/src/PJONSimpleSwitch.h index 5267fcd22f..9d663c0dff 100644 --- a/src/PJONSimpleSwitch.h +++ b/src/PJONSimpleSwitch.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -15,17 +15,14 @@ PJONSimpleSwitch has been contributed by Fred Larsen. -It routes packets between buses with different bus ids, and between segmented -buses as well, even for local buses with no bus ids. It is limited to one -single strategy in contrast to its descendant PJONSwitch. +It routes packets between buses with different bus ids, and also between +local buses with no bus ids. It is limited to one single strategy in contrast +to its descendant PJONSwitch. A default gateway can be specified, identifying one of the attached buses to receive packets to other target buses than any of the attached buses. It is possible to use a PJONSimpleSwitch to handle leaf buses in a tree structure. -A segmented bus is a "virtual" bus where ranges of its devices are located -in separate physical buses. - NAT (network address translation) support is present, allowing a local bus to communicate with shared buses. To do this, the local bus must have the bus id set to a public/NAT bus id with which it can be reached from other @@ -41,7 +38,7 @@ enabling receivers on shared buses to reply back to the local bus. This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -58,36 +55,6 @@ limitations under the License. */ #pragma once #include "PJON.h" -template -class PJONBus : public PJON { -public: - PJONBus( - const uint8_t id = PJON_NOT_ASSIGNED, - const uint32_t receive_time_in = 0, - const uint8_t num_device_id_segments = 1, - const uint8_t device_id_segment = 0 - ) : PJON(id) { - receive_time = receive_time_in; - segment_count = num_device_id_segments; - segment = device_id_segment; - }; - - PJONBus( - const uint8_t bus_id[], - const uint8_t id = PJON_NOT_ASSIGNED, - const uint32_t receive_time_in = 0, - const uint8_t num_device_id_segments = 1, - const uint8_t device_id_segment = 0 - ) : PJON(bus_id, id) { - receive_time = receive_time_in; - segment_count = num_device_id_segments; - segment = device_id_segment; - } - - uint32_t receive_time; - uint8_t segment_count, segment; -}; - #ifndef PJON_ROUTER_MAX_BUSES #define PJON_ROUTER_MAX_BUSES 5 #endif @@ -98,11 +65,11 @@ class PJONSimpleSwitch { uint8_t bus_count = 0; uint8_t default_gateway = PJON_NOT_ASSIGNED; uint8_t current_bus = PJON_NOT_ASSIGNED; - PJONBus *buses[PJON_ROUTER_MAX_BUSES]; + PJON *buses[PJON_ROUTER_MAX_BUSES]; void connect( uint8_t bus_count_in, - PJONBus *buses_in[], + PJON * const buses_in[], uint8_t default_gateway_in, void *custom_pointer, PJON_Receiver receiver, @@ -122,20 +89,13 @@ class PJONSimpleSwitch { uint8_t find_attached_bus_with_id( const uint8_t *bus_id, - const uint8_t device_id, + const uint8_t /*device_id*/, uint8_t &start_bus ) { for(uint8_t i=start_bus; ibus_id)) { - // Check if bus is segmented and if device belongs to bus's segment - if( - (buses[i]->segment_count <= 1) || // Not segmented - (device_id == PJON_BROADCAST) || // Broadcast to all segments - ((device_id / (256 / buses[i]->segment_count)) == buses[i]->segment) - ) { // Segment match - start_bus = i + 1; // Continue searching for more matches after this - return i; // Explicit bus id match - } + if(memcmp(bus_id, buses[i]->tx.bus_id, 4) == 0) { + start_bus = i + 1; // Continue searching for more matches after this + return i; // Explicit bus id match } } start_bus = PJON_NOT_ASSIGNED; @@ -152,70 +112,78 @@ class PJONSimpleSwitch { if( !ack_sent && (packet_info.header & PJON_ACK_REQ_BIT) && - (packet_info.receiver_id != PJON_BROADCAST) + (packet_info.rx.id != PJON_BROADCAST) ) { buses[sender_bus]->strategy.send_response(PJON_ACK); ack_sent = true; } - // Set current_bus to receiver bus before potentially calling error callback for that bus + /* Set current_bus to receiver bus before potentially calling error + callback for that bus */ uint8_t send_bus = current_bus; current_bus = receiver_bus; - // NAT support: If a shared packet comes from a local bus destined to a - // non-local receiver, then put the NAT address of the bus as the sender - // bus id so that replies can find the route back via NAT. - uint8_t sender_bus_id[4]; - memcpy(sender_bus_id, packet_info.sender_bus_id, 4); + /* NAT support: If a shared packet comes from a local bus destined to a + non-local receiver, then put the NAT address of the bus as the sender + bus id so that replies can find the route back via NAT. */ + PJON_Packet_Info p_info = packet_info; if ((packet_info.header & PJON_MODE_BIT) && !(buses[sender_bus]->config & PJON_MODE_BIT) && - memcmp(buses[sender_bus]->bus_id, PJONTools::localhost(), 4)!=0 && - memcmp(packet_info.sender_bus_id, PJONTools::localhost(), 4)==0) { + memcmp(buses[sender_bus]->tx.bus_id, PJONTools::localhost(), 4)!=0 && + memcmp(packet_info.tx.bus_id, PJONTools::localhost(), 4)==0) { // Replace sender bus id with public/NAT bus id in the packet - memcpy(&sender_bus_id, buses[sender_bus]->bus_id, 4); + memcpy(&p_info.tx.bus_id, buses[sender_bus]->tx.bus_id, 4); } - // NAT support: If a shared packet comes with receiver bus id matching the - // NAT address of a local bus, then change the receiver bus id to 0.0.0.0 - // before forwarding the shared packet to the local bus. - uint8_t receiver_bus_id[4]; - memcpy(receiver_bus_id, packet_info.receiver_bus_id, 4); + /* NAT support: If a shared packet comes with receiver bus id matching the + NAT address of a local bus, then change the receiver bus id to 0.0.0.0 + before forwarding the shared packet to the local bus. */ if ((packet_info.header & PJON_MODE_BIT) && !(buses[receiver_bus]->config & PJON_MODE_BIT) && - memcmp(buses[receiver_bus]->bus_id, PJONTools::localhost(), 4)!=0 && - memcmp(packet_info.receiver_bus_id, buses[receiver_bus]->bus_id, 4)==0) { + memcmp(buses[receiver_bus]->tx.bus_id, PJONTools::localhost(), 4)!=0 && + memcmp(packet_info.rx.bus_id, buses[receiver_bus]->tx.bus_id, 4)==0) { // Replace receiver bus id with 0.0.0.0 when sending to local bus - memcpy(receiver_bus_id, PJONTools::localhost(), 4); + memcpy(p_info.rx.bus_id, PJONTools::localhost(), 4); } - // Forward the packet - uint16_t result = buses[receiver_bus]->send_from_id( - packet_info.sender_id, - sender_bus_id, - packet_info.receiver_id, - receiver_bus_id, - (const uint8_t*)payload, - length, - packet_info.header, - packet_info.id, - packet_info.port - ); - + uint16_t result = #if PJON_MAX_PACKETS == 0 - // Call error function explicitly, because that will not be done while sending - // when PJON_MAX_PACKETS=0. - if (result == PJON_FAIL) dynamic_error_function(PJON_CONNECTION_LOST, 0); + buses[receiver_bus]->forward_blocking( + p_info, + (const uint8_t *)payload, + length + ); + /* Call error function explicitly, because it is not called by + forward_blocking */ + if(result == PJON_FAIL) dynamic_error_function(PJON_CONNECTION_LOST, 0); + #else + buses[receiver_bus]->forward( + p_info, + (const uint8_t *)payload, + length + ); #endif current_bus = send_bus; } - void forward_packet(const uint8_t *payload, const uint16_t length, - const uint8_t receiver_bus, const uint8_t sender_bus, - bool &ack_sent, const PJON_Packet_Info &packet_info) { + void forward_packet( + const uint8_t *payload, + const uint16_t length, + const uint8_t receiver_bus, + const uint8_t sender_bus, + bool &ack_sent, + const PJON_Packet_Info &packet_info + ) { // If receiving bus matches and not equal to sending bus, then route packet - if(receiver_bus != PJON_NOT_ASSIGNED && receiver_bus != sender_bus) { - send_packet(payload, length, receiver_bus, sender_bus, ack_sent, packet_info); - } + if(receiver_bus != PJON_NOT_ASSIGNED && receiver_bus != sender_bus) + send_packet( + payload, + length, + receiver_bus, + sender_bus, + ack_sent, + packet_info + ); } #ifdef PJON_ROUTER_NEED_INHERITANCE @@ -238,12 +206,12 @@ class PJONSimpleSwitch { const PJON_Packet_Info &packet_info ) { uint8_t start_search = 0; - bool ack_sent = false; // Send ACK only once even if delivering copies to multiple buses + bool ack_sent = false; // Send ACK once even if delivering to multiple buses do { uint8_t receiver_bus = find_bus_with_id((const uint8_t*) ((packet_info.header & PJON_MODE_BIT) != 0 ? - packet_info.receiver_bus_id : PJONTools::localhost()), - packet_info.receiver_id, start_search + packet_info.rx.bus_id : PJONTools::localhost()), + packet_info.rx.id, start_search ); /* The NAT case: @@ -258,7 +226,14 @@ class PJONSimpleSwitch { if(receiver_bus == PJON_NOT_ASSIGNED) receiver_bus = default_gateway; - forward_packet(payload, length, receiver_bus, current_bus, ack_sent, packet_info); + forward_packet( + payload, + length, + receiver_bus, + current_bus, + ack_sent, + packet_info + ); } while(start_search != PJON_NOT_ASSIGNED); }; @@ -274,12 +249,33 @@ class PJONSimpleSwitch { PJONSimpleSwitch( uint8_t bus_count, - PJONBus *buses[], + PJON * const buses[], uint8_t default_gateway = PJON_NOT_ASSIGNED ) { connect_buses(bus_count, buses, default_gateway); }; + // Specialized constructor to simplify syntax when using 2 buses + PJONSimpleSwitch( + PJON &bus0, + PJON &bus1, + uint8_t default_gateway = PJON_NOT_ASSIGNED + ) { + PJON *buses[2] = { &bus0, &bus1 }; + connect_buses(2, buses, default_gateway); + }; + + // Specialized constructor to simplify syntax when using 3 buses + PJONSimpleSwitch( + PJON &bus0, + PJON &bus1, + PJON &bus2, + uint8_t default_gateway = PJON_NOT_ASSIGNED + ) { + PJON *buses[3] = { &bus0, &bus1, &bus2 }; + connect_buses(3, buses, default_gateway); + }; + void begin() { for(uint8_t i = 0; i < bus_count; i++) buses[i]->begin(); }; @@ -287,7 +283,9 @@ class PJONSimpleSwitch { void loop() { for(current_bus = 0; current_bus < bus_count; current_bus++) { uint16_t code = - buses[current_bus]->receive(buses[current_bus]->receive_time); + buses[current_bus]->receive( + buses[current_bus]->strategy.get_receive_time() + ); if(PJON_MAX_PACKETS < bus_count && code == PJON_ACK) break; } for(current_bus = 0; current_bus < bus_count; current_bus++) @@ -297,7 +295,7 @@ class PJONSimpleSwitch { void connect_buses( uint8_t bus_count_in, - PJONBus *buses_in[], + PJON * const buses_in[], uint8_t default_gateway_in = PJON_NOT_ASSIGNED ) { connect( @@ -315,7 +313,7 @@ class PJONSimpleSwitch { uint8_t get_callback_bus() const { return current_bus; } // Return one of the buses, in the same order as sent to the constructor - PJONBus &get_bus(const uint8_t ix) { return *(buses[ix]); } + PJON &get_bus(const uint8_t ix) { return *(buses[ix]); } static void receiver_function( uint8_t *payload, @@ -332,6 +330,9 @@ class PJONSimpleSwitch { } static void error_function(uint8_t code, uint16_t data, void *custom_pointer) { - ((PJONSimpleSwitch*)custom_pointer)->dynamic_error_function(code, data); + ((PJONSimpleSwitch*)custom_pointer)->dynamic_error_function( + code, + data + ); } }; diff --git a/src/PJONSoftwareBitBang.h b/src/PJONSoftwareBitBang.h new file mode 100644 index 0000000000..3964b7a1c9 --- /dev/null +++ b/src/PJONSoftwareBitBang.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/SoftwareBitBang/SoftwareBitBang.h" + +#define PJONSoftwareBitBang PJON diff --git a/src/PJONSwitch.h b/src/PJONSwitch.h index d722a18ce0..f47ae2ab13 100644 --- a/src/PJONSwitch.h +++ b/src/PJONSwitch.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -22,7 +22,7 @@ between buses of different strategies using the Any strategy. This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -39,40 +39,33 @@ limitations under the License. */ #pragma once #include "PJONSimpleSwitch.h" +#include "strategies/Any/Any.h" -class PJONAny : public PJONBus { +class PJONAny : public PJON { public: + PJONAny( + const uint8_t id = PJON_NOT_ASSIGNED + ) : PJON(id) {}; + PJONAny( StrategyLinkBase *link, - const uint8_t id = PJON_NOT_ASSIGNED, - const uint32_t receive_time_in = 0, - const uint8_t num_device_id_segments = 1, - const uint8_t device_id_segment = 0 - ) : PJONBus( - id, - receive_time_in, - num_device_id_segments, - device_id_segment - ) { + const uint8_t id = PJON_NOT_ASSIGNED + ) : PJON(id) { strategy.set_link(link); }; PJONAny( StrategyLinkBase *link, const uint8_t bus_id[], - const uint8_t id = PJON_NOT_ASSIGNED, - const uint32_t receive_time_in = 0, - const uint8_t num_device_id_segments = 1, - const uint8_t device_id_segment = 0 - ) : PJONBus( + const uint8_t id = PJON_NOT_ASSIGNED + ) : PJON( bus_id, - id, - receive_time_in, - num_device_id_segments, - device_id_segment + id ) { strategy.set_link(link); } + + void set_link(StrategyLinkBase *link) { strategy.set_link(link); } }; class PJONSwitch : public PJONSimpleSwitch { @@ -81,7 +74,50 @@ class PJONSwitch : public PJONSimpleSwitch { PJONSwitch( uint8_t bus_count, - PJONAny *bus_list[], + PJONAny * const bus_list[], uint8_t default_gateway = PJON_NOT_ASSIGNED - ) : PJONSimpleSwitch(bus_count, (PJONBus**)bus_list, default_gateway) { }; + ) : PJONSimpleSwitch(bus_count, (PJON* const *)bus_list, default_gateway) { }; +}; + +// Specialized class to simplify declaration when using 2 buses +template +class PJONSwitch2 : public PJONSwitch { + StrategyLink linkA; + StrategyLink linkB; + PJONAny busA, busB; +public: + PJONSwitch2(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON* buses[2] = { &busA, &busB }; + PJONSimpleSwitch::connect_buses(2, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : busB; } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } }; + +// Specialized class to simplify declaration when using 3 buses +template +class PJONSwitch3 : public PJONSwitch { + StrategyLink linkA; + StrategyLink linkB; + StrategyLink linkC; + PJONAny busA, busB, busC; +public: + PJONSwitch3(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON *buses[3] = { &busA, &busB, &busC }; + PJONSimpleSwitch::connect_buses(3, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + busC.set_link(&linkC); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : (ix == 1 ? busB : busC); } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } + C &get_strategy_2() { return linkC.strategy; } +}; \ No newline at end of file diff --git a/src/PJONThroughLora.h b/src/PJONThroughLora.h new file mode 100644 index 0000000000..b9af20952e --- /dev/null +++ b/src/PJONThroughLora.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/ThroughLoRa/ThroughLora.h" + +#define PJONThroughLora PJON diff --git a/src/PJONThroughSerial.h b/src/PJONThroughSerial.h new file mode 100644 index 0000000000..66f020dd1d --- /dev/null +++ b/src/PJONThroughSerial.h @@ -0,0 +1,7 @@ + +#pragma once + +#include "PJON.h" +#include "strategies/ThroughSerial/ThroughSerial.h" + +#define PJONThroughSerial PJON diff --git a/src/PJONVirtualBusRouter.h b/src/PJONVirtualBusRouter.h index 84aca65cb9..023c53f8ba 100644 --- a/src/PJONVirtualBusRouter.h +++ b/src/PJONVirtualBusRouter.h @@ -1,9 +1,9 @@ /*-O//\ __ __ |-gfo\ |__| | | | |\ | ® - |!y°o:\ | __| |__| | \| 12.1 + |!y°o:\ | __| |__| | \| 13.1 |y"s§+`\ multi-master, multi-media bus network protocol - /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com + /so+:-..`\ Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com |+/:ngr-*.`\ |5/:%&-a3f.:;\ \+//u/+g%{osv,,\ @@ -18,8 +18,7 @@ PJONVirtualBusRouter has been contributed by Fred Larsen. This class adds functionality to the PJONSwitch, PJONRouter, PJONDynamicRouter and potential future classes derived from them. This functionality allows a switch or router to treat multiple attached buses with the same bus id as a -"virtual" bus, where devices can be placed anywhere independent of device id, -and without any explicit segmentation of the device id range. +"virtual" bus, where devices can be placed anywhere independent of device id. It will start in promiscuous mode, delivering every packet to all attached buses except the one where the packet comes from. As it learns by looking at @@ -31,7 +30,7 @@ and reducing traffic. This software is experimental and it is distributed "AS IS" without any warranty, use it at your own risk. -Copyright 2010-2020 by Giovanni Blu Mitolo gioscarab@gmail.com +Copyright 2010-2025 by Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -66,7 +65,7 @@ limitations under the License. */ #define PJON_VIRTUALBUS_ROUTE_TIMEOUT_S 0 #endif -template +template class PJONVirtualBusRouter : public RouterClass { protected: // The array position of one (any) of the parts of the virtual bus. @@ -81,7 +80,7 @@ class PJONVirtualBusRouter : public RouterClass { void init_vbus() { for (uint8_t i=0; ibus_id, bus_id, 4)==0; + memcmp(RouterClass::buses[virtual_bus]->tx.bus_id, bus_id, 4)==0; } void register_device_on_vbus(const uint8_t device_id, const uint8_t attached_bus) { @@ -121,10 +120,9 @@ class PJONVirtualBusRouter : public RouterClass { bool &ack_sent, const PJON_Packet_Info &packet_info) { // Override the base class send_packet to disable requesting and sending ACK // if the receiver's location is not registered. - bool disable_ack = unknown_device_location && is_vbus(RouterClass::buses[receiver_bus]->bus_id); + bool disable_ack = unknown_device_location && is_vbus(RouterClass::buses[receiver_bus]->tx.bus_id); if (disable_ack) { - PJON_Packet_Info info; - memcpy(&info, &packet_info, sizeof info); + PJON_Packet_Info info = packet_info; info.header &= ~PJON_ACK_REQ_BIT; bool disable_ack = true; @@ -137,7 +135,7 @@ class PJONVirtualBusRouter : public RouterClass { else { RouterClass::send_packet(payload, length, receiver_bus, sender_bus, ack_sent, packet_info); #ifdef DEBUG_PRINT_PACKETS - Serial.print(F("FORWARD ")); Serial.print(packet_info.receiver_id); Serial.print(F(" to bus ")); + Serial.print(F("FORWARD ")); Serial.print(packet_info.rx.id); Serial.print(F(" to bus ")); Serial.println(receiver_bus); #endif } @@ -146,7 +144,7 @@ class PJONVirtualBusRouter : public RouterClass { void handle_send_error(uint8_t code, uint8_t packet) { // Find out which device id does not receive if (PJON_CONNECTION_LOST == code && - is_vbus(RouterClass::buses[RouterClass::current_bus]->bus_id) && + is_vbus(RouterClass::buses[RouterClass::current_bus]->tx.bus_id) && (packet < PJON_MAX_PACKETS || PJON_MAX_PACKETS == 0)) { PJON_Packet_Info info; @@ -157,14 +155,14 @@ class PJONVirtualBusRouter : public RouterClass { RouterClass::buses[RouterClass::current_bus]-> parse((RouterClass::buses[RouterClass::current_bus]->packets[packet].content), info); #endif - if (info.receiver_id < PJON_VIRTUALBUS_MAX_DEVICES && is_vbus(info.receiver_bus_id)) { + if (info.rx.id < PJON_VIRTUALBUS_MAX_DEVICES && is_vbus(info.rx.bus_id)) { // Unregister the device if we got an error trying to deliver to the attached // bus on which it is registered. This will step back from pointed delivery // to duplication on all parts of the virtual bus for this device. - if (device_via_attached_bus[info.receiver_id] == RouterClass::current_bus) { - device_via_attached_bus[info.receiver_id] = PJON_NOT_ASSIGNED; + if (device_via_attached_bus[info.rx.id] == RouterClass::current_bus) { + device_via_attached_bus[info.rx.id] = PJON_NOT_ASSIGNED; #ifdef DEBUG_PRINT - Serial.print("Unregister "); Serial.print(info.receiver_id); + Serial.print("Unregister "); Serial.print(info.rx.id); Serial.print(" from bus "); Serial.println(RouterClass::current_bus); #endif } @@ -177,11 +175,11 @@ class PJONVirtualBusRouter : public RouterClass { // If a packet is sent to this device later, it is possible to fall back // from delivering a copy to each part of the virtual bus, to just // delivering to the part where the device is actually present. - if (is_vbus(packet_info.sender_bus_id)) - register_device_on_vbus(packet_info.sender_id, RouterClass::current_bus); + if (is_vbus(packet_info.tx.bus_id)) + register_device_on_vbus(packet_info.tx.id, RouterClass::current_bus); // Search for the device on the virtual bus - uint8_t receiver_bus = find_vbus_with_device(packet_info.receiver_bus_id, packet_info.receiver_id); + uint8_t receiver_bus = find_vbus_with_device(packet_info.rx.bus_id, packet_info.rx.id); // If found on part of a virtual bus, do not deliver copies to others if (receiver_bus != PJON_NOT_ASSIGNED) { @@ -203,7 +201,7 @@ class PJONVirtualBusRouter : public RouterClass { PJONVirtualBusRouter() : RouterClass() { init_vbus(); } PJONVirtualBusRouter( uint8_t bus_count, - PJONAny*buses[], + PJONAny* const *buses, uint8_t default_gateway = PJON_NOT_ASSIGNED) : RouterClass(bus_count, buses, default_gateway) { init_vbus(); } @@ -214,3 +212,46 @@ class PJONVirtualBusRouter : public RouterClass { virtual_bus = first_bus; } }; + +// Specialized class to simplify declaration when using 2 buses +template +class PJONVirtualBusRouter2 : public PJONVirtualBusRouter { + StrategyLink linkA; + StrategyLink linkB; + PJONAny busA, busB; +public: + PJONVirtualBusRouter2(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON* buses[2] = { &busA, &busB }; + PJONSimpleSwitch::connect_buses(2, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : busB; } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } +}; + +// Specialized class to simplify declaration when using 3 buses +template +class PJONVirtualBusRouter3 : public PJONVirtualBusRouter { + StrategyLink linkA; + StrategyLink linkB; + StrategyLink linkC; + PJONAny busA, busB, busC; +public: + PJONVirtualBusRouter3(uint8_t default_gateway = PJON_NOT_ASSIGNED) { + PJON* buses[3] = { &busA, &busB, &busC }; + PJONSimpleSwitch::connect_buses(3, buses, default_gateway); + busA.set_link(&linkA); + busB.set_link(&linkB); + busC.set_link(&linkC); + }; + + PJONAny &get_bus(const uint8_t ix) { return ix == 0 ? busA : (ix == 1 ? busB : busC); } + + A &get_strategy_0() { return linkA.strategy; } + B &get_strategy_1() { return linkB.strategy; } + C &get_strategy_2() { return linkC.strategy; } +}; \ No newline at end of file diff --git a/src/interfaces/ARDUINO/ESPNOWHelper.h b/src/interfaces/ARDUINO/ESPNOWHelper.h index ed25ce60cf..0de94b85d8 100644 --- a/src/interfaces/ARDUINO/ESPNOWHelper.h +++ b/src/interfaces/ARDUINO/ESPNOWHelper.h @@ -29,10 +29,10 @@ static const char *TAG = "espnow"; It is configured in menuconfig. */ #if CONFIG_STATION_MODE #define ESPNOW_WIFI_MODE WIFI_MODE_STA - #define ESPNOW_WIFI_IF ESP_IF_WIFI_STA + #define ESPNOW_WIFI_IF WIFI_IF_STA #else #define ESPNOW_WIFI_MODE WIFI_MODE_AP - #define ESPNOW_WIFI_IF ESP_IF_WIFI_AP + #define ESPNOW_WIFI_IF WIFI_IF_AP #endif #define ESPNOW_MAX_PACKET 250 @@ -116,12 +116,11 @@ class ENHelper { memset(peer, 0, sizeof(esp_now_peer_info_t)); peer->channel = _channel; peer->ifidx = ESPNOW_WIFI_IF; - if(IS_BROADCAST_ADDR(mac_addr)) - peer->encrypt = false; - // else { - // peer->encrypt = true; - // memcpy(peer->lmk, _esp_pmk, 16); - // } + if(IS_BROADCAST_ADDR(mac_addr)) peer->encrypt = false; + else { + peer->encrypt = true; + memcpy(peer->lmk, _esp_pmk, 16); + } memcpy(peer->peer_addr, mac_addr, ESP_NOW_ETH_ALEN); ESP_ERROR_CHECK(esp_now_add_peer(peer)); free(peer); diff --git a/src/interfaces/ARDUINO/PJON_IO.h b/src/interfaces/ARDUINO/PJON_IO.h index 8071192531..5bfb5d5c2a 100644 --- a/src/interfaces/ARDUINO/PJON_IO.h +++ b/src/interfaces/ARDUINO/PJON_IO.h @@ -10,6 +10,7 @@ List of supported MCUs: - ATmega8/88/168/328/1280/1284P/2560 (Duemilanove, Uno, Nano, Mini, Pro, Mega) - ATmega16U4/32U4 (Leonardo, Micro) + - ATmega4809 (Nano every, Uno WiFi Rev 2) - ATtiny44/84/44A/84A Added by Wilfried Klaas - ATtiny45/85 (Trinket, Digispark) - SAMD21G18A (Arduino Zero) Added by Esben Soeltoft 03/09/2016 @@ -95,6 +96,7 @@ inform the reader of their definition as macros in the global scope. /* AVR ATmega88/168/328/328P - Arduino Duemilanove, Uno, Nano, Mini, Pro -- */ #if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || \ + defined(__AVR_ATmega168P__)|| \ defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || \ defined(__AVR_ATmega328PB__) #define PJON_IO_PIN_TO_PORT_REG(P) \ @@ -176,6 +178,25 @@ inform the reader of their definition as macros in the global scope. #endif #endif +// --- Arduino Uno WiFi Rev 2, Nano Every --- +#if defined(__AVR_ATmega4809__) + #define PJON_IO_PIN_TO_PORT_REG(P) \ + (((P) == 2 || (P) == 7 ) ? &VPORTA.OUT : ((P) == 5 || (P) == 9 || (P) == 10) ? &VPORTB.OUT : \ + ((P) == 4) ? &VPORTC.OUT : (((P) >= 14 && (P) <= 17) || (P) == 20 || (P) == 21) ? &VPORTD.OUT : \ + ((P) == 8 || (P) == 11 || (P) == 12 || (P) == 13) ? &VPORTE.OUT : &VPORTF.OUT) + #define PJON_IO_PIN_TO_DDR_REG(P) \ + (((P) == 2 || (P) == 7 ) ? &VPORTA.DIR : ((P) == 5 || (P) == 9 || (P) == 10) ? &VPORTB.DIR : \ + ((P) == 4) ? &VPORTC.DIR : (((P) >= 14 && (P) <= 17) || (P) == 20 || (P) == 21) ? &VPORTD.DIR : \ + ((P) == 8 || (P) == 11 || (P) == 12 || (P) == 13) ? &VPORTE.DIR : &VPORTF.DIR) + #define PJON_IO_PIN_TO_PIN_REG(P) \ + (((P) == 2 || (P) == 7 ) ? &VPORTA.IN : ((P) == 5 || (P) == 9 || (P) == 10) ? &VPORTB.IN : \ + ((P) == 4) ? &VPORTC.IN : (((P) >= 14 && (P) <= 17) || (P) == 20 || (P) == 21) ? &VPORTD.IN : \ + ((P) == 8 || (P) == 11 || (P) == 12 || (P) == 13) ? &VPORTE.IN : &VPORTF.IN) + #define PJON_IO_PIN_TO_BIT(P) \ + (((P) == 2 || (P) == 9 || (P) == 11 || (P) == 17) ? 0 : ((P) == 7 || (P) == 10 || (P) == 12 || (P) == 16) ? 1 : \ + ((P) == 5 || (P) == 13 || (P) == 15 || (P) == 18) ? 2 : ((P) == 9 || (P) == 14 || (P) == 19) ? 3 : \ + ((P) == 6 || (P) == 20) ? 4 : ((P) == 3 || (P) == 21) ? 5 : 6 ) +#endif /* SAMD21G18A - Arduino Zero ---------------------------------------------- */ #if defined(__SAMD21G18A__) || defined(ARDUINO_SAM_ZERO) // Arduino Zero pins @@ -310,8 +331,9 @@ inform the reader of their definition as macros in the global scope. do { if(__builtin_constant_p(P)) { \ PJON_IO_WRITE(P, LOW); \ PJON_IO_MODE(P, INPUT); \ - } else \ + } else { \ digitalWrite(P, LOW); \ pinMode(P, INPUT); \ + } \ } while(0) #endif diff --git a/src/interfaces/LINUX/PJON_LINUX_Interface.h b/src/interfaces/LINUX/PJON_LINUX_Interface.h index 68a84c6f83..ae21aabe90 100644 --- a/src/interfaces/LINUX/PJON_LINUX_Interface.h +++ b/src/interfaces/LINUX/PJON_LINUX_Interface.h @@ -40,6 +40,7 @@ extern "C" { #include #include #include + #include #define OUTPUT 1 #define INPUT 0 diff --git a/src/interfaces/LINUX/PJON_LINUX_Interface.inl b/src/interfaces/LINUX/PJON_LINUX_Interface.inl index b34fa6a4f2..2b56040a3f 100644 --- a/src/interfaces/LINUX/PJON_LINUX_Interface.inl +++ b/src/interfaces/LINUX/PJON_LINUX_Interface.inl @@ -8,48 +8,59 @@ #include "PJON_LINUX_Interface.h" #include "/usr/include/asm-generic/termbits.h" #include "/usr/include/asm-generic/ioctls.h" - -auto start_ts = std::chrono::high_resolution_clock::now(); -auto start_ts_ms = std::chrono::high_resolution_clock::now(); - -uint32_t micros() { +#include + +inline auto& getMutableStartTime() +{ + static auto start_ts = std::chrono::high_resolution_clock::now(); + return start_ts; +} +inline auto getStartTime() +{ + static auto start_ts_ms = std::chrono::high_resolution_clock::now(); + return start_ts_ms; +} + +inline uint32_t micros() { auto elapsed_usec = std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - start_ts + std::chrono::high_resolution_clock::now() - getMutableStartTime() ).count(); if(elapsed_usec >= UINT32_MAX) { - start_ts = std::chrono::high_resolution_clock::now(); + getMutableStartTime() = std::chrono::high_resolution_clock::now(); return 0; } else return elapsed_usec; }; -uint32_t millis() { +inline uint32_t millis() { return (uint32_t) std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - start_ts_ms + std::chrono::high_resolution_clock::now() - getStartTime() ).count(); }; -void delayMicroseconds(uint32_t delay_value) { - auto begin_ts = std::chrono::high_resolution_clock::now(); - while(true) { - auto elapsed_usec = - std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - begin_ts - ).count(); - if(elapsed_usec >= delay_value) break; - std::this_thread::sleep_for(std::chrono::microseconds(50)); +inline void delayMicroseconds(uint32_t delay_value) { + struct timeval tv; + if (delay_value < 1000000){ + tv.tv_sec = 0; + tv.tv_usec = delay_value; } + else{ + tv.tv_sec = floor(delay_value / 1000000); + tv.tv_usec = delay_value - tv.tv_sec * 1000000; + } + + select(0, NULL, NULL, NULL, &tv); }; -void delay(uint32_t delay_value_ms) { +inline void delay(uint32_t delay_value_ms) { std::this_thread::sleep_for(std::chrono::milliseconds(delay_value_ms)); }; /* Open serial port ----------------------------------------------------- */ -int serialOpen(const char *device, const int baud) { +inline int serialOpen(const char *device, const int baud) { speed_t bd; int fd; @@ -90,13 +101,13 @@ int serialOpen(const char *device, const int baud) { r = ioctl(fd, TIOCMSET, &state); if(r) return -1; - usleep(10000); // Sleep for 10 milliseconds + delayMicroseconds(10000); // Sleep for 10 milliseconds return fd; }; /* Returns the number of bytes of data available to be read in the buffer */ -int serialDataAvailable(const int fd) { +inline int serialDataAvailable(const int fd) { int result = 0; ioctl(fd, FIONREAD, &result); return result; @@ -104,7 +115,7 @@ int serialDataAvailable(const int fd) { /* Reads a character from the serial buffer ------------------------------- */ -int serialGetCharacter(const int fd) { +inline int serialGetCharacter(const int fd) { uint8_t result; if(read(fd, &result, 1) != 1) return -1; return ((int)result) & 0xFF; diff --git a/src/interfaces/LINUX/TCPHelper_POSIX.h b/src/interfaces/LINUX/TCPHelper_POSIX.h index dcf4506a15..4c4ad75e72 100644 --- a/src/interfaces/LINUX/TCPHelper_POSIX.h +++ b/src/interfaces/LINUX/TCPHelper_POSIX.h @@ -13,6 +13,7 @@ #define close(fd) closesocket(fd) #define ssize_t int #else +#include #include #include #include @@ -101,11 +102,14 @@ class TCPHelperClient { struct timeval read_timeout; read_timeout.tv_sec = 0; read_timeout.tv_usec = 2000000; +#ifndef __ZEPHYR__ setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&read_timeout, sizeof read_timeout); setsockopt(_fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&read_timeout, sizeof read_timeout); +#endif bool connected = ::connect(_fd, (struct sockaddr *) &_remote_addr,sizeof(_remote_addr)) == 0; if (connected) { +#ifndef __ZEPHYR__ // Shorten timeouts for reading and writing struct timeval read_timeout; read_timeout.tv_sec = 0; @@ -113,8 +117,8 @@ class TCPHelperClient { setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&read_timeout, sizeof read_timeout); read_timeout.tv_usec = 2000000; setsockopt(_fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&read_timeout, sizeof read_timeout); - - // Disable Nagles algorith because we are sending small packets and waiting for reply +#endif + // Disable Nagles algorithm because we are sending small packets and waiting for reply set_nodelay(true); } return connected; @@ -189,14 +193,15 @@ class TCPHelperClient { #endif // Set timeouts for reading and writing +#ifndef __ZEPHYR__ struct timeval read_timeout; read_timeout.tv_sec = 0; read_timeout.tv_usec = 1000; setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&read_timeout, sizeof read_timeout); read_timeout.tv_usec = 2000000; setsockopt(_fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&read_timeout, sizeof read_timeout); - - // Disable Nagles algorith because we are sending small packets and waiting for reply +#endif + // Disable Nagles algorithm because we are sending small packets and waiting for reply set_nodelay(true); return 1; @@ -233,7 +238,7 @@ class TCPHelperClient { int write(const uint8_t *buffer, int size) { if (_fd == -1) return -1; -#ifdef _WIN32 +#if defined(_WIN32) || defined(__ZEPHYR__) int w = ::send(_fd, (char*)buffer, size, 0); #else int w = ::send(_fd, (char*)buffer, size, MSG_NOSIGNAL); @@ -298,6 +303,7 @@ class TCPHelperServer { memset(&_remote_sender_addr, 0, len); int connected_fd = _fd == -1 ? -1 : ::accept(_fd, (struct sockaddr *) &_remote_sender_addr, &len); if (connected_fd != -1) { +#ifndef __ZEPHYR__ // Shorten timeout for reading and writing struct timeval read_timeout; read_timeout.tv_sec = 0; @@ -305,8 +311,8 @@ class TCPHelperServer { setsockopt(connected_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&read_timeout, sizeof read_timeout); read_timeout.tv_usec = 2000000; setsockopt(connected_fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&read_timeout, sizeof read_timeout); - - // Disable Nagles algorith because we are sending small packets and waiting for reply +#endif + // Disable Nagles algorithm because we are sending small packets and waiting for reply int flag = 1; setsockopt(connected_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof flag); } diff --git a/src/interfaces/LINUX/UDPHelper_POSIX.h b/src/interfaces/LINUX/UDPHelper_POSIX.h index f6982cdedb..64ee2a3c23 100644 --- a/src/interfaces/LINUX/UDPHelper_POSIX.h +++ b/src/interfaces/LINUX/UDPHelper_POSIX.h @@ -10,6 +10,7 @@ #define close(fd) closesocket(fd) #define ssize_t int #else +#include #include #include #include @@ -18,6 +19,11 @@ #include #endif +#ifdef __ZEPHYR__ +#include +#define INADDR_BROADCAST ((u32_t) 0xffffffff) +#endif + class UDPHelper { uint16_t _port; uint32_t _magic_header; @@ -69,7 +75,11 @@ class UDPHelper { read_timeout.tv_sec = 0; read_timeout.tv_usec = 1000; #endif +#ifdef __ZEPHYR__ + fcntl(_fd, F_SETFL, O_NONBLOCK); +#else setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&read_timeout, sizeof read_timeout); +#endif // Bind to specific local port memset(&_localaddr, 0, sizeof(_localaddr)); @@ -88,12 +98,14 @@ class UDPHelper { _remote_receiver_addr.sin_port = htons(_port); _remote_receiver_addr.sin_addr.s_addr = INADDR_BROADCAST; +#ifndef __ZEPHYR__ // Allow broadcasts int broadcast=1; if (setsockopt(_fd,SOL_SOCKET,SO_BROADCAST,(const char*)&broadcast,sizeof(broadcast))==-1) { //printf("INIT send setsockopt %s\n", strerror(errno)); return false; } +#endif return true; } diff --git a/src/interfaces/PJON_Interfaces.h b/src/interfaces/PJON_Interfaces.h index ab7bebcd76..4db6c7203b 100644 --- a/src/interfaces/PJON_Interfaces.h +++ b/src/interfaces/PJON_Interfaces.h @@ -5,3 +5,4 @@ #include "RPI/PJON_RPI_Interface.h" #include "WINX86/PJON_WINX86_Interface.h" #include "LINUX/PJON_LINUX_Interface.h" +#include "ZEPHYR/PJON_ZEPHYR_Interface.h" diff --git a/src/interfaces/WINX86/Serial/Serial.cpp b/src/interfaces/WINX86/Serial/Serial.cpp index ba7ff8c630..4da114175c 100644 --- a/src/interfaces/WINX86/Serial/Serial.cpp +++ b/src/interfaces/WINX86/Serial/Serial.cpp @@ -10,6 +10,9 @@ * - modified flush method to use WIN API * - added initial tests * - changed timeouts to 1s + * + * + * 11/05/2020 - getByte function simplified, now returns -1 in case of failure */ #if defined(_WIN32) @@ -32,12 +35,7 @@ std::wstring s2ws(const std::string& s){ }; -Serial::Serial( - std::string &commPortName, - int bitRate, - bool testOnStartup, - bool cycleDtrOnStartup -) { +Serial::Serial(std::string &commPortName, int bd) { std::wstring com_name_ws = s2ws(commPortName); commHandle = @@ -80,7 +78,7 @@ Serial::Serial( // set DCB; disabling harware flow control; setting 1N8 mode memset(&dcb, 0, sizeof(dcb)); dcb.DCBlength = sizeof(dcb); - dcb.BaudRate = bitRate; + dcb.BaudRate = bd; dcb.fBinary = 1; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fRtsControl = RTS_CONTROL_DISABLE; @@ -93,23 +91,6 @@ Serial::Serial( throw("ERROR: Could not set com port parameters"); } } - - if(cycleDtrOnStartup) { - if(!EscapeCommFunction(commHandle, CLRDTR)) - throw("ERROR: clearing DTR"); - Sleep(200); - if(!EscapeCommFunction(commHandle, SETDTR)) - throw("ERROR: setting DTR"); - } - - if(testOnStartup) { - DWORD numWritten; - char init[] = "PJON-python init"; - if(!WriteFile(commHandle, init, sizeof(init), &numWritten, NULL)) - throw("writing initial data to port failed"); - if(numWritten != sizeof(init)) - throw("ERROR: not all test data written to port"); - } }; @@ -123,19 +104,17 @@ int Serial::writeByte(uint8_t *buffer) { return numWritten; }; -uint8_t Serial::getByte() { +int16_t Serial::getByte() { uint8_t buff; - read(&buff, 1, false); + if(read(&buff, 1) == -1) return -1; return buff; }; -int Serial::read(uint8_t *buffer, int buffLen, bool nullTerminate) { +int Serial::read(uint8_t *buffer, int buffLen) { DWORD numRead; - if(nullTerminate) --buffLen; BOOL ret = ReadFile(commHandle, buffer, buffLen, &numRead, NULL); - if(!ret) return 0; - if(nullTerminate) buffer[numRead] = '\0'; + if(!ret) return -1; return numRead; }; diff --git a/src/interfaces/WINX86/Serial/Serial.h b/src/interfaces/WINX86/Serial/Serial.h index 3bd07d2676..5626154783 100644 --- a/src/interfaces/WINX86/Serial/Serial.h +++ b/src/interfaces/WINX86/Serial/Serial.h @@ -13,6 +13,8 @@ * @version 0.1 -- 28 October 2008 * @version 0.2 -- 20 April 2017 (Zbigniew Zasieczny) * - added methods needed by PJON to handle WINX86 abstraction interface + * + * 11/05/2020 getByte function simplified, now returns -1 in case of failure */ #pragma once @@ -31,9 +33,7 @@ public: Serial( std::string &commPortName, - int bitRate = 115200, - bool testOnStartup = false, - bool cycleDtrOnStartup = false + int bitRate = 115200 ); virtual ~Serial(); @@ -50,15 +50,16 @@ * * @param buffer pointer to the buffer to be written to * @param buffLen the size of the buffer - * @param nullTerminate if set to true it will null terminate the string * * @return int the number of bytes read */ - int read(uint8_t *buffer, int buffLen, bool nullTerminate = true); + int read(uint8_t *buffer, int buffLen); - /** Returns single byte (uint8_t) from the receive buffer - */ - uint8_t getByte(); + /** Returns an integer (uint16_t) + * + * @return a value < 256 or -1 in case of failure + */ + int16_t getByte(); /** Returns true if there is data available in receive buffer */ diff --git a/src/interfaces/ZEPHYR/PJON_ZEPHYR_Interface.h b/src/interfaces/ZEPHYR/PJON_ZEPHYR_Interface.h new file mode 100644 index 0000000000..bc3905a1c0 --- /dev/null +++ b/src/interfaces/ZEPHYR/PJON_ZEPHYR_Interface.h @@ -0,0 +1,104 @@ +#pragma once + +#if defined(__ZEPHYR__) + +#define OUTPUT GPIO_OUTPUT + +#include +#include +#include +#include + +int serial_get_char(struct device* dev); +bool serial_char_available(struct device* dev); +void uart_irq_callback(struct device *dev); +int serial_put_char(struct device* dev, uint8_t byte); +struct device* serial_open(const char* dt_label); +void serial_close(const char* dt_label); +void digitalWrite(int pin, bool state); +void pinMode(int pin, int mode); +void serial_flush(struct device* dev); + +#if defined CONFIG_PJON_STRATEGY_THROUGHSERIAL +#ifndef PJON_ZEPHYR_SEPARATE_DEFINITION +#include "PJON_ZEPHYR_Interface.inl" +#endif +#endif +// deal with randomness + +#ifndef PJON_RANDOM +#define PJON_RANDOM(randMax) (int)((1.0 + randMax) * rand() / ( RAND_MAX + 1.0 )) +#endif + +#ifndef PJON_RANDOM_SEED +#define PJON_RANDOM_SEED srand +#endif + +#ifndef A0 +#define A0 0 +#endif + +#ifndef PJON_ANALOG_READ +#define PJON_ANALOG_READ(P) 0 +#endif + +// delay and timing functions + +#ifndef PJON_DELAY +#define PJON_DELAY(x) (k_sleep(K_MSEC(x))) +#endif + +#ifndef PJON_DELAY_MICROSECONDS +#define PJON_DELAY_MICROSECONDS(x) (k_sleep(K_USEC(x))) +#endif + +#ifndef PJON_MILLIS +#define PJON_MILLIS k_uptime_get +#endif + +#ifndef PJON_MICROS +#define PJON_MICROS 1000*k_uptime_get +#endif + +// serial port handling + +#ifndef PJON_SERIAL_TYPE +#define PJON_SERIAL_TYPE struct device* +#endif + +#ifndef PJON_SERIAL_AVAILABLE +#define PJON_SERIAL_AVAILABLE(S) serial_char_available(S) +#endif + +#ifndef PJON_SERIAL_READ +#define PJON_SERIAL_READ(S) serial_get_char(S) +#endif + +#ifndef PJON_SERIAL_WRITE +#define PJON_SERIAL_WRITE(S, C) serial_put_char(S, C) +#endif + +#ifndef PJON_SERIAL_FLUSH +#define PJON_SERIAL_FLUSH(S) serial_flush(S) +#endif + +// io pin handling (for setting the rs485 txe pin) is not needed since we use the auto-direction +// feature of the rs485 transceiver + +#ifndef PJON_IO_WRITE +#define PJON_IO_WRITE digitalWrite +#endif + +#ifndef PJON_IO_MODE +#define PJON_IO_MODE pinMode +#endif + +#ifndef LOW +#define LOW 0 +#endif + +#ifndef HIGH +#define HIGH 1 +#endif + +#endif diff --git a/src/interfaces/ZEPHYR/PJON_ZEPHYR_Interface.inl b/src/interfaces/ZEPHYR/PJON_ZEPHYR_Interface.inl new file mode 100644 index 0000000000..8158b77129 --- /dev/null +++ b/src/interfaces/ZEPHYR/PJON_ZEPHYR_Interface.inl @@ -0,0 +1,128 @@ +#ifndef ZEPHYR + #define ZEPHYR +#endif +#ifndef PJON_ZEPHYR_SEPARATE_DEFINITION + #define PJON_ZEPHYR_SEPARATE_DEFINITION +#endif + +#include "PJON_ZEPHYR_Interface.h" +#include + +#include +#include +#include +#include + +#include +#include +#include + +static struct device* pin_dev = NULL; + +static std::map ringbuffers; + +static struct ring_buf* _get_ring_buf(struct device* dev) +{ + auto search = ringbuffers.find(dev); + struct ring_buf* tmp = nullptr; + if (search != ringbuffers.end()) { + tmp = search->second; + } + return tmp; +} + +struct device* serial_open(const char* dt_label) +{ + struct device* uart = device_get_binding(dt_label); ///@todo multiple uarts for this layer --SA + struct uart_config cfg; + uart_config_get(uart, &cfg); + cfg.data_bits = UART_CFG_DATA_BITS_8; + cfg.stop_bits = UART_CFG_STOP_BITS_1; + uart_configure(uart, &cfg); + + uart_irq_callback_set(uart, uart_irq_callback); + uart_irq_rx_enable(uart); + + uint8_t* buf = (uint8_t*)calloc(1, CONFIG_PJON_MTU); + struct ring_buf* r = (struct ring_buf*)calloc(1, sizeof(struct ring_buf)); + r->size = CONFIG_PJON_MTU, + r->buf.buf8 = buf; + + auto ret = ringbuffers.insert(std::make_pair(uart, r)); + + if (ret.second != true) { + uart = nullptr; + } + + return uart; +} + +void serial_close(const char* dt_label) +{ + struct ring_buf* r = _get_ring_buf(device_get_binding(dt_label)); + free(r->buf.buf8); + free(r); +} + +int serial_get_char(struct device* dev) +{ + size_t ret; + uint8_t b; + struct ring_buf* r = _get_ring_buf(dev); + if (r) { + ret = ring_buf_get(r, &b, sizeof(b)); + } + return b; +} + +bool serial_char_available(struct device* dev) +{ + struct ring_buf* r = _get_ring_buf(dev); + bool b = false; + if (r) { + b = !ring_buf_is_empty(r); + } + return b; +} + +void uart_irq_callback(struct device* dev) +{ + uart_irq_update(dev); + + if (uart_irq_rx_ready(dev)) { + uint8_t tmp; + while (1) { + if (uart_fifo_read(dev, &tmp, 1) == 0) { + break; + } + struct ring_buf* r = _get_ring_buf(dev); + + if (r) { + ring_buf_put(r, &tmp, sizeof(tmp)); + } + } + } +} + +int serial_put_char(struct device* dev, uint8_t b) +{ + uart_poll_out(dev, b); + return 1; +} + +void digitalWrite(int pin, bool state) +{ + gpio_pin_set(pin_dev, pin, state); +} + +void pinMode(int pin, int mode) +{ + pin_dev = device_get_binding(DT_GPIO_LABEL(DT_ALIAS(pjon_txe_pin), gpios)); + + gpio_pin_configure(pin_dev, pin, mode); +} + +void serial_flush(struct device* dev) +{ + k_usleep(1000); +} diff --git a/src/strategies/AnalogSampling/AnalogSampling.h b/src/strategies/AnalogSampling/AnalogSampling.h index 7f3a716308..d831c88853 100644 --- a/src/strategies/AnalogSampling/AnalogSampling.h +++ b/src/strategies/AnalogSampling/AnalogSampling.h @@ -31,7 +31,7 @@ necessary to tweak timing constants in Timing.h. ___________________________________________________________________________ - Copyright 2010-2020 Giovanni Blu Mitolo gioscarab@gmail.com + Copyright 2010-2025 Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -87,6 +87,11 @@ #include "Timing.h" +// Recommended receive time for this strategy, in microseconds +#ifndef AS_RECEIVE_TIME + #define AS_RECEIVE_TIME 1000 +#endif + class AnalogSampling { public: @@ -159,6 +164,13 @@ class AnalogSampling { }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { + return AS_RECEIVE_TIME; + }; + + /* Handle a collision: */ void handle_collision() { diff --git a/src/strategies/AnalogSampling/README.md b/src/strategies/AnalogSampling/README.md index 5313d49e79..2d009f07e0 100644 --- a/src/strategies/AnalogSampling/README.md +++ b/src/strategies/AnalogSampling/README.md @@ -1,10 +1,12 @@ ## AnalogSampling -**Medium**: light pulses over air or optic-fibre | **Pins used**: 1 or 2 +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Light pulses over air or optic-fibre | 1 or 2 | `#include `| -`AnalogSampling` strategy or data link complies with [PJDLS v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md), it is designed to communicate data wirelessly using light impulses and its sampling technique is based on analog readings. This strategy is able to use a single LED for both photo-emission and photo-reception phases providing with wireless half-duplex connectivity between devices with a range of up to 5 meters. Most appliances have at least a useless energy consuming LED on board, right? +The `AnalogSampling` strategy is a software implementation of [PJDLS](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md), it is designed to communicate data wirelessly using light impulses and its sampling technique is based on analog readings. This strategy is able to use a single LED for both photo-emission and photo-reception phases providing with wireless half-duplex connectivity between devices with a range of up to 5 meters. Most appliances have at least a useless energy consuming LED on board, right? Thanks to this strategy that can be used for communication. -`AnalogSampling` can also be used with separate emitter and receiver pins enabling cheap long range wireless communication using standard photo-diodes, light-emitting diodes or laser diodes. The proposed circuit, technique and codebase were originally implemented in the far 2011, see the first [video documented experiment](https://www.youtube.com/watch?v=-Ul2j6ixbmE). Take a look at the [video introduction](https://www.youtube.com/watch?v=1BeGYMjg-DI) for a brief showcase of its features. +`AnalogSampling` can also be used with separate emitter and receiver pins enabling cheap long range wireless or optic-fibre communication using standard photo-diodes, light-emitting diodes or laser diodes. The proposed circuit, technique and codebase were originally implemented in 2011, see the first [video documented experiment](https://www.youtube.com/watch?v=-Ul2j6ixbmE). Take a look at the [video introduction](https://www.youtube.com/watch?v=1BeGYMjg-DI) for a brief showcase of its features. ### Compatibility | MCU | Clock | Supported pins | Supported modes | @@ -36,7 +38,7 @@ It is possible to use LEDs as wireless (bidirectional) transceivers. This means `AnalogSampling` can be used to experiment with short range infrared or visible light communication (remote control, robot swarms, data streaming using lighting), medium range using light sources (cars transmitting data through front and backlights) or long range laser communication (data between ground and LEO). ### Configuration -Before including `PJON.h` it is possible to configure `AnalogSampling` using predefined constants: +Before including the library it is possible to configure `AnalogSampling` using predefined constants: | Constant | Purpose | Supported value | | ------------------------- |------------------------------------ | ------------------------------------------ | @@ -46,11 +48,11 @@ Before including `PJON.h` it is possible to configure `AnalogSampling` using pre | `AS_MAX_ATTEMPTS` | Maximum transmission attempts | Numeric value (10 by default) | | `AS_PRESCALE` | Set ADC pre-scaler | 8, 16, 32 | -Pass the `AnalogSampling` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. All the other necessary information is present in the general [Documentation](/documentation). +Use `PJONAnalogSampling` to instantiate a PJON object ready to communicate using `AnalogSampling` strategy. All the other necessary information is present in the general [Documentation](/documentation). ```cpp -#include +#include -PJON bus; +PJONAnalogSampling bus; void setup() { // Set the pin A0 as the communication pin diff --git a/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md b/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md index 028b006ba3..663257fb17 100644 --- a/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md +++ b/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md @@ -1,14 +1,13 @@ ### Specifications index #### Network layer -- [PJON (Padded Jittering Operative Network) v3.2](/specification/PJON-protocol-specification-v3.2.md) -- [Acknowledge specification v1.0](/specification/PJON-protocol-acknowledge-specification-v1.0.md) +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) - [Network services list](/specification/PJON-network-services-list.md) #### Data link layer -- [PJDL (Padded Jittering Data Link) v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) +- [PJDL (Padded Jittering Data Link) v5.0](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) - [PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) - **[PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md)** -- [TSDL (Tardy Serial Data Link) v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) +- [TSDL (Tardy Serial Data Link) v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) - [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) --- diff --git a/src/strategies/Any/Any.h b/src/strategies/Any/Any.h index dd67e34846..f0ce0f3444 100644 --- a/src/strategies/Any/Any.h +++ b/src/strategies/Any/Any.h @@ -7,7 +7,7 @@ Proposed and developed by Fred Larsen ___________________________________________________________________________ - Copyright 2010-2020 Giovanni Blu Mitolo gioscarab@gmail.com + Copyright 2010-2025 Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -50,7 +50,7 @@ class Any { /* Check if the channel is free for transmission */ - bool can_start() { return s->can_start(); } + bool can_start() { return s->can_start(); }; /* Returns the maximum number of attempts for each transmission: */ @@ -58,6 +58,11 @@ class Any { uint8_t get_max_attempts() { return s->get_max_attempts(); } + /* Returns the recommended receive time for this strategy: */ + + uint16_t get_receive_time() { return s->get_receive_time(); } + + /* Handle a collision: */ void handle_collision() { s->handle_collision(); }; diff --git a/src/strategies/Any/README.md b/src/strategies/Any/README.md index 659df8f036..4e97a71f8e 100644 --- a/src/strategies/Any/README.md +++ b/src/strategies/Any/README.md @@ -1,5 +1,10 @@ ## Any +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Any | NA | `#include ` | + + The `Any` strategy includes virtual inheritance and let PJON objects change from a strategy to another after instantiation or a collection of PJON objects with different strategies to be treated agnostically. ### How to use Any @@ -10,10 +15,10 @@ PJON bus; ``` Call the `set_link` method passing the `StrategyLink` instance: ```cpp -#include +#include StrategyLink link; -PJON bus; +PJONAny bus; void setup() { Serial.begin(9600); diff --git a/src/strategies/Any/StrategyLink.h b/src/strategies/Any/StrategyLink.h index 188acf50b4..97866a2135 100644 --- a/src/strategies/Any/StrategyLink.h +++ b/src/strategies/Any/StrategyLink.h @@ -4,7 +4,7 @@ Proposed and developed by Fred Larsen ___________________________________________________________________________ - Copyright 2010-2020 Giovanni Blu Mitolo gioscarab@gmail.com + Copyright 2010-2025 Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -49,6 +49,11 @@ class StrategyLink : public StrategyLinkBase { uint8_t get_max_attempts() { return strategy.get_max_attempts(); } + /* Returns the recommended receive time for this strategy: */ + + uint16_t get_receive_time() { return strategy.get_receive_time(); } + + /* Handle a collision: */ void handle_collision() { strategy.handle_collision(); }; diff --git a/src/strategies/Any/StrategyLinkBase.h b/src/strategies/Any/StrategyLinkBase.h index 077f5a9e32..4cd44cc315 100644 --- a/src/strategies/Any/StrategyLinkBase.h +++ b/src/strategies/Any/StrategyLinkBase.h @@ -4,7 +4,7 @@ Proposed and developed by Fred Larsen ___________________________________________________________________________ - Copyright 2010-2020 Giovanni Blu Mitolo gioscarab@gmail.com + Copyright 2010-2025 Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -42,6 +42,9 @@ class StrategyLinkBase { virtual uint8_t get_max_attempts() = 0; + /* Returns the recommended receive time for this strategy: */ + + virtual uint16_t get_receive_time() = 0; /* Handle a collision: */ diff --git a/src/strategies/DualUDP/DualUDP.h b/src/strategies/DualUDP/DualUDP.h index 8fcc345b08..2af5ccc3d5 100644 --- a/src/strategies/DualUDP/DualUDP.h +++ b/src/strategies/DualUDP/DualUDP.h @@ -79,6 +79,11 @@ #define DUDP_DEFAULT_PORT 7500 #define DUDP_MAGIC_HEADER (uint32_t) 0x0EFA23FF +// Recommended receive time for this strategy, in microseconds +#ifndef DUDP_RECEIVE_TIME + #define DUDP_RECEIVE_TIME 0 +#endif + //#define DUDP_DEBUG_PRINT class DualUDP { @@ -244,6 +249,10 @@ class DualUDP { static uint8_t get_max_attempts() { return DUDP_MAX_RETRIES; }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { return DUDP_RECEIVE_TIME; }; + /* Handle a collision (empty because handled on Ethernet level): */ void handle_collision() { }; @@ -257,13 +266,13 @@ class DualUDP { if(length != PJON_FAIL && length > 4) { // Extract some info from the header PJONTools::parse_header(data, _packet_info); - _last_in_receiver_id = _packet_info.receiver_id; - _last_in_sender_id = _packet_info.sender_id; + _last_in_receiver_id = _packet_info.rx.id; + _last_in_sender_id = _packet_info.tx.id; // Autoregister sender if the packet was sent directly if( - _packet_info.sender_id != PJON_NOT_ASSIGNED && + _packet_info.tx.id != PJON_NOT_ASSIGNED && _last_out_sender_id != PJON_NOT_ASSIGNED && - _packet_info.receiver_id == _last_out_sender_id + _packet_info.rx.id == _last_out_sender_id ) autoregister_sender(); } return length; @@ -330,8 +339,8 @@ class DualUDP { if(length > 4) { // Extract some info from the header PJONTools::parse_header(data, _packet_info); - _last_out_receiver_id = _packet_info.receiver_id; - _last_out_sender_id = _packet_info.sender_id; + _last_out_receiver_id = _packet_info.rx.id; + _last_out_sender_id = _packet_info.tx.id; // Locate receiver in table unless it is a PJON broadcast (receiver 0) int16_t pos = -1; @@ -356,7 +365,7 @@ class DualUDP { udp.send_frame(data, length, _remote_ip[pos], _remote_port[pos]); _send_attempts[pos]++; } - _last_out_time = millis(); + _last_out_time = PJON_MILLIS(); } }; diff --git a/src/strategies/DualUDP/README.md b/src/strategies/DualUDP/README.md index 4c0468911f..d3cb2d1987 100644 --- a/src/strategies/DualUDP/README.md +++ b/src/strategies/DualUDP/README.md @@ -1,9 +1,11 @@ ## DualUDP -**Medium:** Ethernet port, wired or WiFi +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Ethernet port, wired or WiFi | NA |`#include `| With the `DualUDP` PJON strategy, multiple devices with Ethernet ports can use PJON to communicate with each other over an Ethernet network, wired or over WiFi or both. Like the `GlobalUDP` strategy, this strategy is not limited to the local network -and can therefore reach devices farther away, to another LAN connected through VPN, or potentially across the Internet (beware of security issues). Like the `DualUDP` strategy it will reach devices on the LAN without configuration. +and can therefore reach devices farther away, to another LAN connected through VPN, or potentially across the Internet (beware of security issues). Like the `LocalUDP` strategy it will reach devices on the LAN without configuration. Feature summary: * Will autodiscover devices on the LAN. These can use DHCP assigned IP addresses. @@ -16,10 +18,11 @@ If a cabled or wireless Ethernet network exists, using this to let devices commu It can also be useful for connecting physically separate clusters of devices that are connected wired with the `SoftwareBitBang` strategy, or wirelessly with the `Oversampling` strategy, when a LAN or WAN is connecting the locations. ### How to use DualUDP -Pass the `DualUDP` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. -```cpp - // Use DualUDP strategy with PJON device id 44 - PJON bus(44); +Use `PJONDualUDP` to instantiate a PJON object ready to communicate using the `DualUDP` strategy: +```cpp + #include + + PJONDualUDP bus(44); // Use device id 44 ``` Now the Ethernet card must be set up. This can be done by using a static IP address or by getting an address assigned by DHCP. diff --git a/src/strategies/ESPNOW/ESPNOW.h b/src/strategies/ESPNOW/ESPNOW.h index 2fc4d1818f..432a1d4ec6 100644 --- a/src/strategies/ESPNOW/ESPNOW.h +++ b/src/strategies/ESPNOW/ESPNOW.h @@ -31,6 +31,11 @@ #define EN_MAX_REMOTE_NODES 10 #endif +// Recommended receive time for this strategy, in microseconds +#ifndef EN_RECEIVE_TIME + #define EN_RECEIVE_TIME 0 +#endif + #define EN_MAGIC_HEADER (uint8_t*)"\xEE\xFE\x0E\xEF" class ESPNOW { @@ -56,10 +61,12 @@ class ESPNOW { return _espnow_initialised; }; - int16_t find_remote_node(uint8_t id) { + int16_t find_remote_node(uint8_t id, uint8_t* mac) { for(uint8_t i = 0; i < _remote_node_count; i++) - if(_remote_id[i] == id) - return i; + if( + ((_remote_id[i] == id) && (id != PJON_NOT_ASSIGNED)) || + (memcmp(_remote_mac, mac, ESP_NOW_ETH_ALEN) == 0) + ) return i; return -1; }; @@ -69,7 +76,7 @@ class ESPNOW { // First get PJON sender id from incoming packet PJON_Packet_Info packet_info; PJONTools::parse_header(message, packet_info); - uint8_t sender_id = packet_info.sender_id; + uint8_t sender_id = packet_info.tx.id; if(sender_id == 0) { ESP_LOGE("ESPNOW", "AutoRegister parsing failed"); return; // If parsing fails, it will be 0 @@ -80,20 +87,23 @@ class ESPNOW { en.get_sender(sender_mac); // See if PJON id is already registered, add if not - int16_t pos = find_remote_node(sender_id); + int16_t pos = find_remote_node(sender_id, sender_mac); if(pos == -1) { ESP_LOGI("ESPNOW", "Autoregister new sender %d",sender_id); add_node(sender_id, sender_mac); } - else if(memcmp(_remote_mac[pos], sender_mac, ESP_NOW_ETH_ALEN) != 0) { + else if(memcmp(_remote_mac[pos], sender_mac, ESP_NOW_ETH_ALEN) == 0) { // Update mac of existing node ESP_LOGI( "ESPNOW", - "Update sender mac %d %d:%d:%d", + "Update sender sender_id(%d) [%02X:%02X:%02X:%02X:%02X:%02X]", sender_id, + sender_mac[0], sender_mac[1], sender_mac[2], - sender_mac[3] + sender_mac[3], + sender_mac[4], + sender_mac[5] ); memcpy(_remote_mac[pos], sender_mac, ESP_NOW_ETH_ALEN); } @@ -155,6 +165,11 @@ class ESPNOW { static uint8_t get_max_attempts() { return 10; }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { return EN_RECEIVE_TIME; }; + + /* Handle a collision (empty because handled on Ethernet level): */ void handle_collision() { }; @@ -203,10 +218,12 @@ class ESPNOW { void send_frame(uint8_t *data, uint16_t length) { if(length > 0) { uint8_t id = data[0]; // Package always starts with a receiver id + PJON_Packet_Info packet_info; // use parser to get intended recipient MAC + PJONTools::parse_header(data, packet_info); if(id == 0) { // Broadcast, send to all receivers en.send_frame(data, length); } else { // To a specific receiver - int16_t pos = find_remote_node(id); + int16_t pos = find_remote_node(id, packet_info.rx.mac); if(pos != -1) en.send_frame(data, length, _remote_mac[pos]); else //Broadcast - any replies will get registered diff --git a/src/strategies/ESPNOW/README.md b/src/strategies/ESPNOW/README.md index f4bf1ed6b3..361c12a15c 100644 --- a/src/strategies/ESPNOW/README.md +++ b/src/strategies/ESPNOW/README.md @@ -1,5 +1,8 @@ ## ESPNOW -**Medium:** 802.11 Peer-to-peer + +| Medium | Pins used | Constant | +|--------|-----------|--------------------| +| ESPNOW over WiFi | NA | `#include ` | With the `ESPNOW` PJON strategy, up to 10 ESP32 devices can use PJON to communicate with each other over the [Espressif ESPNOW protocol](https://www.espressif.com/en/products/software/esp-now/overview) (peer-to-peer 802.11). @@ -15,12 +18,12 @@ PJON over WiFi has the following benefit: ### How to use ESPNOW ESPNOW strategy can be used within the Arduino IDE or as an esp-idf component with [arduino-esp32](https://github.com/espressif/arduino-esp32). -Pass the `ESPNOW` type as PJON template parameter to instantiate a -PJON object ready to communicate through this Strategy. +Use `PJONESPNOW` to instantiate a PJON object ready to communicate using `ESPNOW` strategy: -```cpp - // Use ESPNOW strategy with PJON device id 44 - PJON bus(44); +```cpp + #include + + PJONESPNOW bus(44); // Use device id 44 ``` You can customise the channel (default is channel 1) and PMK (encryption) as follows (all devices must be the same): diff --git a/src/strategies/EthernetTCP/EthernetLink.h b/src/strategies/EthernetTCP/EthernetLink.h index 237a07b52d..6e4c9934b6 100644 --- a/src/strategies/EthernetTCP/EthernetLink.h +++ b/src/strategies/EthernetTCP/EthernetLink.h @@ -129,7 +129,9 @@ #include "../../interfaces/ARDUINO/TCPHelper_ARDUINO.h" #else #include "../../interfaces/LINUX/TCPHelper_POSIX.h" - const char *F(const char *s) { return s; } + #ifndef F + #define F(x) (x) + #endif #define Serial DummyPrint struct DummyPrint { static void print(const char *s) { printf("%s", s); } diff --git a/src/strategies/EthernetTCP/EthernetTCP.h b/src/strategies/EthernetTCP/EthernetTCP.h index 6984ef3c6b..e30bef86da 100644 --- a/src/strategies/EthernetTCP/EthernetTCP.h +++ b/src/strategies/EthernetTCP/EthernetTCP.h @@ -24,6 +24,11 @@ #include "EthernetLink.h" #include +// Recommended receive time for this strategy, in microseconds +#ifndef ETCP_RECEIVE_TIME + #define ETCP_RECEIVE_TIME 0 +#endif + class EthernetTCP { public: EthernetLink link; @@ -91,7 +96,7 @@ class EthernetTCP { bool can_start() { return link.device_id() != 0; }; - + /* Returns the maximum number of attempts for each transmission: */ @@ -100,6 +105,13 @@ class EthernetTCP { }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { + return ETCP_RECEIVE_TIME; + }; + + /* Handle a collision (empty because handled on Ethernet level): */ void handle_collision() { }; diff --git a/src/strategies/EthernetTCP/README.md b/src/strategies/EthernetTCP/README.md index ef8e9e4680..9432adda2c 100644 --- a/src/strategies/EthernetTCP/README.md +++ b/src/strategies/EthernetTCP/README.md @@ -1,6 +1,8 @@ ## EthernetTCP -**Medium:** Ethernet port, wired or WiFi +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Ethernet port, wired or WiFi | NA | `#include `| With the `EthernetTCP` PJON strategy, multiple devices with Ethernet ports can use PJON to communicate with each other on a LAN, WAN or across the Internet. Take a look at the [video introduction](https://www.youtube.com/watch?v=DQzcAv38yxM) for a brief showcase of its features. @@ -12,10 +14,11 @@ It can also be useful for connecting physically separate clusters of devices tha It also enables devices to be connected through the Internet if firewalls are configured to allow this. ### How to use EthernetTCP -Pass the `EthernetTCP` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. +Use `PJONEthernetTCP` to instantiate a PJON object ready to communicate using `EthernetTCP` strategy: ```cpp - // Use EthernetTCP strategy with PJON device id 44 - PJON bus(44); + #include + + PJONEthernetTCP bus(44); // Use device id 44 ``` Set up the Ethernet card in the usual manner by calling `Ethernet.begin`, then call setter functions for the link object in the EthernetTCP strategy, and then call the `begin` method on the PJON object: ```cpp diff --git a/src/strategies/GlobalUDP/GlobalUDP.h b/src/strategies/GlobalUDP/GlobalUDP.h index 4a849bef7d..ac390dc045 100644 --- a/src/strategies/GlobalUDP/GlobalUDP.h +++ b/src/strategies/GlobalUDP/GlobalUDP.h @@ -38,6 +38,11 @@ #define GUDP_MAX_REMOTE_NODES 10 #endif +// Recommended receive time for this strategy, in microseconds +#ifndef GUDP_RECEIVE_TIME + #define GUDP_RECEIVE_TIME 0 +#endif + #define GUDP_DEFAULT_PORT 7000 #define GUDP_MAGIC_HEADER (uint32_t) 0x0DFAC3FF @@ -75,7 +80,7 @@ class GlobalUDP { // First get PJON sender id from incoming packet PJON_Packet_Info packet_info; PJONTools::parse_header(message, packet_info); - uint8_t sender_id = packet_info.sender_id; + uint8_t sender_id = packet_info.tx.id; if (sender_id == 0) return; // If parsing fails, it will be 0 // Then get the IP address and port number of the sender @@ -143,13 +148,18 @@ class GlobalUDP { /* Check if the channel is free for transmission */ bool can_start() { return check_udp(); }; - + /* Returns the maximum number of attempts for each transmission: */ static uint8_t get_max_attempts() { return 10; }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { return GUDP_RECEIVE_TIME; }; + + /* Handle a collision (empty because handled on Ethernet level): */ void handle_collision() { }; diff --git a/src/strategies/GlobalUDP/README.md b/src/strategies/GlobalUDP/README.md index b5c1dc9daa..3947c9d993 100644 --- a/src/strategies/GlobalUDP/README.md +++ b/src/strategies/GlobalUDP/README.md @@ -1,6 +1,8 @@ ## GlobalUDP -**Medium:** Ethernet port, wired or WiFi +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Ethernet port, wired or WiFi | NA | `#include `| With the `GlobalUDP` PJON strategy, multiple devices with Ethernet ports can use PJON to communicate with each other over an Ethernet network, wired or over WiFi or both. This strategy demands a little more configuration than the `LocalUDP` strategy @@ -13,10 +15,11 @@ If a cabled or wireless Ethernet network exists, using this to let devices commu It can also be useful for connecting physically separate clusters of devices that are connected wired with the `SoftwareBitBang` strategy, or wirelessly with the `Oversampling` strategy, when a LAN or WAN is connecting the locations. ### How to use GlobalUDP -Pass the `GlobalUDP` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. +Use `PJONGlobalUDP` to instantiate a PJON object ready to communicate using `PJONGlobalUDP` strategy: ```cpp - // Use LocalUDP strategy with PJON device id 44 - PJON bus(44); + #include + + PJONGlobalUDP bus(44); // Use device id 44 ``` Set up the Ethernet card in the usual manner by calling `Ethernet.begin`, register the other devices to send to, then call the `begin` method on the PJON object: diff --git a/src/strategies/LocalFile/FileLockFunctions.h b/src/strategies/LocalFile/FileLockFunctions.h index ded81abf1b..c3791a9e43 100644 --- a/src/strategies/LocalFile/FileLockFunctions.h +++ b/src/strategies/LocalFile/FileLockFunctions.h @@ -233,5 +233,12 @@ int LockFileSection(const int iFileNo, // the fileno #undef W_OK #undef R_OK #undef X_OK +#undef access +#undef lseek +#undef locking +#undef open +#undef write +#undef read +#undef close #endif diff --git a/src/strategies/LocalFile/LocalFile.h b/src/strategies/LocalFile/LocalFile.h index 51c8661ba3..7a997e04ad 100644 --- a/src/strategies/LocalFile/LocalFile.h +++ b/src/strategies/LocalFile/LocalFile.h @@ -20,6 +20,11 @@ #define LF_POLLDELAY 10 #endif +// Recommended receive time for this strategy, in microseconds +#ifndef LF_RECEIVE_TIME + #define LF_RECEIVE_TIME 0 +#endif + #define PJON_LF_DEBUG class LocalFile { @@ -233,6 +238,10 @@ class LocalFile { return 10; }; + static uint16_t get_receive_time() { + return LF_RECEIVE_TIME; + }; + uint16_t receive_frame(uint8_t *data, uint16_t max_length) { Record record; if(readNextPacketFromFile(record)) { diff --git a/src/strategies/LocalFile/README.md b/src/strategies/LocalFile/README.md index b91db9b9c2..1c5e1efbf7 100644 --- a/src/strategies/LocalFile/README.md +++ b/src/strategies/LocalFile/README.md @@ -1,12 +1,14 @@ ## LocalFile -**Medium:** Hard disk +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| System memory | NA | `#include `| `LocalFile` uses a file present on the hard drive to let multiple processes communicate on the same machine. It can be used for inter-process communication and for developing, simulating and testing applications and networks on a real time operative system without having to deploy physical hardware. ### Configuration -Before including `PJON.h` it is possible to configure `LocalFile` using predefined constants: +Before including the library it is possible to configure `LocalFile` using predefined constants: | Constant | Purpose | Supported value | | ------------------ |--------------------------------------------- | ------------------------------------------ | @@ -14,10 +16,11 @@ Before including `PJON.h` it is possible to configure `LocalFile` using predefin | `LF_FILENAME` | Name and location of the file used as medium | Duration in microseconds (1500 by default) | | `LF_QUEUESIZE` | Size of the packets queue | > 0 (20 by default) | -Pass the `LocalFile` type as PJON template parameter to instantiate a PJON object ready to communicate through this strategy. +Use `PJONLocalFile` to instantiate a PJON object ready to communicate using `LocalFile` strategy: ```cpp - // Use LocalFile strategy with PJON device id 44 - PJON bus(44); + #include + + PJONLocalFile bus(44); // Use device id 44 ``` After testing or simulation you may want to use conditional compiling and exchange this strategy with the actual one on your target hardware. diff --git a/src/strategies/LocalUDP/LocalUDP.h b/src/strategies/LocalUDP/LocalUDP.h index 0e6a37f85d..807f60f956 100644 --- a/src/strategies/LocalUDP/LocalUDP.h +++ b/src/strategies/LocalUDP/LocalUDP.h @@ -34,6 +34,11 @@ #endif #define LUDP_MAGIC_HEADER (uint32_t) 0x0DFAC3D0 +// Recommended receive time for this strategy, in microseconds +#ifndef LUDP_RECEIVE_TIME + #define LUDP_RECEIVE_TIME 0 +#endif + class LocalUDP { bool _udp_initialized = false; uint16_t _port = LUDP_DEFAULT_PORT; @@ -78,6 +83,11 @@ class LocalUDP { static uint8_t get_max_attempts() { return 10; }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { return LUDP_RECEIVE_TIME; }; + + /* Handle a collision (empty because handled on Ethernet level): */ void handle_collision() { }; diff --git a/src/strategies/LocalUDP/README.md b/src/strategies/LocalUDP/README.md index b5b9f4e280..05dc32c422 100644 --- a/src/strategies/LocalUDP/README.md +++ b/src/strategies/LocalUDP/README.md @@ -1,6 +1,8 @@ ## LocalUDP -**Medium:** Ethernet port, wired or WiFi +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Ethernet port, wired or WiFi | NA | `#include `| With the `LocalUDP` PJON strategy, multiple devices with Ethernet ports can use PJON to communicate with each other on a local subnet, wired or over WiFi or both. Take a look at the [video introduction](https://www.youtube.com/watch?v=cxEUqkK5BQg) for a brief showcase of its features. @@ -10,10 +12,11 @@ If a cabled or wireless Ethernet network exists, using this to let devices commu It can also be useful for connecting physically separate clusters of devices that are connected wired with the SoftwareBitBang strategy, or wirelessly with the Oversampling strategy, when a LAN is connecting the locations. ### How to use LocalUDP -Pass the `LocalUDP` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. +Use `PJONLocalUDP` to instantiate a PJON object ready to communicate using `LocalUDP` strategy: ```cpp - // Use LocalUDP strategy with PJON device id 44 - PJON bus(44); + #include + + PJONLocalUDP bus(44); // Device id 44 ``` Set up the Ethernet card in the usual manner by calling `Ethernet.begin`, then call the `begin` method on the PJON object: ```cpp diff --git a/src/strategies/MQTTTranslate/MQTTTranslate.h b/src/strategies/MQTTTranslate/MQTTTranslate.h index c213681922..58f2516f1e 100644 --- a/src/strategies/MQTTTranslate/MQTTTranslate.h +++ b/src/strategies/MQTTTranslate/MQTTTranslate.h @@ -56,7 +56,7 @@ pjon/AE7804FEA7D0/output. This can be useful to avoid setting a device id and instead just use the MAC address as a unique subject identifier. - Compliant with the PJON protocol layer specification v3.2 + Compliant with the PJON protocol layer specification v4.0 _____________________________________________________________________________ MQTTTranslate strategy proposed and developed by Fred Larsen 07/12/2019 @@ -113,6 +113,11 @@ #define MQTTT_TRANSLATION_TABLE_SIZE 5 #endif +// Recommended receive time for this strategy, in microseconds +#ifndef MQTTT_RECEIVE_TIME + #define MQTTT_RECEIVE_TIME 0 +#endif + #if defined(MQTTT_USE_MAC) && ((MQTTT_MODE == MQTTT_MODE_MIRROR_TRANSLATE) || (MQTTT_MODE == MQTTT_MODE_MIRROR_DIRECT)) #define MQTTT_MAC #endif @@ -121,7 +126,7 @@ class MQTTTranslate { bool last_send_success = false; uint16_t incoming_packet_size = 0; -// TODO: Eliminate extra buffer -- is the on in the MqttClient not enough? +// TODO: Eliminate extra buffer -- is the one in the MqttClient not enough? uint8_t packet_buffer[MQTTT_BUFFER_SIZE]; PJON_Packet_Info _packet_info; // Used for parsing incoming and outgoing packets @@ -155,6 +160,17 @@ class MQTTTranslate { } #endif + static PJON_Packet_Info fill_info(uint8_t sender_id, const uint8_t sender_bus_id[4], + uint8_t receiver_id, const uint8_t receiver_bus_id[4], uint8_t header) { + PJON_Packet_Info info; + info.tx.id = sender_id; + PJONTools::copy_id(info.tx.bus_id, sender_bus_id, 4); + info.rx.id = receiver_id; + PJONTools::copy_id(info.rx.bus_id, receiver_bus_id, 4); + info.header = header; + return info; + } + static void static_receiver(const char *topic, const uint8_t *payload, uint16_t len, void *callback_object) { if (callback_object) ((MQTTTranslate*)callback_object)->receiver(topic, payload, len); } @@ -207,8 +223,8 @@ class MQTTTranslate { // Package the data message into a PJON packet uint8_t h = header; if (sender_id != 0) header |= PJON_TX_INFO_BIT; - incoming_packet_size = PJONTools::compose_packet(sender_id, bus_id, receiver_id, - bus_id, packet_buffer, payload, len, h); + PJON_Packet_Info info = fill_info(sender_id, bus_id, receiver_id, bus_id, h); + incoming_packet_size = PJONTools::compose_packet(info, packet_buffer, payload, len); #endif #if (MQTTT_MODE == MQTTT_MODE_MIRROR_TRANSLATE || MQTTT_MODE == MQTTT_MODE_MIRROR_DIRECT) uint8_t receiver_id = my_id; @@ -241,16 +257,16 @@ class MQTTTranslate { value[l] = 0; // Null terminate String s = key; s += "="; s += value; // Package the key=value into a PJON packet - incoming_packet_size = PJONTools::compose_packet(receiver_id, bus_id, receiver_id, - bus_id, packet_buffer, s.c_str(), s.length()+1, header); + PJON_Packet_Info info = fill_info(receiver_id, bus_id, receiver_id, bus_id, header); + incoming_packet_size = PJONTools::compose_packet(info, packet_buffer, s.c_str(), s.length()+1); } } return; #endif #if (MQTTT_MODE == MQTTT_MODE_MIRROR_DIRECT) // Package the payload as it is, into a PJON packet - incoming_packet_size = PJONTools::compose_packet(receiver_id, bus_id, receiver_id, - bus_id, packet_buffer, payload, len, header); + PJON_Packet_Info info = fill_info(receiver_id, bus_id, receiver_id, bus_id, header); + incoming_packet_size = PJONTools::compose_packet(info, packet_buffer, payload, len); #endif } @@ -343,6 +359,11 @@ class MQTTTranslate { static uint8_t get_max_attempts() { return 0; }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { return MQTTT_RECEIVE_TIME; }; + + /* Handle a collision (empty because handled on Ethernet level): */ void handle_collision() { }; @@ -395,18 +416,18 @@ class MQTTTranslate { if (p-mqttclient.topic_buf()+7+3+7 >= SMCTOPICSIZE) return; strcpy(p, "/device"); p += 7; #if (MQTTT_MODE == MQTTT_MODE_MIRROR_TRANSLATE || MQTTT_MODE == MQTTT_MODE_MIRROR_DIRECT) - p += mqttclient.uint8toa(_packet_info.sender_id, p); + p += mqttclient.uint8toa(_packet_info.tx.id, p); strcat(p, "/output"); // Like pjon/device44/output p = &p[strlen(p)]; // End of /output #else // One of the bus modes, publish to receiver device - mqttclient.uint8toa(_packet_info.receiver_id, p); + mqttclient.uint8toa(_packet_info.rx.id, p); #endif #endif #if (MQTTT_MODE != MQTTT_MODE_BUS_RAW) uint8_t overhead = PJONTools::packet_overhead(_packet_info.header); - uint8_t crc_size = PJONTools::crc_overhead(_packet_info.header); + uint8_t crc_size = PJONTools::crc_overhead(_packet_info.header); #endif - + // Re-compose packet in other modes than RAW #if (MQTTT_MODE == MQTTT_MODE_MIRROR_TRANSLATE) // Split into multiple topics (must assume a specific payload format to parse): @@ -444,14 +465,14 @@ class MQTTTranslate { #if (MQTTT_MODE == MQTTT_MODE_BUS_JSON) // Must assume that payload is text, unless UUencoding/base64encoding // {"to": to_id, "from": from id, "data": "payload"} + uint8_t payload_len = length - overhead; p = (char *) packet_buffer; if (6+3+8+3+9+payload_len+2 >= MQTTT_BUFFER_SIZE) return; strcpy(p, "{\"to\":"); p += 6; - p += mqttclient.uint8toa(_packet_info.receiver_id, p); + p += mqttclient.uint8toa(_packet_info.rx.id, p); strcpy(p, ",\"from\":"); p+= 8; - p += mqttclient.uint8toa(_packet_info.sender_id, p); + p += mqttclient.uint8toa(_packet_info.tx.id, p); strcpy(p, ",\"data\":\""); p+= 9; - uint8_t payload_len = length - overhead; strncpy(p, (const char*)&data[overhead - crc_size], payload_len); p[payload_len] = 0; p += strlen(p); strcpy(p, "\"}"); p += 2; diff --git a/src/strategies/MQTTTranslate/README.md b/src/strategies/MQTTTranslate/README.md index e8c754c499..85b0398630 100644 --- a/src/strategies/MQTTTranslate/README.md +++ b/src/strategies/MQTTTranslate/README.md @@ -1,6 +1,8 @@ ## MQTTTranslate -**Medium:** MQTT protocol +| Medium | Pins used | Inclusion Constant | +|--------|-----------|--------------------| +| MQTT protocol | NA | `#include `| MQTTTranslate uses the [ReconnectingMqttClient](https://github.com/fredilarsen/ReconnectingMqttClient) library (minimum version required v1.1.1) to deliver PJON packets over TCP on local network (LAN) as a MQTT protocol client. It may be useful to connect PJON networks and more standard applications to each other using the MQTT protocol. This strategy works in one of four modes. The first two modes enable to implement a PJON bus via MQTT, the first mode is "closed" and the second is "open" to use by non-PJON programs. The last two modes are for behaving like MQTT devices normally do. @@ -8,7 +10,7 @@ MQTTTranslate uses the [ReconnectingMqttClient](https://github.com/fredilarsen/R 2. `MQTTT_MODE_BUS_JSON` mode sends JSON packets with to, from and data, delivered to a topic like `pjon/device45` (where `45` is a receiver device id). Each device subscribes to a topic with its own name and receives packets like `{to:45,from:44,data:"message text sent from device 44 to device 45"}`. -3. `MQTTT_MODE_MIRROR_TRANSLATE` mode does not not use JSON encapsulation of values, and publishes to its own topic, not the receiver's. It publishes to an "output" folder and subscribes to an "input" folder. An outgoing packet with payload `P=44.1,T=22.0` results in the topics `pjon/device44/output/temperature`, with a value `44.1` and `pjon/device44/output/pressure`, with a value `22.0`. Likewise, when receiving an update of `pjon/device44/input/setpoint`, with a value `45` results in a packet with payload `S=45`. This mode supports a translation table to allow short names to be used in packets while topic names are longer. For example `T` translated in `temperature`. If no translation table is populated, the same names will be used in the packets and the topics. The directory [examples/ESP8266/Local/MQTTTranslate/EnvironmentController](../../../examples/ESP8266/Local/MQTTTranslate/EnvironmentController) contains the ESP8266 example, to build it, just use the Arduino IDE. +3. `MQTTT_MODE_MIRROR_TRANSLATE` mode does not not use JSON encapsulation of values, and publishes to its own topic, not the receiver's. It publishes to an "output" folder and subscribes to an "input" folder. An outgoing packet with payload `P=44.1,T=22.0` results in the topics `pjon/device44/output/temperature`, with a value `22.0` and `pjon/device44/output/pressure`, with a value `44.1`. Likewise, when receiving an update of `pjon/device44/input/setpoint`, with a value `45` results in a packet with payload `S=45`. This mode supports a translation table to allow short names to be used in packets while topic names are longer. For example `T` translated in `temperature`. If no translation table is populated, the same names will be used in the packets and the topics. The directory [examples/ESP8266/Local/MQTTTranslate/EnvironmentController](../../../examples/ESP8266/Local/MQTTTranslate/EnvironmentController) contains the ESP8266 example, to build it, just use the Arduino IDE. 4. `MQTTT_MODE_MIRROR_DIRECT` mode works like `MQTTT_MODE_MIRROR_TRANSLATE`, but just passes the payload on without any translation, leaving the formatting to the user. It does not split packets into separate topics but transfers the packets as-is to one output topic and from one input topic `pjon/device44/output`, `pjon/device44/input`. The user sketch will have control of the format used, which can be plain text like `P=44.1,T=22.0` or a JSON text. The directory [examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway](../../../examples/ARDUINO/Local/MQTTTranslate/SWBB-MQTT-Gateway) contains the Arduino SWBB-MQTT-Gateway example, that showcases bidirectional, transparent data transmission between an MQTT client and a [SoftwareBitBang](../SoftwareBitBang/README.md) bus. To build it, just use the Arduino IDE. @@ -24,19 +26,18 @@ Note that this functionality does not cover Windows/Linux/OsX in this release. ### Configuration -Before including `PJON.h` it is possible to configure `MQTTTranslate` using predefined constants: +Before including the library it is possible to configure `MQTTTranslate` using predefined constants: | Constant | Purpose | Supported value | | ------------------ |--------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | `MQTTT_MODE` | Select mode | `MQTTT_MODE_BUS_RAW`, `MQTTT_MODE_BUS_JSON`, `MQTTT_MODE_MIRROR_TRANSLATE`, `MQTTT_MODE_MIRROR_DIRECT` | -Define the `PJON_INCLUDE_MQTT` constant before including the library and pass the `MQTTTranslate` type as PJON template parameter to instantiate an object ready to communicate using this strategy: +Use `PJONMQTTTranslate` to instantiate an object ready to communicate using `MQTTTranslate` strategy: ```cpp - #define PJON_INCLUDE_MQTT // Include MQTTTranslate strategy - #include // Include the PJON library + #include // Include the PJON library // Use MQTTTranslate strategy with PJON device id 44 - PJON bus(44); + PJONMQTTTranslate bus(44); uint8_t broker_ip[] = { 127, 0, 0, 1 }; void setup() { diff --git a/src/strategies/OverSampling/OverSampling.h b/src/strategies/OverSampling/OverSampling.h index 986039727e..0b67a8fc22 100644 --- a/src/strategies/OverSampling/OverSampling.h +++ b/src/strategies/OverSampling/OverSampling.h @@ -40,6 +40,11 @@ #define OS_MODE 1 #endif +// Recommended receive time for this strategy, in microseconds +#ifndef OS_RECEIVE_TIME + #define OS_RECEIVE_TIME 1000 +#endif + // Used to signal communication failure #define OS_FAIL 65535 @@ -87,7 +92,6 @@ class OverSampling { return true; }; - /* Returns the maximum number of attempts for each transmission: */ static uint8_t get_max_attempts() { @@ -95,6 +99,13 @@ class OverSampling { }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { + return OS_RECEIVE_TIME; + }; + + /* Handle a collision: */ void handle_collision() { diff --git a/src/strategies/OverSampling/README.md b/src/strategies/OverSampling/README.md index 37fc5dece7..d18e508c04 100644 --- a/src/strategies/OverSampling/README.md +++ b/src/strategies/OverSampling/README.md @@ -1,7 +1,7 @@ ## OverSampling - -**Media:** Radio, Wire | -**Pins used:** 1 / 2 +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| ASK/FSK radio modules | 1 or 2 | `#include `| `OverSampling` is a software implementation of [PJDLR (Padded Jittering Data Link over Radio)](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md). It supports simplex and half-duplex asynchronous serial communication and implements a carrier-sense, non-persistent random multiple access method (non-persistent CSMA). This implementation can run on limited microcontrollers with low clock accuracy, supports communication for many devices connected to the same medium and stable operation in spite of interference. Its procedure is a more efficient alternative to the LoRa Open Standard (that specifies a variation of Slotted ALOHA) and it is designed to obtain long range and high reliability using FSK, ASK or OOK modulation radio transceivers. Take a look at the [video introduction](https://www.youtube.com/watch?v=G1ckfsMzPns) for a brief showcase of its features. @@ -19,7 +19,7 @@ - Range: 250 meters with no line of sight, 5 km with line of sight and ideal atmospheric conditions ### Configuration -Before including `PJON.h` it is possible to configure `OverSampling` using predefined constants: +Before including the library it is possible to configure `OverSampling` using predefined constants: | Constant | Purpose | Supported value | | ------------------------- |------------------------------------ | ------------------------------------------- | @@ -27,12 +27,12 @@ Before including `PJON.h` it is possible to configure `OverSampling` using prede | `OS_BACK_OFF_DEGREE` | Maximum back-off exponential degree | Numeric value (5 by default) | | `OS_MAX_ATTEMPTS` | Maximum transmission attempts | Numeric value (10 by default) | -Pass the `OverSampling` type as PJON template parameter to instantiate a new PJON object. All the other necessary information is present in the general [Documentation](/documentation). +Use `PJONOverSampling` to instantiate a new PJON object ready to communicate using the `OverSampling` strategy. All the other necessary information is present in the general [Documentation](/documentation). ```cpp -#include +#include -PJON bus; +PJONOverSampling bus; void setup() { // Set the pin 12 as the communication pin diff --git a/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md b/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md index 829740d670..aac3f079a7 100644 --- a/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md +++ b/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md @@ -2,14 +2,13 @@ ### Specifications index #### Network layer -- [PJON (Padded Jittering Operative Network) v3.2](/specification/PJON-protocol-specification-v3.2.md) -- [Acknowledge specification v1.0](/specification/PJON-protocol-acknowledge-specification-v1.0.md) +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) - [Network services list](/specification/PJON-network-services-list.md) #### Data link layer -- [PJDL (Padded Jittering Data Link) v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) +- [PJDL (Padded Jittering Data Link) v5.0](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) - **[PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md)** - [PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) -- [TSDL (Tardy Serial Data Link) v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md) +- [TSDL (Tardy Serial Data Link) v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) - [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) --- diff --git a/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.0.md b/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.0.md index 2e38d81dee..6cacb5cd04 100644 --- a/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.0.md +++ b/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.0.md @@ -3,7 +3,7 @@ /* Milan, Italy - 18/01/2017 PJDLR (Padded jittering data link) specification is an invention and intellectual property -of Giovanni Blu Mitolo - Copyright 2010-2020 All rights reserved +of Giovanni Blu Mitolo - Copyright 2010-2025 All rights reserved Related work: /src/strategies/SoftwareBitBang/ Compliant implementation versions: PJON 7.0-7.1 diff --git a/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.1.md b/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.1.md index 77e2b7f69e..2a5dee8b05 100644 --- a/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.1.md +++ b/src/strategies/OverSampling/specification/obsolete/PJDLR-specification-v1.1.md @@ -4,7 +4,7 @@ Milan, Italy - 31/03/2017 PJDLR (Padded jittering data link) specification is an invention and intellectual property of Giovanni Blu Mitolo -Copyright 2010-2020 All rights reserved +Copyright 2010-2025 All rights reserved Related work: /src/strategies/SoftwareBitBang/ Compliant implementation versions: PJON 8.0 and following diff --git a/src/strategies/PJON_Strategies.h b/src/strategies/PJON_Strategies.h deleted file mode 100644 index 1050a2f7f5..0000000000 --- a/src/strategies/PJON_Strategies.h +++ /dev/null @@ -1,91 +0,0 @@ - -/* PJON dynamic Strategy inclusion - ___________________________________________________________________________ - - Copyright 2018 Giovanni Blu Mitolo gioscarab@gmail.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. */ - -#pragma once - -/* Strategy related constant predefinition memory optimization */ - -#if defined(PJON_INCLUDE_ANY) - #include "Any/Any.h" -#endif -#if defined(PJON_INCLUDE_AS) - #include "AnalogSampling/AnalogSampling.h" -#endif -#if defined(PJON_INCLUDE_ETCP) - #include "EthernetTCP/EthernetTCP.h" -#endif -#if defined(PJON_INCLUDE_LUDP) - #include "LocalUDP/LocalUDP.h" -#endif -#if defined(PJON_INCLUDE_GUDP) - #include "GlobalUDP/GlobalUDP.h" -#endif -#if defined(PJON_INCLUDE_DUDP) - #include "DualUDP/DualUDP.h" -#endif -#if defined(PJON_INCLUDE_MQTT) - #include "EthernetTCP/EthernetTCP.h" - #include "MQTTTranslate/MQTTTranslate.h" -#endif -#if defined(PJON_INCLUDE_OS) - #include "OverSampling/OverSampling.h" -#endif -#if defined(PJON_INCLUDE_SWBB) - #include "SoftwareBitBang/SoftwareBitBang.h" -#endif -#if defined(PJON_INCLUDE_TS) - #include "ThroughSerial/ThroughSerial.h" -#endif -#if defined(PJON_INCLUDE_TSA) - #include "ThroughSerialAsync/ThroughSerialAsync.h" -#endif -#if defined(PJON_INCLUDE_TL) - #include "ThroughLoRa/ThroughLora.h" -#endif -#if defined(PJON_INCLUDE_EN) - #include "ESPNOW/ESPNOW.h" -#endif -#if defined(PJON_INCLUDE_LF) - #include "LocalFile/LocalFile.h" -#endif -#if defined(PJON_INCLUDE_NONE) - /* None for custom strategy inclusion */ -#endif - -#if !defined(PJON_INCLUDE_AS) && !defined(PJON_INCLUDE_ETCP) && \ - !defined(PJON_INCLUDE_GUDP) && !defined(PJON_INCLUDE_LUDP) && \ - !defined(PJON_INCLUDE_OS) && !defined(PJON_INCLUDE_SWBB) && \ - !defined(PJON_INCLUDE_TS) && !defined(PJON_INCLUDE_NONE) && \ - !defined(PJON_INCLUDE_TSA) && !defined(PJON_INCLUDE_DUDP) && \ - !defined(PJON_INCLUDE_LF) && !defined(PJON_INCLUDE_SM) && \ - !defined(PJON_INCLUDE_MQTT) - #include "Any/Any.h" - #include "AnalogSampling/AnalogSampling.h" - #include "OverSampling/OverSampling.h" - #include "SoftwareBitBang/SoftwareBitBang.h" - #include "ThroughSerial/ThroughSerial.h" - #include "ThroughSerialAsync/ThroughSerialAsync.h" - /* Avoid ATtiny44/84/45/85 and STM32F1 missing inclusion error */ - #if !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && \ - !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(ARDUINO_ARCH_STM32) - #include "EthernetTCP/EthernetTCP.h" - #include "LocalUDP/LocalUDP.h" - #include "GlobalUDP/GlobalUDP.h" - #include "DualUDP/DualUDP.h" - #endif -#endif diff --git a/src/strategies/README.md b/src/strategies/README.md index 4fbe38071a..2a00f035f9 100644 --- a/src/strategies/README.md +++ b/src/strategies/README.md @@ -1,24 +1,26 @@ -### What is a Strategy? +### What is a Strategy A strategy is an abstraction layer used to physically transmit data. Thanks to the strategies PJON can operate transparently on a wide range of media and protocols. Take a look at the [strategies video introduction](https://www.youtube.com/watch?v=yPu45xoAHGg) for a brief showcase of their features. -| Strategy | Physical layer | Protocol | Pins needed | -| ------------- | -------------- | -------- | ------------- | -| [SoftwareBitBang](SoftwareBitBang) | Electrical impulses over wire | [PJDL](SoftwareBitBang/specification/PJDL-specification-v4.1.md) | 1 or 2 | -| [OverSampling](OverSampling) | Electrical/radio impulses over wire/air | [PJDLR](OverSampling/specification/PJDLR-specification-v3.0.md) | 1 or 2 | -| [AnalogSampling](AnalogSampling) | Light pulses over air or optic fiber | [PJDLS](AnalogSampling/specification/PJDLS-specification-v2.0.md) | 1 or 2 | -| [ThroughSerial](ThroughSerial) | Electrical/radio impulses over wire/air | [TSDL](ThroughSerial/specification/TSDL-specification-v2.1.md) | 1 or 2 | -| [ThroughSerialAsync](ThroughSerialAsync) | Electrical/radio impulses over wire/air | [TSDL](ThroughSerial/specification/TSDL-specification-v2.1.md) | 1 or 2 | -| [ThroughLoRa](ThroughLoRa) | Radio impulses over air | [LoRa](https://lora-alliance.org/sites/default/files/2018-07/lorawan1.0.3.pdf) | 3 or 4 | -| [EthernetTCP](EthernetTCP) | Electrical/radio impulses over wire/air | [TCP](https://tools.ietf.org/html/rfc793) | Ethernet of WiFi | -| [LocalUDP](LocalUDP) | Electrical/radio impulses over wire/air | [UDP](https://tools.ietf.org/html/rfc768) | Ethernet of WiFi | -| [GlobalUDP](GlobalUDP) | Electrical/radio impulses over wire/air | [UDP](https://tools.ietf.org/html/rfc768) | Ethernet of WiFi | -| [DualUDP](DualUDP) | Electrical/radio impulses over wire/air | [UDP](https://tools.ietf.org/html/rfc768) | Ethernet of WiFi | -| [MQTTTranslate](MQTTTranslate) | Electrical/radio impulses over wire/air | [MQTT](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf) | Ethernet of WiFi | -| [ESPNOW](ESPNOW) | Radio impulses over air | [ESPNOW](https://www.espressif.com/en/products/software/esp-now/overview) | WiFi link | -| [LocalFile](LocalFile) | Shared file system in memory | None | None | -| [Any](Any) | Virtual inheritance, any of the above | Any of the above | Any of the above | - +The table below lists the strategies available: + +| Strategy | Physical layer | Protocol | Inclusion | +| ------------- | -------------- | -------- | --------- | +| [AnalogSampling](/src/strategies/AnalogSampling) | Light | [PJDLS](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) | `#include ` | +| [Any](/src/strategies/Any) | Virtual inheritance | Any | `#include ` | +| [DualUDP](/src/strategies/DualUDP) | Ethernet/WiFi | [UDP](https://tools.ietf.org/html/rfc768) | `#include ` | +| [ESPNOW](/src/strategies/ESPNOW) | WiFi | [ESPNOW](https://www.espressif.com/en/products/software/esp-now/overview) | `#include ` | +| [EthernetTCP](/src/strategies/EthernetTCP) | Ethernet/WiFi | [TCP](https://tools.ietf.org/html/rfc793) | `#include ` | +| [GlobalUDP](/src/strategies/GlobalUDP) | Ethernet/WiFi | [UDP](https://tools.ietf.org/html/rfc768) | `#include ` | +| [LocalFile](/src/strategies/LocalFile) | File system | None | `#include ` | +| [LocalUDP](/src/strategies/LocalUDP) | Ethernet/WiFi | [UDP](https://tools.ietf.org/html/rfc768) | `#include ` | +| [MQTTTranslate](/src/strategies/MQTTTranslate) | Ethernet/WiFi | [MQTT](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf) | `#include ` | +| [OverSampling](/src/strategies/OverSampling) | Radio | [PJDLR](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) | `#include ` | +| [SoftwareBitBang](/src/strategies/SoftwareBitBang) | Wire | [PJDL](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) | `#include ` | +| [ThroughLoRa](/src/strategies/ThroughLoRa) | Radio | [LoRa](https://lora-alliance.org/sites/default/files/2018-07/lorawan1.0.3.pdf) | `#include ` | +| [ThroughSerial](/src/strategies/ThroughSerial) | Wire | [TSDL](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) | `#include ` | + +### How the strategy is implemented A `Strategy` is a class containing a set of methods used to physically send and receive data along with the required getters to handle retransmission and collision: ```cpp @@ -45,7 +47,10 @@ Handles a collision. uint8_t get_max_attempts() ``` Returns the maximum number of attempts in case of failed transmission. - +```cpp +uint16_t get_receive_time() +``` +Returns the minimum polling time required to successfully receive a frame. ```cpp void send_frame(uint8_t *data, uint16_t length) ``` @@ -74,9 +79,9 @@ void send_response(uint8_t response) { ``` Above it is demonstrated how simply other communication protocols can be used to define a new custom strategy. -### How to define a new strategy -To define the strategy it is required to create a new folder named for example `YourStrategyName` in the `strategies` -directory and write the necessary file `YourStrategyName.h`: +### How to implement a custom strategy +To define a new custom strategy you need to create a new folder named for example `YourStrategyName` in the `src/strategies` +directory and create the necessary file `YourStrategyName.h`: ```cpp class YourStrategyName { @@ -85,6 +90,7 @@ class YourStrategyName { bool begin(uint8_t did) { }; bool can_start() { }; uint8_t get_max_attempts() { }; + uint16_t get_receive_time() { }; uint16_t receive_frame(uint8_t *data, uint16_t max_length) { }; uint16_t receive_response() { }; void send_response(uint8_t response) { }; @@ -92,7 +98,6 @@ class YourStrategyName { }; ``` -The last thing to do is to add the inclusion of the new strategy in `PJON_Strategies.h`. If all is correct it should be possible to instantiate PJON using the new strategy: ```cpp diff --git a/src/strategies/SoftwareBitBang/README.md b/src/strategies/SoftwareBitBang/README.md index 1c113ec89d..c675bfaba9 100644 --- a/src/strategies/SoftwareBitBang/README.md +++ b/src/strategies/SoftwareBitBang/README.md @@ -1,9 +1,10 @@ ## SoftwareBitBang -**Medium:** Wire | -**Pins used:** 1 / 2 +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Wire | 1 or 2 | `#include `| -`SoftwareBitBang` is a software implementation of [PJDL (Padded Jittering Data Link)](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md). It supports simplex and half-duplex asynchronous serial communication for up to 254 devices over a single wire. The maximum length of the bus can reach between 800 and 2000 meters depending on the mode used. It is a valid alternative to 1-Wire because of its flexibility and reliability. Fault tolerance schemes can be easily implemented because communication pins can be configured at runtime. Take a look at the [video introduction](https://www.youtube.com/watch?v=GWlhKD5lz5w) for a brief showcase of its features. +`SoftwareBitBang` is a software implementation of [PJDL (Padded Jittering Data Link)](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md). It supports simplex and half-duplex asynchronous serial communication for up to 254 devices over a single wire. The maximum length of the bus can reach between 800 and 2000 meters depending on the mode used. It is a valid alternative to 1-Wire because of its flexibility and reliability. Fault tolerance schemes can be easily implemented because communication pins can be configured at runtime. Take a look at the [video introduction](https://www.youtube.com/watch?v=GWlhKD5lz5w) for a brief showcase of its features. ```cpp PJDL SINGLE WIRE BUS ______ ______ ______ ______ ______ | | @@ -22,16 +23,16 @@ It is suggested to add 8kΩ-5MΩ pull-down resistor as shown in the graph above | MCU | Clock | Supported pins | | ---------------- |------ | ---------------- | | ATtiny84/84A | 16MHz | 0, 1, 2, 3, 4 | -| ATtiny85 (Digispark development board) | 16MHz | 1, 2 | -| ATmega88/168/328 (Duemilanove, Uno, Nano, Pro) | 16MHz | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1 | +| ATtiny85 | 16MHz | 1, 2 | +| ATmega88/168/328 (Uno, Nano, Pro) | 16MHz | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1 | | ATmega328PB | 16MHz | 10 | | ATmega16u4/32u4 (Leonardo, Micro) | 16MHz | 2, 4, 8, 12 | | ATmega2560 (Mega, Mega nano) | 16MHz | 3, 4, 7, 8, 9, 10, 12 | | ATmega1284P | 16MHz | 18, 19, 20, 21, 22, 23, A0, A1, A2, A3, A4, A5, A6, A7 | | SAMD (Arduino Zero) | 48MHz | D0, D1, D3, A0, A1 | -| STM32F1 | 72MHz | ? | +| STM32F1 | 72MHz | PB15, PB14, PB13, PB12, PB11, PB10, PB9, PB8, PB7, PB6, PB4, PB3, PA15, PA10 | | MK20DX256 (Teensy 3.1) | 96MHz | All pins | -| ESP8266 (NodeMCU, AI-THINKER modules) | 80/160MHz | D1 or GPIO 5 | +| ESP8266 (NodeMCU, AI-THINKER) | 80/160MHz | D1 or GPIO 5 | | ESP32 (Heltech WiFi LoRa) | 160MHz | 12, 25 | ### Performance @@ -39,10 +40,10 @@ It is suggested to add 8kΩ-5MΩ pull-down resistor as shown in the graph above | Mode | Speed | Range | Supported MCUs | | ---- | ----- |------ | ---------------- | -| `1` | 1.95kB/s 15625Bd | 2000m | ATtiny84/84A, ATtiny85, ATmega88/168/328, ATmega328PB, ATmega16u4/32u4, ATmega2560, ATmega1284P, SAMD, STM32F1, MK20DX256, ESP8266, ESP32 | -| `2` | 2.21kB/s 17696Bd | 1600m | ATtiny84/84A, ATtiny85, ATmega88/168/328, ATmega328PB, ATmega16u4/32u4, ATmega2560 | -| `3` | 2.94kB/s 23529Bd | 1200m | ATtiny84/84A, ATtiny85, ATmega88/168/328 | -| `4` | 3.40kB/s 27210Bd | 800m | ATtiny84/84A, ATtiny85, ATmega88/168/328 | +| `1` | 1.97kB/s | 2000m | ATtiny84/84A/85, ATmega88/168/328/328PB/16u4/32u4/2560/1284P, SAMD, STM32F1, MK20DX256, ESP8266, ESP32 | +| `2` | 2.21kB/s | 1600m | ATtiny84/84A/85, ATmega88/168/328/328PB/16u4/32u4/2560, STM32F1 | +| `3` | 3.10kB/s | 1200m | ATtiny84/84A/85, ATmega88/168/328, STM32F1 | +| `4` | 3.34kB/s | 800m | ATtiny84/84A/85, ATmega88/168/328, STM32F1 | When including and using the `SoftwareBitBang` strategy you have the complete access to the microcontroller. This happens because `SoftwareBitBang` runs a completely software-defined implementation, transforming a painful walk in a nice flight. @@ -50,24 +51,32 @@ Communication over a single wire enables quick and creative experimentation. The ![PJDL communication over 2000m twisted pair](images/PJDL-2000m-mode4-twistedpair-8.2k-pulldown-60-series.png) -The picture above shows a [PJDL](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) frame transmitted over a 800m twisted pair using mode `4` (test done by [Jack Anderson](https://github.com/jdaandersj)). Although bits are substantially deformed the exchange occurs nominally and performance is not affected. +The picture above shows a [PJDL](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) frame transmitted over a 800m twisted pair using mode `4`. Although bits are substantially deformed the exchange occurs nominally and performance is not affected. This experiment was done and published by [Jack Anderson](https://github.com/jdaandersj) in [LANC Video Camera Control](http://jda.tel/pdf/lanc_video_camera_control.pdf) - Department of Computer Science [Loughborough University](https://www.lboro.ac.uk/departments/compsci/) (UK). + +### PJDL vs. 1-Wire + +| Protocol | Communication speed | Range | Communication mode | Bus Control | +| -------- | ------------------- | --------- | ---------------------- | -------------------------- | +| PJDL | 1.97-3.34kB/s | 800-2000m | Simplex or half-duplex | Multi-controller | +| 1-Wire | 2.03kB/s | 300m | Half-duplex | Controller-peripheral only | ### Configuration -Before including `PJON.h` it is possible to configure `SoftwareBitBang` using predefined constants: +Before including the library it is possible to configure `SoftwareBitBang` using predefined constants: -| Constant | Purpose | Supported value | -| ----------------------- |------------------------------------ | ------------------------------------------ | -| `SWBB_MODE` | Data transmission mode | 1, 2, 3, 4 | -| `SWBB_RESPONSE_TIMEOUT` | Maximum response time-out | Duration in microseconds (1500 by default) | -| `SWBB_BACK_OFF_DEGREE` | Maximum back-off exponential degree | Numeric value (4 by default) | -| `SWBB_MAX_ATTEMPTS` | Maximum transmission attempts | Numeric value (20 by default) | +| Constant | Purpose | Supported value | +| ----------------------- |------------------------------------- | ------------------------------------------ | +| `SWBB_MODE` | Data transmission mode | 1, 2, 3, 4 | +| `SWBB_BACK_OFF_DEGREE` | Maximum back-off exponential degree | Numeric value (4 by default) | +| `SWBB_MAX_ATTEMPTS` | Maximum transmission attempts | Numeric value (20 by default) | +| `SWBB_PREAMBLE` | Preamble Length | Numeric value (1 by default), max 100 | +| `SWBB_MAX_PREAMBLE` | Maximum preamble length | Numeric value (1 by default), max 100 | `SoftwareBitBang` supports the use of input and output pins because separated signals may be required if additional circuitry is used for amplification or noise filtering. It also works if pins are directly connected as a simple point-to-point null-modem or cross-over serial link. ```cpp -#include +#include -PJON bus; +PJONSoftwareBitBang bus; void setup() { // Set the pin 12 as the communication pin @@ -76,7 +85,7 @@ void setup() { bus.strategy.set_pins(11, 12); } ``` -After the PJON object is defined with its strategy it is possible to set the communication pin accessing to the strategy present in the PJON instance. All the other necessary information is present in the general [Documentation](/documentation). +After the PJON object is defined with its strategy, it is possible to set the communication pin by accessing the strategy present in the PJON instance. All the other necessary information is present in the general [Documentation](/documentation). ### Why not interrupts? In the Arduino environment the use of libraries is really extensive and often the end user is not able to go over collisions. Very often a library is using hardware resources of the microcontroller, colliding with other libraries. This happens because in general Arduino boards have limited hardware resources. Software-defined bit-banging, is a stable and reliable solution that leads to "more predictable" results than interrupt driven procedures coexisting on limited microcontrollers without the developer and the end user knowing about it. @@ -87,9 +96,10 @@ PJON application example made by the user [Michael Teeuw](http://michaelteeuw.nl ### Known issues - A 1-5 MΩ pull down resistor could be necessary to reduce interference, see [Mitigate interference](https://github.com/gioblu/PJON/wiki/Mitigate-interference). -- When using more than one instance of `SoftwareBitBang` in the same sketch always use pins connected to a different port group to avoid cross-talk. -- During the execution of other tasks or delays a certain amount of packets could be potentially lost because transmitted out of the polling time of the receiver device. Thanks to the PJON packet handler after some retries the packet is received but a certain amount of bandwidth is wasted. If this situation occurs, try to reduce as much as possible the duration of other tasks and or use a longer polling time using `receive` and passing the requested amount of microseconds: `bus.receive(1000); // Poll for 1 millisecond`. +- When using more than one instance of `SoftwareBitBang` in the same sketch use pins part of different port groups to avoid cross-talk. +- During the execution of other tasks or delays a certain amount of packets could be potentially lost because transmitted out of the polling time of the receiver device. Thanks to the PJON packet handler after some retries the packet is received but a certain amount of bandwidth is wasted. If this situation occurs try to reduce the duration of other tasks and use a frame preamble setting `SWBB_MAX_PREAMBLE` and `SWBB_PREAMBLE` to a value between 1 and 100. The optimal preamble length is the maximum interval between each `bus.receive()` call divided by `SWBB_BIT_SPACER` - `SoftwareBitBang` strategy can have compatibility issues with codebases that are using interrupts, reliability or bandwidth loss can occur because of the interruptions made by third party software. +- If you need to connect devices that operate at different voltages, for example when connecting an Arduino UNOs to an ESP32, consider that voltage level converters available in the market are often not compatible with PJDL, you can try this [alternative approach](http://www.falstad.com/circuit/circuitjs.html?ctz=CQAgjCAMB0l3BWEA2AzNA7ATi8gHACxhaKTJYgaohIHUICmAtGGAFABu4WATCKgj7E+PDH0hQQBCemoT50BJxpg+AvglUhR4ydJqSFSgO5SCefoO0Jkl8WwAm12z0gWeN8D3fgAcqgI2AAduETcvd3CIeTZTD1t1ULsoWJU1KwJzZMhU4XAtePz7UwJkAiK0ipySsorMi1Z7EM0wiwQMFyjDNgBnSp1+8PkQADMAQwAbHoY2ACdnbXDCxIlCeF6kgbzXCwkIcamZ+bzGzaGpVzhUwp2z3evPU-qqh9tTwtV7+eenrJXweDreYtCog24SS5sAAeICYPBcYDerm0xCk2nKqA4qAAOj0HAwOABLADGDFxAEkAPLQmiEFHlDBgDAo5nlHjlBAcXH4omkinUmHECCoOkISAUEWs8BIADKAHVyQAVADCAAkAKIy3EAQQASurcQBVGXqgAiuMVlNxMvJAFlDQAZbWKg09SmGxUABQ9bCAA) proposed by [alastaira](https://github.com/alastaira) instead. It isn't truly converting voltage levels but it is much quicker and cheaper than designs based on transistors. ### Safety warning -In all cases, when installing or maintaining a PJON network, extreme care must be taken to avoid any danger. When a [SoftwareBitBang](/src/strategies/SoftwareBitBang) bus is installed each pin must be protected with a current limiting resistor as described above. If a common ground or power supply line is used its cable size and length must be carefully selected taking in consideration the overall application's power supply requirements and selected components' maximum rating. +In all cases, when installing or maintaining a PJON network, extreme care must be taken to avoid any danger. If devices are connected to AC power, you face a high risk of electrocution unless the hardware is installed carefully and correctly. If you lack sufficient experience, seek assistance from a qualified technician, and be aware that many countries prohibit uncertified installations. When a [SoftwareBitBang](/src/strategies/SoftwareBitBang) bus is installed [interference-mitigation](https://github.com/gioblu/PJON/wiki/Mitigate-interference) and [protective-circuitry](https://github.com/gioblu/PJON/wiki/Protective-circuitry) guidelines must be followed. If a common ground or power supply line is used its cable size and length must be carefully selected taking in consideration the overall application's power supply requirements and selected components' maximum rating. PJDL and its reference implementation [SoftwareBitBang](/src/strategies/SoftwareBitBang/README.md) are experimental, use them at your own risk. diff --git a/src/strategies/SoftwareBitBang/SoftwareBitBang.h b/src/strategies/SoftwareBitBang/SoftwareBitBang.h index 2c06e69e32..948d771fcf 100644 --- a/src/strategies/SoftwareBitBang/SoftwareBitBang.h +++ b/src/strategies/SoftwareBitBang/SoftwareBitBang.h @@ -2,10 +2,10 @@ /* SoftwareBitBang 1 or 2 wires software-defined asynchronous serial data link layer used as a Strategy by PJON (included in version v3.0) - Compliant with PJDL (Padded Jittering Data Link) specification v4.1 + Compliant with PJDL (Padded Jittering Data Link) specification v5.0 ___________________________________________________________________________ - Copyright 2010-2020 Giovanni Blu Mitolo gioscarab@gmail.com + Copyright 2010-2025 Giovanni Blu Mitolo gioscarab@gmail.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,17 +28,21 @@ // Used to signal communication failure #define SWBB_FAIL 65535 - // Used for pin handling #define SWBB_NOT_ASSIGNED 255 /* Transmission speed modes (see Timing.h) - MODE 1: 1.95kB/s - 15625Bd + MODE 1: 1.97kB/s - 15808Bd MODE 2: 2.21kB/s - 17696Bd - MODE 3: 2.94kB/s - 23529Bd - MODE 4: 3.40kB/s - 27210Bd */ + MODE 3: 3.10kB/s - 24844Bd + MODE 4: 3.34kB/s - 26755Bd */ #include "Timing.h" +// Recommended receive time for this strategy, in microseconds +#ifndef SWBB_RECEIVE_TIME + #define SWBB_RECEIVE_TIME 1000 +#endif + class SoftwareBitBang { public: /* Returns the delay related to the attempts passed as parameter: */ @@ -65,6 +69,7 @@ class SoftwareBitBang { bool can_start() { PJON_IO_MODE(_input_pin, INPUT); + // Look for ongoing transmission for 1 padding bit + 9 data bits PJON_DELAY_MICROSECONDS(SWBB_BIT_SPACER / 2); if(PJON_IO_READ(_input_pin)) return false; PJON_DELAY_MICROSECONDS((SWBB_BIT_SPACER / 2)); @@ -76,6 +81,10 @@ class SoftwareBitBang { PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH); } if(PJON_IO_READ(_input_pin)) return false; + // Delay for the maximum expected latency and then check again + PJON_DELAY_MICROSECONDS(SWBB_LATENCY); + if(PJON_IO_READ(_input_pin)) return false; + // Delay for a small random time and then check again PJON_DELAY_MICROSECONDS(PJON_RANDOM(SWBB_COLLISION_DELAY)); if(PJON_IO_READ(_input_pin)) return false; return true; @@ -89,6 +98,13 @@ class SoftwareBitBang { }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { + return SWBB_RECEIVE_TIME; + }; + + /* Handle a collision: */ void handle_collision() { @@ -135,10 +151,7 @@ class SoftwareBitBang { PJON_IO_WRITE(_output_pin, LOW); uint16_t response = SWBB_FAIL; uint32_t time = PJON_MICROS(); - while( - response == SWBB_FAIL && - (uint32_t)(PJON_MICROS() - SWBB_RESPONSE_TIMEOUT) <= time - ) { + while((uint32_t)(PJON_MICROS() - time) < _timeout) { PJON_IO_WRITE(_input_pin, LOW); if(sync()) response = receive_byte(); if(response == SWBB_FAIL) { @@ -146,7 +159,7 @@ class SoftwareBitBang { PJON_IO_WRITE(_output_pin, HIGH); PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH / 4); PJON_IO_PULL_DOWN(_output_pin); - } + } else return response; } return response; }; @@ -159,14 +172,13 @@ class SoftwareBitBang { if(max_length == PJON_PACKET_MAX_LENGTH) { uint32_t time = PJON_MICROS(); // Look for a frame initializer - if(!sync() || !sync() || !sync()) return SWBB_FAIL; + if(!sync_preamble() || !sync() || !sync()) return SWBB_FAIL; // Check its timing consistency if( (uint32_t)(PJON_MICROS() - time) < (((SWBB_BIT_WIDTH * 3) + (SWBB_BIT_SPACER * 3)) - SWBB_ACCEPTANCE) ) return SWBB_FAIL; - } - // Receive incoming bytes + } // Receive one byte result = receive_byte(); if(result == SWBB_FAIL) return SWBB_FAIL; *data = result; @@ -219,7 +231,7 @@ class SoftwareBitBang { while( // If high Wait for low ((uint32_t)(PJON_MICROS() - time) < (SWBB_BIT_WIDTH / 4)) && PJON_IO_READ(_input_pin) - ); + ); // Transmit response prepended with a synchronization pad PJON_IO_MODE(_output_pin, OUTPUT); pulse(1); send_byte(response); @@ -241,10 +253,11 @@ class SoftwareBitBang { Send a frame: */ void send_frame(uint8_t *data, uint16_t length) { + _timeout = (length * SWBB_RESPONSE_OFFSET) + SWBB_LATENCY; PJON_IO_MODE(_output_pin, OUTPUT); pulse(3); // Send frame initializer for(uint16_t b = 0; b < length; b++) - send_byte(data[b]); // Send data + send_byte(data[b]); // Send each byte PJON_IO_PULL_DOWN(_output_pin); }; @@ -266,14 +279,14 @@ class SoftwareBitBang { not, interference, synchronization loss or simply absence of communication is detected at byte level: */ - bool sync() { + bool sync(uint32_t spacer) { PJON_IO_PULL_DOWN(_input_pin); if((_output_pin != _input_pin) && (_output_pin != SWBB_NOT_ASSIGNED)) PJON_IO_PULL_DOWN(_output_pin); uint32_t time = PJON_MICROS(); while( PJON_IO_READ(_input_pin) && - ((uint32_t)(PJON_MICROS() - time) <= SWBB_BIT_SPACER) + ((uint32_t)(PJON_MICROS() - time) <= spacer) ); time = PJON_MICROS() - time; if(time < SWBB_ACCEPTANCE) @@ -288,9 +301,27 @@ class SoftwareBitBang { return false; }; + bool sync() { + return sync(SWBB_BIT_SPACER); + } + + bool sync_preamble() { + return sync(SWBB_BIT_SPACER * SWBB_MAX_PREAMBLE); + }; + /* Emit synchronization pulse: */ void pulse(uint8_t n) { + #if SWBB_PREAMBLE != 1 + if (n == 3) { + // Transmit preamble + PJON_IO_WRITE(_output_pin, HIGH); + PJON_DELAY_MICROSECONDS(SWBB_BIT_SPACER * SWBB_PREAMBLE); + PJON_IO_WRITE(_output_pin, LOW); + PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH); + n--; + } + #endif while(n--) { PJON_IO_WRITE(_output_pin, HIGH); PJON_DELAY_MICROSECONDS(SWBB_BIT_SPACER); @@ -321,6 +352,7 @@ class SoftwareBitBang { }; private: - uint8_t _input_pin; - uint8_t _output_pin; + uint16_t _timeout; + uint8_t _input_pin; + uint8_t _output_pin; }; diff --git a/src/strategies/SoftwareBitBang/Timing.h b/src/strategies/SoftwareBitBang/Timing.h index 3c7a3053e7..c29b51f7d2 100644 --- a/src/strategies/SoftwareBitBang/Timing.h +++ b/src/strategies/SoftwareBitBang/Timing.h @@ -1,20 +1,22 @@ /* PJON SoftwareBitBang strategy Transmission Timing table - Copyright 2010-2020, Giovanni Blu Mitolo All rights reserved. + Copyright 2010-2025, Giovanni Blu Mitolo All rights reserved. - Often timing in two different architectures do not match. Code execution - time can variate and time measurements can be not perfectly equal. - Arduino Duemilanove/UNO/Nano durations are used as master. - Consider that master durations defined below are shorter than specified - in the PJDL-specification-v2.1 to accomodate the input-output pin change - duration (4 microseconds) and effectively produce the specified durations. + Often timing in two different machines do not match, code execution + time can variate and time measurements are not perfectly equal. + Consider that durations defined below may differ from what is specified in + PJDL v5.0. This is done to accomodate machine's inner workings and + effectively produce the specified timing. + + Arduino Duemilanove/UNO/Nano is used as timing master, or the machine used + to test all new supported MCUs. Benchmarks can be executed using NetworkAnalysis and SpeedTest examples. - MODE 1: 1.95kB/s - 15625Bd + MODE 1: 1.97kB/s - 15808Bd MODE 2: 2.21kB/s - 17696Bd - MODE 3: 2.97kB/s - 23529Bd - MODE 4: 3.40kB/s - 27210Bd + MODE 3: 3.10kB/s - 24844Bd + MODE 4: 3.34kB/s - 26755Bd Use the same pin number on all connected devices to achieve maximum timing efficiency, not all different pin combinations work nominally @@ -47,8 +49,8 @@ #if F_CPU == 16000000L /* Working on pin: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1 */ #define SWBB_BIT_WIDTH 24 - #define SWBB_BIT_SPACER 80 - #define SWBB_ACCEPTANCE 40 + #define SWBB_BIT_SPACER 66 + #define SWBB_ACCEPTANCE 30 #define SWBB_READ_DELAY 8 #endif #endif @@ -56,9 +58,9 @@ #if F_CPU == 16000000L /* Working on pin: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1 */ #define SWBB_BIT_WIDTH 22 - #define SWBB_BIT_SPACER 56 + #define SWBB_BIT_SPACER 61 #define SWBB_ACCEPTANCE 30 - #define SWBB_READ_DELAY 9 + #define SWBB_READ_DELAY 7 #endif #endif #endif @@ -91,11 +93,17 @@ #if SWBB_MODE == 1 /* Working on pin: 2, 4, 8, 12 Fallback to default timing */ + #define SWBB_BIT_WIDTH 40 + #define SWBB_BIT_SPACER 112 + #define SWBB_ACCEPTANCE 56 #define SWBB_READ_DELAY 8 #endif #if SWBB_MODE == 2 /* Working on pin: 2, 4, 8, 12 Fallback to default timing */ + #define SWBB_BIT_WIDTH 36 + #define SWBB_BIT_SPACER 88 + #define SWBB_ACCEPTANCE 56 #define SWBB_READ_DELAY 12 #endif #endif @@ -124,12 +132,20 @@ #if F_CPU == 16000000L /* Working on pin: 1, 2 Fallback to default */ + #define SWBB_BIT_WIDTH 40 + #define SWBB_BIT_SPACER 112 + #define SWBB_ACCEPTANCE 56 + #define SWBB_READ_DELAY 4 #endif #endif #if SWBB_MODE == 2 #if F_CPU == 16000000L /* Working on pin: 1, 2 Fallback to default */ + #define SWBB_BIT_WIDTH 36 + #define SWBB_BIT_SPACER 88 + #define SWBB_ACCEPTANCE 56 + #define SWBB_READ_DELAY 4 #endif #endif #endif @@ -141,12 +157,20 @@ #if F_CPU == 16000000L /* Working on pin: 0, 1, 2, 3, 4 Fallback to default */ + #define SWBB_BIT_WIDTH 40 + #define SWBB_BIT_SPACER 112 + #define SWBB_ACCEPTANCE 56 + #define SWBB_READ_DELAY 4 #endif #endif #if SWBB_MODE == 2 #if F_CPU == 16000000L /* Working on pin: 0, 1, 2, 3, 4 Fallback to default */ + #define SWBB_BIT_WIDTH 36 + #define SWBB_BIT_SPACER 88 + #define SWBB_ACCEPTANCE 56 + #define SWBB_READ_DELAY 4 #endif #endif #endif @@ -162,14 +186,6 @@ #define SWBB_ACCEPTANCE 40 #define SWBB_READ_DELAY -4 #endif - #if SWBB_MODE == 3 - /* Added by Esben Soeltoft - 09/03/2016 - Speed: 48000Bd or 6.00kB/s */ - #define SWBB_BIT_WIDTH 12 - #define SWBB_BIT_SPACER 36 - #define SWBB_ACCEPTANCE 12 - #define SWBB_READ_DELAY 1 - #endif #endif /* NodeMCU, generic ESP8266 ----------------------------------------------- */ @@ -212,15 +228,42 @@ #endif #endif + /* STM32F1 ---------------------------------------------------------------- */ +/* @jcallano 09-jul-2020 tested with pin PB15, PB14, PB13, PB12, PB11, PB10, + PB9, PB8, PB7, PB6, PB4, PB3, PA15, PA10. 5v tolerant pins on bluepill */ + #if defined(__STM32F1__) #if SWBB_MODE == 1 #if F_CPU == 72000000L - /* Added by github user osman-aktepe - 22/06/2018 */ - #define SWBB_BIT_WIDTH 44 - #define SWBB_BIT_SPACER 112 - #define SWBB_ACCEPTANCE 40 - #define SWBB_READ_DELAY -10 + #define SWBB_BIT_WIDTH 43 + #define SWBB_BIT_SPACER 115 + #define SWBB_ACCEPTANCE 60 + #define SWBB_READ_DELAY 3 + #endif + #endif + #if SWBB_MODE == 2 + #if F_CPU == 72000000L + #define SWBB_BIT_WIDTH 39 + #define SWBB_BIT_SPACER 91 + #define SWBB_ACCEPTANCE 47 + #define SWBB_READ_DELAY 3 + #endif + #endif + #if SWBB_MODE == 3 + #if F_CPU == 72000000L + #define SWBB_BIT_WIDTH 27.5 + #define SWBB_BIT_SPACER 69.5 + #define SWBB_ACCEPTANCE 33 + #define SWBB_READ_DELAY -5 + #endif + #endif + #if SWBB_MODE == 4 + #if F_CPU == 72000000L + #define SWBB_BIT_WIDTH 25 + #define SWBB_BIT_SPACER 59 + #define SWBB_ACCEPTANCE 30 // + #define SWBB_READ_DELAY 4 #endif #endif #endif @@ -239,6 +282,9 @@ #ifndef SWBB_READ_DELAY #define SWBB_READ_DELAY 4 #endif + #ifndef SWBB_LATENCY + #define SWBB_LATENCY 13 + #endif #endif #if SWBB_MODE == 2 #ifndef SWBB_BIT_WIDTH @@ -253,43 +299,71 @@ #ifndef SWBB_READ_DELAY #define SWBB_READ_DELAY 4 #endif + #ifndef SWBB_LATENCY + #define SWBB_LATENCY 10 + #endif #endif #if SWBB_MODE == 3 #ifndef SWBB_BIT_WIDTH #define SWBB_BIT_WIDTH 24 #endif #ifndef SWBB_BIT_SPACER - #define SWBB_BIT_SPACER 80 + #define SWBB_BIT_SPACER 66 #endif #ifndef SWBB_ACCEPTANCE - #define SWBB_ACCEPTANCE 40 + #define SWBB_ACCEPTANCE 30 #endif #ifndef SWBB_READ_DELAY #define SWBB_READ_DELAY 8 #endif + #ifndef SWBB_LATENCY + #define SWBB_LATENCY 8 + #endif #endif #if SWBB_MODE == 4 #ifndef SWBB_BIT_WIDTH #define SWBB_BIT_WIDTH 22 #endif #ifndef SWBB_BIT_SPACER - #define SWBB_BIT_SPACER 56 + #define SWBB_BIT_SPACER 61 #endif #ifndef SWBB_ACCEPTANCE #define SWBB_ACCEPTANCE 30 #endif #ifndef SWBB_READ_DELAY - #define SWBB_READ_DELAY 9 + #define SWBB_READ_DELAY 7 + #endif + #ifndef SWBB_LATENCY + #define SWBB_LATENCY 5 #endif #endif -/* Synchronous acknowledgement response timeout. (1.5 milliseconds default). - If (latency + CRC computation) > SWBB_RESPONSE_TIMEOUT synchronous - acknowledgement reliability could be affected or disrupted higher - SWBB_RESPONSE_TIMEOUT if necessary. */ -#ifndef SWBB_RESPONSE_TIMEOUT - #define SWBB_RESPONSE_TIMEOUT 1500 +/* Frame preamble length (by default set to 1 x SWBB_BIT_SPACER) + Maximum allowed value is 100 or a preamble of 100 x SWBB_BIT_SPACER + When devices execute other tasks frames may be lost unheard. The preamble + can be used to avoid transmission failure. To avoid retransmissions the + preamble length should be slightly longer than the task's duration. */ + +#ifndef SWBB_PREAMBLE + #define SWBB_PREAMBLE 1 +#endif + +/* Maximum frame preamble length (by default set to 1 x SWBB_BIT_SPACER) + Maximum allowed value is 100 or a preamble of 100 x SWBB_BIT_SPACER + To have full interoperability set SWBB_MAX_PREAMBLE = 100 */ + +#ifndef SWBB_MAX_PREAMBLE + #define SWBB_MAX_PREAMBLE 1 +#endif + +/* Synchronous acknowledgement response offset. + If (latency + CRC computation) > (SWBB_RESPONSE_OFFSET * length) + synchronous acknowledgement reliability could be affected or disrupted + set a higher SWBB_RESPONSE_OFFSET if necessary. */ + +#ifndef SWBB_RESPONSE_OFFSET + #define SWBB_RESPONSE_OFFSET 20 #endif /* Maximum initial delay in milliseconds: */ diff --git a/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md b/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md new file mode 100644 index 0000000000..4c4be9e0b9 --- /dev/null +++ b/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md @@ -0,0 +1,129 @@ + +### Specifications index + +#### Network layer +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) +- [Network services list](/specification/PJON-network-services-list.md) +#### Data link layer +- **[PJDL (Padded Jittering Data Link) v5.0](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md)** +- [PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) +- [PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) +- [TSDL (Tardy Serial Data Link) v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md) +- [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) + +--- + +## PJDL v5.0 +``` +Invented by Giovanni Blu Mitolo with the support of +Fred Larsen, Julio Aguirre, Gerhard Sittig and Jack Anderson +Publication date: 10/04/2010 Latest revision: 24/07/2020 +Related implementation: /src/strategies/SoftwareBitBang/ +Compatible versions: PJON v13.0 and following +Released into the public domain + +10/04/2010 0.1 - First experimental release +12/02/2017 1.0 - Frame initializer, response made safe +31/03/2017 1.1 - Physical layer info +24/09/2017 2.0 - Modes 1, 2, 3 +29/12/2018 3.0 - Medium access control info, mode 4 +03/07/2019 4.0 - Response initializer +10/03/2020 4.1 - Maximum range experimentally determined +17/07/2020 5.0 - Timeout, tolerance and preamble added +``` +PJDL (Padded Jittering Data Link) is an asynchronous serial data link for low-data-rate applications that supports both master-slave and multi-master communication over a common conductive medium. PJDL can be easily implemented on limited microcontrollers with low clock accuracy and can operate directly using a single input-output pin. + +### Physical layer +The medium's maximum length is limited by the wiring resistance, by the voltage level used and by externally induced interference. The maximum length of the bus can reach between 800 and 2000 meters depending on the mode used. +```cpp +PJDL SINGLE WIRE BUS ______ + ______ ______ ______ ______ | | +| | | | | | | | |DEVICE| +|DEVICE| |DEVICE| |DEVICE| |DEVICE| |______| +|______| |______| |______| |______| | +___|__________|________|___________|______/\/\/\__| IO PIN + ___|__ __|___ ___|__ ___|__ | 110-180 Ω +| | | | | | | | | +|DEVICE| |DEVICE| |DEVICE| |DEVICE| |__/\/\/\__ GND +|______| |______| |______| |______| 8 kΩ - 5 MΩ +``` +It is suggested to add 8kΩ-5MΩ pull-down resistor as shown in the graph above to reduce externally induced interference. The longer is the length of the cable and the higher is the amount of induced interference, the lower should be the resistance of the pull-down resistor. Pins can be optionally protected against overload adding a current limiting resistor to each connected pin. The resistor value can be obtained solving the following equation `R = (operating voltage / pin max current drain)`, for example to obtain the current limiting resistor value for an Arduino Uno simply substitute its characteristics: `R = (5v / 0.030A) = 166.66Ω`. + +### Communication modes +The proposed communication modes are the result of years of testing and optimization and have been selected to be easily supported by limited microcontrollers: + +| Mode | Bandwidth | Range | Preamble bit | Pad bit | Data bit | Keep busy bit | Latency | Timeout | +| ---- | ------------------ | ----- | ------------ | ------- | -------- | ------------- | ------- | ------- | +| 1 | 1.97kB/s - 15808Bd | 2000m | 11000µs | 110µs | 44µs | 11µs | 13µs | 20µs/B | +| 2 | 2.21kB/s - 17696Bd | 1600m | 9200µs | 92µs | 40µs | 10µs | 10µs | 20µs/B | +| 3 | 3.10kB/s - 24844Bd | 1200m | 7000µs | 70µs | 28µs | 7µs | 8µs | 20µs/B | +| 4 | 3.34kB/s - 26755Bd | 800m | 6500µs | 65µs | 26µs | 6.5µs | 5µs | 20µs/B | + +The following table specifies the exclusive acceptable tolerance of each bit type: + +| Mode | Preamble bit | Padding bit | Data bit nonet | Keep busy bit | +| ---- | -------------- | ----------- | -------------- | ------------- | +| 1 | -11000us +0us | -5us +17us | -5us +17us | -5µs +10µs | +| 2 | -9200us +0us | -4us +16us | -4us +16us | -5µs +10µs | +| 3 | -7000us +0us | -3us +11us | -3us +11us | -3µs +10µs | +| 4 | -6500us +0us | -3us +10us | -3us +10us | -3µs +10µs | + +Padding bit, data bit and keep busy bit have higher positive tolerance to accept bit-banged signals that are generally longer than expected. + +### Medium access control +PJDL specifies a variation of the carrier-sense, non-persistent random multiple access method (non-persistent CSMA). Devices can detect an ongoing transmission for this reason collisions can only occur in multi-master mode when 2 or more devices start to transmit at the same time. When a collision occurs it can be detected by the receiver because of synchronization loss or by the transmitter if an active collision avoidance procedure is implemented. + +### Byte transmission +Byte transmission is composed by 10 bits, the first two are called synchronization pad and are used to obtain sampling synchronization. The synchronization pad is composed by a high padding bit 2.5 times longer than data bits and a low data bit. The following 8 data bits contain information in LSB-first (least significant bit first) order. + +The reception technique is based on 3 steps: +1. Find a high bit which matches a padding bit +2. Synchronize with its falling edge +3. Ensure it is followed by a low data bit + +If so reception starts, if not, interference, synchronization loss or simply absence of communication is detected. While receiving a sequence of bytes a synchronization pad is acceptable even if prepended by a 0 of up to the maximum positive data bit nonet tolerance. + +```cpp + ___________ ___________________________ +| SYNC PAD | DATA | +|_______ |___ ___ _____ | +| | | | | | | | | +| 1 | 0 | 1 | 0 0 | 1 | 0 | 1 1 | 0 | +|_______|___|___|_____|___|___|_____|___| +``` +The synchronization pad adds overhead although it includes synchronization along with the data and eliminates the need of a dedicated clock line. The presence of the synchronization pad between each byte also ensures that a frame composed of a series of bytes with decimal value 0 can be transmitted safely without risk of collision. + +### Frame transmission +Before a frame transmission the communication medium's state is analysed, if high communication is detected and collision is avoided, if low for a duration of one byte plus the latency and a small random time, frame transmission starts with a frame preamble and a frame initializer composed by 3 consecutive synchronization pads followed by data bytes. The synchronization pad is used for both byte and frame initialization to reduce the implementation complexity. PJDL frames do not have an intrinsic length limit. +```cpp + ________ __________ _________________ ________________ +|ANALYSIS| PREAMBLE | FRAME INIT | DATA BYTES | +|________|__________|_____ _____ _____|________________| +| | |Sync |Sync |Sync |Sync | Byte | +| |__________|___ |___ |___ |___ | __ | +| | | | | | | | | | | | | | +|00000000| 1 | 1 |0| 1 |0| 1 |0| 1 |0|0000|11|00| +|________|__________|___|_|___|_|___|_|___|_|____|__|__| +``` +When a frame is received a low performance microcontroller with an inaccurate clock can correctly identify a preamble, synchronize with transmitter during the frame initializer and consequently each byte is received. Frame initialization is 100% reliable, false positives can only occur because of externally induced interference. If the implementation applies polling, the preamble can be used to reduce the chances of transmission failure when the receiver's polling frequency is too low to detect incoming frames. The preamble's maximum length is 100 times the length of a padding bit. + +### Synchronous response +A frame transmission can be optionally followed by a synchronous response sent by its recipient. Between frame transmission and a synchronous response there is a variable time which duration is influenced by latency. +```cpp +Transmission end Response + ______ ______ ______ _____ +| BYTE || BYTE || BYTE | CRC COMPUTATION / LATENCY | ACK | +|------||------||------|---------------------------|-----| +| || || | | 6 | +|______||______||______| |_____| +``` +In order to avoid other devices to detect the medium free for use and disrupt an ongoing exchange, the sender cyclically transmits a high 1/4 data bit and consequently attempts to receive a response for up to twice the maximum expected latency. The receiver must synchronize to the falling edge of the last high bit and, in order to avoid false positives in case of collision, must transmit its response prepended with an additional synchronization pad. If the response is not transmitted or not received the transmitter continues to keep busy the medium up to the response timeout. +```cpp +Transmission end Bus is kept busy Response + ______ ______ ______ _ _ _ _ _ _ ____ _____ +| BYTE || BYTE || BYTE | | | | | | | | | | | | |SYNC| ACK | +|------||------||------| | | | | | | | | | | | |----|-----| +| || || | | | | | | | | | | | | | | 6 | +|______||______||______|_| |_| |_| |_| |_| |_| |____|_____| +``` +The response timeout is determined multiplying 20µs by the length of the frame and then adding the maximum expected latency. diff --git a/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.0.md b/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.0.md index 86e772fcc1..2dbf1d70e2 100644 --- a/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.0.md +++ b/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.0.md @@ -3,7 +3,7 @@ /* Milan, Italy - 10/04/2010 PJDL (Padded jittering data link) specification is an invention and intellectual property -of Giovanni Blu Mitolo - Copyright 2010-2020 All rights reserved +of Giovanni Blu Mitolo - Copyright 2010-2025 All rights reserved Related work: /src/strategies/SoftwareBitBang/ Compliant implementation versions: PJON 6.0-7.1 diff --git a/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.1.md b/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.1.md index 6c2e30ee95..491fc99f6e 100644 --- a/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.1.md +++ b/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v1.1.md @@ -4,7 +4,7 @@ Milan, Italy - 31/03/2017 PJDL (Padded jittering data link) specification is an invention and intellectual property of Giovanni Blu Mitolo -Copyright 2010-2020 All rights reserved +Copyright 2010-2025 All rights reserved Related work: /src/strategies/SoftwareBitBang/ Compliant implementation versions: PJON 8.0 and following diff --git a/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md b/src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v4.1.md similarity index 100% rename from src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md rename to src/strategies/SoftwareBitBang/specification/obsolete/PJDL-specification-v4.1.md diff --git a/src/strategies/SoftwareBitBang/specification/obsolete/padded-jittering-protocol-specification-v0.1.md b/src/strategies/SoftwareBitBang/specification/obsolete/padded-jittering-protocol-specification-v0.1.md index 0835c53311..3fefc26c75 100644 --- a/src/strategies/SoftwareBitBang/specification/obsolete/padded-jittering-protocol-specification-v0.1.md +++ b/src/strategies/SoftwareBitBang/specification/obsolete/padded-jittering-protocol-specification-v0.1.md @@ -3,7 +3,7 @@ /* Milan, Italy - 10/04/2010 The Padded jittering data link layer specification is an invention and intellectual property -of Giovanni Blu Mitolo - Copyright 2010-2020 All rights reserved +of Giovanni Blu Mitolo - Copyright 2010-2025 All rights reserved Related work: /src/strategies/SoftwareBitBang/ Compliant implementation versions: PJON 1.0-5.0 diff --git a/src/strategies/ThroughLoRa/README.md b/src/strategies/ThroughLoRa/README.md index e8916ce538..b3c4a0e4f6 100644 --- a/src/strategies/ThroughLoRa/README.md +++ b/src/strategies/ThroughLoRa/README.md @@ -1,31 +1,31 @@ ## ThroughLoRa -**Medium:** Radio, Wire | **Pins used:** 6 +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| LoRa radio | 6 | `#include `| With `ThroughLora` strategy, PJON can run through a software or hardware SPI in order to communicate with supported LoRa modules. See [Supported Shields/Modules](https://github.com/gioblu/PJON/tree/master/src/strategies/ThroughLoRa#supported-shieldsmodules). This strategy is a wrapper around [Arduino LoRa library](https://github.com/sandeepmistry/arduino-LoRa) created by [Sandeep Mistry](https://github.com/sandeepmistry) so all the credit to the specific LoRa implementation goes to him. -Consider that, because of the inherent limitations of LoRa, the synchronous acknowledgement is not supported. - ### Compatibility - ATmega88/168/328 16MHz (Diecimila, Duemilanove, Uno, Nano, Mini, Lillypad) - ATmega2560 16MHz (Arduino Mega) - ATmega16u4/32u4 16MHz (Arduino Leonardo) - STM32F103 ([Blue Pill](http://wiki.stm32duino.com/index.php?title=Blue_Pill)) +- ESP32-based boards ### Getting started -1. Define `PJON_INCLUDE_TL` before including PJON header `` -2. Pass the `ThroughLora` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. -3. Configure the shield/module pins according to the correct connection. See [Hardware connection](#hardware-connection). -4. Initialize the module with its specified frequency. +1. Pass the `ThroughLora` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. +2. Configure the shield/module pins according to the correct connection. See [Hardware connection](#hardware-connection). +3. Initialize the module with its specified frequency. ```cpp -#define PJON_INCLUDE_TL //Definition to enable ThroughLora strategy -#include //PJON header +#include + +PJONThroughLora bus; //PJON Lora bus instance -PJON bus; //PJON Lora bus instance bus.strategy.setPins(10,9,2); //CS pin, Reset pin, Interrupt pin bus.strategy.setFrequency(868100000UL); //initialize 868 MHZ module ``` @@ -37,6 +37,9 @@ bus.strategy.setFrequency(868100000UL); //initialize 868 MHZ module | [HopeRF](http://www.hoperf.com/) | [RFM95W](http://www.hoperf.com/rf_transceiver/lora/RFM95W.html) / [RFM96W](http://www.hoperf.com/rf_transceiver/lora/RFM96W.html) / [RFM98W](http://www.hoperf.com/rf_transceiver/lora/RFM98W.html) | | [Modtronix](http://modtronix.com/) | [inAir4](http://modtronix.com/inair4.html) / [inAir9](http://modtronix.com/inair9.html) / [inAir9B](http://modtronix.com/inair9b.html) | | [Adafruit](https://www.adafruit.com/) | [Adafruit Feather 32u4 LoRa Radio (RFM9x)](https://learn.adafruit.com/adafruit-feather-32u4-radio-with-lora-radio-module/overview) | +| [Ai-Thinker](https://en.ai-thinker.com/index.html) | Ra01 / [Ra02](https://en.ai-thinker.com/pro_view-57.html) (SX1278 based) + +See the [Arduino LoRa readme](https://github.com/sandeepmistry/arduino-LoRa) for a more complete list of modules. ### Hardware connection | General Wiring | Arduino | @@ -52,28 +55,26 @@ bus.strategy.setFrequency(868100000UL); //initialize 868 MHZ module - `NSS`, `NRESET`, and `DIO0` pins can be changed by using `PJON.strategy.setPins(ss, reset, dio0)`. - `DIO0` pin is optional, it is only needed for receive callback mode. If `DIO0` pin is used, it **must** be interrupt capable via [`attachInterrupt(...)`](https://www.arduino.cc/en/Reference/AttachInterrupt). +- Some boards support custom pins for `SCK`, `MISO` and `MOSI` (ESP32 series for example). These can be set using `SPI.begin(sck, miso, mosi)` before calling `PJON.strategy.setFrequency(frequency)`. ### Usage Example -Here are listed basic examples of a transmitter and receiver code. After tou include the necessary code to initialize the Lora module you can use the normal PJON functions to handle data communication. +Here are listed basic examples of a transmitter and receiver code. After you include the necessary code to initialize the Lora module you can use the normal PJON functions to handle data communication. -Keep in mind that to use the LoRa startegy you must download the [Arduino LoRa library](https://github.com/sandeepmistry/arduino-LoRa). +Keep in mind that to use the LoRa strategy you must download the [Arduino LoRa library](https://github.com/sandeepmistry/arduino-LoRa). More examples can be found in https://github.com/gioblu/PJON/tree/master/examples/ARDUINO/Local/ThroughLoRa ### Transmitter ```cpp -#define PJON_INCLUDE_TL -#include +#include -PJON bus(45); +PJONThroughLora bus(45); void setup() { // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); bus.begin(); - // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); // Send B to device 44 every second bus.send_repeatedly(44, "B", 1, 1000000); }; @@ -86,12 +87,10 @@ void loop() { ### Receiver ```cpp -#define PJON_INCLUDE_TL - -#include +#include // bus(selected device id) -PJON bus(44); +PJONThroughLora bus(44); void setup() { pinMode(13, OUTPUT); @@ -100,8 +99,6 @@ void setup() { // Obligatory to initialize Radio with correct frequency bus.strategy.setFrequency(868100000UL); - // Synchronous acknowledgement is not supported - bus.set_synchronous_acknowledge(false); // Optional bus.strategy.setSignalBandwidth(250E3); bus.begin(); @@ -225,5 +222,22 @@ byte b = bus.strategy.getRandom(); ``` Generate a random byte, based on the Wideband RSSI measurement. +### Acknowledgement +Acknowledgement allows the sender to request that the receiver acknowledge reception of a message so that multiple transmission attempts can be made if required. Limits on the allowed transmission duty cycle in various parts of the world, power budgets, message importance and network throughput may affect whether acknowledgement is required for some or all messages. Acknowledgement can be enabled or disabled for the sender using: +```cpp +bus.set_acknowledge(true/false); +``` +Depending on the speed of the hardware on either end and the bandwidth and spreading factor configured, it may be necessary to increase the time the sender will wait for an acknowledgement before timing out. This can be set by defining `TL_RESPONSE_TIME_OUT` prior to including the header file. +```cpp +#define TL_RESPONSE_TIME_OUT 500000 // Timeout in us. Default is 100000 +#include +``` + +In some edge cases the sender may be significantly slower than the receiver at switching between transmit and receive modes. This could result in the receiver sending a response before the sender has a chance to listen for it. A delay can be added between receiving a packet and acknowledging it by defining `TL_RESPONSE_DELAY` prior to including the header file. Keep this as short as possible. +```cpp +#define TL_RESPONSE_DELAY 30 // Delay between receiving a packet and sending a response in ms. (default 0) +#define TL_RESPONSE_TIME_OUT 500000 // Timeout in us. Default is 100000 +#include +``` ### Safety warning In all cases, when installing or maintaining a PJON network, extreme care must be taken to avoid any danger. Before any practical test or hardware purchase for a wireless [ThroughLoRa](/src/strategies/ThroughLoRa) radio setup, compliance with government requirements and regulations must be ensured. diff --git a/src/strategies/ThroughLoRa/ThroughLora.h b/src/strategies/ThroughLoRa/ThroughLora.h index 5247f23035..7684f971c7 100644 --- a/src/strategies/ThroughLoRa/ThroughLora.h +++ b/src/strategies/ThroughLoRa/ThroughLora.h @@ -23,6 +23,11 @@ #include #include "Timing.h" +// Recommended receive time for this strategy, in microseconds +#ifndef TL_RECEIVE_TIME + #define TL_RECEIVE_TIME 0 +#endif + class ThroughLora { public: /* Returns the suggested delay related to the attempts @@ -84,11 +89,11 @@ class ThroughLora { LoRa.setTxPower(txPower, boostPin); }; - void idle(uint8_t txPower, uint8_t boostPin) { + void idle() { LoRa.idle(); }; - void sleep(uint8_t txPower, uint8_t boostPin) { + void sleep() { LoRa.sleep(); }; @@ -100,9 +105,7 @@ class ThroughLora { (returns always true) */ bool begin(uint8_t did = 0) { - PJON_DELAY_MICROSECONDS( - PJON_RANDOM(TL_INITIAL_DELAY) + did - ); + PJON_DELAY_MICROSECONDS(PJON_RANDOM(TL_INITIAL_DELAY) + did); return true; }; @@ -119,27 +122,57 @@ class ThroughLora { return TL_MAX_ATTEMPTS; }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { + return TL_RECEIVE_TIME; + }; + /* Handle a collision: */ void handle_collision() { PJON_DELAY_MICROSECONDS(PJON_RANDOM(TL_COLLISION_DELAY)); }; + /* The last 5 bytes of the frame are used as a unique identifier within + the response. PJON has CRC8 or CRC32 at the end of the packet, encoding + a CRC (that is a good hashing algorithm) and using 40 bits looks enough + to provide a relatively safe response that should be nearly flawless + (yield few false positives per millennia). */ + + void prepare_response(const uint8_t *buffer, uint16_t position) { + for(int8_t i = 0; i < TL_RESPONSE_LENGTH; i++) + _response[i] = + buffer[(position - ((TL_RESPONSE_LENGTH - 1) - i)) - 1]; + }; + /* Receive byte response (not supported) */ uint16_t receive_response() { - return PJON_ACK; + uint32_t time = PJON_MICROS(); + while((uint32_t)(PJON_MICROS() - time) < TL_RESPONSE_TIME_OUT) { + uint8_t frame_size = LoRa.parsePacket(); + if(frame_size == TL_RESPONSE_LENGTH) { + for(uint8_t i = 0; i < TL_RESPONSE_LENGTH; i++) + if(LoRa.read() != _response[i]) return PJON_FAIL; + return PJON_ACK; + } + } + return PJON_FAIL; }; /* Receive a frame: */ uint16_t receive_frame(uint8_t *data, uint16_t max_length) { uint8_t frameSize = LoRa.parsePacket(); - if(frameSize > 0) { + /* Filter frames if too short to contain a PJON packet + or if too long to be received */ + if((frameSize > 5) && (frameSize <= max_length)) { while(LoRa.available()) { *data = LoRa.read(); data++; } + prepare_response(data - frameSize, frameSize); return frameSize; } else return PJON_FAIL; }; @@ -153,7 +186,15 @@ class ThroughLora { /* Send byte response to the packet's transmitter (not supported) */ void send_response(uint8_t response) { - return; + if(response == PJON_ACK) { + start_tx(); + #if TL_RESPONSE_DELAY != 0 + PJON_DELAY(TL_RESPONSE_DELAY); + #endif + for(uint8_t i = 0; i < TL_RESPONSE_LENGTH; i++) + send_byte(_response[i]); + end_tx(); + } }; /* Send a frame: */ @@ -162,6 +203,7 @@ class ThroughLora { start_tx(); for(uint8_t b = 0; b < length; b++) send_byte(data[b]); + prepare_response(data, length); end_tx(); }; @@ -175,4 +217,5 @@ class ThroughLora { private: uint32_t _last_reception_time; + uint8_t _response[TL_RESPONSE_LENGTH]; }; diff --git a/src/strategies/ThroughLoRa/Timing.h b/src/strategies/ThroughLoRa/Timing.h index 732fa9a759..061b131bf5 100644 --- a/src/strategies/ThroughLoRa/Timing.h +++ b/src/strategies/ThroughLoRa/Timing.h @@ -32,15 +32,31 @@ Higher if necessary. */ #ifndef TL_RESPONSE_TIME_OUT - #define TL_RESPONSE_TIME_OUT 100000UL + #define TL_RESPONSE_TIME_OUT 100000 +#endif + +/* Set an optional delay (in ms) before responding if the receiver is particularly + slow at swapping between transmit and receive modes. */ +#ifndef TL_RESPONSE_DELAY + #define TL_RESPONSE_DELAY 0 #endif /* Maximum transmission attempts (re-transmission not supported) */ #ifndef TL_MAX_ATTEMPTS - #define TL_MAX_ATTEMPTS 0 + #define TL_MAX_ATTEMPTS 5 #endif /* Back-off exponential degree (re-transmission not supported) */ #ifndef TL_BACK_OFF_DEGREE - #define TL_BACK_OFF_DEGREE 1 + #define TL_BACK_OFF_DEGREE 5 +#endif + +/* Response length (the response is composed by the last TL_RESPONSE_LENGTH + bytes of the packet received). By default should be relatively safe. + (Few false positives per millennia) + If you are ready to trade safety for bandwidth reduce it, consider that + setting TL_RESPONSE_LENGTH < 4 reduces reliability and leads to higher + chances of detecting a false positive. */ +#ifndef TL_RESPONSE_LENGTH + #define TL_RESPONSE_LENGTH 5 #endif diff --git a/src/strategies/ThroughSerial/README.md b/src/strategies/ThroughSerial/README.md index ed33d6ab06..5092d17c32 100644 --- a/src/strategies/ThroughSerial/README.md +++ b/src/strategies/ThroughSerial/README.md @@ -1,41 +1,48 @@ ## ThroughSerial -**Medium:** Hardware/Software Serial port | -**Pins used:** 1 or 2 +| Medium | Pins used | Inclusion | +|--------|-----------|--------------------| +| Wires | 2 | `#include `| -With `ThroughSerial` strategy, PJON can run through a software or hardware Serial port working out-of-the-box with many Arduino compatible serial transceivers, like RS485 or radio modules like HC-12 (HCMODU0054). Take a look at the [video introduction](https://www.youtube.com/watch?v=H4jUsgvM-lw) for a brief showcase of its features. It complies with [TSDL v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md). +With `ThroughSerial` strategy, PJON can run through a software or hardware Serial port working out of the box with many Arduino compatible serial transceivers, like RS485 or radio modules like HC-12 (HCMODU0054). It complies with [TSDL v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md). + +This strategy is based upon the obsolete blocking implementation although reception is now asynchronous and completely non-blocking. It is not required to call `bus.receive()` with any delay, just call it frequently to see if there are any packets that have been received. ### Why PJON over Serial? -Serial communication is fast and reliable but it is often useless without all the features PJON contains. `ThroughSerial` has been developed to enable PJON communication through a serial data link. Adding PJON on top of Serial it is possible to leverage of the PJON protocol layer features like acknowledge, addressing, multiplexing, packet handling, 8 or 32-bit CRC and traffic control. +Serial communication is fast and reliable but it is often useless without all the features PJON contains. `ThroughSerial` has been developed to enable PJON communication through a serial data link. Adding PJON on top of Serial it is possible to leverage of the PJON protocol layer features like acknowledge, addressing, multiplexing, packet handling, 8 or 32-bit CRC and traffic control. -Being impossible to detect or avoid collisions over a serial port, `ThroughSerial` has been developed primarily to be used in master-slave mode. `ThroughSerial` in multi-master mode, being unable to detect or avoid collisions, operates using the slotted ALOHA medium access method. Of all contention based random multiple access methods, slotted ALOHA, which maximum data throughput is only 36.8% of the available bandwidth, is one of the least efficient and should not be applied in networks where many devices often need to arbitrarily transmit data. +`ThroughSerial` implements a variation of CSMA (Carrier Sense Multiple Access). It is able to avoid collision with an ongoing frame transmission but cannot detect or avoid same-time collisions. The reception phase is entirely non-blocking although sending and acknowledgement are still blocking. ### Configuration -Before including `PJON.h` it is possible to configure `ThroughSerial` using predefined constants: +Before including the library it is possible to configure `ThroughSerial` using predefined constants: | Constant | Purpose | Supported value | | ----------------------- |------------------------------------ | ------------------------------------------ | -| `TS_BYTE_TIME_OUT` | Maximum byte response time-out | Duration in microseconds (50000 by default) | -| `TS_RESPONSE_TIME_OUT` | Maximum response time-out | Duration in microseconds (10000 by default) | -| `TS_BACK_OFF_DEGREE` | Maximum back-off exponential degree | Numeric value (4 by default) | -| `TS_MAX_ATTEMPTS` | Maximum transmission attempts | Numeric value (20 by default) | - +| `TS_READ_INTERVAL` | Minimum interval between receptions | Duration in microseconds (100 by default) | +| `TS_BYTE_TIME_OUT` | Maximum byte reception time-out | Duration in microseconds (1000000 by default) | +| `TS_RESPONSE_TIME_OUT` | Maximum response time-out | Duration in microseconds (45000 by default) | +| `TS_BACK_OFF_DEGREE` | Maximum back-off exponential degree | Numeric value (4 by default) | +| `TS_MAX_ATTEMPTS` | Maximum transmission attempts | Numeric value (20 by default) | -Pass the `ThroughSerial` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. +Use `PJONThroughSerial` to instantiate a PJON object ready to communicate using `ThroughSerial` strategy: ```cpp -PJON bus; +#include +PJONThroughSerial bus; ``` Call the `begin` method on the `Serial` or `SoftwareSerial` object you want to use for PJON communication and pass it to the `set_serial` method: ```cpp -#include - -PJON bus; +#include +PJONThroughSerial bus; void setup() { Serial.begin(9600); bus.strategy.set_serial(&Serial); } ``` +There is a default reception interval of 100 microseconds used to allow data to accumulate in the hardware UART buffer. This value is configurable using `bus.strategy.set_read_interval(100)` passing an arbitrary interval in microseconds. The read interval may require adjustment depending on UART RX buffer size and baud rate. +```cpp +bus.strategy.set_read_interval(100); +``` For a simple use with RS485 serial modules a transmission enable pin setter has been added: ```cpp bus.strategy.set_enable_RS485_pin(11); @@ -47,20 +54,10 @@ bus.strategy.set_RS485_rxe_pin(11); // Set RS485 transmission enable pin bus.strategy.set_RS485_txe_pin(12); ``` -In some cases it may be required to add a delay before disabling the RS485 pins txe and or rxe: -```cpp -// Set RS485 txe/rxe pins disable delay in milliseconds -bus.strategy.set_RS485_delay(1); -``` - -See [RS485-Blink](../../../examples/ARDUINO/Local/ThroughSerial/RS485-Blink) and [RS485-AsyncAck](../../../examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck) examples. - -HC-12 wireless module supports both synchronous and asynchronous acknowledgement, see [HC-12-Blink](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-Blink), [HC-12-SendAndReceive](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive), [HC-12-LocalChat](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-LocalChat) and [HC-12-AsyncAck](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck) examples. +See the [BlinkTest](../../../examples/ARDUINO/Local/ThroughSerial/BlinkTest) and [BlinkWithResponse](https://github.com/gioblu/PJON/tree/master/examples/ARDUINO/Local/ThroughSerial/BlinkWithResponse) examples, if you need to interface devices using RS485 see the [RS485-Blink](../../../examples/ARDUINO/Local/ThroughSerial/RS485-Blink) example. HC-12 wireless module supports the synchronous acknowledgement, see [HC-12-Blink](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-Blink), [HC-12-SendAndReceive](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive) and [HC-12-LocalChat](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-LocalChat) examples. All the other necessary information is present in the general [Documentation](/documentation). ### Known issues -- Being PJON not an interrupt driven, its communication can be affected and potentially disrupted by long delays added in the user's sketch. Try to reduce as possible the interval between every `receive` call. - -### Safety warning -In all cases, when installing or maintaining a PJON network, extreme care must be taken to avoid any danger. Before any practical test or hardware purchase for a wireless [ThroughSerial](/src/strategies/ThroughSerial) radio setup, compliance with government requirements and regulations must be ensured. +- Transmission is still blocking, will be made non-blocking in the next versions. +- acknowledgement procedure is still blocking, will be made non-blocking in the next versions. diff --git a/src/strategies/ThroughSerial/ThroughSerial.h b/src/strategies/ThroughSerial/ThroughSerial.h index 0f23990df8..fa2d72f90c 100644 --- a/src/strategies/ThroughSerial/ThroughSerial.h +++ b/src/strategies/ThroughSerial/ThroughSerial.h @@ -1,20 +1,19 @@ -/* ThroughSerial digital communication data link layer - used as a Strategy by the PJON framework (included in version v4.1) +/* ThroughSerial data link layer + used as a Strategy by the PJON framework (included in version v11.2) Compliant with TSDL (Tardy Serial Data Link) specification v2.0 Contributors: + - sticilface async reception development - Fred Larsen, Development, testing and debugging - Zbigniew Zasieczny, collision avoidance multi-drop RS485 (latency) and SoftwareSerial compatibility - Franketto (Arduino forum user) RS485 TX enable pin compatibility - Endre Karlson separate RS485 enable pins handling, flush timing hack - - hyndruide github user added set_RS485_delay - - fabpolli github user RS485 missing ack delay report and testing ___________________________________________________________________________ - ThroughSerial, - copyright 2016-2018 by Giovanni Blu Mitolo All rights reserved + ThroughSerial, based on ThroughSerial, developed by sticilface + copyright 2018 by Giovanni Blu Mitolo All rights reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,23 +29,38 @@ #pragma once -// START frame symbol 10010101 - 0x95 - • -#define TS_START 149 -// END frame symbol 11101010 - 0xea - ê -#define TS_END 234 -// ESCAPE symbol 10111011 - 0xBB - » -#define TS_ESC 187 +// START symbol 10010101 - 0x95 - • +#define TS_START 149 +// END symbol 11101010 - 0xea - ê +#define TS_END 234 +// ESCAPE symbol 10111011 - 0xBB - » +#define TS_ESC 187 // Used to signal communication failure -#define TS_FAIL 65535 - -// Used for pin handling -#define TS_NOT_ASSIGNED 255 +#define TS_FAIL 65535 +// Used for unused pin handling +#define TS_NOT_ASSIGNED 255 #include "Timing.h" +enum TS_state_t : uint8_t { + TS_WAITING, + TS_RECEIVING, + TS_WAITING_ESCAPE, + TS_WAITING_END, + TS_DONE +}; + +// Recommended receive time for this strategy, in microseconds +#ifndef TS_RECEIVE_TIME + #define TS_RECEIVE_TIME 0 +#endif + class ThroughSerial { public: + uint8_t buffer[PJON_PACKET_MAX_LENGTH] = {0}; + uint16_t position = 0; + TS_state_t state = TS_WAITING; PJON_SERIAL_TYPE serial; /* Returns suggested delay related to the attempts passed as parameter: */ @@ -55,16 +69,16 @@ class ThroughSerial { uint32_t result = attempts; for(uint8_t d = 0; d < TS_BACK_OFF_DEGREE; d++) result *= (uint32_t)(attempts); - return result; + return result + PJON_RANDOM(TS_COLLISION_DELAY); }; + /* Begin method, to be called on initialization: (returns always true) */ bool begin(uint8_t did = 0) { PJON_DELAY(PJON_RANDOM(TS_INITIAL_DELAY) + did); - _last_reception_time = 0; - _last_byte = receive_byte(); + _last_reception_time = PJON_MICROS(); return true; }; @@ -73,13 +87,23 @@ class ThroughSerial { bool can_start() { PJON_DELAY_MICROSECONDS(PJON_RANDOM(TS_COLLISION_DELAY)); - if(PJON_SERIAL_AVAILABLE(serial)) return false; - if((uint32_t)(PJON_MICROS() - _last_reception_time) < TS_TIME_IN) - return false; + if( + (state != TS_WAITING) || + PJON_SERIAL_AVAILABLE(serial) || + ((uint32_t)(PJON_MICROS() - _last_reception_time) < TS_TIME_IN) + ) return false; return true; }; + /* Function called when a frame reception fails */ + + uint16_t fail(TS_state_t s) { + state = s; + return (uint16_t)TS_FAIL; + } + + /* Returns the maximum number of attempts for each transmission: */ static uint8_t get_max_attempts() { @@ -87,6 +111,13 @@ class ThroughSerial { }; + /* Returns the recommended receive time for this strategy: */ + + static uint16_t get_receive_time() { + return TS_RECEIVE_TIME; + }; + + /* Handle a collision: */ void handle_collision() { @@ -94,67 +125,136 @@ class ThroughSerial { }; - /* Try to receive a byte with a maximum waiting time */ + /* Receive Byte */ + + int16_t receive_byte() { + int16_t value = PJON_SERIAL_READ(serial); + if(value == -1) return -1; + _last_reception_time = PJON_MICROS(); + return value; + }; + + + /* It returns the state of the previous transmission: */ - uint16_t receive_byte(uint32_t time_out = TS_BYTE_TIME_OUT) { + uint16_t receive_response() { + if(_fail) return TS_FAIL; uint32_t time = PJON_MICROS(); - while((uint32_t)(PJON_MICROS() - time) < time_out) { + uint8_t i = 0; + while((uint32_t)(PJON_MICROS() - time) < TS_RESPONSE_TIME_OUT) { if(PJON_SERIAL_AVAILABLE(serial)) { - _last_reception_time = PJON_MICROS(); int16_t read = PJON_SERIAL_READ(serial); - #if defined(_WIN32) - read = (uint8_t)read; - #endif + _last_reception_time = PJON_MICROS(); if(read >= 0) { - _last_byte = (uint8_t)read; - return _last_byte; + if(_response[i++] != read) return TS_FAIL; + if(i == TS_RESPONSE_LENGTH) return PJON_ACK; } } #if defined(_WIN32) - PJON_DELAY_MICROSECONDS(time_out / 10); + PJON_DELAY_MICROSECONDS(TS_RESPONSE_TIME_OUT / 10); #endif } return TS_FAIL; }; - /* Receive byte response */ - - uint16_t receive_response() { - return receive_byte(TS_RESPONSE_TIME_OUT); - }; - - - /* Receive a frame: */ + /* Receive a string: */ uint16_t receive_frame(uint8_t *data, uint16_t max_length) { - uint16_t result; - // No initial flag, byte-stuffing violation - if(max_length == PJON_PACKET_MAX_LENGTH) - if( - (receive_byte() != TS_START) || - (_last_byte == TS_ESC) - ) return TS_FAIL; + if( // Reception attempts are spaced by an interval + _last_call_time && + (uint32_t)(PJON_MICROS() - _last_call_time) < _read_interval + ) return TS_FAIL; + + _last_call_time = PJON_MICROS(); + + if( // If reception timeout is reached discard data + ( + (state == TS_RECEIVING) || + (state == TS_WAITING_END) || + (state == TS_WAITING_ESCAPE) + ) && + ((uint32_t)(PJON_MICROS() - _last_reception_time) > TS_BYTE_TIME_OUT) + ) return fail(TS_WAITING); + + switch(state) { + case TS_WAITING: { + while(PJON_SERIAL_AVAILABLE(serial)) { + int16_t value = receive_byte(); + if(value == -1) return TS_FAIL; + if(value == TS_START) { + position = 0; + return fail(TS_RECEIVING); + } + }; + break; + } + case TS_RECEIVING: { + while(PJON_SERIAL_AVAILABLE(serial)) { + int16_t value = receive_byte(); + if((value == TS_START) || (value == -1)) return fail(TS_WAITING); + if(value == TS_ESC) { + if(!PJON_SERIAL_AVAILABLE(serial)) + return fail(TS_WAITING_ESCAPE); + else { + value = receive_byte(); + if(value == -1) return fail(TS_WAITING); + value = value ^ TS_ESC; + if( + (value != TS_START) && + (value != TS_ESC) && + (value != TS_END) + ) return fail(TS_WAITING); + buffer[position++] = (uint8_t)value; + continue; + } + } + if(max_length == 1) + return fail(TS_WAITING_END); + if(position + 1 >= PJON_PACKET_MAX_LENGTH) + return fail(TS_WAITING); + if(value == TS_END) + return fail(TS_DONE); + buffer[position++] = (uint8_t)value; + } + return TS_FAIL; + } - result = receive_byte(); - if(result == TS_FAIL) return TS_FAIL; + case TS_WAITING_ESCAPE: { + if(PJON_SERIAL_AVAILABLE(serial)) { + int16_t value = receive_byte(); + if(value == -1) return fail(TS_WAITING); + value = value ^ TS_ESC; + if( + (value != TS_START) && + (value != TS_ESC) && + (value != TS_END) + ) return fail(TS_WAITING); + buffer[position++] = (uint8_t)value; + return fail(TS_RECEIVING); + } + break; + } - // Unescaped START byte stuffing violation - if(result == TS_START) return TS_FAIL; + case TS_WAITING_END: { + if(PJON_SERIAL_AVAILABLE(serial)) { + int16_t value = receive_byte(); + if(value == -1) return fail(TS_WAITING); + if(value == TS_END) return fail(TS_DONE); + else return fail(TS_WAITING); + } + break; + } - if(result == TS_ESC) { - result = receive_byte(); - result ^= TS_ESC; - // Avoid byte-stuffing violation - if((result != TS_START) && (result != TS_ESC) && (result != TS_END)) - return TS_FAIL; - } + case TS_DONE: { + memcpy(&data[0], &buffer[0], position); + prepare_response(buffer, position); + state = TS_WAITING; + return position; + } - // No end flag, byte-stuffing violation - if((max_length == 1) && (receive_byte() != TS_END)) - return TS_FAIL; - *data = (uint8_t)result; - return 1; + }; + return TS_FAIL; }; @@ -162,32 +262,57 @@ class ThroughSerial { void send_byte(uint8_t b) { uint32_t time = PJON_MICROS(); + int16_t result = 0; while( - (PJON_SERIAL_WRITE(serial, b) != 1) && + ((result = PJON_SERIAL_WRITE(serial, b)) != 1) && ((uint32_t)(PJON_MICROS() - time) < TS_BYTE_TIME_OUT) ); + if(result != 1) _fail = true; + }; + + + /* The last 5 bytes of the frame are used as a unique identifier within + the response. PJON has CRC8 or CRC32 at the end of the packet, encoding + a CRC (that is a good hashing algorithm) and using 40 bits looks enough + to provide a relatively safe response that should be nearly flawless + (yield few false positives per millennia). */ + + void prepare_response(const uint8_t *buffer, uint16_t position) { + uint8_t raw = 0; + for(int8_t i = 0; i < TS_RESPONSE_LENGTH; i++) { + raw = buffer[(position - ((TS_RESPONSE_LENGTH - 1) - i)) - 1]; + _response[i] = ( + (raw == TS_START) || (raw == TS_ESC) || (raw == TS_END) + ) ? (raw - 1) : raw; // Avoid encoding symbols + } }; + /* Send byte response to the packet's transmitter */ void send_response(uint8_t response) { - start_tx(); - wait_RS485_pin_change(); - send_byte(response); - PJON_SERIAL_FLUSH(serial); - wait_RS485_pin_change(); - end_tx(); + if(response == PJON_ACK) { + start_tx(); + wait_RS485_pin_change(); + for(uint8_t i = 0; i < TS_RESPONSE_LENGTH; i++) + send_byte(_response[i]); + PJON_SERIAL_FLUSH(serial); + wait_RS485_pin_change(); + end_tx(); + } }; - /* Send a frame: */ + /* Send a string: */ void send_frame(uint8_t *data, uint16_t length) { + _fail = false; start_tx(); uint16_t overhead = 2; // Add frame flag send_byte(TS_START); for(uint16_t b = 0; b < length; b++) { + if(_fail) return; // Byte-stuffing if( (data[b] == TS_START) || @@ -210,6 +335,8 @@ class ThroughSerial { #endif PJON_SERIAL_FLUSH(serial); end_tx(); + // Prepare expected response for the receive_response call + prepare_response(data, length); }; @@ -219,10 +346,6 @@ class ThroughSerial { serial = serial_port; }; - void wait_RS485_pin_change() { - if(_enable_RS485_txe_pin != TS_NOT_ASSIGNED) - PJON_DELAY(_RS485_delay); - }; /* RS485 enable pins handling: */ @@ -252,6 +375,7 @@ class ThroughSerial { _bd = baud; }; + /* Set flush timing offset in microseconds between expected and real serial byte transmission: */ @@ -260,6 +384,19 @@ class ThroughSerial { }; #endif + /* Sets the interval between each read attempt from serial + (TS_READ_INTERVAL or 100 microseconds by default) to allow the buffer + to fill and to reduce the computation time consumed while polling for + incoming data. */ + + uint32_t get_read_interval() { + return _read_interval; + }; + + void set_read_interval(uint32_t t) { + _read_interval = t; + }; + /* RS485 enable pins setters: */ void set_enable_RS485_pin(uint8_t pin) { @@ -276,8 +413,9 @@ class ThroughSerial { PJON_IO_MODE(_enable_RS485_txe_pin, OUTPUT); } - void set_RS485_delay(uint32_t d) { - _RS485_delay = d; + void wait_RS485_pin_change() { + if(_enable_RS485_txe_pin != TS_NOT_ASSIGNED) + PJON_DELAY(_RS485_delay); }; private: @@ -285,9 +423,12 @@ class ThroughSerial { uint16_t _flush_offset = TS_FLUSH_OFFSET; uint32_t _bd; #endif - uint8_t _last_byte; - uint32_t _last_reception_time; + bool _fail = false; + uint8_t _response[TS_RESPONSE_LENGTH]; + uint32_t _last_reception_time = 0; + uint32_t _last_call_time = 0; uint8_t _enable_RS485_rxe_pin = TS_NOT_ASSIGNED; uint8_t _enable_RS485_txe_pin = TS_NOT_ASSIGNED; uint32_t _RS485_delay = TS_RS485_DELAY; + uint32_t _read_interval = TS_READ_INTERVAL; }; diff --git a/src/strategies/ThroughSerial/Timing.h b/src/strategies/ThroughSerial/Timing.h index d0d58984fd..c7a1842ca9 100644 --- a/src/strategies/ThroughSerial/Timing.h +++ b/src/strategies/ThroughSerial/Timing.h @@ -8,7 +8,8 @@ - Franketto (Arduino forum user) RS485 TX enable pin compatibility ____________________________________________________________________________ - ThroughSerial, Copyright (c) 2016 by Giovanni Blu Mitolo All rights reserved. + Based on ThroughSerial, developed by sticilface + copyright 2018 by Giovanni Blu Mitolo All rights reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,30 +30,48 @@ #define TS_INITIAL_DELAY 1000 #endif -/* Maximum 32 microseconds random delay in case of collision */ +/* Maximum 64 microseconds random delay in case of collision */ #ifndef TS_COLLISION_DELAY - #define TS_COLLISION_DELAY 32 + #define TS_COLLISION_DELAY 64 #endif -/* Set 10 milliseconds as the maximum timeframe between transmission and - synchronous acknowledgement response. This value is strictly related to the - maximum time needed by receiver to receive, compute and transmit a response. - Higher if necessary. */ +/* Set 45 milliseconds as the maximum timeframe between transmission and + synchronous acknowledgement response. Its optimal configuration is + strictly related to the maximum time needed by receiver to receive, compute + and transmit back a response. Set TS_RESPONSE_TIME_OUT to 0 and do not use + the acknowledgement feature if the system operates in master-slave mode and + or applies the request-response scheme. */ #ifndef TS_RESPONSE_TIME_OUT - #define TS_RESPONSE_TIME_OUT 10000 + #define TS_RESPONSE_TIME_OUT 45000 #endif -/* Minum timeframe with channel free for use before transmission. - (Avoid disrupting synchronous acknowledgement exchange) */ +/* Minum duration of channel free for use before transmission, used to avoid + disrupting an ongoing acknowledgement exchange. Set TS_TIME_IN to 0 and do + not use the acknowledgement feature if the system operates in master-slave + mode and or applies the request-response scheme. */ #ifndef TS_TIME_IN #define TS_TIME_IN TS_RESPONSE_TIME_OUT + TS_COLLISION_DELAY #endif -/* Set 50 milliseconds as the maximum timeframe for byte reception. - This value depends on the latency, baud rate and computation time. - Always set TS_BYTE_TIME_OUT > (byte transmission time + latency) */ +/* Set 100 microseconds as the interval between each byte read. + Depending on the latency, baud rate and computation time the + optimal TS_READ_INTERVAL value may variate. + Always set: TS_READ_INTERVAL > (byte transmission time + latency) */ +#ifndef TS_READ_INTERVAL + #define TS_READ_INTERVAL 100 +#endif + +/* Byte reception timeout (Default 1 second) */ #ifndef TS_BYTE_TIME_OUT - #define TS_BYTE_TIME_OUT 50000 + #define TS_BYTE_TIME_OUT 1000000 +#endif + +/* Response length (the response is composed by the last TS_RESPONSE_LENGTH + bytes of the packet received). Setting TS_RESPONSE_LENGTH < 4 when using + ThroughSerial in multi-master mode reduces reliability and leads to higher + chances of detecting a false positive. */ +#ifndef TS_RESPONSE_LENGTH + #define TS_RESPONSE_LENGTH 1 #endif /* Maximum transmission attempts */ @@ -62,12 +81,12 @@ /* Back-off exponential degree */ #ifndef TS_BACK_OFF_DEGREE - #define TS_BACK_OFF_DEGREE 4 + #define TS_BACK_OFF_DEGREE 4 #endif /* Delay before enabling and disabling RS485 DE and or RE pin */ #ifndef TS_RS485_DELAY - #define TS_RS485_DELAY 1 + #define TS_RS485_DELAY 1 #endif /* Force blocking sending hack (adds a delay for each character sent). */ diff --git a/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md b/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md similarity index 52% rename from src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md rename to src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md index c747c96c9b..8b38ca2648 100644 --- a/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md +++ b/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md @@ -1,24 +1,23 @@ ### Specifications index #### Network layer -- [PJON (Padded Jittering Operative Network) v3.2](/specification/PJON-protocol-specification-v3.2.md) -- [Acknowledge specification v1.0](/specification/PJON-protocol-acknowledge-specification-v1.0.md) +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) - [Network services list](/specification/PJON-network-services-list.md) #### Data link layer -- [PJDL (Padded Jittering Data Link) v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) +- [PJDL (Padded Jittering Data Link) v5.0](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v5.0.md) - [PJDLR (Padded Jittering Data Link over Radio) v3.0](/src/strategies/OverSampling/specification/PJDLR-specification-v3.0.md) - [PJDLS (Padded Jittering Data Link byte Stuffed) v2.0](/src/strategies/AnalogSampling/specification/PJDLS-specification-v2.0.md) -- **[TSDL (Tardy Serial Data Link) v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md)** +- **[TSDL (Tardy Serial Data Link) v3.0](/src/strategies/ThroughSerial/specification/TSDL-specification-v3.0.md)** - [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) --- -## TSDL v2.1 +## TSDL v3.0 ``` Invented by Giovanni Blu Mitolo -Originally published: 20/11/2017, latest revision: 9/11/2018 +Originally published: 20/11/2017, latest revision: 09/05/2020 Related implementation: /src/strategies/ThroughSerial/ -Compliant versions: PJON v10.0 and following +Compliant versions: PJON v13.0 and following Released into the public domain ``` TSDL (Tardy Serial Data Link) is a simplex or half-duplex serial data link that supports both master-slave and multi-master modes. It supports collision avoidance, reliable frame separation and optional synchronous response to frame transmissions. @@ -32,19 +31,21 @@ TSDL (Tardy Serial Data Link) is a simplex or half-duplex serial data link that TSDL can be used to establish a point-to-point link between two devices if used with a bare serial link, or to support one or many to many communication using radio or RS485 transceivers. ### Medium access control -TSDL operates in master-slave mode applying the request-response procedure. Being impossible to implement a carrier-sense procedure over a serial port TSDL uses variation of slotted ALOHA medium access method for multi-master mode. Before a frame transmission the serial buffer is read, if not empty ongoing communication is detected and collision avoided, if empty for a duration longer than the response time-out plus a short random time, frame transmission starts in which the packet is entirely transmitted. Of all contention based random multiple access methods, slotted ALOHA, which maximum data throughput is only 36.8% of the available bandwidth, is one of the least efficient, therefore TSDL in multi-master mode should not be used in networks where many devices often need to arbitrarily transmit data. +TSDL operates in master-slave mode applying the request-response procedure and specifies a variation of slotted ALOHA medium access method for multi-master mode. Before a frame transmission the serial buffer is read, if not empty ongoing communication is detected and collision avoided, if empty for a duration longer than the response time-out plus a short random time, frame transmission starts in which the packet is entirely transmitted. Of all contention based random multiple access methods, slotted ALOHA, which maximum data throughput is only 36.8% of the available bandwidth, is one of the least efficient, therefore TSDL in multi-master mode should not be used in networks where many devices often need to arbitrarily transmit data. ### Frame transmission Before a frame transmission the communication medium is analysed, if any data is received communication is detected and collision is avoided, if logic 0 is detected for a duration longer than the response time-out plus a small random time, data is transmitted encapsulated in a [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) frame. ### Synchronous response -A frame transmission in both master-slave and multi-master modes can be optionally followed by a synchronous response of its recipient, all devices must use the same response time-out to avoid collisions. The acknowledgment reception phase must be shorter than the response time-out to be successful. +A frame transmission in both master-slave and multi-master modes can be optionally followed by a synchronous response of its recipient, all devices must use the same response time-out to avoid collisions. The acknowledgment reception phase must occur before the response time-out to be successful. The synchronous response is composed by the last 5 bytes of the received frame that are used by both devices as the frame identifier. If any SFSP flag occurs in the response payload its value is reduced by 1. PJON has a CRC8 or CRC32 at the end of the packet, encoding a CRC (that is a good hashing algorithm) and using 40 bits looks enough to provide a relatively safe response that should yield few false positives per millennia. ```cpp -Transmission Response - _______ ______ ______ _____ _____ -| START || BYTE || BYTE || END | CRC COMPUTATION | ACK | -|-------||------||------||-----|-----------------|-----| -| 149 || H || I || 234 | LATENCY | 6 | -|_______||______||______||_____| |_____| + Transmission Response + _____ ____ ____ ____ ____ ____ ___ _____ + |START|BYTE|BYTE|BYTE|BYTE|BYTE|END| | ACK | + |-----|----|----|----|----|----|---|--|-----| + | 149 | C | I | A | O | ! |234| |CIAO!| + |_____|____|____|____|____|____|___| |_____| +BITS: | 8 | 8 | 8 | 8 | 8 | 8 | 8 | | 40 | + |_____|____|____|____|____|____|___| |_____| ``` The required response time-out for a given application can be determined practically transmitting the longest supported frame with the farthest physical distance between the two devices. The highest interval between packet transmission and acknowledgement measured plus a small margin is the correct time-out that should exclude acknowledgement losses. diff --git a/src/strategies/ThroughSerial/specification/obsolete/TSDL-specification-v2.0.md b/src/strategies/ThroughSerial/specification/obsolete/TSDL-specification-v2.0.md index 5c7f979d78..81e9893199 100644 --- a/src/strategies/ThroughSerial/specification/obsolete/TSDL-specification-v2.0.md +++ b/src/strategies/ThroughSerial/specification/obsolete/TSDL-specification-v2.0.md @@ -1,13 +1,21 @@ -## TSDL v2.0 -``` -Invented by Giovanni Blu Mitolo -Originally published: 20/11/2017, latest revision: 9/11/2018 +```cpp +/* +Milan, Italy +Originally published: 20/11/2017 +TSDL (Tardy Serial Data Link) v2.0 specification +Invented by Giovanni Blu Mitolo, +released into the public domain + Related implementation: /src/strategies/ThroughSerial/ Compliant versions: PJON v10.0 and following -Released into the public domain +Changelog: +- Frame separation provided by SFSP v1.0 +*/ ``` -TSDL (Tardy Serial Data Link) is a simplex or half-duplex serial data link that supports both master-slave and multi-master modes. It supports collision avoidance, reliable frame separation and optional synchronous response to frame transmissions. + +### TSDL v2.0 +TSDL (Tardy Serial Data Link) is a simplex or half-duplex serial data link that supports both master-slave and multi-master configuration. It supports collision avoidance, reliable frame separation and optional synchronous response to frame transmissions. ```cpp ______ TX RX ______ | |-------| | @@ -15,16 +23,18 @@ TSDL (Tardy Serial Data Link) is a simplex or half-duplex serial data link that |______|-------|______| RX TX ``` -TSDL can be used to establish a point-to-point link between two devices if used with a bare serial link, or to support one or many to many communication using radio or RS485 transceivers. +TSDL can be used to establish a point-to-point link between two devices if used with a bare serial link, or supporting one or many to many communication with physical layers that are supporting this feature, like serial radio or RS485 transceivers. -### Medium access control -TSDL operates in master-slave mode applying the request-response procedure. Being impossible to implement a carrier-sense procedure over a serial port TSDL uses variation of slotted ALOHA medium access method for multi-master mode. Before a frame transmission the serial buffer is read, if not empty ongoing communication is detected and collision avoided, if empty for a duration longer than the response time-out plus a short random time, frame transmission starts in which the packet is entirely transmitted. Of all contention based random multiple access methods, slotted ALOHA, which maximum data throughput is only 36.8% of the available bandwidth, is one of the least efficient, therefore TSDL in multi-master mode should not be used in networks where many devices often need to arbitrarily transmit data. +### Basic concepts +* Frame separation support provided by [SFSP v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) +* Support collision avoidance +* Support optional 1 byte synchronous response to frame transmissions -### Frame transmission -Before a frame transmission the communication medium is analysed, if any data is received communication is detected and collision is avoided, if logic 0 is detected for a duration longer than the response time-out plus a small random time, data is transmitted encapsulated in a [SFSP (Secure Frame Separation Protocol) v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) frame. +#### Collision avoidance +Before a frame transmission, the serial buffer is read, if not empty ongoing communication is detected and collision avoided, if empty for a duration longer than the time-in (that should be common on all connected devices) before transmission, plus a short random time, frame transmission starts in which the packet is entirely transmitted. -### Synchronous response -A frame transmission in both master-slave and multi-master modes can be optionally followed by a synchronous response of its recipient, all devices must use the same response time-out to avoid collisions. The acknowledgment reception phase must be shorter than the response time-out to be successful. +#### Synchronous response +A frame transmission can be optionally followed by a synchronous response by its recipient. ```cpp Transmission Response _______ ______ ______ _____ _____ @@ -33,4 +43,4 @@ Transmission Response | 149 || H || I || 234 | LATENCY | 6 | |_______||______||______||_____| |_____| ``` -The required response time-out for a given application can be determined practically transmitting the longest supported frame with the farthest physical distance between the two devices. The highest interval between packet transmission and acknowledgement measured plus a small margin is the correct time-out that should exclude acknowledgement losses. +Between frame transmission and a synchronous response there is a variable timeframe influenced by latency and CRC computation time. The maximum time dedicated to potential acknowledgement reception must be shorter than the transmission time-in (to avoid other devices to disrupt a response exchange) and it is estimated adding the maximum frame length CRC computation time to the expected latency. diff --git a/src/strategies/ThroughSerialAsync/specification/TSDL-specification-v2.1.md b/src/strategies/ThroughSerial/specification/obsolete/TSDL-specification-v2.1.md similarity index 95% rename from src/strategies/ThroughSerialAsync/specification/TSDL-specification-v2.1.md rename to src/strategies/ThroughSerial/specification/obsolete/TSDL-specification-v2.1.md index c747c96c9b..0dd6783371 100644 --- a/src/strategies/ThroughSerialAsync/specification/TSDL-specification-v2.1.md +++ b/src/strategies/ThroughSerial/specification/obsolete/TSDL-specification-v2.1.md @@ -1,8 +1,7 @@ ### Specifications index #### Network layer -- [PJON (Padded Jittering Operative Network) v3.2](/specification/PJON-protocol-specification-v3.2.md) -- [Acknowledge specification v1.0](/specification/PJON-protocol-acknowledge-specification-v1.0.md) +- [PJON (Padded Jittering Operative Network) v4.0](/specification/PJON-protocol-specification-v4.0.md) - [Network services list](/specification/PJON-network-services-list.md) #### Data link layer - [PJDL (Padded Jittering Data Link) v4.1](/src/strategies/SoftwareBitBang/specification/PJDL-specification-v4.1.md) diff --git a/src/strategies/ThroughSerialAsync/README.md b/src/strategies/ThroughSerialAsync/README.md deleted file mode 100644 index 245ac68c92..0000000000 --- a/src/strategies/ThroughSerialAsync/README.md +++ /dev/null @@ -1,68 +0,0 @@ -## ThroughSerialAsync - -**Medium:** Hardware/Software Serial port | -**Pins used:** 1 or 2 - -With `ThroughSerialAsync` strategy, PJON can run through a software or hardware Serial port working out of the box with many Arduino compatible serial transceivers, like RS485 or radio modules like HC-12 (HCMODU0054). It complies with [TSDL v2.1](/src/strategies/ThroughSerial/specification/TSDL-specification-v2.1.md). - -This strategy is based upon the `ThroughSerial` but reception is asynchronous and completely non-blocking, making good use of hardware buffers and sparing time that `ThroughSerial` looses polling. It is not required to call `bus.receive()` with any delay, just call it frequently to see if there are any packets that have been received. - -### Why PJON over Serial? -Serial communication is fast and reliable but it is often useless without all the features PJON contains. `ThroughAsyncSerial` has been developed to enable PJON communication through a serial data link. Adding PJON on top of Serial it is possible to leverage of the PJON protocol layer features like acknowledge, addressing, multiplexing, packet handling, 8 or 32-bit CRC and traffic control. - -Being impossible to detect or avoid collisions over a serial port, `ThroughSerial` has been developed primarily to be used in master-slave mode. `ThroughSerial` in multi-master mode, being unable to detect or avoid collisions, operates using the slotted ALOHA medium access method. Of all contention based random multiple access methods, slotted ALOHA, which maximum data throughput is only 36.8% of the available bandwidth, is one of the least efficient and should not be applied in networks where many devices often need to arbitrarily transmit data. - -`ThroughSerialAsync` performs well if used with ESP8266 and ESP32 where blocking procedures can strongly degrade functionality. The reception phase is entirely non-blocking. Sending and acknowledgement however are still blocking. - -There is a default reception interval of 100 microseconds used to allow data to accumulate in the hardware UART buffer. This value is configurable using `bus.strategy.set_read_interval(100)` passing an arbitrary interval in microseconds. The read interval may require adjustment depending on UART RX buffer size and baud rate. - -### Configuration -Before including `PJON.h` it is possible to configure `ThroughSerialAsync` using predefined constants: - -| Constant | Purpose | Supported value | -| ----------------------- |------------------------------------ | ------------------------------------------ | -| `TSA_READ_INTERVAL` | minimum interval between receptions | Duration in microseconds (100 by default) | -| `TSA_BYTE_TIME_OUT` | Maximum byte reception time-out | Duration in microseconds (1000000 by default) | -| `TSA_RESPONSE_TIME_OUT` | Maximum response time-out | Duration in microseconds (10000 by default) | -| `TSA_BACK_OFF_DEGREE` | Maximum back-off exponential degree | Numeric value (4 by default) | -| `TSA_MAX_ATTEMPTS` | Maximum transmission attempts | Numeric value (20 by default) | - -Pass the `ThroughSerial` type as PJON template parameter to instantiate a PJON object ready to communicate through this Strategy. -```cpp -#include PJON_INCLUDE_TSA -PJON bus; -``` -Call the `begin` method on the `Serial` or `SoftwareSerial` object you want to use for PJON communication and pass it to the `set_serial` method: -```cpp -#include - -PJON bus; - -void setup() { - Serial.begin(9600); - bus.strategy.set_serial(&Serial); - bus.strategy.set_read_interval(100); -} -``` -For a simple use with RS485 serial modules a transmission enable pin setter has been added: -```cpp -bus.strategy.set_enable_RS485_pin(11); -``` -If separate enable setters are needed use: -```cpp -// Set RS485 reception enable pin -bus.strategy.set_RS485_rxe_pin(11); -// Set RS485 transmission enable pin -bus.strategy.set_RS485_txe_pin(12); -``` -See the [Blink](../../../examples/ARDUINO/Local/ThroughSerialAsync/Blink) and [BlinkWithResponse](https://github.com/gioblu/PJON/tree/master/examples/ARDUINO/Local/ThroughSerialAsync/BlinkWithResponse) examples. - -Examples for `ThroughSerial` can be easily modifed to work with `ThroughSerialAsync`, see [RS485-Blink](../../../examples/ARDUINO/Local/ThroughSerial/RS485-Blink) and [RS485-AsyncAck](../../../examples/ARDUINO/Local/ThroughSerial/RS485-AsyncAck) examples. - -HC-12 wireless module supports both synchronous and asynchronous acknowledgement, see [HC-12-Blink](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-Blink), [HC-12-SendAndReceive](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-SendAndReceive), [HC-12-LocalChat](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-LocalChat) and [HC-12-AsyncAck](../../../examples/ARDUINO/Local/ThroughSerial/HC-12-AsyncAck) examples. - -All the other necessary information is present in the general [Documentation](/documentation). - -### Known issues -- Transmission is still blocking, will be made non-blocking in the next versions. -- acknowledgement procedure is still blocking, will be made non-blocking in the next versions. diff --git a/src/strategies/ThroughSerialAsync/ThroughSerialAsync.h b/src/strategies/ThroughSerialAsync/ThroughSerialAsync.h deleted file mode 100644 index 51117121cb..0000000000 --- a/src/strategies/ThroughSerialAsync/ThroughSerialAsync.h +++ /dev/null @@ -1,399 +0,0 @@ - -/* ThroughSerialAsync data link layer - used as a Strategy by the PJON framework (included in version v11.2) - Compliant with TSDL (Tardy Serial Data Link) specification v2.0 - - Contributors: - - sticilface async reception development - - Fred Larsen, Development, testing and debugging - - Zbigniew Zasieczny, collision avoidance multi-drop RS485 (latency) - and SoftwareSerial compatibility - - Franketto (Arduino forum user) RS485 TX enable pin compatibility - - Endre Karlson separate RS485 enable pins handling, flush timing hack - ___________________________________________________________________________ - - ThroughSerialAsync, based on ThroughSerial, developed by sticilface - copyright 2018 by Giovanni Blu Mitolo All rights reserved - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. */ - -#pragma once - -// START symbol 10010101 - 0x95 - • -#define TSA_START 149 -// END symbol 11101010 - 0xea - ê -#define TSA_END 234 -// ESCAPE symbol 10111011 - 0xBB - » -#define TSA_ESC 187 - -// Used to signal communication failure -#define TSA_FAIL 65535 -// Used for unused pin handling -#define TSA_NOT_ASSIGNED 255 - -#include "Timing.h" - -enum TSA_state_t : uint8_t { - TSA_WAITING, - TSA_RECEIVING, - TSA_WAITING_ESCAPE, - TSA_WAITING_END, - TSA_DONE -}; - -class ThroughSerialAsync { - public: - uint8_t buffer[PJON_PACKET_MAX_LENGTH] = {0}; - uint16_t position = 0; - TSA_state_t state = TSA_WAITING; - PJON_SERIAL_TYPE serial; - - /* Returns suggested delay related to the attempts passed as parameter: */ - - uint32_t back_off(uint8_t attempts) { - uint32_t result = attempts; - for (uint8_t d = 0; d < TSA_BACK_OFF_DEGREE; d++) - result *= (uint32_t)(attempts); - return result; - }; - - - /* Begin method, to be called on initialization: - (returns always true) */ - - bool begin(uint8_t did = 0) { - PJON_DELAY(PJON_RANDOM(TSA_INITIAL_DELAY) + did); - _last_reception_time = PJON_MICROS(); - return true; - }; - - - /* Check if the channel is free for transmission: */ - - bool can_start() { - if( - (state != TSA_WAITING) || - PJON_SERIAL_AVAILABLE(serial) || - ((uint32_t)(PJON_MICROS() - _last_reception_time) < TSA_TIME_IN) - ) return false; - PJON_DELAY_MICROSECONDS(PJON_RANDOM(TSA_COLLISION_DELAY)); - return true; - }; - - - /* Returns the maximum number of attempts for each transmission: */ - - static uint8_t get_max_attempts() { - return TSA_MAX_ATTEMPTS; - }; - - - /* Handle a collision: */ - - void handle_collision() { - PJON_DELAY_MICROSECONDS(PJON_RANDOM(TSA_COLLISION_DELAY)); - }; - - - /* Receive byte response */ - - uint16_t receive_response() { - uint32_t time = PJON_MICROS(); - while((uint32_t)(PJON_MICROS() - time) < TSA_RESPONSE_TIME_OUT) { - if(PJON_SERIAL_AVAILABLE(serial)) { - int16_t read = PJON_SERIAL_READ(serial); - _last_reception_time = PJON_MICROS(); - if(read >= 0) return (uint8_t)read; - } - #if defined(_WIN32) - PJON_DELAY_MICROSECONDS(TSA_RESPONSE_TIME_OUT / 10); - #endif - } - return TSA_FAIL; - }; - - - /* Receive a string: */ - - uint16_t receive_frame(uint8_t *data, uint16_t max_length) { - if( // Reception attempts are spaced by an interval - _last_call_time && - (uint32_t)(PJON_MICROS() - _last_call_time) < _read_interval - ) return TSA_FAIL; - - _last_call_time = PJON_MICROS(); - - if( // If reception timeout is reached discard data - ( - (state == TSA_RECEIVING) || - (state == TSA_WAITING_END) || - (state == TSA_WAITING_ESCAPE) - ) && - ((uint32_t)(PJON_MICROS() - _last_reception_time) > TSA_BYTE_TIME_OUT) - ) { - state = TSA_WAITING; - return TSA_FAIL; - } - - switch(state) { - case TSA_WAITING: { - while(PJON_SERIAL_AVAILABLE(serial)) { - uint8_t value = PJON_SERIAL_READ(serial); - _last_reception_time = PJON_MICROS(); - if(value == TSA_START) { - state = TSA_RECEIVING; - position = 0; - return TSA_FAIL; - } - }; - break; - } - case TSA_RECEIVING: { - while(PJON_SERIAL_AVAILABLE(serial)) { - uint8_t value = PJON_SERIAL_READ(serial); - _last_reception_time = PJON_MICROS(); - if(value == TSA_START) { - state = TSA_WAITING; - return TSA_FAIL; - } - if(value == TSA_ESC) { - if(!PJON_SERIAL_AVAILABLE(serial)) { - state = TSA_WAITING_ESCAPE; - return TSA_FAIL; - } else { - value = PJON_SERIAL_READ(serial) ^ TSA_ESC; - _last_reception_time = PJON_MICROS(); - if( - (value != TSA_START) && - (value != TSA_ESC) && - (value != TSA_END) - ) { - state = TSA_WAITING; - return TSA_FAIL; - } - buffer[position++] = value; - continue; - } - } - - if(max_length == 1) { - state = TSA_WAITING_END; - return TSA_FAIL; - } - - if(position + 1 >= PJON_PACKET_MAX_LENGTH) { - state = TSA_WAITING; - return TSA_FAIL; - } - - if(value == TSA_END) { - state = TSA_DONE; - return TSA_FAIL; - } - - buffer[position++] = value; - } - return TSA_FAIL; - } - - case TSA_WAITING_ESCAPE: { - if(PJON_SERIAL_AVAILABLE(serial)) { - uint8_t value = PJON_SERIAL_READ(serial) ^ TSA_ESC; - _last_reception_time = PJON_MICROS(); - if( - (value != TSA_START) && - (value != TSA_ESC) && - (value != TSA_END) - ) { - state = TSA_WAITING; - return TSA_FAIL; - } - buffer[position++] = value; - state = TSA_RECEIVING; - return TSA_FAIL; - } - break; - } - - case TSA_WAITING_END: { - if(PJON_SERIAL_AVAILABLE(serial)) { - uint8_t value = PJON_SERIAL_READ(serial); - _last_reception_time = PJON_MICROS(); - if(value == TSA_END) { - state = TSA_DONE; - return TSA_FAIL; - } else { - state = TSA_WAITING; - return TSA_FAIL; - } - } - break; - } - - case TSA_DONE: { - memcpy(&data[0], &buffer[0], position); - state = TSA_WAITING; - return position; - } - - }; - return TSA_FAIL; - }; - - - /* Send a byte and wait for its transmission end */ - - void send_byte(uint8_t b) { - uint32_t time = PJON_MICROS(); - while( - (PJON_SERIAL_WRITE(serial, b) != 1) && - ((uint32_t)(PJON_MICROS() - time) < TSA_BYTE_TIME_OUT) - ); - }; - - - /* Send byte response to the packet's transmitter */ - - void send_response(uint8_t response) { - start_tx(); - wait_RS485_pin_change(); - send_byte(response); - PJON_SERIAL_FLUSH(serial); - wait_RS485_pin_change(); - end_tx(); - }; - - - /* Send a string: */ - - void send_frame(uint8_t *data, uint16_t length) { - start_tx(); - uint16_t overhead = 2; - // Add frame flag - send_byte(TSA_START); - for(uint16_t b = 0; b < length; b++) { - // Byte-stuffing - if( - (data[b] == TSA_START) || - (data[b] == TSA_ESC) || - (data[b] == TSA_END) - ) { - send_byte(TSA_ESC); - send_byte(data[b] ^ TSA_ESC); - overhead++; - } else send_byte(data[b]); - } - send_byte(TSA_END); - /* On RPI flush fails to wait until all bytes are transmitted - here RPI forced to wait blocking using delayMicroseconds */ - #if defined(RPI) || defined(LINUX) - if(_bd) - PJON_DELAY_MICROSECONDS( - ((1000000 / (_bd / 8)) + _flush_offset) * (overhead + length) - ); - #endif - PJON_SERIAL_FLUSH(serial); - end_tx(); - }; - - - /* Pass the Serial port where you want to operate with */ - - void set_serial(PJON_SERIAL_TYPE serial_port) { - serial = serial_port; - }; - - - /* RS485 enable pins handling: */ - - void start_tx() { - if(_enable_RS485_txe_pin != TSA_NOT_ASSIGNED) { - PJON_IO_WRITE(_enable_RS485_txe_pin, HIGH); - if(_enable_RS485_rxe_pin != TSA_NOT_ASSIGNED) - PJON_IO_WRITE(_enable_RS485_rxe_pin, HIGH); - wait_RS485_pin_change(); - } - }; - - void end_tx() { - if(_enable_RS485_txe_pin != TSA_NOT_ASSIGNED) { - wait_RS485_pin_change(); - PJON_IO_WRITE(_enable_RS485_txe_pin, LOW); - if(_enable_RS485_rxe_pin != TSA_NOT_ASSIGNED) - PJON_IO_WRITE(_enable_RS485_rxe_pin, LOW); - } - }; - - #if defined(RPI) || defined(LINUX) - /* Pass baudrate to ThroughSerial - (needed only for RPI flush hack): */ - - void set_baud_rate(uint32_t baud) { - _bd = baud; - }; - - - /* Set flush timing offset in microseconds between expected and real - serial byte transmission: */ - - void set_flush_offset(uint16_t offset) { - _flush_offset = offset; - }; - #endif - - /* Sets the interval between each read attempt from serial - (TSA_READ_INTERVAL or 100 microseconds by default) to allow the buffer - to fill and to reduce the computation time consumed while polling for - incoming data. */ - - uint32_t get_read_interval() { - return _read_interval; - }; - - void set_read_interval(uint32_t t) { - _read_interval = t; - }; - - /* RS485 enable pins setters: */ - - void set_enable_RS485_pin(uint8_t pin) { - set_RS485_txe_pin(pin); - }; - - void set_RS485_rxe_pin(uint8_t pin) { - _enable_RS485_rxe_pin = pin; - PJON_IO_MODE(_enable_RS485_rxe_pin, OUTPUT); - } - - void set_RS485_txe_pin(uint8_t pin) { - _enable_RS485_txe_pin = pin; - PJON_IO_MODE(_enable_RS485_txe_pin, OUTPUT); - } - - void wait_RS485_pin_change() { - if(_enable_RS485_txe_pin != TSA_NOT_ASSIGNED) - PJON_DELAY(_RS485_delay); - }; - - private: - #if defined(RPI) || defined(LINUX) - uint16_t _flush_offset = TSA_FLUSH_OFFSET; - uint32_t _bd; - #endif - uint32_t _last_reception_time = 0; - uint32_t _last_call_time = 0; - uint8_t _enable_RS485_rxe_pin = TSA_NOT_ASSIGNED; - uint8_t _enable_RS485_txe_pin = TSA_NOT_ASSIGNED; - uint32_t _RS485_delay = TSA_RS485_DELAY; - uint32_t _read_interval = TSA_READ_INTERVAL; -}; diff --git a/src/strategies/ThroughSerialAsync/Timing.h b/src/strategies/ThroughSerialAsync/Timing.h deleted file mode 100644 index a271f4eff4..0000000000 --- a/src/strategies/ThroughSerialAsync/Timing.h +++ /dev/null @@ -1,84 +0,0 @@ -/* ThroughSerial digital communication data link layer - used as a Strategy by the PJON framework (included in version v4.1) - - Contributors: - - Fred Larsen, Development, testing and debugging - - Zbigniew Zasieczny, collision avoidance multi-drop RS485 (latency) - and SoftwareSerial compatibility - - Franketto (Arduino forum user) RS485 TX enable pin compatibility - ____________________________________________________________________________ - - ThroughSerialAsync timing, based on ThroughSerial, developed by sticilface - copyright 2018 by Giovanni Blu Mitolo All rights reserved - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. */ - -#pragma once - -/* Maximum 1 second random initial delay */ -#ifndef TSA_INITIAL_DELAY - #define TSA_INITIAL_DELAY 1000 -#endif - -/* Maximum 32 microseconds random delay in case of collision */ -#ifndef TSA_COLLISION_DELAY - #define TSA_COLLISION_DELAY 32 -#endif - -/* Set 10 milliseconds as the maximum timeframe between transmission and - synchronous acknowledgement response. Its optimal configuration is - strictly related to the maximum time needed by receiver to receive, compute - and transmit back an ACK (decimal 6) */ -#ifndef TSA_RESPONSE_TIME_OUT - #define TSA_RESPONSE_TIME_OUT 10000 -#endif - -/* Minum timeframe with channel free for use before transmission. - (Avoid disrupting synchronous acknowledgement exchange) */ -#ifndef TSA_TIME_IN - #define TSA_TIME_IN TSA_RESPONSE_TIME_OUT + TSA_COLLISION_DELAY -#endif - -/* Set 100 microseconds as the interval between each byte read. - Depending on the latency, baud rate and computation time the - optimal TSA_READ_INTERVAL value may variate. - Always set: TSA_READ_INTERVAL > (byte transmission time + latency) */ -#ifndef TSA_READ_INTERVAL - #define TSA_READ_INTERVAL 100 -#endif - -/* Byte reception timeout */ -#ifndef TSA_BYTE_TIME_OUT - #define TSA_BYTE_TIME_OUT 1000000 -#endif - -/* Maximum transmission attempts */ -#ifndef TSA_MAX_ATTEMPTS - #define TSA_MAX_ATTEMPTS 20 -#endif - -/* Back-off exponential degree */ -#ifndef TSA_BACK_OFF_DEGREE - #define TSA_BACK_OFF_DEGREE 4 -#endif - -/* Delay before enabling and disabling RS485 DE and or RE pin */ -#ifndef TSA_RS485_DELAY - #define TSA_RS485_DELAY 1 -#endif - -/* Force blocking sending hack (adds a delay for each character sent). */ - -#ifndef TSA_FLUSH_OFFSET - #define TSA_FLUSH_OFFSET 152 -#endif diff --git a/src/strategies/ThroughSerialAsync/specification/obsolete/TSDL-specification-v1.0.md b/src/strategies/ThroughSerialAsync/specification/obsolete/TSDL-specification-v1.0.md deleted file mode 100644 index 0dc73942b8..0000000000 --- a/src/strategies/ThroughSerialAsync/specification/obsolete/TSDL-specification-v1.0.md +++ /dev/null @@ -1,62 +0,0 @@ - -```cpp -/* -Milan, Italy -Originally published: 27/09/2017 -TSDL (Tardy Serial Data Link) v1.0 specification -Invented by Giovanni Blu Mitolo, -released into the public domain - -Related implementation: /src/strategies/ThroughSerial/ -Compliant versions: PJON v9.0 and following -*/ -``` -### TSDL v1.0 - -TSDL (Tardy Serial Data Link) is a simplex or half-duplex serial data link that supports both master-slave and multi-master configuration. It supports collision avoidance, reliable frame separation through byte stuffing and optional synchronous response to frame transmissions. - -### Basic concepts -* Use start, end and escape flags to support frame separation -* Support collision avoidance -* Support optional 1 byte synchronous response to frame transmissions - -```cpp - ______ TX RX ______ -| |-------| | -|DEVICE| |DEVICE| -|______|-------|______| - RX TX -``` -TSDL can be used to establish a point-to-point link between two devices if used with a bare serial link, or supporting one or many to many communication with physical layers that are supporting this feature, like serial radio or RS485 transceivers. - -#### Frame transmission -Before a frame transmission, the serial buffer is read, if not empty ongoing communication is detected and collision avoided, if empty for a duration longer than the time-in before transmission, frame transmission starts with `START` flag, followed by data bytes, if necessary escaped with `ESC` flag and terminates the frame with an `END` flag. -```cpp - ______________________________ - | DATA 1-65535 bytes | - _______ |______ _____ _______ ______| _____ -| START | | BYTE || ESC || START || BYTE | | END | -|-------| |------||-----||-------||------| |-----| -| 149 | | 23 || 76 || 149 || 52 | | 234 | -|_______| |______||_____||_______||______| |_____| - | - Flags inside data are escaped - -START: 149 - 10010101 - 0x95 - • -END: 234 - 11101010 - 0xea - ê -ESC: 187 - 10111011 - 0xBB - » -``` -`START` and `END` flag bytes are special characters that signal when a frame begins and ends. -Whenever any of the special character appears in the data, transmitter inserts a special `ESC` character before it, that will be ignored and excluded from data during the reception process. Any corrupted special character or data byte causes the receiver to discard the frame and be ready to receive the next one nominally. - -#### Synchronous response -A frame transmission can be optionally followed by a synchronous response by its recipient. -```cpp -Transmission Response - _______ ______ ______ _____ _____ -| START || BYTE || BYTE || END | CRC COMPUTATION | ACK | -|-------||------||------||-----|-----------------|-----| -| 149 || H || I || 234 | LATENCY | 6 | -|_______||______||______||_____| |_____| -``` -Between frame transmission and a synchronous response there is a variable timeframe influenced by latency and CRC computation time. The maximum time dedicated to potential acknowledgement reception must be shorter than the transmission time-in, to avoid other devices to disrupt a response exchange, and it is estimated adding the maximum frame length CRC computation time to the expected latency. diff --git a/src/strategies/ThroughSerialAsync/specification/obsolete/TSDL-specification-v2.0.md b/src/strategies/ThroughSerialAsync/specification/obsolete/TSDL-specification-v2.0.md deleted file mode 100644 index 81e9893199..0000000000 --- a/src/strategies/ThroughSerialAsync/specification/obsolete/TSDL-specification-v2.0.md +++ /dev/null @@ -1,46 +0,0 @@ - -```cpp -/* -Milan, Italy -Originally published: 20/11/2017 -TSDL (Tardy Serial Data Link) v2.0 specification -Invented by Giovanni Blu Mitolo, -released into the public domain - -Related implementation: /src/strategies/ThroughSerial/ -Compliant versions: PJON v10.0 and following -Changelog: -- Frame separation provided by SFSP v1.0 -*/ -``` - -### TSDL v2.0 -TSDL (Tardy Serial Data Link) is a simplex or half-duplex serial data link that supports both master-slave and multi-master configuration. It supports collision avoidance, reliable frame separation and optional synchronous response to frame transmissions. -```cpp - ______ TX RX ______ -| |-------| | -|DEVICE| |DEVICE| -|______|-------|______| - RX TX -``` -TSDL can be used to establish a point-to-point link between two devices if used with a bare serial link, or supporting one or many to many communication with physical layers that are supporting this feature, like serial radio or RS485 transceivers. - -### Basic concepts -* Frame separation support provided by [SFSP v1.0](/specification/SFSP-frame-separation-specification-v1.0.md) -* Support collision avoidance -* Support optional 1 byte synchronous response to frame transmissions - -#### Collision avoidance -Before a frame transmission, the serial buffer is read, if not empty ongoing communication is detected and collision avoided, if empty for a duration longer than the time-in (that should be common on all connected devices) before transmission, plus a short random time, frame transmission starts in which the packet is entirely transmitted. - -#### Synchronous response -A frame transmission can be optionally followed by a synchronous response by its recipient. -```cpp -Transmission Response - _______ ______ ______ _____ _____ -| START || BYTE || BYTE || END | CRC COMPUTATION | ACK | -|-------||------||------||-----|-----------------|-----| -| 149 || H || I || 234 | LATENCY | 6 | -|_______||______||______||_____| |_____| -``` -Between frame transmission and a synchronous response there is a variable timeframe influenced by latency and CRC computation time. The maximum time dedicated to potential acknowledgement reception must be shorter than the transmission time-in (to avoid other devices to disrupt a response exchange) and it is estimated adding the maximum frame length CRC computation time to the expected latency. diff --git a/trademark/LICENSE.md b/trademark/LICENSE.md index 84df7cc2e8..241faeec87 100644 --- a/trademark/LICENSE.md +++ b/trademark/LICENSE.md @@ -1,12 +1,9 @@ ![PJON](http://www.gioblu.com/PJON/PJON-github-header-tiny.png) -PJON® and its brand are registered trademarks, property of Giovanni Blu Mitolo gioscarab@gmail.com +PJON® and its brand are registered trademarks, property of [PJON Technologies srl](https://www.pjon-technologies.com/) Personal use of physical and or digital representations of PJON® and or its brand/icon are unlicensed and free. Commercial use of physical and or digital representations of PJON® and or its brand/icon trademark is subjected to prior application in order to be used. -The applicant may obtain a license of use concerning to physical and/or digital representation of PJON® and/or its brand/icon which can be used within physical and/or digital products of which is entitled to property, only if it deemed fully compliant with the latest official version of the PJON® Protocol layer specification (https://github.com/gioblu/PJON/blob/master/specification/) and fully interoperable with the other compatible systems, devices and implementations. +The applicant may obtain a license of use concerning to physical and/or digital representation of PJON® and/or its brand/icon which can be used within physical and/or digital products of which is entitled to property, only if it deemed fully compliant with the latest version of the PJON® Protocol layer specification (https://github.com/gioblu/PJON/blob/master/specification/) and fully interoperable with other compatible systems, devices and implementations. -To obtain a license for commercial use of digital and or physical representations of PJON® and or its brand/icon: - -1. Write a brief application containing a **product description**, **tool list** (hardware and software used), **interoperability assessment** (tested with other PJON compliant tools?), **functional tests** (It works? How?) and send it to gioscarab@gmail.com -2. Wait for response after application. If an application is considered unfitting, the applicant is informed and, if possible, supported to achieve full compliancy. +To obtain a license for commercial use of digital and or physical representations of PJON® and or its brand/icon write a brief application containing a **product description**, **tools list** (hardware and software used), **interoperability assessment** (tested with other PJON compliant tools?), **functional tests** (It works? How?) and send it to info@pjon-technologies.com diff --git a/trademark/assets/PJON-color-50x50.png b/trademark/assets/PJON-color-50x50.png new file mode 100644 index 0000000000..36d21106d9 Binary files /dev/null and b/trademark/assets/PJON-color-50x50.png differ diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt new file mode 100644 index 0000000000..ace991dd62 --- /dev/null +++ b/zephyr/CMakeLists.txt @@ -0,0 +1,39 @@ +if(CONFIG_PJON) +zephyr_interface_library_named(PJON) + +zephyr_compile_definitions_ifdef(CONFIG_PJON_MAX_PACKETS PJON_MAX_PACKETS=CONFIG_PJON_MAX_PACKETS) +zephyr_compile_definitions_ifdef(CONFIG_PJON_PACKET_MAX_LENGTH PJON_PACKET_MAX_LENGTH=CONFIG_PJON_PACKET_MAX_LENGTH) +zephyr_compile_definitions_ifdef(CONFIG_PJON_INCLUDE_PORT PJON_INCLUDE_PORT) +zephyr_compile_definitions_ifdef(CONFIG_PJON_INCLUDE_MAC PJON_INCLUDE_MAC) + +target_include_directories(PJON INTERFACE ../src) + + + +if(CONFIG_PJON_STRATEGY_THROUGHSERIAL) +target_compile_definitions(PJON INTERFACE +TS_INITIAL_DELAY=CONFIG_TS_INITIAL_DELAY +TS_COLLISION_DELAY=CONFIG_TS_COLLISION_DELAY +TS_RESPONSE_TIME_OUT=CONFIG_TS_RESPONSE_TIME_OUT +TS_TIME_IN=CONFIG_TS_TIME_IN +TS_BYTE_TIME_OUT=CONFIG_TS_BYTE_TIME_OUT +TS_MAX_ATTEMPTS=CONFIG_TS_MAX_ATTEMPTS +TS_BACK_OFF_DEGREE=CONFIG_TS_BACK_OFF_DEGREE +TS_RS485_DELAY=CONFIG_TS_RS485_DELAY +TS_FLUSH_OFFSET=CONFIG_TS_FLUSH_OFFSET +TS_READ_INTERVAL=CONFIG_TS_READ_INTERVAL) +endif() + +if(CONFIG_PJON_STRATEGY_DUALUDP) + +target_compile_definitions(PJON INTERFACE +DUDP_RESPONSE_TIMEOUT=CONFIG_DUDP_RESPONSE_TIMEOUT +DUDP_MINIMUM_SEND_INTERVAL_MS=CONFIG_DUDP_MINIMUM_SEND_INTERVAL_MS +DUDP_MAX_RETRIES=CONFIG_DUDP_MAX_RETRIES +DUDP_MAX_REMOTE_NODES=CONFIG_DUDP_MAX_REMOTE_NODES +DUDP_MAX_FAILURES=CONFIG_DUDP_MAX_FAILURES) + +endif() + + +endif() diff --git a/zephyr/Kconfig b/zephyr/Kconfig new file mode 100644 index 0000000000..c116bda56b --- /dev/null +++ b/zephyr/Kconfig @@ -0,0 +1,205 @@ +menuconfig PJON + bool "PJON communication protocol" + help + Enable the PJON protocol + +if PJON +menu "PJON strategy" + +menuconfig PJON_STRATEGY_DUALUDP + select NETWORKING + select NET_IPV4 + select NET_UDP + select NET_SOCKETS + bool "PJON strategy DualUDP" + +if PJON_STRATEGY_DUALUDP + + + +config DUDP_RESPONSE_TIMEOUT + int "DUDP_RESPONSE_TIMEOUT" + default 50000 + help + Timeout waiting for an ACK. This can be increased if the latency is high + + +config DUDP_MINIMUM_SEND_INTERVAL_MS + int "DUDP_MINIMUM_SEND_INTERVAL_MS" + default 8 + help + Minimum time interval in ms between send attempts. Some devices go into + contention if sending too fast. This can be overridden in an interface + for a device type, or in user sketches. + +config DUDP_MAX_RETRIES + int "DUDP_MAX_RETRIES" + default 10 + help + Max number of retries + + +config DUDP_MAX_REMOTE_NODES + int "DUDP_MAX_REMOTE_NODES" + default 10 + help + The size of the node table + + +config DUDP_MAX_FAILURES + int "DUDP_MAX_FAILURES" + default 10 + help + Remove automatically registered nodes after this number of send failures + +endif + + +menuconfig PJON_STRATEGY_THROUGHSERIAL + select RING_BUFFER + select SERIAL + select UART_INTERRUPT_DRIVEN + bool "PJON strategy Through Serial" + +if PJON_STRATEGY_THROUGHSERIAL + +config TS_INITIAL_DELAY + int "INITIAL DELAY" + default 1000 + help + Maximum 1 second random initial delay + + +config TS_COLLISION_DELAY + int "COLLISION DELAY" + default 32 + help + Maximum 32 microseconds random delay in case of collision + + +config TS_RESPONSE_TIME_OUT + int "RESPONSE TIME OUT" + default 10000 + help + Set 10 milliseconds as the maximum timeframe between transmission and + synchronous acknowledgement response. This value is strictly related to the + maximum time needed by receiver to receive, compute and transmit a response. + Higher if necessary. + + +config TS_TIME_IN + int "TIME IN" + default 100032 + help + Minum timeframe with channel free for use before transmission. + (Avoid disrupting synchronous acknowledgement exchange) + + +config TS_BYTE_TIME_OUT + int "BYTE TIME OUT" + default 50000 + help + Set 50 milliseconds as the maximum timeframe for byte reception. + This value depends on the latency, baud rate and computation time. + Always set TS_BYTE_TIME_OUT > (byte transmission time + latency) + + +config TS_MAX_ATTEMPTS + int "MAX ATTEMPTS" + default 20 + help + Maximum transmission attempts + + +config TS_BACK_OFF_DEGREE + int "BACK OFF DEGREE" + default 4 + help + Back-off exponential degree + + +config TS_RS485_DELAY + int "RS485 DELAY" + default 1 + help + Delay before enabling and disabling RS485 DE and or RE pin + + +config TS_FLUSH_OFFSET + int "FLUSH OFFSET" + default 152 + help + Force blocking sending hack (adds a delay for each character sent). + +config TS_READ_INTERVAL + int "READ INTERVAL" + default 100 + help + Interval between each serial read call. + +endif + +endmenu + +config PJON_DEVICE_ID + int "PJON Device ID" + default 0 + help + PJON Device ID + +config PJON_MTU + int "PJON MTU" + default 1400 + help + Maximum size of SMP frames send and receive over PJON DualUDP, in bytes. + +config PJON_MAX_PACKETS + int "PJON MAX PACKETS" + default 5 + help + Packet buffer length, if full PJON_PACKETS_BUFFER_FULL error is thrown. + The packet buffer is preallocated, so its length strongly affects + memory consumption + +config PJON_PACKET_MAX_LENGTH + int "MAX PACKET LENGTH" + default 50 + help + Max packet length, higher if necessary. + The max packet length defines the length of packets pre-allocated buffers + so it strongly affects memory consumption. + +config PJON_INCLUDE_PACKET_ID + bool "INCLUDE PACKET ID" + default false + help + If set to false packet id feature is not included and 300B of program + memory plus 80B of RAM are spared. + +config PJON_MAX_RECENT_PACKET_IDS + int "MAX RECENT PACKET IDS" + default 10 + help + Maximum packet ids record kept in memory (to avoid duplicated exchanges) + +config PJON_INCLUDE_PORT + bool "INCLUDE PORT" + default false + help + If set to false port feature is not included and 100B of program memory + plus 2B of RAM are spared. + +config PJON_INCLUDE_MAC + bool "INCLUDE MAC" + default false + help + If set to false port feature is not included and 200B of program memory + plus 20B of RAM are spared. + +config APP_LINK_WITH_PJON + bool "Link 'app' with PJON" + default y + help + Add PJON configuration to the 'app' + +endif