kopia lustrzana https://github.com/alpov/SatCam
264 wiersze
8.3 KiB
C
264 wiersze
8.3 KiB
C
/*************************************************************************
|
|
*
|
|
* PSK Transponder Module for PSAT-2
|
|
* Copyright (c) 2014-2017 OK2ALP, OK2PNQ, OK2CPV
|
|
* Dept. of Radio Electronics, Brno University of Technology
|
|
*
|
|
* This work is licensed under the terms of the MIT license
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include <avr/io.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <avr/interrupt.h>
|
|
#include <avr/wdt.h>
|
|
#include <util/delay.h>
|
|
#include "common.h"
|
|
#include "bpsk.h"
|
|
|
|
static const uint16_t VARICODE_CHARSET[] PROGMEM = {
|
|
0b1000000000000000, 1 + 2, //Space
|
|
0b1111111110000000, 9 + 2, //!
|
|
0b1010111110000000, 9 + 2, //"
|
|
0b1111101010000000, 9 + 2, // #
|
|
0b1110110110000000, 9 + 2, // $
|
|
0b1011010101000000, 10 + 2, // %
|
|
0b1010111011000000, 10 + 2, // &
|
|
0b1011111110000000, 9 + 2, // '
|
|
0b1111101100000000, 8 + 2, //(
|
|
0b1111011100000000, 8 + 2, //)
|
|
0b1011011110000000, 9 + 2, // *
|
|
0b1110111110000000, 9 + 2, //+
|
|
0b1110101000000000, 7 + 2, //,
|
|
0b1101010000000000, 6 + 2, //-
|
|
0b1010111000000000, 7 + 2, //.
|
|
0b1101011110000000, 9 + 2, ///
|
|
0b1011011100000000, 8 + 2, //0
|
|
0b1011110100000000, 8 + 2, //1
|
|
0b1110110100000000, 8 + 2, //2
|
|
0b1111111100000000, 8 + 2, //3
|
|
0b1011101110000000, 9 + 2, //4
|
|
0b1010110110000000, 9 + 2, //5
|
|
0b1011010110000000, 9 + 2, //6
|
|
0b1101011010000000, 9 + 2, //7
|
|
0b1101010110000000, 9 + 2, //8
|
|
0b1101101110000000, 9 + 2, //9
|
|
0b1111010100000000, 8 + 2, //:
|
|
0b1101011110000000, 9 + 2, ////
|
|
0b1111011010000000, 9 + 2, // <
|
|
0b1010101000000000, 7 + 2, //=
|
|
0b1110101110000000, 9 + 2, // >
|
|
0b1010101111000000, 10 + 2, //?
|
|
0b1010111101000000, 10 + 2, //@
|
|
0b1111101000000000, 7 + 2, //A
|
|
0b1110101100000000, 8 + 2, //B
|
|
0b1010110100000000, 8 + 2, //C
|
|
0b1011010100000000, 8 + 2, //D
|
|
0b1110111000000000, 7 + 2, //E
|
|
0b1101101100000000, 8 + 2, //F
|
|
0b1111110100000000, 8 + 2, //G
|
|
0b1010101010000000, 9 + 2, //H
|
|
0b1111111000000000, 7 + 2, //I
|
|
0b1111111010000000, 9 + 2, //J
|
|
0b1011111010000000, 9 + 2, //K
|
|
0b1101011100000000, 8 + 2, //L
|
|
0b1011101100000000, 8 + 2, //M
|
|
0b1101110100000000, 8 + 2, //N
|
|
0b1010101100000000, 8 + 2, //O
|
|
0b1101010100000000, 8 + 2, //P
|
|
0b1110111010000000, 9 + 2, //Q
|
|
0b1010111100000000, 8 + 2, //R
|
|
0b1101111000000000, 7 + 2, //S
|
|
0b1101101000000000, 7 + 2, //T
|
|
0b1010101110000000, 9 + 2, //U
|
|
0b1101101010000000, 9 + 2, //V
|
|
0b1010111010000000, 9 + 2, //W
|
|
0b1011101010000000, 9 + 2, //X
|
|
0b1011110110000000, 9 + 2, //Y
|
|
0b1010101101000000, 10 + 2, //Z
|
|
0b1111101110000000, 9 + 2, //[
|
|
0b1111011110000000, 9 + 2, //
|
|
0b1111110110000000, 9 + 2, //]
|
|
0b1010111111000000, 10 + 2, //^
|
|
0b1011011010000000, 9 + 2, //_
|
|
0b1011011111000000, 10 + 2, //'
|
|
0b1011000000000000, 4 + 2, //a
|
|
0b1011111000000000, 7 + 2, //b
|
|
0b1011110000000000, 6 + 2, //c
|
|
0b1011010000000000, 6 + 2, //d
|
|
0b1100000000000000, 2 + 2, //e
|
|
0b1111010000000000, 6 + 2, //f
|
|
0b1011011000000000, 7 + 2, //g
|
|
0b1010110000000000, 6 + 2, //h
|
|
0b1101000000000000, 4 + 2, //i
|
|
0b1111010110000000, 9 + 2, //j
|
|
0b1011111100000000, 8 + 2, //k
|
|
0b1101100000000000, 5 + 2, //l
|
|
0b1110110000000000, 6 + 2, //m
|
|
0b1111000000000000, 4 + 2, //n
|
|
0b1110000000000000, 3 + 2, //o
|
|
0b1111110000000000, 6 + 2, //p
|
|
0b1101111110000000, 9 + 2, //q
|
|
0b1010100000000000, 5 + 2, //r
|
|
0b1011100000000000, 5 + 2, //s
|
|
0b1010000000000000, 3 + 2, //t
|
|
0b1101110000000000, 6 + 2, //u
|
|
0b1111011000000000, 7 + 2, //v
|
|
0b1101011000000000, 7 + 2, //w
|
|
0b1101111100000000, 8 + 2, //x
|
|
0b1011101000000000, 7 + 2, //y
|
|
0b1110101010000000, 9 + 2, //z
|
|
};
|
|
|
|
static const uint16_t VARICODE_SPECIAL[] PROGMEM = {
|
|
0b1111100000000000, 5 + 2, //CR
|
|
0b0000000000000000, 16, //sync
|
|
0b0000000000000000, 4, //tail
|
|
};
|
|
|
|
#define CNT_CARRIER sizeof(tbl_Carrier)
|
|
static const int8_t tbl_Carrier[] PROGMEM = {
|
|
0,6,11,14,15,14,11,6,0,-6,-11,-14,-15,-14,-11,-6
|
|
};
|
|
|
|
#define S_MAX 128
|
|
#define CNT_SHAPE sizeof(tbl_Shape)
|
|
static const int8_t tbl_Shape[] PROGMEM = {
|
|
-127,-127,-127,-127,-127,-127,-126,-126,-126,-126,-125,-125,-125,-124,-124,-123,
|
|
-123,-122,-122,-121,-120,-120,-119,-118,-117,-117,-116,-115,-114,-113,-112,-111,
|
|
-110,-109,-108,-107,-106,-104,-103,-102,-101,-99,-98,-97,-95,-94,-93,-91,-90,-88,
|
|
-87,-85,-84,-82,-81,-79,-77,-76,-74,-72,-71,-69,-67,-65,-64,-62,-60,-58,-56,-54,
|
|
-52,-51,-49,-47,-45,-43,-41,-39,-37,-35,-33,-31,-29,-27,-25,-23,-21,-19,-17,-15,
|
|
-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,
|
|
45,47,49,51,52,54,56,58,60,62,63,65,67,69,71,72,74,76,77,79,81,82,84,85,87,88,90,
|
|
91,93,94,95,97,98,99,101,102,103,104,106,107,108,109,110,111,112,113,114,115,116,
|
|
117,117,118,119,120,120,121,122,122,123,123,124,124,125,125,125,126,126,126,126,
|
|
127,127,127,127,127
|
|
};
|
|
|
|
|
|
static uint8_t BPSK_Speed = 1;
|
|
|
|
static volatile uint8_t BPSK_Phase = 0;
|
|
static volatile int8_t BPSK_next_DA;
|
|
static volatile enum { BPSK_OFF, BPSK_IDLE, BPSK_SEND_READY, BPSK_SEND_WAIT } BPSK_state = BPSK_OFF;
|
|
|
|
|
|
ISR(TIMER0_COMPA_vect)
|
|
{
|
|
static uint8_t j;
|
|
|
|
switch (BPSK_state) {
|
|
case BPSK_OFF:
|
|
set_DA(0x10);
|
|
break;
|
|
|
|
case BPSK_SEND_WAIT:
|
|
j = 0;
|
|
case BPSK_IDLE:
|
|
BPSK_state = BPSK_IDLE;
|
|
int8_t temp = (int8_t)(BPSK_Phase ? -pgm_read_byte(&tbl_Carrier[j % CNT_CARRIER]) : pgm_read_byte(&tbl_Carrier[j % CNT_CARRIER]));
|
|
temp = (int16_t)(temp) * (int8_t)pgm_read_byte(&tbl_Shape[j * BPSK_Speed]) / S_MAX;
|
|
set_DA((temp ^ 0x10) & 0x1F);
|
|
j++;
|
|
if (j >= CNT_SHAPE / BPSK_Speed) {
|
|
BPSK_Phase = !BPSK_Phase;
|
|
BPSK_state = BPSK_SEND_WAIT;
|
|
}
|
|
break;
|
|
|
|
case BPSK_SEND_READY:
|
|
set_DA((BPSK_next_DA ^ 0x10) & 0x1F);
|
|
BPSK_state = BPSK_SEND_WAIT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void BPSK_SigCarrier(void)
|
|
{
|
|
for (uint8_t j = 0; j < CNT_SHAPE / BPSK_Speed; j++) {
|
|
do {} while (BPSK_state != BPSK_SEND_WAIT && BPSK_state != BPSK_OFF);
|
|
int8_t temp = BPSK_Phase ? -pgm_read_byte(&tbl_Carrier[j % CNT_CARRIER]) : pgm_read_byte(&tbl_Carrier[j % CNT_CARRIER]);
|
|
BPSK_next_DA = -temp;
|
|
BPSK_state = BPSK_SEND_READY;
|
|
}
|
|
}
|
|
|
|
|
|
static void BPSK_SigReverse(uint8_t start, uint8_t stop)
|
|
{
|
|
for (uint8_t j = start / BPSK_Speed; j < stop / BPSK_Speed; j++) {
|
|
do {} while (BPSK_state != BPSK_SEND_WAIT && BPSK_state != BPSK_OFF);
|
|
int8_t temp = BPSK_Phase ? -pgm_read_byte(&tbl_Carrier[j % CNT_CARRIER]) : pgm_read_byte(&tbl_Carrier[j % CNT_CARRIER]);
|
|
BPSK_next_DA = (int16_t)(temp) * (int8_t)pgm_read_byte(&tbl_Shape[j * BPSK_Speed]) / S_MAX;
|
|
BPSK_state = BPSK_SEND_READY;
|
|
}
|
|
BPSK_Phase = !BPSK_Phase;
|
|
}
|
|
|
|
|
|
void BPSK_SigStart(void)
|
|
{
|
|
BPSK_Phase = 0;
|
|
BPSK_SigReverse(CNT_SHAPE/2, CNT_SHAPE);
|
|
}
|
|
|
|
|
|
void BPSK_SigStop(void)
|
|
{
|
|
BPSK_SigReverse(0, CNT_SHAPE/2);
|
|
BPSK_state = BPSK_OFF;
|
|
}
|
|
|
|
|
|
bool BPSK_SendChar(uint8_t Byte)
|
|
{
|
|
// Get Pointer to Table
|
|
const uint16_t *p;
|
|
if (Byte >= ' ' && Byte <= 'z') p = VARICODE_CHARSET + 2 * (Byte - ' ');
|
|
else if (Byte == '\r' || Byte == '\n') p = VARICODE_SPECIAL+0; // CR
|
|
else if (Byte == '\f') p = VARICODE_SPECIAL+2; // idle sync - form feed
|
|
else if (Byte == '\t') p = VARICODE_SPECIAL+4; // tail - horizontal tab
|
|
else return true;
|
|
|
|
uint16_t DataByte = pgm_read_word(p++);
|
|
uint16_t DataLength = pgm_read_word(p++);
|
|
for (uint8_t i = 0; i < DataLength; i++) {
|
|
if (DataByte & 0x8000) BPSK_SigCarrier();
|
|
else BPSK_SigReverse(0, CNT_SHAPE);
|
|
DataByte <<= 1;
|
|
}
|
|
return SupervisorTask();
|
|
}
|
|
|
|
|
|
bool BPSK_SendBuffer(const char *p)
|
|
{
|
|
bool ok = true;
|
|
while (*p && ok) {
|
|
ok = BPSK_SendChar(*p++);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
|
|
void BPSK_SetSpeedDiv(uint8_t i)
|
|
{
|
|
BPSK_Speed = i;
|
|
}
|
|
|
|
|
|
void BPSK_Init(void)
|
|
{
|
|
// DA port output init
|
|
DDRD |= _BV(DA0+0) | _BV(DA0+1) | _BV(DA0+2) | _BV(DA0+3) | _BV(DA0+4);
|
|
|
|
// TIMER0 init
|
|
TCNT0 = 0;
|
|
OCR0A = 76; // ((36864000/8) / (76+1)) / (CNT_SHAPE*CNT_CARRIER) = 31.17Bd (should be 31.25Bd)
|
|
TCCR0A = _BV(WGM01);
|
|
TCCR0B = _BV(CS01); // fc/8, CTC
|
|
TIMSK0 = _BV(OCIE0A);
|
|
}
|