michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: "use strict"; michael@0: michael@0: let RIL = {}; michael@0: SpecialPowers.Cu.import("resource://gre/modules/ril_consts.js", RIL); michael@0: michael@0: // Only bring in what we need from ril_worker/RadioInterfaceLayer here. Reusing michael@0: // that code turns out to be a nightmare, so there is some code duplication. michael@0: let PDUBuilder = { michael@0: toHexString: function(n, length) { michael@0: let str = n.toString(16); michael@0: if (str.length < length) { michael@0: for (let i = 0; i < length - str.length; i++) { michael@0: str = "0" + str; michael@0: } michael@0: } michael@0: return str.toUpperCase(); michael@0: }, michael@0: michael@0: writeUint16: function(value) { michael@0: this.buf += (value & 0xff).toString(16).toUpperCase(); michael@0: this.buf += ((value >> 8) & 0xff).toString(16).toUpperCase(); michael@0: }, michael@0: michael@0: writeHexOctet: function(octet) { michael@0: this.buf += this.toHexString(octet, 2); michael@0: }, michael@0: michael@0: writeSwappedNibbleBCD: function(data) { michael@0: data = data.toString(); michael@0: let zeroCharCode = '0'.charCodeAt(0); michael@0: michael@0: for (let i = 0; i < data.length; i += 2) { michael@0: let low = data.charCodeAt(i) - zeroCharCode; michael@0: let high; michael@0: if (i + 1 < data.length) { michael@0: high = data.charCodeAt(i + 1) - zeroCharCode; michael@0: } else { michael@0: high = 0xF; michael@0: } michael@0: michael@0: this.writeHexOctet((high << 4) | low); michael@0: } michael@0: }, michael@0: michael@0: writeStringAsSeptets: function(message, paddingBits, langIndex, michael@0: langShiftIndex) { michael@0: const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex]; michael@0: const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex]; michael@0: michael@0: let dataBits = paddingBits; michael@0: let data = 0; michael@0: for (let i = 0; i < message.length; i++) { michael@0: let septet = langTable.indexOf(message[i]); michael@0: if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) { michael@0: continue; michael@0: } michael@0: michael@0: if (septet >= 0) { michael@0: data |= septet << dataBits; michael@0: dataBits += 7; michael@0: } else { michael@0: septet = langShiftTable.indexOf(message[i]); michael@0: if (septet == -1) { michael@0: throw new Error(message[i] + " not in 7 bit alphabet " michael@0: + langIndex + ":" + langShiftIndex + "!"); michael@0: } michael@0: michael@0: if (septet == RIL.PDU_NL_RESERVED_CONTROL) { michael@0: continue; michael@0: } michael@0: michael@0: data |= RIL.PDU_NL_EXTENDED_ESCAPE << dataBits; michael@0: dataBits += 7; michael@0: data |= septet << dataBits; michael@0: dataBits += 7; michael@0: } michael@0: michael@0: for (; dataBits >= 8; dataBits -= 8) { michael@0: this.writeHexOctet(data & 0xFF); michael@0: data >>>= 8; michael@0: } michael@0: } michael@0: michael@0: if (dataBits != 0) { michael@0: this.writeHexOctet(data & 0xFF); michael@0: } michael@0: }, michael@0: michael@0: buildAddress: function(address) { michael@0: let addressFormat = RIL.PDU_TOA_ISDN; // 81 michael@0: if (address[0] == '+') { michael@0: addressFormat = RIL.PDU_TOA_INTERNATIONAL | RIL.PDU_TOA_ISDN; // 91 michael@0: address = address.substring(1); michael@0: } michael@0: michael@0: this.buf = ""; michael@0: this.writeHexOctet(address.length); michael@0: this.writeHexOctet(addressFormat); michael@0: this.writeSwappedNibbleBCD(address); michael@0: michael@0: return this.buf; michael@0: }, michael@0: michael@0: // assumes 7 bit encoding michael@0: buildUserData: function(options) { michael@0: let headerLength = 0; michael@0: this.buf = ""; michael@0: if (options.headers) { michael@0: for each (let header in options.headers) { michael@0: headerLength += 2; // id + length octets michael@0: if (header.octets) { michael@0: headerLength += header.octets.length; michael@0: } michael@0: }; michael@0: } michael@0: michael@0: let encodedBodyLength = options.body.length; michael@0: let headerOctets = (headerLength ? headerLength + 1 : 0); michael@0: michael@0: let paddingBits; michael@0: let userDataLengthInSeptets; michael@0: let headerSeptets = Math.ceil(headerOctets * 8 / 7); michael@0: userDataLengthInSeptets = headerSeptets + encodedBodyLength; michael@0: paddingBits = headerSeptets * 7 - headerOctets * 8; michael@0: michael@0: this.writeHexOctet(userDataLengthInSeptets); michael@0: if (options.headers) { michael@0: this.writeHexOctet(headerLength); michael@0: michael@0: for each (let header in options.headers) { michael@0: this.writeHexOctet(header.id); michael@0: this.writeHexOctet(header.length); michael@0: michael@0: if (header.octets) { michael@0: for each (let octet in header.octets) { michael@0: this.writeHexOctet(octet); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: this.writeStringAsSeptets(options.body, paddingBits, michael@0: RIL.PDU_NL_IDENTIFIER_DEFAULT, michael@0: RIL.PDU_NL_IDENTIFIER_DEFAULT); michael@0: return this.buf; michael@0: } michael@0: };