/* * Icom serial CI-V to RF-Kit UDP (XML-formatted) frequency data conversion * Compiled for ESP8266 and loaded to NodeMCU board using AVRISP mkII programmer * * In addition to libraries named in #include directives, the BusIO.h library * must also be installed. * * LM Sept. 2022 - CC attribution - https://creativecommons.org/licenses/by/3.0/us/ * * * Rev.1 - Add KHZ_ONLY optional throttle * Rev.2 - Add VHF/UHF frequencies for IC-7100 * */ #include #include #include #include #include // ************ Conditional compile settings ************ #define TEST_MODE // Comment-out or delete for production use #define OLED // Comment-out if no OLED display #define UDP_OK // Comment-out to disable sending UDP packets // ************ Interface parameters section (Implementation-specific) ************ // WiFi access credentials #define WIFI_SSID "WiFi network name goes here" #define WIFI_PASS "WiFi password goes here" // Amplifier (or test server) network address and listening port #ifdef TEST_MODE IPAddress ampIP = {192,168,1,85}; // IPV4 address of test server (example--Substitute appropriate value) #else IPAddress ampIP = {192,168,1,163}; // IPV4 address of amplifier (example--Substitute appropriate value) #endif #define ampPort 12060 // Amplifier's UDP listening port (default is 12060) // Radio number that amplifier is configured to follow #define RadioNr 1 // Radio number - Which radio is sending UDP packet // Transceiver - Uncomment one of the following C-IV addresses for the transceiver being interfaced //const byte civ_address = 0x98; // IC-7610 const byte civ_address = 0x94; // IC-7300 //const byte civ_address = 0x88; // IC-7100 // General const boolean SEND_ALL = false; // If true, UDP message for each CI-V message, (cf KHZ_ONLY below) // else update periodically, as specified by the following - const unsigned long UDP_DELAY = 1000; // Milliseconds interval between periodic UDP messages // Default setting one second (1000 ms) const boolean KHZ_ONLY = SEND_ALL; // Send only when KHz changes (throttle) ... // If true overrides periodic as well as 'all'. // ********** End Interface parameters section (Implementation-specific) ********** // UDP - Instantiate WiFiUDP Udp; // Message buffers const int UDP_BUFFER_DIM = 256; char xmtBuffer[UDP_BUFFER_DIM]; char rcvBuffer[UDP_BUFFER_DIM]; #ifdef OLED // https://randomnerdtutorials.com/esp8266-0-96-inch-oled-display-with-arduino-ide/ #define DSPL_WIDTH 128 #define DSPL_HEIGHT 64 #define DSPL_RESET -1 // Instantiate display Adafruit_SSD1306 display(DSPL_WIDTH, DSPL_HEIGHT, &Wire, DSPL_RESET); // Color definitions (not used) #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define YELLOW 0xFFE0 #endif // Software serial // https://github.com/plerup/espsoftwareserial/ #define SS_TX 12 #define SS_RX 13 #define SS_BAUD 9600 // Set to the same as transceiver // Instantiate SoftwareSerial xcvr; // Transceiver serial interface // CI-V const int CIV_BUFFER_DIM = 80; char civBuffer[CIV_BUFFER_DIM]; int civNdx = 0; const byte EOC = 0xFD; // End of CIV message String sLastFreq = ""; String sLastKHz = ""; unsigned long lastUpdate = 0; // Time const unsigned long JIFFY = 200; const unsigned long ONESEC = 1000; const unsigned long TWOSEC = 2000; const unsigned long FIVESEC = 5000; // Application #define BAUD 115200 // USB Serial monitor (not software serial) // Pushbuttons #define SCRN_PB 14 // Toggle OLED screen display on/off #define TEST_PB 16 // Send test UDP packet (fixed frequency) boolean screen_on = true; // Toggle OLED screen on/off (screen-saving) // Takes effect after setup is complete // No effect if OLED is not defined void setup() { pinMode(SCRN_PB, INPUT); pinMode(TEST_PB, INPUT); Serial.begin(BAUD); delay(JIFFY); Serial.println(); // Initialize WiFi WiFi.begin(WIFI_SSID, WIFI_PASS); Serial.print("Connecting to "); Serial.print(WIFI_SSID); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(JIFFY); Serial.print("."); } Serial.println(); Serial.print("Connected! IP address: "); Serial.println(WiFi.localIP()); // Initialize software serial (transceiver interface) xcvr.begin(SS_BAUD, SWSERIAL_8N1, SS_RX, SS_TX, false); if (!xcvr) { Serial.println("Software serial initialization failed."); while(true) ; // Do not proceed } Serial.println(F("Software serial initialized.")); // Initialize OLED (if present) #ifdef OLED if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F("OLED initialization failed")); while(true) ; // Do not proceed } Serial.println ("OLED initialized."); display.display(); // Adafruit logo delay(TWOSEC); myClearDisplay(); //testdrawchar(); //delay(TWOSEC); //myClearDisplay(); displaySplash(); delay(TWOSEC); displayHelp(); delay(TWOSEC); delay(TWOSEC); myClearDisplay(); #endif // OLED Serial.println ("Setup complete"); } void loop() { civListen(); #ifdef UDP_OK if (SEND_ALL) { ; // UDP sender called from processCIVcommand() } else { // Periodic update if ((millis() > (lastUpdate + UDP_DELAY)) && (sLastFreq.length() > 0)) { sendFrequency(sLastFreq); lastUpdate = millis(); } } #endif #ifdef TEST_MODE if (testBtnPress()) { #ifdef UDP_OK sendTestFrequency(); Serial.println("Test frequency sent."); #endif // UDP_OK #ifndef UDP_OK // not OK Serial.println("Test frequency not sent."); #endif // UDP not OK } #endif // TEST_MODE if (oledBtnPress()) { screen_on = !screen_on; // Toggle OLED screen on/off if (!screen_on) myClearDisplay(); } } void flushXmtBuffer() { for (int i=0; i 0) { // Rev.2 for IC7100 VHF/UHF s.concat(String(hundreds)); s.concat(String(tens)); } else if (tens > 0) // No leading zeros s.concat(String(tens)); s.concat(String(rightDigit(xcvrFreq[3]))); s.concat(String(leftDigit(xcvrFreq[2]))); s.concat(String(rightDigit(xcvrFreq[2]))); s.concat(String(leftDigit(xcvrFreq[1]))); s.concat(String(rightDigit(xcvrFreq[1]))); s.concat(String(leftDigit(xcvrFreq[0]))); // Omit 1's digit - Not used by RF-Kit Serial.println(); Serial.print("Freq: "); Serial.println(s); // To do: Validate that s is a valid frequency and in an amplifier-supported band. if (SEND_ALL) { sendFrequency(s); lastUpdate = millis(); } else { sLastFreq = s; } } int leftDigit(byte b) { return b / 16; } int rightDigit(byte b) { return b % 16; } boolean isKHzNew(String fTens) { String fKHz = ""; fKHz.concat(fTens.substring(0,fTens.length()-2)); if (fKHz == sLastKHz) return false; sLastFreq = fTens; sLastKHz = fKHz; return true; } void sendFrequency(String f) { // RF Kit amplifier frequencies are specified in multiples of 10 Hz // For example 14.06 MHz would be 1406000 if (KHZ_ONLY && !isKHzNew(f)) return; flushXmtBuffer(); Serial.println("Send frequency ..."); Serial.println(); const char Q = 34; String s = ""); s.concat(""); s.concat(""); s.concat(RadioNr); s.concat(""); s.concat(""); s.concat(f); s.concat(""); s.concat(""); for (int i=0; i