yoctolib-esm
Version:
Yoctopuce library for TypeScript/JavaScript, as an ECMAScript 2015 module
1,554 lines • 75.6 kB
JavaScript
/*********************************************************************
*
* $Id: yocto_messagebox.ts 63482 2024-11-26 09:29:16Z seb $
*
* Implements the high-level API for Sms functions
*
* - - - - - - - - - License information: - - - - - - - - -
*
* Copyright (C) 2011 and beyond by Yoctopuce Sarl, Switzerland.
*
* Yoctopuce Sarl (hereafter Licensor) grants to you a perpetual
* non-exclusive license to use, modify, copy and integrate this
* file into your software for the sole purpose of interfacing
* with Yoctopuce products.
*
* You may reproduce and distribute copies of this file in
* source or object form, as long as the sole purpose of this
* code is to interface with Yoctopuce products. You must retain
* this notice in the distributed source file.
*
* You should refer to Yoctopuce General Terms and Conditions
* for additional information regarding your rights and
* obligations.
*
* THE SOFTWARE AND DOCUMENTATION ARE PROVIDED 'AS IS' WITHOUT
* WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO
* EVENT SHALL LICENSOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
* COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR
* SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT
* LIMITED TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR
* CONTRIBUTION, OR OTHER SIMILAR COSTS, WHETHER ASSERTED ON THE
* BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF
* WARRANTY, OR OTHERWISE.
*
*********************************************************************/
import { YAPI, YAPIContext, YFunction } from './yocto_api.js';
//--- (generated code: YSms class start)
/**
* YSms Class: SMS message sent or received, returned by messageBox.get_messages or messageBox.newMessage
*
* YSms objects are used to describe an SMS message, received or to be sent.
* These objects are used in particular in conjunction with the YMessageBox class.
*/
//--- (end of generated code: YSms class start)
export class YSms {
// API symbols as static members
//--- (end of generated code: YSms attributes declaration)
constructor(obj_mbox) {
this._slot = 0;
this._deliv = false;
this._smsc = '';
this._mref = 0;
this._orig = '';
this._dest = '';
this._pid = 0;
this._alphab = 0;
this._mclass = 0;
this._stamp = '';
this._udh = new Uint8Array(0);
this._udata = new Uint8Array(0);
this._npdu = 0;
this._pdu = new Uint8Array(0);
this._parts = [];
this._aggSig = '';
this._aggIdx = 0;
this._aggCnt = 0;
//--- (generated code: YSms constructor)
//--- (end of generated code: YSms constructor)
this._yapi = obj_mbox._yapi;
this._mbox = obj_mbox;
}
//--- (generated code: YSms implementation)
async get_slot() {
return this._slot;
}
async get_smsc() {
return this._smsc;
}
async get_msgRef() {
return this._mref;
}
async get_sender() {
return this._orig;
}
async get_recipient() {
return this._dest;
}
async get_protocolId() {
return this._pid;
}
async isReceived() {
return this._deliv;
}
async get_alphabet() {
return this._alphab;
}
async get_msgClass() {
if ((this._mclass & 16) == 0) {
return -1;
}
return (this._mclass & 3);
}
async get_dcs() {
return (this._mclass | ((this._alphab << 2)));
}
async get_timestamp() {
return this._stamp;
}
async get_userDataHeader() {
return this._udh;
}
async get_userData() {
return this._udata;
}
/**
* Returns the content of the message.
*
* @return a string with the content of the message.
*/
async get_textData() {
let isolatin;
let isosize;
let i;
if (this._alphab == 0) {
// using GSM standard 7-bit alphabet
return await this._mbox.gsm2str(this._udata);
}
if (this._alphab == 2) {
// using UCS-2 alphabet
isosize = (((this._udata).length) >> 1);
isolatin = new Uint8Array(isosize);
i = 0;
while (i < isosize) {
isolatin.set([this._udata[2 * i + 1]], i);
i = i + 1;
}
return this._yapi.imm_bin2str(isolatin);
}
// default: convert 8 bit to string as-is
return this._yapi.imm_bin2str(this._udata);
}
async get_unicodeData() {
let res = [];
let unisize;
let unival;
let i;
if (this._alphab == 0) {
// using GSM standard 7-bit alphabet
return await this._mbox.gsm2unicode(this._udata);
}
if (this._alphab == 2) {
// using UCS-2 alphabet
unisize = (((this._udata).length) >> 1);
res.length = 0;
i = 0;
while (i < unisize) {
unival = 256 * this._udata[2 * i] + this._udata[2 * i + 1];
res.push(unival);
i = i + 1;
}
}
else {
// return straight 8-bit values
unisize = (this._udata).length;
res.length = 0;
i = 0;
while (i < unisize) {
res.push(this._udata[i] + 0);
i = i + 1;
}
}
return res;
}
async get_partCount() {
if (this._npdu == 0) {
await this.generatePdu();
}
return this._npdu;
}
async get_pdu() {
if (this._npdu == 0) {
await this.generatePdu();
}
return this._pdu;
}
async get_parts() {
if (this._npdu == 0) {
await this.generatePdu();
}
return this._parts;
}
async get_concatSignature() {
if (this._npdu == 0) {
await this.generatePdu();
}
return this._aggSig;
}
async get_concatIndex() {
if (this._npdu == 0) {
await this.generatePdu();
}
return this._aggIdx;
}
async get_concatCount() {
if (this._npdu == 0) {
await this.generatePdu();
}
return this._aggCnt;
}
async set_slot(val) {
this._slot = val;
return YAPI.SUCCESS;
}
async set_received(val) {
this._deliv = val;
return YAPI.SUCCESS;
}
async set_smsc(val) {
this._smsc = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_msgRef(val) {
this._mref = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_sender(val) {
this._orig = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_recipient(val) {
this._dest = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_protocolId(val) {
this._pid = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_alphabet(val) {
this._alphab = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_msgClass(val) {
if (val == -1) {
this._mclass = 0;
}
else {
this._mclass = 16 + val;
}
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_dcs(val) {
this._alphab = (((val >> 2)) & 3);
this._mclass = (val & (16 + 3));
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_timestamp(val) {
this._stamp = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async set_userDataHeader(val) {
this._udh = val;
this._npdu = 0;
await this.parseUserDataHeader();
return YAPI.SUCCESS;
}
async set_userData(val) {
this._udata = val;
this._npdu = 0;
return YAPI.SUCCESS;
}
async convertToUnicode() {
let ucs2 = [];
let udatalen;
let i;
let uni;
if (this._alphab == 2) {
return YAPI.SUCCESS;
}
if (this._alphab == 0) {
ucs2 = await this._mbox.gsm2unicode(this._udata);
}
else {
udatalen = (this._udata).length;
ucs2.length = 0;
i = 0;
while (i < udatalen) {
uni = this._udata[i];
ucs2.push(uni);
i = i + 1;
}
}
this._alphab = 2;
this._udata = new Uint8Array(0);
await this.addUnicodeData(ucs2);
return YAPI.SUCCESS;
}
/**
* Add a regular text to the SMS. This function support messages
* of more than 160 characters. ISO-latin accented characters
* are supported. For messages with special unicode characters such as asian
* characters and emoticons, use the addUnicodeData method.
*
* @param val : the text to be sent in the message
*
* @return YAPI.SUCCESS when the call succeeds.
*/
async addText(val) {
let udata;
let udatalen;
let newdata;
let newdatalen;
let i;
if ((val).length == 0) {
return YAPI.SUCCESS;
}
if (this._alphab == 0) {
// Try to append using GSM 7-bit alphabet
newdata = await this._mbox.str2gsm(val);
newdatalen = (newdata).length;
if (newdatalen == 0) {
// 7-bit not possible, switch to unicode
await this.convertToUnicode();
newdata = this._yapi.imm_str2bin(val);
newdatalen = (newdata).length;
}
}
else {
newdata = this._yapi.imm_str2bin(val);
newdatalen = (newdata).length;
}
udatalen = (this._udata).length;
if (this._alphab == 2) {
// Append in unicode directly
udata = new Uint8Array(udatalen + 2 * newdatalen);
i = 0;
while (i < udatalen) {
udata.set([this._udata[i]], i);
i = i + 1;
}
i = 0;
while (i < newdatalen) {
udata.set([newdata[i]], udatalen + 1);
udatalen = udatalen + 2;
i = i + 1;
}
}
else {
// Append binary buffers
udata = new Uint8Array(udatalen + newdatalen);
i = 0;
while (i < udatalen) {
udata.set([this._udata[i]], i);
i = i + 1;
}
i = 0;
while (i < newdatalen) {
udata.set([newdata[i]], udatalen);
udatalen = udatalen + 1;
i = i + 1;
}
}
return await this.set_userData(udata);
}
/**
* Add a unicode text to the SMS. This function support messages
* of more than 160 characters, using SMS concatenation.
*
* @param val : an array of special unicode characters
*
* @return YAPI.SUCCESS when the call succeeds.
*/
async addUnicodeData(val) {
let arrlen;
let newdatalen;
let i;
let uni;
let udata;
let udatalen;
let surrogate;
if (this._alphab != 2) {
await this.convertToUnicode();
}
// compute number of 16-bit code units
arrlen = val.length;
newdatalen = arrlen;
i = 0;
while (i < arrlen) {
uni = val[i];
if (uni > 65535) {
newdatalen = newdatalen + 1;
}
i = i + 1;
}
// now build utf-16 buffer
udatalen = (this._udata).length;
udata = new Uint8Array(udatalen + 2 * newdatalen);
i = 0;
while (i < udatalen) {
udata.set([this._udata[i]], i);
i = i + 1;
}
i = 0;
while (i < arrlen) {
uni = val[i];
if (uni >= 65536) {
surrogate = uni - 65536;
uni = (((surrogate >> 10) & 1023)) + 55296;
udata.set([(uni >> 8)], udatalen);
udata.set([(uni & 255)], udatalen + 1);
udatalen = udatalen + 2;
uni = ((surrogate & 1023)) + 56320;
}
udata.set([(uni >> 8)], udatalen);
udata.set([(uni & 255)], udatalen + 1);
udatalen = udatalen + 2;
i = i + 1;
}
return await this.set_userData(udata);
}
async set_pdu(pdu) {
this._pdu = pdu;
this._npdu = 1;
return await this.parsePdu(pdu);
}
async set_parts(parts) {
let sorted = [];
let partno;
let initpartno;
let i;
let retcode;
let totsize;
let subsms;
let subdata;
let res;
this._npdu = parts.length;
if (this._npdu == 0) {
return YAPI.INVALID_ARGUMENT;
}
sorted.length = 0;
partno = 0;
while (partno < this._npdu) {
initpartno = partno;
i = 0;
while (i < this._npdu) {
subsms = parts[i];
if (await subsms.get_concatIndex() == partno) {
sorted.push(subsms);
partno = partno + 1;
}
i = i + 1;
}
if (initpartno == partno) {
partno = partno + 1;
}
}
this._parts = sorted;
// inherit header fields from first part
subsms = this._parts[0];
retcode = await this.parsePdu(await subsms.get_pdu());
if (retcode != YAPI.SUCCESS) {
return retcode;
}
this._npdu = sorted.length;
// concatenate user data from all parts
totsize = 0;
partno = 0;
while (partno < this._parts.length) {
subsms = this._parts[partno];
subdata = await subsms.get_userData();
totsize = totsize + (subdata).length;
partno = partno + 1;
}
res = new Uint8Array(totsize);
totsize = 0;
partno = 0;
while (partno < this._parts.length) {
subsms = this._parts[partno];
subdata = await subsms.get_userData();
i = 0;
while (i < (subdata).length) {
res.set([subdata[i]], totsize);
totsize = totsize + 1;
i = i + 1;
}
partno = partno + 1;
}
this._udata = res;
return YAPI.SUCCESS;
}
async encodeAddress(addr) {
let bytes;
let srclen;
let numlen;
let i;
let val;
let digit;
let res;
bytes = this._yapi.imm_str2bin(addr);
srclen = (bytes).length;
numlen = 0;
i = 0;
while (i < srclen) {
val = bytes[i];
if ((val >= 48) && (val < 58)) {
numlen = numlen + 1;
}
i = i + 1;
}
if (numlen == 0) {
res = new Uint8Array(1);
res.set([0], 0);
return res;
}
res = new Uint8Array(2 + ((numlen + 1) >> 1));
res.set([numlen], 0);
if (bytes[0] == 43) {
res.set([145], 1);
}
else {
res.set([129], 1);
}
numlen = 4;
digit = 0;
i = 0;
while (i < srclen) {
val = bytes[i];
if ((val >= 48) && (val < 58)) {
if ((numlen & 1) == 0) {
digit = val - 48;
}
else {
res.set([digit + 16 * (val - 48)], (numlen >> 1));
}
numlen = numlen + 1;
}
i = i + 1;
}
// pad with F if needed
if ((numlen & 1) != 0) {
res.set([digit + 240], (numlen >> 1));
}
return res;
}
async decodeAddress(addr, ofs, siz) {
let addrType;
let gsm7;
let res;
let i;
let rpos;
let carry;
let nbits;
let byt;
if (siz == 0) {
return '';
}
res = '';
addrType = (addr[ofs] & 112);
if (addrType == 80) {
// alphanumeric number
siz = (((4 * siz) / (7)) >> 0);
gsm7 = new Uint8Array(siz);
rpos = 1;
carry = 0;
nbits = 0;
i = 0;
while (i < siz) {
if (nbits == 7) {
gsm7.set([carry], i);
carry = 0;
nbits = 0;
}
else {
byt = addr[ofs + rpos];
rpos = rpos + 1;
gsm7.set([(carry | (((byt << nbits)) & 127))], i);
carry = (byt >> (7 - nbits));
nbits = nbits + 1;
}
i = i + 1;
}
return await this._mbox.gsm2str(gsm7);
}
else {
// standard phone number
if (addrType == 16) {
res = '+';
}
siz = ((siz + 1) >> 1);
i = 0;
while (i < siz) {
byt = addr[ofs + i + 1];
res = res + '' + ((byt & 15)).toString(16).toLowerCase() + '' + ((byt >> 4)).toString(16).toLowerCase();
i = i + 1;
}
// remove padding digit if needed
if (((addr[ofs + siz]) >> 4) == 15) {
res = res.substr(0, (res).length - 1);
}
return res;
}
}
async encodeTimeStamp(exp) {
let explen;
let i;
let res;
let n;
let expasc;
let v1;
let v2;
explen = (exp).length;
if (explen == 0) {
res = new Uint8Array(0);
return res;
}
if (exp.substr(0, 1) == '+') {
n = YAPIContext.imm_atoi(exp.substr(1, explen - 1));
res = new Uint8Array(1);
if (n > 30 * 86400) {
n = 192 + ((((n + 6 * 86400)) / ((7 * 86400))) >> 0);
}
else {
if (n > 86400) {
n = 166 + ((((n + 86399)) / (86400)) >> 0);
}
else {
if (n > 43200) {
n = 143 + ((((n - 43200 + 1799)) / (1800)) >> 0);
}
else {
n = -1 + ((((n + 299)) / (300)) >> 0);
}
}
}
if (n < 0) {
n = 0;
}
res.set([n], 0);
return res;
}
if (exp.substr(4, 1) == '-' || exp.substr(4, 1) == '/') {
// ignore century
exp = exp.substr(2, explen - 2);
explen = (exp).length;
}
expasc = this._yapi.imm_str2bin(exp);
res = new Uint8Array(7);
n = 0;
i = 0;
while ((i + 1 < explen) && (n < 7)) {
v1 = expasc[i];
if ((v1 >= 48) && (v1 < 58)) {
v2 = expasc[i + 1];
if ((v2 >= 48) && (v2 < 58)) {
v1 = v1 - 48;
v2 = v2 - 48;
res.set([((v2 << 4)) + v1], n);
n = n + 1;
i = i + 1;
}
}
i = i + 1;
}
while (n < 7) {
res.set([0], n);
n = n + 1;
}
if (i + 2 < explen) {
// convert for timezone in cleartext ISO format +/-nn:nn
v1 = expasc[i - 3];
v2 = expasc[i];
if (((v1 == 43) || (v1 == 45)) && (v2 == 58)) {
v1 = expasc[i + 1];
v2 = expasc[i + 2];
if ((v1 >= 48) && (v1 < 58) && (v1 >= 48) && (v1 < 58)) {
v1 = ((((10 * (v1 - 48) + (v2 - 48))) / (15)) >> 0);
n = n - 1;
v2 = 4 * res[n] + v1;
if (expasc[i - 3] == 45) {
v2 = v2 + 128;
}
res.set([v2], n);
}
}
}
return res;
}
async decodeTimeStamp(exp, ofs, siz) {
let n;
let res;
let i;
let byt;
let sign;
let hh;
let ss;
if (siz < 1) {
return '';
}
if (siz == 1) {
n = exp[ofs];
if (n < 144) {
n = n * 300;
}
else {
if (n < 168) {
n = (n - 143) * 1800;
}
else {
if (n < 197) {
n = (n - 166) * 86400;
}
else {
n = (n - 192) * 7 * 86400;
}
}
}
return '+' + String(Math.round(n));
}
res = '20';
i = 0;
while ((i < siz) && (i < 6)) {
byt = exp[ofs + i];
res = res + '' + ((byt & 15)).toString(16).toLowerCase() + '' + ((byt >> 4)).toString(16).toLowerCase();
if (i < 3) {
if (i < 2) {
res = res + '-';
}
else {
res = res + ' ';
}
}
else {
if (i < 5) {
res = res + ':';
}
}
i = i + 1;
}
if (siz == 7) {
byt = exp[ofs + i];
sign = '+';
if ((byt & 8) != 0) {
byt = byt - 8;
sign = '-';
}
byt = (10 * ((byt & 15))) + ((byt >> 4));
hh = String(Math.round((byt >> 2)));
ss = String(Math.round(15 * ((byt & 3))));
if ((hh).length < 2) {
hh = '0' + hh;
}
if ((ss).length < 2) {
ss = '0' + ss;
}
res = res + '' + sign + '' + hh + ':' + ss;
}
return res;
}
async udataSize() {
let res;
let udhsize;
udhsize = (this._udh).length;
res = (this._udata).length;
if (this._alphab == 0) {
if (udhsize > 0) {
res = res + ((((8 + 8 * udhsize + 6)) / (7)) >> 0);
}
res = ((((res * 7 + 7)) / (8)) >> 0);
}
else {
if (udhsize > 0) {
res = res + 1 + udhsize;
}
}
return res;
}
async encodeUserData() {
let udsize;
let udlen;
let udhsize;
let udhlen;
let res;
let i;
let wpos;
let carry;
let nbits;
let thi_b;
// nbits = number of bits in carry
udsize = await this.udataSize();
udhsize = (this._udh).length;
udlen = (this._udata).length;
res = new Uint8Array(1 + udsize);
udhlen = 0;
nbits = 0;
carry = 0;
// 1. Encode UDL
if (this._alphab == 0) {
// 7-bit encoding
if (udhsize > 0) {
udhlen = ((((8 + 8 * udhsize + 6)) / (7)) >> 0);
nbits = 7 * udhlen - 8 - 8 * udhsize;
}
res.set([udhlen + udlen], 0);
}
else {
// 8-bit encoding
res.set([udsize], 0);
}
// 2. Encode UDHL and UDL
wpos = 1;
if (udhsize > 0) {
res.set([udhsize], wpos);
wpos = wpos + 1;
i = 0;
while (i < udhsize) {
res.set([this._udh[i]], wpos);
wpos = wpos + 1;
i = i + 1;
}
}
// 3. Encode UD
if (this._alphab == 0) {
// 7-bit encoding
i = 0;
while (i < udlen) {
if (nbits == 0) {
carry = this._udata[i];
nbits = 7;
}
else {
thi_b = this._udata[i];
res.set([(carry | (((thi_b << nbits)) & 255))], wpos);
wpos = wpos + 1;
nbits = nbits - 1;
carry = (thi_b >> (7 - nbits));
}
i = i + 1;
}
if (nbits > 0) {
res.set([carry], wpos);
}
}
else {
// 8-bit encoding
i = 0;
while (i < udlen) {
res.set([this._udata[i]], wpos);
wpos = wpos + 1;
i = i + 1;
}
}
return res;
}
async generateParts() {
let udhsize;
let udlen;
let mss;
let partno;
let partlen;
let newud;
let newudh;
let newpdu;
let i;
let wpos;
udhsize = (this._udh).length;
udlen = (this._udata).length;
mss = 140 - 1 - 5 - udhsize;
if (this._alphab == 0) {
mss = ((((mss * 8 - 6)) / (7)) >> 0);
}
this._npdu = ((((udlen + mss - 1)) / (mss)) >> 0);
this._parts.length = 0;
partno = 0;
wpos = 0;
while (wpos < udlen) {
partno = partno + 1;
newudh = new Uint8Array(5 + udhsize);
newudh.set([0], 0); // IEI: concatenated message
newudh.set([3], 1); // IEDL: 3 bytes
newudh.set([this._mref], 2);
newudh.set([this._npdu], 3);
newudh.set([partno], 4);
i = 0;
while (i < udhsize) {
newudh.set([this._udh[i]], 5 + i);
i = i + 1;
}
if (wpos + mss < udlen) {
partlen = mss;
}
else {
partlen = udlen - wpos;
}
newud = new Uint8Array(partlen);
i = 0;
while (i < partlen) {
newud.set([this._udata[wpos]], i);
wpos = wpos + 1;
i = i + 1;
}
newpdu = new YSms(this._mbox);
await newpdu.set_received(await this.isReceived());
await newpdu.set_smsc(await this.get_smsc());
await newpdu.set_msgRef(await this.get_msgRef());
await newpdu.set_sender(await this.get_sender());
await newpdu.set_recipient(await this.get_recipient());
await newpdu.set_protocolId(await this.get_protocolId());
await newpdu.set_dcs(await this.get_dcs());
await newpdu.set_timestamp(await this.get_timestamp());
await newpdu.set_userDataHeader(newudh);
await newpdu.set_userData(newud);
this._parts.push(newpdu);
}
return YAPI.SUCCESS;
}
async generatePdu() {
let sca;
let hdr;
let addr;
let stamp;
let udata;
let pdutyp;
let pdulen;
let i;
// Determine if the message can fit within a single PDU
this._parts.length = 0;
if (await this.udataSize() > 140) {
// multiple PDU are needed
this._pdu = new Uint8Array(0);
return await this.generateParts();
}
sca = await this.encodeAddress(this._smsc);
if ((sca).length > 0) {
sca.set([(sca).length - 1], 0);
}
stamp = await this.encodeTimeStamp(this._stamp);
udata = await this.encodeUserData();
if (this._deliv) {
addr = await this.encodeAddress(this._orig);
hdr = new Uint8Array(1);
pdutyp = 0;
}
else {
addr = await this.encodeAddress(this._dest);
this._mref = await this._mbox.nextMsgRef();
hdr = new Uint8Array(2);
hdr.set([this._mref], 1);
pdutyp = 1;
if ((stamp).length > 0) {
pdutyp = pdutyp + 16;
}
if ((stamp).length == 7) {
pdutyp = pdutyp + 8;
}
}
if ((this._udh).length > 0) {
pdutyp = pdutyp + 64;
}
hdr.set([pdutyp], 0);
pdulen = (sca).length + (hdr).length + (addr).length + 2 + (stamp).length + (udata).length;
this._pdu = new Uint8Array(pdulen);
pdulen = 0;
i = 0;
while (i < (sca).length) {
this._pdu.set([sca[i]], pdulen);
pdulen = pdulen + 1;
i = i + 1;
}
i = 0;
while (i < (hdr).length) {
this._pdu.set([hdr[i]], pdulen);
pdulen = pdulen + 1;
i = i + 1;
}
i = 0;
while (i < (addr).length) {
this._pdu.set([addr[i]], pdulen);
pdulen = pdulen + 1;
i = i + 1;
}
this._pdu.set([this._pid], pdulen);
pdulen = pdulen + 1;
this._pdu.set([await this.get_dcs()], pdulen);
pdulen = pdulen + 1;
i = 0;
while (i < (stamp).length) {
this._pdu.set([stamp[i]], pdulen);
pdulen = pdulen + 1;
i = i + 1;
}
i = 0;
while (i < (udata).length) {
this._pdu.set([udata[i]], pdulen);
pdulen = pdulen + 1;
i = i + 1;
}
this._npdu = 1;
return YAPI.SUCCESS;
}
async parseUserDataHeader() {
let udhlen;
let i;
let iei;
let ielen;
let sig;
this._aggSig = '';
this._aggIdx = 0;
this._aggCnt = 0;
udhlen = (this._udh).length;
i = 0;
while (i + 1 < udhlen) {
iei = this._udh[i];
ielen = this._udh[i + 1];
i = i + 2;
if (i + ielen <= udhlen) {
if ((iei == 0) && (ielen == 3)) {
// concatenated SMS, 8-bit ref
sig = this._orig + '-' + this._dest + '-' + ('00' + (this._mref).toString(16)).slice(-2).toLowerCase() + '-' + ('00' + (this._udh[i]).toString(16)).slice(-2).toLowerCase();
this._aggSig = sig;
this._aggCnt = this._udh[i + 1];
this._aggIdx = this._udh[i + 2];
}
if ((iei == 8) && (ielen == 4)) {
// concatenated SMS, 16-bit ref
sig = this._orig + '-' + this._dest + '-' + ('00' + (this._mref).toString(16)).slice(-2).toLowerCase() + '-' + ('00' + (this._udh[i]).toString(16)).slice(-2).toLowerCase() + '' + ('00' + (this._udh[i + 1]).toString(16)).slice(-2).toLowerCase();
this._aggSig = sig;
this._aggCnt = this._udh[i + 2];
this._aggIdx = this._udh[i + 3];
}
}
i = i + ielen;
}
return YAPI.SUCCESS;
}
async parsePdu(pdu) {
let rpos;
let addrlen;
let pdutyp;
let tslen;
let dcs;
let udlen;
let udhsize;
let udhlen;
let i;
let carry;
let nbits;
let thi_b;
this._pdu = pdu;
this._npdu = 1;
// parse meta-data
this._smsc = await this.decodeAddress(pdu, 1, 2 * (pdu[0] - 1));
rpos = 1 + pdu[0];
pdutyp = pdu[rpos];
rpos = rpos + 1;
this._deliv = ((pdutyp & 3) == 0);
if (this._deliv) {
addrlen = pdu[rpos];
rpos = rpos + 1;
this._orig = await this.decodeAddress(pdu, rpos, addrlen);
this._dest = '';
tslen = 7;
}
else {
this._mref = pdu[rpos];
rpos = rpos + 1;
addrlen = pdu[rpos];
rpos = rpos + 1;
this._dest = await this.decodeAddress(pdu, rpos, addrlen);
this._orig = '';
if (((pdutyp & 16)) != 0) {
if (((pdutyp & 8)) != 0) {
tslen = 7;
}
else {
tslen = 1;
}
}
else {
tslen = 0;
}
}
rpos = rpos + (((addrlen + 3) >> 1));
this._pid = pdu[rpos];
rpos = rpos + 1;
dcs = pdu[rpos];
rpos = rpos + 1;
this._alphab = (((dcs >> 2)) & 3);
this._mclass = (dcs & (16 + 3));
this._stamp = await this.decodeTimeStamp(pdu, rpos, tslen);
rpos = rpos + tslen;
// parse user data (including udh)
nbits = 0;
carry = 0;
udlen = pdu[rpos];
rpos = rpos + 1;
if ((pdutyp & 64) != 0) {
udhsize = pdu[rpos];
rpos = rpos + 1;
this._udh = new Uint8Array(udhsize);
i = 0;
while (i < udhsize) {
this._udh.set([pdu[rpos]], i);
rpos = rpos + 1;
i = i + 1;
}
if (this._alphab == 0) {
// 7-bit encoding
udhlen = ((((8 + 8 * udhsize + 6)) / (7)) >> 0);
nbits = 7 * udhlen - 8 - 8 * udhsize;
if (nbits > 0) {
thi_b = pdu[rpos];
rpos = rpos + 1;
carry = (thi_b >> nbits);
nbits = 8 - nbits;
}
}
else {
// byte encoding
udhlen = 1 + udhsize;
}
udlen = udlen - udhlen;
}
else {
udhsize = 0;
this._udh = new Uint8Array(0);
}
this._udata = new Uint8Array(udlen);
if (this._alphab == 0) {
// 7-bit encoding
i = 0;
while (i < udlen) {
if (nbits == 7) {
this._udata.set([carry], i);
carry = 0;
nbits = 0;
}
else {
thi_b = pdu[rpos];
rpos = rpos + 1;
this._udata.set([(carry | (((thi_b << nbits)) & 127))], i);
carry = (thi_b >> (7 - nbits));
nbits = nbits + 1;
}
i = i + 1;
}
}
else {
// 8-bit encoding
i = 0;
while (i < udlen) {
this._udata.set([pdu[rpos]], i);
rpos = rpos + 1;
i = i + 1;
}
}
await this.parseUserDataHeader();
return YAPI.SUCCESS;
}
/**
* Sends the SMS to the recipient. Messages of more than 160 characters are supported
* using SMS concatenation.
*
* @return YAPI.SUCCESS when the call succeeds.
*
* On failure, throws an exception or returns a negative error code.
*/
async send() {
let i;
let retcode;
let pdu;
if (this._npdu == 0) {
await this.generatePdu();
}
if (this._npdu == 1) {
return await this._mbox._upload('sendSMS', this._pdu);
}
retcode = YAPI.SUCCESS;
i = 0;
while ((i < this._npdu) && (retcode == YAPI.SUCCESS)) {
pdu = this._parts[i];
retcode = await pdu.send();
i = i + 1;
}
return retcode;
}
async deleteFromSIM() {
let i;
let retcode;
let pdu;
if (this._npdu < 2) {
return await this._mbox.clearSIMSlot(this._slot);
}
retcode = YAPI.SUCCESS;
i = 0;
while ((i < this._npdu) && (retcode == YAPI.SUCCESS)) {
pdu = this._parts[i];
retcode = await pdu.deleteFromSIM();
i = i + 1;
}
return retcode;
}
}
//--- (generated code: YMessageBox class start)
/**
* YMessageBox Class: SMS message box interface control interface, available for instance in the
* YoctoHub-GSM-2G, the YoctoHub-GSM-3G-EU, the YoctoHub-GSM-3G-NA or the YoctoHub-GSM-4G
*
* The YMessageBox class provides SMS sending and receiving capability for
* GSM-enabled Yoctopuce devices.
*/
//--- (end of generated code: YMessageBox class start)
/** @extends {YFunction} **/
export class YMessageBox extends YFunction {
//--- (end of generated code: YMessageBox attributes declaration)
constructor(yapi, func) {
//--- (generated code: YMessageBox constructor)
super(yapi, func);
this._slotsInUse = YMessageBox.SLOTSINUSE_INVALID;
this._slotsCount = YMessageBox.SLOTSCOUNT_INVALID;
this._slotsBitmap = YMessageBox.SLOTSBITMAP_INVALID;
this._pduSent = YMessageBox.PDUSENT_INVALID;
this._pduReceived = YMessageBox.PDURECEIVED_INVALID;
this._obey = YMessageBox.OBEY_INVALID;
this._command = YMessageBox.COMMAND_INVALID;
this._valueCallbackMessageBox = null;
this._nextMsgRef = 0;
this._prevBitmapStr = '';
this._pdus = [];
this._messages = [];
this._gsm2unicodeReady = false;
this._gsm2unicode = [];
this._iso2gsm = new Uint8Array(0);
// API symbols as object properties
this.SLOTSINUSE_INVALID = YAPI.INVALID_UINT;
this.SLOTSCOUNT_INVALID = YAPI.INVALID_UINT;
this.SLOTSBITMAP_INVALID = YAPI.INVALID_STRING;
this.PDUSENT_INVALID = YAPI.INVALID_UINT;
this.PDURECEIVED_INVALID = YAPI.INVALID_UINT;
this.OBEY_INVALID = YAPI.INVALID_STRING;
this.COMMAND_INVALID = YAPI.INVALID_STRING;
this._className = 'MessageBox';
//--- (end of generated code: YMessageBox constructor)
}
//--- (generated code: YMessageBox implementation)
imm_parseAttr(name, val) {
switch (name) {
case 'slotsInUse':
this._slotsInUse = val;
return 1;
case 'slotsCount':
this._slotsCount = val;
return 1;
case 'slotsBitmap':
this._slotsBitmap = val;
return 1;
case 'pduSent':
this._pduSent = val;
return 1;
case 'pduReceived':
this._pduReceived = val;
return 1;
case 'obey':
this._obey = val;
return 1;
case 'command':
this._command = val;
return 1;
}
return super.imm_parseAttr(name, val);
}
/**
* Returns the number of message storage slots currently in use.
*
* @return an integer corresponding to the number of message storage slots currently in use
*
* On failure, throws an exception or returns YMessageBox.SLOTSINUSE_INVALID.
*/
async get_slotsInUse() {
let res;
if (this._cacheExpiration <= this._yapi.GetTickCount()) {
if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) {
return YMessageBox.SLOTSINUSE_INVALID;
}
}
res = this._slotsInUse;
return res;
}
/**
* Returns the total number of message storage slots on the SIM card.
*
* @return an integer corresponding to the total number of message storage slots on the SIM card
*
* On failure, throws an exception or returns YMessageBox.SLOTSCOUNT_INVALID.
*/
async get_slotsCount() {
let res;
if (this._cacheExpiration <= this._yapi.GetTickCount()) {
if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) {
return YMessageBox.SLOTSCOUNT_INVALID;
}
}
res = this._slotsCount;
return res;
}
async get_slotsBitmap() {
let res;
if (this._cacheExpiration <= this._yapi.GetTickCount()) {
if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) {
return YMessageBox.SLOTSBITMAP_INVALID;
}
}
res = this._slotsBitmap;
return res;
}
/**
* Returns the number of SMS units sent so far.
*
* @return an integer corresponding to the number of SMS units sent so far
*
* On failure, throws an exception or returns YMessageBox.PDUSENT_INVALID.
*/
async get_pduSent() {
let res;
if (this._cacheExpiration <= this._yapi.GetTickCount()) {
if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) {
return YMessageBox.PDUSENT_INVALID;
}
}
res = this._pduSent;
return res;
}
/**
* Changes the value of the outgoing SMS units counter.
*
* @param newval : an integer corresponding to the value of the outgoing SMS units counter
*
* @return YAPI.SUCCESS if the call succeeds.
*
* On failure, throws an exception or returns a negative error code.
*/
async set_pduSent(newval) {
let rest_val;
rest_val = String(newval);
return await this._setAttr('pduSent', rest_val);
}
/**
* Returns the number of SMS units received so far.
*
* @return an integer corresponding to the number of SMS units received so far
*
* On failure, throws an exception or returns YMessageBox.PDURECEIVED_INVALID.
*/
async get_pduReceived() {
let res;
if (this._cacheExpiration <= this._yapi.GetTickCount()) {
if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) {
return YMessageBox.PDURECEIVED_INVALID;
}
}
res = this._pduReceived;
return res;
}
/**
* Changes the value of the incoming SMS units counter.
*
* @param newval : an integer corresponding to the value of the incoming SMS units counter
*
* @return YAPI.SUCCESS if the call succeeds.
*
* On failure, throws an exception or returns a negative error code.
*/
async set_pduReceived(newval) {
let rest_val;
rest_val = String(newval);
return await this._setAttr('pduReceived', rest_val);
}
/**
* Returns the phone number authorized to send remote management commands.
* When a phone number is specified, the hub will take contre of all incoming
* SMS messages: it will execute commands coming from the authorized number,
* and delete all messages once received (whether authorized or not).
* If you need to receive SMS messages using your own software, leave this
* attribute empty.
*
* @return a string corresponding to the phone number authorized to send remote management commands
*
* On failure, throws an exception or returns YMessageBox.OBEY_INVALID.
*/
async get_obey() {
let res;
if (this._cacheExpiration <= this._yapi.GetTickCount()) {
if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) {
return YMessageBox.OBEY_INVALID;
}
}
res = this._obey;
return res;
}
/**
* Changes the phone number authorized to send remote management commands.
* The phone number usually starts with a '+' and does not include spacers.
* When a phone number is specified, the hub will take contre of all incoming
* SMS messages: it will execute commands coming from the authorized number,
* and delete all messages once received (whether authorized or not).
* If you need to receive SMS messages using your own software, leave this
* attribute empty. Remember to call the saveToFlash() method of the
* module if the modification must be kept.
*
* This feature is only available since YoctoHub-GSM-4G.
*
* @param newval : a string corresponding to the phone number authorized to send remote management commands
*
* @return YAPI.SUCCESS if the call succeeds.
*
* On failure, throws an exception or returns a negative error code.
*/
async set_obey(newval) {
let rest_val;
rest_val = String(newval);
return await this._setAttr('obey', rest_val);
}
async get_command() {
let res;
if (this._cacheExpiration <= this._yapi.GetTickCount()) {
if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) {
return YMessageBox.COMMAND_INVALID;
}
}
res = this._command;
return res;
}
async set_command(newval) {
let rest_val;
rest_val = String(newval);
return await this._setAttr('command', rest_val);
}
/**
* Retrieves a SMS message box interface for a given identifier.
* The identifier can be specified using several formats:
*
* - FunctionLogicalName
* - ModuleSerialNumber.FunctionIdentifier
* - ModuleSerialNumber.FunctionLogicalName
* - ModuleLogicalName.FunctionIdentifier
* - ModuleLogicalName.FunctionLogicalName
*
*
* This function does not require that the SMS message box interface is online at the time
* it is invoked. The returned object is nevertheless valid.
* Use the method YMessageBox.isOnline() to test if the SMS message box interface is
* indeed online at a given time. In case of ambiguity when looking for
* a SMS message box interface by logical name, no error is notified: the first instance
* found is returned. The search is performed first by hardware name,
* then by logical name.
*
* If a call to this object's is_online() method returns FALSE although
* you are certain that the matching device is plugged, make sure that you did
* call registerHub() at application initialization time.
*
* @param func : a string that uniquely characterizes the SMS message box interface, for instance
* YHUBGSM1.messageBox.
*
* @return a YMessageBox object allowing you to drive the SMS message box interface.
*/
static FindMessageBox(func) {
let obj;
obj = YFunction._FindFromCache('MessageBox', func);
if (obj == null) {
obj = new YMessageBox(YAPI, func);
YFunction._AddToCache('MessageBox', func, obj);
}
return obj;
}
/**
* Retrieves a SMS message box interface for a given identifier in a YAPI context.
* The identifier can be specified using several formats:
*
* - FunctionLogicalName
* - ModuleSerialNumber.FunctionIdentifier
* - ModuleSerialNumber.FunctionLogicalName
* - ModuleLogicalName.FunctionIdentifier
* - ModuleLogicalName.FunctionLogicalName
*
*
* This function does not require that the SMS message box interface is online at the time
* it is invoked. The returned object is nevertheless valid.
* Use the method YMessageBox.isOnline() to test if the SMS message box interface is
* indeed online at a given time. In case of ambiguity when looking for
* a SMS message box interface by logical name, no error is notified: the first instance
* found is returned. The search is performed first by hardware name,
* then by logical name.
*
* @param yctx : a YAPI context
* @param func : a string that uniquely characterizes the SMS message box interface, for instance
* YHUBGSM1.messageBox.
*
* @return a YMessageBox object allowing you to drive the SMS message box interface.
*/
static FindMessageBoxInContext(yctx, func) {
let obj;
obj = YFunction._FindFromCacheInContext(yctx, 'MessageBox', func);
if (obj == null) {
obj = new YMessageBox(yctx, func);
YFunction._AddToCache('MessageBox', func, obj);
}
return obj;
}
/**
* Registers the callback function that is invoked on every change of advertised value.
* The callback is invoked only during the execution of ySleep or yHandleEvents.
* This provides control over the time when the callback is triggered. For good responsiveness, remember to call
* one of these two functions periodically. To unregister a callback, pass a null pointer as argument.
*
* @param callback : the callback function to call, or a null pointer. The callback function should take two
* arguments: the function object of which the value has changed, and the character string describing
* the new advertised value.
* @noreturn
*/
async registerValueCallback(callback) {
let val;
if (callback != null) {
await YFunction._UpdateValueCallbackList(this, true);
}
else {
await YFunction._UpdateValueCallbackList(this, false);
}
this._valueCallbackMessageBox = callback;
// Immediately invoke value callback with current value
if (callback != null && await this.isOnline()) {
val = this._advertisedValue;
if (!(val == '')) {
await this._invokeValueCallback(val);
}
}
return 0;
}
async _invokeValueCallback(value) {
if (this._valueCallbackMessageBox != null) {
try {
await this._valueCallbackMessageBox(this, value);
}
catch (e) {
this