logo
  
How to control ICOM DVR with contest software (OTRSP)
NThis hack should work with any software that supports OTRSP protocol. (or MKII protocol)
 
The hack is based on the following fact about DVR enabled Icom radios:
 
Although you could use a series of resistors and switching transistors, this solution is NOT cool!
 
 
A cooler solution is to use a digital pot such as the MCP4231 controlling it via a simple arduino like the nano with a USB serial port. This digital pot has 2x 0-10K resistors in linear 128 steps. When connected in series you can get 0-20K and the control is via SPI
(mode 0 and mode 3 supported)
 
 
 
Update:
My first attempt although worked fine, picked up RF and ended voice messages prematurely.
 
To counter act this, I added a small miniature relay on one of the outputs  such that after the message is triggered the circuit is taken physically off.
 
The relay trigger was on pin A1. Updated schematic and code appear below 
 
There is still problem though with RF feedback that makes this unusable on some bands. My next solution is to solder a DPDT relay to physically disconnect both mic pins after the relay has been triggered off! 
 
 
Here is the schematic!
 
 
You can use any digital or analog pins but configure the correct one in the code
 
I am using A0 for VDD and A5 for CS (=Chip Select).
 
 
 
The code is simple:
 
 
Reset
Then switch on the pot (A0 HIGH) 5V to its DCC 
 
Look out for the Serial commands from the software:
KP1, KP2, KP3 or KP4  or KA (Abort) as per OTSRSP   
 
 
Put the resistance to the right level using SPI
Wait for 50ms for ICOM DVR to detect that
Put the resistance back to 20K using SPI
 Listen to serial port
 
 
It uses MKII serial commands for now as win-test doesnt as yet support OTRSP voice keyer commands.
 
This code has been tested with an icom 756 pro III 
 
#include <SPI.h>
 
/*
 
 This software is written by Marios Nicolaou 5B4WN/G0WWW
 Use this software at your own risk!
 
 More details about this project http://www.5b4wn.com/main/a2138.html
 Connections
 arduino MOSI 11  to SDI  3
 arduino CLK  13  to SCK  2
 arduino CS   10  to CS   1
 
 Resistance is 5 and 6 POT1
 Resistrance is 10 and 9 POT0
 
 putting them in series increases the range!
 
 For Icom we need 
 Message 1 1.5K
 Message 2 3K
 Message 3 5.2K
 Message 4 9.9K
 For OTRSP see http://www.k1xm.org/OTRSP/OTRSP_Protocol.pdf
 Commands supported
 KP1 KP2 KP3 KP4
 KA   abort
 Command terminated by \R
 */
int SSpin=19; //a5
int potPowerPin= 14; //a0
int relayOnPin=15; //a1
int pot0=0x10;
int pot1=0x0;
long timeSincePress;
String serialCommand;
int delayTime=60; //time for the resistance to be applied to the two pins of mic. Min is 50ms 
void setup() {
  //supported modes by MPC are mode 0 and mode 3
  pinMode(SSpin, OUTPUT);
  pinMode(potPowerPin, OUTPUT);
  pinMode(relayOnPin, OUTPUT);
 
  digitalWrite(relayOnPin, LOW);
  digitalWrite(potPowerPin, HIGH); //powerUp Pot
  SPI.setDataMode(0);
  SPI.begin();
 
  Serial.begin(9600); //OTRSP default 9600
  Serial.println("5B4WN Icom voice keyer");
  maxPot(); //go to 20K to avoid triggering the memory
  timeSincePress=millis(); //initialise time
}
 
void loop() {
  if (Serial.available()>0) {
    byte buffer=Serial.read();
    serialCommand +=(char) buffer;
    if (serialCommand.length()>20) {
      serialCommand=""; //avoid too long strings
    }
 
    if (buffer==0x0d) { //received a \r 
 
 
      if (serialCommand.startsWith("MP")) {
        String memory=serialCommand.substring(2,3); //from  2 to 3!
        Serial.println("Memory:"+memory);
        if (memory=="1") {
          digitalWrite(relayOnPin, HIGH);
          writePot(pot0, 1500);
          writePot(pot1, 1500);
 
          delay(delayTime);
          digitalWrite(relayOnPin, LOW);
          maxPot();     
          timeSincePress=millis();
 
 
        } 
        else if (memory=="2") {
          digitalWrite(relayOnPin, HIGH);
          writePot(pot0, 3000);
          writePot(pot1, 3000);
          delay(delayTime);
          digitalWrite(relayOnPin, LOW);
          maxPot();     
          timeSincePress=millis();
 
        } 
        else if (memory=="3") {
          digitalWrite(relayOnPin, HIGH);
          writePot(pot0, 5200);
          writePot(pot1, 5200);
 
          delay(delayTime);
          digitalWrite(relayOnPin, LOW);
          maxPot();     
          timeSincePress=millis();
        } 
        else if (memory=="4") {
          digitalWrite(relayOnPin, HIGH);
          writePot(pot0, 9900);
          writePot(pot1, 9900);
 
          delay(delayTime);
          digitalWrite(relayOnPin, LOW);
          maxPot();     
          timeSincePress=millis();
        }
        else  {
 
        }
 
 
        serialCommand=""; 
 
      } 
      else if (serialCommand.startsWith("MA")) {
        //abort
        if ((millis()-timeSincePress)<3000) { //if esc is pressed within 3 s (time for most messages) the resend control for message 1
          digitalWrite(relayOnPin, HIGH);
          writePot(pot0, 1500);
          writePot(pot1, 1500);
          delay(delayTime);
          digitalWrite(relayOnPin, LOW);
          maxPot();     
          timeSincePress=millis();
 
        }
        serialCommand=""; 
      } 
      else if (serialCommand.startsWith("?NAME")) {
 
        Serial.println ("5B4WN voice keyer"); 
 
      }
      else {
        //some other command so ignore 
        serialCommand=""; 
      }
 
 
 
 
    }
 
 
 
 
  } //serial.available
 
 
 
}
 
 
void writePot(int address, int valueOhms) {
 
  int n=map(valueOhms, 0, 20000,0, 128);
 
  digitalWrite(SSpin, LOW);
  SPI.transfer(address);
  SPI.transfer(n);
  digitalWrite(SSpin, HIGH);
 
 
}
 
void maxPot() {
  writePot(pot0, 20000); //go for 20K
  writePot(pot1, 20000);
 
}