softmodem
This commit is contained in:
parent
e2a62bee98
commit
83508c313e
8 changed files with 814 additions and 327 deletions
23
arduino/libraries/SoftModem/.svn/all-wcprops
Normal file
23
arduino/libraries/SoftModem/.svn/all-wcprops
Normal file
|
@ -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
|
130
arduino/libraries/SoftModem/.svn/entries
Normal file
130
arduino/libraries/SoftModem/.svn/entries
Normal file
|
@ -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
|
||||||
|
|
|
@ -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<cnt; i++){
|
||||||
|
modulate(HIGH);
|
||||||
|
}
|
||||||
|
size_t n = size;
|
||||||
|
while (size--) {
|
||||||
|
uint8_t data = *buffer++;
|
||||||
|
// スタート1ビット
|
||||||
|
modulate(LOW);
|
||||||
|
// データ8ビット
|
||||||
|
for(uint8_t mask = 1; mask; mask <<= 1){
|
||||||
|
if(data & mask){
|
||||||
|
modulate(HIGH);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
modulate(LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ストップ1ビット
|
||||||
|
modulate(HIGH);
|
||||||
|
}
|
||||||
|
// ポストアンブルビット
|
||||||
|
modulate(HIGH);
|
||||||
|
_lastWriteTime = micros();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SoftModem::write(uint8_t data)
|
||||||
|
{
|
||||||
|
return write(&data, 1);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef SoftModem_h
|
||||||
|
#define SoftModem_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
//#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
|
|
@ -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)
|
||||||
|
#######################################
|
|
@ -1,12 +1,8 @@
|
||||||
#include <WProgram.h>
|
|
||||||
#include <WConstants.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
#include <pins_arduino.h>
|
|
||||||
#include "SoftModem.h"
|
#include "SoftModem.h"
|
||||||
|
|
||||||
#define SOFT_MODEM_TX_PIN (3)
|
#define TX_PIN (3)
|
||||||
#define SOFT_MODEM_RX_PIN1 (6) // AIN0
|
#define RX_PIN1 (6) // AIN0
|
||||||
#define SOFT_MODEM_RX_PIN2 (7) // AIN1
|
#define RX_PIN2 (7) // AIN1
|
||||||
|
|
||||||
SoftModem *SoftModem::activeObject = 0;
|
SoftModem *SoftModem::activeObject = 0;
|
||||||
|
|
||||||
|
@ -19,135 +15,112 @@ SoftModem::~SoftModem() {
|
||||||
|
|
||||||
#if F_CPU == 16000000
|
#if F_CPU == 16000000
|
||||||
#if SOFT_MODEM_BAUD_RATE <= 126
|
#if SOFT_MODEM_BAUD_RATE <= 126
|
||||||
#define TIMER_CLOCK_SELECT (7)
|
#define TIMER_CLOCK_SELECT (7)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024))
|
||||||
#elif SOFT_MODEM_BAUD_RATE <= 315
|
#elif SOFT_MODEM_BAUD_RATE <= 315
|
||||||
#define TIMER_CLOCK_SELECT (6)
|
#define TIMER_CLOCK_SELECT (6)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
|
||||||
#elif SOFT_MODEM_BAUD_RATE <= 630
|
#elif SOFT_MODEM_BAUD_RATE <= 630
|
||||||
#define TIMER_CLOCK_SELECT (5)
|
#define TIMER_CLOCK_SELECT (5)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
|
||||||
#elif SOFT_MODEM_BAUD_RATE <= 1225
|
#elif SOFT_MODEM_BAUD_RATE <= 1225
|
||||||
#define TIMER_CLOCK_SELECT (4)
|
#define TIMER_CLOCK_SELECT (4)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
|
||||||
#else
|
#else
|
||||||
#define TIMER_CLOCK_SELECT (3)
|
#define TIMER_CLOCK_SELECT (3)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#if SOFT_MODEM_BAUD_RATE <= 126
|
#if SOFT_MODEM_BAUD_RATE <= 126
|
||||||
#define TIMER_CLOCK_SELECT (6)
|
#define TIMER_CLOCK_SELECT (6)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
|
||||||
#elif SOFT_MODEM_BAUD_RATE <= 315
|
#elif SOFT_MODEM_BAUD_RATE <= 315
|
||||||
#define TIMER_CLOCK_SELECT (5)
|
#define TIMER_CLOCK_SELECT (5)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
|
||||||
#elif SOFT_MODEM_BAUD_RATE <= 630
|
#elif SOFT_MODEM_BAUD_RATE <= 630
|
||||||
#define TIMER_CLOCK_SELECT (4)
|
#define TIMER_CLOCK_SELECT (4)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
|
||||||
#else
|
#else
|
||||||
#define TIMER_CLOCK_SELECT (3)
|
#define TIMER_CLOCK_SELECT (3)
|
||||||
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
|
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SOFT_MODEM_BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE)
|
#define BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE)
|
||||||
#define SOFT_MODEM_HIGH_USEC (1000000/SOFT_MODEM_HIGH_FREQ)
|
#define HIGH_FREQ_MICROS (1000000/SOFT_MODEM_HIGH_FREQ)
|
||||||
#define SOFT_MODEM_LOW_USEC (1000000/SOFT_MODEM_LOW_FREQ)
|
#define LOW_FREQ_MICROS (1000000/SOFT_MODEM_LOW_FREQ)
|
||||||
|
|
||||||
#define SOFT_MODEM_HIGH_CNT (SOFT_MODEM_BIT_PERIOD/SOFT_MODEM_HIGH_USEC)
|
#define HIGH_FREQ_CNT (BIT_PERIOD/HIGH_FREQ_MICROS)
|
||||||
#define SOFT_MODEM_LOW_CNT (SOFT_MODEM_BIT_PERIOD/SOFT_MODEM_LOW_USEC)
|
#define LOW_FREQ_CNT (BIT_PERIOD/LOW_FREQ_MICROS)
|
||||||
|
|
||||||
#define SOFT_MODEM_HIGH_ADJ (SOFT_MODEM_BIT_PERIOD%SOFT_MODEM_HIGH_USEC)
|
#define MAX_CARRIR_BITS (40000/BIT_PERIOD)
|
||||||
#define SOFT_MODEM_LOW_ADJ (SOFT_MODEM_BIT_PERIOD%SOFT_MODEM_LOW_USEC)
|
|
||||||
|
|
||||||
#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_TH_L (TCNT_HIGH_FREQ * 0.90)
|
||||||
#define TCNT_HIGH_FREQ (SOFT_MODEM_HIGH_USEC/MICROS_PER_TIMER_COUNT)
|
#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15)
|
||||||
#define TCNT_LOW_FREQ (SOFT_MODEM_LOW_USEC/MICROS_PER_TIMER_COUNT)
|
#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)
|
#if SOFT_MODEM_DEBUG_ENABLE
|
||||||
#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15)
|
static volatile uint8_t *_portLEDReg;
|
||||||
#define TCNT_LOW_TH_L (TCNT_LOW_FREQ * 0.85)
|
static uint8_t _portLEDMask;
|
||||||
#define TCNT_LOW_TH_H (TCNT_LOW_FREQ * 1.20)
|
|
||||||
|
|
||||||
#if SOFT_MODEM_DEBUG
|
|
||||||
static volatile uint8_t *portLEDReg;
|
|
||||||
static uint8_t portLEDMask;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum { START_BIT = 0, DATA_BIT = 8, STOP_BIT = 9, INACTIVE = 0xff };
|
||||||
|
|
||||||
void SoftModem::begin(void)
|
void SoftModem::begin(void)
|
||||||
{
|
{
|
||||||
pinMode(SOFT_MODEM_RX_PIN1, INPUT);
|
pinMode(RX_PIN1, INPUT);
|
||||||
digitalWrite(SOFT_MODEM_RX_PIN1, LOW);
|
digitalWrite(RX_PIN1, LOW);
|
||||||
|
|
||||||
pinMode(SOFT_MODEM_RX_PIN2, INPUT);
|
pinMode(RX_PIN2, INPUT);
|
||||||
digitalWrite(SOFT_MODEM_RX_PIN2, LOW);
|
digitalWrite(RX_PIN2, LOW);
|
||||||
|
|
||||||
pinMode(SOFT_MODEM_TX_PIN, OUTPUT);
|
pinMode(TX_PIN, OUTPUT);
|
||||||
digitalWrite(SOFT_MODEM_TX_PIN, LOW);
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
|
||||||
_txPortReg = portOutputRegister(digitalPinToPort(SOFT_MODEM_TX_PIN));
|
_txPortReg = portOutputRegister(digitalPinToPort(TX_PIN));
|
||||||
_txPortMask = digitalPinToBitMask(SOFT_MODEM_TX_PIN);
|
_txPortMask = digitalPinToBitMask(TX_PIN);
|
||||||
|
|
||||||
#if SOFT_MODEM_DEBUG
|
#if SOFT_MODEM_DEBUG_ENABLE
|
||||||
portLEDReg = portOutputRegister(digitalPinToPort(13));
|
_portLEDReg = portOutputRegister(digitalPinToPort(13));
|
||||||
portLEDMask = digitalPinToBitMask(13);
|
_portLEDMask = digitalPinToBitMask(13);
|
||||||
_errs = 0;
|
pinMode(13, OUTPUT);
|
||||||
_ints = 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_recvStat = 0xff;
|
_recvStat = INACTIVE;
|
||||||
_recvBufferHead = _recvBufferTail = 0;
|
_recvBufferHead = _recvBufferTail = 0;
|
||||||
|
|
||||||
SoftModem::activeObject = this;
|
SoftModem::activeObject = this;
|
||||||
|
|
||||||
_lastTCNT = TCNT2;
|
_lastTCNT = TCNT2;
|
||||||
_lastDiff = _lowCount = _highCount = 0;
|
_lastDiff = _lowCount = _highCount = 0;
|
||||||
|
|
||||||
TCCR2A = 0;
|
TCCR2A = 0;
|
||||||
TCCR2B = TIMER_CLOCK_SELECT;
|
TCCR2B = TIMER_CLOCK_SELECT;
|
||||||
ACSR = _BV(ACIE) | _BV(ACIS1);
|
ACSR = _BV(ACIE) | _BV(ACIS1);
|
||||||
|
DIDR1 = _BV(AIN1D) | _BV(AIN0D);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftModem::end(void)
|
void SoftModem::end(void)
|
||||||
{
|
{
|
||||||
ACSR &= ~(_BV(ACIE));
|
ACSR &= ~(_BV(ACIE));
|
||||||
TIMSK2 &= ~(_BV(OCIE2A));
|
TIMSK2 &= ~(_BV(OCIE2A));
|
||||||
|
DIDR1 &= ~(_BV(AIN1D) | _BV(AIN0D));
|
||||||
SoftModem::activeObject = 0;
|
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)
|
void SoftModem::demodulate(void)
|
||||||
{
|
{
|
||||||
uint8_t t = TCNT2;
|
uint8_t t = TCNT2;
|
||||||
uint8_t diff;
|
uint8_t diff;
|
||||||
|
|
||||||
if(TIFR2 & _BV(TOV2)){
|
diff = t - _lastTCNT;
|
||||||
TIFR2 |= _BV(TOV2);
|
|
||||||
diff = (255 - _lastTCNT) + t + 1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
diff = t - _lastTCNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SOFT_MODEM_DEBUG
|
if(diff < 4)
|
||||||
_ints++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(diff < (uint8_t)(TCNT_HIGH_TH_L)) // Noise?
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_lastTCNT = t;
|
_lastTCNT = t;
|
||||||
|
@ -155,122 +128,138 @@ void SoftModem::demodulate(void)
|
||||||
if(diff > (uint8_t)(TCNT_LOW_TH_H))
|
if(diff > (uint8_t)(TCNT_LOW_TH_H))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// 移動平均
|
||||||
_lastDiff = (diff >> 1) + (diff >> 2) + (_lastDiff >> 2);
|
_lastDiff = (diff >> 1) + (diff >> 2) + (_lastDiff >> 2);
|
||||||
|
|
||||||
if(_lastDiff >= (uint8_t)(TCNT_LOW_TH_L)){
|
if(_lastDiff >= (uint8_t)(TCNT_LOW_TH_L)){
|
||||||
_lowCount += _lastDiff;
|
_lowCount += _lastDiff;
|
||||||
if((_recvStat == 0xff) && (_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5))){ // maybe Start-Bit
|
if(_recvStat == INACTIVE){
|
||||||
_recvStat = FSK_START_BIT;
|
// スタートビット検出
|
||||||
_highCount = 0;
|
if(_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5)){
|
||||||
_recvBits = 0;
|
_recvStat = START_BIT;
|
||||||
OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount; // 1 bit period after detected
|
_highCount = 0;
|
||||||
TIFR2 |= _BV(OCF2A);
|
_recvBits = 0;
|
||||||
TIMSK2 |= _BV(OCIE2A);
|
OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount;
|
||||||
|
TIFR2 |= _BV(OCF2A);
|
||||||
|
TIMSK2 |= _BV(OCIE2A);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(_lastDiff <= (uint8_t)(TCNT_HIGH_TH_H)){
|
else if(_lastDiff <= (uint8_t)(TCNT_HIGH_TH_H)){
|
||||||
_highCount += _lastDiff;
|
if(_recvStat == INACTIVE){
|
||||||
if((_recvStat == 0xff) && (_highCount >= (uint8_t)(TCNT_BIT_PERIOD))){
|
_lowCount = 0;
|
||||||
_lowCount = _highCount = 0;
|
_highCount = 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_highCount += _lastDiff;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else{
|
|
||||||
#if SOFT_MODEM_DEBUG
|
|
||||||
_errs++;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// アナログコンパレータ割り込み
|
||||||
ISR(ANALOG_COMP_vect)
|
ISR(ANALOG_COMP_vect)
|
||||||
{
|
{
|
||||||
SoftModem *act = SoftModem::activeObject;
|
SoftModem::activeObject->demodulate();
|
||||||
act->demodulate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftModem::recv(void)
|
void SoftModem::recv(void)
|
||||||
{
|
{
|
||||||
uint8_t high;
|
uint8_t high;
|
||||||
|
|
||||||
|
// ビット論理判定
|
||||||
if(_highCount > _lowCount){
|
if(_highCount > _lowCount){
|
||||||
if(_highCount >= (uint8_t)TCNT_BIT_PERIOD)
|
_highCount = 0;
|
||||||
_highCount -= (uint8_t)TCNT_BIT_PERIOD;
|
|
||||||
else
|
|
||||||
_highCount = 0;
|
|
||||||
high = 0x80;
|
high = 0x80;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(_lowCount >= (uint8_t)TCNT_BIT_PERIOD)
|
_lowCount = 0;
|
||||||
_lowCount -= (uint8_t)TCNT_BIT_PERIOD;
|
|
||||||
else
|
|
||||||
_lowCount = 0;
|
|
||||||
high = 0x00;
|
high = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_recvStat == FSK_START_BIT){ // Start bit
|
// スタートビット受信
|
||||||
|
if(_recvStat == START_BIT){
|
||||||
if(!high){
|
if(!high){
|
||||||
_recvStat++;
|
_recvStat++;
|
||||||
}else{
|
}
|
||||||
|
else{
|
||||||
goto end_recv;
|
goto end_recv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(_recvStat <= FSK_D7_BIT) { // Data bits
|
// データビット受信
|
||||||
|
else if(_recvStat <= DATA_BIT) {
|
||||||
_recvBits >>= 1;
|
_recvBits >>= 1;
|
||||||
_recvBits |= high;
|
_recvBits |= high;
|
||||||
_recvStat++;
|
_recvStat++;
|
||||||
}
|
}
|
||||||
else if(_recvStat == FSK_STOP_BIT){ // Stop bit
|
// ストップビット受信
|
||||||
uint8_t new_tail = (_recvBufferTail + 1) & (SOFT_MODEM_MAX_RX_BUFF - 1);
|
else if(_recvStat == STOP_BIT){
|
||||||
if(new_tail != _recvBufferHead){
|
if(high){
|
||||||
_recvBuffer[_recvBufferTail] = _recvBits;
|
// 受信バッファに格納
|
||||||
_recvBufferTail = new_tail;
|
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;
|
goto end_recv;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
end_recv:
|
end_recv:
|
||||||
_recvStat = 0xff;
|
_recvStat = INACTIVE;
|
||||||
TIMSK2 &= ~_BV(OCIE2A);
|
TIMSK2 &= ~_BV(OCIE2A);
|
||||||
#if SOFT_MODEM_DEBUG
|
|
||||||
errs = _errs;
|
|
||||||
_errs = 0;
|
|
||||||
ints = _ints;
|
|
||||||
_ints = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// タイマー2比較一致割り込みA
|
||||||
ISR(TIMER2_COMPA_vect)
|
ISR(TIMER2_COMPA_vect)
|
||||||
{
|
{
|
||||||
OCR2A += (uint8_t)TCNT_BIT_PERIOD;
|
OCR2A += (uint8_t)TCNT_BIT_PERIOD;
|
||||||
SoftModem *act = SoftModem::activeObject;
|
SoftModem::activeObject->recv();
|
||||||
act->recv();
|
#if SOFT_MODEM_DEBUG_ENABLE
|
||||||
#if SOFT_MODEM_DEBUG
|
*_portLEDReg ^= _portLEDMask;
|
||||||
*portLEDReg ^= portLEDMask;
|
#endif
|
||||||
#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)
|
if(_recvBufferHead == _recvBufferTail)
|
||||||
return -1;
|
return -1;
|
||||||
int d = _recvBuffer[_recvBufferHead];
|
int d = _recvBuffer[_recvBufferHead];
|
||||||
_recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_MAX_RX_BUFF - 1);
|
_recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SoftModem::peek()
|
||||||
|
{
|
||||||
|
if(_recvBufferHead == _recvBufferTail)
|
||||||
|
return -1;
|
||||||
|
return _recvBuffer[_recvBufferHead];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoftModem::flush()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void SoftModem::modulate(uint8_t b)
|
void SoftModem::modulate(uint8_t b)
|
||||||
{
|
{
|
||||||
uint8_t cnt,tcnt,tcnt2,adj;
|
uint8_t cnt,tcnt,tcnt2;
|
||||||
if(b){
|
if(b){
|
||||||
cnt = (uint8_t)(SOFT_MODEM_HIGH_CNT);
|
cnt = (uint8_t)(HIGH_FREQ_CNT);
|
||||||
tcnt2 = (uint8_t)(TCNT_HIGH_FREQ / 2);
|
tcnt2 = (uint8_t)(TCNT_HIGH_FREQ / 2);
|
||||||
tcnt = (uint8_t)(TCNT_HIGH_FREQ) - tcnt2;
|
tcnt = (uint8_t)(TCNT_HIGH_FREQ) - tcnt2;
|
||||||
}else{
|
}else{
|
||||||
cnt = (uint8_t)(SOFT_MODEM_LOW_CNT);
|
cnt = (uint8_t)(LOW_FREQ_CNT);
|
||||||
tcnt2 = (uint8_t)(TCNT_LOW_FREQ / 2);
|
tcnt2 = (uint8_t)(TCNT_LOW_FREQ / 2);
|
||||||
tcnt = (uint8_t)(TCNT_LOW_FREQ) - tcnt2;
|
tcnt = (uint8_t)(TCNT_LOW_FREQ) - tcnt2;
|
||||||
}
|
}
|
||||||
|
@ -291,149 +280,47 @@ void SoftModem::modulate(uint8_t b)
|
||||||
} while (cnt);
|
} 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)){
|
uint8_t cnt = ((micros() - _lastWriteTime) / BIT_PERIOD) + 1;
|
||||||
for(uint8_t i = 0; i<(uint8_t)SOFT_MODEM_CARRIR_CNT; i++){
|
if(cnt > MAX_CARRIR_BITS){
|
||||||
modulate(HIGH);
|
cnt = MAX_CARRIR_BITS;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
modulate(LOW); // Start Bit
|
for(uint8_t i = 0; i<cnt; i++){
|
||||||
for(uint8_t mask = 1; mask; mask <<= 1){ // Data Bits
|
modulate(HIGH);
|
||||||
if(data & mask){
|
|
||||||
modulate(HIGH);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
modulate(LOW);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
modulate(HIGH); // Stop Bit
|
size_t n = size;
|
||||||
modulate(HIGH); // Push Bit
|
while (size--) {
|
||||||
lastTransmissionTime = micros();
|
uint8_t data = *buffer++;
|
||||||
|
// スタート1ビット
|
||||||
|
modulate(LOW);
|
||||||
|
// データ8ビット
|
||||||
|
for(uint8_t mask = 1; mask; mask <<= 1){
|
||||||
|
if(data & mask){
|
||||||
|
modulate(HIGH);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
modulate(LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ストップ1ビット
|
||||||
|
modulate(HIGH);
|
||||||
|
}
|
||||||
|
// ポストアンブルビット
|
||||||
|
modulate(HIGH);
|
||||||
|
_lastWriteTime = micros();
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOFT_MODEM_DEBUG
|
size_t SoftModem::write(uint8_t data)
|
||||||
#include <HardwareSerial.h>
|
|
||||||
|
|
||||||
void SoftModem::handleAnalogComp(bool high)
|
|
||||||
{
|
{
|
||||||
int cnt = (high ? SOFT_MODEM_HIGH_CNT : SOFT_MODEM_LOW_CNT);
|
return write(&data, 1);
|
||||||
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<cnt;i++){
|
|
||||||
unsigned long end = micros() + usec;
|
|
||||||
demodulate();
|
|
||||||
while(micros() < end);
|
|
||||||
}
|
|
||||||
if(adj)
|
|
||||||
delayMicroseconds(adj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftModem::demodulateTest(void)
|
|
||||||
{
|
|
||||||
Serial.print("bit period = ");
|
|
||||||
Serial.println(SOFT_MODEM_BIT_PERIOD);
|
|
||||||
|
|
||||||
Serial.print("low usec = ");
|
|
||||||
Serial.println(SOFT_MODEM_LOW_USEC);
|
|
||||||
|
|
||||||
Serial.print("high usec = ");
|
|
||||||
Serial.println(SOFT_MODEM_HIGH_USEC);
|
|
||||||
|
|
||||||
Serial.print("low cnt = ");
|
|
||||||
Serial.println(SOFT_MODEM_LOW_CNT);
|
|
||||||
|
|
||||||
Serial.print("high cnt = ");
|
|
||||||
Serial.println(SOFT_MODEM_HIGH_CNT);
|
|
||||||
|
|
||||||
Serial.print("low adj = ");
|
|
||||||
Serial.println(SOFT_MODEM_LOW_ADJ);
|
|
||||||
|
|
||||||
Serial.print("high adj = ");
|
|
||||||
Serial.println(SOFT_MODEM_HIGH_ADJ);
|
|
||||||
|
|
||||||
Serial.print("TMC micros = ");
|
|
||||||
Serial.println(MICROS_PER_TIMER_COUNT);
|
|
||||||
|
|
||||||
Serial.println("low freq TMC > ");
|
|
||||||
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
|
|
||||||
|
|
|
@ -1,53 +1,36 @@
|
||||||
#ifndef SoftModem_h
|
#ifndef SoftModem_h
|
||||||
#define SoftModem_h
|
#define SoftModem_h
|
||||||
|
|
||||||
#include <Print.h>
|
#include <Arduino.h>
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
//#define SOFT_MODEM_BAUD_RATE (126)
|
//#define SOFT_MODEM_BAUD_RATE (126)
|
||||||
//#define SOFT_MODEM_LOW_FREQ (882)
|
//#define SOFT_MODEM_LOW_FREQ (882)
|
||||||
//#define SOFT_MODEM_HIGH_FREQ (1764)
|
//#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_BAUD_RATE (315)
|
||||||
//#define SOFT_MODEM_LOW_FREQ (800)
|
//#define SOFT_MODEM_LOW_FREQ (1575)
|
||||||
//#define SOFT_MODEM_HIGH_FREQ (1600)
|
//#define SOFT_MODEM_HIGH_FREQ (3150)
|
||||||
//#define SOFT_MODEM_MAX_RX_BUFF (4)
|
//#define SOFT_MODEM_RX_BUF_SIZE (8)
|
||||||
|
|
||||||
// #define SOFT_MODEM_BAUD_RATE (315)
|
//#define SOFT_MODEM_BAUD_RATE (630)
|
||||||
// #define SOFT_MODEM_LOW_FREQ (1575)
|
//#define SOFT_MODEM_LOW_FREQ (3150)
|
||||||
// #define SOFT_MODEM_HIGH_FREQ (3150)
|
//#define SOFT_MODEM_HIGH_FREQ (6300)
|
||||||
// #define SOFT_MODEM_MAX_RX_BUFF (8)
|
//#define SOFT_MODEM_RX_BUF_SIZE (16)
|
||||||
|
|
||||||
// #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 (1225)
|
#define SOFT_MODEM_BAUD_RATE (1225)
|
||||||
#define SOFT_MODEM_LOW_FREQ (4900)
|
#define SOFT_MODEM_LOW_FREQ (4900)
|
||||||
#define SOFT_MODEM_HIGH_FREQ (7350)
|
#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_BAUD_RATE (2450)
|
||||||
//#define SOFT_MODEM_LOW_FREQ (7350)
|
//#define SOFT_MODEM_LOW_FREQ (4900)
|
||||||
//#define SOFT_MODEM_HIGH_FREQ (14700)
|
//#define SOFT_MODEM_HIGH_FREQ (7350)
|
||||||
//#define SOFT_MODEM_MAX_RX_BUFF (32)
|
//#define SOFT_MODEM_RX_BUF_SIZE (32)
|
||||||
|
|
||||||
// Brief carrier tone before each transmission
|
#define SOFT_MODEM_DEBUG_ENABLE (0)
|
||||||
// 1 start bit (LOW)
|
|
||||||
// 8 data bits, LSB first
|
|
||||||
// 1 stop bit (HIGH)
|
|
||||||
// 1 push bit (HIGH)
|
|
||||||
|
|
||||||
#define SOFT_MODEM_DEBUG (0)
|
class SoftModem : public Stream
|
||||||
|
|
||||||
class SoftModem : public Print
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
volatile uint8_t *_txPortReg;
|
volatile uint8_t *_txPortReg;
|
||||||
|
@ -58,29 +41,25 @@ private:
|
||||||
uint8_t _recvBits;
|
uint8_t _recvBits;
|
||||||
uint8_t _recvBufferHead;
|
uint8_t _recvBufferHead;
|
||||||
uint8_t _recvBufferTail;
|
uint8_t _recvBufferTail;
|
||||||
uint8_t _recvBuffer[SOFT_MODEM_MAX_RX_BUFF];
|
uint8_t _recvBuffer[SOFT_MODEM_RX_BUF_SIZE];
|
||||||
uint8_t _lowCount;
|
uint8_t _lowCount;
|
||||||
uint8_t _highCount;
|
uint8_t _highCount;
|
||||||
|
unsigned long _lastWriteTime;
|
||||||
void modulate(uint8_t b);
|
void modulate(uint8_t b);
|
||||||
public:
|
public:
|
||||||
SoftModem();
|
SoftModem();
|
||||||
~SoftModem();
|
~SoftModem();
|
||||||
void begin(void);
|
void begin(void);
|
||||||
void end(void);
|
void end(void);
|
||||||
uint8_t available(void);
|
virtual int available();
|
||||||
int read(void);
|
virtual int read();
|
||||||
void write(uint8_t data);
|
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 demodulate(void);
|
||||||
void recv(void);
|
void recv(void);
|
||||||
static SoftModem *activeObject;
|
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
|
#endif
|
||||||
|
|
51
arduino/softmodemsample/softmodemsample.ino
Normal file
51
arduino/softmodemsample/softmodemsample.ino
Normal file
|
@ -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 <SoftModem.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue