Téléverser les fichiers vers "src"
This commit is contained in:
parent
7cc911f734
commit
ddd41921b4
574
src/cibi.cpp
Normal file
574
src/cibi.cpp
Normal file
|
|
@ -0,0 +1,574 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Vincent Hervieux vincent.hervieux@gmail.com
|
||||||
|
* All rights reserved.
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the author Vincent Hervieux, nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cibi.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "vfo.h"
|
||||||
|
|
||||||
|
const int8_t Cibi::cibi_channels[45] PROGMEM = {
|
||||||
|
1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9,
|
||||||
|
10, 11, 11, 12, 13, 14, 15, 15, 16, 17, 18, 19, 19,
|
||||||
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||||
|
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
40};
|
||||||
|
|
||||||
|
const bool Cibi::cibi_channels_bis[45] PROGMEM = {
|
||||||
|
/* 1- 9*/ false, false, false, true /*3*/, false, false, false, false, true /*7*/, false, false,
|
||||||
|
/*10-19*/ false, false, true /*11*/, false, false, false, false, true /*15*/, false, false, false, false, true /*19*/,
|
||||||
|
/*20-29*/ false, false, false, false, false, false, false, false, false, false,
|
||||||
|
/*30-39*/ false, false, false, false, false, false, false, false, false, false,
|
||||||
|
/* 40 */ false};
|
||||||
|
|
||||||
|
Cibi::Cibi(Config &_config, Input &_input, U8G2 &_display, DDS &_dds) : config_(_config),
|
||||||
|
input_(_input),
|
||||||
|
dds_(_dds),
|
||||||
|
current_cibi_channel_({.channel = -1,
|
||||||
|
.band = CIBI_BAND_UNKNOWN,
|
||||||
|
.bis = false}),
|
||||||
|
current_freq_(0),
|
||||||
|
freq_change_time_(0),
|
||||||
|
current_clarifier_(0),
|
||||||
|
freq_step_(0),
|
||||||
|
current_cursor_pos_(CURSOR_POS_FREQ_DIG5), // <-- should be a parameter?
|
||||||
|
current_modulation_(-1),
|
||||||
|
current_smeter_(0),
|
||||||
|
current_tx_(false),
|
||||||
|
scanning_(false)
|
||||||
|
{
|
||||||
|
view_ = new CibiDisplay(_display);
|
||||||
|
updateFreqStep(current_cursor_pos_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cibi::Cibi(const Cibi &_cibi) : config_(_cibi.config_),
|
||||||
|
input_(_cibi.input_),
|
||||||
|
dds_(_cibi.dds_),
|
||||||
|
current_cibi_channel_({.channel = _cibi.current_cibi_channel_.channel,
|
||||||
|
.band = _cibi.current_cibi_channel_.band,
|
||||||
|
.bis = _cibi.current_cibi_channel_.bis}),
|
||||||
|
current_freq_(_cibi.current_freq_),
|
||||||
|
freq_change_time_(_cibi.freq_change_time_),
|
||||||
|
current_clarifier_(_cibi.current_clarifier_),
|
||||||
|
freq_step_(_cibi.freq_step_),
|
||||||
|
current_cursor_pos_(_cibi.current_cursor_pos_),
|
||||||
|
current_modulation_(_cibi.current_modulation_),
|
||||||
|
current_smeter_(_cibi.current_smeter_),
|
||||||
|
current_tx_(_cibi.current_tx_),
|
||||||
|
scanning_(_cibi.scanning_),
|
||||||
|
view_(_cibi.view_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Cibi::~Cibi()
|
||||||
|
{
|
||||||
|
delete view_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Cibi::getCibiChannel(uint32_t _frequency, Cibi::cibi_channel_t *_channel)
|
||||||
|
{
|
||||||
|
/* Cibi channels */
|
||||||
|
/* Pay attention that TX over 28Mhz is reserved for HAM use */
|
||||||
|
const static uint16_t FREQ_CIBI_LOW_DAKHZ PROGMEM = 2561;
|
||||||
|
const static uint16_t FREQ_CIBI_HIGH_DAKHZ PROGMEM = 2875;
|
||||||
|
/* A cibi band is 45 channels:
|
||||||
|
- 40 channels
|
||||||
|
- 5 'bis' channels: 3,7,11,15,19 */
|
||||||
|
const uint16_t CIBI_BAND_DAKHZ PROGMEM = 45;
|
||||||
|
/* Round to kHz to compute channels
|
||||||
|
* This avoids to get no display of channels
|
||||||
|
* in case a fine tuning was made to clarify the voice
|
||||||
|
*/
|
||||||
|
uint16_t freq_dakhz = _frequency / 10000;
|
||||||
|
_channel->channel = -1;
|
||||||
|
_channel->band = CIBI_BAND_UNKNOWN;
|
||||||
|
_channel->bis = false;
|
||||||
|
/* Check if we are not out of Cibi band */
|
||||||
|
if (freq_dakhz < FREQ_CIBI_LOW_DAKHZ || freq_dakhz > FREQ_CIBI_HIGH_DAKHZ)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* move down band to 0 for computation */
|
||||||
|
freq_dakhz -= FREQ_CIBI_LOW_DAKHZ;
|
||||||
|
|
||||||
|
_channel->band = freq_dakhz / CIBI_BAND_DAKHZ;
|
||||||
|
/* reuse variable freq_dakhz as index in cibi_channel array, */
|
||||||
|
freq_dakhz = freq_dakhz % CIBI_BAND_DAKHZ;
|
||||||
|
_channel->channel = pgm_read_byte_near(cibi_channels + freq_dakhz);
|
||||||
|
_channel->bis = pgm_read_byte_near(cibi_channels_bis + freq_dakhz);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cibi::init()
|
||||||
|
{
|
||||||
|
if (0 == current_freq_)
|
||||||
|
{
|
||||||
|
/* startup: retrieve value from config and compute our context */
|
||||||
|
current_freq_ = config_.getCibiFreq();
|
||||||
|
current_modulation_ = input_.getModulation();
|
||||||
|
current_tx_ = input_.getTx();
|
||||||
|
/* update DDS according to current_freq_ and current_modulation_*/
|
||||||
|
updateDDS(current_freq_, current_modulation_, current_tx_);
|
||||||
|
}
|
||||||
|
/* init display with newly created context */
|
||||||
|
view_->init();
|
||||||
|
view_->setFreq(current_freq_, WHITE);
|
||||||
|
bool cibiBand = (0 == getCibiChannel(current_freq_, ¤t_cibi_channel_));
|
||||||
|
if(cibiBand)
|
||||||
|
{
|
||||||
|
view_->setCibiChannel(current_cibi_channel_.channel, WHITE);
|
||||||
|
view_->setCibiBand(current_cibi_channel_.band, WHITE);
|
||||||
|
view_->setCibiChannelBis(current_cibi_channel_.bis, WHITE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* HAM band */
|
||||||
|
view_->setBand(current_freq_, WHITE);
|
||||||
|
}
|
||||||
|
view_->setCursorPos(current_cursor_pos_, WHITE);
|
||||||
|
view_->setModulation(current_modulation_, WHITE);
|
||||||
|
#ifdef SMETER_DISPLAY
|
||||||
|
view_->setSMeter(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
void Cibi::updateDisplay(uint32_t _frequency, int _position, int _modulation, bool _tx, int _smeter)
|
||||||
|
{
|
||||||
|
cibi_channel_t cibi_channel({.channel = -1,
|
||||||
|
.band = CIBI_BAND_UNKNOWN,
|
||||||
|
.bis = false});
|
||||||
|
uint32_t clarified_freq = add_int32_to_uint32(current_freq_, current_clarifier_);
|
||||||
|
if (_frequency != clarified_freq ||
|
||||||
|
current_cibi_channel_.channel != cibi_channel.channel ||
|
||||||
|
_position != current_cursor_pos_ ||
|
||||||
|
_modulation != current_modulation_ ||
|
||||||
|
_tx != current_tx_)
|
||||||
|
{
|
||||||
|
view_->clear();
|
||||||
|
/* TODO: could be optimized to update only the impacted digits */
|
||||||
|
view_->setTx(_tx);
|
||||||
|
view_->setFreq(_frequency, (_tx? BLACK : WHITE));
|
||||||
|
/* if withing the 10-11m band, check for Cibi channels */
|
||||||
|
/* Outside this range, set HAM bands */
|
||||||
|
bool cibiBand = (0 == getCibiChannel(_frequency, &cibi_channel));
|
||||||
|
if(cibiBand)
|
||||||
|
{
|
||||||
|
#if 0 // def DEBUG
|
||||||
|
Serial.println(cibi_channel.channel);
|
||||||
|
#endif // DEBUG
|
||||||
|
view_->setCibiChannel(cibi_channel.channel, WHITE);
|
||||||
|
current_cibi_channel_.channel = cibi_channel.channel;
|
||||||
|
|
||||||
|
view_->setCibiBand(cibi_channel.band, WHITE);
|
||||||
|
current_cibi_channel_.band = cibi_channel.band;
|
||||||
|
|
||||||
|
view_->setCibiChannelBis(cibi_channel.bis, WHITE);
|
||||||
|
current_cibi_channel_.bis = cibi_channel.bis;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
view_->setBand(_frequency, WHITE);
|
||||||
|
current_cibi_channel_.channel = -1;
|
||||||
|
current_cibi_channel_.band = CIBI_BAND_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
view_->setCursorPos(_position, WHITE);
|
||||||
|
view_->setModulation(_modulation, WHITE);
|
||||||
|
#ifdef SMETER_DISPLAY
|
||||||
|
view_->setSMeter(_smeter);
|
||||||
|
#else
|
||||||
|
view_->display();
|
||||||
|
#endif
|
||||||
|
clarified_freq = _frequency;
|
||||||
|
current_cibi_channel_.channel = cibi_channel.channel;
|
||||||
|
current_cursor_pos_ = _position;
|
||||||
|
current_modulation_ = _modulation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
void Cibi::updateDisplay(uint32_t _frequency, int _position, int _modulation, bool _tx, int _smeter)
|
||||||
|
{
|
||||||
|
bool update = false;
|
||||||
|
cibi_channel_t cibi_channel({.channel = -1,
|
||||||
|
.band = CIBI_BAND_UNKNOWN,
|
||||||
|
.bis = false});
|
||||||
|
uint32_t clarified_freq = add_int32_to_uint32(current_freq_, current_clarifier_);
|
||||||
|
if (_frequency != clarified_freq)
|
||||||
|
{
|
||||||
|
/* TODO: could be optimized to update only the impacted digits */
|
||||||
|
view_->setFreq(clarified_freq, BLACK);
|
||||||
|
view_->setFreq(_frequency, WHITE);
|
||||||
|
update = true;
|
||||||
|
/* if withing the 10-11m band, check for Cibi channels */
|
||||||
|
/* Outside this range, set HAM bands */
|
||||||
|
bool cibiBand = (0 == getCibiChannel(_frequency, &cibi_channel));
|
||||||
|
if(cibiBand)
|
||||||
|
{
|
||||||
|
#if 0 // def DEBUG
|
||||||
|
Serial.println(cibi_channel.channel);
|
||||||
|
#endif // DEBUG
|
||||||
|
if (current_cibi_channel_.channel != cibi_channel.channel)
|
||||||
|
{
|
||||||
|
if(-1 == current_cibi_channel_.channel)
|
||||||
|
{
|
||||||
|
view_->setBand(clarified_freq, BLACK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
view_->setCibiChannel(current_cibi_channel_.channel, BLACK);
|
||||||
|
}
|
||||||
|
view_->setCibiChannel(cibi_channel.channel, WHITE);
|
||||||
|
current_cibi_channel_.channel = cibi_channel.channel;
|
||||||
|
}
|
||||||
|
if (current_cibi_channel_.band != cibi_channel.band &&
|
||||||
|
CIBI_BAND_UNKNOWN != cibi_channel.band)
|
||||||
|
{
|
||||||
|
view_->setCibiBand(current_cibi_channel_.band, BLACK);
|
||||||
|
view_->setCibiBand(cibi_channel.band, WHITE);
|
||||||
|
current_cibi_channel_.band = cibi_channel.band;
|
||||||
|
}
|
||||||
|
if (current_cibi_channel_.bis != cibi_channel.bis)
|
||||||
|
{
|
||||||
|
view_->setCibiChannelBis(current_cibi_channel_.bis, BLACK);
|
||||||
|
view_->setCibiChannelBis(cibi_channel.bis, WHITE);
|
||||||
|
current_cibi_channel_.bis = cibi_channel.bis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* HAM band */
|
||||||
|
if(-1 != current_cibi_channel_.channel)
|
||||||
|
{
|
||||||
|
view_->setCibiChannel(current_cibi_channel_.channel, BLACK);
|
||||||
|
view_->setCibiBand(current_cibi_channel_.band, BLACK);
|
||||||
|
view_->setCibiChannelBis(current_cibi_channel_.bis, BLACK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
view_->setBand(clarified_freq, BLACK);
|
||||||
|
}
|
||||||
|
view_->setBand(_frequency, WHITE);
|
||||||
|
current_cibi_channel_.channel = -1;
|
||||||
|
current_cibi_channel_.band = CIBI_BAND_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_position != current_cursor_pos_)
|
||||||
|
{
|
||||||
|
view_->setCursorPos(current_cursor_pos_, BLACK);
|
||||||
|
view_->setCursorPos(_position, WHITE);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
if (_modulation != current_modulation_)
|
||||||
|
{
|
||||||
|
view_->setModulation(current_modulation_, BLACK);
|
||||||
|
view_->setModulation(_modulation, WHITE);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
if (update)
|
||||||
|
{
|
||||||
|
view_->display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Cibi::updateDDS(uint32_t _frequency, int _modulation, bool _tx)
|
||||||
|
{
|
||||||
|
bool enable_fi = _tx;
|
||||||
|
uint32_t vfo_freq = _frequency;
|
||||||
|
/* order matters, modulation needs to be updated prior to frequency */
|
||||||
|
switch (_modulation)
|
||||||
|
{
|
||||||
|
case MOD_AM:
|
||||||
|
case MOD_FM:
|
||||||
|
/* store the frequency currently used */
|
||||||
|
//dds_.setOutputFreq(DDS::OUTPUT_FI, config_.getFiAm());
|
||||||
|
break;
|
||||||
|
case MOD_CW:
|
||||||
|
/* store the frequency currently used */
|
||||||
|
dds_.setOutputFreq(DDS::OUTPUT_FI, config_.getFiAm());
|
||||||
|
enable_fi = true;
|
||||||
|
break;
|
||||||
|
case MOD_USB:
|
||||||
|
/* store the frequency currently used */
|
||||||
|
dds_.setOutputFreq(DDS::OUTPUT_FI, config_.getFiUsb());
|
||||||
|
enable_fi = true;
|
||||||
|
break;
|
||||||
|
case MOD_LSB:
|
||||||
|
/* store the frequency currently used */
|
||||||
|
dds_.setOutputFreq(DDS::OUTPUT_FI, config_.getFiLsb());
|
||||||
|
enable_fi = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// don't change the clock for unknown modulation type.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* RX/TX frequency is the VF0 + the FI
|
||||||
|
* So if we want to RX/TX on 27.555MHz in AM
|
||||||
|
* Set VFO to 27.555MHz - 10.695MHz = 16.860MHz (infradyne)
|
||||||
|
*/
|
||||||
|
vfo_freq -= dds_.getOutputFreq(DDS::OUTPUT_FI);
|
||||||
|
#if 0
|
||||||
|
/* RX/TX frequency is the VF0 - the FI
|
||||||
|
* So if we want to RX/TX on 27.555MHz in AM
|
||||||
|
* Set VFO to 27.555MHz + 10.695MHz = 38.250MHz (supradyne)
|
||||||
|
*/
|
||||||
|
vfo_freq += dds_.getOutputFreq(DDS::OUTPUT_FI);
|
||||||
|
#endif
|
||||||
|
dds_.setOutputFreq(DDS::OUTPUT_VFO, vfo_freq);
|
||||||
|
dds_.enableOutput(DDS::OUTPUT_VFO, true);
|
||||||
|
/* enable FI oscillator only while transmitting or in CW/SSB mode */
|
||||||
|
dds_.enableOutput(DDS::OUTPUT_FI, enable_fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cibi::updateFreqStep(int cursor_pos)
|
||||||
|
{
|
||||||
|
if (cursor_pos > CURSOR_POS_MAX ||
|
||||||
|
cursor_pos == CURSOR_POS_NONE)
|
||||||
|
{
|
||||||
|
freq_step_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
freq_step_ = quick_pow10(cursor_pos - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cibi::loop(bool _update_display)
|
||||||
|
{
|
||||||
|
uint32_t new_frequency = current_freq_;
|
||||||
|
int new_cursor_pos = current_cursor_pos_;
|
||||||
|
int new_clarifier = current_clarifier_;
|
||||||
|
int16_t increment = input_.getEncoderIncrement();
|
||||||
|
bool click = input_.buttonClicked();
|
||||||
|
int new_smeter = input_.getSMeter();
|
||||||
|
// smeter adjustment
|
||||||
|
if(0 != config_.getSMeterAdj())
|
||||||
|
{
|
||||||
|
if(config_.getSMeterAdj() > 0)
|
||||||
|
{
|
||||||
|
/* if positive, multiply factor */
|
||||||
|
new_smeter = new_smeter * config_.getSMeterAdj();
|
||||||
|
}
|
||||||
|
else if (config_.getSMeterAdj() < 0)
|
||||||
|
{
|
||||||
|
/* if negative, division factor */
|
||||||
|
new_smeter = new_smeter / abs(config_.getSMeterAdj());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
//Serial.print(F("Sig "));Serial.println(smeter);
|
||||||
|
#endif // DEBUG
|
||||||
|
if (_update_display)
|
||||||
|
{
|
||||||
|
/* initial display */
|
||||||
|
init();
|
||||||
|
/* waiting for next call to loop() */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(input_.getIncrementMode() == Input::INCREMENT_MANUAL)
|
||||||
|
{
|
||||||
|
/* Increment mode: manual
|
||||||
|
======================
|
||||||
|
Click the encoder to select a digit
|
||||||
|
Change the selected digit value by encoder rotation
|
||||||
|
*/
|
||||||
|
if (click)
|
||||||
|
{
|
||||||
|
new_cursor_pos++;
|
||||||
|
if (new_cursor_pos > CURSOR_POS_MAX)
|
||||||
|
{
|
||||||
|
new_cursor_pos = CURSOR_POS_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFreqStep(new_cursor_pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Increment mode: step
|
||||||
|
====================
|
||||||
|
Encoder rotation change frequency value by step
|
||||||
|
Click to scan
|
||||||
|
*/
|
||||||
|
new_cursor_pos = CURSOR_POS_NONE;
|
||||||
|
freq_step_ = config_.getFreqStepIncrement();
|
||||||
|
if(click && !scanning_) {
|
||||||
|
scanning_ = true;
|
||||||
|
increment = 1;
|
||||||
|
}
|
||||||
|
else if ((click || input_.getTx()) && scanning_)
|
||||||
|
{
|
||||||
|
scanning_ = false;
|
||||||
|
increment = 0;
|
||||||
|
}
|
||||||
|
else if (increment && scanning_)
|
||||||
|
{
|
||||||
|
scanning_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(scanning_) {
|
||||||
|
/* TODO: does scan threshold needs be in the config?
|
||||||
|
* Playing with RF gain does allow to play around this level
|
||||||
|
*/
|
||||||
|
if(new_smeter > 10) {
|
||||||
|
increment = -1; // seems that measure takes one loop, so return to previous freq
|
||||||
|
scanning_ = false;
|
||||||
|
} else {
|
||||||
|
increment = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (increment)
|
||||||
|
{
|
||||||
|
if (increment < 0 && (freq_step_ * abs(increment)) > new_frequency)
|
||||||
|
{
|
||||||
|
/* avoid negative values */
|
||||||
|
new_frequency = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_frequency += ((uint32_t)increment * freq_step_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Limits with rotation */
|
||||||
|
if (new_frequency > config_.getCibiMaxFreq())
|
||||||
|
new_frequency = config_.getCibiMinFreq();
|
||||||
|
else if (new_frequency < config_.getCibiMinFreq())
|
||||||
|
new_frequency = config_.getCibiMaxFreq();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save new frequency to EEPROM after 30 seconds of usage */
|
||||||
|
if (new_frequency != current_freq_)
|
||||||
|
{
|
||||||
|
freq_change_time_ = millis();
|
||||||
|
input_.setBuiltInLED(HIGH);
|
||||||
|
}
|
||||||
|
else if(freq_change_time_ != 0)
|
||||||
|
{
|
||||||
|
if(millis() - freq_change_time_ > 30000)
|
||||||
|
{
|
||||||
|
/* about 30 seconds on the same frequency, save it */
|
||||||
|
config_.setCibiFreq(current_freq_);
|
||||||
|
freq_change_time_ = 0;
|
||||||
|
input_.setBuiltInLED(LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_frequency != current_freq_ ||
|
||||||
|
(input_.getClarifier() + config_.getClarifierAdj()) != current_clarifier_ ||
|
||||||
|
input_.getModulation() != current_modulation_ ||
|
||||||
|
new_cursor_pos != current_cursor_pos_ ||
|
||||||
|
input_.getTx() != current_tx_
|
||||||
|
#ifdef SMETER_DISPLAY
|
||||||
|
|| new_smeter != current_smeter_
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Update display and context with newer values */
|
||||||
|
if(!input_.getTx())
|
||||||
|
{
|
||||||
|
/* Apply clarifier here if we are receiving */
|
||||||
|
new_clarifier = input_.getClarifier() + config_.getClarifierAdj();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_clarifier = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay(add_int32_to_uint32(new_frequency, new_clarifier), new_cursor_pos, input_.getModulation(), input_.getTx(), new_smeter);
|
||||||
|
updateDDS(add_int32_to_uint32(new_frequency, new_clarifier), input_.getModulation(), input_.getTx());
|
||||||
|
current_freq_ = new_frequency;
|
||||||
|
current_clarifier_ = new_clarifier;
|
||||||
|
current_modulation_ = input_.getModulation();
|
||||||
|
current_cursor_pos_ = new_cursor_pos;
|
||||||
|
current_tx_ = input_.getTx();
|
||||||
|
current_smeter_ = new_smeter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Cibi::getCurrentFreq()
|
||||||
|
{
|
||||||
|
return current_freq_;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int Cibi::getBand(uint32_t _frequency)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Display band names according to
|
||||||
|
* https://en.wikipedia.org/wiki/Amateur_radio_frequency_allocations
|
||||||
|
*/
|
||||||
|
const static uint32_t BAND_2200_LOW PROGMEM = 135700;
|
||||||
|
const static uint32_t BAND_2200_HI PROGMEM = 135800;
|
||||||
|
const static uint32_t BAND_1750_LOW PROGMEM = 160000;
|
||||||
|
const static uint32_t BAND_1750_HI PROGMEM = 190000;
|
||||||
|
const static uint32_t BAND_630_LOW PROGMEM = 472000;
|
||||||
|
const static uint32_t BAND_630_HI PROGMEM = 479000;
|
||||||
|
const static uint32_t BAND_160_LOW PROGMEM = 1800000;
|
||||||
|
const static uint32_t BAND_160_HI PROGMEM = 2000000;
|
||||||
|
const static uint32_t BAND_80_LOW PROGMEM = 3500000;
|
||||||
|
const static uint32_t BAND_80_HI PROGMEM = 4000000;
|
||||||
|
const static uint32_t BAND_60_LOW PROGMEM = 5332000;
|
||||||
|
const static uint32_t BAND_60_HI PROGMEM = 5450000;
|
||||||
|
const static uint32_t BAND_40_LOW PROGMEM = 7000000;
|
||||||
|
const static uint32_t BAND_40_HI PROGMEM = 7300000;
|
||||||
|
const static uint32_t BAND_30_LOW PROGMEM = 10100000;
|
||||||
|
const static uint32_t BAND_30_HI PROGMEM = 10150000;
|
||||||
|
const static uint32_t BAND_20_LOW PROGMEM = 14000000;
|
||||||
|
const static uint32_t BAND_20_HI PROGMEM = 14350000;
|
||||||
|
const static uint32_t BAND_17_LOW PROGMEM = 18068000;
|
||||||
|
const static uint32_t BAND_17_HI PROGMEM = 18168000;
|
||||||
|
const static uint32_t BAND_15_LOW PROGMEM = 21000000;
|
||||||
|
const static uint32_t BAND_15_HI PROGMEM = 21450000;
|
||||||
|
const static uint32_t BAND_12_LOW PROGMEM = 24890000;
|
||||||
|
const static uint32_t BAND_12_HI PROGMEM = 24990000;
|
||||||
|
const static uint32_t BAND_11_LOW PROGMEM = 25000000;
|
||||||
|
const static uint32_t BAND_11_HI PROGMEM = 28000000;
|
||||||
|
const static uint32_t BAND_10_LOW PROGMEM = 28000000;
|
||||||
|
const static uint32_t BAND_10_HI PROGMEM = 29700000;
|
||||||
|
const static uint32_t BAND_6_LOW PROGMEM = 50000000;
|
||||||
|
const static uint32_t BAND_6_HI PROGMEM = 54000000;
|
||||||
|
const static uint32_t BAND_2_LOW PROGMEM = 144000000;
|
||||||
|
const static uint32_t BAND_2_HI PROGMEM = 148000000;
|
||||||
|
if (_frequency > BAND_10_LOW && _frequency <= BAND_10_HI) return BAND_10;
|
||||||
|
else if (_frequency > BAND_11_LOW && _frequency <= BAND_11_HI) return BAND_11;
|
||||||
|
else if (_frequency > BAND_12_LOW && _frequency <= BAND_12_HI) return BAND_12;
|
||||||
|
else if (_frequency > BAND_15_LOW && _frequency <= BAND_15_HI) return BAND_15;
|
||||||
|
else if (_frequency > BAND_17_LOW && _frequency <= BAND_17_HI) return BAND_17;
|
||||||
|
else if (_frequency > BAND_20_LOW && _frequency <= BAND_20_HI) return BAND_20;
|
||||||
|
else if (_frequency > BAND_30_LOW && _frequency <= BAND_30_HI) return BAND_30;
|
||||||
|
else if (_frequency > BAND_2200_LOW && _frequency <= BAND_2200_HI) return BAND_2200;
|
||||||
|
else if (_frequency > BAND_1750_LOW && _frequency <= BAND_1750_HI) return BAND_1750;
|
||||||
|
else if (_frequency > BAND_630_LOW && _frequency <= BAND_630_HI) return BAND_630;
|
||||||
|
else if (_frequency > BAND_160_LOW && _frequency <= BAND_160_HI) return BAND_160;
|
||||||
|
else if (_frequency > BAND_80_LOW && _frequency <= BAND_80_HI) return BAND_80;
|
||||||
|
else if (_frequency > BAND_60_LOW && _frequency <= BAND_60_HI) return BAND_60;
|
||||||
|
else if (_frequency > BAND_40_LOW && _frequency <= BAND_40_HI) return BAND_40;
|
||||||
|
else if (_frequency > BAND_6_LOW && _frequency <= BAND_6_HI) return BAND_6;
|
||||||
|
else if (_frequency > BAND_2_LOW && _frequency <= BAND_2_HI) return BAND_2;
|
||||||
|
else return BAND_UNKNOWN;
|
||||||
|
}
|
||||||
|
#endif /* 0 */
|
||||||
303
src/cibidisplay.cpp
Normal file
303
src/cibidisplay.cpp
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Vincent Hervieux vincent.hervieux@gmail.com
|
||||||
|
* All rights reserved.
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the author Vincent Hervieux, nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
*** Display: using an OLED SSD1306
|
||||||
|
***/
|
||||||
|
#include "cibidisplay.h"
|
||||||
|
#include "vfo.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
|
||||||
|
CibiDisplay::CibiDisplay(U8G2 &_display):
|
||||||
|
display_(_display)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CibiDisplay::CibiDisplay(const CibiDisplay &_cibidisplay):
|
||||||
|
display_(_cibidisplay.display_)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CibiDisplay::~CibiDisplay()
|
||||||
|
{
|
||||||
|
display_.clearDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::init()
|
||||||
|
{
|
||||||
|
const static int16_t SMETER_TOP_X PROGMEM = 5;
|
||||||
|
const static int16_t SMETER_TOP_Y PROGMEM = 8;
|
||||||
|
const static int16_t FREQ_DOT_TEXT_POS_X PROGMEM = 32;
|
||||||
|
const static int16_t MHZ_TEXT_POS_X PROGMEM = 120;
|
||||||
|
const static int16_t H_LINE_WIDTH PROGMEM = 118;
|
||||||
|
const static int16_t H_LINE_POS_X PROGMEM = 0;
|
||||||
|
#ifdef SMETER_DISPLAY
|
||||||
|
/* S meter frame */
|
||||||
|
display_.setFont(u8g2_font_6x10_tr);
|
||||||
|
display_.setCursor(SMETER_TOP_X,SMETER_TOP_Y);
|
||||||
|
display_.setDrawColor(WHITE);
|
||||||
|
display_.print(F("SIG.1.3.5.7.9..+30dB"));
|
||||||
|
#else
|
||||||
|
/* S meter frame */
|
||||||
|
display_.setFont(u8g2_font_6x10_tr);
|
||||||
|
display_.setCursor(SMETER_TOP_X,SMETER_TOP_Y+4);
|
||||||
|
display_.setDrawColor(WHITE);
|
||||||
|
display_.print(SMETER_REPLACEMENT_TEXT);
|
||||||
|
#endif
|
||||||
|
/* Frequency dot */
|
||||||
|
display_.drawDisc(FREQ_DOT_TEXT_POS_X, 35, 2, WHITE);
|
||||||
|
/* Mhz sign */
|
||||||
|
display_.setCursor(MHZ_TEXT_POS_X,24);
|
||||||
|
display_.print(F("M"));
|
||||||
|
display_.setCursor(MHZ_TEXT_POS_X,33);
|
||||||
|
display_.print(F("H"));
|
||||||
|
display_.setCursor(MHZ_TEXT_POS_X,40);
|
||||||
|
display_.print(F("z"));
|
||||||
|
/* 2 lines separation between informations */
|
||||||
|
display_.drawHLine(H_LINE_POS_X, 16, H_LINE_WIDTH);
|
||||||
|
display_.drawHLine(H_LINE_POS_X, 40, H_LINE_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::clear()
|
||||||
|
{
|
||||||
|
display_.clearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::display()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
display_.sendBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::setFreq(uint32_t _freq, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static uint16_t MAX_FREQ_STR_LENGTH PROGMEM = 8; /* 30000000*/
|
||||||
|
char str[MAX_FREQ_STR_LENGTH + 1] = {0};
|
||||||
|
char big_str[4] = {0};
|
||||||
|
snprintf(str, MAX_FREQ_STR_LENGTH + 1, "%08ld", _freq);
|
||||||
|
strncpy (big_str, str, 2 * sizeof(char));
|
||||||
|
display_.setFont(u8g2_font_crox5hb_tr);
|
||||||
|
display_.setCursor(FREQ_DECIMAL_TEXT_POS_X,FREQ_TEXT_POS_Y);
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
display_.print(big_str);
|
||||||
|
display_.setCursor(FREQ_FRACTIONNAL_TEXT_POS_X,FREQ_TEXT_POS_Y);
|
||||||
|
display_.print(str + 2 * sizeof(char));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::setCursorPos(int _position, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int16_t CURSOR_TEXT_POS_Y PROGMEM = 37;
|
||||||
|
const static int16_t CURSOR_DECIMAL_TEXT_POS_X PROGMEM = 17;
|
||||||
|
const static int16_t CURSOR_FRACTIONAL_TEXT_POS_X PROGMEM = FREQ_DECIMAL_TEXT_POS_X + 35;
|
||||||
|
const static int16_t CURSOR_WIDTH PROGMEM = 10;
|
||||||
|
const static int16_t CURSOR_HEIGHT PROGMEM = 2;
|
||||||
|
const static int16_t CURSOR_SHIFT PROGMEM = 14;
|
||||||
|
int16_t x;
|
||||||
|
if(CURSOR_POS_NONE == _position) return;
|
||||||
|
if(CURSOR_POS_FREQ_DIG7 == _position)
|
||||||
|
{
|
||||||
|
x = CURSOR_DECIMAL_TEXT_POS_X;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = CURSOR_FRACTIONAL_TEXT_POS_X +
|
||||||
|
(CURSOR_POS_FREQ_DIG6 - _position) * CURSOR_SHIFT;
|
||||||
|
}
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
display_.drawBox(x, CURSOR_TEXT_POS_Y, CURSOR_WIDTH, CURSOR_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::setModulation(int _modulation, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int16_t MOD_TEXT_POS_X PROGMEM = 70;
|
||||||
|
const static int16_t MOD_TEXT_POS_Y PROGMEM = 64;
|
||||||
|
display_.setFont(u8g2_font_crox5hb_tr);
|
||||||
|
display_.setCursor(MOD_TEXT_POS_X,MOD_TEXT_POS_Y);
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
switch (_modulation)
|
||||||
|
{
|
||||||
|
case MOD_CW:
|
||||||
|
display_.print(F(" CW"));
|
||||||
|
break;
|
||||||
|
case MOD_AM:
|
||||||
|
display_.print(F(" AM"));
|
||||||
|
break;
|
||||||
|
case MOD_FM:
|
||||||
|
display_.print(F(" FM"));
|
||||||
|
break;
|
||||||
|
case MOD_USB:
|
||||||
|
display_.print(F("USB"));
|
||||||
|
break;
|
||||||
|
case MOD_LSB:
|
||||||
|
default:
|
||||||
|
display_.print(F("LSB"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::setCibiChannel(int _channel, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int16_t CIBI_CHANNEL_TEXT_POS_X PROGMEM = 16;
|
||||||
|
const static int16_t CIBI_CHANNEL_TEXT_POS_Y PROGMEM = 64;
|
||||||
|
char str[3] = {0};
|
||||||
|
if(-1 != _channel)
|
||||||
|
{
|
||||||
|
display_.setFont(u8g2_font_crox5hb_tr);
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
if(_channel < 10)
|
||||||
|
display_.setCursor(CIBI_CHANNEL_TEXT_POS_X + 14, CIBI_CHANNEL_TEXT_POS_Y);
|
||||||
|
else
|
||||||
|
display_.setCursor(CIBI_CHANNEL_TEXT_POS_X, CIBI_CHANNEL_TEXT_POS_Y);
|
||||||
|
snprintf(str, sizeof(str), "%d", _channel);
|
||||||
|
display_.print(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::setCibiChannelBis(bool _bis, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int16_t CIBI_CHANNEL_BIS_TEXT_POS_X PROGMEM = 45;
|
||||||
|
const static int16_t CIBI_CHANNEL_BIS_POS_Y PROGMEM = 50;
|
||||||
|
if(_bis)
|
||||||
|
{
|
||||||
|
display_.setFont(u8g2_font_6x10_tr);
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
display_.setCursor(CIBI_CHANNEL_BIS_TEXT_POS_X, CIBI_CHANNEL_BIS_POS_Y);
|
||||||
|
display_.print(F("bis"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::setCibiBand(int _band, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int CIBI_BAND_NORMAL PROGMEM = 3;
|
||||||
|
if(CIBI_BAND_NORMAL == _band) return;
|
||||||
|
int deviation = CIBI_BAND_NORMAL - _band;
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
for(int i = 0; i < abs(deviation); i++)
|
||||||
|
{
|
||||||
|
display_.drawHLine(7, 58 - i*6, 5);
|
||||||
|
}
|
||||||
|
if(deviation < 0)
|
||||||
|
{
|
||||||
|
/* + signs */
|
||||||
|
for(int i = 0; i < abs(deviation); i++)
|
||||||
|
{
|
||||||
|
display_.drawVLine(9, 56 - i*6, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CibiDisplay::setBand(uint32_t _freq, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int16_t BAND_TEXT_POS_X PROGMEM = FREQ_DECIMAL_TEXT_POS_X;
|
||||||
|
const static int16_t BAND_TEXT_POS_Y PROGMEM = 64;
|
||||||
|
display_.setFont(u8g2_font_crox5hb_tr);
|
||||||
|
display_.setCursor(BAND_TEXT_POS_X,BAND_TEXT_POS_Y);
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
if(135700 <=_freq && _freq <= 137800)
|
||||||
|
{
|
||||||
|
/* For this band do not print 'm' to earn on string's lenght */
|
||||||
|
display_.print(F("2222"));
|
||||||
|
}
|
||||||
|
else if(472000 <=_freq && _freq <= 479000)
|
||||||
|
{
|
||||||
|
display_.print(F("630m"));
|
||||||
|
}
|
||||||
|
else if(1800000 <=_freq && _freq <= 2000000)
|
||||||
|
{
|
||||||
|
display_.print(F("160m"));
|
||||||
|
}
|
||||||
|
else if(3500000 <= _freq && _freq <= 4000000)
|
||||||
|
{
|
||||||
|
display_.print(F("80m"));
|
||||||
|
}
|
||||||
|
else if(5351500 <= _freq && _freq <= 5366500)
|
||||||
|
{
|
||||||
|
display_.print(F("60m"));
|
||||||
|
}
|
||||||
|
else if(7000000 <= _freq && _freq <= 7300000)
|
||||||
|
{
|
||||||
|
display_.print(F("40m"));
|
||||||
|
}
|
||||||
|
else if(10100000 <= _freq && _freq <= 10150000)
|
||||||
|
{
|
||||||
|
display_.print(F("30m"));
|
||||||
|
}
|
||||||
|
else if(14000000 <= _freq && _freq <= 14350000)
|
||||||
|
{
|
||||||
|
display_.print(F("20m"));
|
||||||
|
}
|
||||||
|
else if(18068000 <= _freq && _freq <= 18168000)
|
||||||
|
{
|
||||||
|
display_.print(F("17m"));
|
||||||
|
}
|
||||||
|
else if(21000000 <= _freq && _freq <= 21450000)
|
||||||
|
{
|
||||||
|
display_.print(F("15m"));
|
||||||
|
}
|
||||||
|
else if(24890000 <= _freq && _freq <= 24990000)
|
||||||
|
{
|
||||||
|
display_.print(F("12m"));
|
||||||
|
}
|
||||||
|
else if(28000000 <= _freq && _freq <= 29700000)
|
||||||
|
{
|
||||||
|
display_.print(F("10m"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
display_.print(F("OOB"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SMETER_DISPLAY
|
||||||
|
void CibiDisplay::setSMeter(int _signal)
|
||||||
|
{
|
||||||
|
// cursor
|
||||||
|
display_.setDrawColor(BLACK);
|
||||||
|
display_.drawBox(12, 11, 116, 4);
|
||||||
|
display_.setDrawColor(WHITE);
|
||||||
|
for(int index = 0; index < _signal && index < 21; index++)
|
||||||
|
{
|
||||||
|
display_.drawBox(12 + index * 5, 11, 4, 4);
|
||||||
|
}
|
||||||
|
display();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void CibiDisplay::setTx(bool _tx)
|
||||||
|
{
|
||||||
|
// invert black and white of the displayed frequency in TX
|
||||||
|
const static int16_t H_LINE_WIDTH PROGMEM = 118;
|
||||||
|
const static int16_t H_LINE_POS_X PROGMEM = 0;
|
||||||
|
const static int16_t FREQ_DOT_TEXT_POS_X PROGMEM = 32;
|
||||||
|
display_.setDrawColor((_tx? WHITE : BLACK));
|
||||||
|
display_.drawBox(H_LINE_POS_X, 17, H_LINE_WIDTH, 23);
|
||||||
|
}
|
||||||
307
src/config.cpp
Normal file
307
src/config.cpp
Normal file
|
|
@ -0,0 +1,307 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Vincent Hervieux vincent.hervieux@gmail.com
|
||||||
|
* All rights reserved.
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the author Vincent Hervieux, nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "vfo.h"
|
||||||
|
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
|
const static uint32_t EEPROM_HEADER PROGMEM = 0xDEADBEEF;
|
||||||
|
const static uint32_t DEFAULT_CIBI_FREQ PROGMEM = 27555000;
|
||||||
|
const static uint32_t DEFAULT_CIBI_MIN_FREQ PROGMEM = 25000000;
|
||||||
|
const static uint32_t DEFAULT_CIBI_MAX_FREQ PROGMEM = 30000000;
|
||||||
|
const static uint32_t DEFAULT_FREQ_STEP_INC PROGMEM = 5000;
|
||||||
|
/* On superstar 3900 and derivated:
|
||||||
|
- reference oscillator is at 10240KHz
|
||||||
|
- FI is either 10695KHz(CW,AM,FM), 10692.5KHz(USB), 10697.5KHz(LSB) */
|
||||||
|
const static uint32_t DEFAULT_FI_FREQ_AM PROGMEM = 10695000;
|
||||||
|
const static uint32_t DEFAULT_FI_FREQ_USB PROGMEM = 10692500;
|
||||||
|
const static uint32_t DEFAULT_FI_FREQ_LSB PROGMEM = 10697500;
|
||||||
|
const static int32_t DEFAULT_VFO_ADJ PROGMEM = 0;
|
||||||
|
const static int32_t DEFAULT_CLARIFIER_ADJ PROGMEM = 0;
|
||||||
|
const static int32_t DEFAULT_SMETER_ADJ PROGMEM = 0;
|
||||||
|
Config::Config(Input &_input, U8G2 &_display, DDS &_dds):
|
||||||
|
context_({
|
||||||
|
.eeprom_header = EEPROM_HEADER,
|
||||||
|
.cibi_frequency = DEFAULT_CIBI_FREQ,
|
||||||
|
.cibi_min_freq = DEFAULT_CIBI_MIN_FREQ,
|
||||||
|
.cibi_max_freq = DEFAULT_CIBI_MAX_FREQ,
|
||||||
|
.freq_step_inc = DEFAULT_FREQ_STEP_INC,
|
||||||
|
.fi_am = DEFAULT_FI_FREQ_AM,
|
||||||
|
.fi_usb = DEFAULT_FI_FREQ_USB,
|
||||||
|
.fi_lsb = DEFAULT_FI_FREQ_LSB,
|
||||||
|
.vfo_adj = DEFAULT_VFO_ADJ,
|
||||||
|
.clarifier_adj = DEFAULT_CLARIFIER_ADJ,
|
||||||
|
.smeter_adj = DEFAULT_SMETER_ADJ
|
||||||
|
}),
|
||||||
|
input_(_input),
|
||||||
|
dds_(_dds),
|
||||||
|
current_cursor_pos_(CURSOR_POS_NONE),
|
||||||
|
current_menu_index_(CONFIG_CIBI_FREQ),
|
||||||
|
current_value_(&context_.cibi_frequency)
|
||||||
|
{
|
||||||
|
view_ = new ConfigDisplay(_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::Config(const Config& _config) :
|
||||||
|
context_({
|
||||||
|
.eeprom_header = _config.context_.eeprom_header,
|
||||||
|
.cibi_frequency = _config.context_.cibi_frequency,
|
||||||
|
.cibi_min_freq = _config.context_.cibi_min_freq,
|
||||||
|
.cibi_max_freq = _config.context_.cibi_max_freq,
|
||||||
|
.freq_step_inc = _config.context_.freq_step_inc,
|
||||||
|
.fi_am = _config.context_.fi_am,
|
||||||
|
.fi_usb = _config.context_.fi_usb,
|
||||||
|
.fi_lsb = _config.context_.fi_lsb,
|
||||||
|
.vfo_adj = _config.context_.vfo_adj,
|
||||||
|
.clarifier_adj = _config.context_.clarifier_adj,
|
||||||
|
.smeter_adj = _config.context_.smeter_adj,
|
||||||
|
}),
|
||||||
|
input_(_config.input_),
|
||||||
|
dds_(_config.dds_),
|
||||||
|
view_(_config.view_),
|
||||||
|
current_cursor_pos_(_config.current_cursor_pos_),
|
||||||
|
current_menu_index_(_config.current_menu_index_),
|
||||||
|
current_value_(_config.current_value_)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::~Config()
|
||||||
|
{
|
||||||
|
delete view_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::loop(bool _update_display)
|
||||||
|
{
|
||||||
|
bool update = _update_display;
|
||||||
|
uint32_t freq_step = 0;
|
||||||
|
int increment = 0;
|
||||||
|
if(input_.buttonClicked())
|
||||||
|
{
|
||||||
|
update = true;
|
||||||
|
current_cursor_pos_++;
|
||||||
|
if(current_cursor_pos_ >= CURSOR_POS_MAX)
|
||||||
|
{
|
||||||
|
current_cursor_pos_ = CURSOR_POS_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freq_step = quick_pow10(current_cursor_pos_-1);
|
||||||
|
increment = (int)input_.getEncoderIncrement();
|
||||||
|
if(increment)
|
||||||
|
{
|
||||||
|
update = true;
|
||||||
|
if(CURSOR_POS_NONE == current_cursor_pos_)
|
||||||
|
{
|
||||||
|
/* change between menu items */
|
||||||
|
current_menu_index_ += increment;
|
||||||
|
|
||||||
|
if (current_menu_index_ >= CONFIG_MAX)
|
||||||
|
{
|
||||||
|
current_menu_index_ = 0;
|
||||||
|
}
|
||||||
|
else if (current_menu_index_ < 0)
|
||||||
|
{
|
||||||
|
current_menu_index_ = CONFIG_MAX - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* change displayed item value */
|
||||||
|
switch (current_menu_index_)
|
||||||
|
{
|
||||||
|
case CONFIG_CIBI_FREQ:
|
||||||
|
current_value_ = &context_.cibi_frequency;
|
||||||
|
break;
|
||||||
|
case CONFIG_CIBI_MIN_FREQ:
|
||||||
|
current_value_ = &context_.cibi_min_freq;
|
||||||
|
break;
|
||||||
|
case CONFIG_CIBI_MAX_FREQ:
|
||||||
|
current_value_ = &context_.cibi_max_freq;
|
||||||
|
break;
|
||||||
|
case CONFIG_FREQ_STEP:
|
||||||
|
current_value_ = &context_.freq_step_inc;
|
||||||
|
break;
|
||||||
|
case CONFIG_FI_AM:
|
||||||
|
current_value_ = &context_.fi_am; /* FI AM/FM/CW */
|
||||||
|
break;
|
||||||
|
case CONFIG_FI_USB:
|
||||||
|
current_value_ = &context_.fi_usb; /* FI USB */
|
||||||
|
break;
|
||||||
|
case CONFIG_FI_LSB:
|
||||||
|
current_value_ = &context_.fi_lsb; /* FI LSB */
|
||||||
|
break;
|
||||||
|
case CONFIG_VFO_ADJ:
|
||||||
|
current_value_ = (uint32_t*)&context_.vfo_adj;
|
||||||
|
break;
|
||||||
|
case CONFIG_CLARIFIER_ADJ:
|
||||||
|
current_value_ = (uint32_t*)&context_.clarifier_adj;
|
||||||
|
break;
|
||||||
|
case CONFIG_SMETER_ADJ:
|
||||||
|
current_value_ = (uint32_t*)&context_.smeter_adj;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((current_menu_index_ != CONFIG_VFO_ADJ) &&
|
||||||
|
(current_menu_index_ != CONFIG_CLARIFIER_ADJ) &&
|
||||||
|
(current_menu_index_ != CONFIG_SMETER_ADJ) &&
|
||||||
|
(increment < 0) &&
|
||||||
|
(freq_step * abs(increment)) > (*current_value_))
|
||||||
|
{
|
||||||
|
/* avoid negative values */
|
||||||
|
(*current_value_) = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*current_value_) += ((uint32_t)increment * freq_step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(update)
|
||||||
|
{
|
||||||
|
view_->clear();
|
||||||
|
|
||||||
|
if(CURSOR_POS_NONE == current_cursor_pos_)
|
||||||
|
{
|
||||||
|
view_->highlightTitle(WHITE);
|
||||||
|
view_->setTitle(current_menu_index_, BLACK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
view_->setTitle(current_menu_index_, WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_menu_index_ != CONFIG_VFO_ADJ &&
|
||||||
|
current_menu_index_ != CONFIG_CLARIFIER_ADJ &&
|
||||||
|
current_menu_index_ != CONFIG_SMETER_ADJ)
|
||||||
|
{
|
||||||
|
view_->setValueUint((*current_value_), WHITE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
view_->setValueInt((*(int32_t*)current_value_), WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current_menu_index_ == CONFIG_VFO_ADJ)
|
||||||
|
{
|
||||||
|
/* set si5351 correction here */
|
||||||
|
dds_.setOutputCorrection((*(int32_t*)current_value_));
|
||||||
|
}
|
||||||
|
|
||||||
|
view_->setCursorPos(current_cursor_pos_, WHITE);
|
||||||
|
view_->display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Config::open()
|
||||||
|
{
|
||||||
|
eeprom_read_block((void*)&context_, (void*)0, sizeof(context_t));
|
||||||
|
if(context_.eeprom_header != EEPROM_HEADER)
|
||||||
|
{
|
||||||
|
/* EEPROM first time use */
|
||||||
|
context_.eeprom_header = EEPROM_HEADER;
|
||||||
|
context_.cibi_frequency = DEFAULT_CIBI_FREQ;
|
||||||
|
context_.cibi_min_freq = DEFAULT_CIBI_MIN_FREQ;
|
||||||
|
context_.cibi_max_freq = DEFAULT_CIBI_MAX_FREQ;
|
||||||
|
context_.freq_step_inc = DEFAULT_FREQ_STEP_INC;
|
||||||
|
context_.fi_am = DEFAULT_FI_FREQ_AM;
|
||||||
|
context_.fi_usb = DEFAULT_FI_FREQ_USB;
|
||||||
|
context_.fi_lsb = DEFAULT_FI_FREQ_LSB;
|
||||||
|
context_.vfo_adj = DEFAULT_VFO_ADJ;
|
||||||
|
context_.smeter_adj = DEFAULT_SMETER_ADJ;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Config::save()
|
||||||
|
{
|
||||||
|
eeprom_update_block((const void*)&context_, (void*)0, sizeof(context_t));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Config::getCibiFreq()
|
||||||
|
{
|
||||||
|
return context_.cibi_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Config::getCibiMinFreq()
|
||||||
|
{
|
||||||
|
return context_.cibi_min_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Config::getCibiMaxFreq()
|
||||||
|
{
|
||||||
|
return context_.cibi_max_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Config::getFreqStepIncrement()
|
||||||
|
{
|
||||||
|
return context_.freq_step_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Config::getFiAm()
|
||||||
|
{
|
||||||
|
return context_.fi_am;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Config::getFiUsb()
|
||||||
|
{
|
||||||
|
return context_.fi_usb;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& Config::getFiLsb()
|
||||||
|
{
|
||||||
|
return context_.fi_lsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t& Config::getVFOAdj()
|
||||||
|
{
|
||||||
|
return context_.vfo_adj;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t& Config::getClarifierAdj()
|
||||||
|
{
|
||||||
|
return context_.clarifier_adj;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t& Config::getSMeterAdj()
|
||||||
|
{
|
||||||
|
return context_.smeter_adj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::setCibiFreq(const uint32_t& _freq)
|
||||||
|
{
|
||||||
|
if(_freq != context_.cibi_frequency)
|
||||||
|
{
|
||||||
|
context_.cibi_frequency = _freq;
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
153
src/configdisplay.cpp
Normal file
153
src/configdisplay.cpp
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Vincent Hervieux vincent.hervieux@gmail.com
|
||||||
|
* All rights reserved.
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the author Vincent Hervieux, nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "configdisplay.h"
|
||||||
|
#include "vfo.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
ConfigDisplay::ConfigDisplay(U8G2 &_display):
|
||||||
|
display_(_display)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigDisplay::~ConfigDisplay()
|
||||||
|
{
|
||||||
|
display_.clearDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::init()
|
||||||
|
{
|
||||||
|
display_.drawHLine(0, 15, SCREEN_WIDTH);
|
||||||
|
display_.drawHLine(0, 31, SCREEN_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::clear()
|
||||||
|
{
|
||||||
|
display_.clearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::display()
|
||||||
|
{
|
||||||
|
display_.updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::clearDisplay()
|
||||||
|
{
|
||||||
|
display_.clearDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::setTitle(int _title_index, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int16_t TITLE_POS_X PROGMEM = 4;
|
||||||
|
const static int16_t TITLE_POS_Y PROGMEM = 27;
|
||||||
|
const static int16_t INDEX_POS_X PROGMEM = 35;
|
||||||
|
const static int16_t INDEX_POS_Y PROGMEM = 11;
|
||||||
|
const static int16_t MAX_STR_LENGTH PROGMEM = 20;
|
||||||
|
const static char title_cibi_default_freq[] PROGMEM = "CIBI DEFAULT FREQ.";
|
||||||
|
const static char title_cibi_min_freq[] PROGMEM = " CIBI FREQ. MIN.";
|
||||||
|
const static char title_cibi_max_freq[] PROGMEM = " CIBI FREQ. MAX.";
|
||||||
|
const static char title_freq_step_inc[] PROGMEM = "FREQ. STEP INCREM.";
|
||||||
|
const static char title_fi_am_fm[] PROGMEM = " FI AM/FM";
|
||||||
|
const static char title_fi_usb[] PROGMEM = " FI USB";
|
||||||
|
const static char title_fi_lsb[] PROGMEM = " FI LSB";
|
||||||
|
const static char title_vfo_adj[] PROGMEM = " VFO FREQ. ADJ";
|
||||||
|
const static char title_clarifier_adj[] PROGMEM = "CLARIFIER FREQ. ADJ";
|
||||||
|
const static char title_smeter_adj[] PROGMEM = " S-METER ADJ";
|
||||||
|
const static char* const titles[] PROGMEM = {
|
||||||
|
title_cibi_default_freq,
|
||||||
|
title_cibi_min_freq,
|
||||||
|
title_cibi_max_freq,
|
||||||
|
title_freq_step_inc,
|
||||||
|
title_fi_am_fm,
|
||||||
|
title_fi_usb,
|
||||||
|
title_fi_lsb,
|
||||||
|
title_vfo_adj,
|
||||||
|
title_clarifier_adj,
|
||||||
|
title_smeter_adj
|
||||||
|
};
|
||||||
|
char str[MAX_STR_LENGTH] = {0};
|
||||||
|
int menu_index = _title_index + 1;
|
||||||
|
int menu_items = sizeof(titles) / sizeof(char*);
|
||||||
|
//display_.setFont(u8g2_font_6x10_tr);
|
||||||
|
display_.setFont(u8g2_font_6x12_tr);
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
snprintf(str, MAX_STR_LENGTH + 1, "CONFIG %d/%d :", menu_index, menu_items);
|
||||||
|
display_.setCursor(INDEX_POS_X, INDEX_POS_Y);
|
||||||
|
display_.print(str);
|
||||||
|
display_.setCursor(TITLE_POS_X,TITLE_POS_Y);
|
||||||
|
strcpy_P(str, (char*)pgm_read_word(&(titles[_title_index])));
|
||||||
|
display_.print(str);
|
||||||
|
display_.drawHLine(0, 15, SCREEN_WIDTH);
|
||||||
|
display_.drawHLine(0, 31, SCREEN_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::highlightTitle(uint16_t _color)
|
||||||
|
{
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
display_.drawBox(0, 0, SCREEN_WIDTH, 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::setValueUint(uint32_t _value, uint16_t _color)
|
||||||
|
{
|
||||||
|
char str[MAX_STR_LENGTH] = {0};
|
||||||
|
snprintf(str, MAX_STR_LENGTH + 1, "%08lu", _value);
|
||||||
|
display_.setFont(u8g2_font_7x14B_tf);
|
||||||
|
display_.setCursor(VALUE_POS_X,VALUE_POS_Y);
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
display_.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::setValueInt(int32_t _value, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static uint16_t SIGN_SHIFT PROGMEM = 9;
|
||||||
|
char str[MAX_STR_LENGTH] = {0};
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
if(_value < 0) {
|
||||||
|
display_.drawHLine(VALUE_POS_X - SIGN_SHIFT, VALUE_POS_Y - 8, 5);
|
||||||
|
}
|
||||||
|
snprintf(str, MAX_STR_LENGTH + 1, "%08ld", abs(_value));
|
||||||
|
display_.setFont(u8g2_font_7x14B_tr);
|
||||||
|
display_.setCursor(VALUE_POS_X,VALUE_POS_Y);
|
||||||
|
display_.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigDisplay::setCursorPos(int _position, uint16_t _color)
|
||||||
|
{
|
||||||
|
const static int16_t CURSOR_POS_X PROGMEM = 25;
|
||||||
|
const static int16_t CURSOR_POS_Y PROGMEM = 58;
|
||||||
|
const static int16_t CURSOR_BIG_WIDTH PROGMEM = 8;
|
||||||
|
const static int16_t CURSOR_SHIFT PROGMEM = 9;
|
||||||
|
int16_t x;
|
||||||
|
display_.setDrawColor(_color);
|
||||||
|
if(_position >= CURSOR_POS_FREQ_DIG1 && _position <= CURSOR_POS_FREQ_DIG7)
|
||||||
|
{
|
||||||
|
x = CURSOR_POS_X + (8 - _position) * CURSOR_SHIFT;
|
||||||
|
display_.drawBox(x, CURSOR_POS_Y, CURSOR_BIG_WIDTH, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/dds.cpp
Normal file
100
src/dds.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Vincent Hervieux vincent.hervieux@gmail.com
|
||||||
|
* All rights reserved.
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the author Vincent Hervieux, nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
*** DDS: Direct Digital Synthesis
|
||||||
|
*** The three si5351 clock outputs are square wave
|
||||||
|
***/
|
||||||
|
#include "dds.h"
|
||||||
|
#include "vfo.h"
|
||||||
|
|
||||||
|
DDS::DDS():
|
||||||
|
initialized_(false)
|
||||||
|
{
|
||||||
|
/* initialize stored values */
|
||||||
|
for(int i = 0; i < OUTPUT_MAX; i++)
|
||||||
|
current_freq_[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDS::~DDS()
|
||||||
|
{
|
||||||
|
clockgen_.off();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DDS::init()
|
||||||
|
{
|
||||||
|
if(!initialized_)
|
||||||
|
{
|
||||||
|
/* This lib has no way to know if I2C communication is effective */
|
||||||
|
clockgen_.init(XTALFREQ);
|
||||||
|
/* Set drive current to its maximum */
|
||||||
|
clockgen_.setPower(OUTPUT_FI, SIOUT_8mA);
|
||||||
|
enabled_[OUTPUT_FI] = true;
|
||||||
|
/* 2 mA : FM is weak */
|
||||||
|
/* 4 mA : FM is distorded */
|
||||||
|
/* 6 mA : FM is distorded */
|
||||||
|
/* 8 mA : FM is really distorded - adjust VR5*/
|
||||||
|
clockgen_.setPower(OUTPUT_VFO, SIOUT_8mA);
|
||||||
|
enabled_[OUTPUT_VFO] = true;
|
||||||
|
enabled_[OUTPUT_UNUSED] = false;
|
||||||
|
initialized_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t& DDS::getOutputFreq(output_t _output)
|
||||||
|
{
|
||||||
|
return current_freq_[_output];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DDS::setOutputFreq(output_t _output, uint32_t _frequency)
|
||||||
|
{
|
||||||
|
clockgen_.setFreq(_output, _frequency);
|
||||||
|
/* store the frequency currently used */
|
||||||
|
current_freq_[_output] = _frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DDS::setOutputCorrection(int32_t _correction)
|
||||||
|
{
|
||||||
|
/* set quartz correction */
|
||||||
|
clockgen_.correction(_correction);
|
||||||
|
clockgen_.setFreq(OUTPUT_VFO, current_freq_[OUTPUT_VFO]);
|
||||||
|
clockgen_.setFreq(OUTPUT_FI, current_freq_[OUTPUT_FI]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DDS::enableOutput(output_t _output, bool _enable)
|
||||||
|
{
|
||||||
|
if(_enable && !enabled_[_output])
|
||||||
|
{
|
||||||
|
clockgen_.enable(_output);
|
||||||
|
enabled_[_output] = true;
|
||||||
|
}
|
||||||
|
else if(!_enable && enabled_[_output])
|
||||||
|
{
|
||||||
|
clockgen_.disable(_output);
|
||||||
|
enabled_[_output] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user