OSDN Git Service

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