OSDN Git Service

マニュアル整備
[mimic/MiMicSDK.git] / misc / mbedJS / mbddJS.API / mbedJS / MiMicCore.js
1 /**\r
2  * @fileOverview 低レベルAPIを定義する。低レベルAPIは、MiMicRemoteMcuをインストールしたMCUとの通信クラスを提供する。\r
3  */\r
4 \r
5 /**\r
6  * MiMicネームスペース\r
7  * @namespace\r
8  */\r
9 var MiMicJS={};\r
10 (function(){\r
11         var NS=MiMicJS;\r
12         /**\r
13          * MiMicJsAPIのバージョン文字列。\r
14          * @name MiMicJS#VERSION\r
15          */\r
16         NS.VERSION="MiMicJsAPI/2.0.0";\r
17         /**\r
18          * 配列要素、又は値がすべてInt値でない場合に例外を起こします。\r
19          * @name MiMicJS.assertInt\r
20          * @function\r
21          * @params {[array]} v\r
22          * テストする配列\r
23          */\r
24         NS.assertInt=function assertInt(v){\r
25                 if(!NS.isArray(v)){\r
26                         if(!NS.isInt(v)){throw new NS.MiMicException();}\r
27                 }\r
28                 for(var i=0;i<v.length;i++){\r
29                         if(NS.isInt(v[i])){\r
30                                 continue;\r
31                         }\r
32                         throw new NS.MiMicException('"'+v[i]+'" is not integer.');\r
33                 }\r
34         }\r
35         /**\r
36          * 配列要素、、又は値がすべて数値でない場合に例外を起こします。\r
37          * @name MiMicJS.assertNumber\r
38          * @function\r
39          * @params {[array]} v\r
40          * テストする配列\r
41          */\r
42         NS.assertNumber=function assertNumber(v){\r
43                 if(!NS.isArray(v)){\r
44                         if(!NS.isNumber(v)){    throw new NS.MiMicException();}\r
45                 }else{\r
46                         for(var i=0;i<v.length;i++){\r
47                                 if(NS.isNumber(v[i])){\r
48                                         continue;\r
49                                 }\r
50                                 throw new NS.MiMicException('"'+v[i]+'" is not number.');\r
51                         }\r
52                 }\r
53         };\r
54         /**\r
55          * 数値であるかを確認します。\r
56          * @private\r
57          */\r
58         NS.isNumber=function isNumber(o)\r
59         {\r
60                 return (typeof o=='number');\r
61         };\r
62         /**\r
63          * 整数であるかを確認します。\r
64          * @private\r
65          */\r
66         NS.isInt=function isInt(o)\r
67         {\r
68                 return (typeof o=='number') && (o-Math.round(o)==0);\r
69         };\r
70 \r
71         /**\r
72          * @private\r
73          * オブジェクトがジェネレータクラスであるかを返します。\r
74          */\r
75         NS.isGenerator=function isGenerator(o)\r
76         {\r
77                 if(!o){return false;}\r
78                 return o.toString().indexOf('Generator')!=-1;\r
79         };\r
80         /**\r
81          * @private\r
82          * 現在の時刻を返します。\r
83          */\r
84         NS.getNow=function getNow(){\r
85                 return (new Date()).getTime();\r
86         };\r
87         /**\r
88          * @private\r
89          * aが配列であるかを返します。\r
90          */\r
91         NS.isArray=function isArray(a){\r
92                 return a instanceof Array;\r
93         };\r
94         /**\r
95          * @private\r
96          * aが配列であるかを返します。\r
97          */\r
98         NS.isHashArray=function isHashArray(a){\r
99                 return (!(a instanceof Array)) && (typeof a == "object");\r
100         };      \r
101         /**\r
102          * 連想配列をシャローコピーして複製します。\r
103          * @private\r
104          */     \r
105         NS.cloneAssoc=function cloneAssoc(a)\r
106         {\r
107                 var r={};\r
108                 for(var i in a){\r
109                         r[i]=a[i];\r
110                 }\r
111                 return r;\r
112         };\r
113         /**\r
114          * @private\r
115          * 桁数を指定して、int値を16進数に変換します。\r
116          * @param {int} i_val\r
117          * 変換する値\r
118          * @param {int} i_digit\r
119          * 桁数\r
120          * @return {string}\r
121          * 文字列形式の値\r
122          */\r
123         NS.hexout=function hexout(i_val,i_digit)\r
124         {\r
125                 try{\r
126                         var dt=["","0","00","000","0000","00000","000000","0000000"];\r
127                         var s=(i_val>>>0).toString(16).toLowerCase();\r
128                         if(s.length>i_digit){\r
129                                 //マイナスだともれなくエラー\r
130                                 throw new MiMicException(EE.NG);\r
131                         }\r
132                         var l=i_digit-s.length;\r
133                         return dt[l]+s;\r
134                 }catch(e){\r
135                         throw new MiMicException(e);\r
136                 }\r
137         };\r
138         /**\r
139          * @private\r
140          * 連想配列を文字列にして返します。\r
141          */\r
142         NS.assocToStr=function assocToStr(a)\r
143         {\r
144                 var s="";\r
145                 for(k in a){s+=k+":"+a[k]+",";}\r
146                 return s;\r
147         };\r
148 }());\r
149 \r
150 (function(){\r
151         var NS=MiMicJS;\r
152         \r
153         /**\r
154          * MiMicExceptionが使用するエラーコードと、その判定関数を定義する。\r
155          * エラーコードは、以下の形式の配列オブジェクトで表現する。\r
156          * <pre>\r
157          * [code:int,message:string]\r
158          * </pre>\r
159          * \r
160          * codeは31ビットのエラーコードである。ビットフィールドの意味は以下の通りである。\r
161          * <table>\r
162          * <tr><th>bit</th><th>name</th><th>discription</th></tr>\r
163          * <tr><td>30</td><td>ErrorBit</td><td>Error:1,OK:0</td></tr>\r
164          * <tr><td>29-24</td><td>Reserved</td><td>-</td></tr>\r
165          * <tr><td>23-16</td><td>ModuleID</td><td>0x00:unknown<br/>0x39:MiMic<br/>0xF0-0xFF: user define<br/>Other:Reserved<br/></td></tr>\r
166          * <tr><td>15-8</td><td>ClassID</td><td>0x00:unknown</td></tr>\r
167          * <tr><td>7-0</td><td>ErrorID</td><td></td></tr>\r
168          * </table>\r
169          * @namespace\r
170          * @name MiMicJS.Error\r
171          * @example\r
172          * throw new MiMicException(MiMicError.NG);\r
173          */\r
174         NS.Error=\r
175         {\r
176                 /** 成功を示します。\r
177                  * @constant\r
178                  * @name MiMicJS.Error.OK\r
179                  */\r
180                 OK:[0x00000000,"OK"],\r
181                 /** 詳細情報の無いエラーです。\r
182                  * @constant\r
183                  * @name MiMicJS.Error.NG\r
184                  */     \r
185                 NG:[0x40000000,"NG"],\r
186                 /** Generatorを用いたコードで、前回のyieldが終了していないことを示します。\r
187                  * @constant\r
188                  * @name MiMicJS.Error.NG_YIELD_NOT_COMPLETED\r
189                  */\r
190                 NG_YIELD_NOT_COMPLETED:[0x40001001,"The previous function has not been completed."],\r
191                 /** 関数の呼び出し順序が正しくないことを示します。\r
192                  * @constant\r
193                  * @name MiMicJS.Error.NG_ILLEGAL_CALL\r
194                  */\r
195                 NG_ILLEGAL_CALL:[0x40001002,"Illegal procedure call."],\r
196                 /** 引数型の不一致を検出したことを示します。\r
197                  * @constant\r
198                  * @name MiMicJS.Error.NG_INVALID_ARG\r
199                  */\r
200                 NG_INVALID_ARG:[0x40001003,"Invalid arguments."],\r
201                 /**\r
202                  * エラーコードがOKか調べる。\r
203                  * @function\r
204                  * @name MiMicJS.Error.isOK\r
205                  * @param {Object as [MiMicErrorCode]} v\r
206                  * 評価するオブジェクト\r
207                  * @return {Boolean}\r
208                  * エラーコードでなければ、trueを返す。\r
209                  * @example\r
210                  * MiMicError.isOK(MiMicError.OK);//true\r
211                  */\r
212                 isOK:function(v){\r
213                         return (0x40000000 & v)==0x00000000;\r
214                 }\r
215         };\r
216         \r
217 }());\r
218 \r
219 (function(){\r
220         var NS=MiMicJS; \r
221         /**\r
222          * 引数が1個のパターン。\r
223          * @name MiMicJS.MiMicException.2\r
224          * @function\r
225          * @param {object} e\r
226          * eのクラスにより、動作が異なる。\r
227          * <ul>\r
228          * <li>{string} - MiMicException(Error.NG,e)と等価である。</li>\r
229          * <li>{object as [MiMicErrorCode]} - エラーコードを指定して例外を生成する。エラーコードについては、MiMicJs.Errorを参照</li>\r
230          * <li>{object} - MiMicException(MiMicError.NG,e.toString())と等価である。objectを文字列化して例外を生成する。</li>\r
231          * <li>{MiMicException} - codeとmessageを継承して例外を生成する。コールスタックを生成するときは、このパターンを使うこと。</li>\r
232          * </ul>\r
233          * @example\r
234          * throw new MiMicException(MiMicError.NG);\r
235          * throw new MiMicException("Error");\r
236          * try{\r
237          *       throw new MiMicException("Error");\r
238          * }catch(e){\r
239          *       throw new MiMicException(e);\r
240          * }\r
241          */\r
242         /**\r
243          * MiMic javascript APIが生成する例外クラスのコンストラクタである。関数ごとにMiMicExceptionを使ったtry-catchを導入することにより、例外発生時にスタックトレースメッセージを得ることが出来る。\r
244          * スタックトレースは改行で連結された文字列である。messageプロパティに格納される。alert関数で表示することで、効率的なデバックが可能である。\r
245          * 引数の違いにより、数種類の呼び出し方がある。\r
246          * @constructor\r
247          * @name MiMicJS.MiMicException\r
248          * @param ...\r
249          * 詳細は、MiMicException.nを参照。\r
250          */\r
251         NS.MiMicException=function MiMicException(/*...*/)\r
252         {\r
253                 var pfx;\r
254                 if(typeof arguments.callee.caller=="function"){\r
255                          if(arguments.callee.caller.name.toString().length>0){\r
256                                 pfx="function '"+arguments.callee.caller.name+'.';\r
257                          }else{\r
258                                 var s=arguments.callee.caller.toString();\r
259                                 pfx="closure '"+s.substring(0,s.indexOf("{"))+"...'";\r
260                          }\r
261                 }else{\r
262                         pfx="root document";\r
263                 }\r
264                 var sfx="";\r
265                 switch(arguments.length){\r
266                 case 0:\r
267                         //とりあえずexceptiion\r
268                         this.code=NS.Error.NG[0];\r
269                         this.message=pfx+" code(0x"+this.code.toString(16)+")"+NS.Error.NG[1];\r
270                         return;\r
271                 case 1:\r
272                         var v=arguments[0];\r
273                         if(v instanceof NS.MiMicException){\r
274                                 //exception継承\r
275                                 this.code=v.code;\r
276                                 sfx="  \nfrom "+v.message;\r
277                         }else if(typeof v=="object" && v.length==2){\r
278                                 //Errorコードテーブル\r
279                                 this.code=v[0];\r
280                                 sfx=v[1];\r
281                         }else{\r
282                                 //文字列やオブジェクト\r
283                                 this.code=NS.Error.NG[0];\r
284                                 sfx=NS.Error.NG[1]+" "+(((typeof v)!='undefined')?v.toString():"v==undefined");\r
285                         }\r
286                         this.message=pfx+" code(0x"+this.code.toString(16)+")"+sfx;\r
287                         return;\r
288                 default:\r
289                         break;\r
290                 }\r
291                 throw new NS.MiMicException("Invalid MiMicException argument.");\r
292         }\r
293 \r
294         NS.MiMicException.prototype=\r
295         {\r
296                 \r
297                 /**\r
298                  * MiMicErrorCode形式のエラーコードを保持する。\r
299                  * @field {object as MiMicErrorCode}\r
300                  * @name MiMicJS.MiMicException#code\r
301                  */\r
302                 code:null,\r
303                 /**\r
304                  * エラーメッセージを保持する。この値は、改行区切りのコールスタックである。\r
305                  * @field {string}\r
306                  * @name MiMicJS.MiMicException#message\r
307                  */\r
308                 message:"",\r
309                 /**\r
310                  * messageフィールドをalertで表示する。\r
311                  * @name MiMicJS.MiMicException#alert\r
312                  * @function\r
313                  * @example\r
314                  * try{\r
315                  *      throw new MiMicException();\r
316                  * }catch(e){\r
317                  *      e.alert();\r
318                  * }     \r
319                  */\r
320                 alert:function(){\r
321                         alert(this.message);\r
322                 },\r
323                 /**\r
324                  * toStringを上書きする。オブジェクトを文字列化する。\r
325                  * 文字列は例外のコールスタックであり、デバックで役立つ。\r
326                  * @function\r
327                  * @name MiMicJS.MiMicException#toString\r
328                  * @return {string}\r
329                  * 現在のオブジェクトの状態(例外のコールスタック)\r
330                  * @example\r
331                  * try{\r
332                  *      throw new MiMicException();\r
333                  * }catch(e){\r
334                  *      alert(e.toString());\r
335                  * }     \r
336                  */\r
337                 toString:function()\r
338                 {\r
339                         return "MiMicException:"+this.message;\r
340                 }       \r
341         }\r
342 }());\r
343 \r
344 (function(){\r
345         /**@private */\r
346         var NS=MiMicJS;\r
347         /**\r
348          * MiMicRPCのクライアントクラスです。\r
349          * 通信APIを提供します。\r
350          * @name MiMicJS.Rpc\r
351          * @constructor\r
352          * @param {HashMap} i_event\r
353          * 非同期イベントハンドラの連想配列です。登録できるメンバは以下の通りです。\r
354          * <ul>\r
355          * <li>onOpen:function() -\r
356          * open関数のコールバック関数です。\r
357          * <li>onClose:function() -\r
358          * close関数のコールバック関数です。\r
359          * <li>onError:function() -\r
360          * 何らかの異常で通信を継続できないエラーが発生し、コネクションを維持できない時に発生します。\r
361          * このイベントが発生するとコネクションは閉じられます。\r
362          * </ul>\r
363          */\r
364         NS.Rpc=function Rpc(i_event)\r
365         {\r
366                 this._event=(i_event)?i_event:null;\r
367         }\r
368         NS.Rpc.prototype=\r
369         {\r
370                 _event:null,\r
371                 /**\r
372                  * @private \r
373                  * Websocketインスタンスです。\r
374                  */\r
375                 _ws:null,\r
376                 /**\r
377                  * @private\r
378                  * [READ ONLY]\r
379                  * RPCの平均RTT[ms]です。\r
380                  * @name MiMicJs.Rpc#RTT\r
381                  */\r
382                 rtt:0,\r
383                 /** メソッドIDカウンタ。sendJsonを実行する毎にインクリメントされます。*/\r
384                 _method_id:0,\r
385                 /**\r
386                  * RPCコネクションを開きます。\r
387                  * 関数が終了するとonOpenイベントをコールバックします。\r
388                  * @name MiMicJS.Rpc#open\r
389                  * @function\r
390                  * @param i_url\r
391                  * ws://から始まるWebsocketサービスURLを指定します。\r
392                  */\r
393                 open:function open(i_url)\r
394                 {\r
395                         var _t=this;\r
396                         if(this._ws){\r
397                                 throw new MiMicException();\r
398                         }\r
399                         \r
400                         var q=new Array();\r
401                         var ev=this._event;\r
402                         var ws=new WebSocket(i_url);\r
403                         ws.onopen = function(){\r
404                                 if(ev.onOpen){ev.onOpen();}\r
405                         }\r
406                         ws.onclose = function(){\r
407                                 if(ev.onClose){ev.onClose();}\r
408                         };\r
409                         ws.error = function(){\r
410                                 _t.shutdown();\r
411                                 if(ev.onClose){ev.onError();}\r
412                         };\r
413                         var rx="";\r
414                         var rxst=0;\r
415                         var _t=this;\r
416                         ws.onmessage = function (e)\r
417                         {\r
418                                 //ストリームからJSONを抽出。"のエスケープには対応しない。\r
419                                 for(var i=0;i<e.data.length;i++){\r
420                                         var t=e.data[i];\r
421                                         switch(rxst){\r
422                                         case 2:\r
423                                                 if(t!='"'){\r
424                                                         rxst=1;\r
425                                                 }\r
426                                                 break;\r
427                                         case 0:\r
428                                                 if(t!='{'){\r
429                                                         continue;\r
430                                                 }\r
431                                                 rx='({';\r
432                                                 rxst=1;\r
433                                                 continue;\r
434                                         case 1:\r
435                                                 switch(t){\r
436                                                 case '"':\r
437                                                         rxst=2;\r
438                                                         break;\r
439                                                 case '}':\r
440                                                         rx+='})';\r
441                                                         rxst=0;\r
442                                                         {\r
443                                                                 //JSONがたぶん確定\r
444                                                                 var j=eval(rx);\r
445                                                                 for(var i2=q.length-1;i2>=0;i2--){\r
446                                                                         if(q[i2][0]==j.id){\r
447                                                                                 //id一致→コールバック\r
448                                                                                 var qi=q[i2];\r
449                                                                                 q.splice(i2, 1);\r
450                                                                                 //コールバック必要?\r
451                                                                                 if(qi[1]){qi[1](j);}\r
452                                                                                 break;\r
453                                                                         }\r
454                                                                 }\r
455                                                         }\r
456                                                         continue;\r
457                                                 }\r
458                                         }\r
459                                         rx+=t;\r
460                                 }\r
461                         }\r
462                         this._method_id=0;\r
463                         this._q=q;\r
464                         this._ws=ws;\r
465                 },\r
466                 /**\r
467                  * 接続中のRPCコネクションを閉じます。\r
468                  * 関数が終了するとonCloseイベントをコールバックします。\r
469                  * @name MiMicJS.Rpc#close\r
470                  * @function\r
471                  */\r
472                 close:function close()\r
473                 {\r
474                         if(this._ws && this._ws.readyState==1){\r
475                                 this._ws.close();\r
476                                 this._ws=null;\r
477                         }\r
478                 },\r
479                 /**\r
480                  * RPC回線を確実に閉じます。\r
481                  * この関数を実行すると、すべてのコールバックイベントはキャンセルされます。\r
482                  * @name MiMicJS.Rpc#shutdown\r
483                  * @function\r
484                  */\r
485                 shutdown:function shutdown()\r
486                 {\r
487                         var _t=this;\r
488                         if(_t._ws){\r
489                                 _t._ws.onopen=function(){_t._ws.close();};\r
490                                 _t._ws.onmessage=function(){_t._ws.close();};\r
491                                 _t._ws.onclose=function(){_t._ws=null;};\r
492                                 _t._ws.onerror=function(){_t._ws=null;};\r
493                         }\r
494                 },\r
495                 /**\r
496                  * 非同期でJSON RPCメソッドを送信します。\r
497                  * @name MiMicJS.Rpc#sendMethod\r
498                  * @function\r
499                  * @param {string} i_method\r
500                  * RPCメソッドの名前です。\r
501                  * @param {string} i_params\r
502                  * カンマ区切りのJSONスタイルの文字列です。この文字列は[....]に埋め込まれます。エスケープ文字列は使用できません。\r
503                  * @param {function(json)}i_callback\r
504                  * Resultを受け取るコールベック関数です。jsonにはResult JSONをパースしたオブジェクトが入ります。\r
505                  * @return {int}\r
506                  * メソッドIDを返します。\r
507                  */\r
508                 sendMethod:function callJsonRpc(i_method,i_params,i_callback)\r
509                 {\r
510                         this._ws.send("{\"verdion\":\"2.0\",\"method\":\""+i_method+"\",\"params\":["+i_params+"],\"id\":"+this._method_id+"}");\r
511                         this._q.push([this._method_id,i_callback]);//キューに記録\r
512                         this._method_id=(this._method_id+1)&0x0fffffff;//IDインクリメント\r
513                         return this._method_id;\r
514                 }\r
515         }\r
516 \r
517 }());