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);
 
}
 
 
 
 
 

VS1053b and arduino playing a file
Next step how to play a file from a FAT32 formatted SD card
 
eg 1.mp3
 
 
#include <SPI.h>
#include "VS1053.h"
#include <SD.h>
 
File myFile;
 
VS1053 player;
 
uint8_t mp3DataBuffer[ 32];
 
unsigned int modeValue;
const int chipSelect = 10;
 
void setup() {
  Serial.begin(57600);
  player.begin( 16, 17, 14, 15);
 
  delay(100);
 
 
  //do SD stuff
  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
 
  myFile=SD.open("1.mp3");
 
 
 
  SPI.setClockDivider (SPI_CLOCK_DIV8);
 
  player.Mp3SetVolume(0x30, 0x30);
  player.Mp3SoftReset();
  playFile(myFile);
 
}
 
 
 
void loop() {
 
}
 
 
void playFile(File myFile) {
 
  Serial.print("opening file");
 
  boolean moreData=true;
 
  while (1) {
    while (!digitalRead(player.dreqPin)){
      if (moreData) {
        if (!myFile.read(mp3DataBuffer,sizeof(mp3DataBuffer))) {
          break; 
        }
        moreData=false;  
      }
      //check for commands
    }
 
    if (moreData) {
      if (!myFile.read(mp3DataBuffer,sizeof(mp3DataBuffer))) {
        break; 
      }
      moreData=false;  
    }
 
    player.streamBuffer(mp3DataBuffer);
    moreData=true;
  }
  player.SPIWait();
 
  player.sendEndFillByte();
  myFile.close();
 
 
}
 
 

Playing hello using VS1053b and arduino
Having had a successful sign test the next step is to see if we can play the hello buffer
 
 
 
Here is the code:
 
#include <SPI.h>
#include "VS1053.h"
 
