/* * fsk4.c * By SQ2DK */ #include "fsk4.h" #include "adf.h" #include "config.h" #include "main.h" /* * In this file i will try to prepare procedure for transmitting earlier * prepared message using 4fsk We will be using adf.c - library for handling * ADF7012 chip. Frequency setting and initialization of chip will be done * outside of this library idea is to use frequency correction register for * shifting base frequency, which should produce 244Hz steps in frequency. This * will limit minimum baud rate to 100bd and its multipliers. As experience * showed, 244Hz tone-spacing is not sufficient for efficient decoding of * packets using standard 270Hz shift Thus generation of 9MHz signal for radio * chip was required via STM32 PLL to achieve spacing close to 270Hz. Baud rate * will be generated by microcontroler's timer. we will use timer2 for this, * setting prescaler to (cpu_freuency/100000)-1, so, for 100bd single pulse we * should set counter to 1000-1 */ static uint16_t current_2_bit = 0; static bool FSK_Active = false; static char *buffer; static uint8_t buffer_len; static uint8_t QRGCounter = 0; void FSK4_stop_TX() { TIM2->DIER &= ~(TIM_DIER_UIE); // Disable the interrupt adf_RF_off(); // turn TX off FSK_Active = false; } static void FSK4_send_2bit(uint8_t bits_to_send) { // sends 2 bit value bits_to_send = (bits_to_send & 3); // make sure to take only 2 last bites of value - we // cannot send more than 2 bits at the same time adf_4fsk_fone(bits_to_send * FSK4_SPACE_MULTIPLIER); } bool FSK4_is_active() { // returns 1 if transmitter is active for 4FSK return FSK_Active; } static void FSK4_write(char *buff, uint16_t address_2bit) { int full_bytes = address_2bit / 4; // number of full bytes of address int fraction_part = address_2bit - (full_bytes * 4); // fraction part of address (number of 2bytes offset) uint8_t byte_to_send = (buff[full_bytes] >> (6 - (fraction_part * 2)) & 3); // returns 2 bytes of buffer at address FSK4_send_2bit(byte_to_send); // sends those 2 bytes } void FSK4_timer_handler() { // called out by interrupt handling procedure in // main TIM2->CNT = 0; // reset timer - make sure to have it at the beginning of // procedure, otherwise there will be some delays. if (current_2_bit < (FSK4_HEADER_LENGTH * 4)) { // we are still in header uint8_t tmp_offset = ((0xD8 >> current_2_bit % 4) & 3); FSK4_send_2bit(tmp_offset); } else { FSK4_write(buffer, (current_2_bit - (FSK4_HEADER_LENGTH * 4))); // send 2 bits of data from address of current_2_bit * 2 } current_2_bit++; if (current_2_bit > ((buffer_len + FSK4_HEADER_LENGTH) * 4)) { FSK4_stop_TX(); } // if we got to the end of data - finish transmitting } void FSK4_start_TX(char *buff, uint8_t len) { buffer = buff; buffer_len = len; // adf_setup(); current_2_bit = 0; // reset counter of current position of bit address adf_RF_on(QRG_FSK4[QRGCounter++], PA_FSK4); // turn on radio TX if (QRGCounter >= sizeof(QRG_FSK4) / sizeof(QRG_FSK4[0])) QRGCounter = 0; FSK_Active = true; // change status TIM2->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN)); // Disable the TIM Counter uint16_t timer2StartValue = (100000 / FSK4_BAUD) - 1; // timer value calculated according to baud rate 999 for 100bd TIM2->ARR = timer2StartValue; // set timer counter max value to pre-set value // for baudrate (auto-reload register) TIM2->CR1 |= TIM_CR1_CEN; // enable timer again TIM2->DIER |= TIM_DIER_UIE; // Enable the interrupt FSK4_timer_handler(); // force execution of procedure responsible for // interrupt handling }