first commit
This commit is contained in:
346
RH_E32.cpp
Normal file
346
RH_E32.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
// RH_E32.cpp
|
||||
//
|
||||
// Copyright (C) 2017 Mike McCauley
|
||||
// $Id: RH_E32.cpp,v 1.6 2020/01/07 23:35:02 mikem Exp $
|
||||
|
||||
#include <RadioHead.h>
|
||||
#ifdef RH_HAVE_SERIAL // No serial
|
||||
|
||||
#include <RH_E32.h>
|
||||
|
||||
RH_E32::RH_E32(Stream *s, uint8_t m0_pin, uint8_t m1_pin, uint8_t aux_pin)
|
||||
:
|
||||
_s(s),
|
||||
_m0_pin(m0_pin),
|
||||
_m1_pin(m1_pin),
|
||||
_aux_pin(aux_pin)
|
||||
{
|
||||
// Prevent glitches at startup
|
||||
pinMode(_aux_pin, INPUT);
|
||||
digitalWrite(_m0_pin, HIGH);
|
||||
digitalWrite(_m1_pin, HIGH);
|
||||
pinMode(_m0_pin, OUTPUT);
|
||||
pinMode(_m1_pin, OUTPUT);
|
||||
}
|
||||
|
||||
bool RH_E32::init()
|
||||
{
|
||||
// When a message is available, Aux will go low 5 msec before the first character is output
|
||||
// So if we ever wait more than this period of time after Aux low, can conclude there will be no data
|
||||
_s->setTimeout(10);
|
||||
|
||||
// Wait until the module is connected
|
||||
waitAuxHigh();
|
||||
|
||||
if (!getVersion())
|
||||
return false; // Could not communicate with module or wrong type of module
|
||||
|
||||
setMode(RHModeRx);
|
||||
clearRxBuf();
|
||||
|
||||
if (!setDataRate(DataRate5kbps))
|
||||
return false;
|
||||
|
||||
if (!setPower(Power21dBm))
|
||||
return false;
|
||||
|
||||
// if (!setBaudRate(BaudRate9600, Parity8N1))
|
||||
// return false;
|
||||
|
||||
if (!setFrequency(433))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RH_E32::reset()
|
||||
{
|
||||
setOperatingMode(ModeSleep);
|
||||
uint8_t resetCommand[] = { RH_E32_COMMAND_RESET, RH_E32_COMMAND_RESET, RH_E32_COMMAND_RESET };
|
||||
size_t result = _s->write(resetCommand, sizeof(resetCommand));
|
||||
setOperatingMode(ModeNormal);
|
||||
return (result == sizeof(resetCommand));
|
||||
}
|
||||
|
||||
bool RH_E32::readParameters(Parameters& params)
|
||||
{
|
||||
setOperatingMode(ModeSleep);
|
||||
uint8_t readParamsCommand[] = { RH_E32_COMMAND_READ_PARAMS, RH_E32_COMMAND_READ_PARAMS, RH_E32_COMMAND_READ_PARAMS };
|
||||
_s->write(readParamsCommand, sizeof(readParamsCommand));
|
||||
size_t result = _s->readBytes((char*)¶ms, sizeof(params)); // default 1 sec timeout
|
||||
setOperatingMode(ModeNormal);
|
||||
return (result == sizeof(Parameters));
|
||||
}
|
||||
|
||||
bool RH_E32::writeParameters(Parameters& params, bool save)
|
||||
{
|
||||
setOperatingMode(ModeSleep);
|
||||
params.head = save ? RH_E32_COMMAND_WRITE_PARAMS_SAVE : RH_E32_COMMAND_WRITE_PARAMS_NOSAVE;
|
||||
// printBuffer("writing now", (uint8_t*)¶ms, sizeof(params));
|
||||
size_t result = _s->write((uint8_t*)¶ms, sizeof(params));
|
||||
if (result != sizeof(params))
|
||||
return false;
|
||||
|
||||
// Now we expect to get the same data back
|
||||
result = _s->readBytes((char*)¶ms, sizeof(params));
|
||||
if (result != sizeof(params))
|
||||
return false;
|
||||
// printBuffer("additional read", (uint8_t*)¶ms, sizeof(params));
|
||||
// Without a little delay here, writing params often fails
|
||||
delay(20);
|
||||
|
||||
setOperatingMode(ModeNormal);
|
||||
return result == sizeof(params);
|
||||
}
|
||||
|
||||
void RH_E32::setOperatingMode(OperatingMode mode)
|
||||
{
|
||||
waitAuxHigh();
|
||||
switch (mode)
|
||||
{
|
||||
case ModeNormal:
|
||||
digitalWrite(_m0_pin, LOW);
|
||||
digitalWrite(_m1_pin, LOW);
|
||||
break;
|
||||
|
||||
case ModeWakeUp:
|
||||
digitalWrite(_m0_pin, HIGH);
|
||||
digitalWrite(_m1_pin, LOW);
|
||||
break;
|
||||
|
||||
case ModePowerSaving:
|
||||
digitalWrite(_m0_pin, LOW);
|
||||
digitalWrite(_m1_pin, HIGH);
|
||||
break;
|
||||
|
||||
case ModeSleep:
|
||||
digitalWrite(_m0_pin, HIGH);
|
||||
digitalWrite(_m1_pin, HIGH);
|
||||
break;
|
||||
|
||||
}
|
||||
delay(10); // Takes a little while to start its response
|
||||
waitAuxHigh();
|
||||
}
|
||||
|
||||
bool RH_E32::getVersion()
|
||||
{
|
||||
setOperatingMode(ModeSleep);
|
||||
uint8_t readVersionCommand[] = { RH_E32_COMMAND_READ_VERSION, RH_E32_COMMAND_READ_VERSION, RH_E32_COMMAND_READ_VERSION };
|
||||
_s->write(readVersionCommand, sizeof(readVersionCommand));
|
||||
uint8_t version[4];
|
||||
size_t result = _s->readBytes((char *)version, sizeof(version)); // default 1 sec timeout
|
||||
setOperatingMode(ModeNormal);
|
||||
if (result == 4)
|
||||
{
|
||||
// Successful read
|
||||
// printBuffer("read version", version, sizeof(version));
|
||||
if (version[0] != 0xc3 || version [1] != 0x32)
|
||||
{
|
||||
// Not an E32
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// REVISIT: do something with it?
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read failed: no module? Wrong baud?
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RH_E32::waitAuxHigh()
|
||||
{
|
||||
// REVISIT: timeout needed?
|
||||
while (digitalRead(_aux_pin) == false)
|
||||
;
|
||||
}
|
||||
|
||||
void RH_E32::waitAuxLow()
|
||||
{
|
||||
while (digitalRead(_aux_pin) == true)
|
||||
;
|
||||
}
|
||||
|
||||
// Check whether the latest received message is complete and uncorrupted
|
||||
void RH_E32::validateRxBuf()
|
||||
{
|
||||
if (_bufLen < RH_E32_HEADER_LEN)
|
||||
return; // Too short to be a real message
|
||||
if (_bufLen != _buf[0])
|
||||
return; // Do we have all the message?
|
||||
|
||||
// Extract the 4 headers
|
||||
_rxHeaderTo = _buf[1];
|
||||
_rxHeaderFrom = _buf[2];
|
||||
_rxHeaderId = _buf[3];
|
||||
_rxHeaderFlags = _buf[4];
|
||||
if (_promiscuous ||
|
||||
_rxHeaderTo == _thisAddress ||
|
||||
_rxHeaderTo == RH_BROADCAST_ADDRESS)
|
||||
{
|
||||
_rxGood++;
|
||||
_rxBufValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
void RH_E32::clearRxBuf()
|
||||
{
|
||||
_rxBufValid = false;
|
||||
_bufLen = 0;
|
||||
}
|
||||
|
||||
bool RH_E32::available()
|
||||
{
|
||||
// Caution: long packets could be sent in several bursts
|
||||
if (!_rxBufValid)
|
||||
{
|
||||
if (_mode == RHModeTx)
|
||||
return false;
|
||||
|
||||
if (!_s->available())
|
||||
return false;
|
||||
|
||||
// Suck up all the characters we can
|
||||
uint8_t data;
|
||||
while (_s->readBytes((char *)&data, 1) == 1) // Not read timeout
|
||||
{
|
||||
_buf[_bufLen++] = data;
|
||||
}
|
||||
// Now assess what we have
|
||||
if (_bufLen < RH_E32_HEADER_LEN)
|
||||
{
|
||||
// Serial.println("Incomplete header");
|
||||
return false;
|
||||
}
|
||||
else if (_bufLen < _buf[0])
|
||||
{
|
||||
// Serial.println("Incomplete message");
|
||||
return false;
|
||||
}
|
||||
else if ( _bufLen > _buf[0]
|
||||
|| _bufLen > RH_E32_MAX_PAYLOAD_LEN)
|
||||
{
|
||||
// Serial.println("Overrun");
|
||||
clearRxBuf();
|
||||
_rxBad++;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Else it a partial or complete message, test it
|
||||
// printBuffer("read success", _buf, _bufLen);
|
||||
validateRxBuf();
|
||||
}
|
||||
return _rxBufValid;
|
||||
}
|
||||
|
||||
bool RH_E32::recv(uint8_t* buf, uint8_t* len)
|
||||
{
|
||||
if (!available())
|
||||
return false;
|
||||
if (buf && len)
|
||||
{
|
||||
// Skip the 4 headers that are at the beginning of the rxBuf
|
||||
if (*len > _bufLen - RH_E32_HEADER_LEN)
|
||||
*len = _bufLen - RH_E32_HEADER_LEN;
|
||||
memcpy(buf, _buf + RH_E32_HEADER_LEN, *len);
|
||||
}
|
||||
clearRxBuf(); // This message accepted and cleared
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RH_E32::send(const uint8_t* data, uint8_t len)
|
||||
{
|
||||
if (len > RH_E32_MAX_MESSAGE_LEN)
|
||||
return false;
|
||||
|
||||
waitPacketSent(); // Make sure we dont collide with previous message
|
||||
|
||||
// Set up the headers
|
||||
_buf[0] = len + RH_E32_HEADER_LEN; // Number of octets in teh whole message
|
||||
_buf[1] = _txHeaderTo;
|
||||
_buf[2] = _txHeaderFrom;
|
||||
_buf[3] = _txHeaderId;
|
||||
_buf[4] = _txHeaderFlags;
|
||||
|
||||
// REVISIT: do we really have to do this? perhaps just write it after writing the header?
|
||||
memcpy(_buf+RH_E32_HEADER_LEN, data, len);
|
||||
|
||||
_s->write(_buf, len + RH_E32_HEADER_LEN);
|
||||
setMode(RHModeTx);
|
||||
_txGood++;
|
||||
// Aux will return high when the TX buffer is empty
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t RH_E32::maxMessageLength()
|
||||
{
|
||||
return RH_E32_MAX_MESSAGE_LEN;
|
||||
}
|
||||
|
||||
bool RH_E32::waitPacketSent()
|
||||
{
|
||||
if (_mode == RHModeTx)
|
||||
waitAuxHigh();
|
||||
setMode(RHModeRx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RH_E32::setDataRate(DataRate rate)
|
||||
{
|
||||
Parameters params;
|
||||
if (!readParameters(params))
|
||||
return false;
|
||||
// The DataRate enums are the same values as the register bitmasks
|
||||
params.sped &= ~RH_E32_PARAM_SPED_DATARATE_MASK;
|
||||
params.sped |= (rate & RH_E32_PARAM_SPED_DATARATE_MASK);
|
||||
return writeParameters(params);
|
||||
}
|
||||
|
||||
bool RH_E32::setPower(PowerLevel level)
|
||||
{
|
||||
Parameters params;
|
||||
if (!readParameters(params))
|
||||
return false;
|
||||
// The DataRate enums are the same values as the register bitmasks
|
||||
params.option &= ~RH_E32_PARAM_OPTION_POWER_MASK;
|
||||
params.option |= (level & RH_E32_PARAM_OPTION_POWER_MASK);
|
||||
return writeParameters(params);
|
||||
}
|
||||
|
||||
bool RH_E32::setBaudRate(BaudRate rate, Parity parity)
|
||||
{
|
||||
Parameters params;
|
||||
if (!readParameters(params))
|
||||
return false;
|
||||
// The DataRate enums are the same values as the register bitmasks
|
||||
params.sped &= ~RH_E32_PARAM_SPED_UART_BAUD_MASK;
|
||||
params.sped |= (rate & RH_E32_PARAM_SPED_UART_BAUD_MASK);
|
||||
|
||||
// Also set the parity
|
||||
params.sped &= ~RH_E32_PARAM_SPED_UART_MODE_MASK;
|
||||
params.sped |= (parity & RH_E32_PARAM_SPED_UART_MODE_MASK);
|
||||
|
||||
return writeParameters(params);
|
||||
}
|
||||
|
||||
|
||||
bool RH_E32::setFrequency(uint16_t frequency)
|
||||
{
|
||||
if (frequency < 410 || frequency > 441)
|
||||
return false;
|
||||
|
||||
Parameters params;
|
||||
if (!readParameters(params))
|
||||
return false;
|
||||
params.chan = frequency - 410;
|
||||
return writeParameters(params);
|
||||
|
||||
}
|
||||
|
||||
#endif // RH_HAVE_SERIAL
|
Reference in New Issue
Block a user