unsigned char HelloMP3[] = {
  0xFF,0xF2,0x40,0xC0,0x19,0xB7,0x00,0x14,0x02,0xE6,0x5C, /* ..@.......\ */
  0x01,0x92,0x68,0x01,0xF1,0x5E,0x03,0x08,0xF0,0x24,0x80, /* ..h..^...$. */
  0x05,0x9E,0x20,0xC6,0xFC,0x12,0x32,0x5C,0xBF,0xF9,0xB9, /* .. ...2\... */
  0x20,0x4A,0x7F,0x85,0xEC,0x4C,0xCD,0xC7,0x27,0xFE,0x5C, /*  J...L..'.\ */
  0x34,0x25,0xCB,0xE6,0xFF,0xFF,0x8E,0x42,0xE1,0xA0,0x5E, /* 4%.....B..^ */
  0xCA,0x6E,0x30,0x9F,0xFF,0xF8,0xC2,0x12,0x84,0xB9,0x7C, /* .n0.......| */
  0xDC,0x61,0x09,0x4A,0x7F,0xFF,0xFF,0xF9,0x7D,0x32,0x51, /* .a.J....}2Q */
  0x09,0x7C,0xE1,0xA5,0x6E,0xB4,0xFF,0xFF,0xFF,0xFF,0xD3, /* .|..n...... */
  0x34,0x41,0x91,0xF0,0x11,0x8F,0x00,0x0F,0x81,0x9C,0x10, /* 4A......... */
  0xEE,0x59,0xCE,0x56,0x67,0xFF,0xF2,0x42,0xC0,0xEC,0x53, /* .Y.Vg..B..S */
  0x09,0x15,0xF9,0xAA,0xA8,0x0D,0xD9,0x40,0x00,0xCA,0x34, /* .......@..4 */
  0x53,0xD9,0x18,0xAB,0x7D,0xF7,0x89,0x3F,0x11,0x38,0x94, /* S...}..?.8. */
  0x82,0x59,0x93,0x20,0x6A,0x0C,0xEE,0x8E,0x58,0xFA,0x38, /* .Y. j...X.8 */
  0x82,0xCA,0xF0,0x58,0xBB,0xDA,0x0C,0x50,0x56,0x1F,0xBB, /* ...X...PV.. */
  0x18,0x5D,0x8B,0x9F,0xDA,0x71,0x4F,0xFF,0xBD,0xFE,0xEF, /* .]...qO.... */
  0x69,0x36,0x86,0x3C,0x50,0xBB,0x0A,0x07,0x89,0x54,0xF0, /* i6.<P....T. */
  0x88,0x9F,0x90,0x95,0x30,0x94,0x2E,0x7E,0xF0,0x64,0x96, /* ....0..~.d. */
  0x79,0x08,0x3E,0x20,0x97,0x28,0x34,0x9C,0x09,0x7F,0xD2, /* y.> .(4.... */
  0xC0,0x01,0x75,0xF8,0x05,0x6B,0x5F,0x41,0x17,0x0B,0xE7, /* ..u..k_A... */
  0xFF,0xF2,0x40,0xC0,0x61,0xE5,0x0B,0x16,0x09,0xC6,0xC5, /* ..@.a...... */
  0x74,0x7B,0xCC,0x94,0x7A,0xF7,0x80,0x76,0xB2,0xD2,0xF8, /* t{..z..v... */
  0x39,0x06,0x38,0xFD,0x71,0xC5,0xDE,0x3A,0x38,0xBF,0xD5, /* 9.8.q..:8.. */
  0xF7,0x12,0x37,0xCB,0xF5,0x63,0x0C,0x9B,0xCE,0x77,0x25, /* ..7..c...w% */
  0xED,0xFB,0x3D,0x6B,0x35,0xF9,0x6D,0xD7,0xF9,0x2C,0xD1, /* ..=k5.m..,. */
  0x97,0x15,0x87,0x93,0xA4,0x49,0x4A,0x18,0x16,0x07,0xA1, /* .....IJ.... */
  0x60,0xF7,0x52,0x94,0xDB,0x02,0x16,0x70,0xB2,0xD8,0x80, /* `.R....p... */
  0x30,0xC2,0x94,0x40,0x81,0x74,0x5A,0x19,0x7A,0x80,0x60, /* 0..@.tZ.z.` */
  0x41,0x21,0x46,0x95,0xD5,0xC4,0x40,0xD2,0x01,0xC0,0x01, /* A!F...@.... */
  0xDA,0xD9,0xA0,0xB1,0x01,0xFF,0xF2,0x42,0xC0,0x82,0x10, /* .......B... */
  0x0B,0x12,0xF9,0x9E,0xC9,0x7E,0x7A,0xC6,0x95,0x55,0x09, /* .....~z..U. */
  0x8B,0x19,0x5E,0x8B,0x26,0xCA,0xEB,0x68,0x8A,0x05,0x8F, /* ..^.&..h... */
  0x36,0xA5,0xA5,0x03,0xB8,0x9C,0xED,0x24,0x51,0x59,0x90, /* 6......$QY. */
  0xF6,0xC5,0x7D,0xB5,0xAD,0xAF,0xF6,0x3B,0x18,0xEF,0x3F, /* ..}....;..? */
  0xFF,0xFF,0x4E,0xDE,0x16,0x66,0x0B,0xAA,0x33,0x23,0xDD, /* ..N..f..3#. */
  0x9C,0x4E,0x6E,0x55,0x22,0x9D,0xA2,0x40,0xA6,0x36,0x31, /* .NnU"..@.61 */
  0x69,0xA5,0xE1,0xD9,0x7F,0xF7,0xC6,0xCC,0x48,0x00,0x0E, /* i.......H.. */
  0x90,0x16,0x00,0x0F,0xDE,0x6E,0x80,0x11,0x0C,0x9A,0x4F, /* .....n....O */
  0x56,0xDB,0x88,0xD3,0xB2,0x1C,0x00,0xE0,0x2E,0x3E,0xAC, /* V........>. */
  0xFF,0xF2,0x40,0xC0,0x1C,0xE5,0x19,0x13,0x31,0x4E,0xCD, /* ..@.....1N. */
  0x9E,0xC3,0x06,0x71,0x03,0x85,0xE5,0xB5,0x6D,0x88,0x50, /* ...q....m.P */
  0x8E,0x0E,0x17,0x3B,0x19,0xFB,0x4E,0x3B,0x99,0xEF,0x4C, /* ...;..N;..L */
  0x9E,0xF7,0x7B,0x31,0x7C,0x3C,0x5F,0xFF,0xF4,0xF8,0xE3, /* ..{1|<_.... */
  0x92,0x42,0x07,0x8E,0x83,0x8E,0x0F,0x05,0x08,0x91,0xA3, /* .B......... */
  0x16,0xE2,0xDF,0xB7,0x62,0x60,0x48,0x31,0x3C,0xFF,0xD4, /* ....b`H1<.. */
  0x9E,0x0C,0x68,0x00,0x77,0x54,0xE3,0x1E,0x05,0xC5,0xF8, /* ..h.wT..... */
  0xEA,0x8D,0x82,0x9D,0x08,0xA9,0x06,0x8D,0x1E,0x5D,0x7C, /* .........]| */
  0x7F,0x08,0xC0,0x50,0x45,0x42,0xD0,0x36,0xF8,0xB2,0x4D, /* ...PEB.6..M */
  0x53,0x0C,0x80,0x3B,0x4D,0xFF,0xF2,0x42,0xC0,0x2F,0x3C, /* S..;M..B./< */
  0x25,0x19,0x29,0xFE,0xBC,0x2E,0xC4,0xD0,0x99,0x4C,0x48, /* %.)......LH */
  0xB0,0x9C,0x49,0xD2,0x1A,0x2D,0x02,0xC2,0x79,0x69,0x16, /* ..I..-..yi. */
  0x92,0xA8,0xC5,0xAB,0x45,0x5A,0x68,0xE8,0x75,0x57,0xCD, /* ....EZh.uW. */
  0xF1,0xB9,0xAA,0x13,0x88,0xE4,0x87,0x42,0x15,0xB3,0x58, /* .......B..X */
  0xF5,0xA3,0x46,0xB1,0xCF,0xD3,0x59,0x7E,0xBA,0xB5,0xA7, /* ..F...Y~... */
  0x6B,0x0B,0x17,0x57,0x6B,0x5C,0x4A,0xCD,0x53,0x76,0x2A, /* k..Wk\J.Sv* */
  0x1D,0x28,0xC5,0x1C,0x76,0x5C,0xDD,0x0A,0x00,0x4B,0xC0, /* .(..v\...K. */
  0x1B,0xCA,0xA8,0xE9,0x81,0x5B,0xA6,0xDC,0xA4,0x59,0x13, /* .....[...Y. */
  0xFC,0xBA,0x8F,0x98,0x79,0x44,0x25,0xC9,0x35,0x38,0xCA, /* ....yD%.58. */
  0xFF,0xF2,0x40,0xC0,0xB9,0x7D,0x1A,0x13,0x79,0x6A,0xC8, /* ..@..}..yj. */
  0x3E,0xC4,0x46,0x94,0x8D,0x3C,0x67,0x85,0xB1,0xA8,0x89, /* >.F..<g.... */
  0xC0,0xF2,0xE6,0x2F,0x9D,0x7C,0xC9,0xB4,0xBE,0xCF,0xE1, /* .../.|..... */
  0x7D,0xFE,0x1F,0x03,0x00,0x12,0x84,0x72,0x8C,0xE7,0xD8, /* }......r... */
  0x5E,0xC9,0xA9,0x01,0xBA,0x9B,0xC4,0x10,0x5C,0x70,0x2E, /* ^.......\p. */
  0x6C,0x48,0xE7,0x8C,0x15,0x0B,0x06,0x01,0xE5,0xFF,0xFF, /* lH......... */
  0xD4,0x0D,0x00,0x0F,0xCE,0x58,0x95,0x61,0xA8,0x9E,0x7B, /* .....X.a..{ */
  0x19,0x98,0xB0,0xF0,0xC6,0x72,0x82,0xD5,0x27,0x06,0x47, /* .....r..'.G */
  0x41,0x22,0x0F,0x65,0x93,0xC9,0x8A,0x09,0x19,0x48,0x1B, /* A".e.....H. */
  0xBD,0xD6,0x64,0x1A,0xAC,0xFF,0xF2,0x42,0xC0,0xF1,0x11, /* ..d....B... */
  0x25,0x14,0x22,0x06,0xBC,0x0E,0xD4,0x4E,0x99,0x90,0xA8, /* %."....N... */
  0xD8,0xB7,0xAD,0x5D,0x3E,0xAF,0x6E,0xBE,0x66,0x83,0xA4, /* ...]>.n.f.. */
  0xE3,0xC2,0xE0,0x29,0x43,0x87,0x5F,0x4F,0x27,0x9C,0x2C, /* ...)C._O'., */
  0xD0,0x91,0xF3,0x87,0x9B,0x54,0xED,0xD1,0xB4,0xF3,0x39, /* .....T....9 */
  0x87,0x22,0x06,0x86,0x0D,0x71,0xE4,0x6F,0x2A,0x08,0x04, /* ."...q.o*.. */
  0xC0,0x03,0x2A,0xB1,0xE2,0x05,0x4D,0x64,0xA1,0x9C,0xA6, /* ..*...Md... */
  0x0D,0x41,0xA6,0xF2,0x7A,0xC1,0x30,0xC3,0x38,0x26,0x09, /* .A..z.0.8&. */
  0x50,0x08,0xC4,0xF6,0x30,0x0C,0xA6,0xA9,0x17,0x00,0x13, /* P...0...... */
  0x0C,0xDC,0xC4,0x2F,0x28,0xEB,0x3F,0xCD,0x7A,0x3D,0x2F, /* .../(.?.z=/ */
  0xFF,0xF2,0x40,0xC0,0x18,0x6F,0x2E,0x13,0xA1,0xF2,0xBC, /* ..@..o..... */
  0x36,0xCB,0x4E,0x99,0x6E,0xFC,0xEE,0xC5,0xF0,0xA0,0xB7, /* 6.N.n...... */
  0x92,0xD4,0xEE,0x79,0x7C,0x50,0x5D,0xE5,0x04,0x94,0xA9, /* ...y|P].... */
  0x76,0xCF,0x6C,0x70,0xDD,0x0D,0xD4,0xEE,0xED,0x98,0xE8, /* v.lp....... */
  0xC8,0x35,0x36,0x7A,0x0C,0x05,0x80,0x03,0xBC,0xBE,0x91, /* .56z....... */
  0x00,0x7C,0xAE,0x65,0xB8,0x91,0xA3,0x33,0xBA,0x68,0x60, /* .|.e...3.h` */
  0xD4,0x1A,0x66,0xF8,0x43,0xA0,0x20,0x89,0xE7,0x80,0xD8, /* ..f.C. .... */
  0x1E,0x4F,0xA0,0x04,0x60,0x06,0x0A,0xA4,0x91,0x24,0xFA, /* .O..`....$. */
  0x9F,0x57,0x53,0xF4,0x7A,0xDB,0x5F,0x56,0xE3,0x6E,0x0B, /* .WS.z._V.n. */
  0x8B,0x3A,0x1C,0xF9,0x5E,0xFF,0xF2,0x42,0xC0,0xB1,0x00, /* .:..^..B... */
  0x38,0x14,0x09,0xEE,0xB4,0x36,0xD3,0x4E,0x99,0xA4,0x78, /* 8....6.N..x */
  0x94,0x73,0xC4,0x66,0x30,0xF5,0xEA,0xDB,0xBA,0x67,0x67, /* .s.f0....gg */
  0x95,0x6B,0xAB,0x68,0x5D,0x08,0xA1,0x39,0x56,0xAB,0x1E, /* .k.h]..9V.. */
  0xD5,0x03,0xE8,0x01,0x70,0x00,0xB3,0x93,0x33,0x19,0x8C, /* ....p...3.. */
  0x61,0x8F,0xBB,0x5D,0x24,0x12,0x63,0xD3,0x4B,0x5D,0x91, /* a..]$.c.K]. */
  0x08,0x43,0x22,0x56,0x1A,0xC5,0x10,0x21,0x84,0xA8,0xEA, /* .C"V...!... */
  0x80,0xBF,0x16,0x8E,0x3D,0x46,0x18,0x9C,0x6E,0x9A,0x91, /* ....=F..n.. */
  0xE6,0xC9,0x6F,0xD2,0x7D,0x27,0xD7,0xE9,0x6B,0xFF,0x0A, /* ..o.}'..k.. */
  0x03,0x43,0x89,0xD5,0xBF,0x52,0x97,0x0A,0x25,0x95,0x0D, /* .C...R..%.. */
  0xFF,0xF2,0x40,0xC0,0xF5,0xC3,0x41,0x13,0x81,0xEE,0xA8, /* ..@...A.... */
  0x5E,0xD3,0x44,0x98,0xFC,0xCF,0x97,0xF9,0x58,0xB5,0x33, /* ^.D.....X.3 */
  0xB1,0x85,0x47,0x86,0xD7,0x98,0x01,0x3B,0xA3,0x4F,0x7E, /* ..G....;.O~ */
  0x04,0xA6,0xC3,0x39,0x21,0x70,0x27,0x62,0xB5,0x18,0x10, /* ...9!p'b... */
  0x09,0x99,0x00,0x8B,0x7E,0xF2,0xBF,0x52,0x18,0x26,0x30, /* ....~..R.&0 */
  0x1C,0xB0,0x01,0x49,0x30,0xE0,0xC3,0x11,0x46,0x05,0xCC, /* ...I0...F.. */
  0x49,0x14,0x28,0xB2,0xED,0x4B,0x57,0x5A,0x2F,0xB7,0x46, /* I.(..KWZ/.F */
  0x63,0x34,0xD2,0xDA,0x9F,0x56,0x32,0xB7,0xA2,0x25,0xFF, /* c4...V2..%. */
  0x94,0x28,0x33,0x7F,0x3B,0xC4,0x50,0xEC,0xB1,0xE2,0x26, /* .(3.;.P...& */
  0xA1,0xB7,0x07,0x7F,0xFB,0xFF,0xF2,0x42,0xC0,0x67,0x6A, /* .......B.gj */
  0x4C,0x13,0xF9,0x6A,0x90,0x7E,0xDB,0x44,0x94,0x3F,0xFF, /* L..j.~.D.?. */
  0x14,0xD6,0x2A,0xFF,0xFF,0xC1,0x34,0x8C,0x48,0x22,0x00, /* ..*...4.H". */
  0x06,0x8F,0x21,0xFD,0x64,0x60,0x04,0x92,0x42,0xEA,0x74, /* ..!.d`..B.t */
  0x32,0x37,0xAA,0x5A,0x9F,0x67,0x01,0x8B,0x3F,0x37,0x31, /* 27.Z.g..?71 */
  0xDD,0x06,0x3C,0x01,0x34,0x30,0xE0,0x5C,0x78,0x78,0xCB, /* ..<.40.\xx. */
  0xD6,0xF1,0x31,0x8A,0x69,0x61,0x93,0x92,0x42,0xCE,0x4B, /* ..1.ia..B.K */
  0xC5,0x02,0x4E,0x73,0xC6,0x24,0x30,0xCD,0x08,0x66,0xC6, /* ..Ns.$0..f. */
  0x35,0xAB,0xA2,0x3D,0x2F,0xB3,0xBD,0x34,0x87,0x13,0xEE, /* 5..=/..4... */
  0x71,0x45,0x68,0xFA,0xEA,0x05,0x84,0x41,0x36,0x4C,0x9A, /* qEh....A6L. */
  0xFF,0xF2,0x40,0xC0,0xC9,0x92,0x56,0x13,0xD0,0x6E,0x70, /* ..@...V..np */
  0x54,0xD3,0xCC,0x28,0x06,0xD7,0x0E,0xA4,0x1D,0x9C,0x9D, /* T..(....... */
  0xD9,0xA9,0x88,0x7B,0xB5,0xA3,0x56,0xB7,0x4B,0x4B,0x5A, /* ...{..V.KKZ */
  0x9B,0x2C,0xA9,0xAD,0x6F,0x99,0x6C,0xC0,0x4C,0x14,0x14, /* .,..o.l.L.. */
  0xEF,0xB4,0x20,0x91,0x5F,0xBC,0x81,0x41,0x41,0x5D,0xD4, /* .. ._..AA]. */
  0x20,0xBD,0x05,0x1A,0x6F,0xE2,0x68,0x56,0x41,0x41,0x57, /*  ...o.hVAAW */
  0xF9,0xBF,0x89,0x82,0x8E,0xC7,0x8F,0x0A,0x0A,0x09,0x37, /* ..........7 */
  0xF1,0x05,0x0A,0x0A,0x0A,0x0A,0x09,0x05,0x37,0xFF,0x10, /* ........7.. */
  0x50,0x50,0x53,0x65,0xFF,0xFF,0xFD,0x75,0xDF,0xFF,0xFF, /* PPSe...u... */
  0x68,0x4F,0xFF,0x84,0x70,0xFF,0xF2,0x42,0xC0,0x27,0x50, /* hO..p..B.'P */
  0x5F,0x17,0xE8,0x82,0x3C,0x11,0x58,0x18,0x01,0x55,0x48, /* _...<.X..UH */
  0xBC,0x52,0xFC,0x4A,0x4C,0x3C,0xD5,0xF6,0x11,0x2D,0xBF, /* .R.JL<...-. */
  0xEA,0x03,0x5C,0x57,0x29,0xBF,0xC3,0x75,0x1C,0xE6,0xDD, /* ..\W)..u... */
  0xBF,0xED,0xEF,0xD0,0x98,0x77,0x71,0x95,0x73,0xFF,0xED, /* .....wq.s.. */
  0x54,0xBE,0xD5,0xEE,0xAE,0xC2,0xD5,0x0B,0xFF,0xF1,0x97, /* T.......... */
  0x8A,0xE4,0x42,0x09,0x99,0xB1,0xEA,0x94,0xDC,0x78,0xB5, /* ..B......x. */
  0x34,0x0F,0xF1,0x8F,0xFC,0x15,0xF6,0xFA,0xB1,0x47,0xA9, /* 4........G. */
  0x6C,0x67,0x43,0x8B,0xF2,0x76,0x22,0xED,0xDA,0x85,0xBA, /* lgC..v".... */
  0x2F,0xC7,0xF9,0xCF,0xFC,0xDB,0x46,0x2E,0x50,0x0A,0x84, /* /.....F.P.. */
  0xFF,0xF2,0x40,0xC0,0xC6,0x4A,0x59,0x28,0x2B,0x19,0xE0, /* ..@..JY(+.. */
  0x01,0x89,0x78,0x00,0x52,0x85,0x3C,0x8E,0x54,0x9A,0x48, /* ..x.R.<.T.H */
  0x5A,0x72,0x32,0x94,0xBF,0x43,0x4F,0x24,0x53,0x4B,0xEC, /* Zr2..CO$SK. */
  0x4B,0x99,0x0E,0x66,0x1F,0xFF,0xCE,0x7F,0xFF,0x3F,0x10, /* K..f.....?. */
  0xAE,0x82,0x62,0x71,0x34,0x18,0x59,0x9B,0x51,0xC7,0x59, /* ..bq4.Y.Q.Y */
  0xCE,0xEE,0xA5,0xFE,0x02,0xBB,0x30,0x91,0x49,0xD5,0x4B, /* ......0.I.K */
  0xF3,0xDC,0x9A,0xA9,0x57,0x8E,0x72,0x10,0xC0,0x5D,0x60, /* ....W.r..]` */
  0x67,0xFC,0x7D,0xD6,0xBA,0xDD,0xB3,0x8B,0x5A,0x0A,0x4C, /* g.}.....Z.L */
  0x41,0x4D,0x45,0x33,0x2E,0x39,0x33,0xAA,0xAA,0xAA,0xAA, /* AME3.93.... */
  0xAA,0xAA,0xAA,0xAA,0xAA,0x54,0x41,0x47,0x48,0x65,0x6C, /* .....TAGHel */
  0x6C,0x6F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, /* lo          */
  0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, /*             */
  0x20,0x20,0x20,0x20,0x20,0x50,0x61,0x6E,0x75,0x2D,0x4B, /*      Panu-K */
  0x72,0x69,0x73,0x74,0x69,0x61,0x6E,0x20,0x50,0x6F,0x69, /* ristian Poi */
  0x6B,0x73,0x61,0x6C,0x6F,0x20,0x20,0x20,0x20,0x20,0x20, /* ksalo       */
  0x20,0x20,0x56,0x53,0x44,0x53,0x50,0x20,0x54,0x65,0x73, /*   VSDSP Tes */
  0x74,0x69,0x6E,0x67,0x20,0x20,0x20,0x20,0x20,0x20,0x20, /* ting        */
  0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, /*             */
  0x20,0x20,0x20,0x4D,0x50,0x33,0x20,0x48,0x65,0x6C,0x6C, /*    MP3 Hell */
  0x6F,0x2C,0x20,0x57,0x6F,0x72,0x6C,0x64,0x21,0x20,0x20, /* o, World!   */
  0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, /*             */
  0x00, /* . */
};
 
 
VS1053 player;
 
 unsigned int modeValue;
 
 
