You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
5.3 KiB
Arduino
163 lines
5.3 KiB
Arduino
3 years ago
|
/**
|
||
|
HamHead - Remote Head for Ham Radio
|
||
|
Copyright (C)2020 Jay Moore/NQ4T - nq4tango@gmail.com
|
||
|
Licensed under GPL-3.0-or-later
|
||
|
|
||
|
Version .001 Alpha
|
||
|
**/
|
||
|
|
||
|
#include <LEDMatrixDriver.hpp>
|
||
|
#include <Rotary.h>
|
||
|
// Rotary.h uses hardware SPI on Mega2560 pins 52 and 50 or something
|
||
|
const uint8_t LEDMATRIX_CS_PIN = 49; // You're not going to have GPIO49 on an Uno.
|
||
|
const int NO_OF_DRIVERS = 1; // Each MAX7219 driver can drive eight 7-segment displays.
|
||
|
LEDMatrixDriver lmd(NO_OF_DRIVERS, LEDMATRIX_CS_PIN);
|
||
|
const byte numBytes = 32;
|
||
|
byte rxbytes[numBytes]; // store CI-V incoming bytes here
|
||
|
long dec[5]; // part of the decimal to vfo conversion
|
||
|
int bc = 0; // byte counter
|
||
|
boolean newdata = false;
|
||
|
boolean newvfo = false;
|
||
|
unsigned long vfoa;
|
||
|
byte digit; // used by the display routine.
|
||
|
|
||
|
Rotary rotary = Rotary(2, 3);
|
||
|
void setup() {
|
||
|
Serial1.begin(19200); // I'm using a Mega2560 so I have multiple hardware UART
|
||
|
// hardware interrupt for rotary encoder
|
||
|
attachInterrupt(0, rotate, CHANGE);
|
||
|
attachInterrupt(1, rotate, CHANGE);
|
||
|
// copied from display library initialization
|
||
|
lmd.setEnabled(true);
|
||
|
lmd.setIntensity(2); // 0 = min, 15 = max
|
||
|
lmd.setScanLimit(7); // 0-7: Show 1-8 digits. Beware of currenct restrictions for 1-3 digits! See datasheet.
|
||
|
lmd.setDecode(0xFF); // Enable "BCD Type B" decoding for all digits.
|
||
|
}
|
||
|
|
||
|
void loop() {
|
||
|
getdata(); // check for serial data
|
||
|
if (rxbytes[0] == 0x88) newdata=false; // ignore echo (for now. I have an idea)
|
||
|
if (newdata == true) gogovfo(); // Go go VFO!
|
||
|
if (newvfo == true) disp(); // update the LED
|
||
|
|
||
|
}
|
||
|
void getdata() {
|
||
|
byte rb;
|
||
|
while (Serial1.available() > 0 && newdata == false) {
|
||
|
rb = Serial1.read();
|
||
|
if (rb == 0xFE) { // if it's a start byte we don't need it.
|
||
|
newdata = false; // make sure we keep looping
|
||
|
bc = 0; // i don't trust myself
|
||
|
} else if (rb == 0xFD) { // end of the frame
|
||
|
rxbytes[bc] = '\0'; // terminate the string
|
||
|
newdata = true; // indicate there's new data
|
||
|
//i--; // I thought I needed this
|
||
|
} else {
|
||
|
rxbytes[bc] = rb; // write the byte to the array
|
||
|
bc++; // increment byte counter
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
"Go Go VFO" is requires some room to explain just what it does. The data sent
|
||
|
in is both BCD and little-endian; so I not only have to convert the data from BCD,
|
||
|
but I have to load the bytes "backwards".
|
||
|
|
||
|
Grab a byte, bitshift it 4 to the left, multiply it by 10. Take that same byte, bitwise
|
||
|
AND it aginst 00001111, add them together. Now add those together in to
|
||
|
a new array; multiply each entry in the array by the appropriate power of 10,
|
||
|
add all that together in to a new variable.
|
||
|
|
||
|
Oh, and then set newvfo to true so we can update displays.
|
||
|
**/
|
||
|
|
||
|
void gogovfo() {
|
||
|
int i = 0;
|
||
|
long bcd[4];
|
||
|
bc -= 2; // adjust for array index starting at 0 and ditch the V/U byte
|
||
|
if (rxbytes[2] == 0){
|
||
|
for (int x = bc; x > 2; x--) {
|
||
|
bcd[i] = (((rxbytes[x] >> 4) *10) + (rxbytes[x]&0xF));
|
||
|
i++;
|
||
|
}
|
||
|
vfoa = ((bcd[0]*1000000)+(bcd[1]*10000)+(bcd[2]*100)+(bcd[3]));
|
||
|
newvfo = true;
|
||
|
}}
|
||
|
|
||
|
void vfoup() { // this is called by the ISR for the rotary encoder.
|
||
|
vfoa += 1000; // right now we're just adding 1000hz, but this will be selectable
|
||
|
vfotobcd(); // black magic voodoo
|
||
|
newvfo = true; // since we technically updated the VFO
|
||
|
}
|
||
|
|
||
|
void vfodown() { // this is the same thing, but the other direction
|
||
|
vfoa -= 1000; // drop 1000hz
|
||
|
vfotobcd(); // do that voodoo that you do so well
|
||
|
newvfo = true; // since, you know...new VFO
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Here's some black magic for ya. In order to go from the internal VFO
|
||
|
number, I have to basically reverse the process for getting it form the
|
||
|
radio; convert everything in to BCD digits in little-endian.
|
||
|
|
||
|
Do a bunch of math on vfoa that has the basic effect of splitting it in
|
||
|
to two digit chunks, writing each to an array.
|
||
|
|
||
|
Now divide each array entry by 10, bitshift right, add that by the remainder
|
||
|
and slap them in a byte. Do that 4 times running backwards through the
|
||
|
array.
|
||
|
|
||
|
**/
|
||
|
void vfotobcd() {
|
||
|
byte bcd2[10];
|
||
|
int dec[5];
|
||
|
int i = 3;
|
||
|
dec[0] = vfoa / 1000000;
|
||
|
dec[1] = (vfoa % 1000000) / 10000;
|
||
|
dec[2] = (vfoa % 10000) / 100;
|
||
|
dec[3] = vfoa % 100;
|
||
|
for (int x = 0; x < 4; x++){
|
||
|
bcd2[i] = (((dec[x] / 10) << 4) + (dec[x] % 10));
|
||
|
i--;
|
||
|
}
|
||
|
|
||
|
// There's got to be a better/cleaner way of doing this I haven't figured out yet
|
||
|
Serial1.write(0xFE); // start byte
|
||
|
Serial1.write(0xFE); // start byte
|
||
|
Serial1.write(0x88); // IC-7100 hex address
|
||
|
Serial1.write(0xE0); // standard E0 controller address
|
||
|
Serial1.write(0x00); // no-reply VFO change
|
||
|
Serial1.write(bcd2, 4); // the BCD data
|
||
|
Serial1.write(0xFD); // end byte
|
||
|
}
|
||
|
|
||
|
void disp() {
|
||
|
unsigned long vfod = vfoa; // we have to copy this or we'll break vfoa's entry
|
||
|
//bc++; // I thought I needed this.
|
||
|
|
||
|
/**
|
||
|
I know it's a for loop and it looks like it's just getting the remainder
|
||
|
and dividing by 10 each time to split out the digits, but I haven't
|
||
|
actually figured out how this works. Taken from the library example.
|
||
|
**/
|
||
|
for (digit = 0; digit < 8; digit++) {
|
||
|
lmd.setDigit(digit, vfod % 10, digit == 3);
|
||
|
vfod /= 10;
|
||
|
}
|
||
|
lmd.display();
|
||
|
delay(10);
|
||
|
// set these false or you're going to have problems
|
||
|
newdata = false;
|
||
|
newvfo = false;
|
||
|
}
|
||
|
|
||
|
// this came right from the rotary library example.
|
||
|
void rotate() {
|
||
|
unsigned char result = rotary.process();
|
||
|
if (result == DIR_CW) {
|
||
|
vfoup();
|
||
|
} else if (result == DIR_CCW) {
|
||
|
vfodown();
|
||
|
}
|
||
|
}
|