diff --git a/Libraries/aprs/afsk.c b/Libraries/aprs/afsk.c new file mode 100644 --- /dev/null +++ b/Libraries/aprs/afsk.c @@ -0,0 +1,306 @@ +/* + * FeatherHAB + * + * This file is part of FeatherHAB. + * + * FeatherHab is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FeatherHab is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with FeatherHAB. If not, see . + * + * Ethan Zonca + * + */ + +#include "stm32f0xx_hal.h" + +#include "aprs/afsk.h" +#include "Si446x/si446x.h" +#include "config.h" + + +const uint8_t afsk_sine_table[512] = +{127, 129, 130, 132, 133, 135, 136, 138, 139, 141, 143, 144, 146, 147, 149, 150, 152, 153, 155, 156, 158, 159, 161, 162, 164, 165, 167, 168, 170, 171, 173, 174, 176, 177, 178, 180, 181, 183, 184, 185, 187, 188, 190, 191, 192, 194, 195, 196, 198, 199, 200, 201, 203, 204, 205, 206, 208, 209, 210, 211, 212, 213, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 233, 234, 235, 236, 237, 238, 238, 239, 240, 240, 241, 242, 242, 243, 244, 244, 245, 245, 246, 247, 247, 248, 248, 249, 249, 249, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253, 253, 253, 253, 253, 252, 252, 252, 252, 251, 251, 251, 250, 250, 249, 249, 249, 248, 248, 247, 247, 246, 245, 245, 244, 244, 243, 242, 242, 241, 240, 240, 239, 238, 238, 237, 236, 235, 234, 233, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 213, 212, 211, 210, 209, 208, 206, 205, 204, 203, 201, 200, 199, 198, 196, 195, 194, 192, 191, 190, 188, 187, 185, 184, 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, 167, 165, 164, 162, 161, 159, 158, 156, 155, 153, 152, 150, 149, 147, 146, 144, 143, 141, 139, 138, 136, 135, 133, 132, 130, 129, 127, 125, 124, 122, 121, 119, 118, 116, 115, 113, 111, 110, 108, 107, 105, 104, 102, 101, 99, 98, 96, 95, 93, 92, 90, 89, 87, 86, 84, 83, 81, 80, 78, 77, 76, 74, 73, 71, 70, 69, 67, 66, 64, 63, 62, 60, 59, 58, 56, 55, 54, 53, 51, 50, 49, 48, 46, 45, 44, 43, 42, 41, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 21, 20, 19, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 9, 8, 7, 7, 6, 6, 5, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 58, 59, 60, 62, 63, 64, 66, 67, 69, 70, 71, 73, 74, 76, 77, 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 113, 115, 116, 118, 119, 121, 122, 124, 125 }; + +const uint16_t TABLE_SIZE = sizeof(afsk_sine_table); + +static inline uint8_t afsk_read_sample(uint16_t phase) +{ + return afsk_sine_table[phase]; +} + + +// constants +//#define MODEM_CLOCK_RATE F_CPU +//#define PLAYBACK_RATE MODEM_CLOCK_RATE / 256 // Fast PWM + +#define BAUD_RATE 1200 +//#define SAMPLES_PER_BAUD PLAYBACK_RATE / BAUD_RATE // = 156 +//#define SAMPLES_PER_BAUD 36 + +// factor of 4 for the 4x clcokdiv on the counter (maybe kill that) +//#define SAMPLES_PER_BAUD 156 / 4 +#define SAMPLES_PER_BAUD 156 / 2 / 3 + + +// phase offset of 830 gives ~1900 Hz +// phase offset of 1550 gives ~2200 Hz +//#define PHASE_DELTA_1200 1800 +//#define PHASE_DELTA_2200 2200 +//#define PHASE_DELTA_1200 8000 +//#define PHASE_DELTA_2200 10000 + +#define PHASE_DELTA_1200 830 * 3 //1800 +#define PHASE_DELTA_2200 1550*3 //1550 * 6 + + +// Module globals +volatile unsigned char current_byte; +volatile uint8_t current_sample_in_baud; // 1 bit = SAMPLES_PER_BAUD samples +volatile uint16_t phase = 10; +volatile uint16_t phasedelta = 3300; + +volatile uint8_t request_cwoff = 0; +volatile uint8_t go = 0; + +volatile uint32_t packet_pos; // Next bit to be sent out + +volatile uint32_t afsk_packet_size = 10; +volatile const uint8_t *afsk_packet; + + +#define PRESCALE_1200 155 * 6 +#define PRESCALE_2200 84 * 6 + +volatile TIM_HandleTypeDef htim1; + + +//////////////////////////////////////////////// +void afsk_init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = GPIO_PIN_10; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + //GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF2_TIM1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + +// __HAL_RCC_TIM1_CLK_ENABLE(); + + __TIM1_CLK_ENABLE(); + + TIM_MasterConfigTypeDef sMasterConfig; + TIM_OC_InitTypeDef sConfigOC; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig; + + htim1.Instance = TIM1; + htim1.Init.Prescaler = 1; + htim1.Init.CounterMode = TIM_COUNTERMODE_UP; + htim1.Init.Period = 255; + htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim1.Init.RepetitionCounter = 0; + HAL_TIM_OC_Init(&htim1); + + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig); + + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 300; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3); + + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig); + +// +// +// // Init gpio of pin +// gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10); //pa10 radio gp1 +// gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_HIGH, GPIO10); +// gpio_set_af(GPIOA, GPIO_AF2, GPIO10); +// +// // Reset and configure timer +// timer_reset(TIM1); +// //TIM_CR1_CKD_CK_INT_MUL_4 +// timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, //TIM_CR1_CMS_CENTER_1, +// TIM_CR1_DIR_UP); +// timer_set_prescaler(TIM1, 1); // 155 is 1200hz, 84 is 2200hz +// +// +// timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1); +// timer_enable_oc_output(TIM1, TIM_OC3); +// timer_enable_break_main_output(TIM1); +// timer_set_oc_value(TIM1, TIM_OC3, 300); +// timer_set_period(TIM1, 255); // should this be 256? FIXME +// timer_enable_counter(TIM1); +// +// // Enable interrupt for timer capture/compare +// timer_enable_irq(TIM1, TIM_DIER_CC3IE); + + while(afsk_busy()); + //HAL_TIM_OC_Start_IT(&htim1, TIM_CHANNEL_3); + +// HAL_NVIC_SetPriority(TIM1_CC_IRQn, 0, 0); + HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0, 0); +// HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); + HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); + +} + + +void afsk_output_sample(uint8_t s) +{ + //timer_set_oc_value(TIM1, TIM_OC3, s); + htim1.Instance->CCR3 = s; +} + +uint8_t afsk_request_cwoff(void) +{ + if(request_cwoff) + { + request_cwoff = 0; + return 1; + } + else + { + return 0; + } +} + +volatile uint32_t freqctr = 0; + +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (go) { + if (packet_pos == afsk_packet_size) + { + request_cwoff = 1; + //gpio_toggle(GPIOB, GPIO0); + //gpio_toggle(GPIOB, GPIO7); + go = 0; // End of transmission + afsk_timer_stop(); // Disable modem + return; // done + } + + // If sent SAMPLES_PER_BAUD already, go to the next bit + if (current_sample_in_baud == 0) // Load up next bit + { + if ((packet_pos & 7) == 0) // Load up next byte + { + current_byte = afsk_packet[packet_pos >> 3]; + } + else + { + current_byte = current_byte / 2; // ">>1" forces int conversion + } + if ((current_byte & 1) == 0) + { + // Toggle tone (1200 <> 2200) + phasedelta ^= (PHASE_DELTA_1200 ^ PHASE_DELTA_2200); + } + } + + phase += phasedelta; + uint8_t s = afsk_read_sample((phase >> 7) & (TABLE_SIZE - 1)); + + afsk_output_sample(s); //real afsk + + if(++current_sample_in_baud == SAMPLES_PER_BAUD) + { + current_sample_in_baud = 0; + packet_pos++; + } + + } +} + + +void afsk_timer_start() +{ + // Clear the overflow flag, so that the interrupt doesn't go off + // immediately and overrun the next one (p.163). + // Enable interrupt when TCNT2 reaches TOP (0xFF) (p.151, 163) + //nvic_enable_irq(NVIC_TIM1_CC_IRQ); +// HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); + HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); + __HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE); + HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_3); + + //timer_enable_counter(TIM1); +} + +void afsk_timer_stop() +{ + // Resting duty cycle + // Output 0v (could be 255/2, which is 0v after coupling... doesn't really matter) + //OCR2A = 0x80; + + // Disable playback interrupt + //TIMSK2 &= ~_BV(TOIE2); + //nvic_disable_irq(NVIC_TIM1_CC_IRQ); +// HAL_NVIC_DisableIRQ(TIM1_CC_IRQn); +// HAL_NVIC_DisableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); + HAL_TIM_PWM_Stop_IT(&htim1, TIM_CHANNEL_3); + //timer_disable_counter(TIM1); +} + + +// External + +void afsk_start(void) +{ + phasedelta = PHASE_DELTA_1200; + phase = 0; + packet_pos = 0; + current_sample_in_baud = 0; + go = 1; + + // Wake up and configure radio + //si446x_prepare(); + HAL_Delay(100); + + // Key the radio + si446x_cw_on(); + + // Start transmission + afsk_timer_start(); +} + +uint8_t afsk_busy(void) +{ + return go; +} + +void afsk_send(const uint8_t *buffer, uint16_t len) +{ + afsk_packet_size = len; + afsk_packet = buffer; +} + +TIM_HandleTypeDef* afsk_timer_gethandle(void) +{ + return &htim1; +} + + +// vim:softtabstop=4 shiftwidth=4 expandtab