(BLE)WindowsでKonashiのアナログ入力を読む

ようやくできたよ・・・。
Windows 10のノートPCで動作確認。他は知らない。
ハマったポイントは、
characteristic.ReadValueAsync()メソッドが、デフォルトでキャッシュした値を返していたこと。
BluetoothCacheMode enumeration - Windows app development
にあるように、引数をunchachedにしたら、ちゃんと読めた。

以下ソース。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using System.Threading;
using System.Threading.Tasks;
using Windows.UI.Popups;


namespace BreathMonitorKonashi {

    public sealed partial class MainPage : Page {

        private const string KONASHI_SERVICE = "229BFF00-03FB-40DA-98A7-B0DEF65C2D4B";
        private const string KONASHI_AIO0_CHARACTERISTIC = "229B3008-03FB-40DA-98A7-B0DEF65C2D4B";

        private GattDeviceService service;
        private GattCharacteristic characteristic;

        Timer timer;


        public MainPage() {
            this.InitializeComponent();
        }

        private async void btnConnect_Click(object sender, RoutedEventArgs e) {
            //デバイスを検索
            var selector = GattDeviceService.GetDeviceSelectorFromUuid(new Guid(KONASHI_SERVICE));
            var deviceInfomations = await DeviceInformation.FindAllAsync(selector);
            var deviceInfomation = deviceInfomations.FirstOrDefault();
            if (deviceInfomation != null) {
                //サービス取得
                this.service = await GattDeviceService.FromIdAsync(deviceInfomation.Id);

                //キャラクタリスティック取得
                var characteristics = this.service.GetCharacteristics(new Guid(KONASHI_AIO0_CHARACTERISTIC));
                if (characteristics.Count > 0) {
                    this.characteristic = characteristics.First();
                    
                    var dialog = new MessageDialog("Connected to " + deviceInfomation.Name);
                    await dialog.ShowAsync();

                    //ADC読み取りスレッド開始
                    TimerCallback timerDelegate = new TimerCallback(onTimer);
                    timer = new Timer(timerDelegate, null, 0, 100);
                }
            }
        }


        private async void onTimer(object sender) {
            if (characteristic == null) {
                return ;
            }
            
            var result = await characteristic.ReadValueAsync(BluetoothCacheMode.Uncached);  //キャッシュしてやがった!
            byte[] value = result.Value.ToArray();
            
            int val = (value[0] << 8) + value[1];   //[0]番目に上位バイト、[1]番目に下位バイト
            System.Diagnostics.Debug.WriteLine(val);

            lastVal = val;
            
        }


    }
}

(Java,Android)twitter4jで最新のユーザータイムライン1つだけ取得する

題記の通り。
これで、5秒に1回の頻度(?)で監視できる。

Paging paging = new Paging();
paging.setCount(1); //1個に指定
List<twitter4j.Status> statuses =twitter.getUserTimeline("ユーザ名", paging);
final Status status = statuses.get(0);
Log.d("twitter4j", status.getUser().getScreenName() + " - " + status.getText());

【HTML】mmenuで右からスライドメニューを出す【javascript】

ちゃんとリファレンス読みましょう>俺

デモを見てたら、scriptはこう書く模様。

jQuery(document).ready(function( $ ) {
    $("#menu").mmenu({
        "offCanvas": {
            "position": "right"
        }
    });
});

(ToCoStick)Node.jsでシリアル通信してブラウザでグラフ表示(ccchart)

Node.jsのお勉強が必要になり、ひと段落したからメモ。

TWE-Liteから33msecごとにデータが送られてくると想定。
アナログ入力1の値を読み取り、wsモジュールを使ってccchartに送る。

以下、ソース。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=480">
<title>TWE-Lite Monitor by ccchart</title>
</head>
<body>

<script src="ccchart-min.js" charset="utf-8"></script>

<canvas id="hoge"></canvas>
<script>

var chartdata = {
	"config": {
		"width": (window.innerWidth-60) ,
		"height": (window.innerHeight-60)/1.2,
		"lineWidth": 2,
		"xScaleSkip": 33,
		"useVal": "no",
		"bg": "#000",
		"colorSet": ["#00FF00",],
		"maxY": 2000,
		"minY": 0,
		"maxWsColLen": 333
  },

  "data": [
    ["時間"],
    ["電圧"]
  ]
};

ccchart
  .init('hoge', chartdata)
  .ws('ws://127.0.0.1:3001')
  .on('message', ccchart.wscase.someColsAtATime);

</script>


</body>
</html>

ccchartTest.js

