
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!
main.cpp@0:9e9ede3ac523, 2020-08-29 (annotated)
- Committer:
- Jamie Smith
- Date:
- Sat Aug 29 03:06:11 2020 -0700
- Revision:
- 0:9e9ede3ac523
Initial commit
Who changed what in which revision?
User | Revision | Line number | New 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 | } |