GithubHelp home page GithubHelp logo

dustinaevans / pjon Goto Github PK

View Code? Open in Web Editor NEW

This project forked from gioblu/pjon

0.0 1.0 0.0 382 KB

One wire multimaster communications bus system for Arduino and IOT :bird:

C++ 47.41% C 52.59%

pjon's Introduction

##PJON v2.0 beta PJON (Padded Jittering Operative Network) is an Arduino compatible single wire, multi-master communications bus system implemented in 270 lines of C++ and Wiring (not considering comments). It is designed as an alternative to i2c, 1-Wire, Serial and other Arduino compatible protocols. If you are interested to know more about the PJON standard, visit the Wiki. If you need a wireless multimaster implementation check PJON_ASK. If you need help or something is not working visit the Troubleshooting Wiki page. If you own a Saleae Logic Analyzer you can scope communication with saleae-pjon-protocol-analyzer crafted by Andrew Grande.

#include <PJON.h>     // Transmitter board code
PJON network(12, 45); // Bus connection to pin 12, device id 45

void setup() {
  network.send(44, "B", 1, 1000000);
  // Send to device 44, "B" content of 1 byte length every 1000000 microseconds (1 second)
}

void loop() {
  network.update();
}

/* ---------------------------------------------------------------------------- */

#include <PJON.h>     // Receiver board code
PJON network(12, 44); // Bus connection to pin 12, device id 44

void setup() {
  network.set_receiver(receiver_function); // Set the function used to receive messages
};

void receiver_function(uint8_t length, uint8_t *payload) {
  if(payload[0] == 'B') { // If the first letter of the received message is B
    digitalWrite(13, HIGH);
    delay(30);
    digitalWrite(13, LOW);
  }
}

void loop() {
  network.receive(1000);
}

####Features

  • Software emulated non blocking implementation (based on micros and delayMicroseconds)
  • Single wire (plus common ground) physical layer with up to 50 meters range.
  • Device id implementation to enable univocal communication up to 254 devices.
  • Optional auto-addressing with id collision avoidance.
  • Lightweight 1 byte XOR based error detection.
  • Acknowledgement of correct packet sending.
  • Collision avoidance to enable multi-master capability.
  • Broadcast functionality to contact all connected devices.
  • Packet manager to track and retransmit failed packet sendings in background.
  • Error handling.

####Compatibility

  • ATmega88/168/328 8/16Mhz (Diecimila, Duemilanove, Uno, Nano, Mini, Lillypad)
  • ATmega2560 16Mhz (Arduino Mega)
  • ATtiny45/85 8/16Mhz (Trinket, other ATtiny 85 boards), see ATtiny Wiki page
  • SAMD (Arduino Zero)
  • ESP8266 v.1-7 80Mhz "AI-THINKER AT" firmware, see ESP8266 Arduino IDE
  • ESP8266 NodeMCU v0.9-1.0 80Mhz, see ESP8266 Arduino IDE

####Performance PJON works in 3 different communication modes, STANDARD, FAST and OVERDRIVE:

  • STANDARD mode runs at 16.944kBd or 2.12kB/s full cross-architecture / promiscuous clock network compatible.
  • FAST mode runs at 25.157kBd or 3.15kB/s full cross-architecture / promiscuous clock network compatible.
  • OVERDRIVE mode runs a specific architecture at its maximum limits (non cross-architecture compatible). Every architecture has its own limits, Arduino Duemilanove for example runs at 33.898kBd, Arduino Zero can reach 48.000kBd.

When including and using PJON, you have the complete access to the microntroller ready to be used, as usual, untouched. This happens because PJON is completely software emulated with a non blocking implementation, transforming a painfull walk to the hill in a nice flight.

Single wire simplicity let you to experiment quickly and with creativity. The first test I suggest, at your own risk, is to let two arduino boards communicate through your body touching with the left hand the digital port of the first board (5v 40ma, harmless) and with the right the port of the other one. Will be stunning to see high accuracy digital communication running inside a living biological body. This opens the mind to possible creative solutions.

####Why not I2c? I2C is a bus system engineered to work with short wires to connect devices and it needs at least 2 wires, for those reasons is not feasible for home automation applications. If one of the connections to the bus fails, even briefly, one or both devices may freeze. For this reason i2c is not practical for high vibration scenarios such as automotive or robotic applications.

####Why not 1-Wire? 1-Wire is almost what I needed for a lot of projects but has its downsides: it is propietary, in my opinion is over-engineered and Arduino implementations are slow, chaotic and not reliable.

####Why not interrupts? Usage of libraries is really extensive in the Arduino environment and often the end user is not able to go over collisions or redefinitions. Very often a library is using hardware resources of the microcontroller as timers or interrupts, colliding or interrupting other libraries. This happens because in general Arduino boards have limited hardware resources. To have a universal and reliable communication medium in this sort of environment, software emulated bit-banging, I think, is a good, stable and reliable solution that leads to "more predictable" results than interrupt driven systems coexisting on small microcontrollers without the original developer and the end user knowing about it.