void setup() {
  Serial.begin(9600);
  player.begin( 16, 17, 14, 15);
 
  
 
  delay(100);
 player.Mp3SetVolume(0x30, 0x30);
 player.Mp3SoftReset();
 
 
}
 
 
 
void loop() {
  
  unsigned char *p;
  unsigned int i;
  
  
  p = &HelloMP3[0]; // Point "p" to the beginning of array
    while (p <= &HelloMP3[sizeof(HelloMP3)-1]) {
      while (!digitalRead(player.dreqPin)) {
        // Release the SDI bus
        player.Mp3DeselectData();
        
        //do stuff
      }
     player.stream(*p++);
     
     
    }
    
    // End of file - send 2048 zeros before next file
 
  
   player.sendEndFillByte();
  
 
 
 

Interfacing the arduino with the VS1053b shield
This has been a great challenge for me and I hope that I would be able to solve the interfacing problem of the arduino (IDE v1.0) with the VS1053b based shield such as this one
 
OK lets start by getting the sine wave test working:
 
For this to work here is the pseudocode:
 
Hardware Reset
Delay 100ms
Send Dummy char to initialize SPI eg 0xFF
pull xCS High (control)
pull xDCS high (data)
Release from reset
Delay 100ms
 
// go into test mode 
pull xCS LOW (control)
Send SPI 0x02   WRITE
Send SPI 0x00   Register
Send SPI 0x08   MSB
Send SPI 0x20  LSB (Test mode)
 check Complete transfer
Pull xCS High (Control)
Check DREQ
 
//start sine wave
pul xDCS low
Send 0x53 then 0xef then 0x6e 0x44 0x00 0x00 0x00 0x00
check complete transfer
put xDCS high
 
Delay 
 
//stop sine test 
pull xDCS LOW
Send 0x45, 0x78, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00
Transfer complete
pull xDCS HIGH 
 
etc
 
 
Here is the working example using my class
#include <SPI.h>
#include "VS1053.h"
 
 
VS1053 player;
 
 unsigned int modeValue;
 
 
void setup() {
  Serial.begin(9600);
  player.begin( 16, 17, 14, 15);
 
  delay(100);
 
 
}
 
 
 
void loop() {
  player.hardReset();
  player.testMode(); 
  player.sineWaveStart();
  delay(3000);
  player.sineWaveStop();
  delay(3000);
 

Connecting a PICAXE OLED LCD to arduino
I recently bought this LCD from picaxe.com (AXE133Y). I was impressed by its quality and price and most importantly, I thought I could use it with my arduino projects by sacrificing only 1 pin.
 
 Unfortunately this was not possible straight out of the box!
 
It seems that the 18M2 Picaxe  chip prefers serial communication using inverted signals! The arduino uses normal signals so without modifying the firmware it is not possible for these devices to talk.
 
Modifying the code was straight forward but uploading it was simply a nightmare as I did not have the picaxe programming cable which looked exactly like my ftdi TTL-232 cable. There are 2 important differences:
 
1) The picaxe cable uses inverted signals whereas the FTDI cable uses non-inverted ones. The problem can be solved by using this program [use instructions here]

2) The wiring of the two cables is different
 
           [ ] Tip
           [ ] Ring
           |  |
           |  | Shield
          [   ]
