GY-63_MS5611/libraries/RS485/RS485.cpp

306 lines
6.1 KiB
C++
Raw Normal View History

2022-05-24 11:24:57 -04:00
//
// FILE: RS485.cpp
// AUTHOR: Rob Tillaart
// DATE: 30-okt-2017
2024-02-03 06:28:23 -05:00
// VERSION: 0.5.0
2022-05-24 11:24:57 -04:00
// PURPOSE: Arduino library for RS485 modules (MAX485)
// URL: https://github.com/RobTillaart/RS485
#include "RS485.h"
2022-11-23 10:14:02 -05:00
// - a stream - SWserial of HW serial (preferred)
// - a pin for TX- enable line
// - slave ID, or 0 as master (or don't care)
2022-05-24 11:24:57 -04:00
RS485::RS485(Stream * stream, uint8_t sendPin, uint8_t deviceID)
{
_stream = stream;
_sendPin = sendPin;
_deviceID = deviceID;
2022-05-24 11:24:57 -04:00
pinMode(_sendPin, OUTPUT);
2023-12-18 05:35:35 -05:00
// default receiver mode ==> _sendPin == LOW
setRXmode();
2023-05-11 05:14:17 -04:00
}
uint8_t RS485::getDeviceID()
{
return _deviceID;
}
///////////////////////////////////////////////////////
//
// STREAM INTERFACE
//
2022-05-24 11:24:57 -04:00
int RS485::available()
{
return _stream->available();
}
2022-11-23 10:14:02 -05:00
2022-05-24 11:24:57 -04:00
int RS485::read()
{
return _stream->read();
}
2022-11-23 10:14:02 -05:00
2022-05-24 11:24:57 -04:00
int RS485::peek()
{
return _stream->peek();
}
2022-11-23 10:14:02 -05:00
2022-05-24 11:24:57 -04:00
void RS485::flush()
{
_stream->flush();
}
2022-11-23 10:14:02 -05:00
2022-05-24 11:24:57 -04:00
size_t RS485::write(uint8_t c)
{
2023-12-06 04:23:31 -05:00
setTXmode(); // transmit mode
2022-05-24 11:24:57 -04:00
size_t n = _stream->write(c);
2023-12-06 04:23:31 -05:00
_stream->flush(); // wait for all data transmitted
setRXmode(); // receiver mode
2022-05-24 11:24:57 -04:00
return n;
}
2022-05-26 02:56:53 -04:00
size_t RS485::write(char * array, uint8_t length)
{
return write((uint8_t *)array, length);
}
///////////////////////////////////////////////////////
//
// discussion about write and yield see
2022-05-26 02:56:53 -04:00
// - https://github.com/RobTillaart/RS485/issues/2
//
2022-11-23 10:14:02 -05:00
// #define RS485_YIELD_ENABLE 1
2022-05-26 02:56:53 -04:00
#ifdef RS485_YIELD_ENABLE
2022-11-23 10:14:02 -05:00
// smallest and slightly fastest.
2022-05-26 02:56:53 -04:00
size_t RS485::write(uint8_t * array, uint8_t length)
{
2023-12-18 05:35:35 -05:00
setTXmode(); // transmit mode
size_t n = 0;
2022-05-26 02:56:53 -04:00
for (uint8_t i = 0; i < length; i++)
{
2023-12-06 04:23:31 -05:00
n += _stream->write(array[i]);
2022-05-26 02:56:53 -04:00
yield();
}
2023-12-18 05:35:35 -05:00
setRXmode(); // receiver mode
2022-05-26 02:56:53 -04:00
return n;
}
#else
2022-05-26 02:56:53 -04:00
// 0.2.1 version
2022-05-26 02:56:53 -04:00
// no yield() calls - might be blocking...
2022-05-24 11:24:57 -04:00
size_t RS485::write(uint8_t * array, uint8_t length)
{
2023-12-06 04:23:31 -05:00
setTXmode(); // transmit mode
2022-05-24 11:24:57 -04:00
size_t n = _stream->write(array, length);
2023-12-06 04:23:31 -05:00
_stream->flush(); // wait for all data transmitted
setRXmode(); // receiver mode
2022-05-24 11:24:57 -04:00
return n;
}
2022-05-26 02:56:53 -04:00
#endif
2022-05-24 11:24:57 -04:00
///////////////////////////////////////////////////////
//
2023-05-11 05:14:17 -04:00
// EXPERIMENTAL - use at own risk.
2022-05-24 11:24:57 -04:00
//
///////////////////////////////////////////////////////
//
2023-02-05 14:00:17 -05:00
// commando value meaning
2022-05-24 11:24:57 -04:00
//
2024-02-03 06:28:23 -05:00
// ASCII_SOH 0x01 start of header
// ASCII_STX 0x02 start of text
// ASCII_ETX 0x03 end of text
// ASCII_EOT 0x04 end of transmission
2022-05-24 11:24:57 -04:00
//
2023-02-05 14:00:17 -05:00
// optional
2024-02-03 06:28:23 -05:00
// ASCII_ACK 0x06 ACKnowledge
// ASCII_NAK 0x15 Not Acknowledge
// ASCII_CAN 0x18 CANcel
2022-05-24 11:24:57 -04:00
//
///////////////////////////////////////////////////////
//
2023-02-05 14:00:17 -05:00
// A message has the following layout
2022-05-24 11:24:57 -04:00
//
2024-02-03 06:28:23 -05:00
// ASCII_SOH start of header
// deviceID to
// deviceID sender
// length length of message
// ASCII_STX start of text
// message idem
// CHECKSUM idem, message only!
// ASCII_ETX end of text
// ASCII_EOT end of transmission
2022-05-24 11:24:57 -04:00
//
2023-12-18 05:35:35 -05:00
size_t RS485::send(uint8_t receiverID, uint8_t msg[], uint8_t len)
2022-05-24 11:24:57 -04:00
{
2023-12-18 05:35:35 -05:00
size_t n = 0;
2022-05-24 11:24:57 -04:00
uint8_t CHKSUM = 0;
2023-12-18 05:35:35 -05:00
2023-12-06 04:23:31 -05:00
setTXmode(); // transmit mode
2024-02-03 06:28:23 -05:00
_stream->write(ASCII_SOH);
2023-12-18 05:35:35 -05:00
n += _stream->write(receiverID); // TO
n += _stream->write(_deviceID); // FROM
n += _stream->write(len); // LENGTH BODY
2024-02-03 06:28:23 -05:00
n += _stream->write(ASCII_STX);
2022-05-24 11:24:57 -04:00
for (int i = 0; i < len; i++)
{
2023-12-18 05:35:35 -05:00
n += _stream->write(msg[i]);
2022-11-23 10:14:02 -05:00
CHKSUM ^= msg[i]; // Simple XOR checksum.
2022-05-24 11:24:57 -04:00
}
2023-12-18 05:35:35 -05:00
n += _stream->write(CHKSUM);
2024-02-03 06:28:23 -05:00
n += _stream->write(ASCII_ETX);
n += _stream->write(ASCII_EOT);
2023-12-06 04:23:31 -05:00
_stream->flush();
setRXmode(); // receive mode
2023-12-18 05:35:35 -05:00
return n;
2022-05-24 11:24:57 -04:00
}
2022-11-23 10:14:02 -05:00
2022-05-24 11:24:57 -04:00
// returns true if complete message is captured.
// multiple calls needed as it should be non-blocking.
2022-11-23 10:14:02 -05:00
bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
2022-05-24 11:24:57 -04:00
{
2022-11-23 10:14:02 -05:00
static uint8_t state = 0;
2022-05-24 11:24:57 -04:00
static uint8_t length = 0;
2022-11-23 10:14:02 -05:00
static bool forMe = false;
2023-05-11 05:14:17 -04:00
static uint8_t CHKSUM = 0;
2022-05-24 11:24:57 -04:00
if (_stream->available() == 0) return false;
uint8_t v = _stream->read();
2022-11-23 10:14:02 -05:00
// if (debug) Serial.print(v, HEX);
2023-05-11 05:14:17 -04:00
// Serial.print(state, HEX);
// Serial.print('\t');
// Serial.println(v, HEX);
2022-05-24 11:24:57 -04:00
2022-11-23 10:14:02 -05:00
switch(state)
2022-05-24 11:24:57 -04:00
{
2022-11-23 10:14:02 -05:00
// waiting for new packet
case 0:
2024-02-03 06:28:23 -05:00
if (v == ASCII_SOH)
2022-11-23 10:14:02 -05:00
{
2023-02-05 14:00:17 -05:00
_bidx = 0; // start new packet
2023-05-11 05:14:17 -04:00
CHKSUM = 0;
2022-11-23 10:14:02 -05:00
state = 1;
}
break;
// extract receiver
case 1:
forMe = ((v == _deviceID) || (v == 255)); // PM or broadcast?
if (not forMe) state = 99;
else state = 2;
break;
// extract sender
case 2:
2023-05-11 05:14:17 -04:00
senderID = v;
2022-11-23 10:14:02 -05:00
state = 3;
break;
// extract length
case 3:
msglen = v;
2023-05-11 05:14:17 -04:00
length = v;
state = 4;
2022-11-23 10:14:02 -05:00
break;
2024-02-03 06:28:23 -05:00
// expect ASCII_STX
2022-11-23 10:14:02 -05:00
case 4:
2024-02-03 06:28:23 -05:00
if (v == ASCII_STX) state = 5;
2022-11-23 10:14:02 -05:00
else state = 99;
break;
// extract message
case 5:
if (length == 0)
{
2023-05-11 05:14:17 -04:00
// expect checksum
if (CHKSUM == v) state = 6;
2023-12-06 04:23:31 -05:00
else
2023-05-11 05:14:17 -04:00
{
// debug failing checksum
// Serial.print(CHKSUM, HEX);
// Serial.print('\t');
// Serial.println(v, HEX);
state = 99; // for debug change to state = 6;
}
2022-11-23 10:14:02 -05:00
break;
}
2023-02-05 14:00:17 -05:00
// error handling if v not ASCII ?
2022-11-23 10:14:02 -05:00
_buffer[_bidx++] = v;
CHKSUM ^= v;
length--;
break;
2024-02-03 06:28:23 -05:00
// expect ASCII_ETX
2022-11-23 10:14:02 -05:00
case 6:
2024-02-03 06:28:23 -05:00
if (v == ASCII_ETX) state = 7;
2022-11-23 10:14:02 -05:00
else state = 99;
break;
2024-02-03 06:28:23 -05:00
// expect ASCII_EOT
2023-05-11 05:14:17 -04:00
case 7:
2024-02-03 06:28:23 -05:00
if (v == ASCII_EOT)
2022-11-23 10:14:02 -05:00
{
2023-05-11 05:14:17 -04:00
msglen = _bidx;
2022-11-23 10:14:02 -05:00
for (int i = 0; i < msglen; i++)
{
msg[i] = _buffer[i];
}
2023-05-11 05:14:17 -04:00
state = 0;
2022-11-23 10:14:02 -05:00
return true;
}
2023-05-11 05:14:17 -04:00
state = 99;
2022-11-23 10:14:02 -05:00
break;
// SKIP until next packet
2024-02-03 06:28:23 -05:00
case 99: // wait for ASCII_EOT in case of error
if (v == ASCII_EOT) state = 0;
2022-11-23 10:14:02 -05:00
break;
2022-05-24 11:24:57 -04:00
}
2022-11-23 10:14:02 -05:00
return false;
2022-05-24 11:24:57 -04:00
}
2022-11-23 10:14:02 -05:00
2022-05-24 11:24:57 -04:00
2023-12-18 05:35:35 -05:00
size_t RS485::send(uint8_t receiverID, char msg[], uint8_t len)
{
return send(receiverID, (uint8_t *)msg, len);
}
bool RS485::receive(uint8_t &senderID, char msg[], uint8_t &len)
{
return receive(senderID, (uint8_t*) msg, len);
}
2023-05-11 05:14:17 -04:00
2022-05-24 11:24:57 -04:00
//////////////////////////////////////////////////
//
// PRIVATE
//
2023-02-05 14:00:17 -05:00
// -- END OF FILE --
2022-05-24 11:24:57 -04:00