mirror of
https://codeberg.org/mclemens/ubitxv6.git
synced 2024-11-02 15:37:21 -04:00
Release Candidate 1
This commit is contained in:
commit
097c106a55
111
morse_reader.ino
Normal file
111
morse_reader.ino
Normal file
@ -0,0 +1,111 @@
|
||||
|
||||
/*
|
||||
* Each byte of the morse table stores one letter.
|
||||
* The 0 is a dot, a 1 is a dash
|
||||
* From the Most significant byte onwards, the letter is padded with 1s.
|
||||
* The first zero after the 1s indicates the start of the letter, it MUST be discarded
|
||||
*/
|
||||
|
||||
struct Morse {
|
||||
char letter;
|
||||
unsigned char code;
|
||||
};
|
||||
|
||||
const PROGMEM struct Morse morse_table[] = {
|
||||
{'a', 0xf9}, // 11111001
|
||||
{'b', 0xe8}, // 11101000
|
||||
{'c', 0xea}, // 11101010
|
||||
{'d', 0xf4}, // 11110100
|
||||
{'e', 0xfc}, // 11111100
|
||||
{'f', 0xe4}, // 11100100
|
||||
{'g', 0xf6}, // 11110110
|
||||
{'h', 0xe0}, // 11100000
|
||||
{'i', 0xf8}, // 11111000
|
||||
{'j', 0xe7}, // 11100111
|
||||
{'k', 0xf6}, // 11110101
|
||||
{'l', 0xe4}, // 11100100
|
||||
{'m', 0xfb}, // 11111011
|
||||
{'n', 0xfa}, // 11111010
|
||||
{'o', 0xf7}, // 11110111
|
||||
{'p', 0xe6}, // 11100110
|
||||
{'q', 0xed}, // 11101101
|
||||
{'r', 0xf2}, // 11110010
|
||||
{'s', 0xf0}, // 11110000
|
||||
{'t', 0xfd}, // 11111101
|
||||
{'u', 0xf1}, // 11110001
|
||||
{'v', 0xe1}, // 11100001
|
||||
{'w', 0xf3}, // 11110011
|
||||
{'x', 0xe9}, // 11101001
|
||||
{'y', 0xe3}, // 11101011
|
||||
{'z', 0xec}, // 11101100
|
||||
{'1', 0xcf}, // 11001111
|
||||
{'2', 0xc7}, // 11000111
|
||||
{'3', 0xc3}, // 11000011
|
||||
{'4', 0xc1}, // 11000001
|
||||
{'5', 0xc0}, // 11000000
|
||||
{'6', 0xd0}, // 11010000
|
||||
{'7', 0xd8}, // 11011000
|
||||
{'8', 0xdc}, // 11011100
|
||||
{'9', 0xde}, // 11011110
|
||||
{'0', 0xdf}, // 11011111
|
||||
{'.', 0xd5}, // 110010101
|
||||
{'?', 0xd3}, // 110110011
|
||||
};
|
||||
|
||||
void morseLetter(char c){
|
||||
unsigned char mask = 0x80;
|
||||
|
||||
//handle space character as three dashes
|
||||
if (c == ' '){
|
||||
active_delay(cwSpeed * 9);
|
||||
Serial.print(' ');
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(morse_table)/ sizeof(struct Morse); i++){
|
||||
struct Morse m;
|
||||
memcpy_P(&m, morse_table + i, sizeof(struct Morse));
|
||||
|
||||
if (m.letter == tolower(c)){
|
||||
unsigned char code = m.code;
|
||||
//Serial.print(m.letter); Serial.println(' ');
|
||||
|
||||
while(mask & code && mask > 1)
|
||||
mask = mask >> 1;
|
||||
//now we are at the first zero, skip and carry on
|
||||
mask = mask >> 1;
|
||||
while(mask){
|
||||
tone(CW_TONE, sideTone,10000);
|
||||
if (mask & code){
|
||||
delay(3 * (int)cwSpeed);
|
||||
//Serial.print('-');
|
||||
}
|
||||
else{
|
||||
delay((int)cwSpeed);
|
||||
//Serial.print('.');
|
||||
}
|
||||
//Serial.print('#');
|
||||
noTone(CW_TONE);
|
||||
delay((int)cwSpeed); // space between dots and dashes
|
||||
mask = mask >> 1;
|
||||
}
|
||||
//Serial.println('@');
|
||||
delay(200); // space between letters is a dash (3 dots), one dot's space has already been sent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void morseText(char *text){
|
||||
// while (1){
|
||||
noTone(CW_TONE);
|
||||
delay(1000);
|
||||
tone(CW_TONE, 600);
|
||||
delay(1000);
|
||||
// }
|
||||
|
||||
Serial.println(sideTone);
|
||||
while(*text){
|
||||
morseLetter(*text++);
|
||||
}
|
||||
}
|
||||
|
596
tft_gui.ino
Normal file
596
tft_gui.ino
Normal file
@ -0,0 +1,596 @@
|
||||
#include <XPT2046_Touchscreen.h>
|
||||
#include <SPI.h>
|
||||
//#include "ubitx_font.h"
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define TFT_CS 10
|
||||
#define TFT_RS 9
|
||||
|
||||
// Color definitions
|
||||
#define ILI9341_BLACK 0x0000 ///< 0, 0, 0
|
||||
#define ILI9341_NAVY 0x000F ///< 0, 0, 123
|
||||
#define ILI9341_DARKGREEN 0x03E0 ///< 0, 125, 0
|
||||
#define ILI9341_DARKCYAN 0x03EF ///< 0, 125, 123
|
||||
#define ILI9341_MAROON 0x7800 ///< 123, 0, 0
|
||||
#define ILI9341_PURPLE 0x780F ///< 123, 0, 123
|
||||
#define ILI9341_OLIVE 0x7BE0 ///< 123, 125, 0
|
||||
#define ILI9341_LIGHTGREY 0xC618 ///< 198, 195, 198
|
||||
#define ILI9341_DARKGREY 0x7BEF ///< 123, 125, 123
|
||||
#define ILI9341_BLUE 0x001F ///< 0, 0, 255
|
||||
#define ILI9341_GREEN 0x07E0 ///< 0, 255, 0
|
||||
#define ILI9341_CYAN 0x07FF ///< 0, 255, 255
|
||||
#define ILI9341_RED 0xF800 ///< 255, 0, 0
|
||||
#define ILI9341_MAGENTA 0xF81F ///< 255, 0, 255
|
||||
#define ILI9341_YELLOW 0xFFE0 ///< 255, 255, 0
|
||||
#define ILI9341_WHITE 0xFFFF ///< 255, 255, 255
|
||||
#define ILI9341_ORANGE 0xFD20 ///< 255, 165, 0
|
||||
#define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255, 41
|
||||
#define ILI9341_PINK 0xFC18 ///< 255, 130, 198
|
||||
|
||||
#define TEXT_LINE_HEIGHT 18
|
||||
#define TEXT_LINE_INDENT 5
|
||||
|
||||
#define BUTTON_PUSH
|
||||
#define BUTTON_CHECK
|
||||
#define BUTTON_SPINNER
|
||||
|
||||
|
||||
GFXfont *gfxFont = NULL;
|
||||
XPT2046_Touchscreen ts(CS_PIN);
|
||||
TS_Point ts_point;
|
||||
|
||||
//filled from a test run of calibration routine
|
||||
int slope_x=104, slope_y=137, offset_x=28, offset_y=29;
|
||||
|
||||
void readTouchCalibration(){
|
||||
EEPROM.get(SLOPE_X, slope_x);
|
||||
EEPROM.get(SLOPE_Y, slope_y);
|
||||
EEPROM.get(OFFSET_X, offset_x);
|
||||
EEPROM.get(OFFSET_Y, offset_y);
|
||||
|
||||
if (slope_x < 10 || 200 < slope_x){
|
||||
slope_x=104;
|
||||
slope_y=137;
|
||||
offset_x=28;
|
||||
offset_y=29;
|
||||
}
|
||||
}
|
||||
|
||||
void writeTouchCalibration(){
|
||||
EEPROM.put(SLOPE_X, slope_x);
|
||||
EEPROM.put(SLOPE_Y, slope_y);
|
||||
EEPROM.put(OFFSET_X, offset_x);
|
||||
EEPROM.put(OFFSET_Y, offset_y);
|
||||
}
|
||||
|
||||
boolean readTouch(){
|
||||
|
||||
boolean istouched = ts.touched();
|
||||
if (istouched) {
|
||||
ts_point = ts.getPoint();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void scaleTouch(TS_Point *p){
|
||||
p->x = ((long)(p->x) * 10l)/(long)(slope_x) - offset_x;
|
||||
p->y = ((long)(p->y) * 10l)/(long)(slope_y) - offset_y;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
|
||||
#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
|
||||
#else
|
||||
#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
|
||||
#endif
|
||||
|
||||
inline GFXglyph * pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c)
|
||||
{
|
||||
#ifdef __AVR__
|
||||
return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
|
||||
#else
|
||||
// expression in __AVR__ section may generate "dereferencing type-punned pointer will break strict-aliasing rules" warning
|
||||
// In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
|
||||
// So expression may be simplified
|
||||
return gfxFont->glyph + c;
|
||||
#endif //__AVR__
|
||||
}
|
||||
|
||||
inline uint8_t * pgm_read_bitmap_ptr(const GFXfont *gfxFont)
|
||||
{
|
||||
#ifdef __AVR__
|
||||
return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
|
||||
#else
|
||||
// expression in __AVR__ section generates "dereferencing type-punned pointer will break strict-aliasing rules" warning
|
||||
// In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
|
||||
// So expression may be simplified
|
||||
return gfxFont->bitmap;
|
||||
#endif //__AVR__
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline static void utft_write(unsigned char d)
|
||||
{
|
||||
SPI.transfer(d);
|
||||
}
|
||||
|
||||
inline static void utftCmd(unsigned char VH)
|
||||
{
|
||||
*(portOutputRegister(digitalPinToPort(TFT_RS))) &= ~digitalPinToBitMask(TFT_RS);//LCD_RS=0;
|
||||
utft_write(VH);
|
||||
}
|
||||
|
||||
inline static void utftData(unsigned char VH)
|
||||
{
|
||||
*(portOutputRegister(digitalPinToPort(TFT_RS)))|= digitalPinToBitMask(TFT_RS);//LCD_RS=1;
|
||||
utft_write(VH);
|
||||
}
|
||||
/*
|
||||
void utftCmd_Data(unsigned char com,unsigned char dat)
|
||||
{
|
||||
utftCmd(com);
|
||||
utftData(dat);
|
||||
}
|
||||
*/
|
||||
static void utftAddress(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
|
||||
{
|
||||
utftCmd(0x2a);
|
||||
utftData(x1>>8);
|
||||
utftData(x1);
|
||||
utftData(x2>>8);
|
||||
utftData(x2);
|
||||
utftCmd(0x2b);
|
||||
utftData(y1>>8);
|
||||
utftData(y1);
|
||||
utftData(y2>>8);
|
||||
utftData(y2);
|
||||
utftCmd(0x2c);
|
||||
}
|
||||
|
||||
/*
|
||||
inline void utftQuickfill(int16_t x1, int16_t y1, int16_t w, int16_t h, uint16_t color) {
|
||||
int16_t x2, y2;
|
||||
x2 = x1 + w;
|
||||
y2 = y1 + h;
|
||||
setAddrWindow(x, y, x2, y2);
|
||||
writeColor(color, (uint32_t)w * h);
|
||||
}
|
||||
*/
|
||||
|
||||
void utftPixel(unsigned int x, unsigned int y, unsigned int c)
|
||||
{
|
||||
unsigned int i,j;
|
||||
digitalWrite(TFT_CS,LOW);
|
||||
utftCmd(0x02c); //write_memory_start
|
||||
//digitalWrite(RS,HIGH);
|
||||
//l=l+x;
|
||||
utftAddress(x,y,x,y);
|
||||
//j=l*2;
|
||||
//for(i=1;i<=j;i++)
|
||||
//{
|
||||
utftData(c>>8);
|
||||
utftData(c);
|
||||
|
||||
//utftData(c);
|
||||
//utftData(c);
|
||||
//}
|
||||
digitalWrite(TFT_CS,HIGH);
|
||||
}
|
||||
|
||||
|
||||
void utftHline(unsigned int x, unsigned int y, unsigned int l, unsigned int c)
|
||||
{
|
||||
unsigned int i,j;
|
||||
digitalWrite(TFT_CS,LOW);
|
||||
utftCmd(0x02c); //write_memory_start
|
||||
//digitalWrite(RS,HIGH);
|
||||
l=l+x;
|
||||
utftAddress(x,y,l,y);
|
||||
// j=l*2;
|
||||
j = l;
|
||||
for(i=1;i<=j;i++)
|
||||
{
|
||||
utftData(c>>8);
|
||||
utftData(c);
|
||||
}
|
||||
digitalWrite(TFT_CS,HIGH);
|
||||
checkCAT();
|
||||
}
|
||||
|
||||
void displayClear(unsigned int j)
|
||||
{
|
||||
unsigned int i,m;
|
||||
digitalWrite(TFT_CS,LOW);
|
||||
utftAddress(0,0,320,240);
|
||||
for(i=0;i<320;i++)
|
||||
for(m=0;m<240;m++)
|
||||
{
|
||||
utftData(j>>8);
|
||||
utftData(j);
|
||||
}
|
||||
digitalWrite(TFT_CS,HIGH);
|
||||
}
|
||||
|
||||
void utftVline(unsigned int x, unsigned int y, unsigned int l, unsigned int c)
|
||||
{
|
||||
unsigned int i,j;
|
||||
digitalWrite(TFT_CS,LOW);
|
||||
utftCmd(0x02c); //write_memory_start
|
||||
//digitalWrite(RS,HIGH);
|
||||
l=l+y;
|
||||
utftAddress(x,y,x,l);
|
||||
//j=l*2;
|
||||
j = l;
|
||||
for(i=1;i<=l;i++)
|
||||
{
|
||||
utftData(c>>8);
|
||||
utftData(c);
|
||||
}
|
||||
digitalWrite(TFT_CS,HIGH);
|
||||
checkCAT();
|
||||
}
|
||||
|
||||
void utftRect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c)
|
||||
{
|
||||
utftHline(x , y , w, c);
|
||||
utftHline(x , y+h, w, c);
|
||||
utftVline(x , y , h, c);
|
||||
utftVline(x+w, y , h, c);
|
||||
}
|
||||
|
||||
void utftFillrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<h;i++)
|
||||
{
|
||||
//utftHline(x , y , w, c);
|
||||
utftHline(x , y+i, w, c);
|
||||
}
|
||||
}
|
||||
|
||||
void displayInit(void)
|
||||
{
|
||||
SPI.begin();
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz (half speed)
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
|
||||
gfxFont = &ubitx_font;
|
||||
pinMode(TFT_CS,OUTPUT);
|
||||
pinMode(TFT_RS,OUTPUT);
|
||||
|
||||
|
||||
digitalWrite(TFT_CS,LOW); //CS
|
||||
utftCmd(0xCB);
|
||||
utftData(0x39);
|
||||
utftData(0x2C);
|
||||
utftData(0x00);
|
||||
utftData(0x34);
|
||||
utftData(0x02);
|
||||
|
||||
utftCmd(0xCF);
|
||||
utftData(0x00);
|
||||
utftData(0XC1);
|
||||
utftData(0X30);
|
||||
|
||||
utftCmd(0xE8);
|
||||
utftData(0x85);
|
||||
utftData(0x00);
|
||||
utftData(0x78);
|
||||
|
||||
utftCmd(0xEA);
|
||||
utftData(0x00);
|
||||
utftData(0x00);
|
||||
|
||||
utftCmd(0xED);
|
||||
utftData(0x64);
|
||||
utftData(0x03);
|
||||
utftData(0X12);
|
||||
utftData(0X81);
|
||||
|
||||
utftCmd(0xF7);
|
||||
utftData(0x20);
|
||||
|
||||
utftCmd(0xC0); //Power control
|
||||
utftData(0x23); //VRH[5:0]
|
||||
|
||||
utftCmd(0xC1); //Power control
|
||||
utftData(0x10); //SAP[2:0];BT[3:0]
|
||||
|
||||
utftCmd(0xC5); //VCM control
|
||||
utftData(0x3e); //Contrast
|
||||
utftData(0x28);
|
||||
|
||||
utftCmd(0xC7); //VCM control2
|
||||
utftData(0x86); //--
|
||||
|
||||
utftCmd(0x36); // Memory Access Control
|
||||
utftData(0x28); // Make this horizontal display
|
||||
|
||||
utftCmd(0x3A);
|
||||
utftData(0x55);
|
||||
|
||||
utftCmd(0xB1);
|
||||
utftData(0x00);
|
||||
utftData(0x18);
|
||||
|
||||
utftCmd(0xB6); // Display Function Control
|
||||
utftData(0x08);
|
||||
utftData(0x82);
|
||||
utftData(0x27);
|
||||
|
||||
utftCmd(0x11); //Exit Sleep
|
||||
delay(120);
|
||||
|
||||
utftCmd(0x29); //Display on
|
||||
utftCmd(0x2c);
|
||||
digitalWrite(TFT_CS,HIGH);
|
||||
|
||||
//now to init the touch screen controller
|
||||
ts.begin();
|
||||
ts.setRotation(1);
|
||||
|
||||
readTouchCalibration();
|
||||
}
|
||||
|
||||
|
||||
// Draw a character
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Draw a single character
|
||||
@param x Bottom left corner x coordinate
|
||||
@param y Bottom left corner y coordinate
|
||||
@param c The 8-bit font-indexed character (likely ascii)
|
||||
@param color 16-bit 5-6-5 Color to draw chraracter with
|
||||
@param bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
|
||||
@param size_x Font magnification level in X-axis, 1 is 'original' size
|
||||
@param size_y Font magnification level in Y-axis, 1 is 'original' size
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#define FAST_TEXT 1
|
||||
|
||||
void displayChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg) {
|
||||
c -= (uint8_t)pgm_read_byte(&gfxFont->first);
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
|
||||
uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
|
||||
|
||||
uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
|
||||
uint8_t w = pgm_read_byte(&glyph->width),
|
||||
h = pgm_read_byte(&glyph->height);
|
||||
int8_t xo = pgm_read_byte(&glyph->xOffset),
|
||||
yo = pgm_read_byte(&glyph->yOffset);
|
||||
uint8_t xx, yy, bits = 0, bit = 0;
|
||||
int16_t xo16 = 0, yo16 = 0;
|
||||
|
||||
digitalWrite(TFT_CS,LOW);
|
||||
|
||||
#ifdef FAST_TEXT
|
||||
uint16_t hpc = 0; // Horizontal foreground pixel count
|
||||
for(yy=0; yy<h; yy++) {
|
||||
for(xx=0; xx<w; xx++) {
|
||||
if(bit == 0) {
|
||||
bits = pgm_read_byte(&bitmap[bo++]);
|
||||
bit = 0x80;
|
||||
}
|
||||
if(bits & bit) hpc++;
|
||||
else {
|
||||
if (hpc) {
|
||||
utftHline(x+xo+xx-hpc, y+yo+yy, hpc, color);
|
||||
hpc=0;
|
||||
}
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
// Draw pixels for this line as we are about to increment yy
|
||||
if (hpc) {
|
||||
utftHline(x+xo+xx-hpc, y+yo+yy, hpc, color);
|
||||
hpc=0;
|
||||
}
|
||||
checkCAT();
|
||||
}
|
||||
#else
|
||||
for(yy=0; yy<h; yy++) {
|
||||
for(xx=0; xx<w; xx++) {
|
||||
if(!(bit++ & 7)) {
|
||||
bits = pgm_read_byte(&bitmap[bo++]);
|
||||
}
|
||||
if(bits & 0x80) {
|
||||
utftPixel(x+xo+xx, y+yo+yy, color);
|
||||
}
|
||||
bits <<= 1;
|
||||
}
|
||||
checkCAT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
void displayChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg) {
|
||||
|
||||
// Character is assumed previously filtered by write() to eliminate
|
||||
// newlines, returns, non-printable characters, etc. Calling
|
||||
// drawChar() directly with 'bad' characters of font may cause mayhem!
|
||||
|
||||
c -= (uint8_t)pgm_read_byte(&gfxFont->first);
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
|
||||
uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
|
||||
|
||||
uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
|
||||
uint8_t w = pgm_read_byte(&glyph->width),
|
||||
h = pgm_read_byte(&glyph->height);
|
||||
int8_t xo = pgm_read_byte(&glyph->xOffset),
|
||||
yo = pgm_read_byte(&glyph->yOffset);
|
||||
uint8_t xx, yy, bits = 0, bit = 0;
|
||||
int16_t xo16 = 0, yo16 = 0;
|
||||
|
||||
digitalWrite(TFT_CS,LOW);
|
||||
|
||||
for(yy=0; yy<h; yy++) {
|
||||
for(xx=0; xx<w; xx++) {
|
||||
if(!(bit++ & 7)) {
|
||||
bits = pgm_read_byte(&bitmap[bo++]);
|
||||
}
|
||||
if(bits & 0x80) {
|
||||
utftPixel(x+xo+xx, y+yo+yy, color);
|
||||
}
|
||||
// else
|
||||
// utftPixel(x+xo+xx, y+yo+yy, bg);
|
||||
|
||||
bits <<= 1;
|
||||
}
|
||||
checkCAT();
|
||||
}
|
||||
digitalWrite(TFT_CS,HIGH);
|
||||
}
|
||||
*/
|
||||
|
||||
int displayTextExtent(char *text) {
|
||||
|
||||
int ext = 0;
|
||||
while(*text){
|
||||
char c = *text++;
|
||||
uint8_t first = pgm_read_byte(&gfxFont->first);
|
||||
if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
|
||||
ext += (uint8_t)pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
}//end of the while loop of the characters to be printed
|
||||
return ext;
|
||||
}
|
||||
|
||||
void displayRawText(char *text, int x1, int y1, int color, int background){
|
||||
while(*text){
|
||||
char c = *text++;
|
||||
|
||||
uint8_t first = pgm_read_byte(&gfxFont->first);
|
||||
if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
|
||||
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
|
||||
uint8_t w = pgm_read_byte(&glyph->width),
|
||||
h = pgm_read_byte(&glyph->height);
|
||||
if((w > 0) && (h > 0)) { // Is there an associated bitmap?
|
||||
int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
|
||||
displayChar(x1, y1+TEXT_LINE_HEIGHT, c, color, background);
|
||||
checkCAT();
|
||||
}
|
||||
x1 += (uint8_t)pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
}//end of the while loop of the characters to be printed
|
||||
|
||||
}
|
||||
|
||||
// The generic routine to display one line on the LCD
|
||||
void displayText(char *text, int x1, int y1, int w, int h, int color, int background, int border) {
|
||||
|
||||
utftFillrect(x1, y1, w ,h, background);
|
||||
utftRect(x1, y1, w ,h, border);
|
||||
|
||||
x1 += (w - displayTextExtent(text))/2;
|
||||
y1 += (h - TEXT_LINE_HEIGHT)/2;
|
||||
while(*text){
|
||||
char c = *text++;
|
||||
|
||||
uint8_t first = pgm_read_byte(&gfxFont->first);
|
||||
if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
|
||||
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
|
||||
uint8_t w = pgm_read_byte(&glyph->width),
|
||||
h = pgm_read_byte(&glyph->height);
|
||||
if((w > 0) && (h > 0)) { // Is there an associated bitmap?
|
||||
int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
|
||||
displayChar(x1, y1+TEXT_LINE_HEIGHT, c, color, background);
|
||||
checkCAT();
|
||||
}
|
||||
x1 += (uint8_t)pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
}//end of the while loop of the characters to be printed
|
||||
}
|
||||
|
||||
void setupTouch(){
|
||||
int x1, y1, x2, y2, x3, y3, x4, y4;
|
||||
|
||||
displayClear(ILI9341_BLACK);
|
||||
displayText("Click on the cross", 20,100, 200, 50, ILI9341_WHITE, ILI9341_BLACK, ILI9341_BLACK);
|
||||
|
||||
// TOP-LEFT
|
||||
utftHline(10,20,20,ILI9341_WHITE);
|
||||
utftVline(20,10,20, ILI9341_WHITE);
|
||||
|
||||
while(!readTouch())
|
||||
delay(100);
|
||||
while(readTouch())
|
||||
delay(100);
|
||||
x1 = ts_point.x;
|
||||
y1 = ts_point.y;
|
||||
|
||||
//rubout the previous one
|
||||
utftHline(10,20,20,ILI9341_BLACK);
|
||||
utftVline(20,10,20, ILI9341_BLACK);
|
||||
|
||||
delay(1000);
|
||||
|
||||
//TOP RIGHT
|
||||
utftHline(290,20,20,ILI9341_WHITE);
|
||||
utftVline(300,10,20, ILI9341_WHITE);
|
||||
|
||||
while(!readTouch())
|
||||
delay(100);
|
||||
while(readTouch())
|
||||
delay(100);
|
||||
x2 = ts_point.x;
|
||||
y2 = ts_point.y;
|
||||
|
||||
utftHline(290,20,20,ILI9341_BLACK);
|
||||
utftVline(300,10,20, ILI9341_BLACK);
|
||||
|
||||
delay(1000);
|
||||
|
||||
//BOTTOM LEFT
|
||||
utftHline(10,220,20,ILI9341_WHITE);
|
||||
utftVline(20,210,20, ILI9341_WHITE);
|
||||
|
||||
while(!readTouch())
|
||||
delay(100);
|
||||
x3 = ts_point.x;
|
||||
y3 = ts_point.y;
|
||||
|
||||
while(readTouch())
|
||||
delay(100);
|
||||
utftHline(10,220,20,ILI9341_BLACK);
|
||||
utftVline(20,210,20, ILI9341_BLACK);
|
||||
|
||||
delay(1000);
|
||||
|
||||
//BOTTOM RIGHT
|
||||
utftHline(290,220,20,ILI9341_WHITE);
|
||||
utftVline(300,210,20, ILI9341_WHITE);
|
||||
|
||||
while(!readTouch())
|
||||
delay(100);
|
||||
x4 = ts_point.x;
|
||||
y4 = ts_point.y;
|
||||
|
||||
|
||||
utftHline(290,220,20,ILI9341_BLACK);
|
||||
utftVline(300,210,20, ILI9341_BLACK);
|
||||
|
||||
// we average two readings and divide them by half and store them as scaled integers 10 times their actual value
|
||||
slope_x = ((x4 - x3) + (x2 - x1))/60; // divide by 300 will give each span it's slope, we add two of them so division reduces to 150 and then by 10 to scale it up : 15
|
||||
slope_y = ((y3 - y1) + (y4 - y2))/44;
|
||||
//x1, y1 is at 10 pixels
|
||||
offset_x = x1 * 10 / slope_x - 10;
|
||||
offset_y = y1 * 10 / slope_y - 10;
|
||||
|
||||
/* //for debugging
|
||||
Serial.print(slope_x); Serial.print(' ');
|
||||
Serial.print(slope_y); Serial.print(' ');
|
||||
Serial.print(offset_x); Serial.print(' ');
|
||||
Serial.println(offset_y); Serial.print(' ');
|
||||
*/
|
||||
writeTouchCalibration();
|
||||
displayClear(ILI9341_BLACK);
|
||||
}
|
||||
|
||||
|
452
ubitx_cat.ino
Normal file
452
ubitx_cat.ino
Normal file
@ -0,0 +1,452 @@
|
||||
/**
|
||||
* The CAT protocol is used by many radios to provide remote control to comptuers through
|
||||
* the serial port.
|
||||
*
|
||||
* This is very much a work in progress. Parts of this code have been liberally
|
||||
* borrowed from other GPLicensed works like hamlib.
|
||||
*
|
||||
* WARNING : This is an unstable version and it has worked with fldigi,
|
||||
* it gives time out error with WSJTX 1.8.0
|
||||
*/
|
||||
|
||||
static unsigned long rxBufferArriveTime = 0;
|
||||
static byte rxBufferCheckCount = 0;
|
||||
#define CAT_RECEIVE_TIMEOUT 500
|
||||
static byte cat[5];
|
||||
static byte insideCat = 0;
|
||||
static byte useOpenRadioControl = 0;
|
||||
|
||||
//for broken protocol
|
||||
#define CAT_RECEIVE_TIMEOUT 500
|
||||
|
||||
#define CAT_MODE_LSB 0x00
|
||||
#define CAT_MODE_USB 0x01
|
||||
#define CAT_MODE_CW 0x02
|
||||
#define CAT_MODE_CWR 0x03
|
||||
#define CAT_MODE_AM 0x04
|
||||
#define CAT_MODE_FM 0x08
|
||||
#define CAT_MODE_DIG 0x0A
|
||||
#define CAT_MODE_PKT 0x0C
|
||||
#define CAT_MODE_FMN 0x88
|
||||
|
||||
#define ACK 0
|
||||
|
||||
unsigned int skipTimeCount = 0;
|
||||
|
||||
byte setHighNibble(byte b,byte v) {
|
||||
// Clear the high nibble
|
||||
b &= 0x0f;
|
||||
// Set the high nibble
|
||||
return b | ((v & 0x0f) << 4);
|
||||
}
|
||||
|
||||
byte setLowNibble(byte b,byte v) {
|
||||
// Clear the low nibble
|
||||
b &= 0xf0;
|
||||
// Set the low nibble
|
||||
return b | (v & 0x0f);
|
||||
}
|
||||
|
||||
byte getHighNibble(byte b) {
|
||||
return (b >> 4) & 0x0f;
|
||||
}
|
||||
|
||||
byte getLowNibble(byte b) {
|
||||
return b & 0x0f;
|
||||
}
|
||||
|
||||
// Takes a number and produces the requested number of decimal digits, staring
|
||||
// from the least significant digit.
|
||||
//
|
||||
void getDecimalDigits(unsigned long number,byte* result,int digits) {
|
||||
for (int i = 0; i < digits; i++) {
|
||||
// "Mask off" (in a decimal sense) the LSD and return it
|
||||
result[i] = number % 10;
|
||||
// "Shift right" (in a decimal sense)
|
||||
number /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Takes a frequency and writes it into the CAT command buffer in BCD form.
|
||||
//
|
||||
void writeFreq(unsigned long freq,byte* cmd) {
|
||||
// Convert the frequency to a set of decimal digits. We are taking 9 digits
|
||||
// so that we can get up to 999 MHz. But the protocol doesn't care about the
|
||||
// LSD (1's place), so we ignore that digit.
|
||||
byte digits[9];
|
||||
getDecimalDigits(freq,digits,9);
|
||||
// Start from the LSB and get each nibble
|
||||
cmd[3] = setLowNibble(cmd[3],digits[1]);
|
||||
cmd[3] = setHighNibble(cmd[3],digits[2]);
|
||||
cmd[2] = setLowNibble(cmd[2],digits[3]);
|
||||
cmd[2] = setHighNibble(cmd[2],digits[4]);
|
||||
cmd[1] = setLowNibble(cmd[1],digits[5]);
|
||||
cmd[1] = setHighNibble(cmd[1],digits[6]);
|
||||
cmd[0] = setLowNibble(cmd[0],digits[7]);
|
||||
cmd[0] = setHighNibble(cmd[0],digits[8]);
|
||||
}
|
||||
|
||||
// This function takes a frquency that is encoded using 4 bytes of BCD
|
||||
// representation and turns it into an long measured in Hz.
|
||||
//
|
||||
// [12][34][56][78] = 123.45678? Mhz
|
||||
//
|
||||
unsigned long readFreq(byte* cmd) {
|
||||
// Pull off each of the digits
|
||||
byte d7 = getHighNibble(cmd[0]);
|
||||
byte d6 = getLowNibble(cmd[0]);
|
||||
byte d5 = getHighNibble(cmd[1]);
|
||||
byte d4 = getLowNibble(cmd[1]);
|
||||
byte d3 = getHighNibble(cmd[2]);
|
||||
byte d2 = getLowNibble(cmd[2]);
|
||||
byte d1 = getHighNibble(cmd[3]);
|
||||
byte d0 = getLowNibble(cmd[3]);
|
||||
return
|
||||
(unsigned long)d7 * 100000000L +
|
||||
(unsigned long)d6 * 10000000L +
|
||||
(unsigned long)d5 * 1000000L +
|
||||
(unsigned long)d4 * 100000L +
|
||||
(unsigned long)d3 * 10000L +
|
||||
(unsigned long)d2 * 1000L +
|
||||
(unsigned long)d1 * 100L +
|
||||
(unsigned long)d0 * 10L;
|
||||
}
|
||||
|
||||
//void ReadEEPRom_FT817(byte fromType)
|
||||
void catReadEEPRom(void)
|
||||
{
|
||||
//for remove warnings
|
||||
byte temp0 = cat[0];
|
||||
byte temp1 = cat[1];
|
||||
/*
|
||||
itoa((int) cat[0], b, 16);
|
||||
strcat(b, ":");
|
||||
itoa((int) cat[1], c, 16);
|
||||
strcat(b, c);
|
||||
printLine2(b);
|
||||
*/
|
||||
|
||||
cat[0] = 0;
|
||||
cat[1] = 0;
|
||||
//for remove warnings[1] = 0;
|
||||
|
||||
switch (temp1)
|
||||
{
|
||||
case 0x45 : //
|
||||
if (temp0 == 0x03)
|
||||
{
|
||||
cat[0] = 0x00;
|
||||
cat[1] = 0xD0;
|
||||
}
|
||||
break;
|
||||
case 0x47 : //
|
||||
if (temp0 == 0x03)
|
||||
{
|
||||
cat[0] = 0xDC;
|
||||
cat[1] = 0xE0;
|
||||
}
|
||||
break;
|
||||
case 0x55 :
|
||||
//0 : VFO A/B 0 = VFO-A, 1 = VFO-B
|
||||
//1 : MTQMB Select 0 = (Not MTQMB), 1 = MTQMB ("Memory Tune Quick Memory Bank")
|
||||
//2 : QMB Select 0 = (Not QMB), 1 = QMB ("Quick Memory Bank")
|
||||
//3 :
|
||||
//4 : Home Select 0 = (Not HOME), 1 = HOME memory
|
||||
//5 : Memory/MTUNE select 0 = Memory, 1 = MTUNE
|
||||
//6 :
|
||||
//7 : MEM/VFO Select 0 = Memory, 1 = VFO (A or B - see bit 0)
|
||||
cat[0] = 0x80 + (vfoActive == VFO_B ? 1 : 0);
|
||||
cat[1] = 0x00;
|
||||
break;
|
||||
case 0x57 : //
|
||||
//0 : 1-0 AGC Mode 00 = Auto, 01 = Fast, 10 = Slow, 11 = Off
|
||||
//2 DSP On/Off 0 = Off, 1 = On (Display format)
|
||||
//4 PBT On/Off 0 = Off, 1 = On (Passband Tuning)
|
||||
//5 NB On/Off 0 = Off, 1 = On (Noise Blanker)
|
||||
//6 Lock On/Off 0 = Off, 1 = On (Dial Lock)
|
||||
//7 FST (Fast Tuning) On/Off 0 = Off, 1 = On (Fast tuning)
|
||||
|
||||
cat[0] = 0xC0;
|
||||
cat[1] = 0x40;
|
||||
break;
|
||||
case 0x59 : // band select VFO A Band Select 0000 = 160 M, 0001 = 75 M, 0010 = 40 M, 0011 = 30 M, 0100 = 20 M, 0101 = 17 M, 0110 = 15 M, 0111 = 12 M, 1000 = 10 M, 1001 = 6 M, 1010 = FM BCB, 1011 = Air, 1100 = 2 M, 1101 = UHF, 1110 = (Phantom)
|
||||
//http://www.ka7oei.com/ft817_memmap.html
|
||||
//CAT_BUFF[0] = 0xC2;
|
||||
//CAT_BUFF[1] = 0x82;
|
||||
break;
|
||||
case 0x5C : //Beep Volume (0-100) (#13)
|
||||
cat[0] = 0xB2;
|
||||
cat[1] = 0x42;
|
||||
break;
|
||||
case 0x5E :
|
||||
//3-0 : CW Pitch (300-1000 Hz) (#20) From 0 to E (HEX) with 0 = 300 Hz and each step representing 50 Hz
|
||||
//5-4 : Lock Mode (#32) 00 = Dial, 01 = Freq, 10 = Panel
|
||||
//7-6 : Op Filter (#38) 00 = Off, 01 = SSB, 10 = CW
|
||||
//CAT_BUFF[0] = 0x08;
|
||||
cat[0] = (sideTone - 300)/50;
|
||||
cat[1] = 0x25;
|
||||
break;
|
||||
case 0x61 : //Sidetone (Volume) (#44)
|
||||
cat[0] = sideTone % 50;
|
||||
cat[1] = 0x08;
|
||||
break;
|
||||
case 0x5F : //
|
||||
//4-0 CW Weight (1.:2.5-1:4.5) (#22) From 0 to 14 (HEX) with 0 = 1:2.5, incrementing in 0.1 weight steps
|
||||
//5 420 ARS (#2) 0 = Off, 1 = On
|
||||
//6 144 ARS (#1) 0 = Off, 1 = On
|
||||
//7 Sql/RF-G (#45) 0 = Off, 1 = On
|
||||
cat[0] = 0x32;
|
||||
cat[1] = 0x08;
|
||||
break;
|
||||
case 0x60 : //CW Delay (10-2500 ms) (#17) From 1 to 250 (decimal) with each step representing 10 ms
|
||||
cat[0] = cwDelayTime;
|
||||
cat[1] = 0x32;
|
||||
break;
|
||||
case 0x62 : //
|
||||
//5-0 CW Speed (4-60 WPM) (#21) From 0 to 38 (HEX) with 0 = 4 WPM and 38 = 60 WPM (1 WPM steps)
|
||||
//7-6 Batt-Chg (6/8/10 Hours (#11) 00 = 6 Hours, 01 = 8 Hours, 10 = 10 Hours
|
||||
//CAT_BUFF[0] = 0x08;
|
||||
cat[0] = 1200 / cwSpeed - 4;
|
||||
cat[1] = 0xB2;
|
||||
break;
|
||||
case 0x63 : //
|
||||
//6-0 VOX Gain (#51) Contains 1-100 (decimal) as displayed
|
||||
//7 Disable AM/FM Dial (#4) 0 = Enable, 1 = Disable
|
||||
cat[0] = 0xB2;
|
||||
cat[1] = 0xA5;
|
||||
break;
|
||||
case 0x64 : //
|
||||
break;
|
||||
case 0x67 : //6-0 SSB Mic (#46) Contains 0-100 (decimal) as displayed
|
||||
cat[0] = 0xB2;
|
||||
cat[1] = 0xB2;
|
||||
break; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed
|
||||
case 0x78 :
|
||||
if (isUSB)
|
||||
cat[0] = CAT_MODE_USB;
|
||||
else
|
||||
cat[0] = CAT_MODE_LSB;
|
||||
|
||||
if (cat[0] != 0) cat[0] = 1 << 5;
|
||||
break;
|
||||
case 0x79 : //
|
||||
//1-0 TX Power (All bands) 00 = High, 01 = L3, 10 = L2, 11 = L1
|
||||
//3 PRI On/Off 0 = Off, 1 = On
|
||||
//DW On/Off 0 = Off, 1 = On
|
||||
//SCN (Scan) Mode 00 = No scan, 10 = Scan up, 11 = Scan down
|
||||
//ART On/Off 0 = Off, 1 = On
|
||||
cat[0] = 0x00;
|
||||
cat[1] = 0x00;
|
||||
break;
|
||||
case 0x7A : //SPLIT
|
||||
//7A 0 HF Antenna Select 0 = Front, 1 = Rear
|
||||
//7A 1 6 M Antenna Select 0 = Front, 1 = Rear
|
||||
//7A 2 FM BCB Antenna Select 0 = Front, 1 = Rear
|
||||
//7A 3 Air Antenna Select 0 = Front, 1 = Rear
|
||||
//7A 4 2 M Antenna Select 0 = Front, 1 = Rear
|
||||
//7A 5 UHF Antenna Select 0 = Front, 1 = Rear
|
||||
//7A 6 ? ?
|
||||
//7A 7 SPL On/Off 0 = Off, 1 = On
|
||||
|
||||
cat[0] = (splitOn ? 0xFF : 0x7F);
|
||||
break;
|
||||
case 0xB3 : //
|
||||
cat[0] = 0x00;
|
||||
cat[1] = 0x4D;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// sent the data
|
||||
Serial.write(cat, 2);
|
||||
}
|
||||
|
||||
void processCATCommand2(byte* cmd) {
|
||||
byte response[5];
|
||||
unsigned long f;
|
||||
|
||||
switch(cmd[4]){
|
||||
/* case 0x00:
|
||||
response[0]=0;
|
||||
Serial.write(response, 1);
|
||||
break;
|
||||
*/
|
||||
case 0x01:
|
||||
//set frequency
|
||||
f = readFreq(cmd);
|
||||
setFrequency(f);
|
||||
updateDisplay();
|
||||
response[0]=0;
|
||||
Serial.write(response, 1);
|
||||
//sprintf(b, "set:%ld", f);
|
||||
//printLine2(b);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
//split on
|
||||
splitOn = 1;
|
||||
break;
|
||||
case 0x82:
|
||||
//split off
|
||||
splitOn = 0;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
writeFreq(frequency,response); // Put the frequency into the buffer
|
||||
if (isUSB)
|
||||
response[4] = 0x01; //USB
|
||||
else
|
||||
response[4] = 0x00; //LSB
|
||||
Serial.write(response,5);
|
||||
//printLine2("cat:getfreq");
|
||||
break;
|
||||
|
||||
case 0x07: // set mode
|
||||
if (cmd[0] == 0x00 || cmd[0] == 0x03)
|
||||
isUSB = 0;
|
||||
else
|
||||
isUSB = 1;
|
||||
response[0] = 0x00;
|
||||
Serial.write(response, 1);
|
||||
setFrequency(frequency);
|
||||
//printLine2("cat: mode changed");
|
||||
//updateDisplay();
|
||||
break;
|
||||
|
||||
case 0x08: // PTT On
|
||||
if (!inTx) {
|
||||
response[0] = 0;
|
||||
txCAT = true;
|
||||
startTx(TX_SSB);
|
||||
updateDisplay();
|
||||
} else {
|
||||
response[0] = 0xf0;
|
||||
}
|
||||
Serial.write(response,1);
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case 0x88 : //PTT OFF
|
||||
if (inTx) {
|
||||
stopTx();
|
||||
txCAT = false;
|
||||
}
|
||||
response[0] = 0;
|
||||
Serial.write(response,1);
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
//toggle the VFOs
|
||||
response[0] = 0;
|
||||
if (vfoActive == VFO_A)
|
||||
switchVFO(VFO_B);
|
||||
else
|
||||
switchVFO(VFO_A);
|
||||
//menuVfoToggle(1); // '1' forces it to change the VFO
|
||||
Serial.write(response,1);
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case 0xBB: //Read FT-817 EEPROM Data (for comfirtable)
|
||||
catReadEEPRom();
|
||||
break;
|
||||
|
||||
case 0xe7 :
|
||||
// get receiver status, we have hardcoded this as
|
||||
//as we dont' support ctcss, etc.
|
||||
response[0] = 0x09;
|
||||
Serial.write(response,1);
|
||||
break;
|
||||
|
||||
case 0xf7:
|
||||
{
|
||||
boolean isHighSWR = false;
|
||||
boolean isSplitOn = false;
|
||||
|
||||
/*
|
||||
Inverted -> *ptt = ((p->tx_status & 0x80) == 0); <-- souce code in ft817.c (hamlib)
|
||||
*/
|
||||
response[0] = ((inTx ? 0 : 1) << 7) +
|
||||
((isHighSWR ? 1 : 0) << 6) + //hi swr off / on
|
||||
((isSplitOn ? 1 : 0) << 5) + //Split on / off
|
||||
(0 << 4) + //dummy data
|
||||
0x08; //P0 meter data
|
||||
|
||||
Serial.write(response, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//somehow, get this to print the four bytes
|
||||
ultoa(*((unsigned long *)cmd), c, 16);
|
||||
/*itoa(cmd[4], b, 16);
|
||||
strcat(b, ">");
|
||||
strcat(b, c);
|
||||
printLine2(b);*/
|
||||
response[0] = 0x00;
|
||||
Serial.write(response[0]);
|
||||
}
|
||||
|
||||
insideCat = false;
|
||||
}
|
||||
|
||||
int catCount = 0;
|
||||
void checkCAT(){
|
||||
byte i;
|
||||
|
||||
//Check Serial Port Buffer
|
||||
if (Serial.available() == 0) { //Set Buffer Clear status
|
||||
rxBufferCheckCount = 0;
|
||||
return;
|
||||
}
|
||||
else if (Serial.available() < 5) { //First Arrived
|
||||
if (rxBufferCheckCount == 0){
|
||||
rxBufferCheckCount = Serial.available();
|
||||
rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout
|
||||
}
|
||||
else if (rxBufferArriveTime < millis()){ //Clear Buffer
|
||||
for (i = 0; i < Serial.available(); i++)
|
||||
rxBufferCheckCount = Serial.read();
|
||||
rxBufferCheckCount = 0;
|
||||
}
|
||||
else if (rxBufferCheckCount < Serial.available()){ // Increase buffer count, slow arrive
|
||||
rxBufferCheckCount = Serial.available();
|
||||
rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Arived CAT DATA
|
||||
for (i = 0; i < 5; i++)
|
||||
cat[i] = Serial.read();
|
||||
|
||||
|
||||
//this code is not re-entrant.
|
||||
if (insideCat == 1)
|
||||
return;
|
||||
insideCat = 1;
|
||||
|
||||
/**
|
||||
* This routine is enabled to debug the cat protocol
|
||||
**/
|
||||
catCount++;
|
||||
|
||||
/*
|
||||
if (cat[4] != 0xf7 && cat[4] != 0xbb && cat[4] != 0x03){
|
||||
sprintf(b, "%d %02x %02x%02x%02x%02x", catCount, cat[4],cat[0], cat[1], cat[2], cat[3]);
|
||||
printLine2(b);
|
||||
}
|
||||
*/
|
||||
|
||||
if (!doingCAT){
|
||||
doingCAT = 1;
|
||||
displayText("CAT on", 100,120,100,40, ILI9341_ORANGE, ILI9341_BLACK, ILI9341_WHITE);
|
||||
}
|
||||
|
||||
processCATCommand2(cat);
|
||||
insideCat = 0;
|
||||
}
|
||||
|
||||
|
97
ubitx_factory_alignment.ino
Normal file
97
ubitx_factory_alignment.ino
Normal file
@ -0,0 +1,97 @@
|
||||
|
||||
/**
|
||||
* This procedure is only for those who have a signal generator/transceiver tuned to exactly 7.150 and a dummy load
|
||||
*/
|
||||
|
||||
void btnWaitForClick(){
|
||||
while(!btnDown())
|
||||
active_delay(50);
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a deep breath, math(ematics) ahead
|
||||
* The 25 mhz oscillator is multiplied by 35 to run the vco at 875 mhz
|
||||
* This is divided by a number to generate different frequencies.
|
||||
* If we divide it by 875, we will get 1 mhz signal
|
||||
* So, if the vco is shifted up by 875 hz, the generated frequency of 1 mhz is shifted by 1 hz (875/875)
|
||||
* At 12 Mhz, the carrier will needed to be shifted down by 12 hz for every 875 hz of shift up of the vco
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
void factory_alignment(){
|
||||
|
||||
calibrateClock();
|
||||
|
||||
if (calibration == 0){
|
||||
printLine2("Setup Aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
//move it away to 7.160 for an LSB signal
|
||||
setFrequency(7170000l);
|
||||
updateDisplay();
|
||||
printLine2("#2 BFO");
|
||||
active_delay(1000);
|
||||
|
||||
usbCarrier = 11053000l;
|
||||
menuSetupCarrier(1);
|
||||
|
||||
if (usbCarrier == 11994999l){
|
||||
printLine2("Setup Aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
printLine2("#3:Test 3.5MHz");
|
||||
isUSB = false;
|
||||
setFrequency(3500000l);
|
||||
updateDisplay();
|
||||
|
||||
while (!btnDown()){
|
||||
checkPTT();
|
||||
active_delay(100);
|
||||
}
|
||||
|
||||
btnWaitForClick();
|
||||
printLine2("#4:Test 7MHz");
|
||||
|
||||
setFrequency(7150000l);
|
||||
updateDisplay();
|
||||
while (!btnDown()){
|
||||
checkPTT();
|
||||
active_delay(100);
|
||||
}
|
||||
|
||||
btnWaitForClick();
|
||||
printLine2("#5:Test 14MHz");
|
||||
|
||||
isUSB = true;
|
||||
setFrequency(14000000l);
|
||||
updateDisplay();
|
||||
while (!btnDown()){
|
||||
checkPTT();
|
||||
active_delay(100);
|
||||
}
|
||||
|
||||
btnWaitForClick();
|
||||
printLine2("#6:Test 28MHz");
|
||||
|
||||
setFrequency(28000000l);
|
||||
updateDisplay();
|
||||
while (!btnDown()){
|
||||
checkPTT();
|
||||
active_delay(100);
|
||||
}
|
||||
|
||||
printLine2("Alignment done");
|
||||
active_delay(1000);
|
||||
|
||||
isUSB = false;
|
||||
setFrequency(7150000l);
|
||||
updateDisplay();
|
||||
|
||||
}
|
||||
*/
|
355
ubitx_font2.h
Normal file
355
ubitx_font2.h
Normal file
@ -0,0 +1,355 @@
|
||||
const uint8_t ubitxBitmaps[] PROGMEM = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC,
|
||||
0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F,
|
||||
0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC,
|
||||
0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F,
|
||||
0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC,
|
||||
0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F,
|
||||
0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC,
|
||||
0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F,
|
||||
0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC,
|
||||
0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F,
|
||||
0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC,
|
||||
0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F,
|
||||
0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x21, 0xFF, 0xE0, 0xF3, 0xF9, 0xFC, 0xFE, 0x7E,
|
||||
0x3B, 0x1D, 0x84, 0x0E, 0x70, 0x73, 0x83, 0x9C, 0x18, 0xC7, 0xFF, 0xBF,
|
||||
0xFD, 0xFF, 0xE3, 0x9C, 0x18, 0xC0, 0xC6, 0x0E, 0x7D, 0xFF, 0xEF, 0xFF,
|
||||
0x18, 0xC0, 0xC6, 0x0E, 0x70, 0x73, 0x83, 0x9C, 0x00, 0x04, 0x01, 0xF8,
|
||||
0x7F, 0xCF, 0xDE, 0xE4, 0xEE, 0x4E, 0xE4, 0x0F, 0x40, 0x7E, 0x03, 0xFC,
|
||||
0x0F, 0xE0, 0x5E, 0x04, 0xFE, 0x4F, 0xE4, 0xFF, 0x4E, 0x7F, 0xE3, 0xFC,
|
||||
0x04, 0x00, 0x40, 0x04, 0x00, 0x3C, 0x06, 0x07, 0xE0, 0x60, 0xFF, 0x0C,
|
||||
0x0C, 0x30, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xFF, 0x30, 0x07, 0xE6,
|
||||
0x00, 0x3C, 0x60, 0x00, 0x0C, 0x7C, 0x00, 0xCF, 0xE0, 0x19, 0xC6, 0x01,
|
||||
0x98, 0x70, 0x31, 0x87, 0x03, 0x1C, 0x60, 0x60, 0xFE, 0x04, 0x07, 0xC0,
|
||||
0x0F, 0x80, 0x1F, 0xC0, 0x3D, 0xE0, 0x38, 0xE0, 0x3C, 0xE0, 0x1D, 0xC0,
|
||||
0x1F, 0xC0, 0x0F, 0x00, 0x3F, 0x8C, 0x7B, 0xDC, 0x71, 0xDC, 0xF1, 0xFC,
|
||||
0xF0, 0xF8, 0xF0, 0x78, 0x79, 0xFC, 0x7F, 0xFC, 0x3F, 0x9E, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xE6, 0x60, 0x0C, 0x71, 0x8E, 0x31, 0xC7, 0x38, 0xE3, 0x8E,
|
||||
0x38, 0xE3, 0x8E, 0x38, 0x71, 0xC7, 0x0E, 0x38, 0x70, 0xC0, 0xC3, 0x86,
|
||||
0x1C, 0x70, 0xE3, 0x8E, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xCE, 0x38, 0xE7,
|
||||
0x1C, 0x63, 0x8C, 0x00, 0x10, 0x10, 0x10, 0xFE, 0x7C, 0x38, 0x6C, 0x44,
|
||||
0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x60,
|
||||
0x06, 0x00, 0x60, 0x06, 0x00, 0xFF, 0xF2, 0xFE, 0xFF, 0xFF, 0xC0, 0xFF,
|
||||
0xF0, 0x04, 0x08, 0x30, 0x60, 0x83, 0x06, 0x08, 0x10, 0x60, 0xC1, 0x06,
|
||||
0x0C, 0x10, 0x20, 0xC0, 0x3F, 0x8F, 0xF9, 0xEF, 0x78, 0xFE, 0x0F, 0xC1,
|
||||
0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xE3, 0xDE,
|
||||
0xF3, 0xFE, 0x3F, 0x80, 0x80, 0x06, 0x1C, 0x7F, 0xFF, 0xE1, 0xC3, 0x87,
|
||||
0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x3F, 0x8F, 0xFB, 0xEF,
|
||||
0xF8, 0x7E, 0x0F, 0xC1, 0xC0, 0x38, 0x0F, 0x03, 0xC0, 0xF0, 0x7C, 0x1F,
|
||||
0x07, 0x80, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0x8F, 0xFB, 0xCF,
|
||||
0xF0, 0xFE, 0x1E, 0x03, 0xC0, 0x70, 0x7C, 0x0F, 0xC0, 0xFC, 0x03, 0x80,
|
||||
0x7E, 0x0F, 0xC1, 0xFC, 0xFB, 0xFE, 0x3F, 0x80, 0x80, 0x07, 0xC0, 0x7C,
|
||||
0x0F, 0xC0, 0xFC, 0x1F, 0xC3, 0xBC, 0x33, 0xC7, 0x3C, 0x63, 0xCE, 0x3C,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3F,
|
||||
0xEF, 0xFD, 0xFF, 0xB8, 0x06, 0x00, 0xC0, 0x1F, 0xE7, 0xFE, 0xF1, 0xE0,
|
||||
0x1C, 0x03, 0x80, 0x70, 0x0F, 0xC1, 0xFC, 0xFB, 0xFE, 0x3F, 0x80, 0x80,
|
||||
0x1F, 0x87, 0xF9, 0xE7, 0xB8, 0x7E, 0x01, 0xC0, 0x3B, 0xE7, 0xFE, 0xFB,
|
||||
0xFE, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xE1, 0xDE, 0xFB, 0xFE, 0x3F, 0x80,
|
||||
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0E, 0x01, 0xC0, 0x3C, 0x03, 0x80,
|
||||
0x70, 0x0F, 0x00, 0xE0, 0x0E, 0x01, 0xE0, 0x1C, 0x01, 0xC0, 0x1C, 0x03,
|
||||
0xC0, 0x3C, 0x00, 0x3F, 0x87, 0xFC, 0xF9, 0xEE, 0x0E, 0xE0, 0xEE, 0x0E,
|
||||
0x71, 0xC3, 0xF8, 0x7F, 0xCF, 0x1E, 0xE0, 0xEE, 0x0F, 0xE0, 0xFE, 0x0E,
|
||||
0xF1, 0xE7, 0xFC, 0x3F, 0x80, 0x40, 0x3F, 0x0F, 0xFB, 0xEF, 0x70, 0xFE,
|
||||
0x0F, 0xC1, 0xF8, 0x3F, 0x0F, 0xF3, 0xEF, 0xFC, 0xFB, 0x80, 0x70, 0x0F,
|
||||
0xC3, 0xFE, 0xF3, 0xFE, 0x3F, 0x80, 0x80, 0xFF, 0x80, 0x00, 0xFF, 0xF0,
|
||||
0xFF, 0x80, 0x00, 0xFF, 0xF2, 0xDE, 0x00, 0x70, 0x1F, 0x0F, 0xE7, 0xF0,
|
||||
0xF8, 0x0E, 0x00, 0xFC, 0x03, 0xF8, 0x0F, 0xE0, 0x1F, 0x00, 0x30, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0xC0, 0x0F, 0x80, 0x7F, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0x03, 0xF1,
|
||||
0xFC, 0xFE, 0x0F, 0x80, 0xC0, 0x00, 0x1F, 0x0F, 0xF3, 0xFF, 0x78, 0xFE,
|
||||
0x0F, 0xC1, 0xC0, 0x38, 0x0F, 0x03, 0xE0, 0xF8, 0x3C, 0x07, 0x00, 0xE0,
|
||||
0x00, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xFE,
|
||||
0x00, 0xF0, 0x3C, 0x07, 0x00, 0x38, 0x38, 0x00, 0x30, 0xC0, 0x00, 0xE6,
|
||||
0x0F, 0xF1, 0x98, 0x73, 0xC7, 0xC3, 0x87, 0x0F, 0x0C, 0x1C, 0x3C, 0x30,
|
||||
0x61, 0xF1, 0xC1, 0x86, 0xC7, 0x0E, 0x1B, 0x1C, 0x38, 0xEC, 0x3B, 0xEF,
|
||||
0x38, 0xFD, 0xF8, 0x70, 0xC1, 0x80, 0xE0, 0x00, 0x01, 0xC0, 0x10, 0x03,
|
||||
0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0xE0, 0x07,
|
||||
0xE0, 0x0F, 0xE0, 0x0E, 0xF0, 0x0E, 0xF0, 0x1E, 0x70, 0x1C, 0x78, 0x1C,
|
||||
0x78, 0x3C, 0x38, 0x3F, 0xFC, 0x3F, 0xFC, 0x7F, 0xFC, 0x70, 0x1E, 0xF0,
|
||||
0x1E, 0xF0, 0x0E, 0xE0, 0x0F, 0xFF, 0x03, 0xFF, 0xCF, 0xFF, 0xBC, 0x7E,
|
||||
0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBF, 0xFE, 0xFF, 0xE3, 0xFF, 0xCF, 0x0F,
|
||||
0xBC, 0x0F, 0xF0, 0x1F, 0xC0, 0xFF, 0x03, 0xFF, 0xFE, 0xFF, 0xFB, 0xFF,
|
||||
0x80, 0x03, 0xC0, 0x1F, 0xF0, 0xFF, 0xF1, 0xF1, 0xE7, 0x81, 0xEF, 0x01,
|
||||
0xFC, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F,
|
||||
0x00, 0xEF, 0x01, 0xDE, 0x07, 0x9F, 0xFE, 0x1F, 0xFC, 0x1F, 0xE0, 0x04,
|
||||
0x00, 0xFE, 0x03, 0xFF, 0x8F, 0xFF, 0x38, 0x7E, 0xE0, 0x7B, 0x80, 0xFE,
|
||||
0x03, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x3F,
|
||||
0x80, 0xFE, 0x07, 0xBF, 0xFE, 0xFF, 0xF3, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFE, 0xFF, 0xF7,
|
||||
0xFF, 0xBC, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xE0, 0x0E, 0x00,
|
||||
0xE0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00,
|
||||
0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x03, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC,
|
||||
0x3E, 0x3E, 0x78, 0x0F, 0x70, 0x0F, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00,
|
||||
0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x07, 0x78, 0x0F, 0x7C, 0x1F,
|
||||
0x3F, 0xFF, 0x1F, 0xFB, 0x0F, 0xF3, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8,
|
||||
0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||
0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F,
|
||||
0x80, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xE0, 0x3C,
|
||||
0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07,
|
||||
0x80, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0xFE, 0xFF, 0xCF, 0xF0, 0x00, 0x00,
|
||||
0xE0, 0x3D, 0xC0, 0xFB, 0x83, 0xE7, 0x07, 0x8E, 0x1E, 0x1C, 0x78, 0x39,
|
||||
0xE0, 0x77, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0xFE, 0x07, 0x9E, 0x0E, 0x1E,
|
||||
0x1C, 0x1E, 0x38, 0x3C, 0x70, 0x3C, 0xE0, 0x3D, 0xC0, 0x3C, 0xF0, 0x0F,
|
||||
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
|
||||
0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xF8, 0x1F, 0xFC, 0x0F, 0xFE, 0x07, 0xFF, 0x83, 0xFF, 0xC3, 0xFF,
|
||||
0xE1, 0xFF, 0xB0, 0xFF, 0xDC, 0x6F, 0xEE, 0x77, 0xF7, 0x3B, 0xF9, 0x9D,
|
||||
0xFC, 0xCC, 0xFE, 0x76, 0x7F, 0x3F, 0x3F, 0x8F, 0x9F, 0xC7, 0xCF, 0xE3,
|
||||
0xC7, 0xF1, 0xE3, 0xC0, 0xE0, 0x3F, 0xC0, 0xFF, 0x03, 0xFE, 0x0F, 0xFC,
|
||||
0x3F, 0xF0, 0xFE, 0xE3, 0xFB, 0x8F, 0xE7, 0x3F, 0x9E, 0xFE, 0x3B, 0xF8,
|
||||
0xFF, 0xE1, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x1F, 0xE0, 0x7F, 0x80, 0xF0,
|
||||
0x03, 0xE0, 0x07, 0xFC, 0x07, 0xFF, 0x07, 0xCF, 0xC7, 0x81, 0xF3, 0xC0,
|
||||
0x7B, 0xC0, 0x1D, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE,
|
||||
0x00, 0xFF, 0x00, 0x73, 0xC0, 0x79, 0xF0, 0x7C, 0x7F, 0xFC, 0x1F, 0xFC,
|
||||
0x07, 0xFC, 0x00, 0x20, 0x00, 0xFF, 0x07, 0xFF, 0x3F, 0xFD, 0xC3, 0xFE,
|
||||
0x07, 0xF0, 0x1F, 0x80, 0xFC, 0x0F, 0xE0, 0xFF, 0xFF, 0xBF, 0xF9, 0xFF,
|
||||
0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x03,
|
||||
0xE0, 0x07, 0xFC, 0x07, 0xFF, 0x07, 0xCF, 0xC7, 0x80, 0xF3, 0xC0, 0x7B,
|
||||
0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, 0x04,
|
||||
0xFF, 0x07, 0x73, 0xC3, 0xF9, 0xF0, 0xFC, 0x7F, 0xFC, 0x1F, 0xFF, 0x07,
|
||||
0xFF, 0xC0, 0x20, 0xC0, 0xFF, 0x83, 0xFF, 0xCF, 0xFF, 0xBC, 0x3F, 0xF0,
|
||||
0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xFF, 0xFB, 0xFF, 0x8F, 0xFF, 0xBC,
|
||||
0x1E, 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBC, 0x0E, 0xF0, 0x3F, 0xC0, 0xF0,
|
||||
0x0F, 0x80, 0xFF, 0xC7, 0xFF, 0xBE, 0x1E, 0xF0, 0x3B, 0xC0, 0xFF, 0x00,
|
||||
0x3F, 0x80, 0x7F, 0xE0, 0xFF, 0xE0, 0x3F, 0xC0, 0x0F, 0x00, 0x1F, 0x80,
|
||||
0x7F, 0x03, 0xFF, 0x1F, 0x7F, 0xF8, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0,
|
||||
0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38,
|
||||
0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8,
|
||||
0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFE,
|
||||
0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0xC0, 0xFF, 0x07, 0x9F, 0xFE, 0x7F, 0xF0,
|
||||
0x7F, 0x80, 0x20, 0x00, 0xE0, 0x1F, 0xC0, 0x3B, 0xC0, 0xF3, 0x81, 0xE7,
|
||||
0x03, 0x8F, 0x0F, 0x0E, 0x1C, 0x1C, 0x38, 0x3C, 0x70, 0x39, 0xC0, 0x73,
|
||||
0x80, 0xE7, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x03, 0xC0, 0x07, 0x80,
|
||||
0x0F, 0x00, 0xF0, 0x38, 0x1D, 0xC1, 0xE0, 0xF7, 0x87, 0xC3, 0xDE, 0x1F,
|
||||
0x0F, 0x78, 0x7C, 0x38, 0xE3, 0xB0, 0xE3, 0x8E, 0xC7, 0x8F, 0x3B, 0x9C,
|
||||
0x1C, 0xEE, 0x70, 0x73, 0x39, 0xC1, 0xDC, 0x67, 0x07, 0x71, 0xB8, 0x0F,
|
||||
0xC7, 0xE0, 0x3E, 0x1F, 0x80, 0xF8, 0x3E, 0x01, 0xE0, 0xF0, 0x07, 0x83,
|
||||
0xC0, 0x1E, 0x0F, 0x00, 0xF0, 0x3D, 0xF0, 0x79, 0xE1, 0xE1, 0xE3, 0xC3,
|
||||
0xCF, 0x03, 0xFC, 0x07, 0xF8, 0x07, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x3F,
|
||||
0x00, 0x7F, 0x01, 0xFE, 0x07, 0x9E, 0x0F, 0x3C, 0x3C, 0x3C, 0xF8, 0x3D,
|
||||
0xE0, 0x78, 0xF0, 0x1F, 0xE0, 0x79, 0xE0, 0xF3, 0xC3, 0xC3, 0xC7, 0x87,
|
||||
0x9E, 0x07, 0x3C, 0x0F, 0x70, 0x0F, 0xE0, 0x1F, 0x80, 0x1F, 0x00, 0x3C,
|
||||
0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x80,
|
||||
0x78, 0x07, 0x80, 0x78, 0x07, 0x80, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0,
|
||||
0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xCE, 0x73, 0x9C, 0xE7,
|
||||
0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCF, 0xFF, 0xE0, 0xC1, 0x81, 0x02,
|
||||
0x06, 0x04, 0x08, 0x18, 0x30, 0x20, 0x60, 0xC0, 0x81, 0x83, 0x02, 0x06,
|
||||
0xFF, 0xFF, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7,
|
||||
0x1C, 0x71, 0xC7, 0xFF, 0xFF, 0xC0, 0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xF8,
|
||||
0x1B, 0x83, 0x9C, 0x39, 0xC3, 0x0C, 0x70, 0xE7, 0x0E, 0xE0, 0x70, 0xFF,
|
||||
0xFF, 0xFF, 0xFC, 0x71, 0x86, 0x3F, 0x87, 0xFC, 0xFF, 0xEE, 0x1E, 0x01,
|
||||
0xE0, 0xFE, 0x7F, 0xEF, 0x8E, 0xE1, 0xEE, 0x1E, 0xF3, 0xEF, 0xFE, 0x7E,
|
||||
0xE1, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x7B, 0xE3,
|
||||
0xFF, 0x9F, 0xFE, 0xF8, 0xF7, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8,
|
||||
0x3F, 0xC1, 0xDF, 0x9E, 0xFF, 0xE7, 0xFE, 0x00, 0x40, 0x1F, 0x83, 0xFC,
|
||||
0x7F, 0xEF, 0x0E, 0xE0, 0xEE, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0x0E,
|
||||
0x79, 0xE7, 0xFC, 0x3F, 0x80, 0x00, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07,
|
||||
0x00, 0x71, 0xE7, 0x3F, 0xF7, 0xFF, 0xF0, 0xFE, 0x0F, 0xE0, 0x7E, 0x07,
|
||||
0xE0, 0x7E, 0x0F, 0xF0, 0xF7, 0x9F, 0x7F, 0xF3, 0xF7, 0x00, 0x00, 0x1F,
|
||||
0x07, 0xFC, 0x7B, 0xEE, 0x0E, 0xE0, 0xEF, 0xFE, 0xFF, 0xFF, 0xFF, 0xE0,
|
||||
0x0E, 0x0E, 0xF1, 0xE7, 0xFC, 0x3F, 0x80, 0x40, 0x00, 0x1E, 0x3E, 0x3C,
|
||||
0x3C, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x3C, 0x3C, 0x1E, 0x73, 0xF7, 0x7F, 0xFF, 0x0F, 0xF0, 0xFE, 0x07, 0xE0,
|
||||
0x7E, 0x07, 0xE0, 0x7F, 0x0F, 0x79, 0xF7, 0xFF, 0x3F, 0x70, 0x07, 0x00,
|
||||
0x7F, 0x0F, 0x7F, 0xE3, 0xFC, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01,
|
||||
0xDF, 0x3F, 0xF7, 0xFF, 0xF1, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1,
|
||||
0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1C, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFC, 0x39, 0xCE, 0x70, 0x1C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39,
|
||||
0xCE, 0x7F, 0xFF, 0xC0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F,
|
||||
0x0E, 0xF1, 0xEF, 0x3C, 0xF7, 0x8F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x8F,
|
||||
0x3C, 0xF3, 0xCF, 0x1E, 0xF1, 0xEF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFC, 0xF7, 0xCF, 0x9F, 0xFF, 0xFB, 0xFF, 0xFF, 0xF8, 0x78, 0xFF,
|
||||
0x0E, 0x1F, 0xE1, 0xC3, 0xFC, 0x38, 0x7F, 0x87, 0x0F, 0xF0, 0xE1, 0xFE,
|
||||
0x1C, 0x3F, 0xC3, 0x87, 0xF8, 0x70, 0xFF, 0x0E, 0x1E, 0xEF, 0x9F, 0xFB,
|
||||
0xFF, 0xF8, 0xFE, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83,
|
||||
0xF0, 0x7E, 0x0E, 0x1F, 0x81, 0xFF, 0x1F, 0xFD, 0xE1, 0xEF, 0x07, 0x70,
|
||||
0x3F, 0x81, 0xFC, 0x0F, 0xE0, 0x7F, 0x83, 0x9E, 0x3C, 0xFF, 0xC3, 0xFC,
|
||||
0x01, 0x00, 0xF7, 0xC7, 0xFF, 0x3F, 0xFD, 0xF1, 0xEF, 0x07, 0xF8, 0x3F,
|
||||
0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xBE, 0x3D, 0xFF, 0xCF, 0x7C, 0x78,
|
||||
0x83, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x00, 0x1E, 0x77, 0xF7, 0x7F,
|
||||
0xFF, 0x0F, 0xE0, 0xFE, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0xFF, 0x0F, 0xF9,
|
||||
0xF7, 0xFF, 0x3F, 0x70, 0x47, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0xEF,
|
||||
0xFF, 0xFF, 0x8E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x00, 0x3F,
|
||||
0x8F, 0xFB, 0xEF, 0xF8, 0x7F, 0x01, 0xFE, 0x1F, 0xF0, 0xFF, 0x01, 0xFC,
|
||||
0x1F, 0xC3, 0xFF, 0xF7, 0xFC, 0x08, 0x00, 0x38, 0x70, 0xE7, 0xFF, 0xFF,
|
||||
0xCE, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0F, 0x8F, 0x04, 0xF0, 0x7F,
|
||||
0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F,
|
||||
0x0F, 0x79, 0xF7, 0xFF, 0x3F, 0x70, 0x80, 0xF0, 0x7B, 0x83, 0x9E, 0x1C,
|
||||
0x71, 0xE3, 0x8E, 0x1E, 0x70, 0x73, 0x83, 0xB8, 0x1D, 0xC0, 0x7E, 0x03,
|
||||
0xE0, 0x1F, 0x00, 0x78, 0x00, 0xF0, 0xE1, 0xDC, 0x78, 0x77, 0x1F, 0x3D,
|
||||
0xC7, 0xCE, 0x79, 0xF3, 0x8E, 0xEC, 0xE3, 0xBB, 0x78, 0xEC, 0xFC, 0x1F,
|
||||
0x3F, 0x07, 0xCF, 0xC1, 0xF1, 0xE0, 0x7C, 0x78, 0x0E, 0x1E, 0x00, 0x78,
|
||||
0xF3, 0xC7, 0x8F, 0x78, 0x3B, 0x81, 0xFC, 0x07, 0xC0, 0x1E, 0x01, 0xF0,
|
||||
0x1F, 0xC0, 0xEF, 0x0F, 0x78, 0xF1, 0xE7, 0x87, 0x80, 0xF0, 0x7B, 0x83,
|
||||
0x9E, 0x1C, 0xF1, 0xE3, 0x8E, 0x1E, 0x70, 0x73, 0x83, 0xB8, 0x1D, 0xC0,
|
||||
0x7E, 0x03, 0xE0, 0x1F, 0x00, 0x78, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x3E,
|
||||
0x01, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x1E, 0x0F, 0x83, 0xC1, 0xE0,
|
||||
0xF0, 0x78, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0x3C, 0xF9, 0xC3,
|
||||
0x87, 0x0E, 0x1C, 0x38, 0x73, 0xC7, 0x0F, 0x07, 0x0E, 0x1C, 0x38, 0x70,
|
||||
0xE1, 0xC3, 0xE7, 0xC7, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xC3,
|
||||
0xCF, 0x0C, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0xC7, 0x3C, 0xE3, 0x8E, 0x38,
|
||||
0xE3, 0x8E, 0xF3, 0xCE, 0x00, 0x10, 0x0F, 0x85, 0xBD, 0xE1, 0xF0, 0x08,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC,
|
||||
0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0 };
|
||||
|
||||
const GFXglyph ubitxGlyphs[] PROGMEM = {
|
||||
{ 0, 13, 18, 17, 2, -17 }, // 0x14
|
||||
{ 30, 13, 18, 17, 2, -17 }, // 0x15
|
||||
{ 60, 13, 18, 17, 2, -17 }, // 0x16
|
||||
{ 90, 13, 18, 17, 2, -17 }, // 0x17
|
||||
{ 120, 13, 18, 17, 2, -17 }, // 0x18
|
||||
{ 150, 13, 18, 17, 2, -17 }, // 0x19
|
||||
{ 180, 13, 18, 17, 2, -17 }, // 0x1A
|
||||
{ 210, 13, 18, 17, 2, -17 }, // 0x1B
|
||||
{ 240, 13, 18, 17, 2, -17 }, // 0x1C
|
||||
{ 270, 13, 18, 17, 2, -17 }, // 0x1D
|
||||
{ 300, 13, 18, 17, 2, -17 }, // 0x1E
|
||||
{ 330, 13, 18, 17, 2, -17 }, // 0x1F
|
||||
{ 360, 0, 0, 7, 0, 1 }, // 0x20 ' '
|
||||
{ 360, 3, 17, 8, 3, -16 }, // 0x21 '!'
|
||||
{ 367, 9, 7, 11, 1, -17 }, // 0x22 '"'
|
||||
{ 375, 13, 18, 13, 0, -16 }, // 0x23 '#'
|
||||
{ 405, 12, 21, 13, 1, -17 }, // 0x24 '$'
|
||||
{ 437, 20, 17, 21, 1, -16 }, // 0x25 '%'
|
||||
{ 480, 16, 18, 17, 1, -16 }, // 0x26 '&'
|
||||
{ 516, 4, 7, 6, 1, -17 }, // 0x27 '''
|
||||
{ 520, 6, 23, 8, 1, -17 }, // 0x28 '('
|
||||
{ 538, 6, 23, 8, 1, -17 }, // 0x29 ')'
|
||||
{ 556, 8, 8, 9, 1, -17 }, // 0x2A '*'
|
||||
{ 564, 12, 11, 14, 1, -10 }, // 0x2B '+'
|
||||
{ 581, 3, 8, 7, 2, -3 }, // 0x2C ','
|
||||
{ 584, 6, 3, 8, 1, -7 }, // 0x2D '-'
|
||||
{ 587, 3, 4, 7, 2, -3 }, // 0x2E '.'
|
||||
{ 589, 7, 17, 7, 0, -16 }, // 0x2F '/'
|
||||
{ 604, 11, 18, 13, 1, -16 }, // 0x30 '0'
|
||||
{ 629, 7, 17, 13, 2, -16 }, // 0x31 '1'
|
||||
{ 644, 11, 17, 13, 1, -16 }, // 0x32 '2'
|
||||
{ 668, 11, 18, 13, 1, -16 }, // 0x33 '3'
|
||||
{ 693, 12, 17, 13, 1, -16 }, // 0x34 '4'
|
||||
{ 719, 11, 18, 13, 1, -16 }, // 0x35 '5'
|
||||
{ 744, 11, 18, 13, 1, -16 }, // 0x36 '6'
|
||||
{ 769, 12, 17, 13, 1, -16 }, // 0x37 '7'
|
||||
{ 795, 12, 18, 13, 1, -16 }, // 0x38 '8'
|
||||
{ 822, 11, 18, 13, 1, -16 }, // 0x39 '9'
|
||||
{ 847, 3, 12, 8, 3, -11 }, // 0x3A ':'
|
||||
{ 852, 3, 16, 8, 3, -11 }, // 0x3B ';'
|
||||
{ 858, 12, 11, 14, 1, -10 }, // 0x3C '<'
|
||||
{ 875, 12, 9, 14, 1, -9 }, // 0x3D '='
|
||||
{ 889, 12, 11, 14, 1, -10 }, // 0x3E '>'
|
||||
{ 906, 11, 18, 15, 2, -17 }, // 0x3F '?'
|
||||
{ 931, 22, 21, 23, 1, -17 }, // 0x40 '@'
|
||||
{ 989, 16, 18, 17, 1, -17 }, // 0x41 'A'
|
||||
{ 1025, 14, 18, 17, 2, -17 }, // 0x42 'B'
|
||||
{ 1057, 15, 19, 17, 1, -17 }, // 0x43 'C'
|
||||
{ 1093, 14, 18, 17, 2, -17 }, // 0x44 'D'
|
||||
{ 1125, 13, 18, 16, 2, -17 }, // 0x45 'E'
|
||||
{ 1155, 12, 18, 15, 2, -17 }, // 0x46 'F'
|
||||
{ 1182, 16, 18, 19, 1, -17 }, // 0x47 'G'
|
||||
{ 1218, 14, 18, 17, 2, -17 }, // 0x48 'H'
|
||||
{ 1250, 3, 18, 7, 2, -17 }, // 0x49 'I'
|
||||
{ 1257, 11, 19, 13, 1, -17 }, // 0x4A 'J'
|
||||
{ 1284, 15, 18, 17, 2, -17 }, // 0x4B 'K'
|
||||
{ 1318, 12, 18, 15, 2, -17 }, // 0x4C 'L'
|
||||
{ 1345, 17, 18, 20, 2, -17 }, // 0x4D 'M'
|
||||
{ 1384, 14, 18, 17, 2, -17 }, // 0x4E 'N'
|
||||
{ 1416, 17, 19, 19, 1, -17 }, // 0x4F 'O'
|
||||
{ 1457, 13, 18, 16, 2, -17 }, // 0x50 'P'
|
||||
{ 1487, 17, 19, 19, 1, -17 }, // 0x51 'Q'
|
||||
{ 1528, 14, 18, 17, 2, -17 }, // 0x52 'R'
|
||||
{ 1560, 14, 19, 16, 1, -17 }, // 0x53 'S'
|
||||
{ 1594, 14, 18, 15, 0, -17 }, // 0x54 'T'
|
||||
{ 1626, 14, 19, 17, 2, -17 }, // 0x55 'U'
|
||||
{ 1660, 15, 18, 16, 1, -17 }, // 0x56 'V'
|
||||
{ 1694, 22, 18, 23, 0, -17 }, // 0x57 'W'
|
||||
{ 1744, 15, 18, 16, 1, -17 }, // 0x58 'X'
|
||||
{ 1778, 15, 18, 16, 1, -17 }, // 0x59 'Y'
|
||||
{ 1812, 13, 18, 15, 1, -17 }, // 0x5A 'Z'
|
||||
{ 1842, 5, 23, 8, 2, -17 }, // 0x5B '['
|
||||
{ 1857, 7, 17, 7, 0, -16 }, // 0x5C '\'
|
||||
{ 1872, 6, 23, 8, 0, -17 }, // 0x5D ']'
|
||||
{ 1890, 12, 11, 14, 1, -16 }, // 0x5E '^'
|
||||
{ 1907, 15, 2, 13, -1, 4 }, // 0x5F '_'
|
||||
{ 1911, 5, 3, 8, 0, -17 }, // 0x60 '`'
|
||||
{ 1913, 12, 14, 13, 1, -12 }, // 0x61 'a'
|
||||
{ 1934, 13, 19, 15, 1, -17 }, // 0x62 'b'
|
||||
{ 1965, 12, 14, 13, 1, -12 }, // 0x63 'c'
|
||||
{ 1986, 12, 19, 15, 1, -17 }, // 0x64 'd'
|
||||
{ 2015, 12, 14, 13, 1, -12 }, // 0x65 'e'
|
||||
{ 2036, 8, 18, 8, 0, -17 }, // 0x66 'f'
|
||||
{ 2054, 12, 18, 15, 1, -12 }, // 0x67 'g'
|
||||
{ 2081, 11, 18, 15, 2, -17 }, // 0x68 'h'
|
||||
{ 2106, 3, 18, 7, 2, -17 }, // 0x69 'i'
|
||||
{ 2113, 5, 23, 7, 0, -17 }, // 0x6A 'j'
|
||||
{ 2128, 12, 18, 13, 1, -17 }, // 0x6B 'k'
|
||||
{ 2155, 3, 18, 7, 2, -17 }, // 0x6C 'l'
|
||||
{ 2162, 19, 13, 21, 1, -12 }, // 0x6D 'm'
|
||||
{ 2193, 11, 13, 15, 2, -12 }, // 0x6E 'n'
|
||||
{ 2211, 13, 14, 15, 1, -12 }, // 0x6F 'o'
|
||||
{ 2234, 13, 18, 15, 1, -12 }, // 0x70 'p'
|
||||
{ 2264, 12, 18, 15, 1, -12 }, // 0x71 'q'
|
||||
{ 2291, 7, 13, 9, 2, -12 }, // 0x72 'r'
|
||||
{ 2303, 11, 14, 13, 1, -12 }, // 0x73 's'
|
||||
{ 2323, 7, 17, 8, 0, -15 }, // 0x74 't'
|
||||
{ 2338, 12, 14, 15, 1, -12 }, // 0x75 'u'
|
||||
{ 2359, 13, 13, 13, 0, -12 }, // 0x76 'v'
|
||||
{ 2381, 18, 13, 19, 0, -12 }, // 0x77 'w'
|
||||
{ 2411, 13, 13, 13, 0, -12 }, // 0x78 'x'
|
||||
{ 2433, 13, 18, 13, 0, -12 }, // 0x79 'y'
|
||||
{ 2463, 10, 13, 12, 1, -12 }, // 0x7A 'z'
|
||||
{ 2480, 7, 23, 9, 1, -17 }, // 0x7B '{'
|
||||
{ 2501, 2, 23, 7, 2, -17 }, // 0x7C '|'
|
||||
{ 2507, 6, 23, 9, 2, -17 }, // 0x7D '}'
|
||||
{ 2525, 11, 5, 14, 1, -7 }, // 0x7E '~'
|
||||
{ 2532, 13, 18, 17, 2, -17 } }; // 0x7F
|
||||
|
||||
const GFXfont ubitx_font PROGMEM = {
|
||||
(uint8_t *)ubitxBitmaps,
|
||||
(GFXglyph *)ubitxGlyphs,
|
||||
0x14, 0x7F, 33 };
|
||||
|
||||
// Approx. 3325 bytes
|
||||
|
||||
// Color definitions
|
||||
#define ILI9341_BLACK 0x0000 ///< 0, 0, 0
|
||||
#define ILI9341_NAVY 0x000F ///< 0, 0, 123
|
||||
#define ILI9341_DARKGREEN 0x03E0 ///< 0, 125, 0
|
||||
#define ILI9341_DARKCYAN 0x03EF ///< 0, 125, 123
|
||||
#define ILI9341_MAROON 0x7800 ///< 123, 0, 0
|
||||
#define ILI9341_PURPLE 0x780F ///< 123, 0, 123
|
||||
#define ILI9341_OLIVE 0x7BE0 ///< 123, 125, 0
|
||||
#define ILI9341_LIGHTGREY 0xC618 ///< 198, 195, 198
|
||||
#define ILI9341_DARKGREY 0x7BEF ///< 123, 125, 123
|
||||
#define ILI9341_BLUE 0x001F ///< 0, 0, 255
|
||||
#define ILI9341_GREEN 0x07E0 ///< 0, 255, 0
|
||||
#define ILI9341_CYAN 0x07FF ///< 0, 255, 255
|
||||
#define ILI9341_RED 0xF800 ///< 255, 0, 0
|
||||
#define ILI9341_MAGENTA 0xF81F ///< 255, 0, 255
|
||||
#define ILI9341_YELLOW 0xFFE0 ///< 255, 255, 0
|
||||
#define ILI9341_WHITE 0xFFFF ///< 255, 255, 255
|
||||
#define ILI9341_ORANGE 0xFD20 ///< 255, 165, 0
|
||||
#define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255, 41
|
||||
#define ILI9341_PINK 0xFC18 ///< 255, 130, 198
|
||||
|
||||
|
289
ubitx_keyer.ino
Normal file
289
ubitx_keyer.ino
Normal file
@ -0,0 +1,289 @@
|
||||
/**
|
||||
CW Keyer
|
||||
CW Key logic change with ron's code (ubitx_keyer.cpp)
|
||||
Ron's logic has been modified to work with the original uBITX by KD8CEC
|
||||
|
||||
Original Comment ----------------------------------------------------------------------------
|
||||
* The CW keyer handles either a straight key or an iambic / paddle key.
|
||||
* They all use just one analog input line. This is how it works.
|
||||
* The analog line has the internal pull-up resistor enabled.
|
||||
* When a straight key is connected, it shorts the pull-up resistor, analog input is 0 volts
|
||||
* When a paddle is connected, the dot and the dash are connected to the analog pin through
|
||||
* a 10K and a 2.2K resistors. These produce a 4v and a 2v input to the analog pins.
|
||||
* So, the readings are as follows :
|
||||
* 0v - straight key
|
||||
* 1-2.5 v - paddle dot
|
||||
* 2.5 to 4.5 v - paddle dash
|
||||
* 2.0 to 0.5 v - dot and dash pressed
|
||||
*
|
||||
* The keyer is written to transparently handle all these cases
|
||||
*
|
||||
* Generating CW
|
||||
* The CW is cleanly generated by unbalancing the front-end mixer
|
||||
* and putting the local oscillator directly at the CW transmit frequency.
|
||||
* The sidetone, generated by the Arduino is injected into the volume control
|
||||
*/
|
||||
|
||||
//CW ADC Range
|
||||
int cwAdcSTFrom = 0;
|
||||
int cwAdcSTTo = 50;
|
||||
int cwAdcBothFrom = 51;
|
||||
int cwAdcBothTo = 300;
|
||||
int cwAdcDotFrom = 301;
|
||||
int cwAdcDotTo = 600;
|
||||
int cwAdcDashFrom = 601;
|
||||
int cwAdcDashTo = 800;
|
||||
//byte cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
|
||||
|
||||
byte delayBeforeCWStartTime = 50;
|
||||
|
||||
|
||||
|
||||
|
||||
// in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
|
||||
//#define CW_TIMEOUT (600l) //Change to CW Delaytime for value save to eeprom
|
||||
#define PADDLE_DOT 1
|
||||
#define PADDLE_DASH 2
|
||||
#define PADDLE_BOTH 3
|
||||
#define PADDLE_STRAIGHT 4
|
||||
|
||||
//we store the last padde's character
|
||||
//to alternatively send dots and dashes
|
||||
//when both are simultaneously pressed
|
||||
char lastPaddle = 0;
|
||||
|
||||
/*
|
||||
//reads the analog keyer pin and reports the paddle
|
||||
byte getPaddle(){
|
||||
int paddle = analogRead(ANALOG_KEYER);
|
||||
//handle the ptt as the straight key
|
||||
|
||||
if (digitalRead(PTT) == 0)
|
||||
return PADDLE_STRAIGHT;
|
||||
|
||||
if (paddle > 800) // above 4v is up
|
||||
return 0;
|
||||
|
||||
if (!Iambic_Key)
|
||||
return PADDLE_STRAIGHT;
|
||||
|
||||
if (paddle > 600) // 4-3v is dot
|
||||
return PADDLE_DASH;
|
||||
else if (paddle > 300) //1-2v is dash
|
||||
return PADDLE_DOT;
|
||||
else if (paddle > 50)
|
||||
return PADDLE_BOTH; //both are between 1 and 2v
|
||||
else
|
||||
return PADDLE_STRAIGHT; //less than 1v is the straight key
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Starts transmitting the carrier with the sidetone
|
||||
* It assumes that we have called cwTxStart and not called cwTxStop
|
||||
* each time it is called, the cwTimeOut is pushed further into the future
|
||||
*/
|
||||
void cwKeydown(){
|
||||
|
||||
keyDown = 1; //tracks the CW_KEY
|
||||
tone(CW_TONE, (int)sideTone);
|
||||
digitalWrite(CW_KEY, 1);
|
||||
|
||||
//Modified by KD8CEC, for CW Delay Time save to eeprom
|
||||
//cwTimeout = millis() + CW_TIMEOUT;
|
||||
cwTimeout = millis() + cwDelayTime * 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the cw carrier transmission along with the sidetone
|
||||
* Pushes the cwTimeout further into the future
|
||||
*/
|
||||
void cwKeyUp(){
|
||||
keyDown = 0; //tracks the CW_KEY
|
||||
noTone(CW_TONE);
|
||||
digitalWrite(CW_KEY, 0);
|
||||
|
||||
//Modified by KD8CEC, for CW Delay Time save to eeprom
|
||||
//cwTimeout = millis() + CW_TIMEOUT;
|
||||
cwTimeout = millis() + cwDelayTime * 10;
|
||||
}
|
||||
|
||||
//Variables for Ron's new logic
|
||||
#define DIT_L 0x01 // DIT latch
|
||||
#define DAH_L 0x02 // DAH latch
|
||||
#define DIT_PROC 0x04 // DIT is being processed
|
||||
#define PDLSWAP 0x08 // 0 for normal, 1 for swap
|
||||
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
|
||||
enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
|
||||
static unsigned long ktimer;
|
||||
unsigned char keyerState = IDLE;
|
||||
|
||||
//Below is a test to reduce the keying error. do not delete lines
|
||||
//create by KD8CEC for compatible with new CW Logic
|
||||
char update_PaddleLatch(byte isUpdateKeyState) {
|
||||
unsigned char tmpKeyerControl = 0;
|
||||
|
||||
int paddle = analogRead(ANALOG_KEYER);
|
||||
//diagnostic, VU2ESE
|
||||
//itoa(paddle, b, 10);
|
||||
//printLine2(b);
|
||||
|
||||
//use the PTT as the key for tune up, quick QSOs
|
||||
if (digitalRead(PTT) == 0)
|
||||
tmpKeyerControl |= DIT_L;
|
||||
else if (paddle >= cwAdcDashFrom && paddle <= cwAdcDashTo)
|
||||
tmpKeyerControl |= DAH_L;
|
||||
else if (paddle >= cwAdcDotFrom && paddle <= cwAdcDotTo)
|
||||
tmpKeyerControl |= DIT_L;
|
||||
else if (paddle >= cwAdcBothFrom && paddle <= cwAdcBothTo)
|
||||
tmpKeyerControl |= (DAH_L | DIT_L) ;
|
||||
else
|
||||
{
|
||||
if (Iambic_Key)
|
||||
tmpKeyerControl = 0 ;
|
||||
else if (paddle >= cwAdcSTFrom && paddle <= cwAdcSTTo)
|
||||
tmpKeyerControl = DIT_L ;
|
||||
else
|
||||
tmpKeyerControl = 0 ;
|
||||
}
|
||||
|
||||
if (isUpdateKeyState == 1)
|
||||
keyerControl |= tmpKeyerControl;
|
||||
|
||||
return tmpKeyerControl;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
// New logic, by RON
|
||||
// modified by KD8CEC
|
||||
******************************************************************************/
|
||||
void cwKeyer(void){
|
||||
lastPaddle = 0;
|
||||
bool continue_loop = true;
|
||||
unsigned tmpKeyControl = 0;
|
||||
|
||||
if( Iambic_Key ) {
|
||||
while(continue_loop) {
|
||||
switch (keyerState) {
|
||||
case IDLE:
|
||||
tmpKeyControl = update_PaddleLatch(0);
|
||||
if ( tmpKeyControl == DAH_L || tmpKeyControl == DIT_L ||
|
||||
tmpKeyControl == (DAH_L | DIT_L) || (keyerControl & 0x03)) {
|
||||
update_PaddleLatch(1);
|
||||
keyerState = CHK_DIT;
|
||||
}else{
|
||||
if (0 < cwTimeout && cwTimeout < millis()){
|
||||
cwTimeout = 0;
|
||||
stopTx();
|
||||
}
|
||||
continue_loop = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHK_DIT:
|
||||
if (keyerControl & DIT_L) {
|
||||
keyerControl |= DIT_PROC;
|
||||
ktimer = cwSpeed;
|
||||
keyerState = KEYED_PREP;
|
||||
}else{
|
||||
keyerState = CHK_DAH;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHK_DAH:
|
||||
if (keyerControl & DAH_L) {
|
||||
ktimer = cwSpeed*3;
|
||||
keyerState = KEYED_PREP;
|
||||
}else{
|
||||
keyerState = IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEYED_PREP:
|
||||
//modified KD8CEC
|
||||
if (!inTx){
|
||||
//DelayTime Option
|
||||
active_delay(delayBeforeCWStartTime * 2);
|
||||
|
||||
keyDown = 0;
|
||||
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
|
||||
startTx(TX_CW);
|
||||
}
|
||||
ktimer += millis(); // set ktimer to interval end time
|
||||
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||
keyerState = KEYED; // next state
|
||||
|
||||
cwKeydown();
|
||||
break;
|
||||
|
||||
case KEYED:
|
||||
if (millis() > ktimer) { // are we at end of key down ?
|
||||
cwKeyUp();
|
||||
ktimer = millis() + cwSpeed; // inter-element time
|
||||
keyerState = INTER_ELEMENT; // next state
|
||||
}else if (keyerControl & IAMBICB) {
|
||||
update_PaddleLatch(1); // early paddle latch in Iambic B mode
|
||||
}
|
||||
break;
|
||||
|
||||
case INTER_ELEMENT:
|
||||
// Insert time between dits/dahs
|
||||
update_PaddleLatch(1); // latch paddle state
|
||||
if (millis() > ktimer) { // are we at end of inter-space ?
|
||||
if (keyerControl & DIT_PROC) { // was it a dit or dah ?
|
||||
keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
|
||||
keyerState = CHK_DAH; // dit done, check for dah
|
||||
}else{
|
||||
keyerControl &= ~(DAH_L); // clear dah latch
|
||||
keyerState = IDLE; // go idle
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
checkCAT();
|
||||
} //end of while
|
||||
}
|
||||
else{
|
||||
while(1){
|
||||
char state = update_PaddleLatch(0);
|
||||
// Serial.println((int)state);
|
||||
if (state == DIT_L) {
|
||||
// if we are here, it is only because the key is pressed
|
||||
if (!inTx){
|
||||
startTx(TX_CW);
|
||||
|
||||
//DelayTime Option
|
||||
active_delay(delayBeforeCWStartTime * 2);
|
||||
|
||||
keyDown = 0;
|
||||
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
|
||||
}
|
||||
cwKeydown();
|
||||
|
||||
while ( update_PaddleLatch(0) == DIT_L )
|
||||
active_delay(1);
|
||||
|
||||
cwKeyUp();
|
||||
}
|
||||
else{
|
||||
if (0 < cwTimeout && cwTimeout < millis()){
|
||||
cwTimeout = 0;
|
||||
keyDown = 0;
|
||||
stopTx();
|
||||
}
|
||||
//if (!cwTimeout) //removed by KD8CEC
|
||||
// return;
|
||||
// got back to the beginning of the loop, if no further activity happens on straight key
|
||||
// we will time out, and return out of this routine
|
||||
//delay(5);
|
||||
//delay_background(5, 3); //removed by KD8CEC
|
||||
//continue; //removed by KD8CEC
|
||||
return; //Tx stop control by Main Loop
|
||||
}
|
||||
|
||||
checkCAT();
|
||||
} //end of while
|
||||
} //end of elese
|
||||
}
|
||||
|
||||
|
402
ubitx_setup.ino
Normal file
402
ubitx_setup.ino
Normal file
@ -0,0 +1,402 @@
|
||||
/** Menus
|
||||
* The Radio menus are accessed by tapping on the function button.
|
||||
* - The main loop() constantly looks for a button press and calls doMenu() when it detects
|
||||
* a function button press.
|
||||
* - As the encoder is rotated, at every 10th pulse, the next or the previous menu
|
||||
* item is displayed. Each menu item is controlled by it's own function.
|
||||
* - Eache menu function may be called to display itself
|
||||
* - Each of these menu routines is called with a button parameter.
|
||||
* - The btn flag denotes if the menu itme was clicked on or not.
|
||||
* - If the menu item is clicked on, then it is selected,
|
||||
* - If the menu item is NOT clicked on, then the menu's prompt is to be displayed
|
||||
*/
|
||||
|
||||
void drawCommandbar(char *text){
|
||||
utftFillrect(30,45,280, 32, ILI9341_NAVY);
|
||||
displayRawText(text, 30, 45, ILI9341_WHITE, ILI9341_NAVY);
|
||||
}
|
||||
|
||||
/** A generic control to read variable values
|
||||
*/
|
||||
int getValueByKnob(int minimum, int maximum, int step_size, int initial, char* prefix, char *postfix)
|
||||
{
|
||||
int knob = 0;
|
||||
int knob_value;
|
||||
|
||||
while (btnDown())
|
||||
active_delay(100);
|
||||
|
||||
active_delay(200);
|
||||
knob_value = initial;
|
||||
|
||||
strcpy(b, prefix);
|
||||
itoa(knob_value, c, 10);
|
||||
strcat(b, c);
|
||||
strcat(b, postfix);
|
||||
drawCommandbar(b);
|
||||
//printLine2(b);
|
||||
//active_delay(300);
|
||||
|
||||
while(!btnDown() && digitalRead(PTT) == HIGH){
|
||||
|
||||
knob = enc_read();
|
||||
if (knob != 0){
|
||||
if (knob_value > minimum && knob < 0)
|
||||
knob_value -= step_size;
|
||||
if (knob_value < maximum && knob > 0)
|
||||
knob_value += step_size;
|
||||
|
||||
//printLine2(prefix);
|
||||
strcpy(b, prefix);
|
||||
itoa(knob_value, c, 10);
|
||||
strcat(b, c);
|
||||
strcat(b, postfix);
|
||||
drawCommandbar(b);
|
||||
// utftFillrect(30,41,280, 32, ILI9341_NAVY);
|
||||
// displayRawText(b, 30, 41, ILI9341_WHITE, ILI9341_NAVY);
|
||||
//printLine1(b);
|
||||
}
|
||||
checkCAT();
|
||||
}
|
||||
utftFillrect(30,41,280, 32, ILI9341_NAVY);
|
||||
return knob_value;
|
||||
}
|
||||
|
||||
// The generic routine to display one line on the LCD
|
||||
void printLine(int linenmbr, char *c) {
|
||||
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
|
||||
utftFillrect(50, 100 + (50 * linenmbr), 200, 40, ILI9341_BLACK);
|
||||
displayRawText(c, 50, 100 + (50 * linenmbr), ILI9341_WHITE, ILI9341_BLACK);
|
||||
strcpy(printBuff[linenmbr], c);
|
||||
}
|
||||
}
|
||||
|
||||
// short cut to print to the first line
|
||||
void printLine1(char *c){
|
||||
printLine(1,c);
|
||||
//displayText(c, 0,180,320, 25, ILI9341_YELLOW, ILI9341_BLACK, ILI9341_BLUE);
|
||||
}
|
||||
|
||||
// short cut to print to the first line
|
||||
void printLine2(char *c){
|
||||
printLine(0,c);
|
||||
|
||||
//displayText(c, 0,210,320, 25, ILI9341_YELLOW, ILI9341_BLACK, ILI9341_BLUE);
|
||||
}
|
||||
|
||||
void printFLine1(String s){
|
||||
printLine1(s.c_str());
|
||||
}
|
||||
|
||||
void printFLine2(String s){
|
||||
printLine2(s.c_str());
|
||||
}
|
||||
|
||||
void setupExit(){
|
||||
menuOn = 0;
|
||||
guiUpdate();
|
||||
}
|
||||
|
||||
void printCarrierFreq(unsigned long freq){
|
||||
|
||||
memset(c, 0, sizeof(c));
|
||||
memset(b, 0, sizeof(b));
|
||||
|
||||
ultoa(freq, b, DEC);
|
||||
|
||||
strncat(c, b, 2);
|
||||
strcat(c, ".");
|
||||
strncat(c, &b[2], 3);
|
||||
strcat(c, ".");
|
||||
strncat(c, &b[5], 1);
|
||||
displayText(c, 110, 100, 100, 30, ILI9341_CYAN, ILI9341_NAVY, ILI9341_NAVY);
|
||||
}
|
||||
|
||||
void displayDialog(char *title, char *instructions){
|
||||
displayClear(ILI9341_BLACK);
|
||||
utftRect(10,10,300,220, ILI9341_WHITE);
|
||||
utftHline(20,45,280,ILI9341_WHITE);
|
||||
utftRect(12,12,296,216, ILI9341_WHITE);
|
||||
displayRawText(title, 20, 20, ILI9341_CYAN, ILI9341_NAVY);
|
||||
displayRawText(instructions, 20, 200, ILI9341_CYAN, ILI9341_NAVY);
|
||||
}
|
||||
|
||||
//this is used by the si5351 routines in the ubitx_5351 file
|
||||
extern int32_t calibration;
|
||||
extern uint32_t si5351bx_vcoa;
|
||||
|
||||
int setupFreq(){
|
||||
int knob = 0;
|
||||
int32_t prev_calibration;
|
||||
|
||||
displayDialog("Set Frequency", "Push TUNE to Save");
|
||||
|
||||
//round off the the nearest khz
|
||||
frequency = (frequency/1000l)* 1000l;
|
||||
setFrequency(frequency);
|
||||
|
||||
displayRawText("You should have a", 20, 50, ILI9341_CYAN, ILI9341_NAVY);
|
||||
displayRawText("signal exactly at ", 20, 75, ILI9341_CYAN, ILI9341_NAVY);
|
||||
ltoa(c, frequency/1000l, 10);
|
||||
|
||||
displayRawText(c, 20, 100, ILI9341_CYAN, ILI9341_NAVY);
|
||||
displayRawText("Rotate to zerobeat", 20, 180, ILI9341_CYAN, ILI9341_NAVY);
|
||||
//keep clear of any previous button press
|
||||
while (btnDown())
|
||||
active_delay(100);
|
||||
active_delay(100);
|
||||
|
||||
prev_calibration = calibration;
|
||||
calibration = 0;
|
||||
|
||||
// ltoa(calibration/8750, c, 10);
|
||||
// strcpy(b, c);
|
||||
// strcat(b, "Hz");
|
||||
// printLine2(b);
|
||||
|
||||
while (!btnDown())
|
||||
{
|
||||
knob = enc_read();
|
||||
if (knob != 0)
|
||||
calibration += knob * 875;
|
||||
/* else if (knob < 0)
|
||||
calibration -= 875; */
|
||||
else
|
||||
continue; //don't update the frequency or the display
|
||||
|
||||
si5351bx_setfreq(0, usbCarrier); //set back the cardrier oscillator anyway, cw tx switches it off
|
||||
si5351_set_calibration(calibration);
|
||||
setFrequency(frequency);
|
||||
|
||||
//displayRawText("Rotate to zerobeat", 20, 120, ILI9341_CYAN, ILI9341_NAVY);
|
||||
|
||||
ltoa(calibration, b, 10);
|
||||
displayText(b, 100, 140, 100, 26, ILI9341_CYAN, ILI9341_NAVY, ILI9341_WHITE);
|
||||
}
|
||||
|
||||
EEPROM.put(MASTER_CAL, calibration);
|
||||
initOscillators();
|
||||
si5351_set_calibration(calibration);
|
||||
setFrequency(frequency);
|
||||
|
||||
//debounce and delay
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(100);
|
||||
}
|
||||
|
||||
void setupBFO(){
|
||||
int knob = 0;
|
||||
unsigned long prevCarrier;
|
||||
|
||||
prevCarrier = usbCarrier;
|
||||
|
||||
displayDialog("Set BFO", "Press TUNE to Save");
|
||||
|
||||
usbCarrier = 11053000l;
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
printCarrierFreq(usbCarrier);
|
||||
|
||||
while (!btnDown()){
|
||||
knob = enc_read();
|
||||
|
||||
if (knob != 0)
|
||||
usbCarrier -= 50 * knob;
|
||||
else
|
||||
continue; //don't update the frequency or the display
|
||||
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
setFrequency(frequency);
|
||||
printCarrierFreq(usbCarrier);
|
||||
|
||||
active_delay(100);
|
||||
}
|
||||
|
||||
EEPROM.put(USB_CAL, usbCarrier);
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
setFrequency(frequency);
|
||||
updateDisplay();
|
||||
printLine2("");
|
||||
menuOn = 0;
|
||||
}
|
||||
|
||||
void setupCwDelay(){
|
||||
int knob = 0;
|
||||
int prev_cw_delay;
|
||||
|
||||
displayDialog("Set CW T/R Delay", "Press tune to Save");
|
||||
|
||||
active_delay(500);
|
||||
prev_cw_delay = cwDelayTime;
|
||||
|
||||
itoa(10 * (int)cwDelayTime, b, 10);
|
||||
strcat(b, " msec");
|
||||
displayText(b, 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
|
||||
while (!btnDown()){
|
||||
knob = enc_read();
|
||||
|
||||
if (knob < 0 && cwDelayTime > 10)
|
||||
cwDelayTime -= 10;
|
||||
else if (knob > 0 && cwDelayTime < 100)
|
||||
cwDelayTime += 10;
|
||||
else
|
||||
continue; //don't update the frequency or the display
|
||||
|
||||
itoa(10 * (int)cwDelayTime, b, 10);
|
||||
strcat(b, " msec");
|
||||
displayText(b, 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
|
||||
}
|
||||
|
||||
EEPROM.put(CW_DELAYTIME, cwDelayTime);
|
||||
|
||||
|
||||
// cwDelayTime = getValueByKnob(10, 1000, 50, cwDelayTime, "CW Delay>", " msec");
|
||||
|
||||
active_delay(500);
|
||||
menuOn = 0;
|
||||
}
|
||||
|
||||
void setupKeyer(){
|
||||
int tmp_key, knob;
|
||||
|
||||
displayDialog("Set CW Keyer", "Press tune to Save");
|
||||
|
||||
if (!Iambic_Key)
|
||||
displayText("< Hand Key >", 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
else if (keyerControl & IAMBICB)
|
||||
displayText("< Iambic A >", 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
else
|
||||
displayText("< Iambic B >", 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
|
||||
if (!Iambic_Key)
|
||||
tmp_key = 0; //hand key
|
||||
else if (keyerControl & IAMBICB)
|
||||
tmp_key = 2; //Iambic B
|
||||
else
|
||||
tmp_key = 1;
|
||||
|
||||
while (!btnDown())
|
||||
{
|
||||
knob = enc_read();
|
||||
if (knob == 0){
|
||||
active_delay(50);
|
||||
continue;
|
||||
}
|
||||
if (knob < 0 && tmp_key > 0)
|
||||
tmp_key--;
|
||||
if (knob > 0)
|
||||
tmp_key++;
|
||||
if (tmp_key > 2)
|
||||
tmp_key = 0;
|
||||
|
||||
if (tmp_key == 0)
|
||||
displayText("< Hand Key >", 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
else if (tmp_key == 1)
|
||||
displayText("< Iambic A >", 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
else if (tmp_key == 2)
|
||||
displayText("< Iambic B >", 100, 100, 120, 26, ILI9341_CYAN, ILI9341_BLACK, ILI9341_BLACK);
|
||||
}
|
||||
|
||||
active_delay(500);
|
||||
if (tmp_key == 0)
|
||||
Iambic_Key = false;
|
||||
else if (tmp_key == 1){
|
||||
Iambic_Key = true;
|
||||
keyerControl &= ~IAMBICB;
|
||||
}
|
||||
else if (tmp_key == 2){
|
||||
Iambic_Key = true;
|
||||
keyerControl |= IAMBICB;
|
||||
}
|
||||
|
||||
EEPROM.put(CW_KEY_TYPE, tmp_key);
|
||||
|
||||
menuOn = 0;
|
||||
}
|
||||
|
||||
void drawSetupMenu(){
|
||||
displayClear(ILI9341_BLACK);
|
||||
|
||||
displayText("Setup", 10, 10, 300, 35, ILI9341_WHITE, ILI9341_NAVY, ILI9341_WHITE);
|
||||
utftRect(10,10,300,220, ILI9341_WHITE);
|
||||
|
||||
displayRawText("Set Freq...", 30, 50, ILI9341_WHITE, ILI9341_NAVY);
|
||||
displayRawText("Set BFO...", 30, 80, ILI9341_WHITE, ILI9341_NAVY);
|
||||
displayRawText("CW Delay...", 30, 110, ILI9341_WHITE, ILI9341_NAVY);
|
||||
displayRawText("CW Keyer...", 30, 140, ILI9341_WHITE, ILI9341_NAVY);
|
||||
displayRawText("Touch Screen...", 30, 170, ILI9341_WHITE, ILI9341_NAVY);
|
||||
displayRawText("Exit", 30, 200, ILI9341_WHITE, ILI9341_NAVY);
|
||||
}
|
||||
|
||||
static int prevPuck = -1;
|
||||
void movePuck(int i){
|
||||
if (prevPuck >= 0)
|
||||
utftRect(15, 49 + (prevPuck * 30), 290, 25, ILI9341_NAVY);
|
||||
utftRect(15, 49 + (i * 30), 290, 25, ILI9341_WHITE);
|
||||
prevPuck = i;
|
||||
|
||||
}
|
||||
|
||||
void doSetup2(){
|
||||
int select=0, i,btnState;
|
||||
|
||||
drawSetupMenu();
|
||||
movePuck(select);
|
||||
|
||||
//wait for the button to be raised up
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(50); //debounce
|
||||
|
||||
menuOn = 2;
|
||||
|
||||
while (menuOn){
|
||||
i = enc_read();
|
||||
|
||||
if (i > 0){
|
||||
if (select + i < 60)
|
||||
select += i;
|
||||
movePuck(select/10);
|
||||
}
|
||||
if (i < 0 && select - i >= 0){
|
||||
select += i; //caught ya, i is already -ve here, so you add it
|
||||
movePuck(select/10);
|
||||
}
|
||||
|
||||
if (!btnDown()){
|
||||
active_delay(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
//wait for the touch to lift off and debounce
|
||||
while(btnDown()){
|
||||
active_delay(50);
|
||||
}
|
||||
active_delay(300);
|
||||
|
||||
if (select < 10)
|
||||
setupFreq();
|
||||
else if (select < 20 )
|
||||
setupBFO();
|
||||
else if (select < 30 )
|
||||
setupCwDelay();
|
||||
else if (select < 40)
|
||||
setupKeyer();
|
||||
else if (select < 50)
|
||||
setupTouch();
|
||||
else
|
||||
setupExit();
|
||||
//redraw
|
||||
drawSetupMenu();
|
||||
}
|
||||
|
||||
//debounce the button
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(50);
|
||||
|
||||
checkCAT();
|
||||
guiUpdate();
|
||||
}
|
125
ubitx_si5351.ino
Normal file
125
ubitx_si5351.ino
Normal file
@ -0,0 +1,125 @@
|
||||
// ************* SI5315 routines - tks Jerry Gaffke, KE7ER ***********************
|
||||
|
||||
// An minimalist standalone set of Si5351 routines.
|
||||
// VCOA is fixed at 875mhz, VCOB not used.
|
||||
// The output msynth dividers are used to generate 3 independent clocks
|
||||
// with 1hz resolution to any frequency between 4khz and 109mhz.
|
||||
|
||||
// Usage:
|
||||
// Call si5351bx_init() once at startup with no args;
|
||||
// Call si5351bx_setfreq(clknum, freq) each time one of the
|
||||
// three output CLK pins is to be updated to a new frequency.
|
||||
// A freq of 0 serves to shut down that output clock.
|
||||
|
||||
// The global variable si5351bx_vcoa starts out equal to the nominal VCOA
|
||||
// frequency of 25mhz*35 = 875000000 Hz. To correct for 25mhz crystal errors,
|
||||
// the user can adjust this value. The vco frequency will not change but
|
||||
// the number used for the (a+b/c) output msynth calculations is affected.
|
||||
// Example: We call for a 5mhz signal, but it measures to be 5.001mhz.
|
||||
// So the actual vcoa frequency is 875mhz*5.001/5.000 = 875175000 Hz,
|
||||
// To correct for this error: si5351bx_vcoa=875175000;
|
||||
|
||||
// Most users will never need to generate clocks below 500khz.
|
||||
// But it is possible to do so by loading a value between 0 and 7 into
|
||||
// the global variable si5351bx_rdiv, be sure to return it to a value of 0
|
||||
// before setting some other CLK output pin. The affected clock will be
|
||||
// divided down by a power of two defined by 2**si5351_rdiv
|
||||
// A value of zero gives a divide factor of 1, a value of 7 divides by 128.
|
||||
// This lightweight method is a reasonable compromise for a seldom used feature.
|
||||
|
||||
|
||||
#define BB0(x) ((uint8_t)x) // Bust int32 into Bytes
|
||||
#define BB1(x) ((uint8_t)(x>>8))
|
||||
#define BB2(x) ((uint8_t)(x>>16))
|
||||
|
||||
#define SI5351BX_ADDR 0x60 // I2C address of Si5351 (typical)
|
||||
#define SI5351BX_XTALPF 2 // 1:6pf 2:8pf 3:10pf
|
||||
|
||||
// If using 27mhz crystal, set XTAL=27000000, MSA=33. Then vco=891mhz
|
||||
#define SI5351BX_XTAL 25000000 // Crystal freq in Hz
|
||||
#define SI5351BX_MSA 35 // VCOA is at 25mhz*35 = 875mhz
|
||||
|
||||
// User program may have reason to poke new values into these 3 RAM variables
|
||||
uint32_t si5351bx_vcoa = (SI5351BX_XTAL*SI5351BX_MSA); // 25mhzXtal calibrate
|
||||
uint8_t si5351bx_rdiv = 0; // 0-7, CLK pin sees fout/(2**rdiv)
|
||||
uint8_t si5351bx_drive[3] = {3, 3, 3}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
|
||||
uint8_t si5351bx_clken = 0xFF; // Private, all CLK output drivers off
|
||||
int32_t calibration = 0;
|
||||
|
||||
void i2cWrite(uint8_t reg, uint8_t val) { // write reg via i2c
|
||||
Wire.beginTransmission(SI5351BX_ADDR);
|
||||
Wire.write(reg);
|
||||
Wire.write(val);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void i2cWriten(uint8_t reg, uint8_t *vals, uint8_t vcnt) { // write array
|
||||
Wire.beginTransmission(SI5351BX_ADDR);
|
||||
Wire.write(reg);
|
||||
while (vcnt--) Wire.write(*vals++);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
|
||||
void si5351bx_init() { // Call once at power-up, start PLLA
|
||||
uint8_t reg; uint32_t msxp1;
|
||||
Wire.begin();
|
||||
i2cWrite(149, 0); // SpreadSpectrum off
|
||||
i2cWrite(3, si5351bx_clken); // Disable all CLK output drivers
|
||||
i2cWrite(183, SI5351BX_XTALPF << 6); // Set 25mhz crystal load capacitance
|
||||
msxp1 = 128 * SI5351BX_MSA - 512; // and msxp2=0, msxp3=1, not fractional
|
||||
uint8_t vals[8] = {0, 1, BB2(msxp1), BB1(msxp1), BB0(msxp1), 0, 0, 0};
|
||||
i2cWriten(26, vals, 8); // Write to 8 PLLA msynth regs
|
||||
i2cWrite(177, 0x20); // Reset PLLA (0x80 resets PLLB)
|
||||
// for (reg=16; reg<=23; reg++) i2cWrite(reg, 0x80); // Powerdown CLK's
|
||||
// i2cWrite(187, 0); // No fannout of clkin, xtal, ms0, ms4
|
||||
|
||||
//initializing the ppl2 as well
|
||||
i2cWriten(34, vals, 8); // Write to 8 PLLA msynth regs
|
||||
i2cWrite(177, 0xa0); // Reset PLLA & PPLB (0x80 resets PLLB)
|
||||
|
||||
}
|
||||
|
||||
void si5351bx_setfreq(uint8_t clknum, uint32_t fout) { // Set a CLK to fout Hz
|
||||
uint32_t msa, msb, msc, msxp1, msxp2, msxp3p2top;
|
||||
if ((fout < 500000) || (fout > 109000000)) // If clock freq out of range
|
||||
si5351bx_clken |= 1 << clknum; // shut down the clock
|
||||
else {
|
||||
msa = si5351bx_vcoa / fout; // Integer part of vco/fout
|
||||
msb = si5351bx_vcoa % fout; // Fractional part of vco/fout
|
||||
msc = fout; // Divide by 2 till fits in reg
|
||||
while (msc & 0xfff00000) {
|
||||
msb = msb >> 1;
|
||||
msc = msc >> 1;
|
||||
}
|
||||
msxp1 = (128 * msa + 128 * msb / msc - 512) | (((uint32_t)si5351bx_rdiv) << 20);
|
||||
msxp2 = 128 * msb - 128 * msb / msc * msc; // msxp3 == msc;
|
||||
msxp3p2top = (((msc & 0x0F0000) << 4) | msxp2); // 2 top nibbles
|
||||
uint8_t vals[8] = { BB1(msc), BB0(msc), BB2(msxp1), BB1(msxp1),
|
||||
BB0(msxp1), BB2(msxp3p2top), BB1(msxp2), BB0(msxp2)
|
||||
};
|
||||
i2cWriten(42 + (clknum * 8), vals, 8); // Write to 8 msynth regs
|
||||
// if (clknum == 1) //PLLB | MS src | drive current
|
||||
// i2cWrite(16 + clknum, 0x20 | 0x0C | si5351bx_drive[clknum]); // use local msynth
|
||||
// else
|
||||
i2cWrite(16 + clknum, 0x0C | si5351bx_drive[clknum]); // use local msynth
|
||||
|
||||
si5351bx_clken &= ~(1 << clknum); // Clear bit to enable clock
|
||||
}
|
||||
i2cWrite(3, si5351bx_clken); // Enable/disable clock
|
||||
}
|
||||
|
||||
void si5351_set_calibration(int32_t cal){
|
||||
si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + cal; // apply the calibration correction factor
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
}
|
||||
|
||||
void initOscillators(){
|
||||
//initialize the SI5351
|
||||
si5351bx_init();
|
||||
si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + calibration; // apply the calibration correction factor
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
}
|
||||
|
||||
|
||||
|
835
ubitx_ui.ino
Normal file
835
ubitx_ui.ino
Normal file
@ -0,0 +1,835 @@
|
||||
/**
|
||||
* The user interface of the ubitx consists of the encoder, the push-button on top of it
|
||||
* and the 16x2 LCD display.
|
||||
* The upper line of the display is constantly used to display frequency and status
|
||||
* of the radio. Occasionally, it is used to provide a two-line information that is
|
||||
* quickly cleared up.
|
||||
*/
|
||||
|
||||
#define BUTTON_SELECTED 1
|
||||
|
||||
struct Button {
|
||||
int x, y, w, h;
|
||||
char *text;
|
||||
char *morse;
|
||||
};
|
||||
|
||||
#define MAX_BUTTONS 17
|
||||
const struct Button btn_set[MAX_BUTTONS] PROGMEM = {
|
||||
//const struct Button btn_set [] = {
|
||||
{0, 10, 159, 36, "VFOA", "A"},
|
||||
{160, 10, 159, 36, "VFOB", "B"},
|
||||
|
||||
{0, 80, 60, 36, "RIT", "R"},
|
||||
{64, 80, 60, 36, "USB", "U"},
|
||||
{128, 80, 60, 36, "LSB", "L"},
|
||||
{192, 80, 60, 36, "CW", "M"},
|
||||
{256, 80, 60, 36, "SPL", "S"},
|
||||
|
||||
{0, 120, 60, 36, "80", "8"},
|
||||
{64, 120, 60, 36, "40", "4"},
|
||||
{128, 120, 60, 36, "30", "3"},
|
||||
{192, 120, 60, 36, "20", "2"},
|
||||
{256, 120, 60, 36, "17", "7"},
|
||||
|
||||
{0, 160, 60, 36, "15", "5"},
|
||||
{64, 160, 60, 36, "10", "1"},
|
||||
{128, 160, 60, 36, "WPM", "W"},
|
||||
{192, 160, 60, 36, "TON", "T"},
|
||||
{256, 160, 60, 36, "FRQ", "F"},
|
||||
};
|
||||
|
||||
#define MAX_KEYS 17
|
||||
const struct Button keypad[MAX_KEYS] PROGMEM = {
|
||||
{0, 80, 60, 36, "1", "1"},
|
||||
{64, 80, 60, 36, "2", "2"},
|
||||
{128, 80, 60, 36, "3", "3"},
|
||||
{192, 80, 60, 36, "", ""},
|
||||
{256, 80, 60, 36, "OK", "K"},
|
||||
|
||||
{0, 120, 60, 36, "4", "4"},
|
||||
{64, 120, 60, 36, "5", "5"},
|
||||
{128, 120, 60, 36, "6", "6"},
|
||||
{192, 120, 60, 36, "0", "0"},
|
||||
{256, 120, 60, 36, "<-", "B"},
|
||||
|
||||
{0, 160, 60, 36, "7", "7"},
|
||||
{64, 160, 60, 36, "8", "8"},
|
||||
{128, 160, 60, 36, "9", "9"},
|
||||
{192, 160, 60, 36, "", ""},
|
||||
{256, 160, 60, 36, "Can", "C"},
|
||||
};
|
||||
|
||||
boolean getButton(char *text, struct Button *b){
|
||||
for (int i = 0; i < MAX_BUTTONS; i++){
|
||||
memcpy_P(b, btn_set + i, sizeof(struct Button));
|
||||
if (!strcmp(text, b->text)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char vfoDisplay[12];
|
||||
void displayVFO(int vfo){
|
||||
int x, y;
|
||||
int displayColor, displayBorder;
|
||||
Button b;
|
||||
|
||||
if (vfo == VFO_A){
|
||||
getButton("VFOA", &b);
|
||||
if (splitOn){
|
||||
if (vfoActive == VFO_A)
|
||||
strcpy(c, "R:");
|
||||
else
|
||||
strcpy(c, "T:");
|
||||
}
|
||||
else
|
||||
strcpy(c, "A:");
|
||||
if (vfoActive == VFO_A){
|
||||
formatFreq(frequency, c+2);
|
||||
displayColor = ILI9341_WHITE;
|
||||
displayBorder = ILI9341_BLACK;
|
||||
}else{
|
||||
formatFreq(vfoA, c+2);
|
||||
displayColor = ILI9341_GREEN;
|
||||
displayBorder = ILI9341_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
if (vfo == VFO_B){
|
||||
getButton("VFOB", &b);
|
||||
|
||||
if (splitOn){
|
||||
if (vfoActive == VFO_B)
|
||||
strcpy(c, "R:");
|
||||
else
|
||||
strcpy(c, "T:");
|
||||
}
|
||||
else
|
||||
strcpy(c, "B:");
|
||||
if (vfoActive == VFO_B){
|
||||
formatFreq(frequency, c+2);
|
||||
displayColor = ILI9341_WHITE;
|
||||
displayBorder = ILI9341_WHITE;
|
||||
} else {
|
||||
displayColor = ILI9341_GREEN;
|
||||
displayBorder = ILI9341_BLACK;
|
||||
formatFreq(vfoB, c+2);
|
||||
}
|
||||
}
|
||||
|
||||
if (vfoDisplay[0] == 0){
|
||||
utftFillrect(b.x, b.y, b.w, b.h, ILI9341_BLACK);
|
||||
if (vfoActive == vfo)
|
||||
utftRect(b.x, b.y, b.w , b.h, ILI9341_WHITE);
|
||||
else
|
||||
utftRect(b.x, b.y, b.w , b.h, ILI9341_NAVY);
|
||||
}
|
||||
x = b.x + 6;
|
||||
y = b.y + 3;
|
||||
|
||||
char *text = c;
|
||||
|
||||
for (int i = 0; i <= strlen(c); i++){
|
||||
char digit = c[i];
|
||||
if (digit != vfoDisplay[i]){
|
||||
|
||||
utftFillrect(x, y, 15, b.h-6, ILI9341_BLACK);
|
||||
//checkCAT();
|
||||
|
||||
displayChar(x, y + TEXT_LINE_HEIGHT + 3, digit, displayColor, ILI9341_BLACK);
|
||||
checkCAT();
|
||||
}
|
||||
if (digit == ':' || digit == '.')
|
||||
x += 7;
|
||||
else
|
||||
x += 16;
|
||||
text++;
|
||||
}//end of the while loop of the characters to be printed
|
||||
|
||||
strcpy(vfoDisplay, c);
|
||||
}
|
||||
|
||||
void btnDraw(struct Button *b){
|
||||
if (!strcmp(b->text, "VFOA")){
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_A);
|
||||
}
|
||||
else if(!strcmp(b->text, "VFOB")){
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_B);
|
||||
}
|
||||
else if ((!strcmp(b->text, "RIT") && ritOn == 1) ||
|
||||
(!strcmp(b->text, "USB") && isUSB == 1) ||
|
||||
(!strcmp(b->text, "LSB") && isUSB == 0) ||
|
||||
(!strcmp(b->text, "SPL") && splitOn == 1))
|
||||
displayText(b->text, b->x, b->y, b->w, b->h, ILI9341_BLACK, ILI9341_ORANGE, ILI9341_DARKGREY);
|
||||
else if (!strcmp(b->text, "CW") && cwMode == 1)
|
||||
displayText(b->text, b->x, b->y, b->w, b->h, ILI9341_BLACK, ILI9341_ORANGE, ILI9341_DARKGREY);
|
||||
else
|
||||
displayText(b->text, b->x, b->y, b->w, b->h, ILI9341_GREEN, ILI9341_BLACK, ILI9341_DARKGREY);
|
||||
}
|
||||
|
||||
|
||||
void displayRIT(){
|
||||
utftFillrect(0,41,320,30, ILI9341_NAVY);
|
||||
if (ritOn){
|
||||
strcpy(c, "TX:");
|
||||
formatFreq(ritTxFrequency, c+3);
|
||||
if (vfoActive == VFO_A)
|
||||
displayText(c, 0, 45,159, 30, ILI9341_WHITE, ILI9341_NAVY, ILI9341_NAVY);
|
||||
else
|
||||
displayText(c, 160, 45,159, 30, ILI9341_WHITE, ILI9341_NAVY, ILI9341_NAVY);
|
||||
}
|
||||
else {
|
||||
if (vfoActive == VFO_A)
|
||||
displayText("", 0, 45,159, 30, ILI9341_WHITE, ILI9341_NAVY, ILI9341_NAVY);
|
||||
else
|
||||
displayText("", 160, 45,159, 30, ILI9341_WHITE, ILI9341_NAVY, ILI9341_NAVY);
|
||||
}
|
||||
}
|
||||
|
||||
void fastTune(){
|
||||
int encoder;
|
||||
|
||||
//if the btn is down, wait until it is up
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(300);
|
||||
|
||||
displayRawText("Fast tune", 100, 55, ILI9341_CYAN, ILI9341_NAVY);
|
||||
while(1){
|
||||
checkCAT();
|
||||
|
||||
//exit after debouncing the btnDown
|
||||
if (btnDown()){
|
||||
utftFillrect(100, 55, 120, 30, ILI9341_NAVY);
|
||||
|
||||
//wait until the button is realsed and then return
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(300);
|
||||
return;
|
||||
}
|
||||
|
||||
encoder = enc_read();
|
||||
if (encoder != 0){
|
||||
|
||||
if (encoder > 0 && frequency < 30000000l)
|
||||
frequency += 50000l;
|
||||
else if (encoder < 0 && frequency > 600000l)
|
||||
frequency -= 50000l;
|
||||
setFrequency(frequency);
|
||||
displayVFO(vfoActive);
|
||||
}
|
||||
}// end of the event loop
|
||||
}
|
||||
|
||||
void enterFreq(){
|
||||
//force the display to refresh everything
|
||||
//display all the buttons
|
||||
int f;
|
||||
|
||||
for (int i = 0; i < MAX_KEYS; i++){
|
||||
struct Button b;
|
||||
memcpy_P(&b, keypad + i, sizeof(struct Button));
|
||||
btnDraw(&b);
|
||||
}
|
||||
|
||||
int cursor_pos = 0;
|
||||
int encoder;
|
||||
memset(c, 0, sizeof(c));
|
||||
f = frequency / 1000l;
|
||||
while(1){
|
||||
checkCAT();
|
||||
/*
|
||||
encoder = enc_read();
|
||||
if (encoder != 0){
|
||||
if (c[0] = 0){
|
||||
itoa(c, f, 10);
|
||||
Serial.print("f");
|
||||
Serial.println(f);
|
||||
drawCommandbar(c);
|
||||
}
|
||||
|
||||
if (encoder < 0 && f < 30000)
|
||||
f += 100;
|
||||
else if (encoder > 0 && f > 600)
|
||||
f -= 100;
|
||||
itoa(f, c, 10);
|
||||
strcat(c, " ");
|
||||
drawCommandbar(c);
|
||||
}
|
||||
*/
|
||||
if(!readTouch())
|
||||
continue;
|
||||
|
||||
scaleTouch(&ts_point);
|
||||
|
||||
int total = sizeof(btn_set)/sizeof(struct Button);
|
||||
for (int i = 0; i < MAX_KEYS; i++){
|
||||
struct Button b;
|
||||
memcpy_P(&b, keypad + i, sizeof(struct Button));
|
||||
|
||||
int x2 = b.x + b.w;
|
||||
int y2 = b.y + b.h;
|
||||
|
||||
if (b.x < ts_point.x && ts_point.x < x2 &&
|
||||
b.y < ts_point.y && ts_point.y < y2){
|
||||
if (!strcmp(b.text, "OK")){
|
||||
long f = atol(c);
|
||||
if(30000 >= f && f > 100){
|
||||
frequency = f * 1000l;
|
||||
setFrequency(frequency);
|
||||
if (vfoActive == VFO_A)
|
||||
vfoA = frequency;
|
||||
else
|
||||
vfoB = frequency;
|
||||
saveVFOs();
|
||||
}
|
||||
guiUpdate();
|
||||
return;
|
||||
}
|
||||
else if (!strcmp(b.text, "<-")){
|
||||
c[cursor_pos] = 0;
|
||||
if (cursor_pos > 0)
|
||||
cursor_pos--;
|
||||
}
|
||||
else if (!strcmp(b.text, "Can")){
|
||||
guiUpdate();
|
||||
return;
|
||||
}
|
||||
else if('0' <= b.text[0] && b.text[0] <= '9'){
|
||||
c[cursor_pos++] = b.text[0];
|
||||
c[cursor_pos] = 0;
|
||||
}
|
||||
}
|
||||
} // end of the button scanning loop
|
||||
displayText(c, 0, 40, 320, 40, ILI9341_WHITE, ILI9341_NAVY, ILI9341_NAVY);
|
||||
delay(300);
|
||||
while(readTouch())
|
||||
checkCAT();
|
||||
} // end of event loop : while(1)
|
||||
|
||||
}
|
||||
|
||||
void drawCWStatus(){
|
||||
utftFillrect(0, 201, 320, 39, ILI9341_NAVY);
|
||||
strcpy(b, " cw:");
|
||||
int wpm = 1200/cwSpeed;
|
||||
itoa(wpm,c, 10);
|
||||
strcat(b, c);
|
||||
strcat(b, "wpm, ");
|
||||
itoa(sideTone, c, 10);
|
||||
strcat(b, c);
|
||||
strcat(b, "hz");
|
||||
displayRawText(b, 0, 201, ILI9341_CYAN, ILI9341_NAVY);
|
||||
}
|
||||
|
||||
|
||||
void drawTx(){
|
||||
if (inTx)
|
||||
displayText("TX", 280, 48, 37, 28, ILI9341_BLACK, ILI9341_ORANGE, ILI9341_BLUE);
|
||||
else
|
||||
utftFillrect(280, 48, 37, 28, ILI9341_NAVY);
|
||||
}
|
||||
void drawStatusbar(){
|
||||
drawCWStatus();
|
||||
}
|
||||
|
||||
void guiUpdate(){
|
||||
|
||||
/*
|
||||
if (doingCAT)
|
||||
return;
|
||||
*/
|
||||
// use the current frequency as the VFO frequency for the active VFO
|
||||
displayClear(ILI9341_NAVY);
|
||||
|
||||
memset(vfoDisplay, 0, 12);
|
||||
displayVFO(VFO_A);
|
||||
checkCAT();
|
||||
memset(vfoDisplay, 0, 12);
|
||||
displayVFO(VFO_B);
|
||||
|
||||
checkCAT();
|
||||
displayRIT();
|
||||
checkCAT();
|
||||
|
||||
//force the display to refresh everything
|
||||
//display all the buttons
|
||||
for (int i = 0; i < MAX_BUTTONS; i++){
|
||||
struct Button b;
|
||||
memcpy_P(&b, btn_set + i, sizeof(struct Button));
|
||||
btnDraw(&b);
|
||||
checkCAT();
|
||||
}
|
||||
drawStatusbar();
|
||||
checkCAT();
|
||||
}
|
||||
|
||||
/*
|
||||
* This formats the frequency given in f
|
||||
*/
|
||||
void formatFreq(long f, char *buff) {
|
||||
// tks Jack Purdum W8TEE
|
||||
// replaced fsprint commmands by str commands for code size reduction
|
||||
|
||||
memset(buff, 0, 10);
|
||||
memset(b, 0, sizeof(b));
|
||||
|
||||
ultoa(f, b, DEC);
|
||||
|
||||
//one mhz digit if less than 10 M, two digits if more
|
||||
if (f < 10000000l){
|
||||
buff[0] = ' ';
|
||||
strncat(buff, b, 4);
|
||||
strcat(buff, ".");
|
||||
strncat(buff, &b[4], 2);
|
||||
}
|
||||
else {
|
||||
strncat(buff, b, 5);
|
||||
strcat(buff, ".");
|
||||
strncat(buff, &b[5], 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this builds up the top line of the display with frequency and mode
|
||||
void updateDisplay() {
|
||||
displayVFO(vfoActive);
|
||||
}
|
||||
|
||||
int enc_prev_state = 3;
|
||||
|
||||
/**
|
||||
* The A7 And A6 are purely analog lines on the Arduino Nano
|
||||
* These need to be pulled up externally using two 10 K resistors
|
||||
*
|
||||
* There are excellent pages on the Internet about how these encoders work
|
||||
* and how they should be used. We have elected to use the simplest way
|
||||
* to use these encoders without the complexity of interrupts etc to
|
||||
* keep it understandable.
|
||||
*
|
||||
* The enc_state returns a two-bit number such that each bit reflects the current
|
||||
* value of each of the two phases of the encoder
|
||||
*
|
||||
* The enc_read returns the number of net pulses counted over 50 msecs.
|
||||
* If the puluses are -ve, they were anti-clockwise, if they are +ve, the
|
||||
* were in the clockwise directions. Higher the pulses, greater the speed
|
||||
* at which the enccoder was spun
|
||||
*/
|
||||
|
||||
byte enc_state (void) {
|
||||
//Serial.print(digitalRead(ENC_A)); Serial.print(":");Serial.println(digitalRead(ENC_B));
|
||||
return (digitalRead(ENC_A) == 1 ? 1 : 0) + (digitalRead(ENC_B) == 1 ? 2: 0);
|
||||
}
|
||||
|
||||
int enc_read(void) {
|
||||
int result = 0;
|
||||
byte newState;
|
||||
int enc_speed = 0;
|
||||
|
||||
long stop_by = millis() + 200;
|
||||
|
||||
while (millis() < stop_by) { // check if the previous state was stable
|
||||
newState = enc_state(); // Get current state
|
||||
|
||||
// if (newState != enc_prev_state)
|
||||
// active_delay(20);
|
||||
|
||||
if (enc_state() != newState || newState == enc_prev_state)
|
||||
continue;
|
||||
//these transitions point to the encoder being rotated anti-clockwise
|
||||
if ((enc_prev_state == 0 && newState == 2) ||
|
||||
(enc_prev_state == 2 && newState == 3) ||
|
||||
(enc_prev_state == 3 && newState == 1) ||
|
||||
(enc_prev_state == 1 && newState == 0)){
|
||||
result--;
|
||||
}
|
||||
//these transitions point o the enccoder being rotated clockwise
|
||||
if ((enc_prev_state == 0 && newState == 1) ||
|
||||
(enc_prev_state == 1 && newState == 3) ||
|
||||
(enc_prev_state == 3 && newState == 2) ||
|
||||
(enc_prev_state == 2 && newState == 0)){
|
||||
result++;
|
||||
}
|
||||
enc_prev_state = newState; // Record state for next pulse interpretation
|
||||
enc_speed++;
|
||||
active_delay(1);
|
||||
}
|
||||
//if (result)
|
||||
// Serial.println(result);
|
||||
return(result);
|
||||
}
|
||||
|
||||
void vfoReset(){
|
||||
Button b;
|
||||
if (vfoActive = VFO_A)
|
||||
vfoB = vfoA;
|
||||
else
|
||||
vfoA = vfoB;
|
||||
|
||||
if (splitOn){
|
||||
getButton("SPL", &b);
|
||||
splitToggle(&b);
|
||||
}
|
||||
|
||||
if (ritOn){
|
||||
getButton("RIT", &b);
|
||||
ritToggle(&b);
|
||||
}
|
||||
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_A);
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_B);
|
||||
|
||||
saveVFOs();
|
||||
}
|
||||
|
||||
void ritToggle(struct Button *b){
|
||||
if (ritOn == 0){
|
||||
ritEnable(frequency);
|
||||
}
|
||||
else
|
||||
ritDisable();
|
||||
btnDraw(b);
|
||||
displayRIT();
|
||||
}
|
||||
|
||||
void cwToggle(struct Button *b){
|
||||
if (cwMode == 0){
|
||||
cwMode = 1;
|
||||
}
|
||||
else
|
||||
cwMode = 0;
|
||||
|
||||
setFrequency(frequency);
|
||||
btnDraw(b);
|
||||
}
|
||||
|
||||
void sidebandToggle(struct Button *b){
|
||||
if (!strcmp(b->text, "LSB"))
|
||||
isUSB = 0;
|
||||
else
|
||||
isUSB = 1;
|
||||
|
||||
struct Button e;
|
||||
getButton("USB", &e);
|
||||
btnDraw(&e);
|
||||
getButton("LSB", &e);
|
||||
btnDraw(&e);
|
||||
|
||||
saveVFOs();
|
||||
}
|
||||
|
||||
void splitToggle(struct Button *b){
|
||||
|
||||
if (splitOn)
|
||||
splitOn = 0;
|
||||
else
|
||||
splitOn = 1;
|
||||
|
||||
btnDraw(b);
|
||||
|
||||
//disable rit as well
|
||||
ritDisable();
|
||||
|
||||
struct Button b2;
|
||||
getButton("RIT", &b2);
|
||||
btnDraw(&b2);
|
||||
|
||||
displayRIT();
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_A);
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_B);
|
||||
}
|
||||
|
||||
void switchVFO(int vfoSelect){
|
||||
if (vfoSelect == VFO_A){
|
||||
if (vfoActive == VFO_B){
|
||||
vfoB = frequency;
|
||||
isUsbVfoB = isUSB;
|
||||
EEPROM.put(VFO_B, frequency);
|
||||
if (isUsbVfoB)
|
||||
EEPROM.put(VFO_B_MODE, VFO_MODE_USB);
|
||||
else
|
||||
EEPROM.put(VFO_B_MODE, VFO_MODE_LSB);
|
||||
}
|
||||
vfoActive = VFO_A;
|
||||
// printLine2("Selected VFO A ");
|
||||
frequency = vfoA;
|
||||
isUSB = isUsbVfoA;
|
||||
}
|
||||
else {
|
||||
if (vfoActive == VFO_A){
|
||||
vfoA = frequency;
|
||||
isUsbVfoA = isUSB;
|
||||
EEPROM.put(VFO_A, frequency);
|
||||
if (isUsbVfoA)
|
||||
EEPROM.put(VFO_A_MODE, VFO_MODE_USB);
|
||||
else
|
||||
EEPROM.put(VFO_A_MODE, VFO_MODE_LSB);
|
||||
}
|
||||
vfoActive = VFO_B;
|
||||
// printLine2("Selected VFO B ");
|
||||
frequency = vfoB;
|
||||
isUSB = isUsbVfoB;
|
||||
}
|
||||
|
||||
setFrequency(frequency);
|
||||
|
||||
struct Button b;
|
||||
ritDisable();
|
||||
getButton("RIT", &b);
|
||||
btnDraw(&b);
|
||||
displayRIT();
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_A);
|
||||
memset(vfoDisplay, 0, sizeof(vfoDisplay));
|
||||
displayVFO(VFO_B);
|
||||
saveVFOs();
|
||||
|
||||
//draw the lsb/usb buttons, the sidebands might have changed
|
||||
getButton("LSB", &b);
|
||||
btnDraw(&b);
|
||||
getButton("USB", &b);
|
||||
btnDraw(&b);
|
||||
}
|
||||
|
||||
void switchBand(long bandfreq){
|
||||
long offset;
|
||||
|
||||
// Serial.println(frequency);
|
||||
// Serial.println(bandfreq);
|
||||
if (3500000l <= frequency && frequency <= 4000000l)
|
||||
offset = frequency - 3500000l;
|
||||
else if (24800000l <= frequency && frequency <= 25000000l)
|
||||
offset = frequency - 24800000l;
|
||||
else
|
||||
offset = frequency % 1000000l;
|
||||
|
||||
// Serial.println(offset);
|
||||
|
||||
setFrequency(bandfreq + offset);
|
||||
updateDisplay();
|
||||
saveVFOs();
|
||||
}
|
||||
|
||||
int setCwSpeed(){
|
||||
int knob = 0;
|
||||
int wpm;
|
||||
|
||||
wpm = 1200/cwSpeed;
|
||||
|
||||
wpm = getValueByKnob(1, 100, 1, wpm, "CW: ", " WPM");
|
||||
|
||||
cwSpeed = 1200/wpm;
|
||||
|
||||
EEPROM.put(CW_SPEED, cwSpeed);
|
||||
active_delay(500);
|
||||
drawStatusbar();
|
||||
// printLine2("");
|
||||
// updateDisplay();
|
||||
}
|
||||
|
||||
void setCwTone(){
|
||||
int knob = 0;
|
||||
int prev_sideTone;
|
||||
|
||||
tone(CW_TONE, sideTone);
|
||||
|
||||
//disable all clock 1 and clock 2
|
||||
while (digitalRead(PTT) == HIGH && !btnDown())
|
||||
{
|
||||
knob = enc_read();
|
||||
|
||||
if (knob > 0 && sideTone < 2000)
|
||||
sideTone += 10;
|
||||
else if (knob < 0 && sideTone > 100 )
|
||||
sideTone -= 10;
|
||||
else
|
||||
continue; //don't update the frequency or the display
|
||||
|
||||
tone(CW_TONE, sideTone);
|
||||
itoa(sideTone, c, 10);
|
||||
strcpy(b, "CW Tone: ");
|
||||
strcat(b, c);
|
||||
strcat(b, " Hz");
|
||||
drawCommandbar(b);
|
||||
//printLine2(b);
|
||||
|
||||
checkCAT();
|
||||
active_delay(20);
|
||||
}
|
||||
noTone(CW_TONE);
|
||||
//save the setting
|
||||
EEPROM.put(CW_SIDETONE, sideTone);
|
||||
|
||||
utftFillrect(30,41,280, 32, ILI9341_NAVY);
|
||||
drawStatusbar();
|
||||
// printLine2("");
|
||||
// updateDisplay();
|
||||
}
|
||||
|
||||
void doCommand(struct Button *b){
|
||||
|
||||
if (!strcmp(b->text, "RIT"))
|
||||
ritToggle(b);
|
||||
else if (!strcmp(b->text, "LSB"))
|
||||
sidebandToggle(b);
|
||||
else if (!strcmp(b->text, "USB"))
|
||||
sidebandToggle(b);
|
||||
else if (!strcmp(b->text, "CW"))
|
||||
cwToggle(b);
|
||||
else if (!strcmp(b->text, "SPL"))
|
||||
splitToggle(b);
|
||||
else if (!strcmp(b->text, "VFOA")){
|
||||
if (vfoActive == VFO_A)
|
||||
fastTune();
|
||||
else
|
||||
switchVFO(VFO_A);
|
||||
}
|
||||
else if (!strcmp(b->text, "VFOB")){
|
||||
if (vfoActive == VFO_B)
|
||||
fastTune();
|
||||
else
|
||||
switchVFO(VFO_B);
|
||||
}
|
||||
else if (!strcmp(b->text, "A=B"))
|
||||
vfoReset();
|
||||
else if (!strcmp(b->text, "80"))
|
||||
switchBand(3500000l);
|
||||
else if (!strcmp(b->text, "40"))
|
||||
switchBand(7000000l);
|
||||
else if (!strcmp(b->text, "30"))
|
||||
switchBand(10000000l);
|
||||
else if (!strcmp(b->text, "20"))
|
||||
switchBand(14000000l);
|
||||
else if (!strcmp(b->text, "18"))
|
||||
switchBand(18000000l);
|
||||
else if (!strcmp(b->text, "15"))
|
||||
switchBand(21000000l);
|
||||
else if (!strcmp(b->text, "13"))
|
||||
switchBand(24800000l);
|
||||
else if (!strcmp(b->text, "10"))
|
||||
switchBand(28000000l);
|
||||
else if (!strcmp(b->text, "FRQ"))
|
||||
enterFreq();
|
||||
else if (!strcmp(b->text, "WPM"))
|
||||
setCwSpeed();
|
||||
else if (!strcmp(b->text, "TON"))
|
||||
setCwTone();
|
||||
}
|
||||
|
||||
void checkTouch(){
|
||||
|
||||
if (!readTouch())
|
||||
return;
|
||||
|
||||
while(readTouch())
|
||||
checkCAT();
|
||||
scaleTouch(&ts_point);
|
||||
|
||||
/* //debug code
|
||||
Serial.print(ts_point.x); Serial.print(' ');Serial.println(ts_point.y);
|
||||
*/
|
||||
int total = sizeof(btn_set)/sizeof(struct Button);
|
||||
for (int i = 0; i < MAX_BUTTONS; i++){
|
||||
struct Button b;
|
||||
memcpy_P(&b, btn_set + i, sizeof(struct Button));
|
||||
|
||||
int x2 = b.x + b.w;
|
||||
int y2 = b.y + b.h;
|
||||
|
||||
if (b.x < ts_point.x && ts_point.x < x2 &&
|
||||
b.y < ts_point.y && ts_point.y < y2)
|
||||
doCommand(&b);
|
||||
}
|
||||
}
|
||||
|
||||
//returns true if the button is pressed
|
||||
int btnDown(){
|
||||
if (digitalRead(FBUTTON) == HIGH)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void drawFocus(int ibtn, int color){
|
||||
struct Button b;
|
||||
|
||||
memcpy_P(&b, btn_set + ibtn, sizeof(struct Button));
|
||||
utftRect(b.x, b.y, b.w, b.h, color);
|
||||
}
|
||||
|
||||
void doMenu2(){
|
||||
int select=0, i, prevButton, btnState;
|
||||
|
||||
//wait for the button to be raised up
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(50); //debounce
|
||||
|
||||
menuOn = 2;
|
||||
|
||||
while (menuOn){
|
||||
|
||||
//check if the knob's button was pressed
|
||||
btnState = btnDown();
|
||||
if (btnState){
|
||||
struct Button b;
|
||||
memcpy_P(&b, btn_set + select/10, sizeof(struct Button));
|
||||
|
||||
doCommand(&b);
|
||||
|
||||
//unfocus the buttons
|
||||
drawFocus(select, ILI9341_BLUE);
|
||||
if (vfoActive == VFO_A)
|
||||
drawFocus(0, ILI9341_WHITE);
|
||||
else
|
||||
drawFocus(1, ILI9341_WHITE);
|
||||
|
||||
//wait for the button to be up and debounce
|
||||
while(btnDown())
|
||||
active_delay(100);
|
||||
active_delay(500);
|
||||
return;
|
||||
}
|
||||
|
||||
i = enc_read();
|
||||
|
||||
if (i == 0){
|
||||
active_delay(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i > 0){
|
||||
if (select + i < MAX_BUTTONS * 10)
|
||||
select += i;
|
||||
}
|
||||
if (i < 0 && select + i >= 0)
|
||||
select += i; //caught ya, i is already -ve here, so you add it
|
||||
|
||||
if (prevButton == select / 10)
|
||||
continue;
|
||||
|
||||
//we are on a new button
|
||||
drawFocus(prevButton, ILI9341_BLUE);
|
||||
drawFocus(select/10, ILI9341_WHITE);
|
||||
prevButton = select/10;
|
||||
}
|
||||
// guiUpdate();
|
||||
|
||||
//debounce the button
|
||||
while(btnDown())
|
||||
active_delay(50);
|
||||
active_delay(50);
|
||||
|
||||
checkCAT();
|
||||
}
|
||||
|
807
ubitx_v6.3_code.ino
Normal file
807
ubitx_v6.3_code.ino
Normal file
@ -0,0 +1,807 @@
|
||||
/**
|
||||
* This source file is under General Public License version 3.
|
||||
*
|
||||
* This verision uses a built-in Si5351 library
|
||||
* Most source code are meant to be understood by the compilers and the computers.
|
||||
* Code that has to be hackable needs to be well understood and properly documented.
|
||||
* Donald Knuth coined the term Literate Programming to indicate code that is written be
|
||||
* easily read and understood.
|
||||
*
|
||||
* The Raduino is a small board that includes the Arduin Nano, a TFT display and
|
||||
* an Si5351a frequency synthesizer. This board is manufactured by HF Signals Electronics Pvt Ltd
|
||||
*
|
||||
* To learn more about Arduino you may visit www.arduino.cc.
|
||||
*
|
||||
* The Arduino works by starts executing the code in a function called setup() and then it
|
||||
* repeatedly keeps calling loop() forever. All the initialization code is kept in setup()
|
||||
* and code to continuously sense the tuning knob, the function button, transmit/receive,
|
||||
* etc is all in the loop() function. If you wish to study the code top down, then scroll
|
||||
* to the bottom of this file and read your way up.
|
||||
*
|
||||
* Below are the libraries to be included for building the Raduino
|
||||
* The EEPROM library is used to store settings like the frequency memory, caliberation data, etc.
|
||||
*
|
||||
* The main chip which generates upto three oscillators of various frequencies in the
|
||||
* Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
|
||||
* from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
|
||||
* Instead, you can look up the Si5351 library written by xxx, yyy. You can download and
|
||||
* install it from www.url.com to complile this file.
|
||||
* The Wire.h library is used to talk to the Si5351 and we also declare an instance of
|
||||
* Si5351 object to control the clocks.
|
||||
*/
|
||||
#include <Wire.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
/**
|
||||
The main chip which generates upto three oscillators of various frequencies in the
|
||||
Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
|
||||
from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
|
||||
|
||||
We no longer use the standard SI5351 library because of its huge overhead due to many unused
|
||||
features consuming a lot of program space. Instead of depending on an external library we now use
|
||||
Jerry Gaffke's, KE7ER, lightweight standalone mimimalist "si5351bx" routines (see further down the
|
||||
code). Here are some defines and declarations used by Jerry's routines:
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* We need to carefully pick assignment of pin for various purposes.
|
||||
* There are two sets of completely programmable pins on the Raduino.
|
||||
* First, on the top of the board, in line with the LCD connector is an 8-pin connector
|
||||
* that is largely meant for analog inputs and front-panel control. It has a regulated 5v output,
|
||||
* ground and six pins. Each of these six pins can be individually programmed
|
||||
* either as an analog input, a digital input or a digital output.
|
||||
* The pins are assigned as follows (left to right, display facing you):
|
||||
* Pin 1 (Violet), A7, SPARE
|
||||
* Pin 2 (Blue), A6, KEYER (DATA)
|
||||
* Pin 3 (Green), +5v
|
||||
* Pin 4 (Yellow), Gnd
|
||||
* Pin 5 (Orange), A3, PTT
|
||||
* Pin 6 (Red), A2, F BUTTON
|
||||
* Pin 7 (Brown), A1, ENC B
|
||||
* Pin 8 (Black), A0, ENC A
|
||||
*Note: A5, A4 are wired to the Si5351 as I2C interface
|
||||
* *
|
||||
* Though, this can be assigned anyway, for this application of the Arduino, we will make the following
|
||||
* assignment
|
||||
* A2 will connect to the PTT line, which is the usually a part of the mic connector
|
||||
* A3 is connected to a push button that can momentarily ground this line. This will be used for RIT/Bandswitching, etc.
|
||||
* A6 is to implement a keyer, it is reserved and not yet implemented
|
||||
* A7 is connected to a center pin of good quality 100K or 10K linear potentiometer with the two other ends connected to
|
||||
* ground and +5v lines available on the connector. This implments the tuning mechanism
|
||||
*/
|
||||
|
||||
#define ENC_A (A0)
|
||||
#define ENC_B (A1)
|
||||
#define FBUTTON (A2)
|
||||
#define PTT (A3)
|
||||
#define ANALOG_KEYER (A6)
|
||||
#define ANALOG_SPARE (A7)
|
||||
|
||||
#include "Adafruit_GFX.h"
|
||||
//#include "Adafruit_ILI9341.h"
|
||||
#include "ubitx_font2.h"
|
||||
#include <XPT2046_Touchscreen.h>
|
||||
#include <SPI.h>
|
||||
|
||||
/** pin assignments
|
||||
14 T_IRQ 2 std changed
|
||||
13 T_DOUT (parallel to SOD/MOSI, pin 9 of display)
|
||||
12 T_DIN (parallel to SDI/MISO, pin 6 of display)
|
||||
11 T_CS 9 (we need to specify this)
|
||||
10 T_CLK (parallel to SCK, pin 7 of display)
|
||||
9 SDO(MSIO) 12 12 (spi)
|
||||
8 LED A0 8 (not needed, permanently on +3.3v) (resistor from 5v,
|
||||
7 SCK 13 13 (spi)
|
||||
6 SDI 11 11 (spi)
|
||||
5 D/C A3 7 (changable)
|
||||
4 RESET A4 9 (not needed, permanently +5v)
|
||||
3 CS A5 10 (changable)
|
||||
2 GND GND
|
||||
1 VCC VCC
|
||||
|
||||
The model is called tjctm24028-spi
|
||||
it uses an ILI9341 display controller and an XPT2046 touch controller.
|
||||
*/
|
||||
|
||||
#define TFT_DC 9
|
||||
#define TFT_CS 10
|
||||
|
||||
//#define TIRQ_PIN 2
|
||||
#define CS_PIN 8
|
||||
|
||||
// MOSI=11, MISO=12, SCK=13
|
||||
|
||||
//XPT2046_Touchscreen ts(CS_PIN);
|
||||
|
||||
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
|
||||
|
||||
/**
|
||||
* The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory.
|
||||
* We have to be very careful with variables that are declared inside the functions as they are
|
||||
* created in a memory region called the stack. The stack has just a few bytes of space on the Arduino
|
||||
* if you declare large strings inside functions, they can easily exceed the capacity of the stack
|
||||
* and mess up your programs.
|
||||
* We circumvent this by declaring a few global buffers as kitchen counters where we can
|
||||
* slice and dice our strings. These strings are mostly used to control the display or handle
|
||||
* the input and output from the USB port. We must keep a count of the bytes used while reading
|
||||
* the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable.
|
||||
*/
|
||||
char c[30], b[30];
|
||||
char printBuff[2][20]; //mirrors what is showing on the two lines of the display
|
||||
int count = 0; //to generally count ticks, loops, etc
|
||||
|
||||
/**
|
||||
* The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig.
|
||||
* This assignment is as follows :
|
||||
* Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
||||
* GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7
|
||||
* These too are flexible with what you may do with them, for the Raduino, we use them to :
|
||||
* - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer
|
||||
* - CW_KEY line : turns on the carrier for CW
|
||||
*/
|
||||
|
||||
#define TX_RX (7)
|
||||
#define CW_TONE (6)
|
||||
#define TX_LPF_A (5)
|
||||
#define TX_LPF_B (4)
|
||||
#define TX_LPF_C (3)
|
||||
#define CW_KEY (2)
|
||||
|
||||
/**
|
||||
* These are the indices where these user changable settinngs are stored in the EEPROM
|
||||
*/
|
||||
#define MASTER_CAL 0
|
||||
#define LSB_CAL 4
|
||||
#define USB_CAL 8
|
||||
#define SIDE_TONE 12
|
||||
//these are ids of the vfos as well as their offset into the eeprom storage, don't change these 'magic' values
|
||||
#define VFO_A 16
|
||||
#define VFO_B 20
|
||||
#define CW_SIDETONE 24
|
||||
#define CW_SPEED 28
|
||||
// the screen calibration parameters : int slope_x=104, slope_y=137, offset_x=28, offset_y=29;
|
||||
#define SLOPE_X 32
|
||||
#define SLOPE_Y 36
|
||||
#define OFFSET_X 40
|
||||
#define OFFSET_Y 44
|
||||
#define CW_DELAYTIME 48
|
||||
|
||||
//These are defines for the new features back-ported from KD8CEC's software
|
||||
//these start from beyond 256 as Ian, KD8CEC has kept the first 256 bytes free for the base version
|
||||
#define VFO_A_MODE 256 // 2: LSB, 3: USB
|
||||
#define VFO_B_MODE 257
|
||||
|
||||
//values that are stroed for the VFO modes
|
||||
#define VFO_MODE_LSB 2
|
||||
#define VFO_MODE_USB 3
|
||||
|
||||
// handkey, iambic a, iambic b : 0,1,2f
|
||||
#define CW_KEY_TYPE 358
|
||||
|
||||
/**
|
||||
* The uBITX is an upconnversion transceiver. The first IF is at 45 MHz.
|
||||
* The first IF frequency is not exactly at 45 Mhz but about 5 khz lower,
|
||||
* this shift is due to the loading on the 45 Mhz crystal filter by the matching
|
||||
* L-network used on it's either sides.
|
||||
* The first oscillator works between 48 Mhz and 75 MHz. The signal is subtracted
|
||||
* from the first oscillator to arriive at 45 Mhz IF. Thus, it is inverted : LSB becomes USB
|
||||
* and USB becomes LSB.
|
||||
* The second IF of 12 Mhz has a ladder crystal filter. If a second oscillator is used at
|
||||
* 57 Mhz, the signal is subtracted FROM the oscillator, inverting a second time, and arrives
|
||||
* at the 12 Mhz ladder filter thus doouble inversion, keeps the sidebands as they originally were.
|
||||
* If the second oscillator is at 33 Mhz, the oscilaltor is subtracated from the signal,
|
||||
* thus keeping the signal's sidebands inverted. The USB will become LSB.
|
||||
* We use this technique to switch sidebands. This is to avoid placing the lsbCarrier close to
|
||||
* 12 MHz where its fifth harmonic beats with the arduino's 16 Mhz oscillator's fourth harmonic
|
||||
*/
|
||||
|
||||
|
||||
#define INIT_USB_FREQ (11059200l)
|
||||
// limits the tuning and working range of the ubitx between 3 MHz and 30 MHz
|
||||
#define LOWEST_FREQ (100000l)
|
||||
#define HIGHEST_FREQ (30000000l)
|
||||
|
||||
//we directly generate the CW by programmin the Si5351 to the cw tx frequency, hence, both are different modes
|
||||
//these are the parameter passed to startTx
|
||||
#define TX_SSB 0
|
||||
#define TX_CW 1
|
||||
|
||||
char ritOn = 0;
|
||||
char vfoActive = VFO_A;
|
||||
int8_t meter_reading = 0; // a -1 on meter makes it invisible
|
||||
unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier;
|
||||
char isUsbVfoA=0, isUsbVfoB=1;
|
||||
unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
|
||||
unsigned long firstIF = 45005000L;
|
||||
|
||||
// if cwMode is flipped on, the rx frequency is tuned down by sidetone hz instead of being zerobeat
|
||||
int cwMode = 0;
|
||||
|
||||
|
||||
//these are variables that control the keyer behaviour
|
||||
int cwSpeed = 100; //this is actuall the dot period in milliseconds
|
||||
extern int32_t calibration;
|
||||
int cwDelayTime = 60;
|
||||
bool Iambic_Key = true;
|
||||
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
|
||||
unsigned char keyerControl = IAMBICB;
|
||||
//during CAT commands, we will freeeze the display until CAT is disengaged
|
||||
unsigned char doingCAT = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Raduino needs to keep track of current state of the transceiver. These are a few variables that do it
|
||||
*/
|
||||
boolean txCAT = false; //turned on if the transmitting due to a CAT command
|
||||
char inTx = 0; //it is set to 1 if in transmit mode (whatever the reason : cw, ptt or cat)
|
||||
int splitOn = 0; //working split, uses VFO B as the transmit frequency
|
||||
char keyDown = 0; //in cw mode, denotes the carrier is being transmitted
|
||||
char isUSB = 0; //upper sideband was selected, this is reset to the default for the
|
||||
//frequency when it crosses the frequency border of 10 MHz
|
||||
byte menuOn = 0; //set to 1 when the menu is being displayed, if a menu item sets it to zero, the menu is exited
|
||||
unsigned long cwTimeout = 0; //milliseconds to go before the cw transmit line is released and the radio goes back to rx mode
|
||||
unsigned long dbgCount = 0; //not used now
|
||||
unsigned char txFilter = 0; //which of the four transmit filters are in use
|
||||
boolean modeCalibrate = false;//this mode of menus shows extended menus to calibrate the oscillators and choose the proper
|
||||
//beat frequency
|
||||
|
||||
/**
|
||||
* Below are the basic functions that control the uBitx. Understanding the functions before
|
||||
* you start hacking around
|
||||
*/
|
||||
|
||||
/**
|
||||
* Our own delay. During any delay, the raduino should still be processing a few times.
|
||||
*/
|
||||
|
||||
void active_delay(int delay_by){
|
||||
unsigned long timeStart = millis();
|
||||
while (millis() - timeStart <= (unsigned long)delay_by) {
|
||||
delay(10);
|
||||
//Background Work
|
||||
checkCAT();
|
||||
}
|
||||
}
|
||||
|
||||
void saveVFOs(){
|
||||
|
||||
if (vfoActive == VFO_A)
|
||||
EEPROM.put(VFO_A, frequency);
|
||||
else
|
||||
EEPROM.put(VFO_A, vfoA);
|
||||
|
||||
if (isUsbVfoA)
|
||||
EEPROM.put(VFO_A_MODE, VFO_MODE_USB);
|
||||
else
|
||||
EEPROM.put(VFO_A_MODE, VFO_MODE_LSB);
|
||||
|
||||
if (vfoActive == VFO_B)
|
||||
EEPROM.put(VFO_B, frequency);
|
||||
else
|
||||
EEPROM.put(VFO_B, vfoB);
|
||||
|
||||
if (isUsbVfoB)
|
||||
EEPROM.put(VFO_B_MODE, VFO_MODE_USB);
|
||||
else
|
||||
EEPROM.put(VFO_B_MODE, VFO_MODE_LSB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the properly tx harmonic filters
|
||||
* The four harmonic filters use only three relays
|
||||
* the four LPFs cover 30-21 Mhz, 18 - 14 Mhz, 7-10 MHz and 3.5 to 5 Mhz
|
||||
* Briefly, it works like this,
|
||||
* - When KT1 is OFF, the 'off' position routes the PA output through the 30 MHz LPF
|
||||
* - When KT1 is ON, it routes the PA output to KT2. Which is why you will see that
|
||||
* the KT1 is on for the three other cases.
|
||||
* - When the KT1 is ON and KT2 is off, the off position of KT2 routes the PA output
|
||||
* to 18 MHz LPF (That also works for 14 Mhz)
|
||||
* - When KT1 is On, KT2 is On, it routes the PA output to KT3
|
||||
* - KT3, when switched on selects the 7-10 Mhz filter
|
||||
* - KT3 when switched off selects the 3.5-5 Mhz filter
|
||||
* See the circuit to understand this
|
||||
*/
|
||||
|
||||
void setTXFilters(unsigned long freq){
|
||||
|
||||
if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq >= 14000000L){ //thrown the KT1 relay on, the 30 MHz LPF is bypassed and the 14-18 MHz LPF is allowd to go through
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq > 7000000L){
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 1);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else {
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setTXFilters_v5(unsigned long freq){
|
||||
|
||||
if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq >= 14000000L){ //thrown the KT1 relay on, the 30 MHz LPF is bypassed and the 14-18 MHz LPF is allowd to go through
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq > 7000000L){
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 1);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else {
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is the most frequently called function that configures the
|
||||
* radio to a particular frequeny, sideband and sets up the transmit filters
|
||||
*
|
||||
* The transmit filter relays are powered up only during the tx so they dont
|
||||
* draw any current during rx.
|
||||
*
|
||||
* The carrier oscillator of the detector/modulator is permanently fixed at
|
||||
* uppper sideband. The sideband selection is done by placing the second oscillator
|
||||
* either 12 Mhz below or above the 45 Mhz signal thereby inverting the sidebands
|
||||
* through mixing of the second local oscillator.
|
||||
*/
|
||||
|
||||
void setFrequency(unsigned long f){
|
||||
uint64_t osc_f, firstOscillator, secondOscillator;
|
||||
|
||||
setTXFilters(f);
|
||||
|
||||
/*
|
||||
if (isUSB){
|
||||
si5351bx_setfreq(2, firstIF + f);
|
||||
si5351bx_setfreq(1, firstIF + usbCarrier);
|
||||
}
|
||||
else{
|
||||
si5351bx_setfreq(2, firstIF + f);
|
||||
si5351bx_setfreq(1, firstIF - usbCarrier);
|
||||
}
|
||||
*/
|
||||
//alternative to reduce the intermod spur
|
||||
if (isUSB){
|
||||
if (cwMode)
|
||||
si5351bx_setfreq(2, firstIF + f + sideTone);
|
||||
else
|
||||
si5351bx_setfreq(2, firstIF + f);
|
||||
si5351bx_setfreq(1, firstIF + usbCarrier);
|
||||
}
|
||||
else{
|
||||
if (cwMode)
|
||||
si5351bx_setfreq(2, firstIF + f + sideTone);
|
||||
else
|
||||
si5351bx_setfreq(2, firstIF + f);
|
||||
si5351bx_setfreq(1, firstIF - usbCarrier);
|
||||
}
|
||||
|
||||
frequency = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* startTx is called by the PTT, cw keyer and CAT protocol to
|
||||
* put the uBitx in tx mode. It takes care of rit settings, sideband settings
|
||||
* Note: In cw mode, doesnt key the radio, only puts it in tx mode
|
||||
* CW offest is calculated as lower than the operating frequency when in LSB mode, and vice versa in USB mode
|
||||
*/
|
||||
|
||||
void startTx(byte txMode){
|
||||
unsigned long tx_freq = 0;
|
||||
|
||||
digitalWrite(TX_RX, 1);
|
||||
inTx = 1;
|
||||
|
||||
if (ritOn){
|
||||
//save the current as the rx frequency
|
||||
ritRxFrequency = frequency;
|
||||
setFrequency(ritTxFrequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (splitOn == 1) {
|
||||
if (vfoActive == VFO_B) {
|
||||
vfoActive = VFO_A;
|
||||
isUSB = isUsbVfoA;
|
||||
frequency = vfoA;
|
||||
}
|
||||
else if (vfoActive == VFO_A){
|
||||
vfoActive = VFO_B;
|
||||
frequency = vfoB;
|
||||
isUSB = isUsbVfoB;
|
||||
}
|
||||
}
|
||||
setFrequency(frequency);
|
||||
}
|
||||
|
||||
if (txMode == TX_CW){
|
||||
digitalWrite(TX_RX, 0);
|
||||
|
||||
//turn off the second local oscillator and the bfo
|
||||
si5351bx_setfreq(0, 0);
|
||||
si5351bx_setfreq(1, 0);
|
||||
|
||||
//shif the first oscillator to the tx frequency directly
|
||||
//the key up and key down will toggle the carrier unbalancing
|
||||
//the exact cw frequency is the tuned frequency + sidetone
|
||||
if (isUSB)
|
||||
si5351bx_setfreq(2, frequency + sideTone);
|
||||
else
|
||||
si5351bx_setfreq(2, frequency - sideTone);
|
||||
|
||||
delay(20);
|
||||
digitalWrite(TX_RX, 1);
|
||||
}
|
||||
drawTx();
|
||||
//updateDisplay();
|
||||
}
|
||||
|
||||
void stopTx(){
|
||||
inTx = 0;
|
||||
|
||||
digitalWrite(TX_RX, 0); //turn off the tx
|
||||
si5351bx_setfreq(0, usbCarrier); //set back the cardrier oscillator anyway, cw tx switches it off
|
||||
|
||||
if (ritOn)
|
||||
setFrequency(ritRxFrequency);
|
||||
else{
|
||||
if (splitOn == 1) {
|
||||
//vfo Change
|
||||
if (vfoActive == VFO_B){
|
||||
vfoActive = VFO_A;
|
||||
frequency = vfoA;
|
||||
isUSB = isUsbVfoA;
|
||||
}
|
||||
else if (vfoActive == VFO_A){
|
||||
vfoActive = VFO_B;
|
||||
frequency = vfoB;
|
||||
isUSB = isUsbVfoB;
|
||||
}
|
||||
}
|
||||
setFrequency(frequency);
|
||||
}
|
||||
//updateDisplay();
|
||||
drawTx();
|
||||
}
|
||||
|
||||
/**
|
||||
* ritEnable is called with a frequency parameter that determines
|
||||
* what the tx frequency will be
|
||||
*/
|
||||
void ritEnable(unsigned long f){
|
||||
ritOn = 1;
|
||||
//save the non-rit frequency back into the VFO memory
|
||||
//as RIT is a temporary shift, this is not saved to EEPROM
|
||||
ritTxFrequency = f;
|
||||
}
|
||||
|
||||
// this is called by the RIT menu routine
|
||||
void ritDisable(){
|
||||
if (ritOn){
|
||||
ritOn = 0;
|
||||
setFrequency(ritTxFrequency);
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic User Interface Routines. These check the front panel for any activity
|
||||
*/
|
||||
|
||||
/**
|
||||
* The PTT is checked only if we are not already in a cw transmit session
|
||||
* If the PTT is pressed, we shift to the ritbase if the rit was on
|
||||
* flip the T/R line to T and update the display to denote transmission
|
||||
*/
|
||||
|
||||
void checkPTT(){
|
||||
//we don't check for ptt when transmitting cw
|
||||
if (cwTimeout > 0)
|
||||
return;
|
||||
|
||||
if (digitalRead(PTT) == 0 && inTx == 0){
|
||||
startTx(TX_SSB);
|
||||
active_delay(50); //debounce the PTT
|
||||
}
|
||||
|
||||
if (digitalRead(PTT) == 1 && inTx == 1)
|
||||
stopTx();
|
||||
}
|
||||
|
||||
void checkButton(){
|
||||
int i, t1, t2, knob, new_knob;
|
||||
|
||||
|
||||
//only if the button is pressed
|
||||
if (!btnDown())
|
||||
return;
|
||||
active_delay(50);
|
||||
if (!btnDown()) //debounce
|
||||
return;
|
||||
|
||||
//disengage any CAT work
|
||||
doingCAT = 0;
|
||||
|
||||
int downTime = 0;
|
||||
while(btnDown()){
|
||||
active_delay(10);
|
||||
downTime++;
|
||||
if (downTime > 300){
|
||||
doSetup2();
|
||||
return;
|
||||
}
|
||||
}
|
||||
active_delay(100);
|
||||
|
||||
|
||||
doMenu2();
|
||||
//wait for the button to go up again
|
||||
while(btnDown())
|
||||
active_delay(10);
|
||||
active_delay(50);//debounce
|
||||
}
|
||||
|
||||
/**
|
||||
* The tuning jumps by 50 Hz on each step when you tune slowly
|
||||
* As you spin the encoder faster, the jump size also increases
|
||||
* This way, you can quickly move to another band by just spinning the
|
||||
* tuning knob
|
||||
*/
|
||||
|
||||
void doTuning(){
|
||||
int s;
|
||||
static unsigned long prev_freq;
|
||||
static unsigned long nextFrequencyUpdate = 0;
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
if (now >= nextFrequencyUpdate && prev_freq != frequency){
|
||||
updateDisplay();
|
||||
nextFrequencyUpdate = now + 500;
|
||||
prev_freq = frequency;
|
||||
}
|
||||
|
||||
s = enc_read();
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
doingCAT = 0; // go back to manual mode if you were doing CAT
|
||||
prev_freq = frequency;
|
||||
|
||||
|
||||
if (s > 10)
|
||||
frequency += 200l * s;
|
||||
else if (s > 5)
|
||||
frequency += 100l * s;
|
||||
else if (s > 0)
|
||||
frequency += 50l * s;
|
||||
else if (s < -10)
|
||||
frequency += 200l * s;
|
||||
else if (s < -5)
|
||||
frequency += 100l * s;
|
||||
else if (s < 0)
|
||||
frequency += 50l * s;
|
||||
|
||||
if (prev_freq < 10000000l && frequency > 10000000l)
|
||||
isUSB = true;
|
||||
|
||||
if (prev_freq > 10000000l && frequency < 10000000l)
|
||||
isUSB = false;
|
||||
|
||||
setFrequency(frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* RIT only steps back and forth by 100 hz at a time
|
||||
*/
|
||||
void doRIT(){
|
||||
unsigned long newFreq;
|
||||
|
||||
int knob = enc_read();
|
||||
unsigned long old_freq = frequency;
|
||||
|
||||
if (knob < 0)
|
||||
frequency -= 100l;
|
||||
else if (knob > 0)
|
||||
frequency += 100;
|
||||
|
||||
if (old_freq != frequency){
|
||||
setFrequency(frequency);
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings are read from EEPROM. The first time around, the values may not be
|
||||
* present or out of range, in this case, some intelligent defaults are copied into the
|
||||
* variables.
|
||||
*/
|
||||
void initSettings(){
|
||||
byte x;
|
||||
//read the settings from the eeprom and restore them
|
||||
//if the readings are off, then set defaults
|
||||
EEPROM.get(MASTER_CAL, calibration);
|
||||
EEPROM.get(USB_CAL, usbCarrier);
|
||||
EEPROM.get(VFO_A, vfoA);
|
||||
EEPROM.get(VFO_B, vfoB);
|
||||
EEPROM.get(CW_SIDETONE, sideTone);
|
||||
EEPROM.get(CW_SPEED, cwSpeed);
|
||||
EEPROM.get(CW_DELAYTIME, cwDelayTime);
|
||||
|
||||
// the screen calibration parameters : int slope_x=104, slope_y=137, offset_x=28, offset_y=29;
|
||||
|
||||
if (usbCarrier > 11060000l || usbCarrier < 11048000l)
|
||||
usbCarrier = 11052000l;
|
||||
if (vfoA > 35000000l || 3500000l > vfoA)
|
||||
vfoA = 7150000l;
|
||||
if (vfoB > 35000000l || 3500000l > vfoB)
|
||||
vfoB = 14150000l;
|
||||
if (sideTone < 100 || 2000 < sideTone)
|
||||
sideTone = 800;
|
||||
if (cwSpeed < 10 || 1000 < cwSpeed)
|
||||
cwSpeed = 100;
|
||||
if (cwDelayTime < 10 || cwDelayTime > 100)
|
||||
cwDelayTime = 50;
|
||||
|
||||
/*
|
||||
* The VFO modes are read in as either 2 (USB) or 3(LSB), 0, the default
|
||||
* is taken as 'uninitialized
|
||||
*/
|
||||
|
||||
EEPROM.get(VFO_A_MODE, x);
|
||||
|
||||
switch(x){
|
||||
case VFO_MODE_USB:
|
||||
isUsbVfoA = 1;
|
||||
break;
|
||||
case VFO_MODE_LSB:
|
||||
isUsbVfoA = 0;
|
||||
break;
|
||||
default:
|
||||
if (vfoA > 10000000l)
|
||||
isUsbVfoA = 1;
|
||||
else
|
||||
isUsbVfoA = 0;
|
||||
}
|
||||
|
||||
EEPROM.get(VFO_B_MODE, x);
|
||||
switch(x){
|
||||
case VFO_MODE_USB:
|
||||
isUsbVfoB = 1;
|
||||
break;
|
||||
case VFO_MODE_LSB:
|
||||
isUsbVfoB = 0;
|
||||
break;
|
||||
default:
|
||||
if (vfoA > 10000000l)
|
||||
isUsbVfoB = 1;
|
||||
else
|
||||
isUsbVfoB = 0;
|
||||
}
|
||||
|
||||
//set the current mode
|
||||
isUSB = isUsbVfoA;
|
||||
|
||||
/*
|
||||
* The keyer type splits into two variables
|
||||
*/
|
||||
EEPROM.get(CW_KEY_TYPE, x);
|
||||
|
||||
if (x == 0)
|
||||
Iambic_Key = false;
|
||||
else if (x == 1){
|
||||
Iambic_Key = true;
|
||||
keyerControl &= ~IAMBICB;
|
||||
}
|
||||
else if (x == 2){
|
||||
Iambic_Key = true;
|
||||
keyerControl |= IAMBICB;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void initPorts(){
|
||||
|
||||
analogReference(DEFAULT);
|
||||
|
||||
//??
|
||||
pinMode(ENC_A, INPUT_PULLUP);
|
||||
pinMode(ENC_B, INPUT_PULLUP);
|
||||
pinMode(FBUTTON, INPUT_PULLUP);
|
||||
|
||||
//configure the function button to use the external pull-up
|
||||
// pinMode(FBUTTON, INPUT);
|
||||
// digitalWrite(FBUTTON, HIGH);
|
||||
|
||||
pinMode(PTT, INPUT_PULLUP);
|
||||
// pinMode(ANALOG_KEYER, INPUT_PULLUP);
|
||||
|
||||
pinMode(CW_TONE, OUTPUT);
|
||||
digitalWrite(CW_TONE, 0);
|
||||
|
||||
pinMode(TX_RX,OUTPUT);
|
||||
digitalWrite(TX_RX, 0);
|
||||
|
||||
pinMode(TX_LPF_A, OUTPUT);
|
||||
pinMode(TX_LPF_B, OUTPUT);
|
||||
pinMode(TX_LPF_C, OUTPUT);
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
|
||||
pinMode(CW_KEY, OUTPUT);
|
||||
digitalWrite(CW_KEY, 0);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(38400);
|
||||
Serial.flush();
|
||||
|
||||
displayInit();
|
||||
initSettings();
|
||||
initPorts();
|
||||
initOscillators();
|
||||
frequency = vfoA;
|
||||
setFrequency(vfoA);
|
||||
|
||||
if (btnDown()){
|
||||
isUSB = 1;
|
||||
setFrequency(10000000l);
|
||||
setupFreq();
|
||||
isUSB = 0;
|
||||
setFrequency(7100000l);
|
||||
setupBFO();
|
||||
}
|
||||
guiUpdate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The loop checks for keydown, ptt, function button and tuning.
|
||||
*/
|
||||
|
||||
byte flasher = 0;
|
||||
boolean wastouched = false;
|
||||
|
||||
void loop(){
|
||||
|
||||
if (cwMode)
|
||||
cwKeyer();
|
||||
else if (!txCAT)
|
||||
checkPTT();
|
||||
|
||||
checkButton();
|
||||
//tune only when not tranmsitting
|
||||
if (!inTx){
|
||||
if (ritOn)
|
||||
doRIT();
|
||||
else
|
||||
doTuning();
|
||||
checkTouch();
|
||||
}
|
||||
|
||||
checkCAT();
|
||||
}
|
Loading…
Reference in New Issue
Block a user