B1205是在B8k基础上的cost down产品,接入设备,上行GE,下行5框可以混插ASL和FXS板,主控板为CSM,设备提供VOIP和ASL服务,
FXS硬件图
FXS板代码跑RTEMS,对比B8K改动有:
成本考虑,裁剪51利用SBUS和CSM通信,改为HDLC通信
在链路层和网络层间增加UTMAC层,将普通包数据和IP包数据分开处理
FXS+ASL结合板,增加ASL控制模块
FXS和CSM是通过背板联系起来的,硬件连接CSM的FPGA,CPLD和CSM搭timeslot用
1. FXS板插入
CSM起一个定时器函数,定时去读FPGA,当有板插入时,CSM知道是哪个slot有板插入了;
接着CSM读取单板的CPLD信息,确定具体板类型,有了这些信息,CSM分配highway和HDLC;
FXS侧代码跑起来后,通过底层驱动得到slot,配置CPLD分配highway和HDLC(事先和CSM都协商好的);
接着FXS起utmacstart,通过send_addr_req请求ip地址,CSM响应,根据slot和板类型,分配一个IP给FXS
(比如FXS+slot1:192.168.110.2)
有了这些通信已经建立起来了
2. UTMAC实现
这是UTMAC的数据类型,有包信息类型,有IP请求类型,有心跳类型
/*
*Frame type field
*/
#define UTMAC_DATA_FRAME 0x1
/* Control frame types */
#define UTMAC_IPADDR_REQ_FRAME 0x2
#define UTMAC_IPADDR_FRAME 0x3
#define UTMAC_IPADDR_ACK_FRAME 0x4
#define UTMAC_ECHO_REQ_FRAME 0x5
#define UTMAC_ECHO_RESP_FRAME 0x6
#define UTMAC_SHUTDOWN_FRAME 0x7
#define UTMAC_TEST_DATA_FRAME 0xA
#define UTMAC_51_DATA_FRAME 0x10
这就是心跳的包,00 05 和00 06就是UTMAC头
< 0: (1792) 1939276544
< 49 e1 fe db 00 05 01 c0 a8 6e 02
> 0: (1792) 1939276544
> 49 e1 fe db 00 06 01 c0 a8 6e 00
< 0: (1792) -946339072
< 49 e1 fe df 00 05 02 c0 a8 6e 02
> 0: (1792) -946339072
> 49 e1 fe df 00 06 02 c0 a8 6e 00
这是纯数据包,业务部分几乎都是这种包
> 0: (3072) -946535680
> 49 e1 fe d7 00 10 00 06 00 04 03 fe 08 37 44 bb
> 0: (6656) -946535680
> 49 e1 fe d7 00 10 00 14 00 12 16 03 01 c2 ff 92
> 00 00 00 00 07 07 00 00 00 00 00 00 8d 72
这是IP包,MIB表项配置几乎都是这种包
< 0: (22528) 462816000
< 49 e1 fe d8 00 01 45 00 00 56 00 01 00 00 40 11
< 1d 43 c0 a8 6e 02 c0 a8 6e 00 13 8e 13 8d 00 42
< 25 a9 55 4d 03 01 08 01 00 11 00 00 00 00 02 01
< a5 00 00 02 06 00 04 00 01 00 00 00 01 01 04 00
< 01 c0 a8 6e 02 02 01 00 01 00 03 01 00 01 00 04
< 01 00 06 00 00 00 00 00 00 ff 84 b7
UTMAC必须保证工作正常,所以保持和CSM来交互;
当超时时,UTMAC会挂掉,报警到NMS;
但是UTMAC必须要自动起来,所以这个时候心跳
UTMAC从一开始就起定时器函数,超时处理函数为timer_handler,
FXS发UTMAC_ECHO_REQ_FRAME到CSM,CSM回UTMAC_ECHO_RESP_FRAME,FXS收到回UTMAC_ECHO_RESP_FRAME,(这里很重要一点,记录当前时钟)stop_echo_timer,并重新定时,这个时候FXS没有请求,timer_handler会超时,处理process_utmac_timeout,重新开始UTMAC_ECHO_REQ_FRAME请求和定时
static void start_echo_timer ()
{
start_timer((TIMER **)&echo_timer,
(U32)0, timer_handler, ECHO_TIMEOUT, 0);
}
......
static void timer_handler (U32 tm)
{
OS_STATUS rc;
qbuf_t *q;
/* echo_timer = 0; Removed by Jacky Liu. */
rc = alloc_msg_buf( (void **)&q, sizeof(qbuf_t));
if ( rc == SUCCESS )
{
memset((void *)q, 0, sizeof(qbuf_t));
q->buffer_retain = BUFFER_FREE;
q->primitive = UTMAC_TIMEOUT_EVENT;
q->source = IP_PROC_ID;
rc = send_msg(UTMAC_QUEUE,(void **)&q, NO_SUSPEND );
if (rc != SUCCESS)
dealloc_msg_buf( (void *)q );
}
}
......
static void process_utmac_timeout ()
{
int utmac_idx;
U32 time_diff;
utmac_info_t *info_p=NULL;
hdlc_ibc_ts_t ibc;
info_p = find_utmac_chan(LocalShelf, LocalSlot);
utmac_idx = info_p - &UtmacInfo[0];
switch (info_p->state)
{
case UTMAC_UP:
if (!info_p->alarm_state)
{
time_diff = (Retrieve_Clock() - info_p->last_echo_tm)/100;
if(time_diff > ECHO_THRESHOLD)
{
/* Let OAM know this state. */
info_p->state = UTMAC_DOWN;
info_p->alarm_state = TRUE;
send_oam_status(ECHO_ACK_EXPIRED);
}
else
{
send_echo_req(info_p, Tag);
Tag++;
start_echo_timer();
}
}
......
case UTMAC_DOWN:
/* add by hyg for UTMAC_DOWN state */
/* Let OAM know this state. */
down_up = 1;
info_p->state = UTMAC_UP;
info_p->alarm_state = FALSE;
//send_oam_status(UTMAC_IS_UP);
/* should not send UTMAC_IS_UP state, for now it is still down */
info_p->last_echo_tm = Retrieve_Clock();
send_echo_req(info_p, Tag);
Tag++;
start_echo_timer();
break;
default:
}
}
出问题的时候,FXS没有收到回UTMAC_ECHO_RESP_FRAME,这个时候,timer_handler会超时,处理process_utmac_timeout,重新开始UTMAC_ECHO_REQ_FRAME请求和定时,重复这几步,等待下面条件符合的时候,就会UTMAC挂掉,报警
time_diff = (Retrieve_Clock() - info_p->last_echo_tm)/100;
/* 当前时间和最后一次正常心跳的时间差 */
if(time_diff > ECHO_THRESHOLD)
/* 大于设定的一个值,比如3分钟 */
如果重新起来,记录当前时间,重新发,如果3分钟内UTMAC通了,就UP起来了,如果3分钟内还没通,又重复这样的工作。
搞不懂新泽西研发为什么这样写,直接一个定时器函数心跳,不通就DOWN,再起定时器,非常的简单
3. HDLC代替51通信
两个数据接口要重新封装,发送数据用sendDatatohdlc代替sendDatato51底层接口
#if 0
int sendDatato51(int minor, const char *buf, int len){
if(SPI_SUCCESS==spi_send(buf,len))
{
spi_ignore_next_pack=TRUE;
//record len to trim returned package, get the ACK/NACK byte
spi_ignore_package_len=len;
return len;
}
else
return -1;
}
#endif
int sendDatatohdlc(int minor, const char *buf, int len){
if(SUCCESS == hdlc_utmac_send_51(minor, buf, len))
{
//spi_ignore_next_pack=TRUE;
//record len to trim returned package, get the ACK/NACK byte
//spi_ignore_package_len=len;
return len;
}
else
return -1;
}
接收数据不需要从51收了,直接从UTMAC收到的数据做为接口,增加UTMAC_51_DATA_FRAME数据类型,当然CSM侧同样增加这个类型,所有原来发往51的数据全部走这条路,HDLC消息处理的方式和原来51一样即可
......
case UTMAC_51_DATA_FRAME:
if (utmac_dedug_flag) printf("UTMAC_51_DATA_FRAME /n");
sc->sc_stats.ipackets += 1;
receiveDatafromhdlc(qb->pdata+UTMAC_HEADER_SIZE, qb->data_size-UTMAC_HEADER_SIZE);
break;
......
4. ADSL控制任务
需要增加一个任务adsl_ctrl_main,和ASL通信模块利用SCC接口,收发数据通过中断
下面是adsl_ctrl_main接收到的事件
......
if(event_out & EVNT_SCC3_TO_ADSL)
adsl_ctrl_proc_scc3_msg();
if(event_out & EVNT_OAM_TO_ADSL)
adsl_ctrl_proc_oam_msg();
if(event_out & EVNT_ADSL_TIMEROUT)
adsl_ctrl_proc_timerout_msg();
......
收到的EVNT_OAM_TO_ADSL来自OAM控制模块,因为FXS只是做一个控制模块而已,比如升级ASL模块,MIB信息先到FXS的OAM,FXS通过OAM模块送到adsl_ctrl_main,收到之后,会讲消息转发到ADSL板
收到EVNT_SCC3_TO_ADSL来自底层的SCC的中断,这是来自的ADSL板的消息
流程是:
ASL板起来后,会发消息过来,取板卡的shelf和slot;FXS响应,起心跳函数
void repeat_HeartBeat()
{
snd_heartbeat_req_to_adsl();
//start a timer to monitor the response.
if(heartBeat_repeat_count >= 10)// repeat 10 timers
{
if(sys_info.adsl_st != ADSL_ACTIVE)
reset_adsl();
if(sys_info.adsl_st != ADSL_UPSTARTING)
sys_info.adsl_st = ADSL_INACTIVE;
heartBeat_repeat_count = 0;
send_fxs_alarm_to_oam (ALARM_FXS_ADSL_COMMUNICATION , 1, 0xff);
}
else heartBeat_repeat_count++;
start_timer(&ADSL_HEARTBEAT_RESPONSE_TIMER, 0, heartBeat_TimerOut, HEARTBEAT_REPEAT_TIMER,0);
}
发送心跳消息到ASL,起定时器
如果正常情况收到ASL的心跳响应,关定时器,再心跳重复操作
/*when rcv heartbeat cmd from adsl*/
case 0x00:
{
/*response with 0xff*/
snd_heartbeat_rsp_to_adsl();
if(sys_info.adsl_st == ADSL_UPSTARTING)
{
//adsl has been successfully started,then close the timer;
if(ADSL_STARTUP_TIMER)
{
stop_timer(ADSL_STARTUP_TIMER);
ADSL_STARTUP_TIMER = NULL;
ADSL_TRACE(adsl_trace_debug,"ADSL has been started......../n");
}
//snd the repeated heartbeat
//repeat_HeartBeat();
}
else if(sys_info.adsl_st != ADSL_DOWNLOAD) sys_info.adsl_st = ADSL_ACTIVE;
ADSL_TRACE(adsl_trace_debug,"send heartbeat response code 0xff/n");
heartBeat_repeat_count = 0;
pmsg++;
}
break;
如果不正常情况会超时,执行定时器超时函数,给adsl_ctrl_main发送EVNT_ADSL_TIMEROUT事件,执行repeat_HeartBeat,上报NMS响应ALARM
5. 小结
编译FXS出错,是因为编译过IVD了,有些LIB是共用的,应该删除后重编
出现 bin/sh莫名其妙字符错误,说明是dos和unix的问题
shelf_slot_port = (sys_info.shelf_id<<16)+(sys_info.slot_id<<8)+0xff;找了很久原因居然是这里,应该用或就OK
ST的大呼没过,调试发现23层间的UTMAC层有数据包丢了,怀疑是HDLC问题,只好写个暴力测试函数,从CSM发N多包到FXS,HDLC统计数据和CSM测统计对比,数据数量不一致,研究一下HDLC驱动,修改OK
大呼效率低下,发现VCP串口打印过多,关掉打印,OK
现场出现了UTMAC挂掉后,电话通信OK,FXS管理断掉了,这个问题说明了HDLC底层通信正常,UTMAC层不通了,最后发现是process_utmac_timeout中没对UTMAC_DOWN: 处理,添加处理函数,OK