var WsServer = require('ws').Server;
var ws = new WsServer({port : 3001});
var express = require('express');
var serialport = require('serialport');

const ARRAY_NUM = 333;
var dataArr = new Array(ARRAY_NUM);
var time = 0;	//in msec

clearArray();
function clearArray(){
	var now = new Date();
	var hour = ZeroFormat(now.getHours(),2);
	var min = ZeroFormat(now.getMinutes(),2);
	var sec = ZeroFormat(now.getSeconds(),2);
	var nowStr = hour + ":" + min + ":" + sec;
	
	for(i = 0;i < ARRAY_NUM;i++){
		dataArr.push([[nowStr],[1000.0]]);
	}
	//console.log(dataArr);
}

broadcast();
function broadcast(volt){
	var tid = setInterval( function(){
		ws.clients.forEach(function(client){
			client.send(JSON.stringify(dataArr));
//			console.log(dataArr);
			
		});
	}, 100);	//100msec毎に送信
}



var portName = 'COM3';
var sp = new serialport.SerialPort(portName,{
	baudRate: 115200,
	dataBits: 8,
	parity: 'none',
	stopBits: 1,
	flowControl: false,
	//parser: '\n'//serialport.parsers.readLine("\n");
});

sp.on('open', function(){
	console.log('serial port open');
})
sp.on('data',function(input){
	var inBuffer = new Buffer(input, 'ascii');

	if(inBuffer.length < 49){
		return;
	}
	
	var inStr = inBuffer.toString('ascii',37,39);
	var volt = 1.0 * (parseInt(inStr,16) * 16);	//10進に変換,16倍して電圧にも変換,1.0倍してfloatに変換
//	console.log(volt);
	addData(volt);
	
});

function addData(volt){
	var now = new Date();
	var hour = ZeroFormat(now.getHours(),2);
	var min = ZeroFormat(now.getMinutes(),2);
	var sec = ZeroFormat(now.getSeconds(),2);
	var nowStr = hour + ":" + min + ":" + sec;

	dataArr.shift();	//最初の要素を取り除いて、
	dataArr.push([[nowStr],[volt]]);	//push
}

/**
 * [関数名] ZeroFormat
 * [機 能] ゼロ埋め
 * [説 明] 数値が指定した桁数になるまで数値の先頭をゼロで埋める
 *
 * @param  integer num    数値
 * @param  integer max    桁数
 * @return integer tmpS   ゼロ埋め後の数値
 */
function ZeroFormat(num,max){
    var tmp=""+num;
    while(tmp.length<max){
        tmp="0"+tmp;
    }
    return tmp;
}

ZeroFormat関数は
http://phpjavascriptroom.com/exp.php?f=include/js/formcheck/zero2.inc&ttl=%E6%95%B0%E5%80%A4%E3%81%AE%E5%85%88%E9%A0%AD%E3%82%92%E3%82%BC%E3%83%AD%E3%81%A7%E5%9F%8B%E3%82%81%E3%82%8B
を使わせて頂きました。

(HTML)VLC WebプラグインでGoPro HERO3のプレビュー表示

タイトルのまんま。

1.VLC Media Playerをインストールする。
 このとき、Webプラグインを必ずインストールする。
2.以下の通りHTMLファイルを作成

<!DOCTYPE HTML>
<html>
<title>VLCプラグインのテスト</title>
<body>

<embed type="application/x-vlc-plugin"
       pluginspage="http://www.videolan.org"
       width="640"
       height="480"
       id="vlc"
       target="http://10.5.5.9:8080/live/amba.m3u8"/>
</body>
</html>

とりあえず、GoPro本体のWifiパスワードとかは必要ない。
あと、現時点ではChromeでは動かなかった。Firefoxでのみ確認。
参考にしたのは以下のサイト。ありがとうございます。

VLC の Web Pluginを利用した動画配信試験 (Xsrv)

(Android)API Level 17未満で動的にIDを設定する(Java)

タイトルの通りの必要に迫られたので、ググってみたら、generateViewID()メソッドが出てきた。
後々も使いそうなのでメモ。

import java.util.concurrent.atomic.AtomicInteger;

//http://tools.oesf.biz/android-4.3.0_r2.2/xref/frameworks/base/core/java/android/view/View.java#sNextGeneratedId
//のまんま

public class IdGenerater {
    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

    public static int GenerateID(){
        while(true) {
	    final int result = sNextGeneratedId.get();
	        int newValue = result + 1;
		if (newValue > 0x00FFFFFF) newValue = 1;
		    if (sNextGeneratedId.compareAndSet(result, newValue)) {
			return result;
		    }
		}
	}
}