⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.cpp

📁 C++ modem驱动代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/** * uart.cpp * This file is part of the YATE Project http://YATE.null.ro * * Yet Another Modem * * Yet Another Telephony Engine - a fully featured software PBX and IVR * Copyright (C) 2004-2006 Null Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */#include "yatemodem.h"#include <string.h>using namespace TelEngine;// ETSI EN 300 659-1: 5.2// Channel seizure signal: block of 300 continuous bits of alternating 0 and 1// Use both values to detect the begining of an ETSI defined message://  the modem might loose the first bits#define ETSI_CHANNEL_SEIZURE_1 0x55            // 01010101#define ETSI_CHANNEL_SEIZURE_2 0xaa            // 10101010// Convert a buffer to a shortstatic inline short net2short(unsigned char* buffer){    return (buffer[0] << 8) | buffer[1];}// Get date and time from system of received param// dt: month,day,hour,minute;// Return false if invalidstatic bool getDateTime(unsigned char dt[4], String* src = 0, char sep = ':'){    static int minDt[4] = {1,1,0,0};    static int maxDt[4] = {12,31,23,59};    if (!src) {	// TODO: implement from system time	return false;    }    ObjList* list = src->split(sep);    int i = 0;    for (; i < 4; i++) {	String* s = static_cast<String*>((*list)[i]);	int tmp = s ? s->toInteger(-1) : -1;	if (tmp >= minDt[i] && tmp <= maxDt[i])	    dt[i] = (unsigned char)tmp;	else	    i = 5;    }    delete list;    return (i == 4);}// ETSI EN 300 659-3 5.4.4 Reason of caller absencestatic TokenDict s_dict_callerAbsence[] = {    {"unavailable", 0x4f},    {"restricted",  0x50},    {0,0}};// ETSI EN 300 659-3 5.4.8 Message identificationstatic TokenDict s_dict_mwiStatus[] = {    {"removed",     0x00},    {"reference",   0x55},               // Message reference only    {"added",       0xff},    {0,0}};// ETSI EN 300 659-3 5.4.12 Call typestatic TokenDict s_dict_callType[] = {    {"voice",          0x01},            // Normal (voice) Call    {"ccbs-ccnr",      0x02},            // CCBS / CCNR    {"callername",     0x03},            // Calling Name Delivery    {"return",         0x04},            // Call Return    {"alarm",          0x05},            // Alarm Call    {"download",       0x06},            // Download Function    {"reverse-charge", 0x07},            // Reverse Charging Call    {"vpn_external",   0x10},            // External Call (VPN)    {"vpn_internal",   0x11},            // Internal Call (VPN)    {"monitoring",     0x50},            // Monitoring Call    {"message",        0x81},            // Message Waiting Call    {0,0}};// ETSI EN 300 659-3 5.4.16 Caller typestatic TokenDict s_dict_callerType[] = {    {"unknown",             0x00},       // Origination unknown or unavailable    {"voice",               0x01},       // Voice Call    {"text",                0x02},       // Text Call    {"vpn",                 0x03},       // VPN (Virtual Private Network)    {"mobile",              0x04},       // Mobile phone    {"mobile-vpn",          0x05},       // Mobile phone + VPN    {"fax",                 0x06},       // Fax Call    {"video",               0x07},       // Video Call    {"e-mail",              0x08},       // E-mail Call    {"operator",            0x09},       // Operator Call    {"ordinary-subscriber", 0x0a},       // Ordinary calling subscriber    {"priority-subscriber", 0x0b},       // Calling subscriber with priority    {"data",                0x0c},       // Data Call    {"test",                0x0d},       // Test call    {"telemetric",          0x0e},       // Telemetric Call    {"payphone",            0x0f},       // Payphone    {0,0}};// ETSI EN 300 659-3 5.4.15 Forwarded call reasonstatic TokenDict s_dict_ffwdReason[] = {    {"unknown",             0x00},       // Unavailable or unknown forwarded call type    {"busy",                0x01},       // Forwarded call on busy    {"noanswer",            0x02},       // Forwarded call on no reply    {"unconditional",       0x03},       // Unconditional forwarded call    {"deflected-alerted",   0x04},       // Deflected call (after alerting)    {"deflected-immediate", 0x05},       // Deflected call (immediate)    {"mobile-not-found",    0x06},       // Forwarded call on inability to reach mobile subscriber    {0,0}};/** * ETSIModem */static TokenDict s_etsiState[] = {    {"Error",    ETSIModem::StateError},    {"FSKStart", ETSIModem::WaitFSKStart},    {"Mark",     ETSIModem::WaitMark},    {"Msg",      ETSIModem::WaitMsg},    {"MsgLen",   ETSIModem::WaitMsgLen},    {"Param",    ETSIModem::WaitParam},    {"ParamLen", ETSIModem::WaitParamLen},    {"Data",     ETSIModem::WaitData},    {"Chksum",   ETSIModem::WaitChksum},    {0,0}};TokenDict ETSIModem::s_msg[] = {    {"CallSetup", ETSIModem::MsgCallSetup},    {"MWI",       ETSIModem::MsgMWI},    {"Charge",    ETSIModem::MsgCharge},    {"SMS",       ETSIModem::MsgSMS},    {0,0}};#define MAKE_NAME(x) { #x, ETSIModem::x }TokenDict ETSIModem::s_msgParams[] = {    {"datetime",              DateTime},    {"caller",                CallerId},    {"called",                CalledId},    {"callerpres",            CallerIdReason},    {"callername",            CallerName},    {"callernamepres",        CallerNameReason},    {"visualindicator",       VisualIndicator},    {"message_status",        MessageId},    {"message_caller",        LastMsgCLI},    {"service_datetime",      CompDateTime},    {"networkprovidedcaller", CompCallerId},    {"calltype",              CallType},    {"fwd_first",             FirstCalledId},    {"message_count",         MWICount},    {"fwd_calltype",          FwdCallType},    {"callertype",            CallerType},    {"fwd_last",              RedirNumber},    {"charge",                Charge},    {"additionalcharge",      AdditionalCharge},    {"callduration",          Duration},    {"netid",                 NetworkID},    {"carrierid",             CarrierId},    {"display",               Display},    {"serviceinfo",           ServiceInfo},    {"extension",             Extension},    {"selectfunction",        SelectFunction},    {0,0}};ETSIModem::ETSIModem(const NamedList& params, const char* name)    : UART(UART::Idle,params,name),    m_buffer(this),    m_state(WaitFSKStart),    m_waitSeizureCount(3),    m_crtSeizureCount(0){    reset();}ETSIModem::~ETSIModem(){}void ETSIModem::reset(){    m_buffer.reset();    m_crtMsg = m_crtParamLen = 0;    m_chksum = 0;    m_crtSeizureCount = 0;    m_state = WaitFSKStart;    UART::reset();}// Process accumulated byte in Idle state// Return negative to stop, positive to change state to BitStart, 0 to continue// See ETSI EN 300 659-1 for data transmission// 1. Channel seizure signal: block of 300 continuous bits of alternating 0 and 1// 1. Mark (stop bits) signal: 180(+/-25) or 80(+/-25) bits// 3. Message transmission: START bit / DATA bits / STOP bitint ETSIModem::idleRecvByte(unsigned char data){    XDebug(this,DebugAll,"idleRecvByte(%u,0x%02x,'%c') ETSI state=%s [%p]",	data,data,(data>=32)?(char)data:' ',lookup(m_state,s_etsiState),this);    switch (m_state) {	case WaitFSKStart:	    if (data == ETSI_CHANNEL_SEIZURE_1 || data == ETSI_CHANNEL_SEIZURE_2) {		m_crtSeizureCount++;		if (m_crtSeizureCount == m_waitSeizureCount) {		    DDebug(this,DebugInfo,"Received FSK start pattern [%p]",this);		    changeState(WaitMark);		}	    }	    else		m_crtSeizureCount = 0;	    return 0;	case WaitMark:	    if (data != 0xff)		return 0;	    DDebug(this,DebugInfo,"Received mark signal. Waiting message [%p]",this);	    changeState(WaitMsg);	    return 1;	default: ;    }    return -1;}// Push a data byte into this UART. Reset this UART and call decode after validated a received message// Return false to stop feeding databool ETSIModem::recvByte(unsigned char data){    XDebug(this,DebugAll,"recvByte(%u,0x%02x,'%c') ETSI state=%s [%p]",	data,data,(data>=32)?(char)data:' ',lookup(m_state,s_etsiState),this);    switch (m_state) {	case WaitData:	    if (!m_crtParamLen) {		Debug(this,DebugWarn,"Internal: received unexpected parameter data [%p]",this);		break;	    }	    XDebug(this,DebugAll,"Received parameter data %u [%p]",data,this);	    if (!m_buffer.accumulate(data))		break;	    m_chksum += data;	    m_crtParamLen--;	    if (!m_crtParamLen)		changeState(m_buffer.free() ? WaitParam : WaitChksum);	    return true;	case WaitParam:	    NDebug(this,DebugAll,"Received parameter start %u=%s [%p]",		data,lookup(data,s_msgParams),this);	    if (!m_buffer.accumulate(data))		break;	    m_chksum += data;	    changeState(WaitParamLen);	    return true;	case WaitParamLen:	    if (!data || data > m_buffer.free()) {		Debug(this,DebugNote,		    "Received invalid parameter length %u (buffer=%u free=%u) [%p]",		    data,m_buffer.buffer().length(),m_buffer.free(),this);		break;	    }	    NDebug(this,DebugAll,"Received parameter length %u [%p]",data,this);	    if (!m_buffer.accumulate(data))		break;	    m_chksum += data;	    m_crtParamLen = data;	    changeState(WaitData);	    return true;	case WaitMsgLen:	    if (data < 3) {		Debug(this,DebugNote,"Received invalid message length %u [%p]",data,this);		break;	    }	    m_buffer.reset(data);	    m_chksum = m_crtMsg + data;	    NDebug(this,DebugAll,"Received message length %u [%p]",data,this);	    changeState(WaitParam);	    return true;	case WaitMsg:	    if (!lookup(data,s_msg))		return true;	    m_crtMsg = data;	    NDebug(this,DebugInfo,"Received message start: %s [%p]",lookup(m_crtMsg,s_msg),this);	    changeState(WaitMsgLen);	    return true;	case WaitChksum:	    if (data == (256 - (m_chksum & 0xff))) {		NDebug(this,DebugAll,"Checksum OK for message %s [%p]",		    lookup(m_crtMsg,s_msg),this);		return decode((MsgType)m_crtMsg,m_buffer.buffer());	    }	    Debug(this,DebugNote,"Checksum failed for message (recv=%u crt=%u) %s [%p]",		data,m_chksum,lookup(m_crtMsg,s_msg),this);	    changeState(StateError);	    return UART::error(UART::EChksum);	case StateError:	    return false;	default:	    DDebug(this,DebugNote,"Can't process data in state %s [%p]",		lookup(m_state,s_etsiState),this);	    return true;    }    changeState(StateError);    return UART::error(UART::EInvalidData);}// Set a date time digits stringinline void setDateTime(String& dest, const char* data, unsigned int count){    dest << data[0] << data[1];    for (unsigned int i = 2; i < count; i += 2)	dest << ':' << data[i] << data[i+1];}// Process (decode) a valid received buffer. Call recvParams() after decoding the message// Return false to stop processing databool ETSIModem::decode(MsgType msg, const DataBlock& buffer){    NamedList params("");    DDebug(this,DebugAll,"Decoding message %s [%p]",lookup(msg,s_msg),this);    unsigned char* data = (unsigned char*)buffer.data();    for (unsigned int i = 0; i < buffer.length();) {	unsigned char param = data[i++];                                // Param type	const char* pname = lookup(param,s_msgParams);	unsigned int len = data[i++];                                   // Param length (non 0)	unsigned char* pdata = data + i;	// End of buffer: Force index outside the end of buffer	if (i < buffer.length())	    i += data[i-1];	else	    i++;	if (i > buffer.length()) {	    Debug(this,DebugWarn,"Unexpected end of %s parameter [%p]",pname,this);	    return UART::error(UART::EInvalidData);	}	String tmp;#define CHECK_LEN(expected) \	if (len != expected) { \	    Debug(this,DebugNote,"Invalid len=%u (expected %u) for %s parameter [%p]",len,expected,pname,this); \	    continue; \	}#define SET_PARAM_FROM_DATA(paramname) \	tmp.assign((char*)pdata,len); \	params.addParam(paramname,tmp);#define SET_PARAM_FROM_DICT(paramname,dict) \	tmp = lookup(*pdata,dict,"unknown"); \	params.addParam(paramname,tmp);	// Process parameters	// References are the sections from ETSI EN 300 659-3	switch (param) {	    case CallerId:               // 5.4.2		SET_PARAM_FROM_DATA("caller")		break;	    case CallerName:             // 5.4.5		SET_PARAM_FROM_DATA("callername")		break;	    case CallerIdReason:         // 5.4.4		CHECK_LEN(1)		SET_PARAM_FROM_DICT("callerpres",s_dict_callerAbsence)		break;	    case CallerNameReason:       // 5.4.6		CHECK_LEN(1)		SET_PARAM_FROM_DICT("callernamepres",s_dict_callerAbsence)		break;	    case DateTime:               // 5.4.1

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -