OSDN Git Service

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