RadioBanter

RadioBanter (https://www.radiobanter.com/)
-   Digital (https://www.radiobanter.com/digital/)
-   -   Bell 202 modulation (AFSK1200) (https://www.radiobanter.com/digital/7788-bell-202-modulation-afsk1200.html)

R C July 5th 03 07:21 AM

Bell 202 modulation (AFSK1200)
 
I'm working on a telemetry board and wish to include software FSK1200
(MX-614's are getting harder to find). The official Bell 202 spec is
out of print and hard to find as well, so I pieced this together from
what I can find. Multimon won't decode the output, so I'm likely doing
something wrong. This is supposed to be (once it works) my reference
implementation before I port it to my telemetry board, so I'm trying
to keep it as simple as possible.

The program outputs 22050 hz 8-bit signed data to stdout;
gcc fsk.c -o fsk -lm; ./fsk test; sox -s -b -r 22050 test -w
test.wav

Phase is coherent, and there are peaks at 1200 and 2200 in the
spectrum analysis.

Any help or suggestions would be appreciated.

Robert Cicconetti
KG4MVB

-- begin fsk.c --
#include math.h
#include stdio.h

// $#@$#@
//#define BAUDRATE 1200
// octet rate is 150 octet / sec. (1200 / 8). BIT period is
// .000666, or 1/1500 (10 bits per symbol, including start and stop).
// BAUDRATE is therefor used improperly here; fixme.
#define BAUDRATE 1500
#define MARK 1200
#define SPACE 2200

// For convenience when working with multimon
#define SAMPLERATE 22050

double sendbyte(char a, double angle);

int main (void)
{
// 8 bit output; encoder DAC is likely to be only 3 or 4 bit
short outbyte;
int i;
double angle = 0;
char test[]= "fm KG4MVB-0 to FFFFFF-0 SABM+";

for (i = 0 ; i 5000; i++) putchar(0);
//PREAMBLE
for (i = 0 ; i 24; i++) sendbyte(0, angle);

for (i = 0 ; i 29 ; i++)
{
angle = sendbyte(test[i], angle);
}

for (i = 0 ; i 2; i++) sendbyte(0, angle);
for (i = 0 ; i 50000; i++) putchar(0);
return 0;
}

double sendbyte(char a, double angle)
{
// LSB first. Start bit MARK end bit SPACE
// MARK is 1, SPACE is 0
//
double phase_offset = 0;
int freq, j = 0, i;
char bit;

for (i = 0; i 10; i++)
{
if (i == 0)
bit = 1;
else if (i == 9)
bit = 0;
else
bit =( a (i-1)) & 0x1;

if (bit == 1)
freq = MARK;
else
freq = SPACE;

phase_offset = angle -
(double)2*M_PI*freq*((double)(j-1)/SAMPLERATE);
while (j ((i+1)*SAMPLERATE)/BAUDRATE )
{
angle =
(double)2*M_PI*freq*((double)j/SAMPLERATE) + phase_offset;
putchar((short)(0.5*sin(angle)*128));
j++;
}
}
return angle;
}

R C July 5th 03 05:10 PM

Dana Myers K6JQ wrote in message ws.com...
R C wrote:
I'm working on a telemetry board and wish to include software FSK1200
(MX-614's are getting harder to find). The official Bell 202 spec is
out of print and hard to find as well, so I pieced this together from
what I can find. Multimon won't decode the output, so I'm likely doing
something wrong. This is supposed to be (once it works) my reference
implementation before I port it to my telemetry board, so I'm trying
to keep it as simple as possible.


Any help or suggestions would be appreciated.


First - is multimon expecting a properly formatted AX.25 frame?
(This code is clearly not creating an HDLC-encoded, AX.25-formatted
frame). It looks like you're sending conventional async-encoded
ASCII. You need to:


That would explain it. I hadn't planned on using AX-25 (TX is the
audio subcarrier of an FM ATV camera; no point in packetizing it since
no digipeaters would be able to hear it, and unit should never be out
of reception range in any case). I had planned on adding framing,
checksums and possibly FEC later.

I was also trying to keep it as simple as possible initially; encode
raw octets and make sure I can decode them.

It may be worth adding the HDLC/ax.25; initial basestation will likely
be a laptop running soundmodem.

Also - I'd avoid the use of transcendental functions (sin()) in the
synthesizer loop ; I'd create a lookup table and index it via an
integer phase accumulator. Off the top of my head, I'd guess a
16-bit phase accumulator and a 256-element sine array would be
plenty. You'd need to precalculate the phase increments for
1200 and 2200 Hz, likely as constants.


That is step 2 :) The target CPU will most likely be a Mega8535 AVR,
so conversion to integer is definately indicated. :)

Thanks,
R C
KG4MVB

R C July 5th 03 05:10 PM

Dana Myers K6JQ wrote in message ws.com...
R C wrote:
I'm working on a telemetry board and wish to include software FSK1200
(MX-614's are getting harder to find). The official Bell 202 spec is
out of print and hard to find as well, so I pieced this together from
what I can find. Multimon won't decode the output, so I'm likely doing
something wrong. This is supposed to be (once it works) my reference
implementation before I port it to my telemetry board, so I'm trying
to keep it as simple as possible.


Any help or suggestions would be appreciated.


First - is multimon expecting a properly formatted AX.25 frame?
(This code is clearly not creating an HDLC-encoded, AX.25-formatted
frame). It looks like you're sending conventional async-encoded
ASCII. You need to:


That would explain it. I hadn't planned on using AX-25 (TX is the
audio subcarrier of an FM ATV camera; no point in packetizing it since
no digipeaters would be able to hear it, and unit should never be out
of reception range in any case). I had planned on adding framing,
checksums and possibly FEC later.

I was also trying to keep it as simple as possible initially; encode
raw octets and make sure I can decode them.

It may be worth adding the HDLC/ax.25; initial basestation will likely
be a laptop running soundmodem.

Also - I'd avoid the use of transcendental functions (sin()) in the
synthesizer loop ; I'd create a lookup table and index it via an
integer phase accumulator. Off the top of my head, I'd guess a
16-bit phase accumulator and a 256-element sine array would be
plenty. You'd need to precalculate the phase increments for
1200 and 2200 Hz, likely as constants.


That is step 2 :) The target CPU will most likely be a Mega8535 AVR,
so conversion to integer is definately indicated. :)

