diff --git a/keywords.txt b/keywords.txt index 6a2d0f6d..b5587933 100644 --- a/keywords.txt +++ b/keywords.txt @@ -55,6 +55,7 @@ FSK4Client KEYWORD1 APRSClient KEYWORD1 PagerClient KEYWORD1 ExternalRadio KEYWORD1 +BellClient KEYWORD1 # SSTV modes Scottie1 KEYWORD1 @@ -67,6 +68,11 @@ PasokonP3 KEYWORD1 PasokonP5 KEYWORD1 PasokonP7 KEYWORD1 +# Bell Modems +Bell101 KEYWORD1 +Bell103 KEYWORD1 +Bell202 KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### @@ -260,6 +266,9 @@ dropSync KEYWORD2 setTimerFlag KEYWORD2 setInterruptSetup KEYWORD2 +# BellModem +setModem KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/RadioLib.h b/src/RadioLib.h index 669169a9..f4e690a7 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -107,6 +107,8 @@ #include "protocols/FSK4/FSK4.h" #include "protocols/APRS/APRS.h" #include "protocols/ExternalRadio/ExternalRadio.h" +#include "protocols/Print/Print.h" +#include "protocols/BellModem/BellModem.h" // only create Radio class when using RadioShield #if defined(RADIOLIB_RADIOSHIELD) diff --git a/src/protocols/BellModem/BellModem.cpp b/src/protocols/BellModem/BellModem.cpp new file mode 100644 index 00000000..69a67187 --- /dev/null +++ b/src/protocols/BellModem/BellModem.cpp @@ -0,0 +1,97 @@ +#include "BellModem.h" +#if !defined(RADIOLIB_EXCLUDE_BELL) + +const struct BellModem_t Bell101 { + .freqMark = 1270, + .freqSpace = 1070, + .baudRate = 110, + .freqMarkReply = 2225, + .freqSpaceReply = 2025, +}; + +const struct BellModem_t Bell103 { + .freqMark = 1270, + .freqSpace = 1070, + .baudRate = 300, + .freqMarkReply = 2225, + .freqSpaceReply = 2025, +}; + +const struct BellModem_t Bell202 { + .freqMark = 1200, + .freqSpace = 2200, + .baudRate = 1200, + .freqMarkReply = 1200, + .freqSpaceReply = 2200, +}; + +BellClient::BellClient(PhysicalLayer* phy, uint32_t pin) : AFSKClient(phy, pin) { + this->reply = false; +} + +BellClient::BellClient(AFSKClient* aud) : AFSKClient(aud) { + this->reply = false; +} + +int16_t BellClient::begin(const BellModem_t& modem) { + int16_t state = setModem(modem); + RADIOLIB_ASSERT(state); + + state = phyLayer->startDirect(); + return(state); +} + +int16_t BellClient::setModem(const BellModem_t& modem) { + this->modemType = modem; + this->toneLen = (1000000.0/(float)this->modemType.baudRate)*this->correction; + return(RADIOLIB_ERR_NONE); +} + +int16_t BellClient::setCorrection(float corr) { + this->correction = corr; +} + +size_t BellClient::write(uint8_t b) { + // first get the frequencies + uint16_t toneMark = this->modemType.freqMark; + uint16_t toneSpace = this->modemType.freqSpace; + if(this->reply) { + toneMark = this->modemType.freqMarkReply; + toneMark = this->modemType.freqSpaceReply; + } + + // get the Module pointer to access HAL + Module* mod = this->phyLayer->getMod(); + + if(this->autoStart) { + phyLayer->transmitDirect(); + } + + // iterate over the bits and set correct frequencies + for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { + uint32_t start = mod->hal->micros(); + if(b & mask) { + this->tone(toneMark, false); + } else { + this->tone(toneSpace, false); + } + mod->waitForMicroseconds(start, this->toneLen); + } + + if(this->autoStart) { + phyLayer->standby(); + } + return(1); +} + +int16_t BellClient::idle() { + this->autoStart = false; + return(phyLayer->transmitDirect()); +} + +int16_t BellClient::standby() { + this->autoStart = true; + return(phyLayer->standby()); +} + +#endif diff --git a/src/protocols/BellModem/BellModem.h b/src/protocols/BellModem/BellModem.h new file mode 100644 index 00000000..d16c44d9 --- /dev/null +++ b/src/protocols/BellModem/BellModem.h @@ -0,0 +1,127 @@ +#if !defined(_RADIOLIB_BELL_MODEM_H) +#define _RADIOLIB_BELL_MODEM_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#if defined(RADIOLIB_BUILD_ARDUINO) +#include "../../ArduinoHal.h" +#endif + +#include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" +#include "../Print/Print.h" +#include "../Print/ITA2String.h" + +/*! + \struct BellModem_t + \brief Definition of the Bell-compatible modem. +*/ +struct BellModem_t { + /*! + \brief Frequency of the mark tone. + */ + int16_t freqMark; + + /*! + \brief Frequency of the space tone. + */ + int16_t freqSpace; + + /*! + \brief Baud rate. + */ + int16_t baudRate; + + /*! + \brief Frequency of the mark tone when replying. + */ + int16_t freqMarkReply; + + /*! + \brief Frequency of the space tone when replying. + */ + int16_t freqSpaceReply; +}; + +// currently implemented Bell modems +extern const struct BellModem_t Bell101; +extern const struct BellModem_t Bell103; +extern const struct BellModem_t Bell202; + +/*! + \class BellClient + \brief Client for Bell modem communication. The public interface is the same as Arduino Serial. +*/ +class BellClient: public AFSKClient, public RadioLibPrint { + + public: + + /*! + \brief Whether the modem is replying. + On some modems, the replying station has different tone frequencies. + */ + bool reply; + + /*! + \brief Default constructor. + \param phy Pointer to the wireless module providing PhysicalLayer communication. + \param pin The GPIO pin at which the tones will be generated. + */ + explicit BellClient(PhysicalLayer* phy, uint32_t pin); + + /*! + \brief Audio-client constructor. Can be used when AFSKClient instance already exists. + \param aud Audio client to use. + */ + BellClient(AFSKClient* aud); + + /*! + \brief Initialization method. + \param modem Definition of the Bell modem to use for communication. + \returns \ref status_codes + */ + int16_t begin(const BellModem_t& modem); + + /*! + \brief Set Bell modem. + \param modem Definition of the Bell modem to use for communication. + \returns \ref status_codes + */ + int16_t setModem(const BellModem_t& modem); + + /*! + \brief Set correction coefficient for tone length. + \param correction Timing correction factor, used to adjust the length of tones. + Less than 1.0 leads to shorter tones, defaults to 1.0 (no correction). + \returns \ref status_codes + */ + int16_t setCorrection(float corr); + + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ + size_t write(uint8_t b); + + /*! + \brief Set the modem to idle (ready to transmit). + */ + int16_t idle(); + + /*! + \brief Set the modem to standby (transmitter off). + */ + int16_t standby(); + +#if !defined(RADIOLIB_GODMODE) + private: +#endif + BellModem_t modemType; + float correction = 1.0; + uint16_t toneLen = 0; + bool autoStart = true; + +}; + +#endif diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 9da9c78d..b19339b6 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -382,6 +382,7 @@ class PhysicalLayer { friend class AX25Client; friend class FSK4Client; friend class PagerClient; + friend class BellClient; }; #endif