IC-7410の制御をhttpで(8)

あなたはウォーターフォール上のトレースをクリックすることにより、その周波数に同調することができます。

index.html

var cwmarker1 = Math.floor(  cwpitch        / (32000 / 4096) );
var cwmarker2 = Math.floor( (cwpitch - 100) / (32000 / 4096) );
var cwmarker3 = Math.floor( (cwpitch + 100) / (32000 / 4096) );

function onClick(e) {
  var rect = e.target.getBoundingClientRect();
  var mx   = e.clientX - rect.left;
  var my   = e.clientY - rect.top;
  socket.emit('message7', mx);
}
canvas1.addEventListener('click', onClick, false);

index.js

  socket.on('message7', function(mx) {
    var newfreq = freqHz - (32000/4096 * mx - cwpitch);
    setfreq(newfreq);
  });

もちろん、新しい周波数を計算するには、自分がどちらのサイドバンドを聴いているのかを意識する必要があります。

IC-7410の制御をhttpで(7)

リモートにあるIC-7410のVFO周波数を、ブラウザのボタンをクリックすることで変更できます。

index.js

const bufa = new Buffer('fefe80e017', 'hex');              // preamble
const bufz = new Buffer('fd', 'hex');                      // postamble
const buf1 = new Buffer('fefe80e0174351fd', 'hex');        // CQ
const buf2 = new Buffer('fefe80e01751525a3ffd', 'hex');    // QRZ?
const buf3 = new Buffer('fefe80e003fd', 'hex');            // read freq
var buf4   = new Buffer('fefe80e0050000000000fd', 'hex');  // send freq

var SerialPort = require('serialport');
var serial     = new SerialPort(
    '/dev/ttyUSB0',
    {baudrate : 19200, parser : SerialPort.parsers.byteDelimiter([ 0xfd ])});

var http  = require('http');
var fs    = require('fs');
var index = fs.readFileSync(__dirname + '/index.html');
var app   = http.createServer(function(req, res) {
                res.writeHead(200, {'Content-Type' : 'text/html'});
                res.end(index);
              })
              .listen(3000);

var io     = require('socket.io').listen(app);
var freqHz = 7026000;

var ndata   = 512;  // data[512] + 0x0a
var pos     = 0;
var myarray = new Array();

// -- water fall --

var count = 0;
process.stdin.on('readable', function() {
  var buf = process.stdin.read();
  if (buf !== null) {
    for (var i = 0; i < buf.length; i++) {
      if (buf[i] == 0x0a) {
        if (pos >= 512) {
          io.emit('waterfall', myarray);
        }
        pos = 0;
      } else {
        myarray[pos++] = buf[i];
      }
    }
  }
});

// -- serial for IC-7410 --

serial.on('open',
          function() { console.log('serial port /dev/ttyUSB0 is opened.'); });

var count2 = 0;
serial.on('data', function(data) {
  //    console.log('received data: ', data.length, data);
  if (!(data[0] == 0xfe & data[1] == 0xfe)) {
    console.log('------------- received serial data error');
    }
  if (data[2] == 0xe0 & data[3] == 0x80 & data[4] == 0x03) {
    var f10   = data[5] >> 4 & 0x0f;
    var f1    = data[5] & 0x0f;
    var f1k   = data[6] >> 4 & 0x0f;
    var f100  = data[6] & 0x0f;
    var f100k = data[7] >> 4 & 0x0f;
    var f10k  = data[7] & 0x0f;
    var f10m  = data[8] >> 4 & 0x0f;
    var f1m   = data[8] & 0x0f;
    var freq  = f10m.toString() + f1m.toString() + "," + f100k.toString() +
               f10k.toString() + f1k.toString() + "." + f100.toString() +
               f10.toString() + f1 + " kHz";
    freqHz = f10m * 10000000 + f1m * 1000000 + f100k * 100000 + f10k * 10000 +
             f1k * 1000 + f100 * 100 + f10 * 10 + f1;
    //        console.log('count2 = ', count2++, 'freq: ' + freq, freqHz);
    io.emit('freqmsg', 'VFO A: ' + freq);
  }

});

serial
    .on('error', function(err) { console.log('Error: ', err.message); })

    // -- set frequency --

    function setfreq(f) {
      var f10m  = Math.floor(f / 10000000); f -= f10m  * 10000000;
      var f1m   = Math.floor(f / 1000000);  f -= f1m   * 1000000;
      var f100k = Math.floor(f / 100000);   f -= f100k * 100000;
      var f10k  = Math.floor(f / 10000);    f -= f10k  * 10000;
      var f1k   = Math.floor(f / 1000);     f -= f1k   * 1000;
      var f100  = Math.floor(f / 100);      f -= f100  * 100;
      var f10   = Math.floor(f / 10);       f -= f10   * 10;
      var f1    = Math.floor(f / 1);

      var data = new Array(
          [ 0xfe, 0xfe, 0x80, 0xe0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd ]);
      buf4[5] = f10   << 4 | f1;
      buf4[6] = f1k   << 4 | f100;
      buf4[7] = f100k << 4 | f10k;
      buf4[8] = f10m  << 4 | f1m;
      buf4[9] = 0;
      serial.write(buf4);
    }

// -- socket --

io.on('connection', function(socket) {

  socket.on('message1', function() { serial.write(buf1); });
  socket.on('message2', function() { serial.write(buf2); });

  socket.on('message3', function() {
    var newfreq = freqHz + 1000;
    setfreq(newfreq);
  });

  socket.on('message4', function() {
    var newfreq = freqHz + 100;
    setfreq(newfreq);
  });

  socket.on('message5', function() {
    var newfreq = freqHz - 100;
    setfreq(newfreq);
  });

  socket.on('message6', function() {
    var newfreq = freqHz - 1000;
    setfreq(newfreq);
  });

  socket.on('your message', function(msg) {
    serial.write(bufa);
    serial.write(msg);
    serial.write(bufz);
    io.emit('your message', msg);
  });

});

// -- request freq --

function sendTime() {
  serial.write(buf3);
  // console.log('Freq asked..');
}

setInterval(sendTime, 100);

// -- EOF --

index.html

<!doctype html>
<html>
<head>