Thanks,
R C
KG4MVB

Dana Myers K6JQ July 6th 03 01:52 AM

R C wrote:

Dana Myers K6JQ wrote in message ws.com...



It may be worth adding the HDLC/ax.25; initial basestation will likely
be a laptop running soundmodem.


In which case, AX.25 isn't that hard at all to implement,
HDLC is fairly trivial, and the checksum code can be found
pretty readily (I have a Java port of something I sponged out
of an old RFC if you're looking for sample code).

You'll likely need it all for soundmodem recognize your frames, but
you don't need to do full-on connected-mode AX.25, UI datagrams are
likely enough.

Also - I'd avoid the use of transcendental functions (sin()) in the
synthesizer loop ; I'd create a lookup table and index it via an
integer phase accumulator. Off the top of my head, I'd guess a
16-bit phase accumulator and a 256-element sine array would be
plenty. You'd need to precalculate the phase increments for
1200 and 2200 Hz, likely as constants.



That is step 2 :) The target CPU will most likely be a Mega8535 AVR,
so conversion to integer is definately indicated. :)


Heh. You're tempting to cobble up the DDS code for giggles and
flash it into an atMega16 I have sitting here ;-)

Dana


Dana Myers K6JQ July 6th 03 01:52 AM

R C wrote:

Dana Myers K6JQ wrote in message ws.com...



It may be worth adding the HDLC/ax.25; initial basestation will likely
be a laptop running soundmodem.


In which case, AX.25 isn't that hard at all to implement,
HDLC is fairly trivial, and the checksum code can be found
pretty readily (I have a Java port of something I sponged out
of an old RFC if you're looking for sample code).

You'll likely need it all for soundmodem recognize your frames, but
you don't need to do full-on connected-mode AX.25, UI datagrams are
likely enough.

Also - I'd avoid the use of transcendental functions (sin()) in the
synthesizer loop ; I'd create a lookup table and index it via an
integer phase accumulator. Off the top of my head, I'd guess a
16-bit phase accumulator and a 256-element sine array would be
plenty. You'd need to precalculate the phase increments for
1200 and 2200 Hz, likely as constants.



That is step 2 :) The target CPU will most likely be a Mega8535 AVR,
so conversion to integer is definately indicated. :)


Heh. You're tempting to cobble up the DDS code for giggles and
flash it into an atMega16 I have sitting here ;-)

Dana


Paul Keinanen July 6th 03 10:58 PM

On 4 Jul 2003 23:21:05 -0700, (R C) wrote:

