1/** 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/** 18 * @fileoverview Mock Radio Interface Layer (RIL) used for testing 19 * 20 * The following routines are defined in c++: 21 * 22 * Print a string to android log 23 * print(string) 24 * 25 * Read a file to a string. 26 * String readFileToString(String fileName) 27 * 28 * Read a file to a Buffer. 29 * Buffer readFileToBuffer(String fileName) 30 * 31 * Send an response unsolicited response to the framework. 32 * sendRilUnsolicitedResponse(Number responseNum, Buffer responseProtobuf) 33 * 34 * Send a completion request to the framework. 35 * sendRilRequestComplete(Number rilErrCode, Number reqNum, 36 * String token, Buffer responseProtobuf) 37 * 38 * Send a complete request to the controller. 39 * sendCtrlRequestComplete(Number ctrlStatus, Number reqNum, 40 * String token, Buffer responseProtobuf) 41 * 42 * Include the javascript file. 43 * include(string) 44 * 45 * The following objects are defined in c++ 46 * 47 * Buffer is defined in node_buffer and provides a wrapper 48 * for a buffer that can be shared between c++ and js. 49 * Buffer(length) 50 * Buffer::length() 51 * Buffer::data() 52 * 53 * Schema is defined in protobuf_v8 and converts between 54 * a buffer and an object. A protobuf descriptor, ril.desc 55 * and ctrl.desc, is used to drive the conversation. 56 * Object Schema::parse(Buffer protobuf) 57 * Buffer Schema::serialize(object) 58 * 59 * Worker is a thread which receives messages to be handled. 60 * It is passed a function which is called once for each 61 * message as it arrives. Call the add method to queue up 62 * requests for the worker function to process. 63 * Object Worker(function (req)) 64 * Worker::add(req); 65 */ 66 67/** 68 * Globals 69 */ 70 71include("ril_vars.js"); 72 73var NULL_RESPONSE_STRING = '*magic-null*'; 74 75// The state of the radio, needed by currentState() 76var gRadioState = RADIOSTATE_UNAVAILABLE; 77 78// The state of the screen 79var gScreenState = 0; 80 81// The base band version 82var gBaseBandVersion = 'mock-ril 0.1'; 83 84// define a global variable to access the global object 85var globals = this; 86 87// Empty Protobuf, defined here so we don't have 88// to recreate an empty Buffer frequently 89var emptyProtobuf = new Buffer(); 90 91// Get the ril description file and create a schema 92var packageNameAndSeperator = 'ril_proto.'; 93var rilSchema = new Schema(readFileToBuffer('ril.desc')); 94var ctrlSchema = new Schema(readFileToBuffer('ctrl.desc')); 95 96/** 97 * Print properties of an object 98 */ 99function printProperties(obj, maxDepth, depth) { 100 if (typeof maxDepth == 'undefined') { 101 maxDepth = 1; 102 } 103 if (typeof depth == 'undefined') { 104 depth = 1; 105 } 106 if (depth == 1) { 107 print('printProperties:'); 108 } 109 for (var property in obj) { 110 try { 111 if ((typeof obj[property] == 'object') 112 && (depth < maxDepth)) { 113 printProperties(obj[property], maxDepth, depth+1); 114 } else { 115 print(depth + ': ' + property + '=' + obj[property] + 116 ' type=' + typeof obj[property]); 117 } 118 } catch (err) { 119 print('err=' + err) 120 } 121 } 122} 123 124// Test printProperties 125if (false) { 126 var myObject = { 'field1' : '1', 'field2' : '2', 'hello' : [ 'hi', 'there' ] }; 127 printProperties(myObject, 3); 128} 129 130/** 131 * Include the components 132 */ 133 134include("simulated_radio.js"); 135include("simulated_icc.js"); 136include("ctrl_server.js"); 137 138/** 139 * Construct a new request which is passed to the 140 * Worker handler method. 141 */ 142function Request(reqNum, token, protobuf, schema, schemaName) { 143 this.reqNum = reqNum; 144 this.token = token; 145 try { 146 this.data = schema[packageNameAndSeperator + schemaName].parse(protobuf); 147 } catch (err) { 148 // not a valid protobuf in the request 149 this.data = null; 150 } 151} 152 153/** 154 * Dispatch incoming requests from RIL to the appropriate component. 155 */ 156function onRilRequest(reqNum, token, requestProtobuf) { 157 try { 158 //print('onRilRequest E: reqNum=' + reqNum + ' token=' + token); 159 160 /** 161 * Validate parameters 162 */ 163 rilErrCode = RIL_E_SUCCESS; 164 if (typeof reqNum != 'number') { 165 print('onRilRequest: reqNum is not a number'); 166 rilErrCode = RIL_E_GENERIC_FAILURE; 167 } 168 if (typeof token != 'number') { 169 print('onRilRequest: token is not a number'); 170 rilErrCode = RIL_E_GENERIC_FAILURE; 171 } 172 if (typeof requestProtobuf != 'object') { 173 print('onRilRequest: requestProtobuf is not an object'); 174 rilErrCode = RIL_E_GENERIC_FAILURE; 175 } 176 if (rilErrCode != RIL_E_SUCCESS) { 177 sendRilRequestComplete(rilErrCode, reqNum, token); 178 return 'onRilRequest X: invalid parameter'; 179 } 180 181 try { 182 //print('onRilRequest: get entry from dispatchTable reqNum=' + reqNum); 183 entry = dispatchTable[reqNum]; 184 if (typeof entry == 'undefined') { 185 throw ('entry = dispatchTable[' + reqNum + '] was undefined'); 186 } else { 187 req = new Request(reqNum, token, requestProtobuf, rilSchema, entry.schemaName); 188 for(i = 0; i < entry.components.length; i++) { 189 entry.components[i].add(req); 190 } 191 } 192 } catch (err) { 193 print('onRilRequest: Unknown reqNum=' + reqNum + ' err=' + err); 194 sendRilRequestComplete(RIL_E_REQUEST_NOT_SUPPORTED, reqNum, token); 195 } 196 // print('onRilRequest X: reqNum=' + reqNum + ' token=' + token); 197 } catch (err) { 198 print('onRilRequest X: Exception err=' + err); 199 return('onRilRequest X: Exception err=' + err); 200 } 201 return 'onRilRequest X'; 202} 203 204function onUnsolicitedTick(tick) { 205 print('onUnsolicitedTick EX tick=' + tick); 206 return 3; 207} 208 209/** 210 * Dispatch table for requests 211 * 212 * Each table entry is index by the RIL_REQUEST_xxxx 213 * and contains an array of components this request 214 * is to be sent to and the name of the schema 215 * that converts the incoming protobuf to the 216 * appropriate request data. 217 * 218 * DispatchTable[RIL_REQUEST_xxx].components = Array of components 219 * DisptachTable[RIL_REQUEST_xxx].Entry.schemaName = 'Name-of-schema'; 220 */ 221var dispatchTable = new Array(); 222 223dispatchTable[RIL_REQUEST_GET_SIM_STATUS] = { // 1 224 'components' : [simulatedIccWorker], 225 'schemaName' : 'ReqGetSimStatus', 226}; 227dispatchTable[RIL_REQUEST_ENTER_SIM_PIN] = { // 2 228 'components' : [simulatedIccWorker], 229 'schemaName' : 'ReqEnterSimPin', 230}; 231dispatchTable[RIL_REQUEST_GET_CURRENT_CALLS] = { // 9 232 'components' : [simulatedRadioWorker], 233}; 234dispatchTable[RIL_REQUEST_DIAL] = { // 10 235 'components' : [simulatedRadioWorker], 236 'schemaName' : 'ReqDial', 237}; 238dispatchTable[RIL_REQUEST_GET_IMSI] = { // 11 239 'components' : [simulatedIccWorker], 240}; 241dispatchTable[RIL_REQUEST_HANGUP] = { // 12 242 'components' : [simulatedRadioWorker], 243 'schemaName' : 'ReqHangUp', 244}; 245dispatchTable[RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND] = { // 13 246 'components' : [simulatedRadioWorker], 247}; 248dispatchTable[RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = { // 14 249 'components' : [simulatedRadioWorker], 250}; 251dispatchTable[RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = { // 15 252 'components' : [simulatedRadioWorker], 253}; 254dispatchTable[RIL_REQUEST_CONFERENCE] = { // 16 255 'components' : [simulatedRadioWorker], 256}; 257dispatchTable[RIL_REQUEST_LAST_CALL_FAIL_CAUSE] = { // 18 258 'components' : [simulatedRadioWorker], 259}; 260dispatchTable[RIL_REQUEST_SIGNAL_STRENGTH] = { // 19 261 'components' : [simulatedRadioWorker], 262}; 263dispatchTable[RIL_REQUEST_REGISTRATION_STATE] = { // 20 264 'components' : [simulatedRadioWorker], 265}; 266dispatchTable[RIL_REQUEST_GPRS_REGISTRATION_STATE] = { // 21 267 'components' : [simulatedRadioWorker], 268}; 269dispatchTable[RIL_REQUEST_OPERATOR] = { // 22 270 'components' : [simulatedIccWorker], 271}; 272dispatchTable[RIL_REQUEST_GET_IMEI] = { // 38 273 'components' : [simulatedIccWorker], 274}; 275dispatchTable[RIL_REQUEST_GET_IMEISV] = { // 39 276 'components' : [simulatedIccWorker], 277}; 278dispatchTable[RIL_REQUEST_ANSWER] = { // 40 279 'components' : [simulatedRadioWorker], 280}; 281dispatchTable[RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE] = { // 45 282 'components' : [simulatedRadioWorker], 283}; 284dispatchTable[RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = { // 46 285 'components' : [simulatedRadioWorker], 286}; 287dispatchTable[RIL_REQUEST_BASEBAND_VERSION] = { // 51 288 'components' : [simulatedRadioWorker], 289}; 290dispatchTable[RIL_REQUEST_SEPARATE_CONNECTION] = { // 52 291 'components' : [simulatedRadioWorker], 292 'schemaName' : 'ReqSeparateConnection', 293}; 294dispatchTable[RIL_REQUEST_SET_MUTE ] = { // 53 295 'components' : [simulatedRadioWorker], 296 'schemaName' : 'ReqSetMute', 297}; 298dispatchTable[RIL_REQUEST_SCREEN_STATE] = { // 61 299 'components' : [simulatedRadioWorker], 300 'schemaName' : 'ReqScreenState', 301}; 302 303/** 304 * Start the mock rill after loading 305 */ 306function startMockRil() { 307 print("startMockRil E:"); 308 setRadioState(RADIOSTATE_SIM_READY); 309 // send the signal strength after 5 seconds, wait until mock ril is started 310 simulatedRadioWorker.addDelayed({ 311 'reqNum' : CMD_UNSOL_SIGNAL_STRENGTH}, 5000); 312 print("startMockRil X:"); 313} 314 315/** 316 * Optional tests 317 */ 318if (false) { 319 include("mock_ril_tests.js"); 320} 321