def plusCLIP(self, righthandside): """ Connecting Line Identification Presence """ number, ntype, rest = safesplit(righthandside, ',', 2) number = number.replace('"', '') logger.warning("plusCLIP not handled -- please fix me")
def percentCSTAT(self, righthandside): """ TI Calypso subsystem status report PHB is phonebook, SMS is messagebook. RDY is supposed to be sent, after PHB and SMS both being 1, however it's not sent on all devices. EONS is completely undocumented. Due to RDY being unreliable, we wait for PHB and SMS sending availability and then synthesize a global SimReady signal. """ subsystem, available = safesplit(righthandside, ",") if not bool(int(available)): # not ready if subsystem in ("PHB", "SMS"): self.subsystemReadyness[subsystem] = False logger.info("subsystem %s readyness now %s" % (subsystem, self.subsystemReadyness[subsystem])) if not self.fullReadyness == False: self._object.ReadyStatus(False) self.fullReadyness = False else: # ready if subsystem in ("PHB", "SMS"): self.subsystemReadyness[subsystem] = True logger.info("subsystem %s readyness now %s" % (subsystem, self.subsystemReadyness[subsystem])) newFullReadyness = self.subsystemReadyness[ "PHB"] and self.subsystemReadyness["SMS"] if newFullReadyness and (not self.fullReadyness == True): self._object.ReadyStatus(True) self.fullReadyness = True logger.info("full readyness now %s" % self.fullReadyness)
def plusCIEV(self, righthandside): """ Indicator Event Reporting. Based on 3GPP TS 07.07, Chapter 8.9, but slightly extended. As +CIND=? gives us a hint (one of the few test commands EZX exposes), we conclude: 0: battery charge level (0-5) 1: signal level (0-5) 2: service availability (0-1) 3: call active? (0-1) 4: voice mail (message) (0-1) 5: transmit activated by voice activity (0-1) 6: call progress (0-3) [0:no more in progress, 1:incoming, 2:outgoing, 3:ringing] 7: roaming (0-2) 8: sms storage full (0-1) 11: ??? 20: ??? (SIM not inserted?) """ indicator, value = (int(x) for x in safesplit(righthandside, ',')) try: method = getattr(self, "CIEV_%d" % indicator) except AttributeError: logger.debug("EZX: unhandled CIEV", indicator, value) else: method(value)
def percentCSQ(self, righthandside): """ signal strength report """ strength, snr, quality = safesplit(righthandside, ",") self._object.SignalStrength( const.signalQualityToPercentage(int(strength))) # send dbus signal
def percentCCCN(self, righthandside): direction, callId, ie = safesplit(righthandside, ",") # this is ASN.1 BER, but we don't want a full decoder here info = {} if ie[0:8] + ie[10:30] == "A10E020102011030068101428F01": info["held"] = bool(int(ie[30:32], 16)) if info: self._callHandler.statusChangeFromNetwork(int(callId) + 1, info)
def plusCCTP(self, righthandside): callnumber, peer = safesplit(righthandside, ',') callnumber = int(callnumber) peer = peer.strip('"') # synthesize call status self._callHandler.statusChangeFromNetwork(callnumber, { "status": "outgoing", "peer": peer })
def plusCMT(self, righthandside, pdu): """ Message Transfer Indication """ header = safesplit(righthandside, ',') length = int(header[1]) # Now we decode the actual PDU sms = ogsmd.gsm.sms.SMS.decode(pdu, "sms-deliver") self._object.IncomingMessage(str(sms.addr), sms.ud, sms.properties)
def plusCMTI(self, righthandside): """ Message Transfer Indication """ storage, index = safesplit(righthandside, ',') if storage != '"SM"': logger.warning("unhandled +CMTI message notification") else: self._object.IncomingStoredMessage(int(index))
def trigger(self): request, response, error = yield ("+CSQ") result = {} if error is not None: self.errorFromChannel(request, error) else: if response[-1] != "OK" or len(response) == 1: pass else: result["strength"] = const.signalQualityToPercentage( int(safesplit(self._rightHandSide(response[0]), ',')[0])) # +CSQ: 22,99 request, response, error = yield ("+COPS?") if error is not None: self.errorFromChannel(request, error) else: if response[-1] != "OK" or len(response) == 1: pass else: values = safesplit(self._rightHandSide(response[0]), ',') if len(values) < 3: result["mode"] = const.REGISTER_MODE[int(values[0])] result["registration"] = "unregistered" else: result["mode"] = const.REGISTER_MODE[int(values[0])] roaming = self._object.modem.data("network:roaming", False) result["registration"] = "roaming" if roaming else "home" mccmnc = values[2].strip('"').replace('-', '') if mccmnc == "": result["registration"] = "busy" else: result["code"] = mccmnc network = const.NETWORKS.get((mccmnc[:3], mccmnc[3:]), {}) if "brand" in network: result["provider"] = network["brand"] elif "operator" in network: result["provider"] = network["operator"] else: result["provider"] = "Unknown" self._ok(result)
def plusEOPER(self, righthandside): values = safesplit(righthandside, ',') status = {} if len(values) == 1: status["registration"] = "unregistered" else: # FIXME: This is not correct. Need to listen for the roaming status as well roaming = self._object.modem.data("network:roaming", False) status["registration"] = "roaming" if roaming else "home" status["provider"] = values[1] self._object.Status(status)
def plusCGREG(self, righthandside): """ Gprs Registration Status Update """ charset = currentModem()._charsets["DEFAULT"] values = safesplit(righthandside, ',') status = {} status["registration"] = const.REGISTER_STATUS[int(values[0])] if len(values) >= 3: status["lac"] = values[1].strip('"').decode(charset) status["cid"] = values[2].strip('"').decode(charset) self._object.NetworkStatus(status)
def plusCREG(self, righthandside): """ Network Registration Status Update """ charset = currentModem()._charsets["DEFAULT"] values = safesplit(righthandside, ',') self.register = const.REGISTER_STATUS[int(values[0])] if len(values) >= 3: self.lac = values[1].strip('"').decode(charset) self.cid = values[2].strip('"').decode(charset) self._mediator.NetworkGetStatus(self._object, self.statusOK, self.statusERR)
def plusCUSD(self, righthandside): """ Incoming USSD result """ charset = currentModem()._charsets["USSD"] values = safesplit(righthandside, ',') if len(values) == 1: mode = const.NETWORK_USSD_MODE[int(values[0])] self._object.IncomingUssd(mode, "") elif len(values) == 3: mode = const.NETWORK_USSD_MODE[int(values[0])] message = values[1].strip('" ').decode(charset) self._object.IncomingUssd(mode, message) else: logger.warning("Ignoring unknown format: '%s'" % righthandside)
def plusCGEV(self, righthandside): """ Gprs Context Event """ values = safesplit(righthandside, ',') if len(values ) == 1: # detach, but we're not having an IP context online if values[0] == "ME DETACH": # FIXME this will probably lead to a zombie instance = pdp.Pdp.getInstance() if instance is not None: instance.deactivate() # FIXME force dropping the dataport, this will probably kill the zombie elif len(values) >= 3: # detach while we were attached pass
def plusCREG(self, righthandside): # call base implementation AbstractUnsolicitedResponseDelegate.plusCREG(self, righthandside) # do we care for recamping? if not self.checkForRecamping: return # check for recamping values = safesplit(righthandside, ',') register = const.REGISTER_STATUS[int(values[0])] if self.lastStatus == "unregistered": if self.register in "home roaming".split(): self.reregisterIntervals.append(time.time() - self.lastTime) if len(self.reregisterIntervals) == 1: self.firstReregister = time.time() gobject.idle_add(self._checkRecampingBug) self.lastReregister = time.time() self.lastStatus = register self.lastTime = time.time()
def plusCBM(self, righthandside, pdu): """ Cell Broadcast Message """ values = safesplit(righthandside, ',') if len(values) == 1: # PDU MODE cb = ogsmd.gsm.sms.CellBroadcast.decode(pdu) sn = cb.sn channel = cb.mid dcs = cb.dcs page = cb.page data = cb.ud elif len(values) == 5: # TEXT MODE sn, mid, dcs, page, pages = values channel = int(mid) data = pdu else: logger.warning( "unrecognized +CBM cell broadcast notification, please fix me..." ) return self._object.IncomingCellBroadcast(channel, data)
def plusCSSU(self, righthandside): code, index, number, type = safesplit(righthandside, ",") info = {} if code == "0": info["forwarded"] = True elif code == "1": info["cug"] = True elif code == "2": info["remotehold"] = True elif code == "3": info["remotehold"] = False elif code == "4": info["conference"] = True else: logger.info("unhandled +CSSU code '%s'" % code) if info: # This is not failsafe since we don't know the call ID if code in "234": self._callHandler.statusChangeFromNetworkByStatus( "active", info) else: self._callHandler.statusChangeFromNetworkByStatus( "incoming", info)
def percentCPRI(self, righthandside): gsm, gprs = safesplit(righthandside, ',') cipher_gsm = const.NETWORK_CIPHER_STATUS.get(int(gsm), "unknown") cipher_gprs = const.NETWORK_CIPHER_STATUS.get(int(gprs), "unknown") self._object.CipherStatus(cipher_gsm, cipher_gprs)
def plusCLIP(self, righthandside): number, ntype = safesplit(righthandside, ',') if number and ntype: peer = const.phonebookTupleToNumber(number[1:-1], int(ntype)) self._mediator.Call.clip(self._object, peer)
def plusCKEV(self, righthandside): values = safesplit(righthandside, ',') keyname = KEYCODES.get(int(values[0]), "unknown") pressed = bool(int(values[1])) self._object.KeypadEvent(keyname, pressed)
def percentCPI(self, righthandside): """ Call Progress Indication: callId = call number in internal call table (same as call number in CCLD) msgType = 0:setup, 1:disconnect, 2:alert, 3:call proceed, 4:sync, 5:progress, 6:connected, 7:release, 8:reject (from network), 9:request (MO Setup), 10: hold ibt = 1, if in-band-tones enabled tch = 1, if traffic channel assigned direction = 0:MO, 1:MT, 2:CCBS, 3:MO-autoredial mode = 0:voice, 1:data, 2:fax, ..., 9 [see gsm spec bearer type] number = "number" [gsm spec] ntype = number type [gsm spec] alpha = "name", if number found in SIM phonebook [gsm spec] cause = GSM Network Cause [see gsm spec, section 04.08 annex H] line = 0, if line 1. 1, if line2. Typical chunks during a call: ... case A: incoming (MT) ... %CPI: 1,0,0,0,1,0,"+496912345678",145,,,0 ( setup call, MT, line one, no traffic channel yet ) +CRING: VOICE %CPI: 1,0,0,1,1,0,"+496912345678",145,,,0 ( setup call, MT, line one, traffic channel assigned ) %CPI: 1,4,0,1,1,0,"+496912345678",145,,,0 ( sync call, MT, line one, traffic channel assigned ) %CPI: 1,0,0,1,1,0,"+496912345678",145,,,0 ( setup call, MT, line one, traffic channel assigned ) +CRING: VOICE %CPI: 1,4,0,1,1,0,"+496912345678",145,,,0 ( sync call, MT, line one, traffic channel assigned ) +CRING: VOICE ... case A.1: remote line hangs up ... %CPI: 1,1,0,1,1,0,"+496912345678",145,,,0 ( disconnect call, MT line one, traffic channel assigned ) %CPI: 1,7,0,0,,,,,,,0 (release from network, traffic channel freed) (NO CARRIER, if call was connected, i.e. local accepted) ... case A.2: local accept (ATA) ... %CPI: 1,6,0,1,1,0,"+496912345678",145,,,0 ( connected call, MT, line one, traffic channel assigned ) => from here see case A.1 or A.3 ... case A.3: local reject (ATH) ... %CPI: 1,1,0,1,1,0,"+496912345678",145,,,0 ( disconnect call, MT line one, traffic channel assigned ) %CPI: 1,7,0,0,,,,,,,0 (release from network, traffic channel freed) ... case B: outgoing (MO) ... %CPI: 1,9,0,0,0,0,"+496912345678",145,,,0 ( request call, MO, line one, no traffic channel yet ) %CPI: 1,3,0,0,0,0,"+496912345678",145,,,0 ( call call, MO, line one, no traffic channel yet ) %CPI: 1,4,0,1,0,0,"+496912345678",145,,,0 ( sync call, MO, line one, traffic channel assigned ) %CPI: 1,2,1,1,0,0,"+496912345678",145,,,0 ( alert call, MO, line one, traffic channel assigned ) (at this point, it is ringing on the other side) ... case B.1: remote line rejects or sends busy... %CPI: 1,6,0,1,0,0,"+496912345678",145,,,0 ( connect call, MO, line one, traffic channel assigned ) (at this point, ATD returns w/ OK) %CPI: 1,1,0,1,0,0,"+496912345678",145,,17,0 ( disconnect call, MO, line one, traffic channel assigned ) (at this point, BUSY(17) or NO CARRIER(16) is sent) %CPI: 1,7,0,0,,,,,,,0 (release from network, traffic channel freed) ... case B.2: remote line accepts... %CPI: 1,6,0,1,0,0,"+496912345678",145,,,0 ( connect call, MO, line one, traffic channel assigned ) (at this point, ATD returns w/ OK) ... case B.3: local cancel ... ? ... case C.1: first call active, second incoming and accepted (puts first on hold) %CPI: 1,10,0,1,0,0,"+496912345678",145,,,0 %CPI: 2,6,0,1,1,0,"+496912345679",129,,,0 """ callId, msgType, ibt, tch, direction, mode, number, ntype, alpha, cause, line = safesplit( righthandside, ",") if msgType == "10": msgType = "A" # stupid hack to have single char types #devchannel = self._object.modem.communicationChannel( "DeviceMediator" ) #devchannel.enqueue( "+CPAS;+CEER" ) info = {} # Report number, reason, and line, if available if number and ntype: info["peer"] = const.phonebookTupleToNumber( number[1:-1], int(ntype)) if cause: info["reason"] = const.ISUP_RELEASE_CAUSE.get( int(cause), "unknown cause") if line: info["line"] = int(line) # Always report the direction if direction == "0": info.update({"direction": "outgoing"}) elif direction == "1": info.update({"direction": "incoming"}) # Report mode if mode: info["mode"] = const.CALL_MODE.revlookup(int(mode)) # Compute status if msgType == "0": # setup (MT) info.update({"status": "incoming"}) elif msgType == "6": # connected (MO & MT) info.update({"status": "active"}) elif msgType == "1": # disconnected (MO & MT) # FIXME try to gather reason for disconnect? info.update({"status": "release"}) elif msgType == "8": # network reject (MO) info.update({"status": "release", "reason": "no service"}) elif msgType == "9": # request (MO) info.update({"status": "outgoing"}) elif msgType == "3": # Sometimes setup is not sent?! info.update({"status": info["direction"]}) elif msgType == "A": # hold info.update({"status": "held"}) if msgType in "013689A": self._callHandler.statusChangeFromNetwork(int(callId), info) # DSP bandaid if msgType in "34": currentModem().channel("MiscMediator").enqueue(createDspCommand())
def percentCSSN(self, righthandside): direction, transPart, ie = safesplit(righthandside, ",")
def plusCSSU(self, righthandside): values = safesplit(righthandside, ',') if len(values) == 4: code, index, number, type_ = values else: code = values[0]