Skip to content

Instantly share code, notes, and snippets.

@shabaz123
Created July 11, 2024 05:44
Show Gist options
  • Save shabaz123/66665fe08701d78dc9f2d1349c501277 to your computer and use it in GitHub Desktop.
Save shabaz123/66665fe08701d78dc9f2d1349c501277 to your computer and use it in GitHub Desktop.
Starmap on ESP32 (work in progress)
// StarmapProjectESP32.ino
// rev 0.1 - June 2024 - shabaz
// This code implements a star chart in an ESP32
// ******** includes ********
#include <Starmap.h>
#include <Flash_SST25VF.h>
//#include <Teseo.h>
#include <Arduino_GFX_Library.h>
// ******** defines ********
#define NO_GPS
#define FOREVER 1
#define DELAY_MS delay
// time offset, example: 1 hour ahead of UTC (e.g. British Summer Time) is 1
#define DISPLAYED_TIME_OFFSET 1
// GPS (uses Serial1, requires an Arduino which supports that)
// Note: set GNSS_BAUDRATE to 9600 for a new GPS module.
// I'm using 115200 because I've configured my GPS module to that baudrate
#define GNSS_BAUDRATE 115200
// screen dimensions
#define TFT_W 480
#define TFT_H 480
// default co-ordinates, lat: deg N, lon: deg W
#define DEFAULT_LAT 47.0
#define DEFAULT_LON 122.0
// hardware SPI CS must be set to the same as TFT_CS
#define FLASH_CS A0
// Flash memory command to read data
#define FLASH_READ 0x03
#define DATA_BUF_SIZE 256
// ***** flags *********
#define FLAG_USA 0
#define FLAG_EU 1
#define FLAG_CHINA 2
#define FLAG_RUSSIA 3
// flag colors in RGB565 format
#define FLAG_BORDER 0x0000
// USA
#define US_RED 0xf800
#define US_WHITE 0xffff
#define US_BLUE 0x001f
// Russia
#define RU_RED 0xf800
#define RU_WHITE 0xffff
#define RU_BLUE 0x001f
// China
#define CN_RED 0xf800
#define CN_YELLOW 0xffe0
// EU
#define EU_BLUE 0x001f
#define EU_YELLOW 0xffe0
// flag icons
const uint16_t flag_usa[7][7] = {
{US_RED, US_WHITE, US_RED, US_BLUE, US_BLUE, US_BLUE, US_BLUE},
{US_RED, US_WHITE, US_RED, US_BLUE, US_WHITE, US_BLUE, US_WHITE},
{US_RED, US_WHITE, US_RED, US_BLUE, US_BLUE, US_BLUE, US_BLUE},
{US_RED, US_WHITE, US_RED, US_BLUE, US_WHITE, US_BLUE, US_WHITE},
{US_RED, US_WHITE, US_RED, US_WHITE, US_RED, US_WHITE, US_RED},
{US_RED, US_WHITE, US_RED, US_WHITE, US_RED, US_WHITE, US_RED},
{US_RED, US_WHITE, US_RED, US_WHITE, US_RED, US_WHITE, US_RED}
};
const uint16_t flag_russia[7][6] = {
{RU_RED, RU_RED, RU_BLUE, RU_BLUE, RU_WHITE, RU_WHITE},
{RU_RED, RU_RED, RU_BLUE, RU_BLUE, RU_WHITE, RU_WHITE},
{RU_RED, RU_RED, RU_BLUE, RU_BLUE, RU_WHITE, RU_WHITE},
{RU_RED, RU_RED, RU_BLUE, RU_BLUE, RU_WHITE, RU_WHITE},
{RU_RED, RU_RED, RU_BLUE, RU_BLUE, RU_WHITE, RU_WHITE},
{RU_RED, RU_RED, RU_BLUE, RU_BLUE, RU_WHITE, RU_WHITE},
{RU_RED, RU_RED, RU_BLUE, RU_BLUE, RU_WHITE, RU_WHITE}
};
const uint16_t flag_china[7][7] = {
{CN_RED, CN_RED, CN_RED, CN_YELLOW, CN_RED, CN_YELLOW, CN_YELLOW},
{CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_YELLOW},
{CN_RED, CN_RED, CN_RED, CN_RED, CN_YELLOW, CN_RED, CN_RED},
{CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_YELLOW},
{CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED},
{CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED},
{CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED, CN_RED}
};
const uint16_t flag_eu[7][7] = {
{EU_BLUE, EU_BLUE, EU_BLUE, EU_YELLOW, EU_BLUE, EU_BLUE, EU_BLUE},
{EU_BLUE, EU_YELLOW, EU_BLUE, EU_BLUE, EU_BLUE, EU_YELLOW, EU_BLUE},
{EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE},
{EU_YELLOW, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_YELLOW},
{EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE, EU_BLUE},
{EU_BLUE, EU_YELLOW, EU_BLUE, EU_BLUE, EU_BLUE, EU_YELLOW, EU_BLUE},
{EU_BLUE, EU_BLUE, EU_BLUE, EU_YELLOW, EU_BLUE, EU_BLUE, EU_BLUE}
};
//10x12 font for N,E,S,W characters only
const uint16_t font10_12[4][12] = {
{0x0fff, 0x0fff, 0x0700, 0x03c0, 0x01e0, 0x0078, 0x003c, 0x000e, 0x0fff, 0x0fff},
{0x0fff, 0x0fff, 0x0c63, 0x0c63, 0x0c63, 0x0c63, 0x0c63, 0x0c63, 0x0c03, 0x0c03},
{0x038c, 0x07ce, 0x0ee7, 0x0c63, 0x0c63, 0x0c63, 0x0c63, 0x0e77, 0x073e, 0x031c},
{0x0f80, 0x0ff8, 0x00ff, 0x0007, 0x007e, 0x007e, 0x0007, 0x00ff, 0x0ff8, 0x0f80}
};
// TFT configuration commands array
static const uint8_t st7701_2_8_aliexpress_operations[] = {
BEGIN_WRITE, WRITE_COMMAND_8, 0xFF, WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, WRITE_C8_D8, 0xEF, 0x08, WRITE_COMMAND_8, 0xFF,
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, WRITE_C8_D16, 0xC0, 0x3B, 0x00, WRITE_C8_D16, 0xC1, 0x10, 0x0C, WRITE_C8_D16, 0xC2, 0x07, 0x0A,
WRITE_C8_D8, 0xC7, 0x04, WRITE_C8_D8, 0xCC, 0x10, WRITE_C8_D8, 0xCD, 0x08, WRITE_COMMAND_8, 0xB0, WRITE_BYTES, 16, 0x05, 0x12, 0x98, 0x0E,
0x0F, 0x07, 0x07, 0x09, 0x09, 0x23, 0x05, 0x52, 0x0F, 0x67, 0x2C, 0x11, WRITE_COMMAND_8, 0xB1, WRITE_BYTES, 16, 0x0B, 0x11, 0x97, 0x0C,
0x12, 0x06, 0x06, 0x08, 0x08, 0x22, 0x03, 0x51, 0x11, 0x66, 0x2B, 0x0F, WRITE_COMMAND_8, 0xFF, WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11,
WRITE_C8_D8, 0xB0, 0x5D, WRITE_C8_D8, 0xB1, 0x3e, WRITE_C8_D8, 0xB2, 0x81, WRITE_C8_D8, 0xB3, 0x80, WRITE_C8_D8, 0xB5, 0x4E,
WRITE_C8_D8, 0xB7, 0x85, WRITE_C8_D8, 0xB8, 0x20, WRITE_C8_D8, 0xC1, 0x78, WRITE_C8_D8, 0xC2, 0x78, WRITE_C8_D8, 0xD0, 0x88,
WRITE_COMMAND_8, 0xE0, WRITE_BYTES, 3, 0x00, 0x00, 0x02, WRITE_COMMAND_8, 0xE1, WRITE_BYTES, 11, 0x06, 0x30, 0x08, 0x30, 0x05, 0x30, 0x07, 0x30,
0x00, 0x33, 0x33, WRITE_COMMAND_8, 0xE2, WRITE_BYTES, 12, 0x11, 0x11, 0x33, 0x33, 0xF4, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00,
WRITE_COMMAND_8, 0xE3, WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, WRITE_C8_D16, 0xE4, 0x44, 0x44, WRITE_COMMAND_8, 0xE5, WRITE_BYTES, 16,
0x0D, 0xF5, 0x30, 0xF0, 0x0F, 0xF7, 0x30, 0xF0, 0x09, 0xF1, 0x30, 0xF0, 0x0B, 0xF3, 0x30, 0xF0, WRITE_COMMAND_8, 0xE6, WRITE_BYTES, 4,
0x00, 0x00, 0x11, 0x11, WRITE_C8_D16, 0xE7, 0x44, 0x44, WRITE_COMMAND_8, 0xE8, WRITE_BYTES, 16, 0x0C, 0xF4, 0x30, 0xF0, 0x0E, 0xF6, 0x30, 0xF0,
0x08, 0xF0, 0x30, 0xF0, 0x0A, 0xF2, 0x30, 0xF0, WRITE_C8_D16, 0xE9, 0x36, 0x01, WRITE_COMMAND_8, 0xEB, WRITE_BYTES, 7, 0x00, 0x01, 0xE4, 0xE4,
0x44, 0x88, 0x40, WRITE_COMMAND_8, 0xED, WRITE_BYTES, 16, 0xFF, 0x10, 0xAF, 0x76, 0x54, 0x2B, 0xCF, 0xFF, 0xFF, 0xFC, 0xB2, 0x45,
0x67, 0xFA, 0x01, 0xFF, WRITE_COMMAND_8, 0xEF, WRITE_BYTES, 6, 0x08, 0x08, 0x08, 0x45, 0x3F, 0x54, WRITE_COMMAND_8, 0xFF, WRITE_BYTES, 5,
0x77, 0x01, 0x00, 0x00, 0x00, WRITE_COMMAND_8, 0x11, END_WRITE, DELAY, 120, BEGIN_WRITE, WRITE_C8_D8, 0x3A, 0x66, WRITE_C8_D8, 0x36, 0x00,
WRITE_C8_D8, 0x35, 0x00, WRITE_COMMAND_8, 0x29, END_WRITE};
#define NORTH_SYMBOL 0
#define EAST_SYMBOL 1
#define SOUTH_SYMBOL 2
#define WEST_SYMBOL 3
#define NESW_COLOR 0xf800
// misc
#ifndef PI
#define PI 3.14159265358979323846
#endif
// ***** class based on Starmap ******
class SM : public Starmap {
// you need to implement plot_pixel and/or draw_line
// if you want text output, then implement either plot_pixel or text_out
void plot_pixel(uint16_t color, int x, int y);
void draw_line(int x0, int y0, int x1, int y1, uint16_t color);
// optionally you can also implement text_out
// void text_out(int x, int y, char* lab, unsigned char len, char type);
// if star plotting is required, then storage_read is implemented
int storage_read(uint32_t addr, char* data, uint16_t len);
};
// ***** class based on Flash_SST25VF ********
class Flash : public Flash_SST25VF
{
public:
Flash(uint8_t pin_CS) : Flash_SST25VF(pin_CS) {};
// override/release functions to play nice with
// other devices on the SPI bus that may be using
// the default CS pin
void override_default_cs(); // override the default CS pin if required
void release_default_cs(); // release the default CS pin if required
};
// ******** global variables ********
SM starmap;
Flash flash(FLASH_CS); // create an instance of the Flash class
#ifndef NO_GPS
Teseo gnss;
#endif
Arduino_XCA9554SWSPI *expander = new Arduino_XCA9554SWSPI(PCA_TFT_RESET, PCA_TFT_CS, PCA_TFT_SCK, PCA_TFT_MOSI, &Wire, 0x3F);
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(TFT_DE, TFT_VSYNC, TFT_HSYNC, TFT_PCLK, TFT_R1, TFT_R2, TFT_R3, TFT_R4, TFT_R5,
TFT_G0, TFT_G1, TFT_G2, TFT_G3, TFT_G4, TFT_G5, TFT_B1, TFT_B2, TFT_B3, TFT_B4, TFT_B5, 1 , 50, 2, 44, 1, 16, 2, 18);
Arduino_RGB_Display *gfx = new Arduino_RGB_Display(480, 480, rgbpanel, 0 /* rotation */, true /* auto_flush */,
expander, GFX_NOT_DEFINED /* RST */, st7701_2_8_aliexpress_operations, sizeof(st7701_2_8_aliexpress_operations));
double mag;
rect_s screen_rect;
tm_t tm;
char first_fix_done = 0;
char flash_present = 0; // set to 1 if the flash is present and valid
char flash_data[DATA_BUF_SIZE]; // buffer used for storing data read from Flash
uint32_t flash_data_addr; // starting address of the contents of flash_data
uint32_t starmap_update_period = 5 * 60000; // multiply by 60000 to convert minutes to milliseconds
uint8_t sat_id[24]; // buffer to store the satellite ID
// ******** function prototypes ************
void draw_flag(int x, int y, int flagtype);
void ccw_azimuth_elevation_to_xy(double az, double el, int *x, int *y);
void get_first_fix(void);
#ifndef NO_GPS
int copy_gnss_time_to_starmap(void);
int copy_gnss_loc_to_starmap(void);
#endif
void invalidate_displayed_sat_list(void);
int check_and_add_sat(uint8_t id);
void plot_char_10_12(char c, int x, int y, int color); // only supports N, E, S, W characters
void disp_lat_lon(double lat, double lon, int x, int y, int col);
// ****** flash functions ***********
void Flash::override_default_cs()
{
// comment the line below if the default SPI CS pin is unused by any device
//pinMode(DEFAULT_CS, INPUT_PULLUP);
}
void Flash::release_default_cs()
{
// comment the line below if the default SPI CS pin is unused by any device
//pinMode(DEFAULT_CS, OUTPUT);
}
// ******* plot_pixel function ******
void SM::draw_line(int x0, int y0, int x1, int y1, uint16_t color) {
// sanity check
if (x0<0) x0=0;
if (x1<0) x1=0;
if (y0<0) y0=0;
if (y1<0) y1=0;
if (x0>=TFT_W) x0=TFT_W-1;
if (x1>=TFT_W) x1=TFT_W-1;
if (y0>=TFT_H) y0=TFT_H-1;
if (y1>=TFT_H) y1=TFT_H-1;
// handle your TFT here
gfx->drawLine(x0, y0, x1, y1, color);
}
void SM::plot_pixel(uint16_t color, int x, int y) {
// sanity check
if (x<0) x=0;
if (y<0) y=0;
if (x>=TFT_W) x=TFT_W-1;
if (y>=TFT_H) y=TFT_H-1;
// handle your TFT here
gfx->drawPixel(x, y, color);
}
// ******* storage_read function *******
int SM::storage_read(uint32_t addr, char* data, uint16_t len){
// read from Flash memory
flash.flash_read(addr, data, len);
return 0;
}
// ******** setup() function ********
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
// TFT setup
#ifdef GFX_EXTRA_PRE_INIT
GFX_EXTRA_PRE_INIT();
#endif
Wire.setClock(1000000); // speed up I2C
if (!gfx->begin()) {
Serial.println("gfx->begin() failed!");
}
gfx->fillScreen(BLACK);
// GPS setup
#ifndef NO_GPS
gnss.init(GNSS_BAUDRATE);
#endif
// starmap setup
mag = 5; // render magnitude level
screen_rect.left = 0;
screen_rect.right = TFT_W;
screen_rect.top = 0;
screen_rect.bottom = TFT_H;
starmap.siteLat = DEFAULT_LAT;
starmap.siteLon = DEFAULT_LON;
// colors
starmap.col_coord_grid = 0x4a49; // dark gray
starmap.col_ecliptic = 0xab91; // dark pink-red
starmap.col_constel = 0x326b; // dark aqua
starmap.col_stardim = 0xa520; // dim yellow
starmap.col_starbright = 0xffe0; // bright yellow
starmap.col_startext = 0x001f; // pure blue
starmap.col_moon_bright = 0xffff; // white
starmap.col_moon_dim = 0xe71c; // light gray
starmap.col_moon_dark = 0xce79; // med gray
starmap.col_moon_phtext = 0x0000; // black
starmap.col_bright_st_text = 0x001f; // pure blue
starmap.col_ecliptic_text = 0xab91; // dark pink-red
starmap.col_celest_eq_text = 0x4a49; // dark gray
starmap.col_constel_text = 0x0030; // dark blue
// check if flash is available and valid
if (flash.flash_read_id() == 0x8e) {
// Flash chip is installed, but check if it contains the magic string:
flash_data[0] = 0;
flash.flash_read(0x00000, flash_data, 12);
if (strcmp(flash_data, "starmap v01")==0) {
flash_present=1; // magic string is present.
}
}
DELAY_MS(3000);
Serial.print("setup() complete\n\r");
if(flash_present) {
Serial.print("flash present and valid\n\r");
}
}
// ******** loop() function ********
void loop() {
double lat, lon;
int valid=0;
int i;
int x, y;
uint32_t ts; // timestamp in milliseconds
int hr, min, sec; // used to store the displayed time
int old_min;
char disp_lat_lon_complete;
char text_string[24];
if (!first_fix_done) {
// wait for GNSS to start providing data
gfx->fillScreen(BLACK); // clear the TFT screen
gfx->setCursor(40, 240);
gfx->setTextColor(WHITE);
gfx->setTextSize(1);
gfx->println("Acquiring Satellite Fix..");
yield();
get_first_fix(); // executes gnss.get_data() repeatedly until we have a valid fix
first_fix_done = 1;
} else {
#ifndef NO_GPS
gnss.flush_buffer(); // clear out the buffer
gnss.get_data(PRINT_ENABLE); // get GNSS data and print the raw sentence to Serial
#endif
}
#ifdef NO_GPS
tm.tm_sec = 0; // seconds 0-59
tm.tm_min = 15; // minutes 0-59
tm.tm_hour = 02; // hour 0-23
tm.tm_mday = 11; // date 1-31
tm.tm_mon = 7 - 1; // month 0-11
tm.tm_year = 2024 - 1900; // year since 1900. Example: 100 means year 2000
starmap.jdtime = starmap.jtime(&tm); // store the time in Julian days
#else
// fill starmap object with the GNSS time and location
copy_gnss_time_to_starmap();
copy_gnss_loc_to_starmap();
#endif
gfx->fillScreen(BLACK); // clear the TFT screen
yield();
Serial.print("executing paintSky..\n\r");
starmap.paintSky(mag, &screen_rect); // paint the sky!
yield();
Serial.print("done executing paintSky.\n\r");
// print lat and lon on tft
//lat = starmap.siteLat;
//lon = starmap.siteLon;
//disp_lat_lon(lat, lon, 40, 80, WHITE);
invalidate_displayed_sat_list(); // clear the list of displayed satellites
old_min = -1;
disp_lat_lon_complete = 0;
// loop until the starmap needs to be redrawn
ts = millis(); // get current Arduino timestamp
while (millis() - ts < starmap_update_period) {
//if (disp_lat_lon_complete==0) {
// if ((millis() - ts > 10000)) { // display the lat and lon for 10 seconds
// gfx->fillScreen(BLACK); // clear the TFT screen
// starmap.paintSky(mag, &screen_rect);
// yield();
// disp_lat_lon_complete = 1;
// }
//}
DELAY_MS(1100);
#ifdef NO_GPS
#else
gnss.get_data(PRINT_DISABLE);
#endif
// store the time so we can display it
#ifdef NO_GPS
#else
hr = gnss.rmc.hour + DISPLAYED_TIME_OFFSET;
if (hr > 23) hr -= 24;
min = gnss.rmc.min;
sec = gnss.rmc.sec;
char sat_drawn = 0;
for (i=0; i<gnss.satnum; i++) {
//Serial.print("sat_id[0] = ");
//Serial.print((uint8_t)sat_id[0]);
//Serial.print("\n\r");
if (check_and_add_sat((uint8_t)gnss.gsv[i].prn) < 1) {
// satellite already in the list, no need to redraw it.
continue;
}
ccw_azimuth_elevation_to_xy(gnss.gsv[i].azim, gnss.gsv[i].elev, &x, &y);
switch(gnss.gsv[i].source) {
case SOURCE_GPS:
draw_flag(x, y, FLAG_USA);
sat_drawn = 1;
break;
case SOURCE_GALILEO:
draw_flag(x, y, FLAG_EU);
sat_drawn = 1;
break;
case SOURCE_BEIDOU:
draw_flag(x, y, FLAG_CHINA);
sat_drawn = 1;
break;
case SOURCE_GLONASS:
draw_flag(x, y, FLAG_RUSSIA);
sat_drawn = 1;
break;
case SOURCE_UNK:
// should draw some default flag
sat_drawn = 1;
Serial.print("warning! unknown satellite source.\n");
break;
default:
Serial.print("error! unexpected satellite source.\n");
break;
}
if (sat_drawn) { // don't want satellite icons to overlap the text
// overlay N, E, S, W characters onto the screen
plot_char_10_12(NORTH_SYMBOL, 115, 18, NESW_COLOR);
plot_char_10_12(EAST_SYMBOL, 3, 125, NESW_COLOR);
plot_char_10_12(SOUTH_SYMBOL, 115, 234, NESW_COLOR);
plot_char_10_12(WEST_SYMBOL, 225, 125, NESW_COLOR);
// display lat and lon
lat = starmap.siteLat;
lon = starmap.siteLon;
disp_lat_lon(lat, lon, 52, 190, WHITE);
}
}
#endif
// display the time if it has changed
if (min != old_min) {
old_min = min;
sprintf(text_string, "%02d:%02d", hr, min);
gfx->fillRect(91, 199, 60, 16, BLACK);
gfx->setCursor(92, 200);
gfx->setTextColor(WHITE);
gfx->setTextSize(2);
gfx->println(text_string);
yield();
}
} // end while loop for starmap_update_period
// starmap has been displayed for starmap_update_period
// now loop back to the beginning, so that the starmap is completely redrawn
}
// ************ other functions *****************
// plot_char_10_12 only supports N, E, S, W characters
void plot_char_10_12(char c, int x, int y, int color) {
int i, j;
// check that the character is in the font
// only 0-3 are valid (N, E, S, W)
if (c > 3 || c < 0)
{
return;
}
for (i = 0; i < 10; i++)
{
for (j = 0; j < 12; j++)
{
if (font10_12[c][i] & (1 << j))
{
gfx->drawPixel(x + i, y - j, color);
} else {
gfx->drawPixel(x + i, y - j, BLACK);
}
}
}
}
void draw_flag(int x, int y, int flagtype) {
int i, j;
for (i=0; i<7; i++) {
for (j=0; j<7; j++) {
switch (flagtype) {
case FLAG_USA:
gfx->drawPixel(x+i-3, y-j+3, flag_usa[i][j]);
//starmap.plot_pixel(flag_usa[i][j], x+i-3, y-j+3);
break;
case FLAG_EU:
gfx->drawPixel(x+i-3, y-j+3, flag_eu[i][j]);
//starmap.plot_pixel(flag_eu[i][j], x+i-3, y-j+3);
break;
case FLAG_CHINA:
gfx->drawPixel(x+i-3, y-j+3, flag_china[i][j]);
//starmap.plot_pixel(flag_china[i][j], x+i-3, y-j+3);
break;
case FLAG_RUSSIA:
if (j<6) {
gfx->drawPixel(x+i-3, y-j+3, flag_russia[i][j]);
//starmap.plot_pixel(flag_russia[i][j], x+i-3, y-j+3);
}
break;
}
}
}
// draw a border outside each flag, using draw_line
gfx->drawLine(x-4, y-4, x+4, y-4, FLAG_BORDER);
gfx->drawLine(x-4, y+4, x-4, y-4, FLAG_BORDER);
gfx->drawLine(x+4, y+4, x+4, y-4, FLAG_BORDER);
//starmap.draw_line(x-4, y+4, x+4, y+4, 0x0000);
//starmap.draw_line(x-4, y+4, x-4, y-4, 0x0000);
//starmap.draw_line(x+4, y+4, x+4, y-4, 0x0000);
if (flagtype != FLAG_RUSSIA) {
gfx->drawLine(x-4, y-4, x+4, y-4, FLAG_BORDER);
//starmap.draw_line(x-4, y-4, x+4, y-4, 0x0000);
} else {
gfx->drawLine(x-4, y-3, x+4, y-3, FLAG_BORDER);
//starmap.draw_line(x-4, y-3, x+4, y-3, 0x0000);
}
yield();
}
// function to convert elevation and azimuth to x,y coordinates
// with north-up, but in a counter-clockwise fashion, since we are
// plotting an overhead view of the sky
void ccw_azimuth_elevation_to_xy(double az, double el, int *x, int *y) {
// convert to radians
az = az * PI / 180.0;
el = el * PI / 180.0;
// calculate x and y
*x = (int)(TFT_W/2 + (TFT_W/2-1) * cos(el) * sin(az));
*y = (int)(TFT_H/2 - (TFT_H/2-1) * cos(el) * cos(az));
// we want anticlockwise rotation
*x = TFT_W - *x;
}
#ifdef NO_GPS
#else
// copy GNSS data to Starmap object
int copy_gnss_time_to_starmap(void) {
int valid = 1;
if ((gnss.rmc.sec<0) || (gnss.rmc.sec>59)) valid = 0;
if ((gnss.rmc.min<0) || (gnss.rmc.min>59)) valid = 0;
if ((gnss.rmc.hour<0) || (gnss.rmc.hour>23)) valid = 0;
if ((gnss.rmc.date<1) || (gnss.rmc.date>31)) valid = 0;
if ((gnss.rmc.month<1) || (gnss.rmc.month>12)) valid = 0;
if ((gnss.rmc.year<2000) || (gnss.rmc.year>2199)) valid = 0;
if (!valid) return -1;
// populate the starmap object with the time
tm.tm_sec = gnss.rmc.sec; // seconds 0-59
tm.tm_min = gnss.rmc.min; // minutes 0-59
tm.tm_hour = gnss.rmc.hour; // hour 0-23
tm.tm_mday = gnss.rmc.date; // date 1-31
tm.tm_mon = gnss.rmc.month - 1; // month 0-11
tm.tm_year = gnss.rmc.year - 1900; // year since 1900. Example: 100 means year 2000
starmap.jdtime = starmap.jtime(&tm); // store the time in Julian days
return 1;
}
int copy_gnss_loc_to_starmap(void) {
int valid = 1;
if ((gnss.rmc.lat<-90) || (gnss.rmc.lat>90)) valid = 0;
if ((gnss.rmc.lon<-180) || (gnss.rmc.lon>180)) valid = 0;
if (!valid) {
Serial.print("error! invalid GNSS location: lat=");
Serial.print(gnss.rmc.lat);
Serial.print(", lon=");
Serial.print(gnss.rmc.lon);
Serial.print("\n\r");
return -1;
}
// populate the starmap object with the location
starmap.siteLat = gnss.rmc.lat;
// GNSS longitude is in degrees East, but starmap object requires degrees West
starmap.siteLon = 0.0 - gnss.rmc.lon;
return 1;
}
#endif
#ifdef NO_GPS
void get_first_fix(void) {
//
}
#else
void get_first_fix(void) {
double lat, lon;
int valid=0;
// wait for GNSS to start providing data
// set to invalid values
gnss.rmc.lat = 9999;
gnss.rmc.lon = 9999;
gnss.rmc.hour = 9999;
while (!valid) {
DELAY_MS(1100);
gnss.flush_buffer(); // clear out the buffer
gnss.get_data(PRINT_ENABLE); // get GNSS data and print the raw sentence to Serial
if ((gnss.rmc.lat < 999) && (gnss.rmc.lon < 999) && (gnss.rmc.hour < 999)) {
// ok we seem to have received at least lat/lon and time
valid = 1;
}
}
}
#endif
void invalidate_displayed_sat_list(void) {
int i;
for (i=0; i<24; i++) {
sat_id[i] = 255;
}
}
#ifdef NO_GPS
int check_and_add_sat(uint8_t id) {
return(0);
}
#else
int check_and_add_sat(uint8_t id) {
int i;
// check if the id is valid
if (id == SOURCE_INVALID) {
Serial.print("error! invalid satellite ID.\n\r");
return(0);
}
// check if the satellite is already in the list
for (i=0; i<24; i++) {
if (sat_id[i] == 255) {
// end of list
sat_id[i] = id;
return 1;
}
if (sat_id[i] == id) {
// already in the list
return 0;
}
}
// list is full
Serial.print("error! satellite list is full.\n\r");
return(0);
}
#endif
void disp_lat_lon(double lat, double lon, int x, int y, int col) {
char text_string[32];
char neg_lat=0;
char neg_lon=0;
int width;
if (lat < 0) {
neg_lat = 1;
lat = 0 - lat;
}
if (lon < 0) {
neg_lon = 1;
lon = 0 - lon;
}
// build text string; there must be an easier way to do this!
if (neg_lat) {
if (neg_lon) {
sprintf(text_string, "LAT:-%02d.%03dN LON:-%02d.%03dW", (int)lat, (int)((lat - (int)lat) * 1000), (int)lon, (int)((lon - (int)lon) * 1000));
} else {
sprintf(text_string, "LAT:-%02d.%03dN LON:%02d.%03dW", (int)lat, (int)((lat - (int)lat) * 1000), (int)lon, (int)((lon - (int)lon) * 1000));
}
} else {
if (neg_lon) {
sprintf(text_string, "LAT:%02d.%03dN LON:-%02d.%03dW", (int)lat, (int)((lat - (int)lat) * 1000), (int)lon, (int)((lon - (int)lon) * 1000));
} else {
sprintf(text_string, "LAT:%02d.%03dN LON:%02d.%03dW", (int)lat, (int)((lat - (int)lat) * 1000), (int)lon, (int)((lon - (int)lon) * 1000));
}
}
width = 158;
if (neg_lat) width += 8;
if (neg_lon) width += 8;
gfx->fillRect(x-1, y-1, width, 10, BLACK);
gfx->setCursor(x, y);
gfx->setTextColor(col);
gfx->setTextSize(1);
gfx->println(text_string);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment