Access-B1202

B1202B1205的小框,直接放楼道,接入设备,上行GE,或者EPON,下行4框可以混插ASLFXS板,提供VOIPASL服务,CSM主控板含VOIPDSP芯片处理VOIP业务

支持ADSL2+接入,ADSL2+ 板卡密度为32路/卡,每框最大支持128路 
    支持VoIP接入,POTS板卡密度为48路/卡,每框最大支持192路 
    支持VDSL2接入,VDSL2板卡密度为16路/卡,每框最大支持最多64路 
    支持LAN接入,LAN板卡密度为24路/卡,每框最大支持96路 

FXS板卡上CPU为了costdown,裁减,代码移植到CSM主控板做为linux的一个进程运行,移植的改动包括:

down_ctrl以及filesystem以及RTEMS协议栈等这些任务不需要了

B1205跑的是RTEMS系统,现在跑的是LINUX,系统相关的API全部要重新封装

因为进程后台运行,增加cliserv_task线程,方便终端调试

UTMAC不需要了,起main_thread线程代替B1205HDLC通信

FXS通信的HIP进程同样换成socket通信

MIB通信以前由192.168.100.*来通信,现在改走localhost,每个板子的port不一样

 

1.        编译问题

 

因为从RTMESLINUX的更改,耗时而繁琐的工作,先把需要更改的理一下:

B1205FXS是基于JAMFILE来管理编译的,虽然CSM是用cmake,为了减轻工作量,毕竟这个FXS进程是我一个人维护,不会影响别人的,所以在LINUX下继续坚持用JAMFILE,到时候只要添加到整个项目的脚本中即可

先把不需要的任务统统删除,为了编译通过,先暂时增加一个undef_func.cundef_func.h,添加一些没有定义的函数以及变量,到时候调试代码过程中再去响应的*.c中添加函数和变量

B1205RTEMS系统API,通通封装为空,为了编译通过,暂时不要理会

下面是B1205B1202目录的对比图

 

其中MISS目录就是为了添加的undef_func.cundef_func.h目录,其它没有的目录全部删除掉,当然JAMFILE中这些目录的编译选项要相应删除

另外增加一个mian入口,要不然编译不通过的

 

2.        系统API封装

 

编译通过了,就开始porting系统的API了,主要集中在utkernel.c,包括:任务(线程)消息队列事件 信号量 信号 定时器

 

信号量相对简单,几乎小改即可

rtems_semaphore_create

sem_init

 

rtems_semaphore_release

sem_post

 

rtems_semaphore_obtain

sem_wait

 

......

OS_STATUS

free_semaphore (SEMAPHORE * semaphore)

{

  OS_STATUS rc;

 

  if ( semaphore == NULL )

  {

     return( FAILURE );

  }

 

//  rc = (OS_STATUS) rtems_semaphore_release( semaphore->sem_id );

    rc = (OS_STATUS)sem_post((sem_t *)&semaphore->sem_id);

  return ( rc );

}

......

 

 

信号

这个是增加用来debug用,当crash的时候可以dump看挂掉的位置,直接添加几个信号加上backtrace

 

定时器函数

RTEMS拥有rtems_timer_create定时器函数,linux下这个我还没实现呢,linux下虽然可以用SIGALRM信号实现,但是如果同一进程中多次使用的定时器呢?应该需要增加一个结构,当定时器超时时来判断到底是哪个函数执行

 

线程

task_create就是封装的线程

alloc_task_info的目的是维护task_tables 为了get_set_task_name/get_task_id/print_tasks,为了照顾RTEMS的那一套机制

......   

    #if 0

    /* Create task */

    status = rtems_task_create( tptr->namestr,

                                tptr->priority,

                                tptr->stack_size,

                                tptr->preempt_option,

                                tptr->attribute,

                                &(tptr->task_id) );

                 

    if ( status == RTEMS_SUCCESSFUL )

       rtems_task_start(tptr->task_id, tptr->entrypt, tptr->attribute);

    else

       printf("INIT ERROR: Failure creating task: %s, status = %d/n",

              tptr->task_name, status );

    #endif

    syslog(LOG_INFO,"creating task: %s",tptr->task_name);

    task_create( tptr->task_name, tptr->priority,

                                tptr->stack_size,

                                tptr->preempt_option,&(tptr->task_id),tptr->entrypt ,NULL);

......

 

int task_create( char *name, U32 priority, U32 stack_size,U32 preempt_option,U32 *id,void*(*entrypt)(void*) ,void *param)

{

  pthread_attr_t attr;

  struct sched_param s_param;

  int status;

  rtems_user_task_table *task;

  if(disable_cli&&(strncmp(name,"cli_",4)==0))

      return 0;

  pthread_attr_init(&attr);

  pthread_attr_setstacksize(&attr, (size_t)stack_size);

  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

 

  task=alloc_task_info(name,entrypt,param);

  if(task == NULL)

  {

    syslog(LOG_ERR,"alloc_task_info(%s,%p,%p) failed/n",name,entrypt,param);

    return -1;

  }

  if ((status=pthread_create(id, &attr, task_startup, task)) != 0)

      {      /* mt020.201 - Addition for destroying thread attribute object attr */

      pthread_attr_destroy(&attr);

    fprintf(stderr,"INIT ERROR: Failure creating task: %s, status = %d/n",              name, status );

    return status;

    }   /* mt020.201 - Addition for destroying thread attribute object attr */

  pthread_attr_destroy(&attr);

  task->task_id = *id;

  fprintf(stderr,"creating task: %s, status = %d/n",              name, status );

 

  return 0;

}

移植的消息队列-rtems_message_queue_create,和事件-rtems_event_send没仔细研究过,部门架构师之前封装了这些RTEMSLINUX的接口,直接拿过来用的,需要改动的就是参数的调整

 

3.        cliserv_task线程

 

debug命令行还是RTEMS的那一套机制,dbg_entry是单独起的一个调试线程,shell_add_cmdRTMES的命令行调试命令,getaline是解析输入命令,process_line调用shell_lookup_cmd来执行调试命令

cliserv_task这个线程用来起一个socket的服务器,采用select方式,后台运行的话,写一个client程序,连接到FXS进程就有一个单独的调试窗口了,fcli0.ipc就是通信用的IPC,参考socket

 

......

    const char *pathcli[]={

        "/tmp/ipc/fcli0.ipc",

        "/tmp/ipc/fcli1.ipc",

        "/tmp/ipc/fcli2.ipc",

        "/tmp/ipc/fcli3.ipc",

    };   

......  

    task_create("clis",81,8096,SCHED_FIFO,&init_tid,cliserv_task,(void*)(pathcli[sys_info.slot_id]));

......

void dbg_entry (

        void* ignore)

{

    U8 line[512];

    U8*  dbg_prompt_s ;

    struct termios term;

    setvbuf(stdin, NULL, _IONBF, 0); /* Not buffered*/

#if 1

    if (tcgetattr(fileno(stdin), &term) >= 0)    

    {   

        oldterm = term;

        term.c_lflag &= ~(ECHO|ECHONL | ICANON | ISIG | IEXTEN);/*ECHO | */

        term.c_cc[VMIN] = 1;

        term.c_cc[VTIME] = 0;

        if (tcsetattr(fileno(stdin), TCSADRAIN, &term) < 0)

        {

            fprintf(stderr, "shell:cannot set terminal attributes/n");

        }

    }

#endif

    dbg_prompt_s =  "FXS> " ;

 

    udbg_init();

    shell_add_cmd(NULL, NULL, NULL, NULL, 0); /* init the chain list*/

    for (;;)

    {

        printf(dbg_prompt_s);

        fflush(stdout);

        getaline(&line);             /* in target, there is a different way ? */

        if ((line[0] == 0)||(line[0] == '/n'))

            continue;

        process_line(line);

    }

 

}

......

 

4.        main_thread的实现

 

B1205HDLC通信在B1202中不需要了,因为在一个CPU上,通信变得更简单了,采用AF_UNIX内部的localhost通信,port不一致而已,仍然采用select方式,sys_info.slot_id是脚本带入的参数,slot0.ipc就是通信用的IPC,参考socket

HIP进程底层一样的做相应的改动,在原来收发包的地方换成,socket通信

 

......   

    const char *path[]={

        "/tmp/ipc/slot0.ipc",

        "/tmp/ipc/slot1.ipc",

        "/tmp/ipc/slot2.ipc",

        "/tmp/ipc/slot3.ipc",

    };   

    slotx_fd = setup_server_socket_udp(path[sys_info.slot_id]);

......

void *main_thread(void *param)

{

    fd_set rset;

    int maxfd=0;

    int rv;

    qbuf_t *msgp;

 

    while(1)

    {

        FD_ZERO(&rset);

        if(slotx_fd != -1)

                    FD_SET(slotx_fd, &rset);

        maxfd = max( maxfd, slotx_fd);

 

        rv =  select (maxfd + 1, &rset, NULL, NULL, NULL);

        if (rv < 0)

        {

            syslog(LOG_INFO, "select returned error %d/n", errno);

            continue;

        }

        if ((slotx_fd != -1) && (FD_ISSET(slotx_fd, &rset)))

        {

            //syslog(LOG_INFO,"receive from SBUS driver/n");

            //syslog(LOG_INFO,"data------------/n");

            rv = recv_msg_from_slotx(slotx_fd,rx_buffer);

            if(rv)

            proc_msg_from_slotx(rx_buffer,rv);

        }

    }

 

}

 