I'm working on a telemetry board and wish to include software FSK1200
(MX-614's are getting harder to find). The official Bell 202 spec is
out of print and hard to find as well, so I pieced this together from
what I can find. Multimon won't decode the output, so I'm likely doing
something wrong.


What is this Multimon thing expecting ?

Is it expecting ordinary asynchronous characters ?

// LSB first. Start bit MARK end bit SPACE
// MARK is 1, SPACE is 0


for (i = 0; i 10; i++)
{
if (i == 0)
bit = 1;
else if (i == 9)
bit = 0;
else
bit =( a (i-1)) & 0x1;


In that case I assume you have mixed the polarity of the start and
stop bits.

In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.

If that Multimon thing is expecting AX.25, don't forget to add the bit
stuffing in the last stage before transmission.

Paul OH3LWR



Paul Keinanen July 6th 03 10:58 PM

On 4 Jul 2003 23:21:05 -0700, (R C) wrote:

I'm working on a telemetry board and wish to include software FSK1200
(MX-614's are getting harder to find). The official Bell 202 spec is
out of print and hard to find as well, so I pieced this together from
what I can find. Multimon won't decode the output, so I'm likely doing
something wrong.


What is this Multimon thing expecting ?

Is it expecting ordinary asynchronous characters ?

// LSB first. Start bit MARK end bit SPACE
// MARK is 1, SPACE is 0


for (i = 0; i 10; i++)
{
if (i == 0)
bit = 1;
else if (i == 9)
bit = 0;
else
bit =( a (i-1)) & 0x1;


In that case I assume you have mixed the polarity of the start and
stop bits.

In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.

If that Multimon thing is expecting AX.25, don't forget to add the bit
stuffing in the last stage before transmission.

Paul OH3LWR



R C July 7th 03 02:36 AM

Dana Myers K6JQ wrote in message ws.com...
R C wrote:
That is step 2 :) The target CPU will most likely be a Mega8535 AVR,
so conversion to integer is definately indicated. :)


Heh. You're tempting to cobble up the DDS code for giggles and
flash it into an atMega16 I have sitting here ;-)


Hmm.. shot one, for GCC, no ASM. Nominally targetted for 8515 at 8
mhz, easy
to redo.

Not quite finished implementing, and definately not tested, but
framework should be there.

R C
KG4MVB

-- begin fsk2.c --

#include avr/io.h
#include avr/pgmspace.h


// Generated via sine.c. Theory suggests you can use reflexive nature
of sine.
// but we'll keep it simple. Besides, we have 8K of flash.

// For avr use prog_uchar?
prog_uchar s_table[] = [
0x80,0x83,0x86,0x89,0x8C,0x90,0x93,0x96,0x99,0x9C, 0x9F,0xA2,0xA5,0xA8,0xAB,0xAE,
0xB1,0xB3,0xB6,0xB9,0xBC,0xBF,0xC1,0xC4,0xC7,0xC9, 0xCC,0xCE,0xD1,0xD3,0xD5,0xD8,
0xDA,0xDC,0xDE,0xE0,0xE2,0xE4,0xE6,0xE8,0xEA,0xEB, 0xED,0xEF,0xF0,0xF1,0xF3,0xF4,
0xF5,0xF6,0xF8,0xF9,0xFA,0xFA,0xFB,0xFC,0xFD,0xFD, 0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFE,0xFD,0xFD,0xFC, 0xFB,0xFA,0xFA,0xF9,0xF8,0xF6,
0xF5,0xF4,0xF3,0xF1,0xF0,0xEF,0xED,0xEB,0xEA,0xE8, 0xE6,0xE4,0xE2,0xE0,0xDE,0xDC,
0xDA,0xD8,0xD5,0xD3,0xD1,0xCE,0xCC,0xC9,0xC7,0xC4, 0xC1,0xBF,0xBC,0xB9,0xB6,0xB3,
0xB1,0xAE,0xAB,0xA8,0xA5,0xA2,0x9F,0x9C,0x99,0x96, 0x93,0x90,0x8C,0x89,0x86,0x83,
0x80,0x7D,0x7A,0x77,0x74,0x70,0x6D,0x6A,0x67,0x64, 0x61,0x5E,0x5B,0x58,0x55,0x52,
0x4F,0x4D,0x4A,0x47,0x44,0x41,0x3F,0x3C,0x39,0x37, 0x34,0x32,0x2F,0x2D,0x2B,0x28,
0x26,0x24,0x22,0x20,0x1E,0x1C,0x1A,0x18,0x16,0x15, 0x13,0x11,0x10,0x0F,0x0D,0x0C,
0x0B,0x0A,0x08,0x07,0x06,0x06,0x05,0x04,0x03,0x03, 0x02,0x02,0x02,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x04, 0x05,0x06,0x06,0x07,0x08,0x0A,
0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x13,0x15,0x16,0x18, 0x1A,0x1C,0x1E,0x20,0x22,0x24,
0x26,0x28,0x2B,0x2D,0x2F,0x32,0x34,0x37,0x39,0x3C, 0x3F,0x41,0x44,0x47,0x4A,0x4D,
0x4F,0x52,0x55,0x58,0x5B,0x5E,0x61,0x64,0x67,0x6A, 0x6D,0x70,0x74,0x77,0x7A,0x7D
];


// Hmm.. for now assume an 8515-class running at 8 mhz. I've got a few
// spares in the box, and haven't gotten to ordering the megas from
digikey
// yet.

// This will not be a dedicated DDS, and it only needs to produce two
// frequencies. Output methods include a DAC (R2R or separate), I2C
digipot
// (not sure if fast enough, but have some laying around) or PWM.
Assume DAC
// for now.


// Choose an apropriate sample rate. ~10 khz should be adequate, and
not put
// a large burden on the AVR. A low pass may be indicated.

// Keep things simple.. use 32-bit accumulator, so we can run on a
slow clock.
// This is overkill, but easier to do in GCC than 24-bit.
volatile register uint32_t accum, freq_offset;

/* May want to make a circular buffer */
volatile uint8_t fsk_out, fsk_bit, fsk_done_flag;


// Okay.. 8M clock

// Use /256 for TCNT0. 3 of the /256 cycles will give us a sample rate
of
// 10416 Hz
#define TCNT0_PRESCALE 4
#define TCNT0_PERIOD 3


// FCLK = 10416/2^32 = 2.43x10^-6 resolution.
// 1199.9999987893 hz
#define MARK 494780232
// 2200.0000002057 hz
#define SPACE 907097093

// Use /8 for TCNT1. This puts our nominal bitrate at 1199.4 bps,
prolly close
// enough. (0.05%)
#define TCNT1_PRESCALE 2
#define BIT_PERIOD 667

SIGNAL(SIG_OUTPUT_COMPARE0)
{
// Not sure how well this will be optimized, but as it's only run
// every 10khz..
accum += freq_offset;
PORTC = PRG_RDB(s_table + (accum 24));
0CR0 += TCNT0_PERIOD;
// is this needed?
sei();
}


/* This needs to be set pretty close to 1/1500 second. */
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
switch (fsk_bit)
{
case 0 : freq_offset = MARK; break;
case 9 : freq_offset = SPACE; fsk_done = 1; break;
default : freq_offset = (fsk_out (fsk_bit-1)) ?
MARK : SPACE; break;
}
fsk_bit++;
// If only item on TCNT1;
//TCNT1 = 0;
// If sharing TCNT1
OCR1A += BIT_PERIOD;
// is this needed?
sei();
}

