結局 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 のキットを最初から買えばよかった。残念。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.