From 67719ea8b536b3dea9e5a3f8cca3280b7dfccd27 Mon Sep 17 00:00:00 2001 From: Richard Meadows Date: Fri, 6 Mar 2015 19:30:33 +0000 Subject: [PATCH] More re-orginisation to telemetry etc, added working RSID demo run --- firmware/Peripherals.md | 2 +- firmware/inc/contestia.h | 2 + firmware/inc/hw_config.h | 1 + firmware/inc/rsid.h | 184 +++++++++++++++++++++++++++++++++++++++ firmware/inc/rtty.h | 7 ++ firmware/inc/si_trx.h | 4 +- firmware/inc/telemetry.h | 12 ++- firmware/src/contestia.c | 12 ++- firmware/src/main.c | 11 ++- firmware/src/rsid.c | 174 ++++++++++++++++++++++++++++++++++++ firmware/src/rtty.c | 14 +-- firmware/src/si_trx.c | 81 +++++++++-------- firmware/src/telemetry.c | 135 ++++++++++++++++++++++++++-- 13 files changed, 581 insertions(+), 58 deletions(-) create mode 100644 firmware/inc/rsid.h create mode 100644 firmware/src/rsid.c diff --git a/firmware/Peripherals.md b/firmware/Peripherals.md index 1c29107..68b1851 100644 --- a/firmware/Peripherals.md +++ b/firmware/Peripherals.md @@ -3,7 +3,7 @@ | Type | Peripheral | Function | Notes | --- | --- | --- | --- |*GLCK*| -||gclk0|main| +||gclk0|main|2MHz?? |*TC*|| ||tc0| ||tc1| diff --git a/firmware/inc/contestia.h b/firmware/inc/contestia.h index cac6a31..f34e2bf 100644 --- a/firmware/inc/contestia.h +++ b/firmware/inc/contestia.h @@ -30,6 +30,8 @@ */ #define CONTESTIA_NUMBER_OF_TONES 32 #define CONTESTIA_CHARACTERS_PER_BLOCK 5 +#define CONTESTIA_CHANNEL_SPACING 4 // Corresponds to 31.22 Hz +#define CONTESTIA_SYMBOL_RATE 31.25 void contestia_start(char* data); diff --git a/firmware/inc/hw_config.h b/firmware/inc/hw_config.h index 82726c4..64a7e33 100644 --- a/firmware/inc/hw_config.h +++ b/firmware/inc/hw_config.h @@ -114,6 +114,7 @@ #define SI406X_SDN_PIN PIN_PA16 #define SI406X_GPIO0_PIN PIN_PA27 #define SI406X_GPIO1_PIN PIN_PA25 +#define SI406X_GPIO1_PINMUX PINMUX_PA25F_TC5_WO1 #define SI406X_TCXO_PIN PIN_PA17 #define SI406X_TCXO_PINMUX PINMUX_PA17H_GCLK_IO3 diff --git a/firmware/inc/rsid.h b/firmware/inc/rsid.h new file mode 100644 index 0000000..7884e5f --- /dev/null +++ b/firmware/inc/rsid.h @@ -0,0 +1,184 @@ +/* + * Reed-Solomon Identification (RSID) functions + * Copyright (C) 2014 Richard Meadows + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef RSID_H +#define RSID_H + +#define RSID_NSYMBOLS 15 +#define RSID_SYMBOL_RATE (11025.0 / 1024.0) + +/** + * The RSID codes for all supported modes. + * + * From http://www.w1hkj.com/RSID_description.html + */ +typedef enum rsid_code_t { + RSID_BPSK31 = 1, + RSID_QPSK31 = 110, + RSID_BPSK63 = 2, + RSID_QPSK63 = 3, + RSID_BPSK125 = 4, + RSID_QPSK125 = 5, + RSID_BPSK250 = 126, + RSID_QPSK250 = 127, + RSID_BPSK500 = 173, + RSID_PSK125R = 183, + RSID_PSK250R = 186, + RSID_PSK500R = 187, + RSID_PSKFEC31 = 7, + RSID_PSK10 = 8, + RSID_MT63_500_LG = 9, + RSID_MT63_500_ST = 10, + RSID_MT63_500_VST = 11, + RSID_MT63_1000_LG = 12, + RSID_MT63_1000_ST = 13, + RSID_MT63_1000_VST = 14, + RSID_MT63_2000_LG = 15, + RSID_MT63_2000_ST = 17, + RSID_MT63_2000_VST = 18, + RSID_PSKAM10 = 19, + RSID_PSKAM31 = 20, + RSID_PSKAM50 = 21, + RSID_PSK63F = 22, + RSID_PSK220F = 23, + RSID_CHIP64 = 24, + RSID_CHIP128 = 25, + RSID_CW = 26, + RSID_CCW_OOK_12 = 27, + RSID_CCW_OOK_24 = 28, + RSID_CCW_OOK_48 = 29, + RSID_CCW_FSK_12 = 30, + RSID_CCW_FSK_24 = 31, + RSID_CCW_FSK_48 = 33, + RSID_PACTOR1_FEC = 34, + RSID_PACKET_110 = 113, + RSID_PACKET_300 = 35, + RSID_PACKET_1200 = 36, + RSID_RTTY_ASCII_7 = 37, + RSID_RTTY_ASCII_8 = 38, + RSID_RTTY_45 = 39, + RSID_RTTY_50 = 40, + RSID_RTTY_75 = 41, + RSID_AMTOR_FEC = 42, + RSID_THROB_1 = 43, + RSID_THROB_2 = 44, + RSID_THROB_4 = 45, + RSID_THROBX_1 = 46, + RSID_THROBX_2 = 47, + RSID_THROBX_4 = 146, + RSID_CONTESTIA_4_125 = 204, + RSID_CONTESTIA_4_250 = 55, + RSID_CONTESTIA_4_500 = 54, + RSID_CONTESTIA_4_1000 = 255, + RSID_CONTESTIA_4_2000 = 254, + RSID_CONTESTIA_8_125 = 169, + RSID_CONTESTIA_8_250 = 49, + RSID_CONTESTIA_8_500 = 52, + RSID_CONTESTIA_8_1000 = 117, + RSID_CONTESTIA_8_2000 = 247, + RSID_CONTESTIA_16_500 = 50, + RSID_CONTESTIA_16_1000 = 53, + RSID_CONTESTIA_16_2000 = 259, + RSID_CONTESTIA_32_1000 = 51, + RSID_CONTESTIA_32_2000 = 201, + RSID_CONTESTIA_64_500 = 194, + RSID_CONTESTIA_64_1000 = 193, + RSID_CONTESTIA_64_2000 = 191, + RSID_VOICE = 56, + RSID_MFSK8 = 60, + RSID_MFSK16 = 57, + RSID_MFSK32 = 147, + RSID_MFSK11 = 148, + RSID_MFSK22 = 152, + RSID_RTTYM_8_250 = 61, + RSID_RTTYM_16_500 = 62, + RSID_RTTYM_32_1000 = 63, + RSID_RTTYM_8_500 = 65, + RSID_RTTYM_16_1000 = 66, + RSID_RTTYM_4_500 = 67, + RSID_RTTYM_4_250 = 68, + RSID_RTTYM_8_1000 = 119, + RSID_RTTYM_8_125 = 170, + RSID_OLIVIA_4_125 = 203, + RSID_OLIVIA_4_250 = 75, + RSID_OLIVIA_4_500 = 74, + RSID_OLIVIA_4_1000 = 229, + RSID_OLIVIA_4_2000 = 238, + RSID_OLIVIA_8_125 = 163, + RSID_OLIVIA_8_250 = 69, + RSID_OLIVIA_8_500 = 72, + RSID_OLIVIA_8_1000 = 116, + RSID_OLIVIA_8_2000 = 214, + RSID_OLIVIA_16_500 = 70, + RSID_OLIVIA_16_1000 = 73, + RSID_OLIVIA_16_2000 = 234, + RSID_OLIVIA_32_1000 = 71, + RSID_OLIVIA_32_2000 = 221, + RSID_OLIVIA_64_2000 = 211, + RSID_PAX = 76, + RSID_PAX2 = 77, + RSID_DOMINOF = 78, + RSID_FAX = 79, + RSID_SSTV = 81, + RSID_DOMINOEX_4 = 84, + RSID_DOMINOEX_5 = 85, + RSID_DOMINOEX_8 = 86, + RSID_DOMINOEX_11 = 87, + RSID_DOMINOEX_16 = 88, + RSID_DOMINOEX_22 = 90, + RSID_DOMINOEX_4_FEC = 92, + RSID_DOMINOEX_5_FEC = 93, + RSID_DOMINOEX_8_FEC = 97, + RSID_DOMINOEX_11_FEC = 98, + RSID_DOMINOEX_16_FEC = 99, + RSID_DOMINOEX_22_FEC = 101, + RSID_FELD_HELL = 104, + RSID_PSK_HELL = 105, + RSID_HELL_80 = 106, + RSID_FM_HELL_105 = 107, + RSID_FM_HELL_245 = 108, + RSID_MODE_141A = 114, + RSID_DTMF = 123, + RSID_ALE400 = 125, + RSID_FDMDV = 131, + RSID_JT65_A = 132, + RSID_JT65_B = 134, + RSID_JT65_C = 135, + RSID_THOR_4 = 136, + RSID_THOR_8 = 137, + RSID_THOR_16 = 138, + RSID_THOR_5 = 139, + RSID_THOR_11 = 143, + RSID_THOR_22 = 145, + RSID_CALL_ID = 153, + RSID_PACKET_PSK1200 = 155, + RSID_PACKET_PSK250 = 156, + RSID_PACKET_PSK63 = 159, + RSID_MODE_188_110A_8N1 = 172, +} rsid_code_t; + +void rsid_start(rsid_code_t rsid_code); +uint8_t rsid_tick(void); + +#endif diff --git a/firmware/inc/rtty.h b/firmware/inc/rtty.h index af6ebd1..7221585 100644 --- a/firmware/inc/rtty.h +++ b/firmware/inc/rtty.h @@ -25,6 +25,13 @@ #ifndef RTTY_H #define RTTY_H +/** + * 50 baud RTTY + */ +#define RTTY_BITRATE 50 +#define RTTY_CHANNEL_SPACING 52 // Corresponds to 405.9Hz spacing + + void rtty_start(uint8_t data); uint8_t rtty_tick(void); diff --git a/firmware/inc/si_trx.h b/firmware/inc/si_trx.h index 01f908c..a9a5f2d 100644 --- a/firmware/inc/si_trx.h +++ b/firmware/inc/si_trx.h @@ -29,9 +29,9 @@ float si_trx_get_temperature(void); -void si_trx_on(uint8_t modulation_type, float channel_spacing); +void si_trx_on(uint8_t modulation_type); void si_trx_off(void); -void si_trx_switch_channel(uint8_t channel); +void si_trx_switch_channel(int16_t channel); void si_trx_init(void); diff --git a/firmware/inc/telemetry.h b/firmware/inc/telemetry.h index 2e98008..211cc56 100644 --- a/firmware/inc/telemetry.h +++ b/firmware/inc/telemetry.h @@ -31,7 +31,10 @@ uint16_t crc_checksum(char *string); enum telemetry_t { TELEMETRY_RTTY, - TELEMETRY_CONTESTIA + TELEMETRY_CONTESTIA, + TELEMETRY_RSID, + TELEMETRY_APRS, + TELEMETRY_PIPS, }; /** @@ -49,6 +52,11 @@ int telemetry_start(enum telemetry_t type); int32_t telemetry_get_index(void); void telemetry_set_length(int32_t length); -void timer0_tick_init(float frequency); + +float timer0_tick_init(float frequency); +void timer0_tick_deinit(); +void telemetry_gpio1_pwm_init(void); +void telemetry_gpio1_pwm_duty(float duty_cycle); +void telemetry_gpio1_pwm_deinit(void); #endif /* TELEMETRY_H */ diff --git a/firmware/src/contestia.c b/firmware/src/contestia.c index 1852c69..3fd1d5b 100644 --- a/firmware/src/contestia.c +++ b/firmware/src/contestia.c @@ -22,9 +22,11 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "si_trx.h" +#include "samd20.h" #include "contestia.h" - +#include "telemetry.h" +#include "si_trx.h" +#include "mfsk.h" /** * Current output tones @@ -52,11 +54,15 @@ uint8_t contestia_tick(void) { if (contestia_tone_index < CONTESTIA_NUMBER_OF_TONES) { uint8_t binary_code; uint8_t grey_code; + int16_t channel; /* Output grey code */ binary_code = contestia_tones[contestia_tone_index]; grey_code = (binary_code >> 1) ^ binary_code; - si_trx_switch_channel(grey_code); + + /* Align this to a channel */ + channel = grey_code - (CONTESTIA_NUMBER_OF_TONES / 2); + si_trx_switch_channel(channel * CONTESTIA_CHANNEL_SPACING); } else { return 0; diff --git a/firmware/src/main.c b/firmware/src/main.c index 0707e47..d106f69 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -39,6 +39,7 @@ #include "system/wdt.h" #include "timepulse.h" #include "telemetry.h" +#include "rsid.h" #include "si_trx.h" #include "si_trx_defs.h" #include "analogue.h" @@ -317,11 +318,19 @@ int main(void) led_on(); + while (1) { /* Watchdog */ //wdt_reset_count(); /* Send the next packet */ - output_telemetry_string(); + //output_telemetry_string(); + + telemetry_start_rsid(RSID_CONTESTIA_32_1000); + + /* Sleep Wait */ + while (telemetry_active()) { + system_sleep(); + } } } diff --git a/firmware/src/rsid.c b/firmware/src/rsid.c new file mode 100644 index 0000000..33b5f8c --- /dev/null +++ b/firmware/src/rsid.c @@ -0,0 +1,174 @@ +/* + * Reed-Solomon Identification (RSID) functions + * Copyright (C) 2014 Richard Meadows + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "samd20.h" +#include "rsid.h" +#include "telemetry.h" +#include "si_trx.h" + +/** + * USEFUL RESOURCES ============================================================ + * + * http://www.w1hkj.com/RSID_description.html + * + * dl-fldigi source: + * https://github.com/jamescoxon/dl-fldigi/blob/master/src/rsid/rsid.cxx#L180 + */ + + +/** + * ENCODING + * ============================================================================= + */ + + +/** + * Constants used in the Reed-Solomon encoding + */ +const int rsid_squares[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 0, 2, 4, 6, 8,10,12,14, 9,11,13,15, 1, 3, 5, 7, + 0, 3, 6, 5,12,15,10, 9, 1, 2, 7, 4,13,14,11, 8, + 0, 4, 8,12, 9,13, 1, 5,11,15, 3, 7, 2, 6,10,14, + 0, 5,10,15,13, 8, 7, 2, 3, 6, 9,12,14,11, 4, 1, + 0, 6,12,10, 1, 7,13,11, 2, 4,14, 8, 3, 5,15, 9, + 0, 7,14, 9, 5, 2,11,12,10,13, 4, 3,15, 8, 1, 6, + 0, 8, 9, 1,11, 3, 2,10,15, 7, 6,14, 4,12,13, 5, + 0, 9,11, 2,15, 6, 4,13, 7,14,12, 5, 8, 1, 3,10, + 0,10,13, 7, 3, 9,14, 4, 6,12,11, 1, 5,15, 8, 2, + 0,11,15, 4, 7,12, 8, 3,14, 5, 1,10, 9, 2, 6,13, + 0,12, 1,13, 2,14, 3,15, 4, 8, 5, 9, 6,10, 7,11, + 0,13, 3,14, 6,11, 5, 8,12, 1,15, 2,10, 7, 9, 4, + 0,14, 5,11,10, 4,15, 1,13, 3, 8, 6, 7, 9, 2,12, + 0,15, 7, 8,14, 1, 9, 6, 5,10, 2,13,11, 4,12, 3 +}; +const int rsid_indices[] = { + 2, 4, 8, 9, 11, 15, 7, 14, 5, 10, 13, 3 +}; + +/** + * This function populates the RSID_NSYMBOLS tones needed to transmit + * a RSID for the given rsid_code + */ +void rsid_encode(rsid_code_t rsid_code, int8_t* rsid) +{ + memset(rsid, 0, RSID_NSYMBOLS * sizeof(int8_t)); + + /* Encode the 12-bit code into the first 3 nibbles */ + rsid[0] = (rsid_code >> 8) & 0x0F; + rsid[1] = (rsid_code >> 4) & 0x0F; + rsid[2] = (rsid_code >> 0) & 0x0F; + + + for (int i = 0; i < 12; i++) { + for (int j = RSID_NSYMBOLS - 1; j > 0; j--) { + rsid[j] = rsid[j - 1] ^ rsid_squares[(rsid[j] << 4) + rsid_indices[i]]; + } + + rsid[0] = rsid_squares[(rsid[0] << 4) + rsid_indices[i]]; + } +} + + +/** + * TRANSMISSION + * ============================================================================= + */ + +uint8_t rsid_index = 0xFE; +int8_t rsid[RSID_NSYMBOLS]; + +#define MODEM_TONE_SPACING 7.805 + +#define RSID_LOOKUP +/* Lookup tables designed for a modem tone spacing of 7.805 Hz */ +int8_t rsid_tones_channels[] = { 0, 1, 3, 4, 6, 7, 8, 10, 11 }; +float rsid_tones_deviations[] = { + 0, 0.379, -0.241, 0.138, -0.482, -0.103, 0.276, -0.344, 0.035 }; + + +/** + * Setup a rsid transmission + */ +void rsid_start(rsid_code_t rsid_code) +{ + /* Start transmission */ + rsid_index = 0; + rsid_encode(rsid_code, rsid); +} + +/** + * Outputs one of the 16 RSID tones + */ +void rsid_tone(uint8_t tone) +{ + int16_t channel; + float deviation; + int8_t air_tone = tone - 7; + +#ifdef RSID_LOOKUP + if (air_tone >= 0) { + channel = rsid_tones_channels[air_tone]; + deviation = rsid_tones_deviations[air_tone]; + } else { + channel = -rsid_tones_channels[-air_tone]; + deviation = -rsid_tones_deviations[-air_tone]; + } +#else + /* Calcuate the offset of this tone in channels */ + float tone_offset = ((float)air_tone * (float)RSID_SYMBOL_RATE) / (float)MODEM_TONE_SPACING; + /* Centre channel */ + channel = (int16_t)round(tone_offset); + /* And the deviation from this we need, in channels */ + deviation = tone_offset - (float)channel; +#endif + + float duty_cycle = 0.5 + (deviation / 2); // FSK only provides a marginal improvement in performance! + + si_trx_switch_channel(channel); + telemetry_gpio1_pwm_duty(duty_cycle); +} + +/** + * Called at the rsid baud rate + */ +uint8_t rsid_tick(void) +{ + + if (rsid_index < RSID_NSYMBOLS) { + + /* Transmit this tone */ + rsid_tone(rsid[rsid_index]); + + rsid_index++; + if (rsid_index < RSID_NSYMBOLS) { + return 1; + } + } + + return 0; +} diff --git a/firmware/src/rtty.c b/firmware/src/rtty.c index 60f5517..419778d 100644 --- a/firmware/src/rtty.c +++ b/firmware/src/rtty.c @@ -27,15 +27,19 @@ #include "samd20.h" #include "rtty.h" #include "hw_config.h" -#include "system/port.h" +#include "si_trx.h" + /** * Interface to the physical world. */ -#define RTTY_ACTIVATE() -#define RTTY_DEACTIVATE() -#define RTTY_SET(b) port_pin_set_output_level(SI406X_GPIO1_PIN, !b); -#define RTTY_NEXT() +#define RTTY_CHANNEL_DEVIATION (RTTY_CHANNEL_SPACING / 2) +#define RTTY_CHANNEL(b) (b ? RTTY_CHANNEL_DEVIATION : -RTTY_CHANNEL_DEVIATION) +#define RTTY_SET(b) si_trx_switch_channel(RTTY_CHANNEL(b)) + +//port_pin_set_output_level(SI406X_GPIO1_PIN, !b); + + /** * Formatting 8N2 diff --git a/firmware/src/si_trx.c b/firmware/src/si_trx.c index c0bab3a..087f8cb 100644 --- a/firmware/src/si_trx.c +++ b/firmware/src/si_trx.c @@ -35,6 +35,13 @@ #define VCXO_FREQUENCY SI406X_TCXO_FREQUENCY #define RF_DEVIATION 200 +/** + * The LSB tuning resolution of the frac-n pll as currently + * configured. + */ +float lsb_tuning_resolution = 0; + + /** * Generic SPI Send / Receive */ @@ -223,16 +230,6 @@ static void si_trx_frequency_control_set_divider(uint8_t integer_divider, SI_FREQ_CONTROL_INTE, divider); } -/** - * Sets the step size between adjacent channels, in units of the - * resolution of the frac-n pll synthesiser. - */ -static void si_trx_frequency_control_set_channel_step_size(uint16_t step_size) -{ - _si_trx_set_property_16(SI_PROPERTY_GROUP_FREQ_CONTROL, - SI_FREQ_CONTROL_CHANNEL_STEP_SIZE, - step_size); -} /** * Sets the output divider of the frac-n pll synthesiser */ @@ -243,7 +240,11 @@ static void si_trx_frequency_control_set_band(uint8_t band, uint8_t sy_sel) sy_sel | (band & 0x7)); } /** - * Sets the frequency deviation in the modem + * Sets the modem frequency deviation. This is how much the external + * pin deviates the synthesiser from the centre frequency. In units of + * the resolution of the frac-n pll synthsiser. + * + * This is an unsigned 17-bit value. */ static void si_trx_modem_set_deviation(uint32_t deviation) { @@ -251,6 +252,19 @@ static void si_trx_modem_set_deviation(uint32_t deviation) SI_MODEM_FREQ_DEV, deviation); } +/** + * Sets the modem frequency offset manually. In units of the + * resolution of the frac-n pll synthsiser. + * + * This is a signed 16-bit value. + */ +static void si_trx_modem_set_offset(int16_t offset) +{ + _si_trx_set_property_16(SI_PROPERTY_GROUP_MODEM, + SI_MODEM_FREQ_OFFSET, + offset); +} + /** * Sets the modulation mode */ @@ -283,9 +297,11 @@ static void si_trx_set_tx_pa_duty_cycle(uint8_t pa_duty_cycle) /** - * Set the synthesiser to the given frequency + * Set the synthesiser to the given frequency. + * + * Returns the LSB tuning resolution of the frac-n pll synthesiser. */ -static void si_trx_set_frequency(uint32_t frequency, float channel_spacing) +static float si_trx_set_frequency(uint32_t frequency) { uint8_t outdiv, band, nprescaler; @@ -309,25 +325,19 @@ static void si_trx_set_frequency(uint32_t frequency, float channel_spacing) outdiv = 24; band = SI_MODEM_CLKGEN_FVCO_DIV_24; } - uint32_t f_pfd = nprescaler * VCXO_FREQUENCY / outdiv; + float f_pfd = nprescaler * VCXO_FREQUENCY / outdiv; uint16_t n = ((uint16_t)(frequency / f_pfd)) - 1; - float ratio = (float)frequency / (float)f_pfd; + float ratio = (float)frequency / f_pfd; float rest = ratio - (float)n; uint32_t m = (uint32_t)(rest * (float)(1 << 19)); + /* Check n and m are in valid ranges, halt otherwise */ if (n > 0x7f || m > 0xfffff) while (1); - /* Set the modem deviation, in units of the VCO resolution */ - float dev_ratio = (float)RF_DEVIATION / (float)f_pfd; - uint32_t dev = (uint32_t)(dev_ratio * (float)(1 << 19)); - - /* Set the channel spacing, in units of the VCO resolution */ - float channel_spacing_ratio = channel_spacing / (float)f_pfd; - uint32_t channel_step = (uint32_t)(channel_spacing_ratio * (float)(1 << 19)); /* Set the frac-n PLL output divider */ if (nprescaler == 4) { /* Prescaler */ @@ -336,20 +346,21 @@ static void si_trx_set_frequency(uint32_t frequency, float channel_spacing) si_trx_frequency_control_set_band(band, SI_MODEM_CLKGEN_SY_SEL_1); } + /* Set the frac-n PLL divisior */ si_trx_frequency_control_set_divider(n, m); - /* Set the channel step in the PLL */ - si_trx_frequency_control_set_channel_step_size(channel_step); + /* Set the external pin frequency deviation to the LSB tuning resoultion */ + si_trx_modem_set_deviation(1); - /* Set the frequency deviation in the modem */ - si_trx_modem_set_deviation(dev); + /* Return the LSB tuning resolution of the frac-n pll synthesiser. */ + return f_pfd / (float)(1 << 19); } /** * Resets the transceiver */ -void si_trx_reset(uint8_t modulation_type, float channel_spacing) +void si_trx_reset(uint8_t modulation_type) { _si_trx_sdn_enable(); /* active high shutdown = reset */ @@ -376,7 +387,7 @@ void si_trx_reset(uint8_t modulation_type, float channel_spacing) SI_GPIO_PIN_CFG_GPIO_MODE_INPUT | SI_GPIO_PIN_CFG_PULL_ENABLE, SI_GPIO_PIN_CFG_DRV_STRENGTH_LOW); - si_trx_set_frequency(RADIO_FREQUENCY, channel_spacing); + si_trx_set_frequency(RADIO_FREQUENCY); si_trx_set_tx_power(RADIO_POWER); /* RTTY from GPIO1 */ @@ -391,10 +402,10 @@ void si_trx_reset(uint8_t modulation_type, float channel_spacing) /** * Enables the radio and starts transmitting */ -void si_trx_on(uint8_t modulation_type, float channel_spacing) +void si_trx_on(uint8_t modulation_type) { - si_trx_reset(modulation_type, channel_spacing); - si_trx_start_tx(1); + si_trx_reset(modulation_type); + si_trx_start_tx(0); } /** * Disables the radio and places it in shutdown @@ -404,13 +415,13 @@ void si_trx_off(void) si_trx_state_ready(); _si_trx_sdn_enable(); } + /** - * Switches the transmittion to the specified channel + * Switches the transmission to the specified channel. Signed 16-bit int */ -void si_trx_switch_channel(uint8_t channel) +void si_trx_switch_channel(int16_t channel) { - si_trx_state_ready(); - si_trx_start_tx(channel); + si_trx_modem_set_offset(channel); } /** diff --git a/firmware/src/telemetry.c b/firmware/src/telemetry.c index a45c1ec..5b43675 100644 --- a/firmware/src/telemetry.c +++ b/firmware/src/telemetry.c @@ -29,6 +29,7 @@ #include "telemetry.h" #include "rtty.h" #include "contestia.h" +#include "rsid.h" #include "si_trx.h" #include "si_trx_defs.h" #include "system/gclk.h" @@ -125,17 +126,15 @@ int telemetry_start(enum telemetry_t type) { /* Initialise */ telemetry_type = type; telemetry_index = 0; - - /* Initialise first block / character */ telemetry_string_length = TELEMETRY_STRING_MAX; /* Setup timer tick */ switch(telemetry_type) { case TELEMETRY_CONTESTIA: - timer0_tick_init(31.25); + timer0_tick_init(CONTESTIA_SYMBOL_RATE); break; case TELEMETRY_RTTY: - timer0_tick_init(50); + timer0_tick_init(RTTY_BITRATE); break; } @@ -144,6 +143,32 @@ int telemetry_start(enum telemetry_t type) { return 1; /* Already active */ } } +/** + * Start RSID output. Argument: RSID Data + * + * Returns 0 on success, 1 if already active + */ +int telemetry_start_rsid(rsid_code_t rsid) { + if (!telemetry_active()) { + + /* Initialise */ + telemetry_type = TELEMETRY_RSID; + telemetry_index = 0; + telemetry_string_length = 6; + + /* Start RSID */ + rsid_start(rsid); + + /* Setup timer tick */ + timer0_tick_init(RSID_SYMBOL_RATE); + + return 0; /* Success */ + } else { + return 1; /* Already active */ + } +} + + /** * Returns the index of the current byte being outputted from the buffer */ @@ -185,8 +210,8 @@ void telemetry_tick(void) { case TELEMETRY_CONTESTIA: /* ---- ---- A block mode */ if (!radio_on) { - /* Contestia: We switch channel to modulate */ - si_trx_on(SI_MODEM_MOD_TYPE_CW, 31.25); + /* Contestia: We use the modem offset to modulate */ + si_trx_on(SI_MODEM_MOD_TYPE_CW); radio_on = 1; } @@ -205,8 +230,8 @@ void telemetry_tick(void) { case TELEMETRY_RTTY: /* ---- ---- A character mode */ if (!radio_on) { - /* RTTY Mode: We modulate using the external pin */ - si_trx_on(SI_MODEM_MOD_TYPE_2FSK, 0); + /* RTTY: We use the modem offset to modulate */ + si_trx_on(SI_MODEM_MOD_TYPE_CW); radio_on = 1; } @@ -222,10 +247,36 @@ void telemetry_tick(void) { } break; + + case TELEMETRY_RSID: /* ---- ---- A block mode */ + + /* Wait for 5 bit times of silence */ + if (telemetry_index < 5) { + telemetry_index++; + return; + } + + if (!radio_on) { + /* RSID: We PWM frequencies with the external pin */ + si_trx_on(SI_MODEM_MOD_TYPE_2FSK); + telemetry_gpio1_pwm_init(); + + radio_on = 1; + } + + /* Do Tx */ + if (!rsid_tick()) { + /* Force transmission finished */ + telemetry_index++; + is_telemetry_finished(); // Returns true + telemetry_gpio1_pwm_deinit(); + return; + } } } } + /** * CLOCKING * ============================================================================= @@ -250,8 +301,10 @@ void si_gclk_setup(void) /** * Initialises a timer interupt at the given frequency + * + * Returns the frequency we actually initialised. */ -void timer0_tick_init(float frequency) +float timer0_tick_init(float frequency) { //si_gclk_setup(); @@ -293,6 +346,9 @@ void timer0_tick_init(float frequency) /* Enable Timer */ tc_enable(TC0); tc_start_counter(TC0); + + /* Return the frequency we actually initialised */ + return gclk_frequency / (float)count; } /** * Disables the timer @@ -315,3 +371,64 @@ void TC0_Handler(void) telemetry_tick(); } } + + + +#define GPIO1_PWM_STEPS 200 // ~ 20kHz on a 4 MHz clock + +/** + * Initialised PWM at the given duty cycle on the GPIO1 pin of the radio + */ +void telemetry_gpio1_pwm_init(void) +{ + bool capture_channel_enables[] = {false, true}; + uint32_t compare_channel_values[] = {0x0000, 0x0000}; // Set duty cycle at 0% by default + + //float gclk_frequency = (float)system_gclk_chan_get_hz(0); + + tc_init(TC5, + GCLK_GENERATOR_0, + TC_COUNTER_SIZE_8BIT, + TC_CLOCK_PRESCALER_DIV1, + TC_WAVE_GENERATION_NORMAL_PWM, + TC_RELOAD_ACTION_GCLK, + TC_COUNT_DIRECTION_UP, + TC_WAVEFORM_INVERT_OUTPUT_NONE, + false, /* Oneshot = false */ + false, /* Run in standby = false */ + 0x0000, /* Initial value */ + GPIO1_PWM_STEPS, /* Top value */ + capture_channel_enables, /* Capture Channel Enables */ + compare_channel_values); /* Compare Channels Values */ + + + /* Enable the output pin */ + system_pinmux_pin_set_config(SI406X_GPIO1_PINMUX >> 16, /* GPIO Pin */ + SI406X_GPIO1_PINMUX & 0xFFFF, /* Mux Position */ + SYSTEM_PINMUX_PIN_DIR_INPUT, /* Direction */ + SYSTEM_PINMUX_PIN_PULL_NONE, /* Pull */ + false); /* Powersave */ + + tc_enable(TC5); + tc_start_counter(TC5); + +} +/** + * Sets duty cycle on PWM pin + */ +void telemetry_gpio1_pwm_duty(float duty_cycle) +{ + uint32_t compare_value = (float)GPIO1_PWM_STEPS * duty_cycle; + + tc_set_compare_value(TC5, + TC_COMPARE_CAPTURE_CHANNEL_1, + compare_value); +} +/** + * Turn the pwm off again + */ +void telemetry_gpio1_pwm_deinit(void) +{ + tc_stop_counter(TC5); + tc_enable(TC5); +}