void main (void)
{
//setup everything, add ax.25 framing and HDLC encoding. optimized
//crc16 in avr-libc.
}

R C July 7th 03 02:36 AM

Dana Myers K6JQ wrote in message ws.com...
R C wrote:
That is step 2 :) The target CPU will most likely be a Mega8535 AVR,
so conversion to integer is definately indicated. :)


Heh. You're tempting to cobble up the DDS code for giggles and
flash it into an atMega16 I have sitting here ;-)


Hmm.. shot one, for GCC, no ASM. Nominally targetted for 8515 at 8
mhz, easy
to redo.

Not quite finished implementing, and definately not tested, but
framework should be there.

R C
KG4MVB

-- begin fsk2.c --

#include avr/io.h
#include avr/pgmspace.h


// Generated via sine.c. Theory suggests you can use reflexive nature
of sine.
// but we'll keep it simple. Besides, we have 8K of flash.

// For avr use prog_uchar?
prog_uchar s_table[] = [
0x80,0x83,0x86,0x89,0x8C,0x90,0x93,0x96,0x99,0x9C, 0x9F,0xA2,0xA5,0xA8,0xAB,0xAE,
0xB1,0xB3,0xB6,0xB9,0xBC,0xBF,0xC1,0xC4,0xC7,0xC9, 0xCC,0xCE,0xD1,0xD3,0xD5,0xD8,
0xDA,0xDC,0xDE,0xE0,0xE2,0xE4,0xE6,0xE8,0xEA,0xEB, 0xED,0xEF,0xF0,0xF1,0xF3,0xF4,
0xF5,0xF6,0xF8,0xF9,0xFA,0xFA,0xFB,0xFC,0xFD,0xFD, 0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFE,0xFD,0xFD,0xFC, 0xFB,0xFA,0xFA,0xF9,0xF8,0xF6,
0xF5,0xF4,0xF3,0xF1,0xF0,0xEF,0xED,0xEB,0xEA,0xE8, 0xE6,0xE4,0xE2,0xE0,0xDE,0xDC,
0xDA,0xD8,0xD5,0xD3,0xD1,0xCE,0xCC,0xC9,0xC7,0xC4, 0xC1,0xBF,0xBC,0xB9,0xB6,0xB3,
0xB1,0xAE,0xAB,0xA8,0xA5,0xA2,0x9F,0x9C,0x99,0x96, 0x93,0x90,0x8C,0x89,0x86,0x83,
0x80,0x7D,0x7A,0x77,0x74,0x70,0x6D,0x6A,0x67,0x64, 0x61,0x5E,0x5B,0x58,0x55,0x52,
0x4F,0x4D,0x4A,0x47,0x44,0x41,0x3F,0x3C,0x39,0x37, 0x34,0x32,0x2F,0x2D,0x2B,0x28,
0x26,0x24,0x22,0x20,0x1E,0x1C,0x1A,0x18,0x16,0x15, 0x13,0x11,0x10,0x0F,0x0D,0x0C,
0x0B,0x0A,0x08,0x07,0x06,0x06,0x05,0x04,0x03,0x03, 0x02,0x02,0x02,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x04, 0x05,0x06,0x06,0x07,0x08,0x0A,
0x0B,0x0C,0x0D,0x0F,0x10,0x11,0x13,0x15,0x16,0x18, 0x1A,0x1C,0x1E,0x20,0x22,0x24,
0x26,0x28,0x2B,0x2D,0x2F,0x32,0x34,0x37,0x39,0x3C, 0x3F,0x41,0x44,0x47,0x4A,0x4D,
0x4F,0x52,0x55,0x58,0x5B,0x5E,0x61,0x64,0x67,0x6A, 0x6D,0x70,0x74,0x77,0x7A,0x7D
];


