Program to transmit strings as Morse code using the CC1200. Useful for amateur radio projects!

Dependencies:   CC1200 SerialStream

This project contains a class (CC1200Morse) to convert text into Morse code that can be transmitted over a CC1200 radio IC, and a test program for this class. This is useful for amateur radio projects which need to broadcast their call sign in order to operate legally, and just a cool demonstration of the flexibility of the CC1200.

How It Works

First, the input string is translated into Morse code using a conversion table. Nearly all ASCII characters contained in the Morse character set are supported. For example, the string "ha" would become " ···· · −". Then, the Morse code is converted into one and zero bits according to the standard Morse timing rules. " ···· · −" then becomes 10101010 00010111 000". Finally, these bits are enqueued into the radio's packet buffer and transmitted. The CC1200 is configured into OOK (On-Off Keying) mode, so a 1 bit is modulated as full transmit power, and a 0 bit is modulated as zero transmit power. The transmission will occur at the speed (specified as the time unit, or the length of a dot) that you configure. Note that the CC1200 does the transmission in the background, so your processor can enqueue up to 128 bytes worth of Morse and then go do other things while it transmits at a human readable speed. You can't enqueue two packets at a time though.

Demo Video

Hardware Setup

This program assumes that a CC1200 radio is connected to your processor's SPI bus. The CC1200's circuit board must be configured for the 900MHz band (though you could also change the frequency in the code to match your boards).

I used a custom circuit board for my testing, but you should also be able to use an Mbed board connected to an CC1200 eval kit to run the program. Make sure to edit the #defines at the top of main.cpp to match the pins that your equipment is plugged into!

Note: License free transmission on the 900MHz band is only legal in Region 2 countries (North and South America). Make sure to follow all local regulations covering radio transmissions!

