michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: } michael@0: michael@0: function _getWorker() { michael@0: let _postedMessage; michael@0: let _worker = newWorker({ michael@0: postRILMessage: function(data) { michael@0: }, michael@0: postMessage: function(message) { michael@0: _postedMessage = message; michael@0: } michael@0: }); michael@0: return { michael@0: get postedMessage() { michael@0: return _postedMessage; michael@0: }, michael@0: get worker() { michael@0: return _worker; michael@0: } michael@0: }; michael@0: } michael@0: michael@0: /* michael@0: * Helper function to covert a HEX string to a byte array. michael@0: * michael@0: * @param hexString michael@0: * A hexadecimal string of which the length is even. michael@0: */ michael@0: function hexStringToBytes(hexString) { michael@0: let bytes = []; michael@0: michael@0: let length = hexString.length; michael@0: michael@0: for (let i = 0; i < length; i += 2) { michael@0: bytes.push(Number.parseInt(hexString.substr(i, 2), 16)); michael@0: } michael@0: michael@0: return bytes; michael@0: } michael@0: michael@0: /* michael@0: * Helper function to covert a byte array to a HEX string. michael@0: * michael@0: * @param bytes michael@0: * Could be a regular byte array or Uint8Array. michael@0: */ michael@0: function bytesToHexString(bytes) { michael@0: let hexString = ""; michael@0: let hex; michael@0: michael@0: for (let i = 0; i < bytes.length; i++) { michael@0: hex = bytes[i].toString(16).toUpperCase(); michael@0: if (hex.length === 1) { michael@0: hexString += "0"; michael@0: } michael@0: hexString += hex; michael@0: } michael@0: michael@0: return hexString; michael@0: } michael@0: michael@0: /* michael@0: * Helper function to ecode Opaque UserData michael@0: * michael@0: * @param msg_type michael@0: * PDU_CDMA_MSG_TYPE_SUBMIT or PDU_CDMA_MSG_TYPE_DELIVER michael@0: * @param data michael@0: * The byte array of opaque data to be encoded. michael@0: */ michael@0: function encodeOpaqueUserData(bitBufferHelper, options) { michael@0: let bearerDataBuffer = []; michael@0: bitBufferHelper.startWrite(bearerDataBuffer); michael@0: michael@0: // Msg-Id michael@0: bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_MSG_ID, 8); michael@0: bitBufferHelper.writeBits(3, 8); michael@0: bitBufferHelper.writeBits(options.msg_type, 4); // MSG_TYPE michael@0: bitBufferHelper.writeBits(1, 16); // MSG_ID michael@0: bitBufferHelper.flushWithPadding(); // HEADER_IND (1) + RESERVED (3) michael@0: michael@0: // User Data michael@0: bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_BODY, 8); michael@0: let dataLength = options.data.length; michael@0: bitBufferHelper.writeBits(2 + dataLength, 8); // 2 bytes for MSG_ENCODING, NUM_FIELDS michael@0: bitBufferHelper.writeBits(PDU_CDMA_MSG_CODING_OCTET, 5); //MSG_ENCODING michael@0: // MSG_TYPE is omitted if MSG_ENCODING is CODING_OCTET michael@0: bitBufferHelper.writeBits(dataLength, 8); // NUM_FIELDS michael@0: for (let i = 0; i < dataLength; i++) { // CHARi michael@0: bitBufferHelper.writeBits(options.data[i], 8); michael@0: } michael@0: bitBufferHelper.flushWithPadding(); // RESERVED (3 filling bits) michael@0: michael@0: return bearerDataBuffer; michael@0: } michael@0: michael@0: function newSmsParcel(cdmaPduHelper, pdu) { michael@0: return newIncomingParcel(-1, michael@0: RESPONSE_TYPE_UNSOLICITED, michael@0: UNSOLICITED_RESPONSE_CDMA_NEW_SMS, michael@0: pduToParcelData(cdmaPduHelper, pdu)); michael@0: } michael@0: michael@0: /* michael@0: * Helper function to encode PDU into Parcel. michael@0: * See ril_cdma_sms.h for the structure definition of RIL_CDMA_SMS_Message michael@0: * michael@0: * @param teleservice michael@0: * The Teleservice-Id of this PDU. michael@0: * See PDU_CDMA_MSG_TELESERIVCIE_ID_XXX in ril_const.js. michael@0: * @param address michael@0: * The Orginating or Destinating address. michael@0: * @param bearerData michael@0: * The byte array of the encoded bearer data. michael@0: */ michael@0: function pduToParcelData(cdmaPduHelper, pdu) { michael@0: michael@0: let addrInfo = cdmaPduHelper.encodeAddr(pdu.address); michael@0: // Teleservice, isServicePresent, ServiceCategory, michael@0: // addrInfo {digitMode, numberMode, numberType, numberPlan, address.length, address} michael@0: // Sub Address michael@0: // bearerData length, bearerData. michael@0: let dataLength = 4 + 4 + 4 michael@0: + (5 + addrInfo.address.length) * 4 michael@0: + 3 * 4 michael@0: + 4 + pdu.bearerData.length * 4; michael@0: michael@0: let data = new Uint8Array(dataLength); michael@0: let offset = 0; michael@0: michael@0: function writeInt(value) { michael@0: data[offset++] = value & 0xFF; michael@0: data[offset++] = (value >> 8) & 0xFF; michael@0: data[offset++] = (value >> 16) & 0xFF; michael@0: data[offset++] = (value >> 24) & 0xFF; michael@0: } michael@0: michael@0: function writeByte(value) { michael@0: data[offset++] = value & 0xFF; michael@0: data[offset++] = 0; michael@0: data[offset++] = 0; michael@0: data[offset++] = 0; michael@0: } michael@0: michael@0: // Teleservice michael@0: writeInt(pdu.teleservice); michael@0: michael@0: // isServicePresent michael@0: writeByte(0); michael@0: michael@0: // ServiceCategory michael@0: writeInt(PDU_CDMA_MSG_CATEGORY_UNSPEC); michael@0: michael@0: // AddrInfo michael@0: writeByte(addrInfo.digitMode); michael@0: writeByte(addrInfo.numberMode); michael@0: writeByte(addrInfo.numberType); michael@0: writeByte(addrInfo.numberPlan); michael@0: let addressLength = addrInfo.address.length; michael@0: writeByte(addressLength); michael@0: for (let i = 0; i < addressLength; i++) { michael@0: writeByte(addrInfo.address[i]); michael@0: } michael@0: michael@0: // Subaddress michael@0: writeByte(0); michael@0: writeByte(0); michael@0: writeByte(0); michael@0: michael@0: // Bearer Data Length michael@0: let dataLength = pdu.bearerData.length; michael@0: writeByte(dataLength); michael@0: michael@0: // Bearer Data michael@0: for (let i = 0; i < dataLength; i++) { michael@0: writeByte(pdu.bearerData[i]); michael@0: } michael@0: michael@0: return data; michael@0: } michael@0: michael@0: /** michael@0: * Verify CDMA SMS Delivery ACK Message. michael@0: */ michael@0: add_test(function test_processCdmaSmsStatusReport() { michael@0: let workerHelper = _getWorker(); michael@0: let worker = workerHelper.worker; michael@0: let context = worker.ContextPool._contexts[0]; michael@0: michael@0: function test_StatusReport(errorClass, msgStatus) { michael@0: let msgId = 0; michael@0: let sentSmsMap = context.RIL._pendingSentSmsMap; michael@0: michael@0: sentSmsMap[msgId] = {}; michael@0: michael@0: let message = { michael@0: SMSC: "", michael@0: mti: 0, michael@0: udhi: 0, michael@0: sender: "0987654321", michael@0: recipient: null, michael@0: pid: PDU_PID_DEFAULT, michael@0: epid: PDU_PID_DEFAULT, michael@0: dcs: 0, michael@0: mwi: null, michael@0: replace: false, michael@0: header: null, michael@0: body: "Status: Sent, Dest: 0987654321", michael@0: data: null, michael@0: timestamp: new Date().valueOf(), michael@0: language: null, michael@0: status: null, michael@0: scts: null, michael@0: dt: null, michael@0: encoding: PDU_CDMA_MSG_CODING_7BITS_ASCII, michael@0: messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], michael@0: messageType: PDU_CDMA_MSG_TYPE_P2P, michael@0: serviceCategory: 0, michael@0: subMsgType: PDU_CDMA_MSG_TYPE_DELIVER_ACK, michael@0: msgId: msgId, michael@0: errorClass: errorClass, michael@0: msgStatus: msgStatus michael@0: }; michael@0: michael@0: context.RIL._processCdmaSmsStatusReport(message); michael@0: michael@0: let postedMessage = workerHelper.postedMessage; michael@0: michael@0: // Check if pending token is removed. michael@0: do_check_true((errorClass === 2) ? !!sentSmsMap[msgId] : !sentSmsMap[msgId]); michael@0: michael@0: // Check the response message accordingly. michael@0: if (errorClass === -1) { michael@0: // Check if the report is treated as normal incoming SMS michael@0: do_check_eq("sms-received", postedMessage.rilMessageType); michael@0: } else if (errorClass === 2) { michael@0: // Do nothing. michael@0: } else { michael@0: // Check Delivery Status michael@0: if (errorClass === 0) { michael@0: do_check_eq(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_SUCCESS); michael@0: } else { michael@0: do_check_eq(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_ERROR); michael@0: } michael@0: } michael@0: } michael@0: michael@0: test_StatusReport(-1, -1); // Message Status Sub-parameter is absent. michael@0: test_StatusReport(0, 0); // 00|000000: no error|Message accepted michael@0: test_StatusReport(2, 4); // 10|000100: temporary condition|Network congestion michael@0: test_StatusReport(3, 5); // 11|000101: permanent condition|Network error michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify WAP Push over CDMA SMS Message. michael@0: */ michael@0: add_test(function test_processCdmaSmsWapPush() { michael@0: let workerHelper = _getWorker(), michael@0: worker = workerHelper.worker, michael@0: context = worker.ContextPool._contexts[0], michael@0: bitBufferHelper = context.BitBufferHelper, michael@0: cdmaPduHelper = context.CdmaPDUHelper; michael@0: michael@0: function test_CdmaSmsWapPdu(wdpData, reversed) { michael@0: let orig_address = "0987654321", michael@0: hexString, michael@0: fullDataHexString = ""; michael@0: michael@0: for (let i = 0; i < wdpData.length; i++) { michael@0: let dataIndex = (reversed) ? (wdpData.length - i - 1) : i; michael@0: hexString = "00"; // MSG_TYPE michael@0: hexString += bytesToHexString([wdpData.length]); // TOTAL_SEG michael@0: hexString += bytesToHexString([dataIndex]); // SEG_NUM (zero-based) michael@0: if ((dataIndex === 0)) { michael@0: hexString += "23F00B84"; // SOURCE_PORT, DEST_PORT for 1st segment michael@0: } michael@0: hexString += wdpData[dataIndex]; // WDP DATA michael@0: michael@0: do_print("hexString: " + hexString); michael@0: michael@0: fullDataHexString += wdpData[i]; michael@0: michael@0: let pdu = { michael@0: teleservice: PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, michael@0: address: orig_address, michael@0: bearerData: encodeOpaqueUserData(bitBufferHelper, michael@0: { msg_type: PDU_CDMA_MSG_TYPE_DELIVER, michael@0: data: hexStringToBytes(hexString) }) michael@0: }; michael@0: michael@0: worker.onRILMessage(0, newSmsParcel(cdmaPduHelper, pdu)); michael@0: } michael@0: michael@0: let postedMessage = workerHelper.postedMessage; michael@0: michael@0: do_print("fullDataHexString: " + fullDataHexString); michael@0: michael@0: do_check_eq("sms-received", postedMessage.rilMessageType); michael@0: do_check_eq(PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, postedMessage.teleservice); michael@0: do_check_eq(orig_address, postedMessage.sender); michael@0: do_check_eq(0x23F0, postedMessage.header.originatorPort); michael@0: do_check_eq(0x0B84, postedMessage.header.destinationPort); michael@0: do_check_eq(fullDataHexString, bytesToHexString(postedMessage.data)); michael@0: } michael@0: michael@0: // Verify Single WAP PDU michael@0: test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F"]); michael@0: michael@0: run_next_test(); michael@0: });