// Hmm.. for now assume an 8515-class running at 8 mhz. I've got a few
// spares in the box, and haven't gotten to ordering the megas from
digikey
// yet.

// This will not be a dedicated DDS, and it only needs to produce two
// frequencies. Output methods include a DAC (R2R or separate), I2C
digipot
// (not sure if fast enough, but have some laying around) or PWM.
Assume DAC
// for now.


// Choose an apropriate sample rate. ~10 khz should be adequate, and
not put
// a large burden on the AVR. A low pass may be indicated.

// Keep things simple.. use 32-bit accumulator, so we can run on a
slow clock.
// This is overkill, but easier to do in GCC than 24-bit.
volatile register uint32_t accum, freq_offset;

/* May want to make a circular buffer */
volatile uint8_t fsk_out, fsk_bit, fsk_done_flag;


// Okay.. 8M clock

// Use /256 for TCNT0. 3 of the /256 cycles will give us a sample rate
of
// 10416 Hz
#define TCNT0_PRESCALE 4
#define TCNT0_PERIOD 3


// FCLK = 10416/2^32 = 2.43x10^-6 resolution.
// 1199.9999987893 hz
#define MARK 494780232
// 2200.0000002057 hz
#define SPACE 907097093

// Use /8 for TCNT1. This puts our nominal bitrate at 1199.4 bps,
prolly close
// enough. (0.05%)
#define TCNT1_PRESCALE 2
#define BIT_PERIOD 667

SIGNAL(SIG_OUTPUT_COMPARE0)
{
// Not sure how well this will be optimized, but as it's only run
// every 10khz..
accum += freq_offset;
PORTC = PRG_RDB(s_table + (accum 24));
0CR0 += TCNT0_PERIOD;
// is this needed?
sei();
}


/* This needs to be set pretty close to 1/1500 second. */
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
switch (fsk_bit)
{
case 0 : freq_offset = MARK; break;
case 9 : freq_offset = SPACE; fsk_done = 1; break;
default : freq_offset = (fsk_out (fsk_bit-1)) ?
MARK : SPACE; break;
}
fsk_bit++;
// If only item on TCNT1;
//TCNT1 = 0;
// If sharing TCNT1
OCR1A += BIT_PERIOD;
// is this needed?
sei();
}

void main (void)
{
//setup everything, add ax.25 framing and HDLC encoding. optimized
//crc16 in avr-libc.
}

R C July 7th 03 03:46 AM

Paul Keinanen wrote in message . ..
On 4 Jul 2003 23:21:05 -0700, (R C) wrote:

I'm working on a telemetry board and wish to include software FSK1200
(MX-614's are getting harder to find). The official Bell 202 spec is
out of print and hard to find as well, so I pieced this together from
what I can find. Multimon won't decode the output, so I'm likely doing
something wrong.


What is this Multimon thing expecting ?


Okay, I've figured some things out since I first posted. Multimon was
written by Thomas Sailer, who also wrote the soundmodem program.

It's available at
http://www.baycom.org/~tom/ham/linux/multimon.html.

Documentation is lacking, but reviewing the source (don't try and
debug at 4 AM; I should've figured this out originally) the afsk1200
decoder expects hdlc encoding, and possibly AX.25 framing (didn't
trace that far). However, an undocumented option -v 10 yields the raw
bit stream.

In that case I assume you have mixed the polarity of the start and
stop bits.

In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.


That part I figured out from APRS packets recorded off the air. Start
is definately 1200 hz, stop is 2200 hz.

Thanks for the suggestions,
R C
KG4MVB

R C July 7th 03 03:46 AM

Paul Keinanen wrote in message . ..
On 4 Jul 2003 23:21:05 -0700, (R C) wrote:

I'm working on a telemetry board and wish to include software FSK1200
(MX-614's are getting harder to find). The official Bell 202 spec is
out of print and hard to find as well, so I pieced this together from
what I can find. Multimon won't decode the output, so I'm likely doing
something wrong.


What is this Multimon thing expecting ?


Okay, I've figured some things out since I first posted. Multimon was
written by Thomas Sailer, who also wrote the soundmodem program.

It's available at
http://www.baycom.org/~tom/ham/linux/multimon.html.

Documentation is lacking, but reviewing the source (don't try and
debug at 4 AM; I should've figured this out originally) the afsk1200
decoder expects hdlc encoding, and possibly AX.25 framing (didn't
trace that far). However, an undocumented option -v 10 yields the raw
bit stream.

In that case I assume you have mixed the polarity of the start and
stop bits.

In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.


That part I figured out from APRS packets recorded off the air. Start
is definately 1200 hz, stop is 2200 hz.

Thanks for the suggestions,
R C
KG4MVB

Paul Keinanen July 7th 03 08:16 AM

On 6 Jul 2003 19:46:48 -0700, (R C) wrote:

In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.


That part I figured out from APRS packets recorded off the air. Start
is definately 1200 hz, stop is 2200 hz.


How did you determine this ?

APRS is definitively AX.25, which is a version of the X.25 protocol,
which are all members of the HDLC protocol family. These protocols
are _synchronous_ protocols, thus, they do not contain any start or
stop bits. The AX.25 protocol sends 8 bit octets (bytes) packed
immediately side by side without any bits in between them forming a
multiple octet frame. The whole frame starts with on octet with the
"01111110" bit pattern (the flag pattern) and it also ends with the
same pattern (or a single flag is used as a _frame_ separators, if
multiple frames are sent at once). In order to avoid false flag
detection within the data part of the frame, the 0 bit is inserted
after five consecutive 1 bits.

To illustrate how synchronous protocols work and how the bit stuffing
is done in HDLC, here is a simplified example (use fixed font).

Assume that you want to send the characters "a?b" which is 0x61 0x3F
0x62. First convert to bits (LSB first)

10000110 = 'a'
11111100 = '?'
01000110 = 'b'

Put them side by side

100001101111110001000110
.........^^^^^...........

Check for 5 consecutive 1 bits and add the bit stuffing.

1000011011111010001000110
_____________I___________

Add the flag octets

01111110100001101111101000100011001111110

It should be noted that the checking for five 1 bits must be done
after the bytes are put into a single bit stream, since sending two
consecutive bytes such as 00001111 11110000 do not violate the
five1bit rule separately, but when the bytes are combined into a bit
sequence, you would end up with 0000111111110000, bit stuffing must be
inserted 00001111101110000. Sending 11111111 11111111 requires three
stuff bits: 1111101111101111101

This a very simplified example, a real AX.25 frame would contain the
address fields and the CRC field at the end.

When you say that the APRS frame starts with a Mark and ends with a
Space, are you sure you are not seeing some effects of TxDelay, i.e.
the Tx is on but no data (or some preamble) is sent.

Paul OH3LWR


Paul Keinanen July 7th 03 08:16 AM

On 6 Jul 2003 19:46:48 -0700, (R C) wrote:

In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.


That part I figured out from APRS packets recorded off the air. Start
is definately 1200 hz, stop is 2200 hz.


How did you determine this ?

APRS is definitively AX.25, which is a version of the X.25 protocol,
which are all members of the HDLC protocol family. These protocols
are _synchronous_ protocols, thus, they do not contain any start or
stop bits. The AX.25 protocol sends 8 bit octets (bytes) packed
immediately side by side without any bits in between them forming a
multiple octet frame. The whole frame starts with on octet with the
"01111110" bit pattern (the flag pattern) and it also ends with the
same pattern (or a single flag is used as a _frame_ separators, if
multiple frames are sent at once). In order to avoid false flag
detection within the data part of the frame, the 0 bit is inserted
after five consecutive 1 bits.

To illustrate how synchronous protocols work and how the bit stuffing
is done in HDLC, here is a simplified example (use fixed font).

Assume that you want to send the characters "a?b" which is 0x61 0x3F
0x62. First convert to bits (LSB first)

10000110 = 'a'
11111100 = '?'
01000110 = 'b'

Put them side by side

100001101111110001000110
.........^^^^^...........

Check for 5 consecutive 1 bits and add the bit stuffing.

1000011011111010001000110
_____________I___________

Add the flag octets

01111110100001101111101000100011001111110

It should be noted that the checking for five 1 bits must be done
after the bytes are put into a single bit stream, since sending two
consecutive bytes such as 00001111 11110000 do not violate the
five1bit rule separately, but when the bytes are combined into a bit
sequence, you would end up with 0000111111110000, bit stuffing must be
inserted 00001111101110000. Sending 11111111 11111111 requires three
stuff bits: 1111101111101111101

This a very simplified example, a real AX.25 frame would contain the
address fields and the CRC field at the end.

When you say that the APRS frame starts with a Mark and ends with a
Space, are you sure you are not seeing some effects of TxDelay, i.e.
the Tx is on but no data (or some preamble) is sent.

Paul OH3LWR


Dana Myers K6JQ July 7th 03 09:28 AM

Paul Keinanen wrote:
On 6 Jul 2003 19:46:48 -0700, (R C) wrote:


In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.


That part I figured out from APRS packets recorded off the air. Start
is definately 1200 hz, stop is 2200 hz.



How did you determine this ?

APRS is definitively AX.25, which is a version of the X.25 protocol,
which are all members of the HDLC protocol family. These protocols
are _synchronous_ protocols, thus, they do not contain any start or
stop bits. The AX.25 protocol sends 8 bit octets (bytes) packed
immediately side by side without any bits in between them forming a
multiple octet frame. The whole frame starts with on octet with the
"01111110" bit pattern (the flag pattern) and it also ends with the
same pattern (or a single flag is used as a _frame_ separators, if
multiple frames are sent at once). In order to avoid false flag
detection within the data part of the frame, the 0 bit is inserted
after five consecutive 1 bits.



Well, don't forget that HDLC is NRZI encoded - the absolute level
(mark vs. space) is meaningless. A transition indicates a 0 and
the lack of a transition indicates a 1. Sending a series of 0s
results in a square wave of 1/2 the baud rate (since each baud
is the opposite of the previous baud). Sending a series of 1s
results in a series of unchanged bauds.

So, if the initial state of the NRZI encoder is '1' and the
'01111110' flag sequence is sent, the resulting output is:

initial state 1 : 0 0 0 0 0 0 0 1 and the next flag looks like
0 0 0 0 0 0 0 1 and this pattern repeats as long
as flags are being sent.

If the initial state is 0 you get:

initial state 0 : 1 1 1 1 1 1 1 0 and this pattern repeats.

So, you can't tell anything about the date being sent
from the absolute levels.

Dana


Dana Myers K6JQ July 7th 03 09:28 AM

Paul Keinanen wrote:
On 6 Jul 2003 19:46:48 -0700, (R C) wrote:


In ordinary RS-232 asynchronous communication the start bit is "0"
SPACE, interrupting the idle MARK state, followed by the data bits
with LSB sent first. The stop bit is "1" or MARK, which then transfers
to a MARK idle state if no more characters are to be transmitted.


That part I figured out from APRS packets recorded off the air. Start
is definately 1200 hz, stop is 2200 hz.



How did you determine this ?

APRS is definitively AX.25, which is a version of the X.25 protocol,
which are all members of the HDLC protocol family. These protocols
are _synchronous_ protocols, thus, they do not contain any start or
stop bits. The AX.25 protocol sends 8 bit octets (bytes) packed
immediately side by side without any bits in between them forming a
multiple octet frame. The whole frame starts with on octet with the
"01111110" bit pattern (the flag pattern) and it also ends with the
same pattern (or a single flag is used as a _frame_ separators, if
multiple frames are sent at once). In order to avoid false flag
detection within the data part of the frame, the 0 bit is inserted
after five consecutive 1 bits.



Well, don't forget that HDLC is NRZI encoded - the absolute level
(mark vs. space) is meaningless. A transition indicates a 0 and
the lack of a transition indicates a 1. Sending a series of 0s
results in a square wave of 1/2 the baud rate (since each baud
is the opposite of the previous baud). Sending a series of 1s
results in a series of unchanged bauds.

So, if the initial state of the NRZI encoder is '1' and the
'01111110' flag sequence is sent, the resulting output is:

initial state 1 : 0 0 0 0 0 0 0 1 and the next flag looks like
0 0 0 0 0 0 0 1 and this pattern repeats as long
as flags are being sent.

If the initial state is 0 you get:

initial state 0 : 1 1 1 1 1 1 1 0 and this pattern repeats.

So, you can't tell anything about the date being sent
from the absolute levels.

Dana


R C July 7th 03 09:12 PM

Paul Keinanen wrote in message . ..
APRS is definitively AX.25, which is a version of the X.25 protocol,
which are all members of the HDLC protocol family. These protocols
are _synchronous_ protocols, thus, they do not contain any start or
stop bits. The AX.25 protocol sends 8 bit octets (bytes) packed
immediately side by side without any bits in between them forming a
multiple octet frame. The whole frame starts with on octet with the
"01111110" bit pattern (the flag pattern) and it also ends with the
same pattern (or a single flag is used as a _frame_ separators, if
multiple frames are sent at once). In order to avoid false flag
detection within the data part of the frame, the 0 bit is inserted
after five consecutive 1 bits.


Therein lies the problem I was having. I was looking at this as
another protocol layered on top of an asynchronous serial connection.

Thank you, it makes more sense now. Bitstuffing on a synchronous
serial
connection is trivial. Receiving is slightly less so, but not too
difficult.

I think I got the impression that bell 202 is asynchronous from some
of the commercial bell 202 modems I found on google; nearly all of
them say asynchronous. (Which, on reflection, is probably on the
computer-modem interface.)

Caller ID _does_ use an asynchronous wireline format, and also uses
Bell 202 signaling. Okay.. so it can go either way, and hdlc is
synchronous.

When you say that the APRS frame starts with a Mark and ends with a
Space, are you sure you are not seeing some effects of TxDelay, i.e.
the Tx is on but no data (or some preamble) is sent.


It does indeed appear to be some sort of runout to keep the squelch
from closing too quickly, but the of end packet flag occurs approx. 32
bits before.

Thanks,
R C
KG4MVB
(In any case, telemetry is not required to be AX.25 encapsulated, but
it's nice for interoperation)

R C July 7th 03 09:12 PM

Paul Keinanen wrote in message . ..
APRS is definitively AX.25, which is a version of the X.25 protocol,
which are all members of the HDLC protocol family. These protocols
are _synchronous_ protocols, thus, they do not contain any start or
stop bits. The AX.25 protocol sends 8 bit octets (bytes) packed
immediately side by side without any bits in between them forming a
multiple octet frame. The whole frame starts with on octet with the
"01111110" bit pattern (the flag pattern) and it also ends with the
same pattern (or a single flag is used as a _frame_ separators, if
multiple frames are sent at once). In order to avoid false flag
detection within the data part of the frame, the 0 bit is inserted
after five consecutive 1 bits.


Therein lies the problem I was having. I was looking at this as
another protocol layered on top of an asynchronous serial connection.

Thank you, it makes more sense now. Bitstuffing on a synchronous
serial
connection is trivial. Receiving is slightly less so, but not too
difficult.

I think I got the impression that bell 202 is asynchronous from some
of the commercial bell 202 modems I found on google; nearly all of
them say asynchronous. (Which, on reflection, is probably on the
computer-modem interface.)

Caller ID _does_ use an asynchronous wireline format, and also uses
Bell 202 signaling. Okay.. so it can go either way, and hdlc is
synchronous.

When you say that the APRS frame starts with a Mark and ends with a
Space, are you sure you are not seeing some effects of TxDelay, i.e.
the Tx is on but no data (or some preamble) is sent.


It does indeed appear to be some sort of runout to keep the squelch
from closing too quickly, but the of end packet flag occurs approx. 32
bits before.

Thanks,
R C
KG4MVB
(In any case, telemetry is not required to be AX.25 encapsulated, but
it's nice for interoperation)


All times are GMT +1. The time now is 09:29 PM.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
RadioBanter.com