#! /usr/bin/env python
# -*- coding: euc-kr -*-
import modem
import time
from setting import setting
import smdl, status, config
import utils
DLL_SMS_DATA = 0x11
DLL_SMS_ERROR = 0x12
DLL_SMS_EST = 0x13
DLL_SMS_REL = 0x14
DLL_SMS_ACK = 0x15
DLL_SMS_NACK = 0x16
sms_error_code = {
'wrong checksum': '\x01',
'wrong message length': '\x02',
'unknown message type': '\x03',
'extension not supported': '\x04',
'unspecified': '\xff'}
class TLError(Exception):
pass
class DLLError(Exception):
pass
class SmsModem(modem.Modem):
def wait_response(self, pattern, timeout=2000):
buf = ''
if config.sms_debug:
print 'in wait_response:', pattern
while 1:
buf += self.read(timeout)
try :
utils.check_interrupt()
except Exception:
#print ' >> sms mode ignore key exception.'
pass
if pattern == 'volt':
value = 0
import re
try :
s_value = re.search("([0-9.]+)",buf).group(1)
arr_value = s_value.split('.')
value = int(arr_value[0])
except:
value = 0
#print 'check voltage returns 0'
if value > 15:
return
if buf.find(pattern) >= 0:
if config.sms_debug:
print 'in wait_response:', pattern, ' OK'
return
# for Type approval
def sms_write_data(self, data):
lendata = len(data)
wait_len = 0.0081 * lendata
if lendata in (58, 69, 88):
wait_len = wait_len + 0.003
elif lendata in (94, 99, 104):
wait_len = wait_len + 0.009
elif lendata in (100, 105, 109, 110, 111, 116, 130, 141, 146, 147, 152, 153, 157, 158, 159):
wait_len = wait_len + 0.015
elif lendata > 70:
wait_len = wait_len + 0.007
elif lendata < 25:
wait_len = wait_len - 0.003
if config.sms_debug:
print '***** wait_len: ', wait_len, 'len: ', lendata
utils.check_interrupt()
time.sleep(0.1)
self.set_bit(modem.RTS)
self.wait_for_set(modem.CTS)
utils.check_interrupt()
self.write(data)
time.sleep(wait_len)
self.clear_bit(modem.RTS)
if config.sms_debug:
print '******************end sms_write_data'
def sms_read_data(self):
if config.sms_debug:
print '*************begin sms_read_data'
print 'wait DCD on'
self.got_dll_header = False
self.extension_bit = False
#self.wait_for_set(modem.DCD)
utils.check_interrupt()
message = smdl.Parser()
message.ignore_gabage = config.sms_ignore_gabage
buf = ''
while not message.dll_pass:
buf = message.read_header(self.read(13500))
utils.check_interrupt()
self.got_dll_header = True
self.extension_bit = message.extension_bit
if message.need_more() and buf:
message.feed(buf)
while message.need_more():
message.feed(self.read(13500))
utils.check_interrupt()
if config.sms_debug:
print 'wait DCD clear'
self.wait_for_clear(modem.DCD)
if config.sms_debug:
print 'end wait DCD clear'
print '***************end sms_read_data'
return message
def sms_answer(self):
## FIXME
#for smsrecv-test
#첫번째 RING에서 cid 가 같이 올라오기 때문에 두번째 RING까지 기다림
# junk data 라고 생각했던 것이 cid
#self.wait_response('RING', 10 * 1000)
#self.wait_response('RING', 10 * 1000)
self.clear_bit(modem.RTS)
self.write_command('AT+MS=V23C;B2;+SMS;X1;A\r')
self.wait_for_clear(modem.DCD)
def sms_call(self, number):
self.clear_bit(modem.RTS)
self.write_command('AT+MS=V23C;B2;+SMS;X1\r')
cmd = "ATDT " + number + '\r'
if config.sms_debug:
print 'in sms_call, cmd=', cmd
self.write(cmd)
try:
self.wait_response('HDX', 10 * 1000) # CONNECT V.23 HDX
except:
pass
time.sleep(1)
def hw_reset(self):
try:
import runtime
#MMW changed 2006. 01.18
if runtime.modem:
runtime.modem.close()
runtime.modem = None
runtime.dspg.modem_reset()
time.sleep(1)
# time.sleep(1)
runtime.manager.modem_init()
'''
try:
self.open()
except IOError:
time.sleep(5)
self.open()
try:
self.write_command('ATZ\r')
except IOError:
time.sleep(5)
self.write_command('ATZ\r')
if setting.pcm_upstream == 0: #on
modem_patch = config.modem_patch_upstream_on
else:
modem_patch = config.modem_patch_upstream_off
for file in modem_patch:
self.load_patch(file)
self.reset()
'''
#end of MMW
except IOError:
#MMW added 2006.01.17
self.hw_reset()
#end of MMW
pass
#print 'sms.py..hw_reset...IOError..self.write_command(\'ATZ\r\')'
#MMW sw reset added by MMW 2006.01.17
def sw_reset(self):
# time.sleep(1)
try:
try:
self.write_command('ATZ\r')
except IOError:
time.sleep(5)
self.write_command('ATZ\r')
pass
if setting.pcm_upstream == 0: #on
modem_patch = config.modem_patch_upstream_on
else:
modem_patch = config.modem_patch_upstream_off
for file in modem_patch:
self.load_patch(file)
self.reset()
except IOError:
print 'do hw reset'
self.hw_reset()
pass
#end of MMW
def enter_ppp_mode(self):
# eicho add debug 06.01.18
print 'eicho) sms.py:: enter_ppp_mode -- '
# eicho remove again 06.02.07
"""
try:
self.write_command('AT+IBC=1\r')
import os
os.system('echo 1 > /proc/modem_emctl')
except IOError:
pass
#print 'enter_ppp_mode ... IO ERROR!!!! '
#print '###### CAN NOT ENTER PPP-mode ######'
"""
# eicho end.
def leave_ppp_mode(self):
# eicho add debug 06.01.18
print 'eicho) sms.py:: leave_ppp_mode -- '
status.phone_status = status.Disconnected
# eicho remove again 06.02.07
"""
self.write_command('AT+IBC=0\r')
import os
os.system('echo 0 > /proc/modem_emctl')
"""
# eicho end.
def load_patch(self, file):
if config.sms_debug:
print 'loading model patch', file
patch = [x.strip() + '\r' for x in open(file)]
#MMW // 2006. 01. 27
try :
# self.write('AT**\r')
# self.wait_response('..') # 'Download initiated ..'
self.write_command('AT**\r') # . for each line and OK additionally in last command
self.write_command("".join(patch)) # . for each line and OK additionally in last command
return True
except IOError:
return False
#end of MMW
# Patch는 echo, vcid setting들을 다 날려버린다.
def send_sms_error(self, cause):
dll_error = smdl.Maker(DLL_SMS_ERROR, sms_error_code[cause])
self.sms_write_data(str(dll_error))
def send_sms_rel(self):
dll_rel = smdl.Maker(DLL_SMS_REL, '')
self.sms_write_data(str(dll_rel))
def send_sms_nack(self, message=chr(0xFF)):
#FIXME
dll_nack = smdl.Maker(DLL_SMS_NACK, message)
dll_rel = self.send_packet(str(dll_nack))
def send_sms_ack(self):
dll_ack = smdl.Maker(DLL_SMS_ACK, '\x00\x00')
if config.sms_debug:
print 'writing DLL ACK'
return self.send_packet(str(dll_ack))
def send_sms_est(self):
dll_est = smdl.Maker(DLL_SMS_EST, '')
if config.sms_debug:
print 'writing DLL EST'
return self.send_packet(str(dll_est))
def send_packet(self, packet):
if config.sms_debug:
print '******* begin send_packet'
self.sms_write_data(packet)
dll = self.get_packet()
if dll.get_type() == DLL_SMS_ERROR:
self.sms_write_data(packet)
dll = self.get_packet()
if dll.get_type() == DLL_SMS_ERROR:
# A.2.8
self.send_sms_rel()
raise DLLError, "Got too many Error"
if config.sms_debug:
print '******* end send_packet', dll
return dll
def enter_sms_mode(self):
pass
def leave_sms_mode(self):
# eicho change the value 06.05.08
if setting.pcm_upstream == 1: # PCM upstream OFF
self.write_command('ATB3;+MS=V92,1,300,36000,300,36000;+PIG=1\r')
else: # PCM upstream ON
self.write_command('ATB3;+MS=V92,1,300,36000,300,36000;+PIG=0\r')
# eicho end.
def get_packet(self):
ntry = 2
while ntry > 0:
# A.1.4
try:
packet = self.sms_read_data()
except IOError:
if self.got_dll_header:
#이미 header를 가져왔으면 실제 데이타가 명시된 값보다
# 더 작게 들어온 경우이므로 에러를 돌려주어야한다
self.send_sms_error('wrong message length')
ntry -= 1
continue
# A.1.8
self.send_sms_rel()
raise DLLError, "Timeout"
except DLLError:
self.send_sms_error('unknown message type')
continue
if not packet.checksum_valid:
# A.2.5
self.send_sms_error('wrong checksum')
ntry -= 1
else:
return packet
# A.1.6
# FIXME: SC로부터 REL message가 온다
raise DLLError, 'failed to get Packet'
def add_segment(self, dll):
import smtp
smtp_segment = dll.get_payload()
if len(smtp_segment) > 176:
# RX 17(b)
if config.sms_debug:
print 'payload size:', len(smtp_segment)
self.send_sms_nack()
raise TLError, 'Payload size over'
mtype = smtp.get_sms_message_type(smtp_segment)
if mtype == 'deliver':
payload = smtp.Deliver(smtp_segment)
elif mtype == 'status':
if config.sms_debug:
print 'FIXME: Status Report'
utils.print_hex(smtp_segment)
payload = smtp.StatusReport(smtp_segment)
else:
if config.sms_debug:
print 'FIXME: Unknown message type'
utils.print_hex(smtp_segment)
raise DLLError, 'Unknown message type'
# Transfer Layer에서 메시지 오류검사
if payload.bad_udl:
if self.extension_bit:
self.send_sms_error('extension not supported')
raise TLError, "Invalid Message"
else:
self.send_sms_nack()
raise TLError, "Invalid Message"
self.payloads.append(payload)
def sms_answer_prepare(self):
self.enter_sms_mode()
# modem_debug False 시에 sleep 이 없으면 answer 이 잘 되지 않음
self.sms_answer()
def sms_cleanup(self):
self.hangup()
self.leave_sms_mode()
def sms_receive(self):
self.payloads = []
try:
# modem_debug False 시에 sleep 이 없으면 answer 이 잘 되지 않음
# sleep(1) 이하일 경우 너무 빨리 받는 warning이 뜬다
time.sleep(1)
dll_data = self.send_sms_est()
if dll_data.get_type() == DLL_SMS_REL:
raise DLLError, "Invalid Message"
if status.sms_storage_full:
import smtp
message = smtp.DeliverReport('SMS Storage Full').segments[0]
self.send_sms_nack(message)
raise TLError, "Storage Full"
self.add_segment(dll_data)
while 1:
#Roxia Begin cmlim sms_timeout 06.04.13
dll_rel = self.send_sms_ack()
#try:
# dll_rel = self.send_sms_ack()
#except DLLError:
#print '!!!! send_sms_ack except !!!!'
# break;
#Roxia End cmlim sms_timeout 06.04.13
if dll_rel.get_type() == DLL_SMS_DATA:
# A.2.3 Send more than one
self.add_segment(dll_rel)
continue
break
finally:
import traceback
traceback.print_exc()
self.hangup()
self.leave_sms_mode()
return self.payloads
def sms_send(self, messages):
self.enter_sms_mode()
try:
# SMS PABX Code 처리
if setting.phone_extension:
if setting.interdigit_pause:
self.sms_call(setting.phone_extension + ',' * int(setting.interdigit_pause)+ setting.service_center1 + setting.terminal_number + '0')
else:
self.sms_call(setting.phone_extension + setting.service_center1 + setting.terminal_number + '0')
else:
self.sms_call(setting.service_center1 + setting.terminal_number + '0')
dll_est = self.get_packet()
if dll_est.get_type() == DLL_SMS_REL:
raise DLLError, "No Message"
for message in messages:
dll_data = smdl.Maker(DLL_SMS_DATA, message)
dll_ack = self.send_packet(str(dll_data))
if dll_ack.get_type() != DLL_SMS_ACK:
if dll_ack.get_type() == DLL_SMS_NACK:
# A.1.2
self.send_sms_rel()
raise DLLError, 'got NACK instead of ACK'
raise DLLError, 'failed to get ACK'
self.send_sms_rel()
finally:
self.hangup()
self.leave_sms_mode()
class SmsQueue:
def __init__(self):
self.segments = []
self.messages = []
def add(self, segments):
for s in segments:
if s.message_total_number == 1:
if (s.bMMSNoti):
self.messages.append(s)
else:
s.contents = self.content_refine(s.contents)
self.messages.append(s)
else:
self.segments.append(s)
self.sort()
try:
self.merge()
except:
import traceback
traceback.print_stack()
traceback.print_exc()
def get_message(self):
message = []
for m in self.messages:
import smtp
sm = smtp.SmsMessage()
if isinstance(m, smtp.StatusReport):
if config.sms_debug:
print 'call set_from_status_report', m
sm.set_from_status_report(m)
elif isinstance(m, smtp.Deliver):
sm.set_from_deliver(m)
message.append(sm)
self.messages = []
return message
def sort(self):
def segment_sort(x,y):
if x.message_ref == y.message_ref:
return cmp(x.message_seq, y.message_seq)
if x.message_ref > y.message_ref:
return 1
return -1
self.segments.sort(segment_sort)
def merge(self):
if config.sms_debug:
for i, seg in enumerate(self.segments):
print 'index=', i, 'seg num =', seg.message_seq, 'total num=', seg.message_total_number, 'ref =', seg.message_ref
i = 0
while i < len(self.segments):
first_seg = self.segments[i]
if config.sms_debug:
print 'total message number', first_seg.message_total_number
ref = first_seg.message_ref
j = i + 1
while j < len(self.segments) and self.segments[j].message_ref == ref:
j += 1
num_seg = j - i
if num_seg < first_seg.message_total_number:
if config.sms_debug:
print 'Message not sufficent'
i = j
continue
segments = self.segments[i:j]
del self.segments[i:j]
i = j
if len(segments) > first_seg.message_total_number:
new_segs = []
msg_seq = 1
for k, s in enumerate(segments):
if s.message_seq == msg_seq:
new_segs.append(s)
msg_seq += 1
elif s.message_seq > msg_seq:
if config.sms_debug:
print 'bad message seq: discarding'
continue
segments = new_segs
# sanity check
for k in range(len(segments)):
if config.sms_debug:
print 'seq:', segments[k].message_seq
if segments[k].message_seq != (k + 1):
if config.sms_debug:
print '********message seq is not valid, discarding'
return
self.messages.append(self.join_segments(segments))
def join_segments(self, segments):
contents = []
for seg in segments:
for dtype, data in seg.contents:
if dtype == 'Text':
if contents and contents[-1][0] == 'Text':
contents[-1] = 'Text', contents[-1][1] + data
continue
contents.append((dtype, data))
if (segments[0].bMMSNoti):
segments[0].contents = contents
else:
segments[0].contents = self.content_refine(contents)
return segments[0]
def content_refine(self, contents):
raw_data = ''
raw_type = ''
for i, (type, data) in enumerate(contents):
if type == 'Text':
import gsm7
contents[i] = 'Text', gsm7.gsm7bit_decode(data)
elif type in ('Large Picture', 'Small Picture', 'Variable Picture'):
contents[i] = 'Bitmap', data.get_bitmap()
elif type in ('CLI Icon', 'Operator Logo'):
contents[i] = 'Bitmap', data.get_bitmap()
elif type in ('Ring','User Defined Sound', 'Predefined Sound'):
contents[i] = 'Melody', data.get_melody()
elif type == 'Raw':
ctype, cdata = data
if raw_type and ctype != raw_type:
if config.sms_debug:
print 'invalid smartmessage output'
print 'contents', contents
continue
raw_type = ctype
raw_data += cdata
contents[i] = None
if raw_type:
import smartmsg
for cdata in contents:
if cdata != None:
if config.sms_debug:
print 'invalid smartmessage output'
print 'contents', contents
return []
if raw_type == 'Multipart':
multi = smartmsg.Multipart(raw_data)
contents = multi.contents
else:
contents = [smartmsg.parse_content(raw_type, raw_data)]
if config.sms_debug:
print 'contents in', self, contents
return self.content_refine(contents)
if config.sms_debug:
print 'contents in', self, contents
return contents
sms_queue = SmsQueue()
def recv(modem):
payloads = modem.sms_receive()
sms_queue.add(payloads)
message = sms_queue.get_message()
if config.sms_debug:
print '######## recv msg len:', len(message)
return message
def send_email(text, **kw):
import smtp
message = smtp.SmsMessage('0', 'email', [('Text', text)])
message.send()
if __name__ == '__main__':
def handle_modem_event(*ev):
print 'modem event', ev
m = SmsModem(handle_modem_event)
print repr(smdl.Maker(DLL_SMS_EST, ''))
# italy
m.write_command('AT+GCI=59\r')
# korean
#m.write_command('AT+GCI=61\r')
m.write_command('AT-STE=7\r')
m.load_patch('Patch_EIS_07_01_RAM.S37')
if 1:
m.sms_send('123456789012')
# try:
# m.sms_send('Test')
# except:
# print 'except occurred '
# m.leave_sms_mode()
else:
m.sms_receive()
#m.hangup()
print 'all ok...'