27 aprilie 2020

K3NG keyer error with DL2SBA bankswitch mod

I decided that I have to make another K3NG keyer, this time full featured in order to test some things. 
Therefore, I started to make it "real" not just a breadboard full of "dead bugs". 
Looking into the code, I found a very interesting feature that provide 9 memories with only 3 buttons. 

The solution is proposed by Dietmar, DL2SBA and consist in both hardware and software modifications of the original source code (which is already big and full of stuff).

Choosing to have Command Buttons AND DL2SBA bankswitch resulted into error.

I gave it a shot and when Command Buttons feature and DL2SBA bankswitch feature are selected, the compiling ends into 
"exit status 1
invalid preprocessing directive #elseif" 
somewhere around the line #8632...




Therefore, I commented the bankswitch and get to my workaround!


And this is my solution, below.



It's just a "shift" of the voltages read by the ADC; each position of the switch is "moving" the voltage with 3 memory places. 
Therefore, we have the same 3 banks but with no software hassle.
Just check to see if in the "keyer_settings.h" there are at least 10 buttons (1 COMMAND and 9 memory).


Basically, my solution is similar to what Dieter proposed but it uses the original code without rewrite the variables on the ADC array.

And gave no compile errors, of course.
73!

10 aprilie 2020

CW and Voice memory keyer for ICOM IC-7300

After a long time I decided to came back to CW.

Just for fun and to use the Pandemia holiday I thought will be interesting to have a little remote for the Voice and CW memory.
While the Voice memory callback is relatively simple with CI-V protocol, for CW memory there are no commands provided by ICOM.
Therefore, the keyer will store the preset messages (10 messages) and send them using a 4 x 4 keypad.
The uC of choice is an Arduino with Atmega 328 on UNO platform.
The keypad is also used to Power On and OFF the radio and TUNE the ATU (I use an AH-4).



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

Here is a small video on youtube about this


Here is the code
/*
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();
}
view raw gistfile1.txt hosted with ❤ by GitHub



08 aprilie 2020

Triggering preset Voice memories and CW Memories on IC-7300

1. Voice memory M1 - M8

The PC send to the radio the following:
$FE $FE $to $from $28 $00 $## $FD
## - Memory Location

2. CW Memory M1 - M8
It cannot be sent directly by a dedicated command via CI-V. (found it hard way, confirmed HERE)
Therefore, a workaround can be done like this:

1. Read the memory by sending
$FE $FE $DEV $RADIO $1A $02 $## $FD (## 1 to 8)
 the radio will respond with byte string 
$FE $FE $DEV $RADIO $1A $02 ____ 70 bytes $FD


2. Load the bytes into an Array
      Mem1[77] ; The Array will have 6 bytes preamble, 70 bytes message, 1 byte STOP BYTE (EOM)
3.  For (int i = 6, i<=76, i++)
    { byte CW = Mem1[i];
       sendPreable();
       sendCW();
       mySerial.write(CW);
       sendSTOP();   
    }
       This will send the stored message.

06 aprilie 2020

ICOM CI-V IC 7300 commands

Here are some finding:
-All end on $FD

Send CW characters 

 "A" - 41
$FE$FEra$E0$17$xx$FD

Tuner On/Off


$FE
$FEra$E0$1C$01$01$FD
1C 01 00 - tuner OFF
1C 01 01 - tuner ON
1C 01 02 - TUNE START

Delta TX On/Off

$FE$FEtofm$05$21$00$08$13$01

BCD format / LSB first
Ex: $21 $00 $08 $13 $01 is dTX -1.308

Voice Memory Keyer



$FE$FEtofm$28$##


$FD
## - Memory slot

CW Memory Keyer


$FE$FEtofm$1A$05$01$56$##$FD

## - Memory slot

For 1.30 FW revision:


Most viewed posts in last 30 days