Skip to content

Instantly share code, notes, and snippets.

@yo3hjv
Last active April 10, 2020 12:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yo3hjv/089ebd759e1bedfdc8073d701ecf27f3 to your computer and use it in GitHub Desktop.
Save yo3hjv/089ebd759e1bedfdc8073d701ecf27f3 to your computer and use it in GitHub Desktop.
Arduino Icom memory CW Keyer
/*
CI-V Voice/Morse keyer
Version 1.1
https://yo3hjv.blogspot.com/2020/04/cw-and-voice-memory-keyer-for-icom-ic.html
This is a CW memory keyer for ICOM CI-V radios.
It was tested on IC-7300 and it is working well.
It was tested on IC-703 and was find not compatible.
Many thanks for inspiring the structure to KEN - KC9UMR.
The 4 x 4 keypad is able to send:
-In CW, 10 preprogrammed CW messages, each of 128 bytes;
-in SSB, AM, FM, 8 prerecorded voice messages
-"A" is Power ON
-"B" is Power OFF
-"C" is TUNE
The rest will be defined later on other versions.
This was a good opportunity for me to learn to use Arrays and Switch/case
Many thanks for the whole community from where I learned!
Thanks also to our wise government for keeping us at home...
de Adrian Florescu, YO3HJV. April, 2020
This code is released under the EUPL v1.2.
*/
#include <SoftwareSerial.h>
#include <Keypad.h>
const byte numRows = 4;
const byte numCols = 4;
byte keymap[numRows][numCols] =
{ {'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[numRows] = {9, 8, 7, 6}; //Rows 0 to 3
byte colPins[numCols] = {5, 4, 3, 2}; //Columns 0 to 3
//initializes an instance of the Keypad class
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);
/*
When sending the power ON commandCW (18 01), you need
to repeatedly send “FE” before the standard format. The
following values for pON has to be observed.
••115200 bps: 150 “FE”s
••57600 bps: 75 “FE”s
••38400 bps: 50 “FE”s
••19200 bps: 25 “FE”s
••9600 bps: 13 “FE”s
••4800 bps: 7 “FE”s
*/
#define START_BYTE 0xFE // Start byte
#define STOP_BYTE 0xFD // Stop byte
#define SEND_CW 0x17
#define VOICE_MEM 0x28
#define ZERO byte(0x00)
#define CONTROLLER_ADDRESS 0xE3 // The hex adress of the Arduino controller
char toSend;
byte asciiCW;
byte i;
byte j;
byte n = 1; // variable. how many times the message is repeated. TBD
int RPTint; // Memory repeat interval. TBD
byte p;
byte pON = 180;
char key;
byte radio;
byte voiceMem1 = 0x01;
byte voiceMem2 = 0x02;
byte voiceMem3 = 0x03;
byte voiceMem4 = 0x04;
byte voiceMem5 = 0x05;
byte voiceMem6 = 0x06;
byte voiceMem7 = 0x07;
byte voiceMem8 = 0x08;
byte vMem;
/*
* The following are USER-DEFINED values.
* The values are to be modified according to the settings on the radio
*/
#define RADIO_ADDRESS 0x94 // ic7300 has default address 0x94
#define CAT_BAUDRATE 19200 // Arduino to radio Baudrate on CI-V interface
#define RX 12 // CAT RX on Arduino UNO for software serial
#define TX 13 // CAT TX on Arduini UNO for software serial
SoftwareSerial CAT(RX, TX); // RX, TX
// THIS ARE THE PRESET CW MESSAGES TO BE SENT
// both Upper-case or Lower-case letters can be used and the following symbols
// * . , ! ? / = ( ) [SPACE] _ -
char msg_1[] = "CQ CQ DE YO3HJV yo3hjv"; // max lenght 128
char msg_2[] = "YO3HJV"; // max lenght 128
char msg_3[] = "5NN 5NN TU 73 DE YO3HJV KN"; // max lenght 128
char msg_4[] = "QRL? QRL? DE YO3HJV K"; // max lenght 128
char msg_5[] = "R R = OP HR ADI ADI BK"; // max lenght 128
char msg_6[] = "NAME ADI ADI ADI BTU"; // max lenght 128
char msg_7[] = "CQ"; // max lenght 128
char msg_8[] = "= TNX FER QSO = GL HP CU AGN 73 DE YO3HJV"; // max lenght 128
char msg_9[] = "5NN 5NN TU 73 K"; // max lenght 128
char msg_0[] = "V";
void setup() {
Serial.begin(19200);
CAT.begin(CAT_BAUDRATE); // set the data rate for the Software Serial port
delay(2);
CAT.flush();
}
void loop() {
checkPad();
}
void checkPad() {
// This is where the magic is happening
char keypressed = myKeypad.getKey();
if (keypressed != NO_KEY) {
key = keypressed;
switch (key) {
/////////// NUMBERS ///////////
case '1':
for (byte j = 0; j < n; j++) {
sendMem1();
vMem = voiceMem1;
sendVoice();
}
break;
case '2':
for (byte j = 0; j < n; j++) {
sendMem2();
vMem = voiceMem2;
sendVoice();
}
break;
case '3':
for (byte j = 0; j < n; j++) {
sendMem3();
vMem = voiceMem3;
sendVoice();
}
break;
case '4':
for (byte j = 0; j < n; j++) {
sendMem4();
vMem = voiceMem4;
sendVoice();
}
break;
case '5':
for (byte j = 0; j < n; j++) {
sendMem5();
vMem = voiceMem5;
sendVoice();
}
break;
case '6':
for (byte j = 0; j < n; j++) {
sendMem6();
vMem = voiceMem6;
sendVoice();
}
break;
case '7':
for (byte j = 0; j < n; j++) {
sendMem7();
vMem = voiceMem7;
sendVoice();
}
break;
case '8':
for (byte j = 0; j < n; j++) {
sendMem8();
vMem = voiceMem8;
sendVoice();
}
break;
case '9':
for (byte j = 0; j < n; j++) {
sendMem9();
}
break;
case '0':
for (byte j = 0; j < n; j++) {
sendMem0();
}
//////////////////// LETTERS //////////////////////
break;
case 'A':
for (byte j = 0; j < n; j++) {
powerON();
}
break;
case 'B':
for (byte j = 0; j < n; j++) {
powerOFF();
}
break;
case 'C':
for (byte j = 0; j < n; j++) {
ATUne();
}
break;
case 'D':
for (byte j = 0; j < n; j++) {
// something ;
}
break;
case '*':
for (byte j = 0; j < n; j++) {
// something();
}
break;
case '#':
for (byte j = 0; j < n; j++) {
// something();
}
break;
}// End of SWITCH
}
}
void sendVoice(){
send_preamble();
commandVOICE();
send_post();
}
void sendMem0() {
for (byte i = 0; i < sizeof(msg_0) - 1; i++) {
toSend = msg_0[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem1() {
for (byte i = 0; i < sizeof(msg_1) - 1; i++) {
toSend = msg_1[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem2() {
for (byte i = 0; i < sizeof(msg_2) - 1; i++) {
toSend = msg_2[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem3() {
for (byte i = 0; i < sizeof(msg_3) - 1; i++) {
toSend = msg_3[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem4() {
for (byte i = 0; i < sizeof(msg_4) - 1; i++) {
toSend = msg_4[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem5() {
for (byte i = 0; i < sizeof(msg_5) - 1; i++) {
toSend = msg_5[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem6() {
for (byte i = 0; i < sizeof(msg_6) - 1; i++) {
toSend = msg_6[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem7() {
for (byte i = 0; i < sizeof(msg_7) - 1; i++) {
toSend = msg_7[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem8() {
for (byte i = 0; i < sizeof(msg_8) - 1; i++) {
toSend = msg_8[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void sendMem9() {
for (byte i = 0; i < sizeof(msg_9) - 1; i++) {
toSend = msg_9[i];
send_preamble();
commandCW();
send_CW();
send_post();
}
}
void ATUne(){
send_preamble();
CAT.write(0x1C);
CAT.write(01);
CAT.write(02);
send_post();
}
void commandCW() {
CAT.write(SEND_CW);
}
void commandVOICE(){
CAT.write(VOICE_MEM);
CAT.write(ZERO);
CAT.write(vMem);
}
void send_CW() {
ASCIItoHEX();
CAT.write(asciiCW);
}
void send_preamble()
{
CAT.write(0xFE);
CAT.write(0xFE);
CAT.write(RADIO_ADDRESS);
CAT.write(CONTROLLER_ADDRESS);
}
void send_post()
{
CAT.write(0xFD);
CAT.flush();
}
////////////////////// Here is ASCII to ICOM HEX ASCII ///////////////////////////////
void ASCIItoHEX () {
switch (toSend) {
////////////////////////////// NUMBERS ///////////////////////
case '0':
asciiCW = 0x30;
break;
case '1':
asciiCW = 0x31;
break;
case '2':
asciiCW = 0x32;
break;
case '3':
asciiCW = 0x33;
break;
case '4':
asciiCW = 0x34;
break;
case '5':
asciiCW = 0x35;
break;
case '6':
asciiCW = 0x36;
break;
case '7':
asciiCW = 0x37;
break;
case '8':
asciiCW = 0x38;
break;
case '9':
asciiCW = 0x39;
break;
////////////////////////////// SYMBOLS ////////////////////////
case ' ' :
asciiCW = 0x20;
break;
case '*': // This is to insert CONTEST NUMBER
asciiCW = 0x2A;
break;
case '/':
asciiCW = 0x2F;
break;
case '-':
asciiCW = 0x2D;
break;
case '?':
asciiCW = 0x3F;
break;
case ',':
asciiCW = 0x2C;
break;
case '.':
asciiCW = 0x2E;
break;
case '@':
asciiCW = 0x40;
break;
case '=':
asciiCW = 0x3D;
break;
case '!':
asciiCW = 0x21;
break;
case '(':
asciiCW = 0x28;
break;
case ')':
asciiCW = 0x29;
break;
case '"':
asciiCW = 0x22;
break;
case '#':
asciiCW = 0x23;
break;
case '_':
asciiCW = 0x5F;
break;
////////////////////// UPPER-CASE LETTERS /////////////////////////////
case 'A':
asciiCW = 0x41;
break;
case 'B':
asciiCW = 0x42;
break;
case 'C':
asciiCW = 0x43;
break;
case 'D':
asciiCW = 0x44;
break;
case 'E':
asciiCW = 0x45;
break;
case 'F':
asciiCW = 0x46;
break;
case 'G':
asciiCW = 0x47;
break;
case 'H':
asciiCW = 0x48;
break;
case 'I':
asciiCW = 0x49;
break;
case 'J':
asciiCW = 0x4A;
break;
case 'K':
asciiCW = 0x4B;
break;
case 'L':
asciiCW = 0x4C;
break;
case 'M':
asciiCW = 0x4D;
break;
case 'N':
asciiCW = 0x4E;
break;
case 'O':
asciiCW = 0x4F;
break;
case 'P':
asciiCW = 0x50;
break;
case 'Q':
asciiCW = 0x51;
break;
case 'R':
asciiCW = 0x52;
break;
case 'S':
asciiCW = 0x53;
break;
case 'T':
asciiCW = 0x54;
break;
case 'U':
asciiCW = 0x55;
break;
case 'V':
asciiCW = 0x56;
break;
case 'W':
asciiCW = 0x57;
break;
case 'X':
asciiCW = 0x58;
break;
case 'Y':
asciiCW = 0x59;
break;
case 'Z':
asciiCW = 0x5A;
break;
///////////////////// LOWER CASE LETTERS ////////////////////////////////
case 'a':
asciiCW = 0x41;
break;
case 'b':
asciiCW = 0x42;
break;
case 'c':
asciiCW = 0x43;
break;
case 'd':
asciiCW = 0x44;
break;
case 'e':
asciiCW = 0x45;
break;
case 'f':
asciiCW = 0x46;
break;
case 'g':
asciiCW = 0x47;
break;
case 'h':
asciiCW = 0x48;
break;
case 'i':
asciiCW = 0x49;
break;
case 'j':
asciiCW = 0x4A;
break;
case 'k':
asciiCW = 0x4B;
break;
case 'l':
asciiCW = 0x4C;
break;
case 'm':
asciiCW = 0x4D;
break;
case 'n':
asciiCW = 0x4E;
break;
case 'o':
asciiCW = 0x4F;
break;
case 'p':
asciiCW = 0x50;
break;
case 'q':
asciiCW = 0x51;
break;
case 'r':
asciiCW = 0x52;
break;
case 's':
asciiCW = 0x53;
break;
case 't':
asciiCW = 0x54;
break;
case 'u':
asciiCW = 0x55;
break;
case 'v':
asciiCW = 0x56;
break;
case 'w':
asciiCW = 0x57;
break;
case 'x':
asciiCW = 0x58;
break;
case 'y':
asciiCW = 0x59;
break;
case 'z':
asciiCW = 0x5A;
break;
}
delay(1); // For stability
}
void powerON() {
for (byte p = 0; p <= pON; p++) {
CAT.write(0xFE); // preamble is sent multiple times
}
send_preamble();
CAT.write(0x18);
CAT.write(0x01);
send_post();
}
void powerOFF() {
send_preamble();
CAT.write(0x18);
CAT.write(ZERO);
send_post();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment