Friday, 10 March 2017

BASIC Tech Group - MyNews 30 - AD9850 RTTY Beacon

To round off this session on generating various digital transmissions with the AD9850 synthesiser and the Arduino, here is the RTTY one.

Beacon Tx

IMG 0812

SDR RX

Screen Shot 2017 03 10 at 12 25 42

Received signals, using MacOS MultiMode Cooca software

Screen Shot 2017 03 10 at 12 26 38

And here's the code

// BCN_RTTY Beacon for RTTY
// V1.1 9-3-17
// thanks to F0GOJ for some of the code
// AD9850
// W_CLK 8
// FQ_UD 9
// DATA 10
// RESET 11
// LCD I2C bus (16x2)
// SDA = A4
// SCL = A5

// ADS9850, LCD and Rotary Encoder libraries
#include "ADS9850.h"
#include "LiquidCrystal_I2C.h"

// AD9850 pins
#define W_CLK 8
#define FQ_UD 9
#define DATA 10
#define RESET 11

// chose address of 0x27 or 0x3F for LCD
//#define LCDADDR 0x27
#define LCDADDR 0x3F
#define LCDCOLS 16
#define LCDROWS 2

// baudot varicode in b4-b0 (sent b0->b4)
char rttyVaricode[59] = {
  4, 22, 17, 5, 18, 0, 11, 26, 30, 9,
  0, 0, 6, 24, 7, 23, 13, 29, 25, 16,
  10, 1, 21, 28, 12, 3, 14, 15, 0, 0,
  0, 19, 0, 24, 19, 14, 18, 16, 22, 11,
  5, 12, 26, 30, 9, 7, 6, 3, 13, 29,
  10, 20, 1, 28, 15, 25, 23, 21, 17
};

#define FIGS 27
#define LTRS 31

// beacon message to send (u.c.)
char msg[] = "RTTY BCN M0IFA";

// freq in Hz and cHz
double freqHz = 7080000;                              // frequency Hz
double freqChz = 0;                                   // sub freuency cHz

// repeat time (ms)
unsigned long repeat = 2000;

// ads (analog-output digital synthesiser) object
ADS9850 ads;

// lcd object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);

void setup() {
  // init LCD
  lcd.begin();

  //init AD9850
  ads.begin(W_CLK, FQ_UD, DATA, RESET);         // initialise synthesiser, pins

  dispMsg(0, 0, "RTTY");
  dispFreq(5, 0, freqHz, freqChz, 0); // display FREQ xxxxxx.xx kHz col 5 row 0
  dispMsg(0, 1, msg); // out msg
}

void loop() {
  // send message at frequency
  sendMsg(freqHz, freqChz, msg);

  delay(repeat); // repeat
}

void sendMsg(double fHz, double fChz, char *m) {
  bool figsLtrs;                        // FIGS/LTRS toggle
  char c;

  figsLtrs = 1;                         // start in letter mode
  
  c = *m++;
  while ( c != '\0') {                 // EOM?
    c = toupper((int)c);               // get char, uppercase
    if (c == 10) {                     // Line Feed 8
      rttyTxByte(fHz, fChz, 8);
    }
    else if (c == 13) {                // Carriage Return 2
      rttyTxByte(fHz, fChz, 2);
    }
    else if (c == 32) {
      rttyTxByte(fHz, fChz, 4);
    }
    else if (c > ' ' && c <= 'Z' ) {   // non-baudot chars sent as blanks 00000
      c = c - ' ';                     // c index 0-58
      
      if (c <  33) {
        if (figsLtrs == 1) {           // if LTRS
          figsLtrs = 0;                // toggle to FIGS
          rttyTxByte(fHz, fChz, FIGS); // send 27
        }
      }
      else if (figsLtrs == 0) {        // if FIGS
        figsLtrs = 1;                  // toggle to LTRS
        rttyTxByte(fHz, fChz, LTRS);   // send 31
      }
      
      rttyTxByte(fHz, fChz, rttyVaricode[c]);  // Send the 5 bits word
    }
    c = *m++;  // Next character in string
  }
  ads.down();
}

// send at fHz, fChz, rttyVaricode s(ymb nnnnn
void rttyTxByte(long fHzSymb, long fChzSymb, char symb) {
  int bits, val;

  // build the byte to send
  symb = (symb << 2) + 3;                     // shift two left, add B00000011, makes B0nnnnn11

  for (bits = 7; bits >= 0; bits--) {          // MSB first, b7 -> b0
    val = bitRead(symb, bits); // Read 1 bit
    ads.setFreq(fHzSymb + (170 * val), fChzSymb, 0); // Let's transmit (bit 1 is 170Hz shifted up)
    delay(22); // Gives the baud rate, 22ms per bit
  }
  delay(110);                                  // intersumbol pause
}

// display freq at c)ol, r)ow, f (cHz), d decimal places
void dispFreq(uint8_t c, uint8_t r, float f, float cf, uint8_t d) {
  lcd.setCursor(c, r);
  lcd.print((f + cf / 100.0), d);
  lcd.print("Hz ");
}

// display msg *m at c)ol, r)ow
void dispMsg(uint8_t c, uint8_t r, char *m) {
  lcd.setCursor(c, r);
  lcd.print(m);
}
I am not too happy with this code as it seems VERY timing sensitive.

No comments: