mirror of
https://github.com/travisgoodspeed/goodwatch
synced 2024-11-23 09:19:58 +00:00
190 lines
4.3 KiB
C
190 lines
4.3 KiB
C
/*! \file counter.c
|
|
\brief Frequency Counter Application
|
|
|
|
Howdy y'all,
|
|
|
|
Once upon a time, a neighbor was in Heidelberg for the Troopers
|
|
conference, and he wanted to join the staff radio networks. So he
|
|
performed the out-of-band-TX mod to his Kenwood TH-D74, and borrowed
|
|
a laptop and SDR to find the staff simplex frequency. From an audio
|
|
recording, he identified the squelch tones and was on the air.
|
|
|
|
But why did he need an SDR, when his wristwatch ought to have been
|
|
able to quickly find the peak during transmission? This applet
|
|
seeks to remedy that problem by providing a basic frequency counter,
|
|
displaying the center frequency of the strongest signal yet
|
|
observed. It is loosely based on Michael Ossmann's spectrum
|
|
analyzer, written for the Girltech IMME in 2010.
|
|
|
|
This implementation does a single sweep from 410 to 470 MHz when the
|
|
0 button is pressed. A better implementation would perform a second
|
|
pass with a narrower filter to better identify the center frequency
|
|
after a sweep.
|
|
|
|
--Travis
|
|
|
|
*/
|
|
|
|
#include<stdio.h>
|
|
#include<string.h>
|
|
#include<msp430.h>
|
|
#include "api.h"
|
|
|
|
|
|
/* Settings were prototyped first in Python. This is basic OOK with
|
|
no preamble, no CRC, and 341µs symbol times.
|
|
*/
|
|
#define LEN 16
|
|
static const uint8_t counter_settings[]={
|
|
/* IF of 457.031 kHz */
|
|
FSCTRL1, 0x12,
|
|
FSCTRL0, 0x00,
|
|
|
|
/* disable 3 highest DVGA settings */
|
|
//AGCCTRL2 |= AGCCTRL2_MAX_DVGA_GAIN;
|
|
|
|
/* frequency synthesizer calibration */
|
|
FSCAL3, 0xEA,
|
|
FSCAL2, 0x2A,
|
|
FSCAL1, 0x00,
|
|
FSCAL0, 0x1F,
|
|
|
|
/* "various test settings" */
|
|
TEST2, 0x88,
|
|
TEST1, 0x31,
|
|
TEST0, 0x09,
|
|
|
|
/* no automatic frequency calibration */
|
|
MCSM0, 0,
|
|
|
|
|
|
/* Filter bandwidth */
|
|
//MDMCFG4, 0xEC, /* 67.708333 kHz */
|
|
//MDMCFG4, 0x0C, /* 812.5 kHz */
|
|
MDMCFG4, 0x6C, /* 270.833333 kHz */
|
|
|
|
//End with null terminator.
|
|
0,0
|
|
};
|
|
|
|
|
|
/* This enum manages the state machine for the frequency counter. The
|
|
state will be IDLE before and after the sweep.
|
|
*/
|
|
static enum {IDLE, SWEEP} counter_state;
|
|
static int best_rssi;
|
|
static float best_freq;
|
|
#define MAX_FREQ 470000000 //Range is 410 to 470 for now.
|
|
#define MIN_FREQ 410000000 //Will open more bands later.
|
|
#define STEP_FREQ 000100000 //600 steps at 100kHz/Step
|
|
//#define STEP_FREQ 000010000 //6000 steps at 10kHz/Step
|
|
static float current_freq;
|
|
|
|
//! Try a given frequency, and update display if it's best.
|
|
static void try_freq(float freq){
|
|
int rssi;
|
|
//Set the frequency.
|
|
radio_setfreq(freq);
|
|
//Get the RSSI.
|
|
rssi=radio_getrssi();
|
|
|
|
//Compare it.
|
|
if(rssi>best_rssi){
|
|
best_freq=freq;
|
|
best_rssi=rssi;
|
|
}
|
|
}
|
|
|
|
//! Try the next frequency in the set.
|
|
static void try_next(){
|
|
//Enforce the range here.
|
|
if(current_freq<MIN_FREQ)
|
|
current_freq=MIN_FREQ;
|
|
|
|
//Try the next center freq and step ahead.
|
|
try_freq(current_freq);
|
|
current_freq+=STEP_FREQ;
|
|
|
|
//We're done!
|
|
if(current_freq>MAX_FREQ){
|
|
current_freq=MIN_FREQ;
|
|
counter_state=IDLE;
|
|
}
|
|
}
|
|
|
|
//! Enter the Counter application.
|
|
void counter_init(){
|
|
/* This enters the application.
|
|
We ignore the codeplug frequency and set our own.
|
|
*/
|
|
if(has_radio){
|
|
//Faster processing time, for rapid packet succession.
|
|
ucs_fast();
|
|
|
|
radio_on();
|
|
radio_writesettings(counter_settings);
|
|
|
|
//Initialize state variables.
|
|
counter_state=IDLE;
|
|
best_rssi=0;
|
|
best_freq=0;
|
|
}else{
|
|
app_next();
|
|
}
|
|
}
|
|
|
|
//! Exit the Counter application.
|
|
int counter_exit(){
|
|
//Cut the radio off and drop the CPU frequency.
|
|
radio_off();
|
|
ucs_slow();
|
|
|
|
//Allow the exit.
|
|
return 0;
|
|
}
|
|
|
|
//! Draw the counter's status.
|
|
static void counter_drawstatus(){
|
|
lcd_number(current_freq/10);
|
|
}
|
|
|
|
//! Draw the Counter screen.
|
|
void counter_draw(){
|
|
switch(counter_state){
|
|
case IDLE:
|
|
if(best_rssi==0)
|
|
lcd_string("CNT IDLE");
|
|
else
|
|
lcd_number(best_freq/10);
|
|
break;
|
|
case SWEEP:
|
|
lcd_string("SWEEPING");
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//! Keypress handler for the Counter applet.
|
|
int counter_keypress(char ch){
|
|
int i=0;
|
|
|
|
switch(ch){
|
|
case '0': //Begin a new sweep.
|
|
best_rssi=0;
|
|
best_freq=0;
|
|
//No break, because we also want the behavior of '1'.
|
|
case '1': //Continue the old sweep.
|
|
counter_state=SWEEP;
|
|
//Do the sweep.
|
|
while(counter_state==SWEEP){
|
|
try_next();
|
|
//Draw every 64th channel.
|
|
if((i++&0x3f)==0)
|
|
counter_drawstatus();
|
|
}
|
|
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|