<style>
* { margin: 0; padding: 0; box - sizing : border - box; }
body { font: 13px Helvetica, Arial; }
form { background: # 000; padding: 3px; position: fixed; bottom: 0; width: 100 % ; }
form input { border: 0; padding: 10px; width: 80 % ; margin - right : .5 % ; }
form button { width: 15 % ; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages{list - style - type : none; margin : 0; padding : 0; }
#messages li{padding : 5px 10px; }
#messages li : nth - child(odd){background : #eee; }
#messages {margin - bottom : 40px }
#messages {font - size : 2em }
#btn1 {position : fixed; top : 10px; left :  10px; font - size : 2em }
#btn2 {position : fixed; top : 10px; left :  70px; font - size : 2em }
#btn3 {position : fixed; top : 10px; left : 150px; font - size : 2em; width : 30px }
#btn4 {position : fixed; top : 10px; left : 190px; font - size : 2em; width : 30px }
#btn5 {position : fixed; top : 10px; left : 230px; font - size : 2em; width : 30px }
#btn6 {position : fixed; top : 10px; left : 270px; font - size : 2em; width : 30px }
#frequency {position : fixed; top :  10px; left : 310px; font - size : 2em }
#mycanvas  {position : fixed; top :  60px; left :  10px; font - size : 2em }
#mycanvas2 {position : fixed; top : 600px; left :  10px; font - size : 2em }
</style>

<script>
  window.addEventListener("load", init);
  function init(){}
</script>
</head>

 <body>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>
    <script src='/socket.io/socket.io.js'></script>
    <script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>

    <button id="btn1"><font size="5">CQ</font></button>
    <button id="btn2"><font size="5">QRZ?</font></button>
    <button id="btn3"><font size="5">++</ font></button>
    <button id="btn4"><font size="5">+</font></button>
    <button id="btn5"><font size="5">-</font></button>
    <button id="btn6"><font size="5">--</font></button>

    <div id="frequency"></div>
    <div id="messages"></div>
    <form action="">
      <input id="m" autocomplete="off"/><button>Send</button>
    </form>
    <canvas id="mycanvas"  width="512" height="512" style="background:white;"></canvas>
    <canvas id="mycanvas2" width="512" height= "90" style="background:white;"></canvas>

<script>
var myarray = new Array();
var socket  = io();
var canvas;
var ctx;
var imgData;
var rgb = new Array(3);

var stage = new createjs.Stage("mycanvas2");
var t     = new createjs.Text("IC-7410", "26px serif", "DarkRed");
t.x       = 10;
t.y       = 10;
stage.addChild(t);
stage.update();

function colormap(charcode) {         // 0~9 or 0x30~0x39
  var tmp = (charcode - 0x30) * 0.1;  // 0.0~0.9
  var val;
  var r, g, b;
  if (tmp < 0.50) {
    r = 0.0;
  } else if (tmp > 0.75) {
    r = 1.0;
  } else {
    r = 4.0 * tmp - 2.0;
  }

  if (tmp < 0.25) {
    g = 4.0 * tmp;
  } else if (tmp > 0.75) {
    g = -4.0 * tmp + 4.0;
  } else {
    g = 1.0;
  }

  if (tmp < 0.25) {
    b = 1.0;
  } else if (tmp > 0.50) {
    b = 0.0;
  } else {
    b = -4.0 * tmp + 2.0;
  }

  rgb[1] = 255.0 * g;
  rgb[0] = 255.0 * r;
  rgb[2] = 255.0 * b;
}

function waterFall(myarray) {
  ctx.putImageData(imgData, 0, 1);
  imgData = ctx.getImageData(0, 0, 512, 512);
  for (j = 0; j < 512; j++) {
    colormap(myarray[j]);
    imgData.data[0 + j * 4] = rgb[0];
    imgData.data[1 + j * 4] = rgb[1];
    imgData.data[2 + j * 4] = rgb[2];
    imgData.data[3 + j * 4] = 255;
  }
}

canvas = document.getElementById('mycanvas');
ctx    = canvas.getContext('2d');

var mx, my;
function onClick(e) {
  var rect = e.target.getBoundingClientRect();
  mx       = e.clientX - rect.left;
  my       = e.clientY - rect.top;
  console.log('mouse clicked: ', mx, my);
}
canvas.addEventListener('click', onClick, false);

imgData = ctx.createImageData(512, 512);
for (i = 0; i < 512; i++) {
  for (j = 0; j < 512; j++) {
    imgData.data[0 + j * 4 + i * imgData.width * 4] = j % 256;
    imgData.data[1 + j * 4 + i * imgData.width * 4] = i % 256;
    imgData.data[2 + j * 4 + i * imgData.width * 4] = 128;
    imgData.data[3 + j * 4 + i * imgData.width * 4] = 255;
  }
}
ctx.putImageData(imgData, 0, 0);

var socket = io();

$('#btn1').click(function() { socket.emit('message1'); });
$('#btn2').click(function() { socket.emit('message2'); });
$('#btn3').click(function() { socket.emit('message3'); });
$('#btn4').click(function() { socket.emit('message4'); });
$('#btn5').click(function() { socket.emit('message5'); });
$('#btn6').click(function() { socket.emit('message6'); });

$('form').submit(function() {
  socket.emit('your message', $('#m').val());
  $('#m').val('');
  return false;
});

socket.on('your message', function(msg) {
  $('#messages').append($('<div>').text(msg));
  window.scrollTo(0, document.body.scrollHeight);
});

socket.on('waterfall', function(data) { waterFall(data); });

socket.on('freqmsg', function(msg) {
  t.text = msg;
  stage.update();
  document.getElementById("frequency").innerHTML = msg;
});

</script>

</body>
</html>

IC-7410の制御をhttpで(6)

これは本物のウォーターフォールです。

ところで、もしあなたがgccで、undefined reference to ‘alloca’というエラーメッセージを得るようであれば、以下の行が役に立つかも知れません。

#include <alloca.h>

もし、あなたが”stderr”ではなくて”stdout”を使うのであれば、あなたはファイルバッファリングのモードを指定する必要があるかも知れません。

% sprig_audio_only /dev/ttyUSB0 hw:2,0 |& node index.js
% sprig_audio_only /dev/ttyUSB0 hw:2,0 |  node index.js

sprig_audio_only.c

#include <stdio.h>
int main () {
 setvbuf(stdout, NULL, _IOLBF, 0); // line buffering mode
//
 for(int i=0;i<512<i++) {
  fprintf(stdout, "%1d", audio_signal_ffted[i]);
 }
 fprintf(stdout,"\n");
 fflush(stdout); // this will also do with full buffering mode
//
}

IC-7410の制御をhttpで(5)

それぞれのパーツを一緒にすると、こんな感じになります。ここで、ウォーターフォールのデータは、計算機で生成されたものであることに注意して下さい。

index.js

// file name = index20.js, reads index20.html

const bufa = new Buffer('fefe80e017'          , 'hex'); // preamble
const bufz = new Buffer('fd'                  , 'hex'); // postamble
const buf1 = new Buffer('fefe80e0174351fd'    , 'hex'); // CQ
const buf2 = new Buffer('fefe80e01751525a3ffd', 'hex'); // QRZ?
const buf3 = new Buffer('fefe80e003fd'        , 'hex'); // read freq

var SerialPort = require('serialport');
var serial = new SerialPort('/dev/ttyUSB0',{
    baudrate: 19200,
    parser: SerialPort.parsers.byteDelimiter([0xfd])
});

var http  = require('http');
var fs    = require('fs');
var index = fs.readFileSync(__dirname + '/index20.html');
var app = http.createServer(function(req, res) {
                res.writeHead(200, {'Content-Type' : 'text/html'});
                res.end(index);
              })
              .listen(3000);

var io = require('socket.io').listen(app);

var ndata   = 512;  // data[512] + 0x0a
var pos     = 0;
var myarray = new Array();

// -- water fall --

process.stdin.on('readable', function() {
  var buf = process.stdin.read();
  if (buf !== null) {
    for (var i = 0; i < buf.length; i++) {
      if (buf[i] == 0x0a) {
        pos = 0;
        io.emit('waterfall', myarray);
      } else {
        myarray[pos++] = buf[i];
      }
    }
  }
});

// -- serial for IC-7410 --

serial.on('open',function(){
    console.log('serial port /dev/ttyUSB0 is opened.');
});

serial.on('data',function(data){
    console.log('received data: ', data.length, data);
    if ( !(data[0] == 0xfe & data[1] == 0xfe) ) {
      console.log('** received serial data error **');
    }
    if (data[2] == 0xe0 & data[3] == 0x80 & data[4] == 0x03) {
        var f10   = data[5]>>4 & 0x0f;
        var f1    = data[5]    & 0x0f;
        var f1k   = data[6]>>4 & 0x0f;
        var f100  = data[6]    & 0x0f;
        var f100k = data[7]>>4 & 0x0f;
        var f10k  = data[7]    & 0x0f;
        var f10m  = data[8]>>4 & 0x0f;
        var f1m   = data[8]    & 0x0f;
        var freq  =  f10m.toString()+ f1m.toString()+","
                   +f100k.toString()+f10k.toString()+f1k.toString()+"."
                   + f100.toString()+ f10.toString()+f1+" kHz";
        console.log('freq: ' + freq);
        io.emit('freqmsg', 'VFO A: ' + freq);
    }

});

serial.on('error', function(err) {
  console.log('Error: ', err.message);
})

// -- socket --

io.on('connection', function(socket){

    socket.on('message1', function(){
    serial.write(buf1);
  });

    socket.on('message2', function(){
    serial.write(buf2);
  });

  socket.on('your message', function(msg){
    serial.write(bufa);
    serial.write(msg);
    serial.write(bufz);
    io.emit('your message', msg);
  });

});

// -- request freq --

function sendTime() {
    serial.write(buf3);
}

setInterval(sendTime, 100);

// -- EOF --

IC-7410の制御をhttpで(4)

カラーマッピングと、ソースコードの一部を修正しました。

index.js

var http  = require('http');
var fs    = require('fs');
var index = fs.readFileSync(__dirname + '/index.html');

var app = http.createServer(function(req, res) {
                res.writeHead(200, {'Content-Type' : 'text/html'});
                res.end(index);
              })
              .listen(3000);

var io = require('socket.io').listen(app);

var ndata   = 512;  // data[512] + 0x0a
var pos     = 0;
var myarray = new Array();

process.stdin.on('readable', function() {
  var buf = process.stdin.read();
  if (buf !== null) {
    for (var i = 0; i < buf.length; i++) {
      if (buf[i] == 0x0a) {
        pos = 0;
        io.emit('waterfall', myarray);
      } else {
        myarray[pos++] = buf[i];
      }
    }
  }
});

process.stdin.on('end', function() {
});

index.html

<!doctype html>
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>

<script>
var myarray = new Array();
var socket  = io();
var canvas;
var ctx;
var imgData;

window.addEventListener("load", init);

function init() {
  canvas = document.getElementById('myCanvas');
  ctx    = canvas.getContext('2d');

  imgData = ctx.createImageData(512, 512);
  for (i = 0; i < 512; i++) {
    for (j = 0; j < 512; j++) {
      imgData.data[0 + j * 4 + i * imgData.width * 4] = j % 256;
      imgData.data[1 + j * 4 + i * imgData.width * 4] = i % 256;
      imgData.data[2 + j * 4 + i * imgData.width * 4] = 128;
      imgData.data[3 + j * 4 + i * imgData.width * 4] = 255;
    }
  }
  ctx.putImageData(imgData, 0, 0);
}

function waterFall(myarray) {
  ctx.putImageData(imgData, 0, 1);
  imgData = ctx.getImageData(0, 0, 512, 512);
  for (j = 0; j < 512; j++) {
    var tmp                 = ((myarray[j] - 48) * 25 % 256) / 256.0;
    imgData.data[0 + j * 4] = colormap_r(tmp);
    imgData.data[1 + j * 4] = colormap_g(tmp);
    imgData.data[2 + j * 4] = colormap_b(tmp);
    imgData.data[3 + j * 4] = 255;
  }
}

socket.on('waterfall', function(data) { waterFall(data); });

function colormap_r(tmp) {
  var val;
  if (tmp < 0.50) {
    val = 0.0;
  } else if (tmp > 0.75) {
    val = 1.0;
  } else {
    val = 4.0 * tmp - 2.0;
  }
  return 255.0 * val;
}

function colormap_g(tmp) {
  var val;
  if (tmp < 0.25) {
    val = 4.0 * tmp;
  } else if (tmp > 0.75) {
    val = -4.0 * tmp + 4.0;
  } else {
    val = 1.0;
  }
  return 255.0 * val;
}

function colormap_b(tmp) {
  var val;
  if (tmp < 0.25) {
    val = 1.0;
  } else if (tmp > 0.50) {
    val = 0.0;
  } else {
    val = -4.0 * tmp + 2.0;
  }
  return 255.0 * val;
}

</script>
</head>

<body>
    <canvas id="myCanvas" width="512" height="512" style="background:white;"></canvas>
</body>
</html>

IC-7410の制御をhttpで(3)

右側の窓はsprigです。Cプログラムで、IC-7410がUSB接続されたリモートホストの上で走ります。

左側の窓はブラウザで、同じウォーターフォール画像を表示しています。

これは、ローカルホスト上の4つの異なるブラウザです。それらは、Chrome, Firefox, Opera, Safariですが、どれがどれだか分かりますか?

Remote host:

% sprig /dev/ttyUSB0 HW:2,0 |& node index.js

sprig.c

  for(int j=0;j<WATERFALL_XSIZE;j++) {
       double tmp  =  audio_signal_ffted[j];
       int    iii  = 10.0*tmp; fprintf(stderr, "%1d", iii);
       *p++ = *q++ = colormap_r(tmp);
       *p++ = *q++ = colormap_g(tmp);
       *p++ = *q++ = colormap_b(tmp);
  }

index.js

var http  = require('http');
var fs    = require('fs');
var index = fs.readFileSync(__dirname + '/index.html');
var count = 0;

var app = http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type' : 'text/html'});
  res.end(index);
});

var io = require('socket.io').listen(app);
app.listen(3000);

var ndata = 512;
var pos   = 0;
var myarray = new Array(ndata);

process.stdin.on('readable', function() {
  var buf = process.stdin.read();
  for (var i = 0; i < buf.length; i++) {
    myarray[pos++] = buf[i];
    if(pos == ndata) {
      pos = 0;
      console.log(myarray[0], myarray[1], myarray[2]);
      io.emit('time', {buffer : myarray});
    }
  }
});

index.html

<!doctype html>
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>
<script>
var myarray = Array();
var socket  = io();
var canvas;
var ctx;
var imgData;
function init() {
  canvas = document.getElementById('myCanvas');
  ctx    = canvas.getContext('2d');

    imgData = ctx.createImageData(512, 512);
    for (i = 0; i < 512; i++) {
      for (j = 0; j < 512; j++) {
        imgData.data[0 + j * 4 + i * imgData.width * 4] = j % 256;
        imgData.data[1 + j * 4 + i * imgData.width * 4] = i % 256;
        imgData.data[2 + j * 4 + i * imgData.width * 4] = 0;
        imgData.data[3 + j * 4 + i * imgData.width * 4] = 255;
      }
    }
    ctx.putImageData(imgData, 0, 0);
}

function emitParticles(myarray) {
  ctx.putImageData(imgData, 0, 1);
  imgData = ctx.getImageData(0, 0, 512, 512);
  for (j = 0; j < 512; j++) {
    var index = (myarray[j] - 48) * 32 % 256;
    imgData.data[0 + j * 4] = index;
    imgData.data[1 + j * 4] = 256 - index;
    imgData.data[2 + j * 4] = 0;
    imgData.data[3 + j * 4] = 255;
  }
}