5.        板卡启动流程

 

B1202因为没有了板卡代码,所以整个流程是

当板卡插入时,HIP进程起一个定时器函数,定时去读FPGA的数据,判断每个slot是否有板卡插入

如果有,去读FXSCPLD寄存器,判断是否是FXS板,如果不是FXS就说明是ASL

如果是FXSstart_rmp_fxs是一个脚本,它会后台起FXS进程的,fxs_board_id是带入到脚本的参数,上面的main_thread中的sys_info.slot_id就是根据这个这个参数值

sprintf(cmd,"start_rmp_fxs %d >>/var/log/messages", fxs_board_id);

xsystem(cmd);

如果板卡拔出,同样HIP会知道的,直接KILLFXS进程

这样整个流程几乎和B1205类似,底层通信接口也正常,上层不用改动

 

6.        MIB通信

 

k_fxsServerPort*是枚举的port,还是sys_info.slot_id根据来分配不同的port给不同slotFXS进程,采用的是localhost,不同的port的区别的

...... 

    switch(sys_info.slot_id)

    {

        case 0:

            k_fxsServerPort = k_fxsServerPort0;

            k_fxsSyncPort = k_fxsSyncPort0;    

            k_fxsAsyncPort = k_fxsAsyncPort0;

            k_fxsmmlPort = k_fxsmmlPort0;       

            break;

        case 1:

            k_fxsServerPort = k_fxsServerPort1;

            k_fxsSyncPort = k_fxsSyncPort1;    

            k_fxsAsyncPort = k_fxsAsyncPort1;

            k_fxsmmlPort = k_fxsmmlPort1;       

            break;

        case 2:

            k_fxsServerPort = k_fxsServerPort2;

            k_fxsSyncPort = k_fxsSyncPort2;    

            k_fxsAsyncPort = k_fxsAsyncPort2;

            k_fxsmmlPort = k_fxsmmlPort2;       

            break;

        case 3:

            k_fxsServerPort = k_fxsServerPort3;

            k_fxsSyncPort = k_fxsSyncPort3;    

            k_fxsAsyncPort = k_fxsAsyncPort3;

            k_fxsmmlPort = k_fxsmmlPort3;       

            break;   

        default:

            break;

    }

......

static void

oamInitUdl(void)

{

  /*  Register the UDL ports.  */

 

  if (register_udl_port(OAM_QUEUE, k_fxsServerPort, k_serverPort) != RV_OK)

    rtems_panic("could not register OAM server port with UDL");

  if (register_udl_port(OAM_QUEUE, k_fxsSyncPort, k_syncPort) != RV_OK)

    rtems_panic("could not register OAM sync port with UDL");

  if (register_udl_port(OAM_QUEUE, k_fxsAsyncPort, k_asyncPort) != RV_OK)

    rtems_panic("could not register OAM async port with UDL");

 

  /*  Register the UDL command handler.  */

 

  if (register_udl_cmd_handler(k_fxsServerPort, oamCommandHandler, (void *) 0)

      != RV_OK)

  {

    rtems_panic("could not register OAM command handler with UDL");

  }

}

 

7.        其它封装

 

查看线程,查看memAPI重新封装一下

FXS原来依靠UTMAC通信的接口要重新做到socket接口,数据格式要重新调整,把UTMAC的包头全部去掉

HIPUTMAC通信接口也重新封装,一样的数据格式需要调整

OAM进程和FXSMIB通信接口的IPPORT需要做相应更改

ASL没有CPLD,每次通过FXSGPIOASL消息

RTMES的一些原来用的调试API封装

......

 

8.        小结

JAMFILE的报错莫名其妙,它对;和;识别有问题;bin/jamfileLC_LIBS += libvcp_ctrl; 也报错,需要加一个空格在""

自己有unharject的文件,没想到这个文件也被别人改过了,所以编译不过啊!!

if (serv_fd = socket(AF_UNIX, SOCK_STREAM, NULL) < 0) 这行代码写得太失败了,接下来当然100%bind错误

taskid也就是线程的ID号,因为没有封装线程ID号和线程命的函数,直接导致线程间通信不正确

第一次用IPC通信,/tmp/ipc/slot0.ipc居然自己去新建一个,可笑

HIP中按照FXSmemmapU8来读GPIO数据完全不对,GPIO这个时候应该U32

VCP升级后,接口API参数也不一样,而且初始化流程也变了,害惨我了

printf打印不成功,是因为printf重定向错误了,打到另外一个终端窗口去了

读取FXSCPLD数据需要延时,要不然数据不正确,直接板卡判断失误

OAM进程的数据发送以前按照192.168.110.*发送,现在发送的IPPORT变换了,发送到了ASL板上去了

 

你可能感兴趣的:(Access-B1202)