Committer:
Jamie Smith
Date:
Sat Aug 29 03:06:11 2020 -0700
Revision:
0:9e9ede3ac523
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jamie Smith 0:9e9ede3ac523 1 //
Jamie Smith 0:9e9ede3ac523 2 // Test program for the CC1200 morse code example
Jamie Smith 0:9e9ede3ac523 3 //
Jamie Smith 0:9e9ede3ac523 4
Jamie Smith 0:9e9ede3ac523 5 #include <mbed.h>
Jamie Smith 0:9e9ede3ac523 6 #include <SerialStream.h>
Jamie Smith 0:9e9ede3ac523 7
Jamie Smith 0:9e9ede3ac523 8 #include <CC1200.h>
Jamie Smith 0:9e9ede3ac523 9 #include <cinttypes>
Jamie Smith 0:9e9ede3ac523 10
Jamie Smith 0:9e9ede3ac523 11 #include "CC1200Morse.h"
Jamie Smith 0:9e9ede3ac523 12
Jamie Smith 0:9e9ede3ac523 13 #define PIN_SPI_MOSI P0_9
Jamie Smith 0:9e9ede3ac523 14 #define PIN_SPI_MISO P0_8
Jamie Smith 0:9e9ede3ac523 15 #define PIN_SPI_SCLK P0_7
Jamie Smith 0:9e9ede3ac523 16
Jamie Smith 0:9e9ede3ac523 17 #define PIN_CC1200_CS P0_6
Jamie Smith 0:9e9ede3ac523 18 #define PIN_CC1200_RST P0_29
Jamie Smith 0:9e9ede3ac523 19
Jamie Smith 0:9e9ede3ac523 20 BufferedSerial serial(USBTX, USBRX, 115200);
Jamie Smith 0:9e9ede3ac523 21 SerialStream<BufferedSerial> pc(serial);
Jamie Smith 0:9e9ede3ac523 22
Jamie Smith 0:9e9ede3ac523 23 CC1200 radio(PIN_SPI_MOSI, PIN_SPI_MISO, PIN_SPI_SCLK, PIN_CC1200_CS, PIN_CC1200_RST, &pc);
Jamie Smith 0:9e9ede3ac523 24
Jamie Smith 0:9e9ede3ac523 25 void testMorseCodeConversion()
Jamie Smith 0:9e9ede3ac523 26 {
Jamie Smith 0:9e9ede3ac523 27 radio.begin();
Jamie Smith 0:9e9ede3ac523 28 CC1200Morse morseConverter(radio);
Jamie Smith 0:9e9ede3ac523 29
Jamie Smith 0:9e9ede3ac523 30 const size_t bufferLen = 64;
Jamie Smith 0:9e9ede3ac523 31 uint8_t outputBuffer[bufferLen];
Jamie Smith 0:9e9ede3ac523 32
Jamie Smith 0:9e9ede3ac523 33 char const * testString = "eternal silence@54!";
Jamie Smith 0:9e9ede3ac523 34
Jamie Smith 0:9e9ede3ac523 35 CC1200Morse::EncodedMorse morse = morseConverter.convertToMorse(testString, outputBuffer, bufferLen);
Jamie Smith 0:9e9ede3ac523 36
Jamie Smith 0:9e9ede3ac523 37 if(!morse.valid)
Jamie Smith 0:9e9ede3ac523 38 {
Jamie Smith 0:9e9ede3ac523 39 pc.printf("Morse is invalid\n");
Jamie Smith 0:9e9ede3ac523 40 }
Jamie Smith 0:9e9ede3ac523 41 else
Jamie Smith 0:9e9ede3ac523 42 {
Jamie Smith 0:9e9ede3ac523 43 pc.printf("Output %zu bytes:", morse.totalLength);
Jamie Smith 0:9e9ede3ac523 44 for(size_t index = 0; index < morse.totalLength; ++index)
Jamie Smith 0:9e9ede3ac523 45 {
Jamie Smith 0:9e9ede3ac523 46 pc.printf(" %" PRIx8, outputBuffer[index]);
Jamie Smith 0:9e9ede3ac523 47 }
Jamie Smith 0:9e9ede3ac523 48 pc.printf("\n");
Jamie Smith 0:9e9ede3ac523 49 }
Jamie Smith 0:9e9ede3ac523 50 }
Jamie Smith 0:9e9ede3ac523 51
Jamie Smith 0:9e9ede3ac523 52 /**
Jamie Smith 0:9e9ede3ac523 53 * Test sending some arbitrary bytes as OOK modulated data.
Jamie Smith 0:9e9ede3ac523 54 */
Jamie Smith 0:9e9ede3ac523 55 void testMorseByteTransmission()
Jamie Smith 0:9e9ede3ac523 56 {
Jamie Smith 0:9e9ede3ac523 57 const float timeUnit = 0.1f;
Jamie Smith 0:9e9ede3ac523 58
Jamie Smith 0:9e9ede3ac523 59 radio.begin();
Jamie Smith 0:9e9ede3ac523 60 CC1200Morse morseConverter(radio);
Jamie Smith 0:9e9ede3ac523 61 morseConverter.configure(CC1200::Band::BAND_820_960MHz, 915e6f, timeUnit, 14.5);
Jamie Smith 0:9e9ede3ac523 62
Jamie Smith 0:9e9ede3ac523 63 const char testString[] = "\xFF\x0E\xFF";
Jamie Smith 0:9e9ede3ac523 64 const size_t testStringLength = 3;
Jamie Smith 0:9e9ede3ac523 65
Jamie Smith 0:9e9ede3ac523 66 // manually create morse code data
Jamie Smith 0:9e9ede3ac523 67 CC1200Morse::EncodedMorse morse;
Jamie Smith 0:9e9ede3ac523 68 morse.valid = true;
Jamie Smith 0:9e9ede3ac523 69 morse.buffer = reinterpret_cast<uint8_t const *>(testString);
Jamie Smith 0:9e9ede3ac523 70 morse.byteLen = testStringLength;
Jamie Smith 0:9e9ede3ac523 71 morse.bitLen = 0;
Jamie Smith 0:9e9ede3ac523 72 morse.totalLength = testStringLength;
Jamie Smith 0:9e9ede3ac523 73
Jamie Smith 0:9e9ede3ac523 74 morseConverter.transmit(morse);
Jamie Smith 0:9e9ede3ac523 75
Jamie Smith 0:9e9ede3ac523 76 Timer messageTimer;
Jamie Smith 0:9e9ede3ac523 77 messageTimer.start();
Jamie Smith 0:9e9ede3ac523 78
Jamie Smith 0:9e9ede3ac523 79 radio.setOnTransmitState(CC1200::State::IDLE);
Jamie Smith 0:9e9ede3ac523 80 radio.startTX();
Jamie Smith 0:9e9ede3ac523 81
Jamie Smith 0:9e9ede3ac523 82 // wait until all bytes have been transmitted.
Jamie Smith 0:9e9ede3ac523 83 // Note: the FIFO length is 0 when the last byte is being sent, so we can't just check the FIFO length
Jamie Smith 0:9e9ede3ac523 84 while(radio.getTXFIFOLen() > 0 || radio.getState() != CC1200::State::IDLE)
Jamie Smith 0:9e9ede3ac523 85 {
Jamie Smith 0:9e9ede3ac523 86 pc.printf("TX FIFO size: %zu\n", radio.getTXFIFOLen());
Jamie Smith 0:9e9ede3ac523 87 ThisThread::sleep_for(std::chrono::milliseconds(static_cast<uint32_t>(timeUnit * 1000)));
Jamie Smith 0:9e9ede3ac523 88 //ThisThread::sleep_for(1ms);
Jamie Smith 0:9e9ede3ac523 89 }
Jamie Smith 0:9e9ede3ac523 90
Jamie Smith 0:9e9ede3ac523 91 float timeSeconds = std::chrono::duration_cast<std::chrono::duration<float>>(messageTimer.elapsed_time()).count();
Jamie Smith 0:9e9ede3ac523 92 size_t numBits = ((morse.byteLen * 8) + morse.bitLen);
Jamie Smith 0:9e9ede3ac523 93 float effectiveBitrate = numBits / timeSeconds;
Jamie Smith 0:9e9ede3ac523 94
Jamie Smith 0:9e9ede3ac523 95 pc.printf("Sent %zu bits in %.03f s, effective bitrate = %.03f sps\n", numBits, timeSeconds, effectiveBitrate);
Jamie Smith 0:9e9ede3ac523 96
Jamie Smith 0:9e9ede3ac523 97 }
Jamie Smith 0:9e9ede3ac523 98
Jamie Smith 0:9e9ede3ac523 99 void testMorseCodeTransmission()
Jamie Smith 0:9e9ede3ac523 100 {
Jamie Smith 0:9e9ede3ac523 101 const float timeUnit = 0.1f;
Jamie Smith 0:9e9ede3ac523 102
Jamie Smith 0:9e9ede3ac523 103 radio.begin();
Jamie Smith 0:9e9ede3ac523 104 CC1200Morse morseConverter(radio);
Jamie Smith 0:9e9ede3ac523 105 morseConverter.configure(CC1200::Band::BAND_820_960MHz, 915e6f, timeUnit, 0);
Jamie Smith 0:9e9ede3ac523 106
Jamie Smith 0:9e9ede3ac523 107 const size_t bufferLen = 64;
Jamie Smith 0:9e9ede3ac523 108 uint8_t outputBuffer[bufferLen];
Jamie Smith 0:9e9ede3ac523 109
Jamie Smith 0:9e9ede3ac523 110 char const * testString = "eternal silence@54!";
Jamie Smith 0:9e9ede3ac523 111
Jamie Smith 0:9e9ede3ac523 112 CC1200Morse::EncodedMorse morse = morseConverter.convertToMorse(testString, outputBuffer, bufferLen);
Jamie Smith 0:9e9ede3ac523 113
Jamie Smith 0:9e9ede3ac523 114 if(!morse.valid)
Jamie Smith 0:9e9ede3ac523 115 {
Jamie Smith 0:9e9ede3ac523 116 pc.printf("Morse is invalid\n");
Jamie Smith 0:9e9ede3ac523 117 }
Jamie Smith 0:9e9ede3ac523 118
Jamie Smith 0:9e9ede3ac523 119 morseConverter.transmit(morse);
Jamie Smith 0:9e9ede3ac523 120
Jamie Smith 0:9e9ede3ac523 121 radio.setOnTransmitState(CC1200::State::IDLE);
Jamie Smith 0:9e9ede3ac523 122 radio.startTX();
Jamie Smith 0:9e9ede3ac523 123
Jamie Smith 0:9e9ede3ac523 124 // wait until all bytes have been transmitted.
Jamie Smith 0:9e9ede3ac523 125 // Note: the FIFO length is 0 when the last byte is being sent, so we can't just check the FIFO length
Jamie Smith 0:9e9ede3ac523 126 while(radio.getTXFIFOLen() > 0 || radio.getState() != CC1200::State::IDLE)
Jamie Smith 0:9e9ede3ac523 127 {
Jamie Smith 0:9e9ede3ac523 128 pc.printf("TX FIFO size: %zu\n", radio.getTXFIFOLen());
Jamie Smith 0:9e9ede3ac523 129 ThisThread::sleep_for(std::chrono::milliseconds(static_cast<uint32_t>(timeUnit * 1000)));
Jamie Smith 0:9e9ede3ac523 130 //ThisThread::sleep_for(1ms);
Jamie Smith 0:9e9ede3ac523 131 }
Jamie Smith 0:9e9ede3ac523 132 }
Jamie Smith 0:9e9ede3ac523 133
Jamie Smith 0:9e9ede3ac523 134 int main()
Jamie Smith 0:9e9ede3ac523 135 {
Jamie Smith 0:9e9ede3ac523 136 pc.printf("\nCC1200 Morse Test Suite:\n");
Jamie Smith 0:9e9ede3ac523 137
Jamie Smith 0:9e9ede3ac523 138 while(1){
Jamie Smith 0:9e9ede3ac523 139 int test=-1;
Jamie Smith 0:9e9ede3ac523 140 //MENU. ADD AN OPTION FOR EACH TEST.
Jamie Smith 0:9e9ede3ac523 141 pc.printf("Select a test: \n");
Jamie Smith 0:9e9ede3ac523 142 pc.printf("1. Test converting to Morse code\n");
Jamie Smith 0:9e9ede3ac523 143 pc.printf("2. Test transmitting bytes as Morse\n");
Jamie Smith 0:9e9ede3ac523 144 pc.printf("3. Test transmitting string of Morse\n");
Jamie Smith 0:9e9ede3ac523 145
Jamie Smith 0:9e9ede3ac523 146 pc.scanf("%d", &test);
Jamie Smith 0:9e9ede3ac523 147 printf("Running test %d:\n\n", test);
Jamie Smith 0:9e9ede3ac523 148 //SWITCH. ADD A CASE FOR EACH TEST.
Jamie Smith 0:9e9ede3ac523 149 switch(test) {
Jamie Smith 0:9e9ede3ac523 150 case 1: testMorseCodeConversion(); break;
Jamie Smith 0:9e9ede3ac523 151 case 2: testMorseByteTransmission(); break;
Jamie Smith 0:9e9ede3ac523 152 case 3: testMorseCodeTransmission(); break;
Jamie Smith 0:9e9ede3ac523 153 default: pc.printf("Invalid test number. Please run again.\n"); continue;
Jamie Smith 0:9e9ede3ac523 154 }
Jamie Smith 0:9e9ede3ac523 155 pc.printf("done.\r\n");
Jamie Smith 0:9e9ede3ac523 156 }
Jamie Smith 0:9e9ede3ac523 157
Jamie Smith 0:9e9ede3ac523 158 return 0;
Jamie Smith 0:9e9ede3ac523 159
Jamie Smith 0:9e9ede3ac523 160 }