631 lines
15 KiB
C
631 lines
15 KiB
C
/*****************************************************************************
|
|
* pos_api.c POS API
|
|
*
|
|
* Author(s): Nenad Corbic <ncorbic@sangoma.com>
|
|
*
|
|
* Copyright: (c) 2003 Sangoma Technologies Inc.
|
|
*
|
|
* 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.
|
|
* ============================================================================
|
|
* Description:
|
|
*
|
|
* The pos_api.c utility interfaces to the POS kernel driver
|
|
* via socket ioctl() calls.
|
|
*
|
|
* Please refer to the POS API document that conatins
|
|
* detailed information on all POS commands.
|
|
*
|
|
* Please use the program as a building block for your POS
|
|
* application.
|
|
*
|
|
* This example has been written for a single interface in mind,
|
|
* where the same process handles tx and rx data.
|
|
*
|
|
*
|
|
*/
|
|
|
|
/* General Linux header files */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <linux/if.h>
|
|
|
|
/* Wanpipe header files */
|
|
#include <linux/wanrouter.h>
|
|
#include <linux/wanpipe.h>
|
|
#include <linux/sdla_pos.h>
|
|
#include <linux/if_wanpipe.h>
|
|
|
|
|
|
/*===================================================
|
|
* Defines
|
|
*==================================================*/
|
|
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
|
|
#define LGTH_CRC_BYTES 2
|
|
#define MAX_TX_DATA 50 /* Size of tx data */
|
|
#define MAX_FRAMES 5000 /* Number of frames to transmit */
|
|
|
|
#define POS_UDELAY 100000 /* 100ms */
|
|
|
|
#define POS_PORT_ENABLE 0
|
|
#define POS_PORT_DISABLE -1
|
|
|
|
#define is_port_ready(x) ((x>0)?1:0)
|
|
|
|
#define POS_ASYNC_PORT1 1
|
|
#define POS_ASYNC_PORT2 2
|
|
|
|
#define POS_PORT1 1
|
|
#define POS_PORT2 2
|
|
|
|
|
|
/*===================================================
|
|
* Golobal data
|
|
*==================================================*/
|
|
|
|
unsigned short Rx_lgth;
|
|
unsigned char Rx_data[4000];
|
|
unsigned char Tx_data[MAX_TX_DATA + sizeof(wan_api_hdr_t)];
|
|
int sock;
|
|
|
|
/* Structure used to execute POS commands
|
|
*
|
|
* struct {
|
|
* unsigned char wan_pos_opp_flag
|
|
* unsigned char wan_pos_pos_state
|
|
* unsigned char wan_pos_async_state
|
|
* unsigned char wan_pos_command
|
|
* unsigned short wan_pos_data_len
|
|
* unsigned char wan_pos_return_code
|
|
* unsigned char wan_pos_port_num
|
|
* unsigned char wan_pos_attr
|
|
* unsigned char wan_pos_data[1030]
|
|
* }wan_mbox_t
|
|
*
|
|
* NOTE: This is the representation of the wan_mbox_t
|
|
* structure. Note how its actually defined.
|
|
* It should be used for information purposes
|
|
* only. i.e. DO NOT TRY TO USE THIS STRUCTURE
|
|
* DEFINITION IN THE ACTUAL CODE :)
|
|
*/
|
|
static wan_mbox_t mbox_g;
|
|
|
|
|
|
/*===================================================
|
|
* Function Prototypes
|
|
*==================================================*/
|
|
int MakeConnection(wan_mbox_t *, char *, char *);
|
|
void process_con(wan_mbox_t *);
|
|
int pos_data_ready(int sock, wan_mbox_t *mbox,
|
|
short *rx_port1, short *rx_port2,
|
|
short *rx_async_port1, short *tx_async_port1,
|
|
short *rx_async_port2, short *tx_async_port2,
|
|
unsigned int udelay);
|
|
|
|
|
|
/*===================================================
|
|
* DoCommand
|
|
*
|
|
* Execute a POS command directly on the
|
|
* sangoma adapter.
|
|
*
|
|
*/
|
|
|
|
int DoCommand (wan_mbox_t *mbox)
|
|
{
|
|
return ioctl(sock, SIOC_WANPIPE_EXEC_CMD, mbox);
|
|
}
|
|
|
|
/*===================================================
|
|
* configure_pos
|
|
*
|
|
* Setup a POS configuration structure and
|
|
* execute a POS CONFIGURATION command.
|
|
*
|
|
* IMPORTANT:
|
|
* The current configuration is only a
|
|
* SAMPLE. It should be changed to sute
|
|
* your network.
|
|
*
|
|
*/
|
|
|
|
|
|
int configure_pos (wan_mbox_t *mbox)
|
|
{
|
|
CONFIGURATION_STRUCT cfg;
|
|
|
|
mbox->wan_pos_command=CONFIGURE;
|
|
mbox->wan_pos_port_num=0;
|
|
|
|
memset(&cfg, 0, sizeof(CONFIGURATION_STRUCT));
|
|
|
|
/* number of active SDLC lines */
|
|
cfg.sdlc_lines=0x02;
|
|
|
|
|
|
/* maximum tx data packet */
|
|
cfg.sdlc_maxdata = DFT_POSDATA;
|
|
|
|
/* number of active ASYNC lines */
|
|
cfg.async_lines=0x02;
|
|
|
|
/* asynchronous line(s) speed */
|
|
cfg.async_speed=0x03; /* 19200 bps*/
|
|
|
|
/* half/full-duplex configuration
|
|
* 1=Full Duplex
|
|
* 0=Half Duplex */
|
|
cfg.half_duplex = 1;
|
|
|
|
memcpy(mbox->wan_pos_data,&cfg,sizeof(CONFIGURATION_STRUCT));
|
|
mbox->wan_pos_data_len=sizeof(CONFIGURATION_STRUCT);
|
|
|
|
if (DoCommand(mbox) != 0){
|
|
printf("Failed to configure pos!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
printf("Pos Configured\n");
|
|
|
|
|
|
/* Enable POS Port 1 */
|
|
memset(mbox,0, 0x16);
|
|
|
|
mbox->wan_pos_command=ENABLE_POS;
|
|
mbox->wan_pos_data_len=0;
|
|
mbox->wan_pos_port_num=1;
|
|
|
|
if (DoCommand(mbox) != 0){
|
|
printf("Failed to enable port 1!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
memset(mbox,0, 0x16);
|
|
|
|
/* Enable POS Port 2 */
|
|
mbox->wan_pos_command=ENABLE_POS;
|
|
mbox->wan_pos_data_len=0;
|
|
mbox->wan_pos_port_num=2;
|
|
|
|
if (DoCommand(mbox) != 0){
|
|
printf("Failed to enable port 2!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
printf("Enabled Port 1 and 2\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*===================================================
|
|
* MakeConnection
|
|
*
|
|
* o Create a Socket
|
|
* o Bind a socket to a wanpipe network interface
|
|
* (Interface name is supplied by the user)
|
|
*
|
|
* The "sock" socket descriptor will be use by
|
|
* the rest of the program to execute ioctl()
|
|
* commands down to the kernel driver.
|
|
*==================================================*/
|
|
|
|
int MakeConnection(wan_mbox_t *mbox, char *r_name, char *i_name )
|
|
{
|
|
struct wan_sockaddr_ll sa;
|
|
|
|
memset(&sa,0,sizeof(struct wan_sockaddr_ll));
|
|
errno = 0;
|
|
sock = socket(AF_WANPIPE, SOCK_RAW, 0);
|
|
if( sock < 0 ) {
|
|
perror("Socket");
|
|
return( FALSE );
|
|
} /* if */
|
|
|
|
printf("\nConnecting to router %s, interface %s\n", r_name, i_name);
|
|
|
|
strcpy( sa.sll_device, i_name);
|
|
strcpy( sa.sll_card, r_name);
|
|
sa.sll_protocol = htons(PVC_PROT);
|
|
sa.sll_family=AF_WANPIPE;
|
|
|
|
if(bind(sock, (struct sockaddr *)&sa, sizeof(struct wan_sockaddr_ll)) < 0){
|
|
perror("bind");
|
|
printf("Failed to bind a socket to %s interface\n",i_name);
|
|
exit(0);
|
|
}
|
|
printf("Socket bound to %s\n\n",i_name);
|
|
|
|
memset(mbox,0, 0x16);
|
|
|
|
return configure_pos(mbox);
|
|
}
|
|
|
|
/*===================================================
|
|
* pos_receive_data
|
|
*
|
|
* Execute POS receive command for a
|
|
* specific PORT.
|
|
*
|
|
* Copy the rx packet into the user supplied
|
|
* Rx_data buffer if the rx command is
|
|
* successful.
|
|
*==================================================*/
|
|
|
|
int pos_receive_data(wan_mbox_t *mbox, char cmd, char port, unsigned char *Rx_data)
|
|
{
|
|
memset(mbox,0, 0x16);
|
|
mbox->wan_pos_command = cmd;
|
|
mbox->wan_pos_data_len = 0;
|
|
mbox->wan_pos_port_num = port;
|
|
|
|
if (DoCommand(mbox) != 0){
|
|
printf("Failed to receive on %s port %i: %s!\n",
|
|
cmd==RECEIVE_POS?"POS":"Async",
|
|
port,
|
|
strerror(errno));
|
|
return -EINVAL;
|
|
}
|
|
|
|
memcpy(Rx_data, mbox->wan_pos_data, mbox->wan_pos_data_len);
|
|
|
|
/* Debugging:
|
|
* Prints out the received packet in HEX or ASCII */
|
|
{
|
|
int i;
|
|
printf("DATA: ");
|
|
for (i=0;i<mbox->wan_pos_data_len;i++){
|
|
|
|
//Print in HEX
|
|
printf("0x%02X ",Rx_data[i]);
|
|
|
|
//Print in ASCII
|
|
//printf("%c ",Rx_data[i]);
|
|
}
|
|
printf("\n\n");
|
|
}
|
|
|
|
return mbox->wan_pos_data_len;
|
|
}
|
|
|
|
/*===================================================
|
|
* pos_send_data
|
|
*
|
|
* Execute POS send command for a
|
|
* specific ASYNC TX PORT.
|
|
*
|
|
*==================================================*/
|
|
int pos_send_data(wan_mbox_t *mbox, char port, unsigned char *Tx_data, int Tx_len)
|
|
{
|
|
memset(mbox,0, 0x16);
|
|
|
|
mbox->wan_pos_command = SEND_ASYNC;
|
|
mbox->wan_pos_data_len = Tx_len;
|
|
mbox->wan_pos_port_num = port;
|
|
|
|
memcpy(mbox->wan_pos_data,Tx_data,Tx_len);
|
|
|
|
if (DoCommand(mbox) != 0){
|
|
printf("Failed to tx on Async port %i: %s!\n",
|
|
port,
|
|
strerror(errno));
|
|
return -EINVAL;
|
|
}
|
|
|
|
return Tx_len;
|
|
}
|
|
|
|
|
|
/*===========================================================
|
|
* process_con
|
|
*
|
|
* o Setup the tx and rx buffers
|
|
*
|
|
* o Poll the POS ports 1 and 2 and POS ASYNC ports 1 and 2
|
|
* Note, that one must select which port the polling
|
|
* routine should poll on.
|
|
*
|
|
* o Receive and Tx
|
|
*
|
|
*
|
|
* IMPORTANT:
|
|
* On TX if the send command fails, one must
|
|
* retransmit the same buffer again.
|
|
*/
|
|
void process_con(wan_mbox_t *mbox)
|
|
{
|
|
unsigned int Rx_count,Tx_count,Tx_length;
|
|
short rx_port1,rx_port2,
|
|
rx_async_port1,tx_async_port1,
|
|
rx_async_port2,tx_async_port2;
|
|
int err,i;
|
|
|
|
Rx_count = 0;
|
|
Tx_count = 0;
|
|
Tx_length = MAX_TX_DATA;
|
|
|
|
memset(&Tx_data[0],0,MAX_TX_DATA);
|
|
|
|
|
|
/* Create a data packet */
|
|
for (i=0;i<Tx_length;i++){
|
|
Tx_data[i] = (unsigned char)1;
|
|
}
|
|
|
|
printf("Starting Pos Tx/Rx, POS_UDELAY=%i \n",POS_UDELAY);
|
|
|
|
for(;;) {
|
|
|
|
/* Indicate which on which ports we'd like to tx or
|
|
* receive. Note port1 and port2 are receive only.
|
|
*
|
|
* The pos_data_ready() function will use these values
|
|
* to determin what data the user is waiting for.
|
|
*
|
|
* POS_PORT_ENABLE: Indicates that we'd like to be
|
|
* woken up when data is available.
|
|
*
|
|
* POS_PORT_DISABLE:Ignore data on this port
|
|
*
|
|
* In this case we would like to rx/tx data on
|
|
* all available ports
|
|
*/
|
|
rx_port1=POS_PORT_ENABLE;
|
|
rx_port2=POS_PORT_ENABLE;
|
|
rx_async_port1=POS_PORT_ENABLE;
|
|
tx_async_port1=POS_PORT_DISABLE;
|
|
rx_async_port2=POS_PORT_ENABLE;
|
|
tx_async_port2=POS_PORT_DISABLE;
|
|
|
|
|
|
/* The pos_data_ready() function must be used to implement flow control.
|
|
* It will block using the POS_UDELAY if no data is available, before
|
|
* POS buffers are re-checked.
|
|
*/
|
|
|
|
if(pos_data_ready(sock,mbox,
|
|
&rx_port1,&rx_port2,
|
|
&rx_async_port1,&tx_async_port1,
|
|
&rx_async_port2,&tx_async_port2,
|
|
POS_UDELAY) == 0){
|
|
|
|
/* Rx packets on PORT 1*/
|
|
if (is_port_ready(rx_port1)){
|
|
err = pos_receive_data(mbox,RECEIVE_POS, POS_PORT1,Rx_data);
|
|
/* err indicates bytes received */
|
|
if(err > 0) {
|
|
printf("Received packet %i, Port %i Length = %i\n",
|
|
++Rx_count,
|
|
POS_PORT1,
|
|
err);
|
|
}
|
|
}
|
|
|
|
/* Rx packets on PORT 2 */
|
|
if (is_port_ready(rx_port2)){
|
|
err = pos_receive_data(mbox,RECEIVE_POS, POS_PORT2,Rx_data);
|
|
if (err > 0){
|
|
|
|
printf("Received packet %i, Port %i Length = %i\n",
|
|
++Rx_count,
|
|
POS_PORT2,
|
|
err);
|
|
}
|
|
}
|
|
|
|
/* Rx packets on Async PORT 1 */
|
|
if (is_port_ready(rx_async_port1)){
|
|
err = pos_receive_data(mbox,RECEIVE_ASYNC, POS_ASYNC_PORT1,Rx_data);
|
|
if(err > 0) {
|
|
printf("Received packet %i, Async Port %i Length = %i\n",
|
|
++Rx_count,
|
|
POS_ASYNC_PORT1,
|
|
err);
|
|
}
|
|
}
|
|
|
|
/* Tx packets on Async PORT 1 */
|
|
if (is_port_ready(tx_async_port1)){
|
|
|
|
if (tx_async_port2 < Tx_length){
|
|
printf("Tx failed on Async port not enough room %i<%i\n",
|
|
tx_async_port2,Tx_length);
|
|
}else{
|
|
err = pos_send_data(mbox,POS_ASYNC_PORT1,Tx_data,Tx_length);
|
|
if(err > 0) {
|
|
printf("Tx packet %i, Async Port %i Length = %i\n",
|
|
++Tx_count,
|
|
Tx_length,
|
|
POS_ASYNC_PORT1);
|
|
}else{
|
|
//printf("Tx failed on Async port %i\n",
|
|
// POS_ASYNC_PORT1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Rx packets on Async PORT 2 */
|
|
if (is_port_ready(rx_async_port2)){
|
|
err = pos_receive_data(mbox,RECEIVE_ASYNC, POS_ASYNC_PORT2,Rx_data);
|
|
if(err > 0) {
|
|
printf("Received packet %i, Async Port %i Length = %i\n",
|
|
++Rx_count,
|
|
POS_ASYNC_PORT2,
|
|
err);
|
|
}
|
|
}
|
|
|
|
/* Tx packets on Async PORT 2 */
|
|
if (is_port_ready(tx_async_port2)){
|
|
|
|
if (tx_async_port2 < Tx_length){
|
|
printf("Tx failed on Async port 2 not enough room %i<%i\n",
|
|
tx_async_port2,Tx_length);
|
|
}else{
|
|
|
|
err = pos_send_data(mbox,POS_ASYNC_PORT2,Tx_data,Tx_length);
|
|
if(err > 0) {
|
|
printf("Tx packet %i, Async Port %i Length = %i\n",
|
|
++Tx_count,
|
|
Tx_length,
|
|
POS_ASYNC_PORT2);
|
|
}else{
|
|
//printf("Tx failed on Async port %i\n",
|
|
// POS_ASYNC_PORT2);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Stop the program afer transmitting MAX_FRAMES */
|
|
if (Tx_count == MAX_FRAMES)
|
|
break;
|
|
|
|
} else {
|
|
printf("\nError selecting socket\n");
|
|
break;
|
|
}
|
|
}
|
|
close (sock);
|
|
}
|
|
|
|
/*===========================================================
|
|
* pos_data_ready
|
|
*
|
|
* Execute the POS STATUS command and check if
|
|
* there is any data on each of the POS ports.
|
|
*
|
|
* We also check the user defined ports we
|
|
* should be waiting on. The port must
|
|
* be enabled and data must be found on that
|
|
* port before we exit and indicate event.
|
|
*/
|
|
|
|
|
|
int pos_data_ready(int sock, wan_mbox_t *mbox,
|
|
short *rx_port1, short *rx_port2,
|
|
short *rx_async_port1, short *tx_async_port1,
|
|
short *rx_async_port2, short *tx_async_port2,
|
|
unsigned int udelay)
|
|
{
|
|
int err;
|
|
struct timeval tv;
|
|
POSSTATESTRUC *tmp_pos_state;
|
|
|
|
for (;;){
|
|
memset(mbox,0, 0x16);
|
|
|
|
mbox->wan_pos_command = SEND_RECV_STATE;
|
|
mbox->wan_pos_data_len = 0;
|
|
|
|
if ((err=DoCommand(mbox)) != 0){
|
|
printf("Failed to get pos status info %x!\n",err);
|
|
return -EINVAL;
|
|
}
|
|
|
|
tmp_pos_state = (POSSTATESTRUC*)mbox->wan_pos_data;
|
|
|
|
if (*rx_port1==POS_PORT_ENABLE && tmp_pos_state->POS1_received){
|
|
*rx_port1=tmp_pos_state->POS1_received;
|
|
udelay=0;
|
|
}
|
|
|
|
if (*rx_port2==POS_PORT_ENABLE && tmp_pos_state->POS2_received){
|
|
*rx_port2=tmp_pos_state->POS2_received;
|
|
udelay=0;
|
|
}
|
|
|
|
if (*rx_async_port1==POS_PORT_ENABLE && tmp_pos_state->async1_recvd){
|
|
*rx_async_port1=tmp_pos_state->async1_recvd;
|
|
udelay=0;
|
|
}
|
|
|
|
if (*tx_async_port1==POS_PORT_ENABLE && tmp_pos_state->async1_transm){
|
|
*tx_async_port1=tmp_pos_state->async1_transm;
|
|
udelay=0;
|
|
}
|
|
|
|
if (*rx_async_port2==POS_PORT_ENABLE && tmp_pos_state->async2_recvd){
|
|
*rx_async_port2=tmp_pos_state->async2_recvd;
|
|
udelay=0;
|
|
}
|
|
|
|
if (*tx_async_port2==POS_PORT_ENABLE && tmp_pos_state->async2_transm){
|
|
*tx_async_port2=tmp_pos_state->async2_transm;
|
|
udelay=0;
|
|
}
|
|
|
|
/* Something has been found, or the user has put
|
|
* in a ZERO delay which means that we shouldn't
|
|
* block */
|
|
if (!udelay){
|
|
#if 0
|
|
printf("POS State: PP1=%d, PP2=%d, APr1=%d, APt1=%d, APr2=%d, APt2=%d\n",
|
|
tmp_pos_state->POS1_received,
|
|
tmp_pos_state->POS2_received,
|
|
tmp_pos_state->async1_recvd,
|
|
tmp_pos_state->async1_transm,
|
|
tmp_pos_state->async2_recvd,
|
|
tmp_pos_state->async2_transm);
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
/* Nothing found on any of the ports,
|
|
* sleep for user defined time and
|
|
* proceed with polling */
|
|
tv.tv_usec = udelay;
|
|
tv.tv_sec = 0;
|
|
|
|
select(sock+1, NULL,NULL,NULL,&tv);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***************************************************************
|
|
* Main:
|
|
*
|
|
* o Make a socket connection to the driver.
|
|
* o Call process_con() to read/write the POS API
|
|
*
|
|
**************************************************************/
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
int proceed;
|
|
|
|
if (argc != 3){
|
|
printf("Usage: rec_wan_sock <router name> <interface name>\n");
|
|
exit(0);
|
|
}
|
|
|
|
memset(&mbox_g,0,sizeof(wan_mbox_t));
|
|
|
|
proceed = MakeConnection(&mbox_g,argv[argc - 2], argv[argc - 1]);
|
|
if( proceed == TRUE ){
|
|
process_con(&mbox_g);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
};
|