From 83508c313ef7995361db8b08a1cbd557a29d530d Mon Sep 17 00:00:00 2001 From: kou029w Date: Tue, 26 Feb 2013 00:38:35 +0900 Subject: [PATCH] softmodem --- arduino/libraries/SoftModem/.svn/all-wcprops | 23 + arduino/libraries/SoftModem/.svn/entries | 130 +++++ .../.svn/text-base/SoftModem.cpp.svn-base | 326 +++++++++++++ .../.svn/text-base/SoftModem.h.svn-base | 65 +++ .../.svn/text-base/keywords.txt.svn-base | 26 + arduino/libraries/SoftModem/SoftModem.cpp | 451 +++++++----------- arduino/libraries/SoftModem/SoftModem.h | 69 +-- arduino/softmodemsample/softmodemsample.ino | 51 ++ 8 files changed, 814 insertions(+), 327 deletions(-) create mode 100644 arduino/libraries/SoftModem/.svn/all-wcprops create mode 100644 arduino/libraries/SoftModem/.svn/entries create mode 100644 arduino/libraries/SoftModem/.svn/text-base/SoftModem.cpp.svn-base create mode 100644 arduino/libraries/SoftModem/.svn/text-base/SoftModem.h.svn-base create mode 100644 arduino/libraries/SoftModem/.svn/text-base/keywords.txt.svn-base create mode 100644 arduino/softmodemsample/softmodemsample.ino diff --git a/arduino/libraries/SoftModem/.svn/all-wcprops b/arduino/libraries/SoftModem/.svn/all-wcprops new file mode 100644 index 0000000..05c3be0 --- /dev/null +++ b/arduino/libraries/SoftModem/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 33 +/svn/!svn/ver/115/trunk/SoftModem +END +SoftModem.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/115/trunk/SoftModem/SoftModem.h +END +keywords.txt +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/39/trunk/SoftModem/keywords.txt +END +SoftModem.cpp +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/117/trunk/SoftModem/SoftModem.cpp +END diff --git a/arduino/libraries/SoftModem/.svn/entries b/arduino/libraries/SoftModem/.svn/entries new file mode 100644 index 0000000..da4057d --- /dev/null +++ b/arduino/libraries/SoftModem/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +115 +https://arms22.googlecode.com/svn/trunk/SoftModem +https://arms22.googlecode.com/svn + + + +2012-09-15T06:54:54.354274Z +115 +arms22@gmail.com + + + + + + + + + + + + + + +6844b672-8a06-11de-b664-3b115b7b7a9b + +SoftModem.h +file + + + + +2012-10-08T18:17:20.000000Z +324ac64ba910e2bbb8ffc9a873735249 +2012-09-15T06:54:54.354274Z +115 +arms22@gmail.com + + + + + + + + + + + + + + + + + + + + + +1672 + +keywords.txt +file + + + + +2012-09-02T06:36:09.000000Z +984fd1160834ff5b862ec7d60db3d34f +2010-05-06T10:56:24.509439Z +39 +arms22 + + + + + + + + + + + + + + + + + + + + + +640 + +SoftModem.cpp +file +117 + + + +2012-10-10T13:40:55.000000Z +6ba1d1f635115b323154a60dc37cdb51 +2012-11-12T13:40:36.532674Z +117 +arms22@gmail.com + + + + + + + + + + + + + + + + + + + + + +7548 + diff --git a/arduino/libraries/SoftModem/.svn/text-base/SoftModem.cpp.svn-base b/arduino/libraries/SoftModem/.svn/text-base/SoftModem.cpp.svn-base new file mode 100644 index 0000000..7464cd1 --- /dev/null +++ b/arduino/libraries/SoftModem/.svn/text-base/SoftModem.cpp.svn-base @@ -0,0 +1,326 @@ +#include "SoftModem.h" + +#define TX_PIN (3) +#define RX_PIN1 (6) // AIN0 +#define RX_PIN2 (7) // AIN1 + +SoftModem *SoftModem::activeObject = 0; + +SoftModem::SoftModem() { +} + +SoftModem::~SoftModem() { + end(); +} + +#if F_CPU == 16000000 +#if SOFT_MODEM_BAUD_RATE <= 126 +#define TIMER_CLOCK_SELECT (7) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024)) +#elif SOFT_MODEM_BAUD_RATE <= 315 +#define TIMER_CLOCK_SELECT (6) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256)) +#elif SOFT_MODEM_BAUD_RATE <= 630 +#define TIMER_CLOCK_SELECT (5) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128)) +#elif SOFT_MODEM_BAUD_RATE <= 1225 +#define TIMER_CLOCK_SELECT (4) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64)) +#else +#define TIMER_CLOCK_SELECT (3) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32)) +#endif +#else +#if SOFT_MODEM_BAUD_RATE <= 126 +#define TIMER_CLOCK_SELECT (6) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256)) +#elif SOFT_MODEM_BAUD_RATE <= 315 +#define TIMER_CLOCK_SELECT (5) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128)) +#elif SOFT_MODEM_BAUD_RATE <= 630 +#define TIMER_CLOCK_SELECT (4) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64)) +#else +#define TIMER_CLOCK_SELECT (3) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32)) +#endif +#endif + +#define BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE) +#define HIGH_FREQ_MICROS (1000000/SOFT_MODEM_HIGH_FREQ) +#define LOW_FREQ_MICROS (1000000/SOFT_MODEM_LOW_FREQ) + +#define HIGH_FREQ_CNT (BIT_PERIOD/HIGH_FREQ_MICROS) +#define LOW_FREQ_CNT (BIT_PERIOD/LOW_FREQ_MICROS) + +#define MAX_CARRIR_BITS (40000/BIT_PERIOD) + +#define TCNT_BIT_PERIOD (BIT_PERIOD/MICROS_PER_TIMER_COUNT) +#define TCNT_HIGH_FREQ (HIGH_FREQ_MICROS/MICROS_PER_TIMER_COUNT) +#define TCNT_LOW_FREQ (LOW_FREQ_MICROS/MICROS_PER_TIMER_COUNT) + +#define TCNT_HIGH_TH_L (TCNT_HIGH_FREQ * 0.90) +#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15) +#define TCNT_LOW_TH_L (TCNT_LOW_FREQ * 0.85) +#define TCNT_LOW_TH_H (TCNT_LOW_FREQ * 1.10) + +#if SOFT_MODEM_DEBUG_ENABLE +static volatile uint8_t *_portLEDReg; +static uint8_t _portLEDMask; +#endif + +enum { START_BIT = 0, DATA_BIT = 8, STOP_BIT = 9, INACTIVE = 0xff }; + +void SoftModem::begin(void) +{ + pinMode(RX_PIN1, INPUT); + digitalWrite(RX_PIN1, LOW); + + pinMode(RX_PIN2, INPUT); + digitalWrite(RX_PIN2, LOW); + + pinMode(TX_PIN, OUTPUT); + digitalWrite(TX_PIN, LOW); + + _txPortReg = portOutputRegister(digitalPinToPort(TX_PIN)); + _txPortMask = digitalPinToBitMask(TX_PIN); + +#if SOFT_MODEM_DEBUG_ENABLE + _portLEDReg = portOutputRegister(digitalPinToPort(13)); + _portLEDMask = digitalPinToBitMask(13); + pinMode(13, OUTPUT); +#endif + + _recvStat = INACTIVE; + _recvBufferHead = _recvBufferTail = 0; + + SoftModem::activeObject = this; + + _lastTCNT = TCNT2; + _lastDiff = _lowCount = _highCount = 0; + + TCCR2A = 0; + TCCR2B = TIMER_CLOCK_SELECT; + ACSR = _BV(ACIE) | _BV(ACIS1); + DIDR1 = _BV(AIN1D) | _BV(AIN0D); +} + +void SoftModem::end(void) +{ + ACSR &= ~(_BV(ACIE)); + TIMSK2 &= ~(_BV(OCIE2A)); + DIDR1 &= ~(_BV(AIN1D) | _BV(AIN0D)); + SoftModem::activeObject = 0; +} + +void SoftModem::demodulate(void) +{ + uint8_t t = TCNT2; + uint8_t diff; + + diff = t - _lastTCNT; + + if(diff < 4) + return; + + _lastTCNT = t; + + if(diff > (uint8_t)(TCNT_LOW_TH_H)) + return; + + // 移動平均 + _lastDiff = (diff >> 1) + (diff >> 2) + (_lastDiff >> 2); + + if(_lastDiff >= (uint8_t)(TCNT_LOW_TH_L)){ + _lowCount += _lastDiff; + if(_recvStat == INACTIVE){ + // スタートビット検出 + if(_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5)){ + _recvStat = START_BIT; + _highCount = 0; + _recvBits = 0; + OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount; + TIFR2 |= _BV(OCF2A); + TIMSK2 |= _BV(OCIE2A); + } + } + } + else if(_lastDiff <= (uint8_t)(TCNT_HIGH_TH_H)){ + if(_recvStat == INACTIVE){ + _lowCount = 0; + _highCount = 0; + } + else{ + _highCount += _lastDiff; + } + } +} + +// アナログコンパレータ割り込み +ISR(ANALOG_COMP_vect) +{ + SoftModem::activeObject->demodulate(); +} + +void SoftModem::recv(void) +{ + uint8_t high; + + // ビット論理判定 + if(_highCount > _lowCount){ + _highCount = 0; + high = 0x80; + } + else{ + _lowCount = 0; + high = 0x00; + } + + // スタートビット受信 + if(_recvStat == START_BIT){ + if(!high){ + _recvStat++; + } + else{ + goto end_recv; + } + } + // データビット受信 + else if(_recvStat <= DATA_BIT) { + _recvBits >>= 1; + _recvBits |= high; + _recvStat++; + } + // ストップビット受信 + else if(_recvStat == STOP_BIT){ + if(high){ + // 受信バッファに格納 + uint8_t new_tail = (_recvBufferTail + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1); + if(new_tail != _recvBufferHead){ + _recvBuffer[_recvBufferTail] = _recvBits; + _recvBufferTail = new_tail; + } + else{ + ;// オーバーランエラー + } + } + else{ + ;// フレミングエラー + } + goto end_recv; + } + else{ + end_recv: + _recvStat = INACTIVE; + TIMSK2 &= ~_BV(OCIE2A); + } +} + +// タイマー2比較一致割り込みA +ISR(TIMER2_COMPA_vect) +{ + OCR2A += (uint8_t)TCNT_BIT_PERIOD; + SoftModem::activeObject->recv(); +#if SOFT_MODEM_DEBUG_ENABLE + *_portLEDReg ^= _portLEDMask; +#endif +} + +int SoftModem::available() +{ + return (_recvBufferTail + SOFT_MODEM_RX_BUF_SIZE - _recvBufferHead) & (SOFT_MODEM_RX_BUF_SIZE - 1); +} + +int SoftModem::read() +{ + if(_recvBufferHead == _recvBufferTail) + return -1; + int d = _recvBuffer[_recvBufferHead]; + _recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1); + return d; +} + +int SoftModem::peek() +{ + if(_recvBufferHead == _recvBufferTail) + return -1; + return _recvBuffer[_recvBufferHead]; +} + +void SoftModem::flush() +{ +} + +void SoftModem::modulate(uint8_t b) +{ + uint8_t cnt,tcnt,tcnt2; + if(b){ + cnt = (uint8_t)(HIGH_FREQ_CNT); + tcnt2 = (uint8_t)(TCNT_HIGH_FREQ / 2); + tcnt = (uint8_t)(TCNT_HIGH_FREQ) - tcnt2; + }else{ + cnt = (uint8_t)(LOW_FREQ_CNT); + tcnt2 = (uint8_t)(TCNT_LOW_FREQ / 2); + tcnt = (uint8_t)(TCNT_LOW_FREQ) - tcnt2; + } + do { + cnt--; + { + OCR2B += tcnt; + TIFR2 |= _BV(OCF2B); + while(!(TIFR2 & _BV(OCF2B))); + } + *_txPortReg ^= _txPortMask; + { + OCR2B += tcnt2; + TIFR2 |= _BV(OCF2B); + while(!(TIFR2 & _BV(OCF2B))); + } + *_txPortReg ^= _txPortMask; + } while (cnt); +} + +// Preamble bit before transmission +// 1 start bit (LOW) +// 8 data bits, LSB first +// 1 stop bit (HIGH) +// ... +// Postamble bit after transmission + +size_t SoftModem::write(const uint8_t *buffer, size_t size) +{ + // プリアンブルビット + uint8_t cnt = ((micros() - _lastWriteTime) / BIT_PERIOD) + 1; + if(cnt > MAX_CARRIR_BITS){ + cnt = MAX_CARRIR_BITS; + } + for(uint8_t i = 0; i + +//#define SOFT_MODEM_BAUD_RATE (126) +//#define SOFT_MODEM_LOW_FREQ (882) +//#define SOFT_MODEM_HIGH_FREQ (1764) +//#define SOFT_MODEM_RX_BUF_SIZE (4) + +//#define SOFT_MODEM_BAUD_RATE (315) +//#define SOFT_MODEM_LOW_FREQ (1575) +//#define SOFT_MODEM_HIGH_FREQ (3150) +//#define SOFT_MODEM_RX_BUF_SIZE (8) + +//#define SOFT_MODEM_BAUD_RATE (630) +//#define SOFT_MODEM_LOW_FREQ (3150) +//#define SOFT_MODEM_HIGH_FREQ (6300) +//#define SOFT_MODEM_RX_BUF_SIZE (16) + +#define SOFT_MODEM_BAUD_RATE (1225) +#define SOFT_MODEM_LOW_FREQ (4900) +#define SOFT_MODEM_HIGH_FREQ (7350) +#define SOFT_MODEM_RX_BUF_SIZE (32) + +//#define SOFT_MODEM_BAUD_RATE (2450) +//#define SOFT_MODEM_LOW_FREQ (4900) +//#define SOFT_MODEM_HIGH_FREQ (7350) +//#define SOFT_MODEM_RX_BUF_SIZE (32) + +#define SOFT_MODEM_DEBUG_ENABLE (0) + +class SoftModem : public Stream +{ +private: + volatile uint8_t *_txPortReg; + uint8_t _txPortMask; + uint8_t _lastTCNT; + uint8_t _lastDiff; + uint8_t _recvStat; + uint8_t _recvBits; + uint8_t _recvBufferHead; + uint8_t _recvBufferTail; + uint8_t _recvBuffer[SOFT_MODEM_RX_BUF_SIZE]; + uint8_t _lowCount; + uint8_t _highCount; + unsigned long _lastWriteTime; + void modulate(uint8_t b); +public: + SoftModem(); + ~SoftModem(); + void begin(void); + void end(void); + virtual int available(); + virtual int read(); + virtual void flush(); + virtual int peek(); + virtual size_t write(const uint8_t *buffer, size_t size); + virtual size_t write(uint8_t data); + void demodulate(void); + void recv(void); + static SoftModem *activeObject; +}; + +#endif diff --git a/arduino/libraries/SoftModem/.svn/text-base/keywords.txt.svn-base b/arduino/libraries/SoftModem/.svn/text-base/keywords.txt.svn-base new file mode 100644 index 0000000..8869d02 --- /dev/null +++ b/arduino/libraries/SoftModem/.svn/text-base/keywords.txt.svn-base @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For SoftModem +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +SoftModem KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +available KEYWORD2 +read KEYWORD2 +write KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/arduino/libraries/SoftModem/SoftModem.cpp b/arduino/libraries/SoftModem/SoftModem.cpp index 4537d76..7464cd1 100644 --- a/arduino/libraries/SoftModem/SoftModem.cpp +++ b/arduino/libraries/SoftModem/SoftModem.cpp @@ -1,12 +1,8 @@ -#include -#include -#include -#include #include "SoftModem.h" -#define SOFT_MODEM_TX_PIN (3) -#define SOFT_MODEM_RX_PIN1 (6) // AIN0 -#define SOFT_MODEM_RX_PIN2 (7) // AIN1 +#define TX_PIN (3) +#define RX_PIN1 (6) // AIN0 +#define RX_PIN2 (7) // AIN1 SoftModem *SoftModem::activeObject = 0; @@ -19,135 +15,112 @@ SoftModem::~SoftModem() { #if F_CPU == 16000000 #if SOFT_MODEM_BAUD_RATE <= 126 - #define TIMER_CLOCK_SELECT (7) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024)) +#define TIMER_CLOCK_SELECT (7) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024)) #elif SOFT_MODEM_BAUD_RATE <= 315 - #define TIMER_CLOCK_SELECT (6) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256)) +#define TIMER_CLOCK_SELECT (6) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256)) #elif SOFT_MODEM_BAUD_RATE <= 630 - #define TIMER_CLOCK_SELECT (5) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128)) +#define TIMER_CLOCK_SELECT (5) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128)) #elif SOFT_MODEM_BAUD_RATE <= 1225 - #define TIMER_CLOCK_SELECT (4) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64)) +#define TIMER_CLOCK_SELECT (4) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64)) #else - #define TIMER_CLOCK_SELECT (3) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32)) +#define TIMER_CLOCK_SELECT (3) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32)) #endif #else #if SOFT_MODEM_BAUD_RATE <= 126 - #define TIMER_CLOCK_SELECT (6) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256)) +#define TIMER_CLOCK_SELECT (6) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256)) #elif SOFT_MODEM_BAUD_RATE <= 315 - #define TIMER_CLOCK_SELECT (5) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128)) +#define TIMER_CLOCK_SELECT (5) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128)) #elif SOFT_MODEM_BAUD_RATE <= 630 - #define TIMER_CLOCK_SELECT (4) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64)) +#define TIMER_CLOCK_SELECT (4) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64)) #else - #define TIMER_CLOCK_SELECT (3) - #define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32)) +#define TIMER_CLOCK_SELECT (3) +#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32)) #endif #endif -#define SOFT_MODEM_BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE) -#define SOFT_MODEM_HIGH_USEC (1000000/SOFT_MODEM_HIGH_FREQ) -#define SOFT_MODEM_LOW_USEC (1000000/SOFT_MODEM_LOW_FREQ) +#define BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE) +#define HIGH_FREQ_MICROS (1000000/SOFT_MODEM_HIGH_FREQ) +#define LOW_FREQ_MICROS (1000000/SOFT_MODEM_LOW_FREQ) -#define SOFT_MODEM_HIGH_CNT (SOFT_MODEM_BIT_PERIOD/SOFT_MODEM_HIGH_USEC) -#define SOFT_MODEM_LOW_CNT (SOFT_MODEM_BIT_PERIOD/SOFT_MODEM_LOW_USEC) +#define HIGH_FREQ_CNT (BIT_PERIOD/HIGH_FREQ_MICROS) +#define LOW_FREQ_CNT (BIT_PERIOD/LOW_FREQ_MICROS) -#define SOFT_MODEM_HIGH_ADJ (SOFT_MODEM_BIT_PERIOD%SOFT_MODEM_HIGH_USEC) -#define SOFT_MODEM_LOW_ADJ (SOFT_MODEM_BIT_PERIOD%SOFT_MODEM_LOW_USEC) +#define MAX_CARRIR_BITS (40000/BIT_PERIOD) -#define SOFT_MODEM_CARRIR_CNT (20000000/SOFT_MODEM_BIT_PERIOD) +#define TCNT_BIT_PERIOD (BIT_PERIOD/MICROS_PER_TIMER_COUNT) +#define TCNT_HIGH_FREQ (HIGH_FREQ_MICROS/MICROS_PER_TIMER_COUNT) +#define TCNT_LOW_FREQ (LOW_FREQ_MICROS/MICROS_PER_TIMER_COUNT) -#define TCNT_BIT_PERIOD (SOFT_MODEM_BIT_PERIOD/MICROS_PER_TIMER_COUNT) -#define TCNT_HIGH_FREQ (SOFT_MODEM_HIGH_USEC/MICROS_PER_TIMER_COUNT) -#define TCNT_LOW_FREQ (SOFT_MODEM_LOW_USEC/MICROS_PER_TIMER_COUNT) +#define TCNT_HIGH_TH_L (TCNT_HIGH_FREQ * 0.90) +#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15) +#define TCNT_LOW_TH_L (TCNT_LOW_FREQ * 0.85) +#define TCNT_LOW_TH_H (TCNT_LOW_FREQ * 1.10) -#define TCNT_HIGH_TH_L (TCNT_HIGH_FREQ * 0.80) -#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15) -#define TCNT_LOW_TH_L (TCNT_LOW_FREQ * 0.85) -#define TCNT_LOW_TH_H (TCNT_LOW_FREQ * 1.20) - -#if SOFT_MODEM_DEBUG -static volatile uint8_t *portLEDReg; -static uint8_t portLEDMask; +#if SOFT_MODEM_DEBUG_ENABLE +static volatile uint8_t *_portLEDReg; +static uint8_t _portLEDMask; #endif +enum { START_BIT = 0, DATA_BIT = 8, STOP_BIT = 9, INACTIVE = 0xff }; + void SoftModem::begin(void) { - pinMode(SOFT_MODEM_RX_PIN1, INPUT); - digitalWrite(SOFT_MODEM_RX_PIN1, LOW); - - pinMode(SOFT_MODEM_RX_PIN2, INPUT); - digitalWrite(SOFT_MODEM_RX_PIN2, LOW); - - pinMode(SOFT_MODEM_TX_PIN, OUTPUT); - digitalWrite(SOFT_MODEM_TX_PIN, LOW); - - _txPortReg = portOutputRegister(digitalPinToPort(SOFT_MODEM_TX_PIN)); - _txPortMask = digitalPinToBitMask(SOFT_MODEM_TX_PIN); - -#if SOFT_MODEM_DEBUG - portLEDReg = portOutputRegister(digitalPinToPort(13)); - portLEDMask = digitalPinToBitMask(13); - _errs = 0; - _ints = 0; + pinMode(RX_PIN1, INPUT); + digitalWrite(RX_PIN1, LOW); + + pinMode(RX_PIN2, INPUT); + digitalWrite(RX_PIN2, LOW); + + pinMode(TX_PIN, OUTPUT); + digitalWrite(TX_PIN, LOW); + + _txPortReg = portOutputRegister(digitalPinToPort(TX_PIN)); + _txPortMask = digitalPinToBitMask(TX_PIN); + +#if SOFT_MODEM_DEBUG_ENABLE + _portLEDReg = portOutputRegister(digitalPinToPort(13)); + _portLEDMask = digitalPinToBitMask(13); + pinMode(13, OUTPUT); #endif - - _recvStat = 0xff; + + _recvStat = INACTIVE; _recvBufferHead = _recvBufferTail = 0; - + SoftModem::activeObject = this; - + _lastTCNT = TCNT2; _lastDiff = _lowCount = _highCount = 0; - + TCCR2A = 0; TCCR2B = TIMER_CLOCK_SELECT; ACSR = _BV(ACIE) | _BV(ACIS1); + DIDR1 = _BV(AIN1D) | _BV(AIN0D); } void SoftModem::end(void) { ACSR &= ~(_BV(ACIE)); TIMSK2 &= ~(_BV(OCIE2A)); + DIDR1 &= ~(_BV(AIN1D) | _BV(AIN0D)); SoftModem::activeObject = 0; } -enum { - FSK_START_BIT = 0, - FSK_D0_BIT, - FSK_D1_BIT, - FSK_D2_BIT, - FSK_D3_BIT, - FSK_D4_BIT, - FSK_D5_BIT, - FSK_D6_BIT, - FSK_D7_BIT, - FSK_STOP_BIT -}; - void SoftModem::demodulate(void) { uint8_t t = TCNT2; uint8_t diff; - if(TIFR2 & _BV(TOV2)){ - TIFR2 |= _BV(TOV2); - diff = (255 - _lastTCNT) + t + 1; - } - else{ - diff = t - _lastTCNT; - } + diff = t - _lastTCNT; -#if SOFT_MODEM_DEBUG - _ints++; -#endif - - if(diff < (uint8_t)(TCNT_HIGH_TH_L)) // Noise? + if(diff < 4) return; _lastTCNT = t; @@ -155,122 +128,138 @@ void SoftModem::demodulate(void) if(diff > (uint8_t)(TCNT_LOW_TH_H)) return; + // 移動平均 _lastDiff = (diff >> 1) + (diff >> 2) + (_lastDiff >> 2); if(_lastDiff >= (uint8_t)(TCNT_LOW_TH_L)){ _lowCount += _lastDiff; - if((_recvStat == 0xff) && (_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5))){ // maybe Start-Bit - _recvStat = FSK_START_BIT; - _highCount = 0; - _recvBits = 0; - OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount; // 1 bit period after detected - TIFR2 |= _BV(OCF2A); - TIMSK2 |= _BV(OCIE2A); + if(_recvStat == INACTIVE){ + // スタートビット検出 + if(_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5)){ + _recvStat = START_BIT; + _highCount = 0; + _recvBits = 0; + OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount; + TIFR2 |= _BV(OCF2A); + TIMSK2 |= _BV(OCIE2A); + } } } else if(_lastDiff <= (uint8_t)(TCNT_HIGH_TH_H)){ - _highCount += _lastDiff; - if((_recvStat == 0xff) && (_highCount >= (uint8_t)(TCNT_BIT_PERIOD))){ - _lowCount = _highCount = 0; + if(_recvStat == INACTIVE){ + _lowCount = 0; + _highCount = 0; + } + else{ + _highCount += _lastDiff; } - } - else{ -#if SOFT_MODEM_DEBUG - _errs++; -#endif } } +// アナログコンパレータ割り込み ISR(ANALOG_COMP_vect) { - SoftModem *act = SoftModem::activeObject; - act->demodulate(); + SoftModem::activeObject->demodulate(); } void SoftModem::recv(void) { uint8_t high; + + // ビット論理判定 if(_highCount > _lowCount){ - if(_highCount >= (uint8_t)TCNT_BIT_PERIOD) - _highCount -= (uint8_t)TCNT_BIT_PERIOD; - else - _highCount = 0; + _highCount = 0; high = 0x80; } else{ - if(_lowCount >= (uint8_t)TCNT_BIT_PERIOD) - _lowCount -= (uint8_t)TCNT_BIT_PERIOD; - else - _lowCount = 0; + _lowCount = 0; high = 0x00; } - if(_recvStat == FSK_START_BIT){ // Start bit + // スタートビット受信 + if(_recvStat == START_BIT){ if(!high){ _recvStat++; - }else{ + } + else{ goto end_recv; } } - else if(_recvStat <= FSK_D7_BIT) { // Data bits + // データビット受信 + else if(_recvStat <= DATA_BIT) { _recvBits >>= 1; _recvBits |= high; _recvStat++; } - else if(_recvStat == FSK_STOP_BIT){ // Stop bit - uint8_t new_tail = (_recvBufferTail + 1) & (SOFT_MODEM_MAX_RX_BUFF - 1); - if(new_tail != _recvBufferHead){ - _recvBuffer[_recvBufferTail] = _recvBits; - _recvBufferTail = new_tail; + // ストップビット受信 + else if(_recvStat == STOP_BIT){ + if(high){ + // 受信バッファに格納 + uint8_t new_tail = (_recvBufferTail + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1); + if(new_tail != _recvBufferHead){ + _recvBuffer[_recvBufferTail] = _recvBits; + _recvBufferTail = new_tail; + } + else{ + ;// オーバーランエラー + } + } + else{ + ;// フレミングエラー } goto end_recv; } else{ end_recv: - _recvStat = 0xff; + _recvStat = INACTIVE; TIMSK2 &= ~_BV(OCIE2A); -#if SOFT_MODEM_DEBUG - errs = _errs; - _errs = 0; - ints = _ints; - _ints = 0; -#endif } } +// タイマー2比較一致割り込みA ISR(TIMER2_COMPA_vect) { OCR2A += (uint8_t)TCNT_BIT_PERIOD; - SoftModem *act = SoftModem::activeObject; - act->recv(); -#if SOFT_MODEM_DEBUG - *portLEDReg ^= portLEDMask; -#endif + SoftModem::activeObject->recv(); +#if SOFT_MODEM_DEBUG_ENABLE + *_portLEDReg ^= _portLEDMask; +#endif } -uint8_t SoftModem::available(void) +int SoftModem::available() { - return (_recvBufferTail + SOFT_MODEM_MAX_RX_BUFF - _recvBufferHead) & (SOFT_MODEM_MAX_RX_BUFF - 1); + return (_recvBufferTail + SOFT_MODEM_RX_BUF_SIZE - _recvBufferHead) & (SOFT_MODEM_RX_BUF_SIZE - 1); } -int SoftModem::read(void) +int SoftModem::read() { if(_recvBufferHead == _recvBufferTail) return -1; int d = _recvBuffer[_recvBufferHead]; - _recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_MAX_RX_BUFF - 1); + _recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1); return d; } +int SoftModem::peek() +{ + if(_recvBufferHead == _recvBufferTail) + return -1; + return _recvBuffer[_recvBufferHead]; +} + +void SoftModem::flush() +{ +} + void SoftModem::modulate(uint8_t b) { - uint8_t cnt,tcnt,tcnt2,adj; + uint8_t cnt,tcnt,tcnt2; if(b){ - cnt = (uint8_t)(SOFT_MODEM_HIGH_CNT); + cnt = (uint8_t)(HIGH_FREQ_CNT); tcnt2 = (uint8_t)(TCNT_HIGH_FREQ / 2); tcnt = (uint8_t)(TCNT_HIGH_FREQ) - tcnt2; }else{ - cnt = (uint8_t)(SOFT_MODEM_LOW_CNT); + cnt = (uint8_t)(LOW_FREQ_CNT); tcnt2 = (uint8_t)(TCNT_LOW_FREQ / 2); tcnt = (uint8_t)(TCNT_LOW_FREQ) - tcnt2; } @@ -291,149 +280,47 @@ void SoftModem::modulate(uint8_t b) } while (cnt); } -void SoftModem::write(uint8_t data) +// Preamble bit before transmission +// 1 start bit (LOW) +// 8 data bits, LSB first +// 1 stop bit (HIGH) +// ... +// Postamble bit after transmission + +size_t SoftModem::write(const uint8_t *buffer, size_t size) { - static unsigned long lastTransmissionTime = 0; - if((micros() - lastTransmissionTime) > (uint16_t)(SOFT_MODEM_LOW_USEC*2)){ - for(uint8_t i = 0; i<(uint8_t)SOFT_MODEM_CARRIR_CNT; i++){ - modulate(HIGH); - } + // プリアンブルビット + uint8_t cnt = ((micros() - _lastWriteTime) / BIT_PERIOD) + 1; + if(cnt > MAX_CARRIR_BITS){ + cnt = MAX_CARRIR_BITS; } - modulate(LOW); // Start Bit - for(uint8_t mask = 1; mask; mask <<= 1){ // Data Bits - if(data & mask){ - modulate(HIGH); - } - else{ - modulate(LOW); - } + for(uint8_t i = 0; i - -void SoftModem::handleAnalogComp(bool high) +size_t SoftModem::write(uint8_t data) { - int cnt = (high ? SOFT_MODEM_HIGH_CNT : SOFT_MODEM_LOW_CNT); - int usec = (high ? SOFT_MODEM_HIGH_USEC : SOFT_MODEM_LOW_USEC); - int adj = (high ? SOFT_MODEM_HIGH_ADJ : SOFT_MODEM_LOW_ADJ); - for(int i=0;i "); - Serial.println(TCNT_LOW_FREQ,DEC); - Serial.println(TCNT_LOW_TH_L,DEC); - Serial.println(TCNT_LOW_TH_H,DEC); - - Serial.println("high freq TMC > "); - Serial.println(TCNT_HIGH_FREQ,DEC); - Serial.println(TCNT_HIGH_TH_L,DEC); - Serial.println(TCNT_HIGH_TH_H,DEC); - - Serial.print("bit period TMC = "); - Serial.println(TCNT_BIT_PERIOD,DEC); - - begin(); - - delay(200); - - handleAnalogComp(0);//start bit - - handleAnalogComp(1); - handleAnalogComp(0); - handleAnalogComp(1); - handleAnalogComp(0); - - handleAnalogComp(0); - handleAnalogComp(1); - handleAnalogComp(0); - handleAnalogComp(1); - - handleAnalogComp(1);//parity bit - handleAnalogComp(1);//stop bit - - delay(300); - - handleAnalogComp(0);//start bit - - handleAnalogComp(1); - handleAnalogComp(1); - handleAnalogComp(1); - handleAnalogComp(0); - - handleAnalogComp(1); - handleAnalogComp(1); - handleAnalogComp(1); - handleAnalogComp(0); - - handleAnalogComp(1);//parity bit - handleAnalogComp(1);//stop bit - - delay(300); - - handleAnalogComp(0);//start bit - - handleAnalogComp(0); - handleAnalogComp(1); - handleAnalogComp(1); - handleAnalogComp(1); - - handleAnalogComp(0); - handleAnalogComp(1); - handleAnalogComp(1); - handleAnalogComp(1); - - handleAnalogComp(1);//parity bit - handleAnalogComp(1);//stop bit - - delay(300); - - Serial.println("--"); - Serial.println(_recvStat,HEX); - Serial.println(_lastTCNT,HEX); - Serial.println(_recvBits,HEX); - - while(available()){ - Serial.print("data="); - Serial.println(read(),HEX); - } - - end(); -} -#endif diff --git a/arduino/libraries/SoftModem/SoftModem.h b/arduino/libraries/SoftModem/SoftModem.h index 8348ebe..2328bda 100644 --- a/arduino/libraries/SoftModem/SoftModem.h +++ b/arduino/libraries/SoftModem/SoftModem.h @@ -1,53 +1,36 @@ #ifndef SoftModem_h #define SoftModem_h -#include -#include +#include //#define SOFT_MODEM_BAUD_RATE (126) //#define SOFT_MODEM_LOW_FREQ (882) //#define SOFT_MODEM_HIGH_FREQ (1764) -//#define SOFT_MODEM_MAX_RX_BUFF (4) +//#define SOFT_MODEM_RX_BUF_SIZE (4) -//#define SOFT_MODEM_BAUD_RATE (100) -//#define SOFT_MODEM_LOW_FREQ (800) -//#define SOFT_MODEM_HIGH_FREQ (1600) -//#define SOFT_MODEM_MAX_RX_BUFF (4) +//#define SOFT_MODEM_BAUD_RATE (315) +//#define SOFT_MODEM_LOW_FREQ (1575) +//#define SOFT_MODEM_HIGH_FREQ (3150) +//#define SOFT_MODEM_RX_BUF_SIZE (8) -// #define SOFT_MODEM_BAUD_RATE (315) -// #define SOFT_MODEM_LOW_FREQ (1575) -// #define SOFT_MODEM_HIGH_FREQ (3150) -// #define SOFT_MODEM_MAX_RX_BUFF (8) - -// #define SOFT_MODEM_BAUD_RATE (630) -// #define SOFT_MODEM_LOW_FREQ (3150) -// #define SOFT_MODEM_HIGH_FREQ (6300) -// #define SOFT_MODEM_MAX_RX_BUFF (16) - -//#define SOFT_MODEM_BAUD_RATE (600) -//#define SOFT_MODEM_LOW_FREQ (2666) -//#define SOFT_MODEM_HIGH_FREQ (4000) -//#define SOFT_MODEM_MAX_RX_BUFF (16) +//#define SOFT_MODEM_BAUD_RATE (630) +//#define SOFT_MODEM_LOW_FREQ (3150) +//#define SOFT_MODEM_HIGH_FREQ (6300) +//#define SOFT_MODEM_RX_BUF_SIZE (16) #define SOFT_MODEM_BAUD_RATE (1225) #define SOFT_MODEM_LOW_FREQ (4900) #define SOFT_MODEM_HIGH_FREQ (7350) -#define SOFT_MODEM_MAX_RX_BUFF (32) +#define SOFT_MODEM_RX_BUF_SIZE (32) //#define SOFT_MODEM_BAUD_RATE (2450) -//#define SOFT_MODEM_LOW_FREQ (7350) -//#define SOFT_MODEM_HIGH_FREQ (14700) -//#define SOFT_MODEM_MAX_RX_BUFF (32) +//#define SOFT_MODEM_LOW_FREQ (4900) +//#define SOFT_MODEM_HIGH_FREQ (7350) +//#define SOFT_MODEM_RX_BUF_SIZE (32) -// Brief carrier tone before each transmission -// 1 start bit (LOW) -// 8 data bits, LSB first -// 1 stop bit (HIGH) -// 1 push bit (HIGH) +#define SOFT_MODEM_DEBUG_ENABLE (0) -#define SOFT_MODEM_DEBUG (0) - -class SoftModem : public Print +class SoftModem : public Stream { private: volatile uint8_t *_txPortReg; @@ -58,29 +41,25 @@ private: uint8_t _recvBits; uint8_t _recvBufferHead; uint8_t _recvBufferTail; - uint8_t _recvBuffer[SOFT_MODEM_MAX_RX_BUFF]; + uint8_t _recvBuffer[SOFT_MODEM_RX_BUF_SIZE]; uint8_t _lowCount; uint8_t _highCount; + unsigned long _lastWriteTime; void modulate(uint8_t b); public: SoftModem(); ~SoftModem(); void begin(void); void end(void); - uint8_t available(void); - int read(void); - void write(uint8_t data); + virtual int available(); + virtual int read(); + virtual void flush(); + virtual int peek(); + virtual size_t write(const uint8_t *buffer, size_t size); + virtual size_t write(uint8_t data); void demodulate(void); void recv(void); static SoftModem *activeObject; -#if SOFT_MODEM_DEBUG - void handleAnalogComp(bool high); - void demodulateTest(void); - uint8_t _errs; - uint16_t _ints; - uint8_t errs; - uint16_t ints; -#endif }; #endif diff --git a/arduino/softmodemsample/softmodemsample.ino b/arduino/softmodemsample/softmodemsample.ino new file mode 100644 index 0000000..8f3196d --- /dev/null +++ b/arduino/softmodemsample/softmodemsample.ino @@ -0,0 +1,51 @@ +/* +Arduinoとは次のように接続します(右側がArduinoの端子)。 + +* FSKOUT→D3 +* GND→GND +* VCC→VCC +* FSKIN→D6 +* AIN1→D7 + +ボリューム調整 + +Arduinoの電源電圧に合わせて調整します。AIN1の電圧をテスターで計り、(VCC / 2) + 300mVになるよう調節します。 + +* 5V電源の場合、2.7V +* 3.3V電源の場合、1.95V + +引用 - http://code.google.com/p/arms22/wiki/SoftModemBreakoutBoard +*/ + +#include +#include + +SoftModem modem; + +void setup() +{ + Serial.begin(57600); + delay(1000); + modem.begin(); +} + +void loop() +{ + while(modem.available()){ + char c = modem.read(); + if(isprint(c)){ + Serial.print(c); + } + else{ + Serial.print("\\x"); + Serial.print((uint8_t)c,HEX); + } + } + if(Serial.available()){ + modem.write(0xff); + while(Serial.available()){ + char c = Serial.read(); + modem.write(c); + } + } +}