I recently set-up an audio stream of my father's HF rig at his house over the internet. (MMS://w5cqu.homeip.net:8000/hf) That was fairly easy using a Linux server and Ice-cast/DarkIce. But, I wanted to take it one step further and allow him to remotely control the frequency and mode of the rig using a web browser on a PC or mobile phone (specifically, iPhone). I have come up with the following solution that I will attempt to describe in case anyone would like to do this also.
Equipment:
Kenwood TS-570S
RS232 Cable
Audio cable
Ubuntu Linux server
I used the HamLib project’s rigctld utility to create a daemon to accept instructions for the HF rig. The website for this project is:
http://sourceforge.net/projects/hamlib/To launch the daemon, I created an init.d script to execute the following command upon boot: /usr/bin/rigctld -r /dev/ttyS0 -m 216 -s 9600 -T 127.0.0.1
Essentially, this connects the control daemon to COM1 on the computer, which is connected to the HF rig. The daemon listens only on the localhost.
I created a Perl CGI script that is called from a website I created to actually control the HF rig. It talks on to the rigctld daemon over a TCP/IP connection. (Code located below instructions)
I found a simple website template designed for the iPhone. It mimics the look and feel of iOS applications. I chose to use this as a base for my web application. It is called iSite and is available on the internet. I modified this template to control the HF rig using the Perl script I created. (HTML located below Perl code)
If anyone would like to stream from the server, direct FStream, VLC, or Windows Media Player to the following URL:
MMS://w5cqu.homeip.net:8000/hf
I hope someone finds this useful!
Chris, KC5HHQ
kc5hhq@gmail.comScreenshots:
FStream (iOS application) streaming the audio:
http://img13.imageshack.us/img13/7775/photo5rh.pngMain page of site:
http://img849.imageshack.us/img849/8439/photofk.pngGet frequency:
http://img269.imageshack.us/img269/2885/photo1ua.pngSet frequency:
http://img831.imageshack.us/img831/1020/photo4s.pngGet mode:
http://img20.imageshack.us/img20/2145/photo2f.png Set mode:
http://img10.imageshack.us/img10/2308/photo3p.png#### BEGIN Perl CGI Code ####
#!/usr/bin/perl -W
use CGI;
use Switch;
use IO::Socket;
use IO::Select;
my $cmd = new CGI->param('cmd');
#my $cmd = @ARGV[0];
my $val1 = new CGI->param('val1');
#my $val1 = @ARGV[1];
my $val2 = new CGI->param('val2');
#my $val2 = @ARGV[2];
if(!$cmd) {
print "Content-type: text/plain\n\nCommand or Value is Null. Halting.";
exit(0);
}
# Create a socket
my $socket = new IO::Socket::INET (
PeerAddr => '127.0.0.1',
PeerPort => '4532',
Proto => 'tcp',
);
if(!$socket) {
print "Content-type: text/plain\n\nCould not create socket. Halting.";
exit(0);
}
my $s = IO::Select->new();
$s->add($socket);
#$socket->autoflush(1);
my $results = '';
# Determine what command is being passed.
switch ($cmd) {
case "get_freq" {
getFreq();
}
case "set_freq" {
setFreq($val1);
}
case "set_mode" {
setMode($val1, 0);
}
case "get_mode" {
getMode();
}
case "dump_caps" {
$results = sendcommand($s,$socket,"+\\dump_caps\n", "Dump capabilities", '');
}
}
close($socket);
sub getMode {
my $results = sendcommand($s,$socket,"m\n", "Get mode", '');
sendResults("The current mode is: $results");
}
sub setMode {
my $mode = shift;
my $passBand = shift;
my $results = sendcommand($s,$socket,"M $mode $passBand\n", "Set mode", '');
sendResults("The mode has been changed to: $mode");
}
sub setFreq {
my $freq = shift;
my $results = sendcommand($s,$socket,"F $freq\n", "Set frequency", '');
sendRedirect();
}
sub getFreq {
my $results = sendcommand($s,$socket,"f\n", "Get frequency", '');
sendResults("The frequency is: $results");
}
sub sendResults {
my $results = shift;
print "Content-type: text/html\n\n";
my $returned = qq^
<html>
<head>
</head>
<body>
^;
$returned = $results;
# $returned .= qq^
# </body>
# </html>
# ^;
print $returned;
}
sub sendRedirect {
print "Content-type: text/html\n\n";
my $redirect = qq^
<html>
<head>
<meta http-equiv="Refresh" content="0;url=http://your.site.net/dir" />
</head>
</html>
^;
print $redirect;
}
sub sendcommand {
my $s = shift;
my $sock = shift;
my $cmd = shift;
my $desc = shift;
my $comment = shift;
my $res = '';
my $return = '';
my $retry = 1;
$sock->send($cmd);
#print $sock $cmd;
sleep 1;
while ($s->can_read(0)) {
$sock->sysread($result,1);
$return .= $result;
}
return $return;
}
#### END Perl CGI Code ####
#### BEGIN HTML ####
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"
http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml">
<head>
<title>Rig Control 0.1</title>
<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<style type="text/css" media="screen">@import "iphonenav.css";</style>
<script type="application/x-javascript" src="iphonenav.js"></script>
</head>
<body>
<h1 id="pageTitle"></h1>
<a id="homeButton" class="button" href="#settings">Settings</a>
<a class="button" href="#manualForm">Set Freq.</a>
<ul id="settings" title="Settings" selected="true">
<li><a href="#Frequency">Frequency</a></li>
<li><a href="#Mode">Mode</a></li>
</ul>
<ul id="Frequency" title="Frequency">
<li><a href="#setFreq">Set Frequency</a></li>
<li><a href="#getFreq">Get Frequency</a></li>
</ul>
<ul id="Mode" title="Mode">
<li><a href="#setMode">Set Mode</a></li>
<li><a href="#getMode">Get Mode</a></li>
</ul>
<div id="setMode" class="panel" title="Mode">
<li><a class="clickButton" href="#" onclick="click_setMode('LSB');">LSB</a></li>
<li><a class="clickButton" href="#USB" onclick="click_setMode('USB');">USB</a></li>
<li><a class="clickButton" href="#AM onclick="click_setMode('AM');"">AM</a></li>
<li><a class="clickButton" href="#FM" onclick="click_setMode('FM');">FM</a></li>
<li><a class="clickButton" href="#CW" onclick="click_setMode('CW');">CW</a></li>
<h2><div id="setModeText"></div></h2>
</div>
<div id="getFreq" class="panel" title="Frequency">
<a class="clickButton" href="#" onclick="click_getFreq();">Get Frequency</a>
<h2>
<div id="freqText"></div>
</h2>
</div>
<div id="getMode" class="panel" title="Mode">
<a class="clickButton" href="#" onclick="click_getMode();">Get Mode</a>
<h2>
<div id="modeText"></div>
</h2>
</div>
<div id="getMem" class="panel" title="Memory">
<a class="clickButton" href="#" onclick="click_getMemory();">Get Memory</a>
<h2>
<div id="memText"></div>
</h2>
</div> <div id="searchResults" class="panel" title="Search">
<h2>Search results go here...</h2>
</div>
<form id="manualForm" class="dialog" method="POST" action="/cgi-bin/ctl.pl?">
<fieldset>
<h1>Frequency Set</h1>
<a class="button toolButton goButton" href="#" onclick="submit_manualForm();">Set Freq.</a>
<input type="hidden" name="cmd" value="set_freq" />
<label>Frequency:</label>
<input type="text" name="val1" onkeypress="dokeypress(event, 'submit_manualForm')"/>
</fieldset>
</form>
<form id="setFreq" class="dialog" method="POST" action="/cgi-bin/ctl.pl?">
<fieldset>
<h1>Frequency Set</h1>
<a class="button toolButton goButton" href="#" onclick="submit_setFreq();">Set Freq.</a>
<input type="hidden" name="cmd" value="set_freq" />
<label>Frequency:</label>
<input type="text" name="val1" onkeypress="dokeypress(event, 'submit_setFreq')"/>
</fieldset>
</form>
<script language="javascript">
function submit_manualForm() {
document.forms["manualForm"].submit();
}
function submit_setFreq() {
document.forms["setFreq"].submit();
}
function dokeypress(e,functionName)
{
if (e.which == 13)
{
document.activeElement.blur();
eval(functionName + "();");
}
}
function click_getFreq() {
var req = getReq();
req.open("GET",'/cgi-bin/control_script.pl?cmd=get_freq', true);
req.onreadystatechange = function () {
document.getElementById('freqText').innerHTML = req.responseText;
}
req.send(null);
}
function click_setMode(val1) {
var req = getReq();
req.open("GET",'/cgi-bin/control_script.pl?cmd=set_mode&val1='+val1, true);
req.onreadystatechange = function () {
document.getElementById('setModeText').innerHTML = req.responseText;
}
req.send(null);
}
function click_getMode() {
var req = getReq();
req.open("GET",'/cgi-bin/control_script.pl?cmd=get_mode', true);
req.onreadystatechange = function () {
document.getElementById('modeText').innerHTML = req.responseText;
}
req.send(null);
}
function getReq(url) {
var req;
// Browser compatibility check
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
return req;
}
</script>
</body>
</html>
#### END HTML ####