OSDN Git Service

mbed.jsの更新
[mimic/MiMicSDK.git] / misc / MiMicVM / mbed.js / mimic / 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          * @name MiMicJS#VERSION\r
14          * MiMicJsAPIのバージョン文字列。\r
15          */\r
16         NS.VERSION="MiMicJsAPI/2.0.0";\r
17         /**\r
18          * @name MiMicJS.assertInt\r
19          * @function\r
20          * 配列要素、又は値がすべてInt値でない場合に例外を起こします。\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          * @name MiMicJS.assertNumber\r
37          * @function\r
38          * 配列要素、、又は値がすべて数値でない場合に例外を起こします。\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          * @private\r
56          * 数値であるかを確認します。\r
57          */\r
58         NS.isNumber=function isNumber(o)\r
59         {\r
60                 return (typeof o=='number');\r
61         };\r
62         /**\r
63          * @private\r
64          * 整数であるかを確認します。\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          * @example\r
171          * throw new MiMicException(MiMicError.NG);\r
172          */\r
173         NS.Error=\r
174         {\r
175                 /** 成功を示すエラー値\r
176                  * @constant*/  \r
177                 OK:[0x00000000,"OK"],\r
178                 /** 失敗を示すエラー値。不明な場所で、不明な何かが、不明なエラーを起こしたことを示す。\r
179                  * @constant*/  \r
180                 NG:[0x40000000,"NG"],\r
181                 NG_YIELD_NOT_COMPLETED:[0x40001001,"The previous function has not been completed."],\r
182                 NG_ILLEGAL_CALL:[0x40001002,"Illegal procedure call."],\r
183                 NG_INVALID_ARG:[0x40001003,"Invalid arguments."],\r
184                 /**\r
185                  * エラーコードがOKか調べる。\r
186                  * @function\r
187                  * @param {Object as [MiMicErrorCode]} v\r
188                  * 評価するオブジェクト\r
189                  * @return {Boolean}\r
190                  * エラーコードでなければ、trueを返す。\r
191                  * @example\r
192                  * MiMicError.isOK(MiMicError.OK);//true\r
193                  */\r
194                 isOK:function(v){\r
195                         return (0x40000000 & v)==0x00000000;\r
196                 }\r
197         };\r
198         \r
199 }());\r
200 \r
201 (function(){\r
202         var NS=MiMicJS; \r
203         /**\r
204          * 引数が1個のパターン。\r
205          * @name MiMicException.2\r
206          * @function\r
207          * @param {object} e\r
208          * eのクラスにより、動作が異なる。\r
209          * <ul>\r
210          * <li>{string} - MiMicException(Error.NG,e)と等価である。</li>\r
211          * <li>{object as [MiMicErrorCode]} - エラーコードを指定して例外を生成する。エラーコードについては、MiMicJs.Errorを参照</li>\r
212          * <li>{object} - MiMicException(MiMicError.NG,e.toString())と等価である。objectを文字列化して例外を生成する。</li>\r
213          * <li>{MiMicException} - codeとmessageを継承して例外を生成する。コールスタックを生成するときは、このパターンを使うこと。</li>\r
214          * </ul>\r
215          * @example\r
216          * throw new MiMicException(MiMicError.NG);\r
217          * throw new MiMicException("Error");\r
218          * try{\r
219          *       throw new MiMicException("Error");\r
220          * }catch(e){\r
221          *       throw new MiMicException(e);\r
222          * }\r
223          */\r
224         /**\r
225          * MiMic javascript APIが生成する例外クラスのコンストラクタである。関数ごとにMiMicExceptionを使ったtry-catchを導入することにより、例外発生時にスタックトレースメッセージを得ることが出来る。\r
226          * スタックトレースは改行で連結された文字列である。messageプロパティに格納される。alert関数で表示することで、効率的なデバックが可能である。\r
227          * 引数の違いにより、数種類の呼び出し方がある。\r
228          * @constructor\r
229          * @param ...\r
230          * 詳細は、MiMicException.nを参照。\r
231          */\r
232         NS.MiMicException=function MiMicException(/*...*/)\r
233         {\r
234                 var pfx;\r
235                 if(typeof arguments.callee.caller=="function"){\r
236                          if(arguments.callee.caller.name.toString().length>0){\r
237                                 pfx="function '"+arguments.callee.caller.name+'.';\r
238                          }else{\r
239                                 var s=arguments.callee.caller.toString();\r
240                                 pfx="closure '"+s.substring(0,s.indexOf("{"))+"...'";\r
241                          }\r
242                 }else{\r
243                         pfx="root document";\r
244                 }\r
245                 var sfx="";\r
246                 switch(arguments.length){\r
247                 case 0:\r
248                         //とりあえずexceptiion\r
249                         this.code=NS.Error.NG[0];\r
250                         this.message=pfx+" code(0x"+this.code.toString(16)+")"+NS.Error.NG[1];\r
251                         return;\r
252                 case 1:\r
253                         var v=arguments[0];\r
254                         if(v instanceof NS.MiMicException){\r
255                                 //exception継承\r
256                                 this.code=v.code;\r
257                                 sfx="  \nfrom "+v.message;\r
258                         }else if(typeof v=="object" && v.length==2){\r
259                                 //Errorコードテーブル\r
260                                 this.code=v[0];\r
261                                 sfx=v[1];\r
262                         }else{\r
263                                 //文字列やオブジェクト\r
264                                 this.code=NS.Error.NG[0];\r
265                                 sfx=NS.Error.NG[1]+" "+(((typeof v)!='undefined')?v.toString():"v==undefined");\r
266                         }\r
267                         this.message=pfx+" code(0x"+this.code.toString(16)+")"+sfx;\r
268                         return;\r
269                 default:\r
270                         break;\r
271                 }\r
272                 throw new NS.MiMicException("Invalid MiMicException argument.");\r
273         }\r
274 \r
275         NS.MiMicException.prototype=\r
276         {\r
277                 \r
278                 /**\r
279                  * MiMicErrorCode形式のエラーコードを保持する。\r
280                  * @field {object as MiMicErrorCode}\r
281                  */\r
282                 code:null,\r
283                 /**\r
284                  * エラーメッセージを保持する。この値は、改行区切りのコールスタックである。\r
285                  * @field {string}\r
286                  */\r
287                 message:"",\r
288                 /**\r
289                  * messageフィールドをalertで表示する。\r
290                  * @function\r
291                  * @example\r
292                  * try{\r
293                  *      throw new MiMicException();\r
294                  * }catch(e){\r
295                  *      e.alert();\r
296                  * }     \r
297                  */\r
298                 alert:function(){\r
299                         alert(this.message);\r
300                 },\r
301                 /**\r
302                  * toStringを上書きする。オブジェクトを文字列化する。\r
303                  * 文字列は例外のコールスタックであり、デバックで役立つ。\r
304                  * @function\r
305                  * @return {string}\r
306                  * 現在のオブジェクトの状態(例外のコールスタック)\r
307                  * @example\r
308                  * try{\r
309                  *      throw new MiMicException();\r
310                  * }catch(e){\r
311                  *      alert(e.toString());\r
312                  * }     \r
313                  */\r
314                 toString:function()\r
315                 {\r
316                         return "MiMicException:"+this.message;\r
317                 }       \r
318         }\r
319 }());\r
320 \r
321 (function(){\r
322         /**@private */\r
323         var NS=MiMicJS;\r
324         /**\r
325          * @name MiMicJs.Rpc\r
326          * @constructor\r
327          * MiMicRPCのクライアントクラスです。\r
328          * 通信APIを提供します。\r
329          * @param {HashMap} i_event\r
330          * 非同期イベントハンドラの連想配列です。登録できるメンバは以下の通りです。\r
331          * <ul>\r
332          * <li>onOpen:function() -\r
333          * open関数のコールバック関数です。\r
334          * <li>onClose:function() -\r
335          * close関数のコールバック関数です。\r
336          * <li>onError:function() -\r
337          * 何らかの異常で通信を継続できないエラーが発生し、コネクションを維持できない時に発生します。\r
338          * このイベントが発生するとコネクションは閉じられます。\r
339          * </ul>\r
340          */\r
341         NS.Rpc=function Rpc(i_event)\r
342         {\r
343                 this._event=(i_event)?i_event:null;\r
344         }\r
345         NS.Rpc.prototype=\r
346         {\r
347                 _event:null,\r
348                 /**\r
349                  * @private \r
350                  * Websocketインスタンスです。\r
351                  */\r
352                 _ws:null,\r
353                 /**\r
354                  * @name MiMicJs.Rpc#RTT\r
355                  *  [READ ONLY]\r
356                  *  RPCの平均RTT[ms]です。\r
357                  */\r
358                 rtt:0,\r
359                 /** メソッドIDカウンタ。sendJsonを実行する毎にインクリメントされます。*/\r
360                 _method_id:0,\r
361                 /**\r
362                  * @name MiMicJS.Rpc#open\r
363                  * @function\r
364                  * RPCコネクションを開きます。\r
365                  * 関数が終了するとonOpenイベントをコールバックします。\r
366                  * @param i_url\r
367                  * ws://から始まるWebsocketサービスURLを指定します。\r
368                  */\r
369                 open:function open(i_url)\r
370                 {\r
371                         var _t=this;\r
372                         if(this._ws){\r
373                                 throw new MiMicException();\r
374                         }\r
375                         \r
376                         var q=new Array();\r
377                         var ev=this._event;\r
378                         var ws=new WebSocket(i_url);\r
379                         ws.onopen = function(){\r
380                                 if(ev.onOpen){ev.onOpen();}\r
381                         }\r
382                         ws.onclose = function(){\r
383                                 if(ev.onClose){ev.onClose();}\r
384                         };\r
385                         ws.error = function(){\r
386                                 _t.shutdown();\r
387                                 if(ev.onClose){ev.onError();}\r
388                         };\r
389                         var rx="";\r
390                         var rxst=0;\r
391                         var _t=this;\r
392                         ws.onmessage = function (e)\r
393                         {\r
394                                 //ストリームからJSONを抽出。"のエスケープには対応しない。\r
395                                 for(var i=0;i<e.data.length;i++){\r
396                                         var t=e.data[i];\r
397                                         switch(rxst){\r
398                                         case 2:\r
399                                                 if(t!='"'){\r
400                                                         rxst=1;\r
401                                                 }\r
402                                                 break;\r
403                                         case 0:\r
404                                                 if(t!='{'){\r
405                                                         continue;\r
406                                                 }\r
407                                                 rx='({';\r
408                                                 rxst=1;\r
409                                                 continue;\r
410                                         case 1:\r
411                                                 switch(t){\r
412                                                 case '"':\r
413                                                         rxst=2;\r
414                                                         break;\r
415                                                 case '}':\r
416                                                         rx+='})';\r
417                                                         rxst=0;\r
418                                                         {\r
419                                                                 //JSONがたぶん確定\r
420                                                                 var j=eval(rx);\r
421                                                                 for(var i2=q.length-1;i2>=0;i2--){\r
422                                                                         if(q[i2][0]==j.id){\r
423                                                                                 //id一致→コールバック\r
424                                                                                 var qi=q[i2];\r
425                                                                                 q.splice(i2, 1);\r
426                                                                                 //コールバック必要?\r
427                                                                                 if(qi[1]){qi[1](j);}\r
428                                                                                 break;\r
429                                                                         }\r
430                                                                 }\r
431                                                         }\r
432                                                         continue;\r
433                                                 }\r
434                                         }\r
435                                         rx+=t;\r
436                                 }\r
437                         }\r
438                         this._method_id=0;\r
439                         this._q=q;\r
440                         this._ws=ws;\r
441                 },\r
442                 /**\r
443                  * @name MiMicJS.Rpc#close\r
444                  * @function\r
445                  * 接続中のRPCコネクションを閉じます。\r
446                  * 関数が終了するとonCloseイベントをコールバックします。\r
447                  */\r
448                 close:function close()\r
449                 {\r
450                         if(this._ws && this._ws.readyState==1){\r
451                                 this._ws.close();\r
452                                 this._ws=null;\r
453                         }\r
454                 },\r
455                 /**\r
456                  * @name MiMicJS.Rpc#shutdown\r
457                  * RPC回線を確実に閉じます。\r
458                  * この関数を実行すると、すべてのコールバックイベントはキャンセルされます。\r
459                  */\r
460                 shutdown:function shutdown()\r
461                 {\r
462                         var _t=this;\r
463                         if(_t._ws){\r
464                                 _t._ws.onopen=function(){_t._ws.close();};\r
465                                 _t._ws.onmessage=function(){_t._ws.close();};\r
466                                 _t._ws.onclose=function(){_t._ws=null;};\r
467                                 _t._ws.onerror=function(){_t._ws=null;};\r
468                         }\r
469                 },\r
470                 /**\r
471                  * @name MiMicJS.Rpc#sendMethod\r
472                  * @function\r
473                  * 非同期でJSON RPCメソッドを送信します。\r
474                  * @param {string} i_method\r
475                  * RPCメソッドの名前です。\r
476                  * @param {string} i_params\r
477                  * カンマ区切りのJSONスタイルの文字列です。この文字列は[....]に埋め込まれます。エスケープ文字列は使用できません。\r
478                  * @param {function(json)}i_callback\r
479                  * Resultを受け取るコールベック関数です。jsonにはResult JSONをパースしたオブジェクトが入ります。\r
480                  * @return\r
481                  * メソッドIDを返します。\r
482                  */\r
483                 sendMethod:function callJsonRpc(i_method,i_params,i_callback)\r
484                 {\r
485                         this._ws.send("{\"verdion\":\"2.0\",\"method\":\""+i_method+"\",\"params\":["+i_params+"],\"id\":"+this._method_id+"}");\r
486                         this._q.push([this._method_id,i_callback]);//キューに記録\r
487                         this._method_id=(this._method_id+1)&0x0fffffff;//IDインクリメント\r
488                         return this._method_id;\r
489                 }\r
490         }\r
491 \r
492 }());