Picaxe Cable
FTDI cable
Tip
Shield
Shield
Ring
Ring
Tip

Finally here is the code I used for the firmware (all credit to www.picaxe.com
 
; AXE133 Serial LCD/OLED using PICAXE-18M2; Emulates basic serial operation of the popular AXE033 module
; CPS, May 2011
; This is an open source firmware
; This code has been modified by 5B4WN
; December 9, 2011
; All credits to www.picaxe.com


; Supported Commands
; 0-7, 8-15    CGRAM characters
; 16-252    normal ASCII characters, according to selected character map table
; 253, X    display 16 character pre-saved message from EEPROM memory, X can be 0-15
; 254, X    LCD command, X can be 0 to 255
; 255, X    control outputs C.2, C.1, C.0 (via lower 3 bits of X)
;        So, if using a backlit LCD with the active low transistor driver
;        on output C.2, then 255,%000 switches backlight on and 255,%100 switches off

#picaxe 18M2

#define use_welcome    ; display the welcome message upon power up
#define use_OLED        ; enable this line for Winstar OLED modules

symbol line_length = 16    ; change to 20 for displays with 20 character lines

symbol baud = T4800_16    ; Serial baud rate 4800,N,8,1. Note main program //modified by 5B4WN runs at 16MHz

symbol spare0     = C.0 ; spare output 0
symbol spare1     = C.1 ; spare output 1
symbol spare2     = C.2 ; spare output 2 (or optional backlight)
symbol backlight     = C.2 ; optional backlight control for backlit LCDs, active low
symbol RX        = C.5    ; serial receive pin
symbol enable     = C.6    ; LCD enable
symbol rs         = C.7    ; LCD RS
; LCD data pins are on B.0 to B.7

; Store the 16 character user defined messages in EEPROM data memory
; First two messages are optionally used as welcome message

; If using a display with 20 characters you will need to edit
; the start addresses to be multiples of 20 (currently at 16)
; and add 4 characters to each message.
; Please remember 4 line displays always use the strange 1-3-2-4 layout.

;--#ifdef use_OLED       
EEPROM $00, ("  Serial OLED   ")     ; store msg in the EEPROM memory
;--#else
;--EEPROM $00, ("   Serial LCD   ")     ; store msg in the EEPROM memory
;--#endif
EEPROM $10, (" www.5b4wn.com ")     ; store msg in the EEPROM memory

EEPROM $20, ("This is msg 2   ")     ; store msg in the EEPROM memory
EEPROM $30, ("This is msg 3   ")     ; store msg in the EEPROM memory
EEPROM $40, ("This is msg 4   ")     ; store msg in the EEPROM memory
EEPROM $50, ("This is msg 5   ")     ; store msg in the EEPROM memory
EEPROM $60, ("This is msg 6   ")     ; store msg in the EEPROM memory
EEPROM $70, ("This is msg 7   ")     ; store msg in the EEPROM memory
EEPROM $80, ("This is msg 8   ")     ; store msg in the EEPROM memory
EEPROM $90, ("This is msg 9   ")     ; store msg in the EEPROM memory
EEPROM $A0, ("This is msg 10  ")     ; store msg in the EEPROM memory
EEPROM $B0, ("This is msg 11  ")     ; store msg in the EEPROM memory
EEPROM $C0, ("This is msg 12  ")     ; store msg in the EEPROM memory
EEPROM $D0, ("This is msg 13  ")     ; store msg in the EEPROM memory
EEPROM $E0, ("This is msg 14  ")     ; store msg in the EEPROM memory
EEPROM $F0, ("This is msg 15  ")     ; store msg in the EEPROM memory

;initialise LCD
init:
    gosub LCD_init         ; initialise LCD

; display welcome message if desired
;--#ifdef use_welcome   
    let b1 = 0            ; message 0 on top line
    gosub msg            ; do it

    low rs            ; command mode
    let pinsB = 192        ; move to line 2, instruction 192
    pulsout enable,1      ; pulse the enable pin to send data.
    high rs            ; character mode again
   
    let b1 = 1            ; message 1 on bottom line
    gosub msg            ; do it
;--#endif       
       
; main program loop, runs at 16MHz

main:

    serin RX,baud,b1            ; wait for the next byte

    ; NB keep character mode test as first item in this list to optimise speed
    if b1 < 253 then
        let pinsB = b1         ; output the data
        pulsout enable,1      ; pulse the enable pin to send data.
        goto main            ; quickly loop back to top
    else if b1 = 254 then
        low rs                  ; change to command mode for next character
        serin RX,baud,b1        ; wait for the command byte
        let pinsB = b1         ; output the data
        pulsout enable,1      ; pulse the enable pin to send data.
        high rs            ; back to character mode
        goto main            ; quickly loop back to top
    else if b1 = 253 then
        serin RX,baud,b1        ; wait for the next byte
        gosub msg            ; do the 16 character message
        goto main            ; back to top
    else ; must be 255
        serin RX,baud,b1        ; wait for the next byte
        let pinsC = b1 & %00000111 | %10000000
                        ; output the data on C.0 to C.1, keep RS high
        goto main            ; back to top
    end if


; power on LCD initialisation sub routine
LCD_init:
    let dirsC = %11000111    ; PortC 0,1,2,6,7 all outputs
    let dirsB = %11111111    ; PortB all outputs
   
   
   
;--#ifdef use_OLED
    ; Winstar OLED Module Initialisation
    ; according to WS0010 datasheet (8 bit mode)

    pause 500             ; Power stabilistation = 500ms

    ; Function set - select only one of these 4 character table modes
    ;let pinsB = %00111000     ; 8 bit, 2 line, 5x8 , English_Japanese table
    let pinsB = %00111001     ; 8 bit, 2 line, 5x8 , Western_European table1
    ;let pinsB = %00111010     ; 8 bit, 2 line, 5x8 , English_Russian  table
    ;let pinsB = %00111011     ; 8 bit, 2 line, 5x8 , Western_European table2
   
    pulsout enable,1      ;
       
    let pinsB = %00001100    ; Display on, no cursor, no blink
    pulsout enable,1    

    let pinsB = %00000001     ; Display Clear
    pulsout enable,1
    pause 7            ; Allow 6.2ms to clear display

    setfreq m16            ; now change to 16Mhz

    let pinsB = %00000010     ; Return Home
    pulsout enable,1

    let pinsB = %00000110     ; Entry Mode, ID=1, SH=0
    pulsout enable, 1



   
    high rs            ; Leave in character mode
    return


; display message from EEPROM sub routine
; message number 0-15 must be in b1 when called
; uses (alters) b1, b2, b3, b4
msg:
    let b2 = b1 & %00001111 * line_length
                        ; EEPROM start address is 0 to 15 multiplied by 16
    let b3 = b2 + line_length - 1 ; end address is start address + (line_length - 1)
    for b4 = b2 to b3            ; for 16 times
        read b4,b1            ; read next character from EEPROM data memory into b1
        let pinsB = b1         ; output the data
        pulsout enable,1      ; pulse the enable pin to send data.
    next b4                ; next loop
    return
   
 


To talk from arduino you can send the following commands
 
  • Clear screen as per manual is 254 followed by 1:
    • Serial.begin(4800);
    • Serial.write(254);
    • delay(10);
    • Serial.write(1);
    • Serial.print("hello World");
    • delay(10);

etc etc
 
 

A morse decoder for arduino
An algorithm for decoding Morse code with arduino, some inspiration from this article
 
From wikipedia:
The perfect morse code needs:
  1. short mark, dot or 'dit' () 'dot duration' is one unit long
  2. longer mark, dash or 'dah' () three units long
  3. inter-element gap between the dots and dashes within a character one dot duration or one unit long
  4. short gap (between letters) three units long
  5. medium gap (between words) seven units long

The real morse code has a dot:dash ratio of 2.5:1 to 3.5:1

Firstly, we need to determine this ratio:
If the inter-element gap length is denoted as Tm and dot as Td:
Use the first ten time lengths to calculate Tm and Td
 
High Level Time=H_TIME [ie not pressing]
Low Level Time=L_TIME [ie key pressing]
blank a dot/dash array
R=H_TIME[n]/Tm
If (R with 0.5 and 1.5) {
      S=L_TIME[n-1]/Td
      if (S within 2.5 and 3.5) {
             dash
      } else {
             dot
      }  
advance to next element in dot/dash array


} else  if R (within 2.5-3.5) {
           we have a letter space hence decode array
}
 
 
Another algorithm obtained from here can be summarised in this diagram

 
 

Controlling the MCP4231 Digital Pot with the arduino
Using the datasheet here is how to control the MCP4231
 
129 steps (0-128)
10K

For arduino Mega:
use
int ss1 = 53;
int clk = 52;
int mosi = 51; 
 
 
//controlling MCP4231  10K
// 1-CS               14-+5V
// 2-SCK              13-NC
// 3-SI               12-+5V
// 4-GND              11-+5V
// 5- POT0 A          10-POT1 A
// 6- POT0 Wiper       9-POT1 Wiper
// 7- POT0 B           8-POT1 B

int ss1 = 2;
int clk = 4;
int mosi = 3;
int ledPin=13;

// Variables and bytes
byte pot0 = B00010000; // write to pot 0  pins 5 and 6
byte pot1 = 0x0; // write to pot 1 pins 9 and 10

byte nil=0;

int resistance;
String serialCommand;

void setup()
{
  Serial.begin( 9600 );

  pinMode( ss1, OUTPUT );
  pinMode( clk, OUTPUT );
  pinMode( mosi, OUTPUT );

  pinMode( ledPin, OUTPUT );

  digitalWrite( ss1, HIGH );
  digitalWrite( clk, HIGH );

  Serial.println( "Ready. value; eg OHM:1000; =1K Ohm" );
  writeValue(pot1, 0);
}

void loop()
{
  if (Serial.available()>0) {

    byte buf=Serial.read();
    serialCommand +=String(buf);

    if (serialCommand.length()>20) {
      serialCommand=""; //avoid too long strings
    }

    if (buf==59) {

      //; received
      if (serialCommand.startsWith("OHM:")) {
        int n;
        char carray[6];
        String newstep=serialCommand.substring(serialCommand.indexOf(":")+1, serialCommand.length()-1);  
        newstep.toCharArray(carray, sizeof(carray));
        resistance = atoi(carray);
        if (resistance<10001) {
          n=map(resistance,0,10000,0,128);

          writeValue(pot0, n);
          Serial.println(resistance);
          Serial.println(n);
        }

      }
      serialCommand="";
    }
  }
}




void writeValue(int pot, int value) {
  digitalWrite( ss1, LOW );
  spi_transfer(pot);
  spi_transfer(value);
  digitalWrite( ss1, HIGH );

}





void spi_transfer( byte data )
{
  int i;

  digitalWrite( clk, LOW );

  for( i=1; i<=8; ++i )
  {
    if( data > 127 ) {
      digitalWrite( mosi, HIGH );
    }
    else {
      digitalWrite( mosi, LOW );
    }

    digitalWrite( clk, HIGH );
    data = data << 1;
    digitalWrite( clk, LOW );
  }
}

 
 
 
 

SO2RDuino - A USB SO2R Box by K1XM
K1XM has just published details of how to build an SO2R box using the arduino platform in NCJ.
 
Some of the features are:
  • switches headphones, microphone, CW keyer and PTT (from the computer or a footswitch)
  • uses relays for headphone and microphone switching
  • communicates through, and is powered by, a USB port
  • includes override switches for transmit and receive and LEDs to display status
  • incorporates a BLEND control that blends left and right channels in stereo mode
  • provides four-bit outputs, with band information for each radio. The outputs are compatible with Array Solutions, Top-Ten, Unified Microsystems or similar band decoders.
  • includes a "latch" mode. If the computer transmits (i.e., sets PTT), the headphones will be connected in mono to the non-transmitting radio, reverting to normal operation when the radio stops transmitting.
  • can be set so it will not go into stereo - useful for people who have a hearing issue in one ear.
  • is compatible with N1MM Logger, WriteLog, Win-Test and similar logging programs

  • The full article can be found here

    A YAESU band decoder converter for use with ICOM rigs
    Icom rigs have their own unique way of providing  information to external rigs based on the current band. This information is provided on a single pin on the ACC-2 socket by varying the voltage from 0-8V (see figure below).
     
     
     
     
    Most peripheral equipment use the ubiquitous YAESU band data method as follows
     
     
    This project uses an arduino to read the voltage from the ACC2 pin, determines the band and then converts it to a YAESU band data to use with the many peripherals that support the latter. Read more here.