// RH_E32.cpp // // Copyright (C) 2017 Mike McCauley // $Id: RH_E32.cpp,v 1.6 2020/01/07 23:35:02 mikem Exp $ #include #ifdef RH_HAVE_SERIAL // No serial #include 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