first commit
This commit is contained in:
commit
ab7d989258
50
Arduino/Readme.md
Normal file
50
Arduino/Readme.md
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# KissTnc ARDUINO #
|
||||||
|
|
||||||
|
## Description ##
|
||||||
|
|
||||||
|
KissTnc is a C++ implementation of the TNC software for Arduino. It can be used for AX.25 / packet radio as well as for APRS applications. It is tested on the Arduino Nano and is compatible with MicroAPRS and PA4RAZ APRS projects. The sketch and all used cpp and header files can be opened in the Arduino IDE.
|
||||||
|
|
||||||
|
## Hardware ##
|
||||||
|
|
||||||
|
Hardware can be made around the Nano or other Arduino board, using the schematic added to this repository.
|
||||||
|
By default the following pins are used:
|
||||||
|
|
||||||
|
- RX LED pin D10
|
||||||
|
- TX LED pin D9
|
||||||
|
- RX only input D8
|
||||||
|
- PTT control pin D3
|
||||||
|
- Low level Input select pin D2
|
||||||
|
- The used analog input is A0
|
||||||
|
- The four pins for generating the AFSK modulation signal are pin D4, D5, D6 and D7.
|
||||||
|
|
||||||
|
The PTT, LED, RX only and level selection pins can be changed in the sketch by editing the defines in KissTnc.ino.
|
||||||
|
|
||||||
|
The squelch on the radio can stay open, detection of incomming data (and collision prevention) is done by software.
|
||||||
|
If the audio level from the transceiver is low (below 1V peak-to-peak), the TNC can be set in the low level mode. To run in low level mode, connect D2 to 5V, and connect R10 to Ref instead of 5V.
|
||||||
|
|
||||||
|
Rx only mode can be activated by connecting the RX only input (pin D9) to GND via a switch.
|
||||||
|
|
||||||
|
## KISS Protocol ##
|
||||||
|
|
||||||
|
KissTnc is compatible with the KISS protocol as described at:
|
||||||
|
<http://www.ax25.net/kiss.aspx>
|
||||||
|
|
||||||
|
The following KISS commands are implemented:
|
||||||
|
|
||||||
|
- CMD_DATA_FRAME (0x00)
|
||||||
|
- CMD_TX_DELAY (0x01)
|
||||||
|
- CMD_P (0x02)
|
||||||
|
- CMD_SLOT_TIME (0x03)
|
||||||
|
- CMD_FULL_DUPLEX (0x05)
|
||||||
|
|
||||||
|
For testing purpose an additional command is implemented:
|
||||||
|
|
||||||
|
- CMD_LOOPBACK_TEST (0xfe)
|
||||||
|
|
||||||
|
When enabling this function, packets transmitted from the host are routed back to the receiving part of the software. Instead of transmitting the packets, a constant 1200Hz tone is audible at the modulation output. After any change of the code, the software can be tested by doing a loop back test. The packet returned back to the host must be the same as the original ones. The signal set on the modulation output must be a stable 1200Hz (+/-1) tone. If this frequency is not 1200Hz or is not stable, the ISR is not returning on time.
|
||||||
|
|
||||||
|
Following is not implemented:
|
||||||
|
|
||||||
|
- CMD_TX_TAIL (0x04) (obsolete)
|
||||||
|
- CMD_SET_HARDWARE (0x06)
|
||||||
|
- CMD_RETURN (0xff)
|
BIN
Arduino/Schematic.pdf
Normal file
BIN
Arduino/Schematic.pdf
Normal file
Binary file not shown.
43
Arduino/afskSampler.cpp
Normal file
43
Arduino/afskSampler.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include "afskSampler.h"
|
||||||
|
|
||||||
|
HdlcAfskRx* g_afskRx;
|
||||||
|
HdlcAfskTx* g_afskTx;
|
||||||
|
byte loopBackSample;
|
||||||
|
|
||||||
|
AfskSampler::AfskSampler(int lowLevelSelectPin, HdlcAfskRx* afskRx, HdlcAfskTx* afskTx) {
|
||||||
|
g_afskRx = afskRx;
|
||||||
|
g_afskTx = afskTx;
|
||||||
|
|
||||||
|
boolean lowLevelMode = false;
|
||||||
|
if (lowLevelSelectPin > 0 ) {
|
||||||
|
pinMode(lowLevelSelectPin, INPUT);
|
||||||
|
lowLevelMode = digitalRead(lowLevelSelectPin) == HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADCSRA = 0;
|
||||||
|
ADCSRB = 0;
|
||||||
|
ADMUX |= (0 & 0x07); // pin A0
|
||||||
|
if (lowLevelMode) {
|
||||||
|
ADMUX |= (1 << REFS1); // set internal reference voltage to 1.1V
|
||||||
|
}
|
||||||
|
ADMUX |= (1 << REFS0); // set reference voltage internal
|
||||||
|
ADMUX |= (1 << ADLAR); // left align ADC value to 8 bits from ADCH register
|
||||||
|
|
||||||
|
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // 128 prescaler 9600 Hz
|
||||||
|
ADCSRA |= (1 << ADATE); // enable auto trigger
|
||||||
|
ADCSRA |= (1 << ADIE); // enable interrupts when measurement complete
|
||||||
|
ADCSRA |= (1 << ADEN); // enable ADC
|
||||||
|
ADCSRA |= (1 << ADSC); // start ADC measurements
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(ADC_vect) {
|
||||||
|
if (g_afskTx->loopbackTest) {
|
||||||
|
g_afskRx->decodeSample(loopBackSample);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_afskRx->decodeSample(ADCH);
|
||||||
|
}
|
||||||
|
loopBackSample = g_afskTx->encodeSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
13
Arduino/afskSampler.h
Normal file
13
Arduino/afskSampler.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef AFSK_SAMPLER_H
|
||||||
|
#define AFSK_SAMPLER_H
|
||||||
|
|
||||||
|
#include "hdlcAfskTx.h"
|
||||||
|
#include "hdlcAfskRx.h"
|
||||||
|
|
||||||
|
class AfskSampler {
|
||||||
|
public:
|
||||||
|
AfskSampler(int lowLevelSelectPin, HdlcAfskRx* afskRx, HdlcAfskTx* afskTx);
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
135
Arduino/hdlcAfskRx.cpp
Normal file
135
Arduino/hdlcAfskRx.cpp
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
#include "hdlcAfskRx.h"
|
||||||
|
|
||||||
|
HdlcAfskRx::HdlcAfskRx(HdlcFrameBuffer* rxBuffer) {
|
||||||
|
_rxBuffer = rxBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcAfskRx::decodeSample(byte sampleVal) {
|
||||||
|
int intAnVal = sampleVal - 127;
|
||||||
|
|
||||||
|
_rxFilter[0][0] = _rxFilter[0][1];
|
||||||
|
_rxFilter[0][1] = (_rxAnSamples[_histAnSampleIndex] * intAnVal) >> 2;
|
||||||
|
_rxFilter[1][0] = _rxFilter[1][1];
|
||||||
|
_rxFilter[1][1] = _rxFilter[0][0] + _rxFilter[0][1] + (_rxFilter[1][0] >> 1);
|
||||||
|
_rxAnSamples[_rxAnSampleIndex] = intAnVal;
|
||||||
|
_histAnSampleIndex++;
|
||||||
|
if (_histAnSampleIndex > MAX_RX_AN_SAMPLE_INDEX) {
|
||||||
|
_histAnSampleIndex = 0;
|
||||||
|
}
|
||||||
|
_rxAnSampleIndex++;
|
||||||
|
if (_rxAnSampleIndex > MAX_RX_AN_SAMPLE_INDEX) {
|
||||||
|
_rxAnSampleIndex = 0;
|
||||||
|
}
|
||||||
|
_spaceMarkSamples <<= 1;
|
||||||
|
_spaceMarkSamples |= (_rxFilter[1][1] > 0) ? 1 : 0;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
( (_spaceMarkSamples)^(_spaceMarkSamples >> 2) ) & SPACE_MARK_TRANSISION_MASK
|
||||||
|
) == SPACE_MARK_TRANSISION_MASK
|
||||||
|
) {
|
||||||
|
if (_currentPhase < HALF_WINDOW_SAMPLE_COUNT) {
|
||||||
|
_currentPhase += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_currentPhase -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentPhase += RX_AN_SAMPLE_COUNT;
|
||||||
|
if (_currentPhase >= WINDOW_SAMPLE_COUNT) {
|
||||||
|
_currentPhase %= WINDOW_SAMPLE_COUNT;
|
||||||
|
byte bits = _spaceMarkSamples & 0x07;
|
||||||
|
setNextMark(
|
||||||
|
(bits == 0x07 || // 111
|
||||||
|
bits == 0x06 || // 110
|
||||||
|
bits == 0x05 || // 101
|
||||||
|
bits == 0x03) // 011
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcAfskRx::setNextMark(boolean spaceMark) {
|
||||||
|
_prevSpace = _currentSpace;
|
||||||
|
_currentSpace = spaceMark;
|
||||||
|
|
||||||
|
boolean flagDetect = false;
|
||||||
|
|
||||||
|
switch (stufState) {
|
||||||
|
case STUF_NO_STUF:
|
||||||
|
_afskShiftInReg >>= 1;
|
||||||
|
_rxBitCount++;
|
||||||
|
if (_rxBitCount > 8) {
|
||||||
|
_rxBitCount = 1;
|
||||||
|
}
|
||||||
|
_afskShiftInReg |= (_prevSpace == _currentSpace) ? 0x80 : 0;
|
||||||
|
flagDetect = _afskShiftInReg == HDLC_FLAG;
|
||||||
|
if ((_afskShiftInReg == STUF1) || (_afskShiftInReg == STUF2)) {
|
||||||
|
stufState = STUF_SKIP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STUF_SKIP:
|
||||||
|
_afskShiftInReg |= (_prevSpace == _currentSpace) ? 0x80 : 0;
|
||||||
|
stufState = STUF_SKIP_CHECKS;
|
||||||
|
break;
|
||||||
|
case STUF_SKIP_CHECKS:
|
||||||
|
_afskShiftInReg >>= 1;
|
||||||
|
_rxBitCount++;
|
||||||
|
if (_rxBitCount > 8) {
|
||||||
|
_rxBitCount = 1;
|
||||||
|
}
|
||||||
|
_afskShiftInReg |= (_prevSpace == _currentSpace) ? 0x80 : 0;
|
||||||
|
stufState = STUF_NO_STUF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stufState == STUF_SKIP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_frameRxState) {
|
||||||
|
case RXST_IDLE:
|
||||||
|
if (flagDetect) {
|
||||||
|
_rxBitCount = 0;
|
||||||
|
_frameRxState = RXST_SYNC1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RXST_SYNC1:
|
||||||
|
if (_rxBitCount > 7) {
|
||||||
|
if (flagDetect) {
|
||||||
|
_rxBuffer->frameReset();
|
||||||
|
_frameRxState = RXST_SYNC2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_frameRxState = RXST_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RXST_SYNC2:
|
||||||
|
if (_rxBitCount > 7) {
|
||||||
|
if (!flagDetect) {
|
||||||
|
_frameRxState = RXST_START;
|
||||||
|
receiving = true;
|
||||||
|
if (!_rxBuffer->push(_afskShiftInReg)) {
|
||||||
|
_frameRxState = RXST_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RXST_START:
|
||||||
|
if (flagDetect) {
|
||||||
|
_rxBitCount = 0;
|
||||||
|
_frameRxState = RXST_SYNC1;
|
||||||
|
receiving = false;
|
||||||
|
_rxBuffer->frameEnd();
|
||||||
|
}
|
||||||
|
else if (_rxBitCount > 7) {
|
||||||
|
if (!_rxBuffer->push(_afskShiftInReg)) {
|
||||||
|
_frameRxState = RXST_IDLE;
|
||||||
|
receiving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
46
Arduino/hdlcAfskRx.h
Normal file
46
Arduino/hdlcAfskRx.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef HDLC_AFSK_RX_H
|
||||||
|
#define HDLC_AFSK_RX_H
|
||||||
|
|
||||||
|
#include "hdlcFramesBuffer.h"
|
||||||
|
|
||||||
|
#define STUF_NO_STUF 0
|
||||||
|
#define STUF_SKIP 1
|
||||||
|
#define STUF_SKIP_CHECKS 2
|
||||||
|
|
||||||
|
#define RXST_IDLE 0
|
||||||
|
#define RXST_SYNC1 1
|
||||||
|
#define RXST_SYNC2 2
|
||||||
|
#define RXST_START 3
|
||||||
|
|
||||||
|
#define STUF1 0x7c
|
||||||
|
#define STUF2 0x7d
|
||||||
|
|
||||||
|
#define RX_AN_SAMPLE_COUNT 8
|
||||||
|
#define MAX_RX_AN_SAMPLE_INDEX 7
|
||||||
|
#define WINDOW_SAMPLE_COUNT 64
|
||||||
|
#define HALF_WINDOW_SAMPLE_COUNT 32
|
||||||
|
#define SPACE_MARK_TRANSISION_MASK 0x03
|
||||||
|
|
||||||
|
class HdlcAfskRx {
|
||||||
|
public:
|
||||||
|
HdlcAfskRx(HdlcFrameBuffer* rxBuffer);
|
||||||
|
void decodeSample(byte sampleVal);
|
||||||
|
boolean receiving = false;
|
||||||
|
private:
|
||||||
|
HdlcFrameBuffer* _rxBuffer;
|
||||||
|
int _rxFilter[2][2];
|
||||||
|
int _rxAnSamples[RX_AN_SAMPLE_COUNT];
|
||||||
|
int _rxAnSampleIndex = 0;
|
||||||
|
int _histAnSampleIndex = 4;
|
||||||
|
byte _spaceMarkSamples = 0x00;
|
||||||
|
int _currentPhase = 0;
|
||||||
|
boolean _prevSpace = false;
|
||||||
|
boolean _currentSpace = false;
|
||||||
|
byte _afskShiftInReg = 0x00;
|
||||||
|
int stufState = STUF_NO_STUF;
|
||||||
|
int _rxBitCount = 0;
|
||||||
|
int _frameRxState = RXST_IDLE;
|
||||||
|
void setNextMark(boolean spaceMark);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
159
Arduino/hdlcAfskTx.cpp
Normal file
159
Arduino/hdlcAfskTx.cpp
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#include "hdlcAfskTx.h"
|
||||||
|
|
||||||
|
const byte sinusTable[SIN_TABLE_SIZE] PROGMEM = { //idx 0=0deg, 1=7.5deg, 2=15deg, 3=22.5deg, etc.
|
||||||
|
0x80, 0x90, 0xa0, 0xb0, 0xbf, 0xcd, 0xda, 0xe5, 0xee, 0xf5, 0xfb, 0xfe, // 0.. 82.5deg
|
||||||
|
0xff, 0xfe, 0xfb, 0xf5, 0xee, 0xe5, 0xda, 0xcd, 0xbf, 0xb0, 0xa0, 0x90, // 90..172.5deg
|
||||||
|
0x80, 0x6f, 0x5f, 0x4f, 0x40, 0x32, 0x25, 0x1a, 0x11, 0x0a, 0x04, 0x01, // 180..262.5deg
|
||||||
|
0x00, 0x01, 0x04, 0x0a, 0x11, 0x1a, 0x25, 0x32, 0x40, 0x4f, 0x5f, 0x6f // 270..352.5deg
|
||||||
|
};
|
||||||
|
|
||||||
|
HdlcAfskTx::HdlcAfskTx(HdlcFrameBuffer* txBuffer) {
|
||||||
|
_txBuffer = txBuffer;
|
||||||
|
for (int idx=0; idx < AFSK_PIN_COUNT; idx++) {
|
||||||
|
pinMode(_pins[idx], OUTPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte HdlcAfskTx::encodeSample() {
|
||||||
|
if (_ready) { return ANALOG_ZERO; }
|
||||||
|
|
||||||
|
byte loopBackSample = ANALOG_ZERO;
|
||||||
|
if (loopbackTest) {
|
||||||
|
PORTD = (pgm_read_byte(&sinusTable[_n7_5degTest]) & AFSK_MASK) | (PORTD & NON_AFSK_MASK);
|
||||||
|
_n7_5degTest += MARK_SAMPLE_DEG_STEP;
|
||||||
|
if (_n7_5degTest >= SIN_TABLE_SIZE) {
|
||||||
|
_n7_5degTest -= SIN_TABLE_SIZE;
|
||||||
|
}
|
||||||
|
loopBackSample = pgm_read_byte(&sinusTable[_n7_5deg]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PORTD = (pgm_read_byte(&sinusTable[_n7_5deg]) & AFSK_MASK) | (PORTD & NON_AFSK_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mark) {
|
||||||
|
_n7_5deg += MARK_SAMPLE_DEG_STEP;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_n7_5deg += SPACE_SAMPLE_DEG_STEP;
|
||||||
|
}
|
||||||
|
if (_n7_5deg >= SIN_TABLE_SIZE) {
|
||||||
|
_n7_5deg -= SIN_TABLE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_runToZero) {
|
||||||
|
if (_n7_5deg < SPACE_SAMPLE_DEG_STEP) {
|
||||||
|
_n7_5deg = 0;
|
||||||
|
_runToZero = false;
|
||||||
|
_ready = true;
|
||||||
|
PORTD = ANALOG_ZERO;
|
||||||
|
loopBackSample = ANALOG_ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_bitSampleCounter++;
|
||||||
|
if (_bitSampleCounter > MAX_BIT_SAMPLE_INDEX) {
|
||||||
|
_bitSampleCounter = 0;
|
||||||
|
if (getNextMark(&_mark)) {
|
||||||
|
_runToZero = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loopBackSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcAfskTx::start() {
|
||||||
|
if (_ready) {
|
||||||
|
_mark = true;
|
||||||
|
_afskByte = HDLC_FLAG;
|
||||||
|
_afskBitMask = MASK_RESET_VALUE;
|
||||||
|
_afskBitPtr = 0;
|
||||||
|
_preampCountDown = _preambleCount;
|
||||||
|
_enableStuffBit = false;
|
||||||
|
_stuffBit = false;
|
||||||
|
_oneCounter = 0;
|
||||||
|
_ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcAfskTx::getReady() {
|
||||||
|
return _ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcAfskTx::setTxDelay(int val) {
|
||||||
|
_preambleCount = val * 12 / 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcAfskTx::getNextMark(boolean* current) {
|
||||||
|
if (_afskBitPtr == 0) {
|
||||||
|
boolean frameEnd=false;
|
||||||
|
switch (frameTxState) {
|
||||||
|
case TX_FRAME_PREAMBLE:
|
||||||
|
_afskByte = HDLC_FLAG;
|
||||||
|
_enableStuffBit = false;
|
||||||
|
_preampCountDown--;
|
||||||
|
if (_preampCountDown < 1) {
|
||||||
|
frameTxState = TX_FRAME_BEGIN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TX_FRAME_BEGIN:
|
||||||
|
if (_txBuffer->more()) {
|
||||||
|
_afskByte = HDLC_FLAG;
|
||||||
|
_enableStuffBit = false;
|
||||||
|
frameTxState = TX_FRAME_DATA;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frameTxState = TX_FRAME_PREAMBLE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TX_FRAME_DATA:
|
||||||
|
if (_txBuffer->pop(&_afskByte, &frameEnd)) {
|
||||||
|
_enableStuffBit = true;
|
||||||
|
if (frameEnd) {
|
||||||
|
frameTxState = TX_FRAME_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frameTxState = TX_FRAME_END;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TX_FRAME_END:
|
||||||
|
_afskByte = HDLC_FLAG;
|
||||||
|
_enableStuffBit = false;
|
||||||
|
frameTxState = TX_FRAME_BEGIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean nextBit;
|
||||||
|
if (_stuffBit) {
|
||||||
|
nextBit = false;
|
||||||
|
_stuffBit = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nextBit = (_afskByte & _afskBitMask) != 0;
|
||||||
|
if (nextBit) {
|
||||||
|
_oneCounter++;
|
||||||
|
if (_oneCounter > MAX_ONES_WITHOUT_STUFFING) {
|
||||||
|
_oneCounter = 0;
|
||||||
|
_stuffBit = _enableStuffBit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_oneCounter = 0;
|
||||||
|
}
|
||||||
|
_afskBitPtr++;
|
||||||
|
_afskBitMask <<= 1;
|
||||||
|
if (_afskBitPtr > MAX_BIT_INDEX) {
|
||||||
|
_afskBitPtr = 0;
|
||||||
|
_afskBitMask = MASK_RESET_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nextBit) {
|
||||||
|
*current = !*current;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
60
Arduino/hdlcAfskTx.h
Normal file
60
Arduino/hdlcAfskTx.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef HDLC_AFSK_TX_H
|
||||||
|
#define HDLC_AFSK_TX_H
|
||||||
|
|
||||||
|
#include "hdlcFramesBuffer.h"
|
||||||
|
|
||||||
|
#define AFSK_PIN_COUNT 4
|
||||||
|
#define AFSK_PIN_4 4
|
||||||
|
#define AFSK_PIN_5 5
|
||||||
|
#define AFSK_PIN_6 6
|
||||||
|
#define AFSK_PIN_7 7
|
||||||
|
#define AFSK_MASK 0xf0
|
||||||
|
#define NON_AFSK_MASK 0x0f
|
||||||
|
|
||||||
|
#define SIN_TABLE_SIZE 48
|
||||||
|
#define MARK_SAMPLE_DEG_STEP 6
|
||||||
|
#define SPACE_SAMPLE_DEG_STEP 11
|
||||||
|
#define MAX_BIT_SAMPLE_INDEX 7
|
||||||
|
|
||||||
|
#define ANALOG_ZERO 0x80
|
||||||
|
#define MASK_RESET_VALUE 0x01
|
||||||
|
#define MAX_BIT_INDEX 7
|
||||||
|
|
||||||
|
#define TX_FRAME_PREAMBLE 0
|
||||||
|
#define TX_FRAME_BEGIN 1
|
||||||
|
#define TX_FRAME_DATA 2
|
||||||
|
#define TX_FRAME_END 3
|
||||||
|
|
||||||
|
#define MAX_ONES_WITHOUT_STUFFING 4
|
||||||
|
#define DEFAULT_PREAMBLE_COUNT 75
|
||||||
|
|
||||||
|
class HdlcAfskTx {
|
||||||
|
public:
|
||||||
|
HdlcAfskTx(HdlcFrameBuffer* txBuffer);
|
||||||
|
boolean loopbackTest=false;
|
||||||
|
byte encodeSample();
|
||||||
|
void start();
|
||||||
|
boolean getReady();
|
||||||
|
void setTxDelay(int val);
|
||||||
|
private:
|
||||||
|
HdlcFrameBuffer* _txBuffer;
|
||||||
|
int _pins[AFSK_PIN_COUNT] = {AFSK_PIN_7, AFSK_PIN_6, AFSK_PIN_5, AFSK_PIN_4};
|
||||||
|
int _n7_5deg = 0;
|
||||||
|
int _n7_5degTest = 0;
|
||||||
|
int _bitSampleCounter = 0;
|
||||||
|
boolean _mark = true;
|
||||||
|
boolean _runToZero = false;
|
||||||
|
boolean _ready = true;
|
||||||
|
byte _afskByte = HDLC_FLAG;
|
||||||
|
byte _afskBitMask = MASK_RESET_VALUE;
|
||||||
|
int frameTxState = TX_FRAME_PREAMBLE;
|
||||||
|
int _afskBitPtr = 0;
|
||||||
|
int _preambleCount = DEFAULT_PREAMBLE_COUNT;
|
||||||
|
int _preampCountDown = DEFAULT_PREAMBLE_COUNT;
|
||||||
|
boolean _enableStuffBit = false;
|
||||||
|
boolean _stuffBit = false;
|
||||||
|
int _oneCounter = 0;
|
||||||
|
boolean getNextMark(boolean* current);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
46
Arduino/hdlcCrc.cpp
Normal file
46
Arduino/hdlcCrc.cpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#include "hdlcCrc.h"
|
||||||
|
|
||||||
|
HdlcCrc::HdlcCrc(HdlcCrcTable* crcTable) {
|
||||||
|
_crcTable = crcTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcCrc::resetFcs() {
|
||||||
|
_fcs = CRC_RESET_VAL;
|
||||||
|
_calcFcs[0] = _calcFcs[1];
|
||||||
|
_calcFcs[1] = _fcs;
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcCrc::calcFcs(byte newByte) {
|
||||||
|
_fcs = (_fcs >> 8) ^ _crcTable->getValue((_fcs ^ newByte) & 0xff);
|
||||||
|
_rxFcs[0] = _rxFcs[1];
|
||||||
|
_rxFcs[1] = newByte;
|
||||||
|
_calcFcs[0] = _calcFcs[1];
|
||||||
|
_calcFcs[1] = _calcFcs[2];
|
||||||
|
_calcFcs[2] = _fcs;
|
||||||
|
_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte HdlcCrc::getFcsL() {
|
||||||
|
return (_fcs & 0xff) ^ 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte HdlcCrc::getFcsH() {
|
||||||
|
return (_fcs >> 8) ^ 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcCrc::checkFcs() {
|
||||||
|
boolean result = false;
|
||||||
|
byte calcFcsL = (_calcFcs[0] & 0xff) ^ 0xff;
|
||||||
|
byte calcFcsH = (_calcFcs[0] >> 8) ^ 0xff;
|
||||||
|
|
||||||
|
if (_count > 2) {
|
||||||
|
if (_rxFcs[0] == calcFcsL) {
|
||||||
|
if (_rxFcs[1] == calcFcsH) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
24
Arduino/hdlcCrc.h
Normal file
24
Arduino/hdlcCrc.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef HDLC_CRC_H
|
||||||
|
#define HDLC_CRC_H
|
||||||
|
|
||||||
|
#include "hdlcCrcTable.h"
|
||||||
|
|
||||||
|
#define CRC_RESET_VAL 0xFFFF
|
||||||
|
|
||||||
|
class HdlcCrc {
|
||||||
|
public:
|
||||||
|
HdlcCrc(HdlcCrcTable* crcTable);
|
||||||
|
void resetFcs();
|
||||||
|
void calcFcs(byte newByte);
|
||||||
|
byte getFcsL();
|
||||||
|
byte getFcsH();
|
||||||
|
boolean checkFcs();
|
||||||
|
private:
|
||||||
|
HdlcCrcTable* _crcTable;
|
||||||
|
uint16_t _fcs = CRC_RESET_VAL;
|
||||||
|
uint16_t _calcFcs[3];
|
||||||
|
byte _rxFcs[2];
|
||||||
|
int _count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
44
Arduino/hdlcCrcTable.cpp
Normal file
44
Arduino/hdlcCrcTable.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "hdlcCrcTable.h"
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
const uint16_t crcTable[256] PROGMEM = {
|
||||||
|
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
|
||||||
|
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
|
||||||
|
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
|
||||||
|
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
|
||||||
|
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
|
||||||
|
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
|
||||||
|
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
|
||||||
|
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
|
||||||
|
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
|
||||||
|
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
|
||||||
|
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
|
||||||
|
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
|
||||||
|
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
|
||||||
|
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
|
||||||
|
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
|
||||||
|
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
|
||||||
|
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
|
||||||
|
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
|
||||||
|
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
|
||||||
|
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
|
||||||
|
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
|
||||||
|
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
|
||||||
|
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
|
||||||
|
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
|
||||||
|
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
|
||||||
|
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
|
||||||
|
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
|
||||||
|
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
|
||||||
|
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
|
||||||
|
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
|
||||||
|
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
|
||||||
|
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
|
||||||
|
};
|
||||||
|
|
||||||
|
HdlcCrcTable::HdlcCrcTable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t HdlcCrcTable::getValue(byte crcTableIndex) {
|
||||||
|
return pgm_read_word(&crcTable[crcTableIndex]);
|
||||||
|
}
|
15
Arduino/hdlcCrcTable.h
Normal file
15
Arduino/hdlcCrcTable.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef HDLC_CRC_TABLE_H
|
||||||
|
#define HDLC_CRC_TABLE_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#define CRC_RESET_VAL 0xFFFF
|
||||||
|
|
||||||
|
class HdlcCrcTable {
|
||||||
|
public:
|
||||||
|
HdlcCrcTable();
|
||||||
|
uint16_t getValue(byte crcTableIndex);
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
134
Arduino/hdlcFramesBuffer.cpp
Normal file
134
Arduino/hdlcFramesBuffer.cpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include "hdlcFramesBuffer.h"
|
||||||
|
|
||||||
|
HdlcFrameBuffer::HdlcFrameBuffer(boolean tx, HdlcCrcTable* crcTable, int bufferSize) {
|
||||||
|
_tx = tx;
|
||||||
|
_crc = new HdlcCrc(crcTable);
|
||||||
|
_bufferData = new byte[bufferSize+6];
|
||||||
|
_bufferData[0] = 0;
|
||||||
|
_bufferData[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcFrameBuffer::push(byte in) {
|
||||||
|
if (spaceAvailable()) {
|
||||||
|
_bufferData[_pushPosition] = in;
|
||||||
|
incrementPushPosition();
|
||||||
|
_pushFrameDataCounter++;
|
||||||
|
_crc->calcFcs(in);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcFrameBuffer::pop(byte* out, boolean* frameEnd) {
|
||||||
|
*frameEnd = false;
|
||||||
|
if (more()) {
|
||||||
|
*out = _bufferData[_popPosition];
|
||||||
|
incrementPopPosition(1);
|
||||||
|
_popFrameSize--;
|
||||||
|
if (_popFrameSize < 1) {
|
||||||
|
*frameEnd = true;
|
||||||
|
if (!_tx) {
|
||||||
|
incrementPopPosition(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcFrameBuffer::more() {
|
||||||
|
if (_popFrameSize < 1) {
|
||||||
|
_popFrameSize = (_bufferData[_popFrameSizeHPos] << 8) + _bufferData[_popFrameSizeLPos];
|
||||||
|
if (_popFrameSize > 0) {
|
||||||
|
_bufferData[_popFrameSizeHPos] = 0;
|
||||||
|
_bufferData[_popFrameSizeLPos] = 0;
|
||||||
|
_popFrameSizeHPos += _popFrameSize + 2;
|
||||||
|
_popFrameSizeLPos += _popFrameSize + 2;
|
||||||
|
if (_popFrameSizeHPos >= BUFFER_SIZE) {
|
||||||
|
_popFrameSizeHPos -= BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
if (_popFrameSizeLPos >= BUFFER_SIZE) {
|
||||||
|
_popFrameSizeLPos -= BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
incrementPopPosition(2);
|
||||||
|
if (!_tx) {
|
||||||
|
_popFrameSize -=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (_popFrameSize > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcFrameBuffer::frameReset(){
|
||||||
|
_pushPosition = _pushFrameSizeLPos;
|
||||||
|
incrementPushPosition();
|
||||||
|
_pushFrameDataCounter = 0;
|
||||||
|
_crc->resetFcs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcFrameBuffer::frameEnd() {
|
||||||
|
if (spaceAvailable()) {
|
||||||
|
if (_tx) {
|
||||||
|
byte fcsL = _crc->getFcsL();
|
||||||
|
byte fcsH = _crc->getFcsH();
|
||||||
|
push(fcsL);
|
||||||
|
push(fcsH);
|
||||||
|
|
||||||
|
startNewFrame();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(_crc->checkFcs()) {
|
||||||
|
startNewFrame();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frameReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frameReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcFrameBuffer::startNewFrame() {
|
||||||
|
_bufferData[_pushFrameSizeHPos] = (_pushFrameDataCounter >> 8) & 0xff;
|
||||||
|
_bufferData[_pushFrameSizeLPos] = (_pushFrameDataCounter & 0xff);
|
||||||
|
_pushFrameDataCounter = 0;
|
||||||
|
|
||||||
|
_pushFrameSizeHPos = _pushPosition;
|
||||||
|
incrementPushPosition();
|
||||||
|
|
||||||
|
_pushFrameSizeLPos = _pushPosition;
|
||||||
|
incrementPushPosition();
|
||||||
|
|
||||||
|
_bufferData[_pushFrameSizeHPos] = 0;
|
||||||
|
_bufferData[_pushFrameSizeLPos] = 0;
|
||||||
|
_crc->resetFcs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcFrameBuffer::incrementPushPosition() {
|
||||||
|
_pushPosition++;
|
||||||
|
if (_pushPosition >= BUFFER_SIZE) {
|
||||||
|
_pushPosition=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcFrameBuffer::incrementPopPosition(int count) {
|
||||||
|
_popPosition += count;
|
||||||
|
if (_popPosition >= BUFFER_SIZE) {
|
||||||
|
_popPosition -= BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcFrameBuffer::spaceAvailable() {
|
||||||
|
int space = _popPosition - _pushPosition;
|
||||||
|
if (space <= 0) {
|
||||||
|
space += BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
return space>4;
|
||||||
|
}
|
||||||
|
|
36
Arduino/hdlcFramesBuffer.h
Normal file
36
Arduino/hdlcFramesBuffer.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef HDLC_FRAMES_BUFFER_H
|
||||||
|
#define HDLC_FRAMES_BUFFER_H
|
||||||
|
|
||||||
|
#include "hdlcCrc.h"
|
||||||
|
|
||||||
|
#define HDLC_FLAG 0x7e
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 500
|
||||||
|
|
||||||
|
class HdlcFrameBuffer {
|
||||||
|
public:
|
||||||
|
HdlcFrameBuffer(boolean tx, HdlcCrcTable* crcTable, int bufferSize);
|
||||||
|
boolean push(byte in);
|
||||||
|
boolean pop(byte* out, boolean* frameEnd);
|
||||||
|
boolean more();
|
||||||
|
void frameReset();
|
||||||
|
void frameEnd();
|
||||||
|
private:
|
||||||
|
HdlcCrc* _crc;
|
||||||
|
byte* _bufferData;
|
||||||
|
boolean _tx;
|
||||||
|
int _pushFrameSizeHPos = 0;
|
||||||
|
int _pushFrameSizeLPos = 1;
|
||||||
|
int _pushPosition = 2;
|
||||||
|
int _pushFrameDataCounter = 0;
|
||||||
|
int _popFrameSizeHPos = 0;
|
||||||
|
int _popFrameSizeLPos = 1;
|
||||||
|
int _popPosition = 0;
|
||||||
|
int _popFrameSize = 0;
|
||||||
|
void startNewFrame();
|
||||||
|
void incrementPushPosition();
|
||||||
|
void incrementPopPosition(int count);
|
||||||
|
boolean spaceAvailable();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
143
Arduino/hdlcTnc.cpp
Normal file
143
Arduino/hdlcTnc.cpp
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#include "hdlcTnc.h"
|
||||||
|
|
||||||
|
HdlcTnc::HdlcTnc(
|
||||||
|
int rxIndicationPin, int txIndicationPin, int rxOnlyPin, int pttPin,
|
||||||
|
int lowLevelSelectPin, int rxBufferSize, int txBufferSize
|
||||||
|
) {
|
||||||
|
_crcTable = new HdlcCrcTable();
|
||||||
|
_rxBuffer = new HdlcFrameBuffer(false, _crcTable, rxBufferSize);
|
||||||
|
_txBuffer = new HdlcFrameBuffer(true , _crcTable, txBufferSize);
|
||||||
|
_afskRx = new HdlcAfskRx(_rxBuffer);
|
||||||
|
_afskTx = new HdlcAfskTx(_txBuffer);
|
||||||
|
_afskSampler = new AfskSampler(lowLevelSelectPin, _afskRx, _afskTx);
|
||||||
|
if (rxIndicationPin > 0 ) {
|
||||||
|
pinMode(rxIndicationPin, OUTPUT);
|
||||||
|
_rxIndicationPin = rxIndicationPin;
|
||||||
|
}
|
||||||
|
if (txIndicationPin > 0 ) {
|
||||||
|
pinMode(txIndicationPin, OUTPUT);
|
||||||
|
_txIndicationPin = txIndicationPin;
|
||||||
|
}
|
||||||
|
if (rxOnlyPin > 0 ) {
|
||||||
|
pinMode(rxOnlyPin, INPUT_PULLUP);
|
||||||
|
_rxOnlyPin = rxOnlyPin;
|
||||||
|
}
|
||||||
|
if (pttPin > 0 ) {
|
||||||
|
pinMode(pttPin, OUTPUT);
|
||||||
|
_pttPin = pttPin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::hdlcTask() {
|
||||||
|
if (_afskRx->receiving) {
|
||||||
|
digitalWrite(_rxIndicationPin, HIGH);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digitalWrite(_rxIndicationPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(_hdlcState) {
|
||||||
|
case HS_IDLE:
|
||||||
|
if (_txBuffer->more()) {
|
||||||
|
if (_fullDuplex) {
|
||||||
|
setPtt(true);
|
||||||
|
_afskTx->start();
|
||||||
|
_hdlcState = HS_TX_FRAME;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_afskRx->receiving) {
|
||||||
|
_hdlcState = HS_WAIT_FOR_FREE_CHANNEL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setPtt(true);
|
||||||
|
_afskTx->start();
|
||||||
|
_hdlcState = HS_TX_FRAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HS_WAIT_FOR_FREE_CHANNEL:
|
||||||
|
if (!_afskRx->receiving) {
|
||||||
|
if (random(RANDOM_VAL_LIMIT) > _persistence) {
|
||||||
|
_randomWaitTimeOutTime = millis() + _slotTime;
|
||||||
|
_hdlcState = HS_RANDOM_WAIT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setPtt(true);
|
||||||
|
_afskTx->start();
|
||||||
|
_hdlcState = HS_TX_FRAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HS_RANDOM_WAIT:
|
||||||
|
if (_afskRx->receiving) {
|
||||||
|
_hdlcState = HS_WAIT_FOR_FREE_CHANNEL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (millis() > _randomWaitTimeOutTime) {
|
||||||
|
setPtt(true);
|
||||||
|
_afskTx->start();
|
||||||
|
_hdlcState = HS_TX_FRAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HS_TX_FRAME:
|
||||||
|
if (_afskTx->getReady()) {
|
||||||
|
setPtt(false);
|
||||||
|
_hdlcState = HS_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::addByteToTxBuf(byte newByte) {
|
||||||
|
if (digitalRead(_rxOnlyPin) == HIGH) {
|
||||||
|
_txBuffer->push(newByte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::addFrameEndToTxBuf() {
|
||||||
|
if (digitalRead(_rxOnlyPin) == HIGH) {
|
||||||
|
_txBuffer->frameEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::resetTxFrame() {
|
||||||
|
_txBuffer->frameReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean HdlcTnc::getRxByte(byte* rxByte, boolean* frameEnd) {
|
||||||
|
return _rxBuffer->pop(rxByte, frameEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::setTxDelay(int val) {
|
||||||
|
_afskTx->setTxDelay(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::setPersistence(byte val) {
|
||||||
|
_persistence = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::setSlotTime(int val) {
|
||||||
|
_slotTime = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::setFullDuplex(boolean val) {
|
||||||
|
_fullDuplex = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::setLoopbackTest(boolean on) {
|
||||||
|
_afskTx->loopbackTest = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HdlcTnc::setPtt(boolean on) {
|
||||||
|
if (on) {
|
||||||
|
digitalWrite(_pttPin, HIGH);
|
||||||
|
digitalWrite(_txIndicationPin, HIGH);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digitalWrite(_pttPin, LOW);
|
||||||
|
digitalWrite(_txIndicationPin, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
53
Arduino/hdlcTnc.h
Normal file
53
Arduino/hdlcTnc.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef HDLC_TNC_H
|
||||||
|
#define HDLC_TNC_H
|
||||||
|
|
||||||
|
#include "hdlcAfskRx.h"
|
||||||
|
#include "hdlcAfskTx.h"
|
||||||
|
#include "afskSampler.h"
|
||||||
|
|
||||||
|
#define DEFAULT_PERSISTENCE 63
|
||||||
|
#define DEFAULT_SLOT_TIME 100
|
||||||
|
|
||||||
|
#define RANDOM_VAL_LIMIT 256
|
||||||
|
|
||||||
|
#define HS_IDLE 0
|
||||||
|
#define HS_WAIT_FOR_FREE_CHANNEL 1
|
||||||
|
#define HS_RANDOM_WAIT 2
|
||||||
|
#define HS_TX_FRAME 3
|
||||||
|
|
||||||
|
class HdlcTnc {
|
||||||
|
public:
|
||||||
|
HdlcTnc(
|
||||||
|
int rxIndicationPin, int txIndicationPin, int rxOnlyPin, int pttPin,
|
||||||
|
int lowLevelSelectPin, int rxBufferSize, int txBufferSize
|
||||||
|
);
|
||||||
|
void hdlcTask();
|
||||||
|
void addByteToTxBuf(byte newByte);
|
||||||
|
void addFrameEndToTxBuf();
|
||||||
|
void resetTxFrame();
|
||||||
|
boolean getRxByte(byte* rxByte, boolean* frameEnd);
|
||||||
|
void setTxDelay(int val);
|
||||||
|
void setPersistence(byte val);
|
||||||
|
void setSlotTime(int val);
|
||||||
|
void setFullDuplex(boolean val);
|
||||||
|
void setLoopbackTest(boolean On);
|
||||||
|
private:
|
||||||
|
HdlcCrcTable* _crcTable;
|
||||||
|
HdlcFrameBuffer* _rxBuffer;
|
||||||
|
HdlcFrameBuffer* _txBuffer;
|
||||||
|
HdlcAfskRx* _afskRx;
|
||||||
|
HdlcAfskTx* _afskTx;
|
||||||
|
AfskSampler* _afskSampler;
|
||||||
|
int _rxIndicationPin = 0;
|
||||||
|
int _txIndicationPin = 0;
|
||||||
|
int _pttPin = 0;
|
||||||
|
int _rxOnlyPin = 0;
|
||||||
|
byte _persistence = DEFAULT_PERSISTENCE;
|
||||||
|
int _slotTime = DEFAULT_SLOT_TIME;
|
||||||
|
boolean _fullDuplex = false;
|
||||||
|
int _hdlcState = HS_IDLE;
|
||||||
|
unsigned long _randomWaitTimeOutTime = 0;
|
||||||
|
void setPtt(boolean on);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
146
Arduino/kiss.cpp
Normal file
146
Arduino/kiss.cpp
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
#include "kiss.h"
|
||||||
|
|
||||||
|
Kiss::Kiss(
|
||||||
|
int baud,
|
||||||
|
int rxIndicationPin, int txIndicationPin, int rxOnlyPin, int pttPin,
|
||||||
|
int lowLevelSelectPin, int rxBufferSize, int txBufferSize
|
||||||
|
) {
|
||||||
|
_baud = baud;
|
||||||
|
_hdlcTnc = new HdlcTnc(
|
||||||
|
rxIndicationPin, txIndicationPin, rxOnlyPin, pttPin, lowLevelSelectPin,
|
||||||
|
rxBufferSize, txBufferSize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kiss::begin() {
|
||||||
|
Serial.begin(_baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kiss::kissTask() {
|
||||||
|
_hdlcTnc->hdlcTask();
|
||||||
|
if (Serial.available() > 0) {
|
||||||
|
processKissInByte(Serial.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean frameEnd;
|
||||||
|
byte rxByte;
|
||||||
|
if (_hdlcTnc->getRxByte(&rxByte, &frameEnd)) {
|
||||||
|
processKissOutByte(rxByte, frameEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kiss::processKissOutByte(byte newByte, boolean frameEnd) {
|
||||||
|
if (_kissOutFrameEnd) {
|
||||||
|
Serial.write(FEND);
|
||||||
|
Serial.write(CMD_DATA_FRAME);
|
||||||
|
_kissOutFrameEnd = false;
|
||||||
|
}
|
||||||
|
if (newByte == FEND) {
|
||||||
|
Serial.write(FESC);
|
||||||
|
Serial.write(TFEND);
|
||||||
|
}
|
||||||
|
else if (newByte == FESC) {
|
||||||
|
Serial.write(FESC);
|
||||||
|
Serial.write(TFESC);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.write(newByte);
|
||||||
|
}
|
||||||
|
if (frameEnd) {
|
||||||
|
Serial.write(FEND);
|
||||||
|
_kissOutFrameEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kiss::processKissInByte(byte newByte) {
|
||||||
|
switch (_kissInState) {
|
||||||
|
case KS_UNDEF:
|
||||||
|
if (newByte == FEND) {
|
||||||
|
_kissCommand = CMD_UNDEF;
|
||||||
|
_kissInState = KS_GET_CMD;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KS_GET_CMD:
|
||||||
|
if (newByte != FEND) {
|
||||||
|
if ((newByte < MAX_KISS_CMD) || (newByte > MIN_KISS_CMD)) {
|
||||||
|
_kissCommand = newByte;
|
||||||
|
_kissInState = KS_GET_DATA;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_kissCommand = CMD_UNDEF;
|
||||||
|
_kissInState = KS_UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KS_GET_DATA:
|
||||||
|
if (newByte == FESC) {
|
||||||
|
_kissInState = KS_ESCAPE;
|
||||||
|
}
|
||||||
|
else if (newByte == FEND) {
|
||||||
|
sendCommandToTnc();
|
||||||
|
_kissCommand = CMD_UNDEF;
|
||||||
|
_kissInState = KS_GET_CMD;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
storeDataByte(newByte);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KS_ESCAPE:
|
||||||
|
if (newByte == TFEND) {
|
||||||
|
storeDataByte(FEND);
|
||||||
|
_kissInState = KS_GET_DATA;
|
||||||
|
}
|
||||||
|
else if (newByte == TFESC) {
|
||||||
|
storeDataByte(FESC);
|
||||||
|
_kissInState = KS_GET_DATA;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_hdlcTnc->resetTxFrame();
|
||||||
|
_kissCommand = CMD_UNDEF;
|
||||||
|
_kissInState = KS_UNDEF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kiss::storeDataByte(byte newByte) {
|
||||||
|
if (_kissCommand == CMD_DATA_FRAME) {
|
||||||
|
_hdlcTnc->addByteToTxBuf(newByte);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_tncParam = newByte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kiss::sendCommandToTnc() {
|
||||||
|
switch (_kissCommand) {
|
||||||
|
case CMD_DATA_FRAME:
|
||||||
|
_hdlcTnc->addFrameEndToTxBuf();
|
||||||
|
break;
|
||||||
|
case CMD_TX_DELAY:
|
||||||
|
_hdlcTnc->setTxDelay(_tncParam * TIME_10_MS_UNITS);
|
||||||
|
break;
|
||||||
|
case CMD_P:
|
||||||
|
_hdlcTnc->setPersistence(_tncParam);
|
||||||
|
break;
|
||||||
|
case CMD_SLOT_TIME:
|
||||||
|
_hdlcTnc->setSlotTime(_tncParam * TIME_10_MS_UNITS);
|
||||||
|
break;
|
||||||
|
case CMD_TX_TAIL:
|
||||||
|
//obsolete
|
||||||
|
break;
|
||||||
|
case CMD_FULL_DUPLEX:
|
||||||
|
_hdlcTnc->setFullDuplex(_tncParam != 0);
|
||||||
|
break;
|
||||||
|
case CMD_SET_HARDWARE:
|
||||||
|
//not implemented
|
||||||
|
break;
|
||||||
|
case CMD_LOOPBACK_TEST:
|
||||||
|
_hdlcTnc->setLoopbackTest(_tncParam > 0);
|
||||||
|
break;
|
||||||
|
case CMD_RETURN:
|
||||||
|
//not implemented
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
58
Arduino/kiss.h
Normal file
58
Arduino/kiss.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef KISS_H
|
||||||
|
#define KISS_H
|
||||||
|
|
||||||
|
#include "hdlcTnc.h"
|
||||||
|
|
||||||
|
#define FEND 0xC0
|
||||||
|
#define FESC 0xDB
|
||||||
|
#define TFEND 0xDC
|
||||||
|
#define TFESC 0xDD
|
||||||
|
|
||||||
|
#define KS_UNDEF 0
|
||||||
|
#define KS_GET_CMD 1
|
||||||
|
#define KS_GET_DATA 2
|
||||||
|
#define KS_ESCAPE 3
|
||||||
|
|
||||||
|
#define TIME_10_MS_UNITS 10
|
||||||
|
|
||||||
|
#define CMD_DATA_FRAME 0x00
|
||||||
|
#define CMD_TX_DELAY 0x01
|
||||||
|
#define CMD_P 0x02
|
||||||
|
#define CMD_SLOT_TIME 0x03
|
||||||
|
#define CMD_TX_TAIL 0x04
|
||||||
|
#define CMD_FULL_DUPLEX 0x05
|
||||||
|
#define CMD_SET_HARDWARE 0x06
|
||||||
|
#define MAX_KISS_CMD 0x07
|
||||||
|
#define CMD_UNDEF 0x80
|
||||||
|
#define MIN_KISS_CMD 0xFD
|
||||||
|
#define CMD_LOOPBACK_TEST 0xFE
|
||||||
|
#define CMD_RETURN 0xFF
|
||||||
|
|
||||||
|
#define LCD_ROW_COUNT 4
|
||||||
|
#define LCD_COL_COUNT 20
|
||||||
|
#define EMPTY_ROW " "
|
||||||
|
|
||||||
|
class Kiss {
|
||||||
|
public:
|
||||||
|
Kiss(
|
||||||
|
int bdRate,
|
||||||
|
int rxIndicationPin, int txIndicationPin, int rxOnlyPin, int pttPin, int lowLevelSelectPin,
|
||||||
|
int rxBufferSize, int txBufferSize
|
||||||
|
);
|
||||||
|
void begin();
|
||||||
|
void kissTask();
|
||||||
|
private:
|
||||||
|
HdlcTnc* _hdlcTnc;
|
||||||
|
int _baud;
|
||||||
|
int _kissInState = KS_UNDEF;
|
||||||
|
byte _kissCommand = CMD_UNDEF;
|
||||||
|
byte _tncParam;
|
||||||
|
boolean _kissOutFrameEnd = true;
|
||||||
|
boolean _readAddress = true;
|
||||||
|
void processKissOutByte(byte newByte, boolean frameEnd);
|
||||||
|
void processKissInByte(byte newByte);
|
||||||
|
void storeDataByte(byte newByte);
|
||||||
|
void sendCommandToTnc();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
24
Arduino/kissTnc.ino
Normal file
24
Arduino/kissTnc.ino
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "kiss.h"
|
||||||
|
|
||||||
|
#define KISS_BD 9600
|
||||||
|
#define RX_LED 3 // 13 for PI4RAZ APRS_iGate
|
||||||
|
#define TX_LED 9
|
||||||
|
#define RX_ONLY 8 // 10 for PI4RAZ APRS_iGate (not used)
|
||||||
|
#define PTT_PIN 10
|
||||||
|
#define LOW_LEVEL_SELECT 2
|
||||||
|
#define RX_BUFFER_SIZE 500
|
||||||
|
#define TX_BUFFER_SIZE 500
|
||||||
|
|
||||||
|
Kiss kiss(
|
||||||
|
KISS_BD,
|
||||||
|
RX_LED, TX_LED, RX_ONLY, PTT_PIN, LOW_LEVEL_SELECT,
|
||||||
|
RX_BUFFER_SIZE, TX_BUFFER_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
kiss.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
kiss.kissTask();
|
||||||
|
}
|
BIN
Arduino/nano_ch340_schematics.pdf
Normal file
BIN
Arduino/nano_ch340_schematics.pdf
Normal file
Binary file not shown.
BIN
CM108/DiiRIy9XkAAfJpp.jpeg
Executable file
BIN
CM108/DiiRIy9XkAAfJpp.jpeg
Executable file
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
1
KissTncAx25_old
Submodule
1
KissTncAx25_old
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit ed112614799dbcf77f20b5c7e5942066dfa93f48
|
27
README.md
Executable file
27
README.md
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
Install et Config des TNC packet radio
|
||||||
|
============================
|
||||||
|
<img src="http://xavier.debert.free.fr/kisstnc.jpg" width="50%">
|
||||||
|
<br>
|
||||||
|
##TNC ARDUINO ##
|
||||||
|
<br>nano ou micro 328p
|
||||||
|
<br>
|
||||||
|
Répertoire Arduino pour la compilation avec arduinoIDE ouvrir le .ino<br>
|
||||||
|
(attention j'ai modifier les pin pour mon projet RX_LED 3, TX_LED 9, RX_ONLY 8 et PTT_PIN 10 )
|
||||||
|
<br>
|
||||||
|
## Carte Son CM108 ##
|
||||||
|
<br>carte audio CM108
|
||||||
|
<br>
|
||||||
|
Répertoire CM108
|
||||||
|
<br>
|
||||||
|
Le fichier install est commun au 2 projets
|
||||||
|
<br>
|
||||||
|
## LES SCRIPTS ##
|
||||||
|
Le répertoire script contient les configuration à modiufier et les fichier exécution:
|
||||||
|
<br>
|
||||||
|
ax_cm108.sh pour la carte audio CM108
|
||||||
|
<br>
|
||||||
|
ax_arduino.sh pour le kisstnc
|
||||||
|
<br>
|
||||||
|
73'51 <br>
|
||||||
|
Xavier
|
||||||
|
|
24
install.sh
Executable file
24
install.sh
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#CM108
|
||||||
|
apt install libasound2-dev libudev-dev
|
||||||
|
# gpsd
|
||||||
|
#apt-get install gpsdlibgps-dev
|
||||||
|
#
|
||||||
|
# hamlib
|
||||||
|
#apt-get install automake libtool texinfo
|
||||||
|
#git clone git://hamlib.git.sourceforge.net/gitroot/hamlib/hamlib
|
||||||
|
#cd hamlib
|
||||||
|
#sh autogen.sh
|
||||||
|
#make
|
||||||
|
#make check
|
||||||
|
#make install
|
||||||
|
#
|
||||||
|
git clone https://www.github.com/wb2osz/direwolf
|
||||||
|
cd direwolf
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
make install-conf
|
||||||
|
|
||||||
|
#Pour Les Tools AX25
|
||||||
|
apt install ax25*
|
||||||
|
|
BIN
kisstnc.jpg
Normal file
BIN
kisstnc.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
12
script/ax_arduino.sh
Executable file
12
script/ax_arduino.sh
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/etc/ax25:/usr/local/ax25
|
||||||
|
echo "Installing one KISS connection on PTY port /tmp/kisstnc"
|
||||||
|
/usr/sbin/mkiss -s 9600 -x 1 /dev/ttyUSB0 > /tmp/unix98
|
||||||
|
#This creates a PTS interface like "/dev/pts/3"
|
||||||
|
export PTS0=`more /tmp/unix98 | grep -w /dev | cut -b -11`
|
||||||
|
echo "PTS0 device: $PTS0"
|
||||||
|
/usr/sbin/kissattach $PTS0 ax0 > /tmp/ax25-config.tmp
|
||||||
|
/usr/sbin/kissparms -p ax0 -t 750 -s 750 -r 25
|
||||||
|
awk '/device/ { print $7 }' /tmp/ax25-config.tmp > /tmp/ax25-config1-tmp
|
||||||
|
read Device < /tmp/ax25-config1-tmp
|
||||||
|
|
19
script/ax_cm108.sh
Executable file
19
script/ax_cm108.sh
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/etc/ax25:/usr/local/ax25
|
||||||
|
echo "Starting direwolf"
|
||||||
|
direwolf -t 0 -c /home/xavier/dwcm108.conf -p &
|
||||||
|
#Check if Direwolf is running
|
||||||
|
sleep 5
|
||||||
|
if [ -z "`ps ax | grep -v grep | grep direwolf`" ]; then
|
||||||
|
echo -e "\nERROR: Direwolf did not start properly and is not running, please review direwolf.conf"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Installing one KISS connection on PTY port /tmp/kisstnc"
|
||||||
|
/usr/sbin/mkiss -s 1200 -x 1 /tmp/kisstnc > /tmp/unix98
|
||||||
|
#This creates a PTS interface like "/dev/pts/3"
|
||||||
|
export PTS0=`more /tmp/unix98 | grep -w /dev | cut -b -11`
|
||||||
|
echo "PTS0 device: $PTS0"
|
||||||
|
/usr/sbin/kissattach $PTS0 ax0 > /tmp/ax25-config.tmp
|
||||||
|
awk '/device/ { print $7 }' /tmp/ax25-config.tmp > /tmp/ax25-config1-tmp
|
||||||
|
read Device < /tmp/ax25-config1-tmp
|
403
script/dwcm108.conf
Normal file
403
script/dwcm108.conf
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# Configuration file for Dire Wolf #
|
||||||
|
# #
|
||||||
|
# Linux version #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#
|
||||||
|
# Consult the User Guide for more details on configuration options.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# These are the most likely settings you might change:
|
||||||
|
#
|
||||||
|
# (1) MYCALL - call sign and SSID for your station.
|
||||||
|
#
|
||||||
|
# Look for lines starting with MYCALL and
|
||||||
|
# change NOCALL to your own.
|
||||||
|
#
|
||||||
|
# (2) PBEACON - enable position beaconing.
|
||||||
|
#
|
||||||
|
# Look for lines starting with PBEACON and
|
||||||
|
# modify for your call, location, etc.
|
||||||
|
#
|
||||||
|
# (3) DIGIPEATER - configure digipeating rules.
|
||||||
|
#
|
||||||
|
# Look for lines starting with DIGIPEATER.
|
||||||
|
# Most people will probably use the given example.
|
||||||
|
# Just remove the "#" from the start of the line
|
||||||
|
# to enable it.
|
||||||
|
#
|
||||||
|
# (4) IGSERVER, IGLOGIN - IGate server and login
|
||||||
|
#
|
||||||
|
# Configure an IGate client to relay messages between
|
||||||
|
# radio and internet servers.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The default location is "direwolf.conf" in the current working directory.
|
||||||
|
# On Linux, the user's home directory will also be searched.
|
||||||
|
# An alternate configuration file location can be specified with the "-c" command line option.
|
||||||
|
#
|
||||||
|
# As you probably guessed by now, # indicates a comment line.
|
||||||
|
#
|
||||||
|
# Remove the # at the beginning of a line if you want to use a sample
|
||||||
|
# configuration that is currently commented out.
|
||||||
|
#
|
||||||
|
# Commands are a keyword followed by parameters.
|
||||||
|
#
|
||||||
|
# Command key words are case insensitive. i.e. upper and lower case are equivalent.
|
||||||
|
#
|
||||||
|
# Command parameters are generally case sensitive. i.e. upper and lower case are different.
|
||||||
|
#
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# FIRST AUDIO DEVICE PROPERTIES #
|
||||||
|
# (Channel 0 + 1 if in stereo) #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#
|
||||||
|
# Many people will simply use the default sound device.
|
||||||
|
# Some might want to use an alternative device by chosing it here.
|
||||||
|
#
|
||||||
|
# Linux ALSA is complicated. See User Guide for discussion.
|
||||||
|
# To use something other than the default, generally use plughw
|
||||||
|
# and a card number reported by "arecord -l" command. Example:
|
||||||
|
|
||||||
|
ADEVICE plughw:1,0
|
||||||
|
|
||||||
|
# Starting with version 1.0, you can also use "-" or "stdin" to
|
||||||
|
# pipe stdout from some other application such as a software defined
|
||||||
|
# radio. You can also specify "UDP:" and an optional port for input.
|
||||||
|
# Something different must be specified for output.
|
||||||
|
# ADEVICE - plughw:1,0
|
||||||
|
# ADEVICE UDP:7355 default
|
||||||
|
#
|
||||||
|
# Number of audio channels for this souncard: 1 or 2.
|
||||||
|
#
|
||||||
|
|
||||||
|
ACHANNELS 1
|
||||||
|
#ACHANNELS 2
|
||||||
|
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# SECOND AUDIO DEVICE PROPERTIES #
|
||||||
|
# (Channel 2 + 3 if in stereo) #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#ADEVICE1 ...
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# THIRD AUDIO DEVICE PROPERTIES #
|
||||||
|
# (Channel 4 + 5 if in stereo) #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#ADEVICE2 ...
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# CHANNEL 0 PROPERTIES #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
|
||||||
|
CHANNEL 0
|
||||||
|
|
||||||
|
#
|
||||||
|
# The following MYCALL, MODEM, PTT, etc. configuration items
|
||||||
|
# apply to the most recent CHANNEL.
|
||||||
|
#
|
||||||
|
# Station identifier for this channel.
|
||||||
|
# Multiple channels can have the same or different names.
|
||||||
|
#
|
||||||
|
# It can be up to 6 letters and digits with an optional ssid.
|
||||||
|
# The APRS specification requires that it be upper case.
|
||||||
|
#
|
||||||
|
# Example (don't use this unless you are me): MYCALL WB2OSZ-5
|
||||||
|
#
|
||||||
|
|
||||||
|
MYCALL MYCALL-10
|
||||||
|
|
||||||
|
#
|
||||||
|
# Pick a suitable modem speed based on your situation.
|
||||||
|
# 1200 Most common for VHF/UHF. Default if not specified.
|
||||||
|
# 300 Low speed for HF SSB.
|
||||||
|
# 9600 High speed - Can't use Microphone and Speaker connections.
|
||||||
|
#
|
||||||
|
# In the simplest form, just specify the speed.
|
||||||
|
#
|
||||||
|
|
||||||
|
MODEM 1200
|
||||||
|
#MODEM 300
|
||||||
|
#MODEM 9600
|
||||||
|
#SERIALKISS /dev/ttyUSB0 9600
|
||||||
|
#
|
||||||
|
# These are the defaults should be fine for most cases. In special situations,
|
||||||
|
# you might want to specify different AFSK tones or the baseband mode which does
|
||||||
|
# not use AFSK.
|
||||||
|
#
|
||||||
|
#MODEM 1200 1200:2200
|
||||||
|
#MODEM 300 1600:1800
|
||||||
|
#MODEM 9600 0:0
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# On HF SSB, you might want to use multiple demodulators on slightly different
|
||||||
|
# frequencies to compensate for stations off frequency. Here we have 7 different
|
||||||
|
# demodulators at 30 Hz intervals. This takes a lot of CPU power so you will
|
||||||
|
# probably need to reduce the audio sampling rate with the /n option.
|
||||||
|
#MODEM 300 1600:1800 7@30 /4
|
||||||
|
#
|
||||||
|
# Uncomment line below to enable the DTMF decoder for this channel.
|
||||||
|
#
|
||||||
|
#DTMF
|
||||||
|
#
|
||||||
|
# If not using a VOX circuit, the transmitter Push to Talk (PTT)
|
||||||
|
# control is usually wired to a serial port with a suitable interface circuit.
|
||||||
|
# DON'T connect it directly!
|
||||||
|
#
|
||||||
|
# For the PTT command, specify the device and either RTS or DTR.
|
||||||
|
# RTS or DTR may be preceded by "-" to invert the signal.
|
||||||
|
# Both can be used for interfaces that want them driven with opposite polarity.
|
||||||
|
#
|
||||||
|
# COM1 can be used instead of /dev/ttyS0, COM2 for /dev/ttyS1, and so on.
|
||||||
|
#
|
||||||
|
#PTT COM1 RTS
|
||||||
|
#PTT COM1 RTS -DTR
|
||||||
|
|
||||||
|
#PTT /dev/ttyS0 -RTS
|
||||||
|
PTT CM108
|
||||||
|
#
|
||||||
|
# On Linux, you can also use general purpose I/O pins if
|
||||||
|
# your system is configured for user access to them.
|
||||||
|
# This would apply mostly to microprocessor boards, not a regular PC.
|
||||||
|
# See separate Raspberry Pi document for more details.
|
||||||
|
# The number may be preceded by "-" to invert the signal.
|
||||||
|
#
|
||||||
|
#PTT GPIO 25
|
||||||
|
# The Data Carrier Detect (DCD) signal can be sent to the same places
|
||||||
|
# as the PTT signal. This could be used to light up an LED like a normal TNC.
|
||||||
|
#DCD COM1 -DTR
|
||||||
|
#DCD GPIO 24
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# CHANNEL 1 PROPERTIES #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#CHANNEL 1
|
||||||
|
#
|
||||||
|
# Specify MYCALL, MODEM, PTT, etc. configuration items for
|
||||||
|
# CHANNEL 1. Repeat for any other channels.
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# TEXT TO SPEECH COMMAND FILE #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#SPEECH dwespeak.sh
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# VIRTUAL TNC SERVER PROPERTIES #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#
|
||||||
|
# Dire Wolf acts as a virtual TNC and can communicate with
|
||||||
|
# client applications by different protocols:
|
||||||
|
#
|
||||||
|
# - the "AGW TCPIP Socket Interface" - default port 8000
|
||||||
|
# - KISS protocol over TCP socket - default port 8001
|
||||||
|
# - KISS TNC via pseudo terminal (-p command line option)
|
||||||
|
#
|
||||||
|
|
||||||
|
AGWPORT 8000
|
||||||
|
KISSPORT 8001
|
||||||
|
|
||||||
|
#
|
||||||
|
# It is sometimes possible to recover frames with a bad FCS.
|
||||||
|
# This applies to all channels.
|
||||||
|
#
|
||||||
|
# 0 [NONE] - Don't try to repair.
|
||||||
|
# 1 [SINGLE] - Attempt to fix single bit error. (default)
|
||||||
|
# 2 [DOUBLE] - Also attempt to fix two adjacent bits.
|
||||||
|
# ... see User Guide for more values and in-depth discussion.
|
||||||
|
#
|
||||||
|
#FIX_BITS 0
|
||||||
|
#
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# BEACONING PROPERTIES #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#
|
||||||
|
# Beaconing is configured with these two commands:
|
||||||
|
#
|
||||||
|
# PBEACON - for a position report (usually yourself)
|
||||||
|
# OBEACON - for an object report (usually some other entity)
|
||||||
|
#
|
||||||
|
# Each has a series of keywords and values for options.
|
||||||
|
# See User Guide for details.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# This results in a broadcast once every 10 minutes.
|
||||||
|
# Every half hour, it can travel via two digipeater hops.
|
||||||
|
# The others are kept local.
|
||||||
|
#
|
||||||
|
#PBEACON delay=1 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA" via=WIDE1-1,WIDE2-1
|
||||||
|
#PBEACON delay=11 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||||
|
#PBEACON delay=21 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||||
|
# With UTM coordinates instead of latitude and longitude.
|
||||||
|
#PBEACON delay=1 every=10 overlay=S symbol="digi" zone=19T easting=307477 northing=4720178
|
||||||
|
#
|
||||||
|
# When the destination field is set to "SPEECH" the information part is
|
||||||
|
# converted to speech rather than transmitted as a data frame.
|
||||||
|
#
|
||||||
|
#CBEACON dest="SPEECH" info="FRA1OD-10"
|
||||||
|
#
|
||||||
|
# Modify for your particular situation before removing
|
||||||
|
# the # comment character from the beginning of appropriate lines above.
|
||||||
|
#
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# DIGIPEATER PROPERTIES #
|
||||||
|
# #
|
||||||
|
############################################################
|
||||||
|
#
|
||||||
|
# For most common situations, use something like this by removing
|
||||||
|
# the "#" from the beginning of the line below.
|
||||||
|
#
|
||||||
|
#DIGIPEAT 0 0 ^WIDE[3-7]-[1-7]$|^TEST$ ^WIDE[12]-[12]$ TRACE
|
||||||
|
|
||||||
|
# See User Guide for more explanation of what this means and how
|
||||||
|
# it can be customized for your particular needs.
|
||||||
|
# Filtering can be used to limit was is digipeated.
|
||||||
|
# For example, only weather weather reports, received on channel 0,
|
||||||
|
# will be retransmitted on channel 1.
|
||||||
|
#
|
||||||
|
#FILTER 0 1 t/wn
|
||||||
|
#
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# INTERNET GATEWAY #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
# First you need to specify the name of a Tier 2 server.
|
||||||
|
# The current preferred way is to use one of these regional rotate addresses:
|
||||||
|
|
||||||
|
# noam.aprs2.net - for North America
|
||||||
|
# soam.aprs2.net - for South America
|
||||||
|
# euro.aprs2.net - for Europe and Africa
|
||||||
|
# asia.aprs2.net - for Asia
|
||||||
|
# aunz.aprs2.net - for Oceania
|
||||||
|
|
||||||
|
IGSERVER euro.aprs2.net
|
||||||
|
|
||||||
|
# You also need to specify your login name and passcode.
|
||||||
|
# Contact the author if you can't figure out how to generate the passcode.
|
||||||
|
|
||||||
|
IGLOGIN MYCALL 12345
|
||||||
|
|
||||||
|
# That's all you need for a receive only IGate which relays
|
||||||
|
# messages from the local radio channel to the global servers.
|
||||||
|
# Some might want to send an IGate client position directly to a server
|
||||||
|
# without sending it over the air and relying on someone else to
|
||||||
|
# forward it to an IGate server. This is done by using sendto=IG rather
|
||||||
|
# than a radio channel number. Overlay R for receive only, T for two way.
|
||||||
|
|
||||||
|
#PBEACON sendto=IG delay=0:30 every=60:00 symbol="igate" overlay=R lat=42^37.14N long=071^20.83W
|
||||||
|
#PBEACON sendto=IG delay=0:30 every=60:00 symbol="igate" overlay=T lat=42^37.14N long=071^20.83W
|
||||||
|
|
||||||
|
|
||||||
|
# To relay messages from the Internet to radio, you need to add
|
||||||
|
# one more option with the transmit channel number and a VIA path.
|
||||||
|
|
||||||
|
IGTXVIA 0 WIDE1-1 WIDE2-1
|
||||||
|
|
||||||
|
# You might want to apply a filter for what packets will be obtained from the server.
|
||||||
|
# Read about filters here: http://www.aprs-is.net/javaprsfilter.aspx
|
||||||
|
# Example, positions and objects within 50 km of my location:
|
||||||
|
|
||||||
|
#IGFILTER m/250
|
||||||
|
|
||||||
|
# That is known as a server-side filter. It is processed by the IGate server.
|
||||||
|
# You can also apply local filtering to limit what will be transmitted on the
|
||||||
|
# RF side. For example, transmit only "messages" on channel 0 and weather
|
||||||
|
# reports on channel 1.
|
||||||
|
|
||||||
|
#FILTER IG 0 t/m
|
||||||
|
#FILTER IG 1 t/wn
|
||||||
|
|
||||||
|
# Finally, we don't want to flood the radio channel.
|
||||||
|
# The IGate function will limit the number of packets transmitted
|
||||||
|
# during 1 minute and 5 minute intervals. If a limit would
|
||||||
|
# be exceeded, the packet is dropped and message is displayed in red.
|
||||||
|
|
||||||
|
IGTXLIMIT 10 20
|
||||||
|
|
||||||
|
#############################################################
|
||||||
|
# #
|
||||||
|
# APRStt GATEWAY #
|
||||||
|
# #
|
||||||
|
#############################################################
|
||||||
|
#
|
||||||
|
# Dire Wolf can receive DTMF (commonly known as Touch Tone)
|
||||||
|
# messages and convert them to packet objects.
|
||||||
|
#
|
||||||
|
# See separate "APRStt-Implementation-Notes" document for details.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Sample gateway configuration based on:
|
||||||
|
#
|
||||||
|
# http://www.aprs.org/aprstt/aprstt-coding24.txt
|
||||||
|
# http://www.aprs.org/aprs-jamboree-2013.html
|
||||||
|
#
|
||||||
|
# Define specific points.
|
||||||
|
|
||||||
|
TTPOINT B01 37^55.37N 81^7.86W
|
||||||
|
TTPOINT B7495088 42.605237 -71.34456
|
||||||
|
TTPOINT B934 42.605237 -71.34456
|
||||||
|
|
||||||
|
TTPOINT B901 42.661279 -71.364452
|
||||||
|
TTPOINT B902 42.660411 -71.364419
|
||||||
|
TTPOINT B903 42.659046 -71.364452
|
||||||
|
TTPOINT B904 42.657578 -71.364602
|
||||||
|
|
||||||
|
# For location at given bearing and distance from starting point.
|
||||||
|
|
||||||
|
TTVECTOR B5bbbddd 37^55.37N 81^7.86W 0.01 mi
|
||||||
|
|
||||||
|
# For location specified by x, y coordinates.
|
||||||
|
|
||||||
|
TTGRID Byyyxxx 37^50.00N 81^00.00W 37^59.99N 81^09.99W
|
||||||
|
|
||||||
|
# UTM location for Lowell-Dracut-Tyngsborough State Forest.
|
||||||
|
|
||||||
|
TTUTM B6xxxyyy 19T 10 300000 4720000
|
||||||
|
|
||||||
|
# Location for the corral.
|
||||||
|
|
||||||
|
TTCORRAL 37^55.50N 81^7.00W 0^0.02N
|
||||||
|
|
||||||
|
# Compact messages - Fixed locations xx and object yyy where
|
||||||
|
# Object numbers 100 - 199 = bicycle
|
||||||
|
# Object numbers 200 - 299 = fire truck
|
||||||
|
# Others = dog
|
||||||
|
|
||||||
|
TTMACRO xx1yy B9xx*AB166*AA2B4C5B3B0A1yy
|
||||||
|
TTMACRO xx2yy B9xx*AB170*AA3C4C7C3B0A2yy
|
||||||
|
TTMACRO xxyyy B9xx*AB180*AA3A6C4A0Ayyy
|
||||||
|
|
||||||
|
TTMACRO z Cz
|
||||||
|
|
||||||
|
# Receive on channel 0, Transmit object reports on channel 1 with optional via path.
|
||||||
|
|
||||||
|
#TTOBJ 0 1 WIDE1-1
|
||||||
|
|
||||||
|
# Advertise gateway position with beacon.
|
||||||
|
|
||||||
|
# OBEACON DELAY=0:15 EVERY=10:00 VIA=WIDE1-1 OBJNAME=WB2OSZ-tt SYMBOL=APRStt LAT=42^37.14N LONG=71^20.83W COMMENT="APRStt Gateway"
|
||||||
|
|
||||||
|
|
||||||
|
DWAIT 5
|
||||||
|
SLOTTIME 10
|
||||||
|
PERSIST 63
|
||||||
|
TXDELAY 150
|
||||||
|
TXTAIL 30
|
||||||
|
|
||||||
|
|
||||||
|
########################### FIN DU FICHIER ######################
|
Loading…
Reference in New Issue
Block a user