HamHead/alpha/alpha001.ino

163 lines
5.3 KiB
C++

/**
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();
}
}