PJON - Michael Teeuw application example

PJON application example made by the user Michael Teeuw

====

How to start

The first step is the physical layer: connect with a wire two boards using a digital pin on both boards. After this you should have both arduino boards connected by the wire on the same pin. The selected pins are the same only for simplicity and to avoid mistakes, PJON works fine on every Arduino digital or analog (used as digital) I/O pin.

Lets start coding, instantiate the PJON object that in the example is called network. To initialize a network based on PJON you need only to define the communication pin (any free digital pin on your board) and a unique ID (0 - 255):

  PJON network(12);
  network.set_id(123); // Set id later

  // or

  PJON network(12, 123);

If you are interested auto-addressing is really easy to use:

  PJON network(12);
  network.acquire_id();

  Serial.println(network.device_id()); // Device id found with scan

All ids are scanned sending a packet containing the ACQUIRE_ID constant. If no answer is received from an id, it is considered free. If auto-addressing approach is your choice, you should never have a blind timeframe longer than 1.5 seconds (i.e. delay(2000)) between every receive function call. This constrain is imposed by the necessity of having the device able to receive incoming packets (as ACQUIRE_ID used to determine if a device id is free or not). If a device is executing something for too much time while not reading the bus for incoming packets, its device id could be stolen by another device. There is still no device id collision detection / correction, but respecting the described rules, collision should not happen.

====

Transmit data

Data transmission is handled by a packet manager, the update() function has to be called at least once per loop cycle. Consider that this is not an interrupt driven system, all the time dedicated to delays or executing other tasks is postponing the sending of all the packets are scheduled to be sent:

  network.update();

To send a string to another device connected to the bus simply call send() function passing the ID you want to contact, the string you want to send and its length:

network.send(100, "Ciao, this is a test!", 21);

I know that the packet length is boring to fill 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.

To send a value repeatedly simply add as last parameter the interval in microseconds you want between every sending:

int one_second_delay_test = network.send(100, "Test sent every second!", 23, 1000000);

one_second_delay_test contains the id of the packet. If you want to remove this repeated task simply:

network.remove(one_second_delay_test);

To broadcast a message to all connected devices, use the BROADCAST constant as recipient ID.

int broadcastTest = network.send(BROADCAST, "Message for all connected devices.", 34);

====

Receive data

Now define a void function that will be called if a correct message is received. This function receives 2 parameters: the message length and its content.

void receiver_function(uint8_t length, uint8_t *payload) {
  Serial.print("Message content: ");

  for(int i = 0; i < length; i++)
    Serial.print((char)payload[i]);

  Serial.print(" | Message length: ");
  Serial.println(length, DEC);
};

Inform the network to call receiver_function when a correct message is received:

network.set_receiver(receiver_function);

To correctly receive data call receive() function at least once per loop cycle passing as a parameter, the maximum reception time in microseconds:

int response = network.receive(1000);

Consider that this is not an interrupt driven system and so all the time passed in delay or executing something a certain amount of packets will be potentially lost unheard. Structure intelligently your loop cycle to avoid huge blind timeframes.

====

####Error handling PJON is designed to inform the user if an error is detected. A void function has to be defined as the error handler, it receives 2 parameters the first is the error code and the second is 1 byte additional data related to the error.

Error types:

  • CONNECTION_LOST (value 101), data parameter contains lost device's id.
  • PACKETS_BUFFER_FULL (value 102), data parameter contains buffer length.
  • MEMORY_FULL (value 103), data parameter contains FAIL.
  • CONTENT_TOO_LONG (value 104), data parameter contains content length.
  • ID_ACQUISITION_FAIL (value 105), data parameter contains actual device id.
void error_handler(uint8_t code, uint8_t data) {
  if(code == CONNECTION_LOST) {
    Serial.print("Connection with device ID ");
    Serial.print(data);
    Serial.println(" is lost.");
  }
  if(code == PACKETS_BUFFER_FULL) {
    Serial.print("Packet buffer is full, has now a length of ");
    Serial.println(data, DEC);
    Serial.println("Possible wrong network configuration!");
    Serial.println("For high complexity networks higher MAX_PACKETS over 10.");
    Serial.println("See in PJON.h");
  }
  if(code == MEMORY_FULL) {
    Serial.println("Packet memory allocation failed. Memory is full.");
  }
  if(code == CONTENT_TOO_LONG) {
    Serial.print("Content is too long, length: ");
    Serial.println(data);
  }
  if(code == ID_ACQUISITION_FAIL) {
    Serial.print("Can't acquire a free id ");
    Serial.println(data);
  }
}

Now inform the network to call the error handler function in case of error:

network.set_error(error_handler);

====

####License

/* Copyright 2012-2016 Giovanni Blu Mitolo

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. */

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.