socket.on('time', function(data) {
  myarray = data.buffer;
  emitParticles(myarray);
console.log(count);
});
</script>
</head>

<body>
    <canvas id="myCanvas" width="512" height="512" style="background:white;"></canvas>
    <p id='messages'></p>
</body>
</html>

WaterfallをcreateImageDataで(2)

getImageDataとputImageDataとを適当なオフセットで用いることにより、imgDataの中のデータをあからさまにシフトする必要が無くなります。

index.html

<!doctype html>
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>
<script>
var nxdata  = 32;
var nydata  = 32;
var myarray = Array(nxdata);
var mytable = Array(nxdata * nydata);
var socket  = io();
var canvas;
var ctx;
var imgData;

window.addEventListener("load", init);

function init() {
  canvas = document.getElementById('myCanvas');
  ctx    = canvas.getContext('2d');

    imgData = ctx.createImageData(512, 512);
    for (i = 0; i < 512; i++) {
      for (j = 0; j < 512; j++) {
        imgData.data[0 + j * 4 + i * imgData.width * 4] = j % 256;
        imgData.data[1 + j * 4 + i * imgData.width * 4] = (255 - (i % 256));
        imgData.data[2 + j * 4 + i * imgData.width * 4] =
            ((i / 2 + j / 2) % 256);
        imgData.data[3 + j * 4 + i * imgData.width * 4] = 255;
      }
    }
    ctx.putImageData(imgData, 0, 0);
}

function emitParticles(myarray) {
  ctx.putImageData(imgData, 0, 1);
  imgData = ctx.getImageData(0, 0, 512, 512);
  for (j = 0; j < 512; j++) {
    imgData.data[0 + j * 4] = (myarray[(j>>4)%8] - 48) * 32 % 256;
    imgData.data[1 + j * 4] = j % 256;
    imgData.data[2 + j * 4] = 0;
    imgData.data[3 + j * 4] = 255;
  }
}

socket.on('time', function(data) {
  myarray = data.buffer;
  emitParticles(myarray);
});
</script>
</head>

<body>
    <canvas id="myCanvas" width="512" height="512" style="background:white;"></canvas>
    <p id='messages'></p>
</body>
</html>

WaterfallをcreateImageDataで

ウォーターフォール画像を描画するもう少し自然な方法は、createImageData, getImageData, putImageDataといったメソッドを使うことでしょうか。

index.html

<!doctype html>
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>
<script>
var nxdata  = 32;
var nydata  = 32;
var myarray = Array(nxdata);
var mytable = Array(nxdata * nydata);
var socket  = io();
var canvas;
var ctx;
var imgData;

window.addEventListener("load", init);

function init() {
  console.log('init..');
  canvas = document.getElementById('myCanvas');
  ctx    = canvas.getContext('2d');

  if (canvas.getContext && canvas.getContext('2d').createImageData) {
    imgData = ctx.createImageData(512, 512);
    for (i = 0; i < 512; i++) {
      for (j = 0; j < 512; j++) {
        imgData.data[0 + j * 4 + i * imgData.width * 4] = j % 256;
        imgData.data[1 + j * 4 + i * imgData.width * 4] = (255 - (i % 256));
        imgData.data[2 + j * 4 + i * imgData.width * 4] =
            ((i / 2 + j / 2) % 256);
        imgData.data[3 + j * 4 + i * imgData.width * 4] = 255;
      }
    }
    ctx.putImageData(imgData, 0, 0);
  }
}

var count  = 0;
var marker = 0;
function emitParticles(myarray) {
  count++;
  if (count % 128 == 0) {
    marker = 255;
    count  = 0;
  } else {
    marker = 0;
  }
  for (j = 0; j < 512; j++) {
    imgData.data[0 + j * 4 + (512 - 1) * imgData.width * 4] = marker;
    imgData.data[1 + j * 4 + (512 - 1) * imgData.width * 4] = 0;
    imgData.data[2 + j * 4 + (512 - 1) * imgData.width * 4] =
        (32 * myarray[(j >> 3) % 10]) % 256;
    imgData.data[3 + j * 4 + (512 - 1) * imgData.width * 4] = 255;
  }

  for (i = 0; i < 512 - 1; i++) {
    for (j = 0; j < 512; j++) {
      for (k = 0; k < 4; k++) {
        imgData.data[k + j * 4 + i * imgData.width * 4] =
            imgData.data[k + j * 4 + (i + 1) * imgData.width * 4];
      }
    }
  }

  ctx.putImageData(imgData, 0, 0);
}

socket.on('time', function(data) {
  myarray = data.buffer;
  emitParticles(myarray);
});
</script>
</head>

<body>
    <canvas id="myCanvas" width="512" height="512" style="background:white;">
    </canvas>
    <p id='messages'></p>
</body>
</html>

ウォーターフォールをパイプで

あなたの表示したい信号が、別のプロセスからパイプで与えられるとしましょう。

bash.sh

while :
 do
  echo "0.13456789"
  sleep 0.1
  echo "1234567890"
  sleep 0.1
  echo "2345678901"
  sleep 0.1
  echo "34567890.1"
  sleep 0.1
  echo "4567890.13"
  sleep 0.1
 done
% ./bash.sh | node index.js

index.js

var http  = require('http');
var fs    = require('fs');
var index = fs.readFileSync(__dirname + '/index12.html');
var count = 0;

var app = http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type' : 'text/html'});
  res.end(index);
});

var io = require('socket.io').listen(app);
app.listen(3000);

var ndata   = 10;
var myarray = new Array(ndata);

process.stdin.on('readable', function() {
  var buf = process.stdin.read();
  console.log(buf);
  for (var i = 0; i < ndata; i++) {
    myarray[i] = buf[i];
  }
  io.emit('time', {buffer : myarray});
});

index.html

<!doctype html>
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>
<script> 
var nxdata  = 32;
var nydata  = 32;                 
var myarray = Array(nxdata);      
var mytable = Array(nxdata * nydata);
var socket = io();
var count  = 0;

window.addEventListener("load", init);

function init() {
// anything you wish
}

function emitParticles(myarray) {
  for (var ix = 0; ix < nxdata; ix++) {
    mytable[ix] = myarray[ix % 10] - 48;
  }
  for (var iy = nydata - 1; iy > 0; iy--) {
    for (var ix = 0; ix < nxdata; ix++) {
      mytable[ix + nxdata * iy] = mytable[ix + nxdata * (iy - 1)];
    }
  }

  var canvas = document.getElementById('myCanvas');
  var ctx    = canvas.getContext('2d');
  for (var iy = 0; iy < nydata; iy++) {
    for (var ix = 0; ix < nxdata; ix++) {
      ctx.beginPath();
      var h         = (360 / 10) * mytable[ix + nxdata * iy] % 360;
      var hsl       = 'hsl(' + h.toString() + ', 100%, 50%)';
      ctx.fillStyle = hsl;
      ctx.arc(ix * (800 / nxdata), iy * (800 / nydata), 400 / nydata, 0,
              2 * Math.PI, true);
      ctx.fill();
    }
  }
}

socket.on('time', function(data) {
  myarray = data.buffer;
  emitParticles(myarray);
});
</script>
</head><body>
    <canvas id="myCanvas" width="800" height="800" style="background:white;">
    </canvas>
    <p id='messages'></p>
</body>
</html>

IC-7410の制御をhttpで(2)

VFO周波数は、リモートホストによって1秒間に数回読み出され、ブラウザにプッシュされます。

remote host % node index.js

index.js

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var port = process.env.PORT || 3000;
var SerialPort = require('serialport');
var serial = new SerialPort('/dev/ttyUSB0',{
    baudrate:19200
});

const bufa = new Buffer('fefe80e017'          , 'hex'); // preamble
const bufz = new Buffer('fd'                  , 'hex'); // postamble
const buf1 = new Buffer('fefe80e0174351fd'    , 'hex'); // CQ
const buf2 = new Buffer('fefe80e01751525a3ffd', 'hex'); // QRZ?
const buf3 = new Buffer('fefe80e003fd'        , 'hex'); // read freq

http.listen(3000,function(){
    console.log('now listening to the port 3000..');
});

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

serial.on('open',function(){
    console.log('serial port /dev/ttyUSB0 is opened.');
    serial.write(buf3);
});

serial.on('data',function(data){
    console.log('received data: ', data);
    if (data[3] == 0x80 &data[4] == 0x03) {
        console.log('received data: ', data[5], data[6], data[7], data[8]);
	var f10   = data[5]>>4 & 0x0f;
	var f1    = data[5]    & 0x0f;
	var f1k   = data[6]>>4 & 0x0f;
	var f100  = data[6]    & 0x0f;
	var f100k = data[7]>>4 & 0x0f;
	var f10k  = data[7]    & 0x0f;
	var f10m  = data[8]>>4 & 0x0f;
	var f1m   = data[8]    & 0x0f;
	var freq  = f10m.toString()+f1m.toString()+","+f100k.toString()+f10k.toString()+f1k.toString()+"."+f100.toString()+f10.toString()+f1+" kHz";
	console.log('freq: ' + freq);
        io.emit('recvmsg', 'VFO A: ' + freq);
    }
});

serial.on('error', function(err) {
  console.log('Error: ', err.message);
})

io.on('connection', function(socket){
    socket.on('message1', function(){
    serial.write(buf1);
  });
    socket.on('message2', function(){
    serial.write(buf2);
  });
  socket.on('your message', function(msg){
    serial.write(bufa);
    serial.write(msg);
    serial.write(bufz);
    io.emit('your message', msg);
  });
});

function sendTime() {
    serial.write(buf3);
}
setInterval(sendTime, 200);

index.html

<!doctype html>
<html>
  <head>
    <title>IC-7410 Rig Control</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 80%; margin-right: .5%; }
      form button { width: 15%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
      #messages { margin-bottom: 40px }
      #messages { font-size: 2em }
      #frequency { position: fixed; top: 10px; left: 200px; font-size: 2em }
    </style>
  </head>
  <body>
    <button id="btn1"><font size="5">CQ</font></button>
    <button id="btn2"><font size="5">QRZ?</font></button>
    <div id="frequency"></div>
    <div id="messages"></div>

    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>

    <script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>

    <script>
        var socket = io();
        $('#btn1').click(function(){
            socket.emit('message1');
        });
        $('#btn2').click(function(){
            socket.emit('message2');
        });
        socket.on('recvmsg',function(data){
            $('h1').text(data);
        });
    </script>

    <script>
      $(function () {
        var socket = io();
        $('form').submit(function(){
          socket.emit('your message', $('#m').val());
          $('#m').val('');
          return false;
        });
        socket.on('your message', function(msg){
          $('#messages').append($('<div>').text(msg));
          window.scrollTo(0, document.body.scrollHeight);
        });
        socket.on('recvmsg', function(msg){
	  document.getElementById("frequency").innerHTML = msg;
        });
      });
    </script>
  </body>
</html>