/*
|
|
Digital VFO with Rotation Dial
|
|
|
|
File: dial.cpp
|
|
Author: JF3HZB / T.UEBO
|
|
|
|
Created on July 1, 2023
|
|
modyfied on Aug. 7, 2024
|
|
*/
|
|
|
|
#include "dial.hpp"
|
|
|
|
void LCD_setup(void)
|
|
{
|
|
lcd.init();
|
|
lcd.setColorDepth(16);
|
|
//if (lcd.width() < lcd.height()) { lcd.setRotation(lcd.getRotation()^1); }
|
|
//lcd.setRotation(1);
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
sprites[i].setColorDepth(lcd.getColorDepth());
|
|
sprites[i].setFont(&fonts::Font2);
|
|
sprites[i].setTextDatum(textdatum_t::top_right);
|
|
}
|
|
|
|
///*
|
|
int div = 1;
|
|
for (;;)
|
|
{
|
|
sprite_height = (lcd.height() + div - 1) / div;
|
|
bool fail = false;
|
|
for (int i = 0; !fail && i < 2; ++i)
|
|
{
|
|
fail = !sprites[i].createSprite(lcd.width(), sprite_height);
|
|
}
|
|
if (!fail) break;
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
sprites[i].deleteSprite();
|
|
}
|
|
div++;
|
|
}
|
|
//*/
|
|
/*
|
|
int div = 2; //try 1,2,3,4,...
|
|
sprite_height = (lcd.height() + div - 1) / div;
|
|
sprites[0].createSprite(lcd.width(), sprite_height);
|
|
sprites[1].createSprite(lcd.width(), sprite_height);
|
|
*/
|
|
|
|
sp.setColorDepth(16);
|
|
//sp.setFont(&fonts::Font6);
|
|
sp.setFont(&fonts::FreeSansBold18pt7b);
|
|
sp.setTextDatum(textdatum_t::middle_center);
|
|
|
|
lcd.startWrite();
|
|
|
|
#ifdef ST7789
|
|
lcd.writeCommand(0xC6);
|
|
lcd.writeData(0x02);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DIAL::draw(int32_t freq, int yoff)
|
|
{
|
|
int num;
|
|
float numf;
|
|
float zoom_x, zoom_y;
|
|
float angle;
|
|
|
|
freq=abs(freq);
|
|
|
|
#ifdef MODE0
|
|
int xc = lcd.width() / 2 + hoff;
|
|
int yc = voff + top_margin + (std::fmax(radiusMain, radiusSub));
|
|
float aoff = 0;
|
|
#endif
|
|
#ifdef MODE1
|
|
int xc = voff + top_margin + (std::fmax(radiusMain, radiusSub));
|
|
int yc = lcd.height() / 2 + hoff;
|
|
float aoff = -90.0f;
|
|
#endif
|
|
#ifdef MODE2
|
|
int xc = lcd.width() - (voff + top_margin + (std::fmax(radiusMain, radiusSub)) );
|
|
int yc = lcd.height() / 2 + hoff;
|
|
float aoff = 90.0f;
|
|
#endif
|
|
|
|
#ifdef MAIN_UNIT_kHz
|
|
TickResoMain = 10000;
|
|
TickResoSub = 1000;
|
|
#endif
|
|
|
|
if(TickResoSub == 10000) TickResoMain = 100000;
|
|
|
|
|
|
// draw dial Background ---------------------------------------------------------
|
|
#ifdef MODE0
|
|
sprites[flip].fillRect(0, voff-yoff, lcd.width(), lcd.height()-voff, DialBGCol);
|
|
#endif
|
|
#ifdef MODE1
|
|
sprites[flip].fillRect(voff, 0-yoff, lcd.width()-voff, lcd.height(), DialBGCol);
|
|
#endif
|
|
#ifdef MODE2
|
|
sprites[flip].fillRect(0, 0-yoff, lcd.width()-voff, lcd.height(), DialBGCol);
|
|
#endif
|
|
|
|
|
|
// draw Sub dial ----------------------------------------------------------------
|
|
#ifdef REV_DIAL
|
|
angle = -resoSub * (float)( freq % (TickResoSub*10) ) / (float)TickResoSub ;
|
|
#else if
|
|
angle = resoSub * (float)( freq % (TickResoSub*10) ) / (float)TickResoSub ;
|
|
#endif
|
|
|
|
sp.createSprite(1, 1);
|
|
sp.clear(TickSubCol);
|
|
float pvoff;
|
|
if (tnSub<=0) pvoff = -0.5f; else pvoff = 0.5f;
|
|
for (int i = -100; i < 100; i++)
|
|
{
|
|
float a = angle - (float)i * resoSub;
|
|
if (a > 100 || a < -100) continue;
|
|
zoom_x = (i%5 ? tickWSub : ((i % 10) ? tick5WSub : tick10WSub));
|
|
zoom_y = (i%5 ? tickLSub : ((i % 10) ? tick5LSub : tick10LSub));
|
|
sp.setPivot(0, radiusSub / zoom_y + pvoff);
|
|
sp.pushRotateZoomWithAA(&sprites[flip], xc, yc - yoff, a+aoff, zoom_x, zoom_y, 0);
|
|
}
|
|
|
|
// draw Sub number ----------------------------------------------------------------
|
|
zoom_x = font_sizex_sub;
|
|
zoom_y = font_sizey_sub;
|
|
sp.createSprite(60, 28);
|
|
|
|
#ifdef MODE0
|
|
if(tnSub<=0){
|
|
sp.setTextDatum(textdatum_t::top_center);
|
|
sp.setPivot((float)sp.width() / 2, (radiusSub + tnSub) / zoom_y);
|
|
}else{
|
|
sp.setTextDatum(textdatum_t::baseline_center);
|
|
sp.setPivot((float)sp.width() / 2, (radiusSub + tnSub) / zoom_y + (float)sp.height() );
|
|
}
|
|
#endif
|
|
|
|
#ifdef MODE1
|
|
if(tnSub<=0){
|
|
sp.setTextDatum(textdatum_t::middle_left);
|
|
sp.setPivot( (radiusSub + tnSub) / zoom_x, (float)sp.height() / 2);
|
|
}else{
|
|
sp.setTextDatum(textdatum_t::middle_right);
|
|
sp.setPivot( (radiusSub + tnSub) / zoom_x + (float)sp.width(), (float)sp.height() / 2);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MODE2
|
|
if(tnSub<=0){
|
|
sp.setTextDatum(textdatum_t::middle_right);
|
|
sp.setPivot( -(radiusSub + tnSub) / zoom_x + (float)sp.width(), (float)sp.height() / 2);
|
|
}else{
|
|
sp.setTextDatum(textdatum_t::middle_left);
|
|
sp.setPivot( -(radiusSub + tnSub) / zoom_x , (float)sp.height() / 2);
|
|
}
|
|
#endif
|
|
|
|
sp.setTextColor(NumSubCol, TFT_BLACK);
|
|
for (int i = -80; i < 80; i += 10)
|
|
{
|
|
#ifdef REV_DIAL
|
|
float a = angle + (float)i * resoSub;
|
|
#else if
|
|
float a = angle - (float)i * resoSub;
|
|
#endif
|
|
|
|
if (a > 100 || a < -100) continue;
|
|
sp.clear(TFT_BLACK);
|
|
num = (freq/(TickResoSub*10)*10 + i + 1000)*(TickResoSub/1000) % (TickResoMain/100);
|
|
#ifdef MODE0
|
|
if(tnSub<=0) sp.drawNumber( num , sp.width()>>1, 0 );
|
|
else sp.drawNumber( num , sp.width()>>1, sp.height()-1 );
|
|
#endif
|
|
|
|
#ifdef MODE1
|
|
if(tnSub<=0) sp.drawNumber( num , 0, sp.height()>>1 );
|
|
else sp.drawNumber( num , sp.width(), sp.height()>>1 );
|
|
#endif
|
|
|
|
#ifdef MODE2
|
|
if(tnSub<=0) sp.drawNumber( num , sp.width(), sp.height()>>1 );
|
|
else sp.drawNumber( num , 0, sp.height()>>1 );
|
|
#endif
|
|
|
|
sp.pushRotateZoomWithAA(&sprites[flip], xc, yc - yoff, a, zoom_x, zoom_y, 0);
|
|
}
|
|
|
|
|
|
|
|
// draw Main dial -----------------------------------------------------------------------
|
|
#ifdef REV_DIAL
|
|
angle = -resoMain * (float)( freq % (TickResoMain*10) ) / (float)TickResoMain;
|
|
#else if
|
|
angle = resoMain * (float)( freq % (TickResoMain*10) ) / (float)TickResoMain;
|
|
#endif
|
|
|
|
sp.createSprite(1, 1);
|
|
sp.clear(TickMainCol);
|
|
if (tnMain<=0) pvoff = -0.5f; else pvoff = 0.5f;
|
|
for (int i = -100; i < 100; i++)
|
|
{
|
|
float a = angle - (float)i * resoMain;
|
|
if (a > 100 || a < -100) continue;
|
|
zoom_x = (i%5 ? tickWMain : ((i % 10) ? tick5WMain : tick10WMain));
|
|
zoom_y = (i%5 ? tickLMain : ((i % 10) ? tick5LMain : tick10LMain));
|
|
sp.setPivot(0, radiusMain / zoom_y + pvoff);
|
|
sp.pushRotateZoomWithAA(&sprites[flip], xc, yc - yoff, a+aoff, zoom_x, zoom_y, 0);
|
|
}
|
|
|
|
|
|
|
|
// draw Main number ----------------------------------------------------------------------
|
|
zoom_x = font_sizex_main;
|
|
zoom_y = font_sizey_main;
|
|
sp.createSprite(85, 28);
|
|
|
|
#ifdef MODE0
|
|
if(tnMain<=0){
|
|
sp.setTextDatum(textdatum_t::top_center);
|
|
sp.setPivot((float)sp.width() / 2, (radiusMain + tnMain)/zoom_y );
|
|
}else{
|
|
sp.setTextDatum(textdatum_t::baseline_center);
|
|
sp.setPivot((float)sp.width() / 2, (radiusMain + tnMain)/zoom_y + (float)sp.height() );
|
|
}
|
|
#endif
|
|
|
|
#ifdef MODE1
|
|
if(tnMain<=0){
|
|
sp.setTextDatum(textdatum_t::middle_left);
|
|
sp.setPivot( (radiusMain + tnMain) / zoom_x , (float)sp.height() / 2);
|
|
}else{
|
|
sp.setTextDatum(textdatum_t::middle_right);
|
|
sp.setPivot( (radiusMain + tnMain) / zoom_x + (float)sp.width(), (float)sp.height() / 2);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MODE2
|
|
if(tnMain<=0){
|
|
sp.setTextDatum(textdatum_t::middle_right);
|
|
sp.setPivot( -(radiusMain + tnMain) / zoom_x + (float)sp.width(), (float)sp.height() / 2);
|
|
}else{
|
|
sp.setTextDatum(textdatum_t::middle_left);
|
|
sp.setPivot( -(radiusMain + tnMain) / zoom_x , (float)sp.height() / 2);
|
|
}
|
|
#endif
|
|
|
|
sp.setTextColor(NumMainCol, TFT_BLACK);
|
|
for (int i = -80; i < 80; i += 10)
|
|
{
|
|
#ifdef REV_DIAL
|
|
float a = angle + (float)i * resoMain;
|
|
#else if
|
|
float a = angle - (float)i * resoMain;
|
|
#endif
|
|
|
|
if (a > 100 || a < -100) continue;
|
|
sp.clear(TFT_BLACK);
|
|
|
|
#ifdef MAIN_UNIT_kHz
|
|
num = abs(freq)/(100000)*100 + i*10;
|
|
#else if
|
|
numf = ( abs(freq)/(TickResoMain*10) + i*0.1f ) * 1e-5 * TickResoMain;
|
|
#endif
|
|
|
|
#ifdef MODE0
|
|
if(tnMain<=0){
|
|
#ifdef MAIN_UNIT_kHz
|
|
if(num>=0) sp.drawNumber( num, sp.width()>>1, 0);
|
|
#else if
|
|
if(numf>=-0.01) sp.drawFloat( fabs(numf), 1, sp.width()>>1, 0);
|
|
#endif
|
|
}else{
|
|
#ifdef MAIN_UNIT_kHz
|
|
if(num>=0) sp.drawNumber( num, sp.width()>>1, sp.height()-1);
|
|
#else if
|
|
if(numf>=-0.01) sp.drawFloat( fabs(numf), 1, sp.width()>>1, sp.height()-1);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef MODE1
|
|
if(tnMain<=0){
|
|
#ifdef MAIN_UNIT_kHz
|
|
if(num>=0) sp.drawNumber( num, 0, sp.height()>>1);
|
|
#else if
|
|
if(numf>=-0.01) sp.drawFloat( fabs(numf), 1, 0, sp.height()>>1 );
|
|
#endif
|
|
}else{
|
|
#ifdef MAIN_UNIT_kHz
|
|
if(num>=0) sp.drawNumber( num, sp.width(), sp.height()>>1 );
|
|
#else if
|
|
if(numf>=-0.01) sp.drawFloat( fabs(numf), 1, sp.width(), sp.height()>>1 );
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef MODE2
|
|
if(tnMain<=0){
|
|
#ifdef MAIN_UNIT_kHz
|
|
if(num>=0) sp.drawNumber( num, sp.width(), sp.height()>>1 );
|
|
#else if
|
|
if(numf>=-0.01) sp.drawFloat( fabs(numf), 1, sp.width(), sp.height()>>1 );
|
|
#endif
|
|
}else{
|
|
#ifdef MAIN_UNIT_kHz
|
|
if(num>=0) sp.drawNumber( num, 0, sp.height()>>1 );
|
|
#else if
|
|
if(numf>=-0.01) sp.drawFloat( fabs(numf), 1, 0, sp.height()>>1 );
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
sp.pushRotateZoomWithAA(&sprites[flip], xc, yc - yoff, a, zoom_x, zoom_y, 0);
|
|
}
|
|
|
|
sp.setTextDatum(textdatum_t::middle_center);
|
|
|
|
|
|
// Lamp emulation
|
|
std::uint16_t* rawbuf = (std::uint16_t*)sprites[flip].getBuffer();
|
|
int xr;
|
|
int yr;
|
|
float distance;
|
|
float rlamp;
|
|
uint16_t pixdata;
|
|
float r, g, b;
|
|
float d_max, d_min;
|
|
|
|
for (int y = 0; y < sprite_height; y++)
|
|
{
|
|
std::uint16_t* rawline = &rawbuf[y * lcd.width()];
|
|
for (int x = 0; x < lcd.width(); x++)
|
|
{
|
|
|
|
if(rawline[x]!=0)
|
|
{
|
|
xr=abs(x-lampX);
|
|
yr=abs(y+yoff-lampY);
|
|
if(xr>yr)
|
|
{
|
|
d_max=(float)xr;
|
|
d_min=(float)yr;
|
|
} else {
|
|
d_max=(float)yr;
|
|
d_min=(float)xr;
|
|
}
|
|
if( 2 * d_max < 5 * d_min )
|
|
{
|
|
distance = 0.8437500f * d_max + 0.5556641f * d_min;
|
|
} else {
|
|
distance = 0.9921875f * d_max + 0.1855469f * d_min;
|
|
}
|
|
|
|
|
|
rlamp = 1.0f - (depth_LE_effect*0.001)*(distance-lampD);
|
|
if(rlamp<1.0f)
|
|
{
|
|
if(rlamp<=0)
|
|
{
|
|
rawline[x] = 0;
|
|
}
|
|
else
|
|
{
|
|
pixdata = rawline[x];
|
|
pixdata = pixdata>>8 | pixdata<<8;
|
|
r = rlamp*(float)( (pixdata&0xF800)>>8 );
|
|
g = rlamp*(float)( (pixdata&0x07E0)>>3 );
|
|
b = rlamp*(float)( (pixdata&0x001F)<<3 );
|
|
rawline[x] = lcd.swap565((uint8_t)(r+0.5f), (uint8_t)(g+0.5f), (uint8_t)(b+0.5f) );
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//Serial.println(rawbuf[0]);
|
|
|
|
|
|
|
|
// draw Pointer --------------------------------------------------------------------------------------------------
|
|
sp.createSprite(1, 1);
|
|
sp.clear(PointerCol);
|
|
sp.setPivot(0, -0.5f);
|
|
#ifdef MODE0
|
|
sp.pushRotateZoomWithAA(&sprites[flip], xc, voff-yoff, 0, WidthPointer, LenPointer, 0);
|
|
#endif
|
|
#ifdef MODE1
|
|
sp.pushRotateZoomWithAA(&sprites[flip], voff, yc-yoff, -90, WidthPointer, LenPointer, 0);
|
|
#endif
|
|
#ifdef MODE2
|
|
sp.pushRotateZoomWithAA(&sprites[flip], lcd.width()-voff, yc-yoff, 90, WidthPointer, LenPointer, 0);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|