Edited at

Wio-LTE で現在時刻を取得する

More than 1 year has passed since last update.

結局 Wio-LTE には時計が二つ入っている。一つは EC21-J のモデムに、もう一つは STM32F4 の SoC 上にある。基本的には電源が切れると、両方とも時刻を忘れる。

時刻の同期元となるものは、携帯網自体か、あるいはNTPによるものか、GPSによるものか、と種類がある。


SoC の時計から時刻を取得する

これは単純に Date() で取得できる。

>console.log(new Date().toString());

Tue Apr 3 2018 02:10:16 GMT+0000
=undefined
>console.log(getTime()); // get in unix epoch seconds
1522721416.42934918403
=undefined

時刻合わせをするときには setTime() で行う。CPU の時刻を使うメリットは、モデムとの通信を待たないでいいことで、他の通信を妨げないのが最大のメリット。モデムの時計をコピーして時刻をセットしておくと便利だろう。あるいはあえて時刻をセットせず、カレンダーとしてではなく、単純に起動時からの経過時間として使うという手もある。

>setTime(1522721463)

=undefined
>console.log(new Date().toString());
Tue Apr 3 2018 02:11:06 GMT+0000
=undefined

E.setTimeZone() で CPU のタイムゾーンを設定すると new Date().toString() の出力を現地時刻に変更できる。

>E.setTimeZone(9)

=undefined
>console.log(new Date().toString());
Tue Apr 3 2018 11:13:39 GMT+0900
=undefined


モデムの時計から時刻を取得する

EC21-J は LTE モデムなので、ネットワークに接続できると、携帯網の機能を使って自動的に時刻が設定される。

モデムの時計からは AT+CCLK コマンドで取得できる。

function clockNow(board){

var pad2 = function(n){ return ("00" + n).slice(-2); };
var normalize_datetime = function(s){
return s.replace("/","-").replace("/","-").replace(",","T");
};
return new Promise((resolve,reject)=>{
board.at.cmd("AT+CCLK?\r\n", 1000, L=>{
if(L===undefined){
reject("timeout");
}else if(parseInt(L[8]) >= 7){ // 1970
reject("uninitialized");
}else{
var dt = normalize_datetime("20" + L.slice(8, 25));
var offset = parseInt(L.slice(26, 28));
dt += L[25] + pad2(offset/4) + pad2((offset%4) * 15);
resolve(new Date(dt));
}
});
});
}

// ここから下はボードの起動手順。後の例では省略。
var board;
function onConnect(err){
if(err){
board = require("wiolte").connect(onConnect);
}else{
clockNow(board).then(T=>{
console.log("clockNow", T);
});
}
}

function onInit(){
board = require("wiolte").connect(onConnect);
}

onInit();


携帯網の時刻を取得する

モデムの時計からではなく、網から明示的に取得する方法。

function networkNow(board, utc){

var pad2 = function(n){ return ("00" + n).slice(-2); }
var normalize_datetime = function(s){
return s.replace("/","-").replace("/","-").replace(",","T");
}
var cmd = "AT+QLTS=2\r\n";
if(utc){
cmd = "AT+QLTS=1\r\n";
}
return new Promise((resolve,reject)=>{
board.at.cmd(cmd, 1000, L=>{
if(L===undefined){
reject("timeout");
}else{
// +QLTS: "2018/04/02,17:31:55+36,0"
var dt = normalize_datetime(L.slice(8, 27));
// Espruino Date accepts 2018-04-02T17:31:55Z
if(utc){
resolve(new Date(dt + "Z"));
}else{
var offset = parseInt(L.slice(28, 30));
dt += L[27] + pad2(offset/4) + pad2((offset%4) * 15);
resolve(new Date(dt));
}
}
});
});
}


NTP で時刻を取得する

NTPで現在時刻を取得する。ネットワークパケットを使う。このコマンドはモデムの AT コマンドを使うのだが、取得と同時にモデムの時計をセットすることもできる。

function ntpNow(board, server){

var pad2 = function(n){ return ("00" + n).slice(-2); };
var normalize_datetime = function(s){
return s.replace("/","-").replace("/","-").replace(",","T");
};
return new Promise((resolve,reject)=>{
var handler = function(L){
if(L===undefined){
reject("QNTP timeout");
}else if(L=="OK"){
return handler;
}else if(L.slice(0,9)=="+QNTP: 0,"){
// +QNTP: 0,"2018/04/03,02:52:26"
var offset = parseInt(L.slice(30,32));
var dt = normalize_datetime(L.slice(10,29));
dt += L[29] + pad2(offset/4) + pad2((offset%4) * 15);
// Espruino Date accepts 2018-04-02T17:31:55Z
resolve(new Date(dt));
}else{
reject(L);
}
};
board.at.cmd("AT+QNTP=1,\""+server+"\"\r\n", 10000, handler);
});
}


GPS

実は Wio-LTE の JP バージョンでのみ GPS が削除されているということに、今気が付きました。日本版だけ劣化してる……。それならそれで soracom のキットを最初から買えばよかった。残念。