2005-05-18 00:21:55 +00:00
|
|
|
/**
|
2006-03-30 00:21:37 +00:00
|
|
|
* wpchanw.cpp
|
2005-05-18 00:21:55 +00:00
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
|
|
*
|
2006-03-30 00:21:37 +00:00
|
|
|
* Wanpipe PRI cards telephony driver for Windows
|
2005-05-18 00:21:55 +00:00
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
2006-05-27 15:08:43 +00:00
|
|
|
* Copyright (C) 2004-2006 Null Team
|
2005-05-18 00:21:55 +00:00
|
|
|
*
|
|
|
|
* 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
|
2006-05-27 15:08:43 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
2005-05-18 00:21:55 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <modules/libypri.h>
|
|
|
|
|
|
|
|
#ifndef _WINDOWS
|
|
|
|
#error This module is only for Windows
|
|
|
|
#else
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
#define MSG_NOSIGNAL 0
|
|
|
|
#define MSG_DONTWAIT 0
|
|
|
|
#include <winioctl.h>
|
|
|
|
#define IOCTL_WRITE 1
|
|
|
|
#define IOCTL_READ 2
|
|
|
|
#define IOCTL_MGMT 3
|
|
|
|
#define IoctlWriteCommand \
|
|
|
|
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_WRITE, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
|
|
|
#define IoctlReadCommand \
|
|
|
|
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_READ, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
using namespace TelEngine;
|
2006-05-27 14:53:18 +00:00
|
|
|
namespace { // anonymous
|
2005-05-18 00:21:55 +00:00
|
|
|
|
|
|
|
class WpChan;
|
|
|
|
|
|
|
|
class WpSpan : public PriSpan, public Thread
|
|
|
|
{
|
|
|
|
friend class WpData;
|
2005-05-18 12:20:04 +00:00
|
|
|
friend class WpReader;
|
|
|
|
friend class WpWriter;
|
2005-05-18 00:21:55 +00:00
|
|
|
friend class WpDriver;
|
|
|
|
public:
|
|
|
|
virtual ~WpSpan();
|
|
|
|
virtual void run();
|
2005-05-30 13:51:38 +00:00
|
|
|
virtual void cleanup();
|
2005-05-18 12:20:04 +00:00
|
|
|
int dataRead(void *buf, int buflen);
|
|
|
|
int dataWrite(void *buf, int buflen);
|
2005-05-18 00:21:55 +00:00
|
|
|
|
|
|
|
private:
|
2005-05-18 12:20:04 +00:00
|
|
|
WpSpan(struct pri *_pri, PriDriver* driver, int span, int first, int chans, int dchan, Configuration& cfg, const String& sect);
|
|
|
|
WpData* m_data;
|
|
|
|
WpReader* m_reader;
|
|
|
|
WpWriter* m_writer;
|
|
|
|
DataBlock m_rdata;
|
2005-05-19 23:38:49 +00:00
|
|
|
ObjList m_wdata;
|
2005-05-18 00:21:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class WpSource : public PriSource
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
WpSource(WpChan *owner, const char* format, unsigned int bufsize);
|
|
|
|
~WpSource();
|
|
|
|
void put(unsigned char val);
|
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned int m_bufpos;
|
|
|
|
};
|
|
|
|
|
|
|
|
class WpConsumer : public PriConsumer, public Fifo
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
WpConsumer(WpChan *owner, const char* format, unsigned int bufsize);
|
|
|
|
~WpConsumer();
|
|
|
|
|
2005-09-06 02:51:09 +00:00
|
|
|
virtual void Consume(const DataBlock &data, unsigned long tStamp);
|
2006-01-17 18:05:20 +00:00
|
|
|
private:
|
|
|
|
DataErrors m_overruns;
|
2005-05-18 00:21:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class WpChan : public PriChan
|
|
|
|
{
|
|
|
|
friend class WpSource;
|
|
|
|
friend class WpConsumer;
|
|
|
|
friend class WpData;
|
|
|
|
public:
|
|
|
|
WpChan(const PriSpan *parent, int chan, unsigned int bufsize);
|
|
|
|
virtual ~WpChan();
|
|
|
|
virtual bool openData(const char* format, int echoTaps);
|
|
|
|
|
|
|
|
private:
|
|
|
|
WpSource* m_wp_s;
|
|
|
|
WpConsumer* m_wp_c;
|
|
|
|
};
|
|
|
|
|
|
|
|
class WpData : public Thread
|
|
|
|
{
|
|
|
|
public:
|
2006-03-30 00:21:37 +00:00
|
|
|
WpData(WpSpan* span, const char* card, const char* device, Configuration& cfg, const String& sect);
|
2005-05-18 00:21:55 +00:00
|
|
|
~WpData();
|
|
|
|
virtual void run();
|
|
|
|
private:
|
|
|
|
WpSpan* m_span;
|
|
|
|
HANDLE m_fd;
|
|
|
|
WpChan **m_chans;
|
2006-03-30 00:21:37 +00:00
|
|
|
bool m_swap;
|
2005-05-18 00:21:55 +00:00
|
|
|
};
|
|
|
|
|
2005-05-18 12:20:04 +00:00
|
|
|
class WpReader : public Thread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
WpReader(WpSpan* span, const char* card, const char* device);
|
|
|
|
~WpReader();
|
|
|
|
virtual void run();
|
|
|
|
private:
|
|
|
|
WpSpan* m_span;
|
|
|
|
HANDLE m_fd;
|
|
|
|
};
|
|
|
|
|
|
|
|
class WpWriter : public Thread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
WpWriter(WpSpan* span, const char* card, const char* device);
|
|
|
|
~WpWriter();
|
|
|
|
virtual void run();
|
|
|
|
private:
|
|
|
|
WpSpan* m_span;
|
|
|
|
HANDLE m_fd;
|
|
|
|
};
|
|
|
|
|
2005-05-18 00:21:55 +00:00
|
|
|
class WpDriver : public PriDriver
|
|
|
|
{
|
|
|
|
friend class PriSpan;
|
|
|
|
friend class WpHandler;
|
|
|
|
public:
|
|
|
|
WpDriver();
|
|
|
|
virtual ~WpDriver();
|
|
|
|
virtual void initialize();
|
2005-05-20 04:06:31 +00:00
|
|
|
virtual bool received(Message &msg, int id);
|
2005-05-18 00:21:55 +00:00
|
|
|
virtual PriSpan* createSpan(PriDriver* driver, int span, int first, int chans, Configuration& cfg, const String& sect);
|
|
|
|
virtual PriChan* createChan(const PriSpan* span, int chan, unsigned int bufsize);
|
|
|
|
};
|
|
|
|
|
|
|
|
INIT_PLUGIN(WpDriver);
|
|
|
|
|
2005-05-18 20:12:41 +00:00
|
|
|
#define WP_HEADER 21
|
2005-05-20 04:06:31 +00:00
|
|
|
#define WP_BUFFER 8188 // maximum length of data = 8K - 4
|
2005-05-18 20:12:41 +00:00
|
|
|
|
|
|
|
|
2006-03-30 00:21:37 +00:00
|
|
|
static Thread::Priority cfgPriority(Configuration& cfg, const String& sect)
|
|
|
|
{
|
|
|
|
String tmp(cfg.getValue(sect,"thread"));
|
|
|
|
if (tmp.null())
|
|
|
|
tmp = cfg.getValue("general","thread");
|
|
|
|
return Thread::priority(tmp);
|
|
|
|
}
|
|
|
|
|
2005-05-18 20:12:41 +00:00
|
|
|
static void dump_buffer(const void* buf, int len)
|
|
|
|
{
|
|
|
|
String s;
|
|
|
|
const unsigned char* p = (const unsigned char*)buf;
|
|
|
|
for (int i=0; i < len; i++) {
|
|
|
|
char tmp[4];
|
|
|
|
sprintf(tmp," %02x",p[i]);
|
|
|
|
//Debug(DebugAll,"%d",i);
|
|
|
|
s += tmp;
|
|
|
|
}
|
|
|
|
Output("[%d@%p]%s",len,buf,s.c_str());
|
|
|
|
}
|
2005-05-18 00:21:55 +00:00
|
|
|
|
|
|
|
static int wp_recv(HANDLE fd, void *buf, int buflen, int flags = 0)
|
|
|
|
{
|
|
|
|
int r = 0;
|
2005-05-18 20:12:41 +00:00
|
|
|
if (!DeviceIoControl(fd,IoctlReadCommand,0,0,buf,buflen,(LPDWORD)&r,0)) {
|
2005-05-18 00:21:55 +00:00
|
|
|
r = 0;
|
2005-05-18 20:12:41 +00:00
|
|
|
Output("recv (%d,%p,%d) last err=%x",fd,buf,buflen,GetLastError());
|
|
|
|
}
|
2005-05-18 00:21:55 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wp_send(HANDLE fd, void *buf, int buflen, int flags = 0)
|
|
|
|
{
|
|
|
|
int w = 0;
|
2005-05-18 20:12:41 +00:00
|
|
|
if (!DeviceIoControl(fd,IoctlWriteCommand,buf,buflen,buf,buflen,(LPDWORD)&w,0)) {
|
2005-05-18 00:21:55 +00:00
|
|
|
w = 0;
|
2005-05-18 20:12:41 +00:00
|
|
|
Output("send (%d,%p,%d) last err=%x",fd,buf,buflen,GetLastError());
|
|
|
|
}
|
2005-05-18 00:21:55 +00:00
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wp_read(struct pri *pri, void *buf, int buflen)
|
|
|
|
{
|
2005-05-18 12:20:04 +00:00
|
|
|
WpSpan* span = (WpSpan*)::pri_get_userdata(pri);
|
|
|
|
return span ? span->dataRead(buf,buflen) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WpSpan::dataRead(void *buf, int buflen)
|
|
|
|
{
|
|
|
|
Lock mylock(this);
|
|
|
|
if (m_rdata.data() && buf && (int)m_rdata.length() <= buflen) {
|
|
|
|
buflen = m_rdata.length();
|
|
|
|
::memcpy(buf,m_rdata.data(),buflen);
|
|
|
|
m_rdata.clear();
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpSpan dequeued %d bytes block [%p]",buflen,this);
|
2005-05-18 12:20:04 +00:00
|
|
|
return buflen+2;
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
2005-05-18 12:20:04 +00:00
|
|
|
return 0;
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int wp_write(struct pri *pri, void *buf, int buflen)
|
|
|
|
{
|
2005-05-18 12:20:04 +00:00
|
|
|
WpSpan* span = (WpSpan*)::pri_get_userdata(pri);
|
|
|
|
return span ? span->dataWrite(buf,buflen) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WpSpan::dataWrite(void *buf, int buflen)
|
|
|
|
{
|
|
|
|
Lock mylock(this);
|
2005-05-19 23:38:49 +00:00
|
|
|
if (buf && (buflen > 2) && (m_wdata.length() < 5)) {
|
2005-05-18 12:20:04 +00:00
|
|
|
buflen -= 2;
|
2005-05-19 23:38:49 +00:00
|
|
|
DataBlock* block = new DataBlock(buf,buflen);
|
|
|
|
m_wdata.append(block);
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpSpan queued %d bytes block, total blocks %d [%p]",block->length(),m_wdata.count(),this);
|
2005-05-18 12:20:04 +00:00
|
|
|
return buflen+2;
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
2005-05-18 12:20:04 +00:00
|
|
|
return 0;
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void wp_close(HANDLE fd)
|
|
|
|
{
|
|
|
|
if (fd == INVALID_HANDLE_VALUE)
|
|
|
|
return;
|
|
|
|
::CloseHandle(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HANDLE wp_open(const char* card, const char* device)
|
|
|
|
{
|
|
|
|
DDebug(DebugAll,"wp_open('%s','%s')",card,device);
|
|
|
|
if (null(card) || null(device))
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
String devname("\\\\.\\");
|
|
|
|
devname << card << "_" << device;
|
|
|
|
HANDLE fd = ::CreateFile(
|
|
|
|
devname,
|
|
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
|
|
0,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH,
|
|
|
|
0);
|
|
|
|
if (fd == INVALID_HANDLE_VALUE) {
|
|
|
|
Debug(DebugGoOn,"Wanpipe failed to open device '%s': error %d: %s",
|
|
|
|
devname.c_str(),errno,::strerror(errno));
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2005-05-18 12:20:04 +00:00
|
|
|
WpReader::WpReader(WpSpan* span, const char* card, const char* device)
|
|
|
|
: Thread("WpReader"), m_span(span), m_fd(INVALID_HANDLE_VALUE)
|
2005-05-18 00:21:55 +00:00
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpReader::WpReader(%p) [%p]",span,this);
|
2005-05-18 12:20:04 +00:00
|
|
|
m_fd = wp_open(card,device);
|
|
|
|
m_span->m_reader = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
WpReader::~WpReader()
|
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpReader::~WpReader() [%p]",this);
|
2005-05-30 13:51:38 +00:00
|
|
|
if (m_span)
|
|
|
|
m_span->m_reader = 0;
|
2005-05-18 12:20:04 +00:00
|
|
|
HANDLE tmp = m_fd;
|
|
|
|
m_fd = INVALID_HANDLE_VALUE;
|
|
|
|
wp_close(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WpReader::run()
|
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
while (m_span && m_span->m_reader && (m_fd != INVALID_HANDLE_VALUE)) {
|
2005-05-18 12:20:04 +00:00
|
|
|
Thread::msleep(1,true);
|
|
|
|
Lock mylock(m_span);
|
|
|
|
if (m_span->m_rdata.data())
|
|
|
|
continue;
|
|
|
|
mylock.drop();
|
2005-05-18 20:12:41 +00:00
|
|
|
unsigned char buf[WP_HEADER+WP_BUFFER];
|
2005-05-18 12:20:04 +00:00
|
|
|
int r = wp_recv(m_fd,buf,sizeof(buf)) - WP_HEADER;
|
2005-05-20 04:06:31 +00:00
|
|
|
XDebug(&__plugin,DebugAll,"WpReader read returned %d [%p]",r,this);
|
2005-05-18 12:20:04 +00:00
|
|
|
if (r <= 0)
|
|
|
|
continue;
|
2005-05-30 13:51:38 +00:00
|
|
|
Thread::check();
|
2005-05-18 12:20:04 +00:00
|
|
|
m_span->lock();
|
2005-05-18 20:12:41 +00:00
|
|
|
m_span->m_rdata.assign(buf+WP_HEADER,r);
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpReader queued %d bytes block [%p]",r,this);
|
2005-05-18 12:20:04 +00:00
|
|
|
m_span->unlock();
|
|
|
|
}
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
2005-05-18 12:20:04 +00:00
|
|
|
WpWriter::WpWriter(WpSpan* span, const char* card, const char* device)
|
|
|
|
: Thread("WpWriter"), m_span(span), m_fd(INVALID_HANDLE_VALUE)
|
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpWriter::WpWriter(%p) [%p]",span,this);
|
2005-05-18 12:20:04 +00:00
|
|
|
m_fd = wp_open(card,device);
|
|
|
|
m_span->m_writer = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
WpWriter::~WpWriter()
|
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpWriter::~WpWriter() [%p]",this);
|
2005-05-30 13:51:38 +00:00
|
|
|
if (m_span)
|
|
|
|
m_span->m_writer = 0;
|
2005-05-18 12:20:04 +00:00
|
|
|
HANDLE tmp = m_fd;
|
|
|
|
m_fd = INVALID_HANDLE_VALUE;
|
|
|
|
wp_close(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WpWriter::run()
|
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
while (m_span && m_span->m_writer && (m_fd != INVALID_HANDLE_VALUE)) {
|
2005-05-18 12:20:04 +00:00
|
|
|
Thread::msleep(1,true);
|
2005-05-19 23:38:49 +00:00
|
|
|
m_span->lock();
|
|
|
|
DataBlock *block = static_cast<DataBlock*>(m_span->m_wdata.remove(false));
|
|
|
|
m_span->unlock();
|
|
|
|
if (!block)
|
2005-05-18 12:20:04 +00:00
|
|
|
continue;
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpWriter dequeued %d bytes block [%p]",block->length(),this);
|
2005-05-18 20:12:41 +00:00
|
|
|
// this is really stupid - have to send a huge buffer, or else
|
|
|
|
// Error : Tx system buffer length not equal sizeof(TX_DATA_STRUCT)!
|
|
|
|
unsigned char buf[WP_HEADER+WP_BUFFER];
|
2005-05-19 23:38:49 +00:00
|
|
|
int len = block->length();
|
|
|
|
::memcpy(buf+WP_HEADER,block->data(),len);
|
|
|
|
block->destruct();
|
2005-05-18 20:12:41 +00:00
|
|
|
buf[0] = 11;
|
|
|
|
buf[1] = len & 0xff;
|
|
|
|
buf[2] = len >> 8;
|
|
|
|
wp_send(m_fd,buf,sizeof(buf));
|
2005-05-18 12:20:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WpSpan::WpSpan(struct pri *_pri, PriDriver* driver, int span, int first, int chans, int dchan, Configuration& cfg, const String& sect)
|
2005-05-18 00:21:55 +00:00
|
|
|
: PriSpan(_pri,driver,span,first,chans,dchan,cfg,sect), Thread("WpSpan"),
|
2005-05-18 12:20:04 +00:00
|
|
|
m_data(0), m_reader(0), m_writer(0)
|
2005-05-18 00:21:55 +00:00
|
|
|
{
|
|
|
|
Debug(&__plugin,DebugAll,"WpSpan::WpSpan() [%p]",this);
|
|
|
|
}
|
|
|
|
|
|
|
|
WpSpan::~WpSpan()
|
|
|
|
{
|
|
|
|
Debug(&__plugin,DebugAll,"WpSpan::~WpSpan() [%p]",this);
|
|
|
|
m_ok = false;
|
2005-05-30 13:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WpSpan::cleanup()
|
|
|
|
{
|
|
|
|
Debug(&__plugin,DebugAll,"WpSpan::cleanup() [%p]",this);
|
|
|
|
m_ok = false;
|
2005-05-20 04:06:31 +00:00
|
|
|
if (m_data)
|
|
|
|
m_data->cancel();
|
|
|
|
if (m_reader)
|
|
|
|
m_reader->cancel();
|
|
|
|
if (m_writer)
|
|
|
|
m_writer->cancel();
|
|
|
|
Debug(&__plugin,DebugAll,"WpSpan waiting for cleanups [%p]",this);
|
|
|
|
Thread::msleep(20);
|
|
|
|
while (m_data || m_reader || m_writer)
|
2005-05-30 13:51:38 +00:00
|
|
|
Thread::msleep(1);
|
|
|
|
Debug(&__plugin,DebugAll,"WpSpan cleanups complete [%p]",this);
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WpSpan::run()
|
|
|
|
{
|
|
|
|
Debug(&__plugin,DebugAll,"WpSpan::run() [%p]",this);
|
2005-05-20 04:06:31 +00:00
|
|
|
while (m_data && m_reader && m_writer) {
|
2005-05-18 12:20:04 +00:00
|
|
|
Thread::msleep(1,true);
|
|
|
|
lock();
|
|
|
|
runEvent(m_rdata.null());
|
|
|
|
unlock();
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WpSource::WpSource(WpChan *owner, const char* format, unsigned int bufsize)
|
|
|
|
: PriSource(owner,format,bufsize),
|
|
|
|
m_bufpos(0)
|
|
|
|
{
|
|
|
|
Debug(m_owner,DebugAll,"WpSource::WpSource(%p) [%p]",owner,this);
|
|
|
|
static_cast<WpChan*>(m_owner)->m_wp_s = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
WpSource::~WpSource()
|
|
|
|
{
|
|
|
|
Debug(m_owner,DebugAll,"WpSource::~WpSource() [%p]",this);
|
|
|
|
static_cast<WpChan*>(m_owner)->m_wp_s = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WpSource::put(unsigned char val)
|
|
|
|
{
|
|
|
|
((char*)m_buffer.data())[m_bufpos] = val;
|
|
|
|
if (++m_bufpos >= m_buffer.length()) {
|
|
|
|
m_bufpos = 0;
|
|
|
|
Forward(m_buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WpConsumer::WpConsumer(WpChan *owner, const char* format, unsigned int bufsize)
|
|
|
|
: PriConsumer(owner,format,bufsize), Fifo(2*bufsize)
|
|
|
|
{
|
|
|
|
Debug(m_owner,DebugAll,"WpConsumer::WpConsumer(%p) [%p]",owner,this);
|
|
|
|
static_cast<WpChan*>(m_owner)->m_wp_c = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
WpConsumer::~WpConsumer()
|
|
|
|
{
|
|
|
|
Debug(m_owner,DebugAll,"WpConsumer::~WpConsumer() [%p]",this);
|
|
|
|
static_cast<WpChan*>(m_owner)->m_wp_c = 0;
|
2006-01-17 18:05:20 +00:00
|
|
|
if (m_overruns.events())
|
|
|
|
Debug(m_owner,DebugMild,"Consumer had %u overruns (%lu bytes)",
|
|
|
|
m_overruns.events(),m_overruns.bytes());
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
2005-09-06 02:51:09 +00:00
|
|
|
void WpConsumer::Consume(const DataBlock &data, unsigned long tStamp)
|
2005-05-18 00:21:55 +00:00
|
|
|
{
|
2006-01-17 18:05:20 +00:00
|
|
|
unsigned int err = put((const unsigned char*)data.data(),data.length());
|
|
|
|
if (err)
|
|
|
|
m_overruns.update(err);
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
2005-10-07 22:03:19 +00:00
|
|
|
|
|
|
|
|
2006-03-30 00:21:37 +00:00
|
|
|
WpData::WpData(WpSpan* span, const char* card, const char* device, Configuration& cfg, const String& sect)
|
|
|
|
: Thread("WpData",cfgPriority(cfg,sect)), m_span(span), m_fd(INVALID_HANDLE_VALUE), m_chans(0), m_swap(true)
|
2005-05-18 00:21:55 +00:00
|
|
|
{
|
2006-03-30 00:21:37 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpData::WpData(%p,'%s','%s') [%p]",span,card,device,this);
|
2005-05-18 00:21:55 +00:00
|
|
|
HANDLE fd = wp_open(card,device);
|
|
|
|
if (fd != INVALID_HANDLE_VALUE) {
|
|
|
|
m_fd = fd;
|
|
|
|
m_span->m_data = this;
|
|
|
|
}
|
2006-03-30 00:21:37 +00:00
|
|
|
m_swap = cfg.getBoolValue("general","bitswap",m_swap);
|
|
|
|
m_swap = cfg.getBoolValue(sect,"bitswap",m_swap);
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WpData::~WpData()
|
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpData::~WpData() [%p]",this);
|
2005-05-30 13:51:38 +00:00
|
|
|
if (m_span)
|
|
|
|
m_span->m_data = 0;
|
2005-05-18 00:21:55 +00:00
|
|
|
wp_close(m_fd);
|
|
|
|
m_fd = INVALID_HANDLE_VALUE;
|
|
|
|
if (m_chans)
|
|
|
|
delete[] m_chans;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WpData::run()
|
|
|
|
{
|
2005-05-20 04:06:31 +00:00
|
|
|
DDebug(&__plugin,DebugAll,"WpData::run() [%p]",this);
|
2005-05-18 20:12:41 +00:00
|
|
|
unsigned char buffer[WP_HEADER+WP_BUFFER];
|
2005-05-18 00:21:55 +00:00
|
|
|
int bchans = m_span->bchans();
|
|
|
|
// Build a compacted list of allocated B channels
|
|
|
|
m_chans = new WpChan* [bchans];
|
|
|
|
int b = 0;
|
|
|
|
for (int n = 0; n < bchans; n++) {
|
|
|
|
while (!m_span->m_chans[b])
|
|
|
|
b++;
|
|
|
|
m_chans[n] = static_cast<WpChan*>(m_span->m_chans[b++]);
|
|
|
|
DDebug(&__plugin,DebugInfo,"wpdata ch[%d]=%d (%p)",n,m_chans[n]->chan(),m_chans[n]);
|
|
|
|
}
|
2005-05-19 23:38:49 +00:00
|
|
|
int rok = 0, rerr = 0;
|
|
|
|
int wok = 0, werr = 0;
|
2005-05-20 04:06:31 +00:00
|
|
|
while (m_span && m_span->m_data && (m_fd != INVALID_HANDLE_VALUE)) {
|
2005-05-18 00:21:55 +00:00
|
|
|
Thread::check();
|
2005-05-20 04:06:31 +00:00
|
|
|
int samp = 0;
|
|
|
|
int r = wp_recv(m_fd,buffer,sizeof(buffer),0/*MSG_NOSIGNAL*/);
|
|
|
|
XDebug(&__plugin,DebugAll,"WpData recv r=%d",r);
|
|
|
|
r -= WP_HEADER;
|
|
|
|
// We should have read N bytes for each B channel
|
|
|
|
if (r > 0) {
|
|
|
|
samp = r / bchans;
|
|
|
|
if ((r % bchans) == 0) {
|
2005-05-18 20:12:41 +00:00
|
|
|
const unsigned char* dat = buffer + WP_HEADER;
|
2005-05-18 00:21:55 +00:00
|
|
|
m_span->lock();
|
2005-05-20 05:37:58 +00:00
|
|
|
int p1 = -1;
|
|
|
|
int p2 = -1;
|
|
|
|
for (int n = samp; n > 0; n--) {
|
2005-05-18 00:21:55 +00:00
|
|
|
for (b = 0; b < bchans; b++) {
|
2005-05-20 23:08:16 +00:00
|
|
|
WpSource *s = m_chans[b]->m_wp_s;
|
|
|
|
if (s)
|
2006-03-30 00:21:37 +00:00
|
|
|
s->put(m_swap ? PriDriver::bitswap(*dat) : *dat);
|
2005-05-18 00:21:55 +00:00
|
|
|
dat++;
|
|
|
|
}
|
2005-05-20 05:37:58 +00:00
|
|
|
}
|
2005-05-18 00:21:55 +00:00
|
|
|
m_span->unlock();
|
2005-05-19 23:38:49 +00:00
|
|
|
++rok;
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
2005-05-19 23:38:49 +00:00
|
|
|
else
|
2005-05-20 04:06:31 +00:00
|
|
|
Debug(DebugWarn,"WpData read %d (ok/bad %d/%d)",r,rok,++rerr);
|
|
|
|
}
|
|
|
|
if (samp) {
|
2005-05-18 20:12:41 +00:00
|
|
|
::memset(buffer,0,WP_HEADER);
|
|
|
|
unsigned char* dat = buffer + WP_HEADER;
|
2005-05-18 00:21:55 +00:00
|
|
|
m_span->lock();
|
2005-05-20 04:06:31 +00:00
|
|
|
for (int n = samp; n > 0; n--) {
|
2005-05-18 00:21:55 +00:00
|
|
|
for (b = 0; b < bchans; b++) {
|
2005-05-20 23:08:16 +00:00
|
|
|
WpConsumer *c = m_chans[b]->m_wp_c;
|
2006-03-30 00:21:37 +00:00
|
|
|
unsigned char d = c ? c->get() : 0xff;
|
|
|
|
*dat++ = m_swap ? PriDriver::bitswap(d) : d;
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
m_span->unlock();
|
2005-05-20 04:06:31 +00:00
|
|
|
int w = samp * bchans;
|
2005-05-18 20:12:41 +00:00
|
|
|
dat = buffer;
|
|
|
|
buffer[0] = 11;
|
|
|
|
buffer[1] = w & 0xff;
|
|
|
|
buffer[2] = w >> 8;
|
|
|
|
w = wp_send(m_fd,buffer,sizeof(buffer),MSG_DONTWAIT);
|
2005-05-19 23:38:49 +00:00
|
|
|
if (w != sizeof(buffer))
|
2005-05-20 04:06:31 +00:00
|
|
|
Debug(DebugWarn,"WpData wrote %d (ok/bad %d/%d)",w,wok,++werr);
|
2005-05-19 23:38:49 +00:00
|
|
|
else
|
|
|
|
++wok;
|
2005-05-20 04:06:31 +00:00
|
|
|
XDebug(&__plugin,DebugAll,"WpData send w=%d",w);
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WpChan::WpChan(const PriSpan *parent, int chan, unsigned int bufsize)
|
|
|
|
: PriChan(parent,chan,bufsize), m_wp_s(0), m_wp_c(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
WpChan::~WpChan()
|
|
|
|
{
|
|
|
|
closeData();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WpChan::openData(const char* format, int echoTaps)
|
|
|
|
{
|
2005-05-20 05:37:58 +00:00
|
|
|
Debug(this,DebugAll,"WpChan::openData(%s,%d) [%p]",format,echoTaps,this);
|
2005-05-18 00:21:55 +00:00
|
|
|
if (echoTaps)
|
|
|
|
Debug(DebugWarn,"Echo cancellation requested but not available in wanpipe");
|
|
|
|
m_span->lock();
|
|
|
|
setSource(new WpSource(this,format,m_bufsize));
|
|
|
|
getSource()->deref();
|
|
|
|
setConsumer(new WpConsumer(this,format,m_bufsize));
|
|
|
|
getConsumer()->deref();
|
|
|
|
m_span->unlock();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-10-07 22:03:19 +00:00
|
|
|
|
2005-05-18 00:21:55 +00:00
|
|
|
PriSpan* WpDriver::createSpan(PriDriver* driver, int span, int first, int chans, Configuration& cfg, const String& sect)
|
|
|
|
{
|
|
|
|
Debug(this,DebugAll,"WpDriver::createSpan(%p,%d,%d,%d) [%p]",driver,span,first,chans,this);
|
|
|
|
int netType = -1;
|
|
|
|
int swType = -1;
|
|
|
|
int dchan = -1;
|
|
|
|
netParams(cfg,sect,chans,&netType,&swType,&dchan);
|
|
|
|
String card;
|
2005-05-18 20:12:41 +00:00
|
|
|
card << "WANPIPE" << span;
|
2005-05-18 00:21:55 +00:00
|
|
|
card = cfg.getValue(sect,"card",card);
|
|
|
|
String dev;
|
2005-05-20 23:08:16 +00:00
|
|
|
dev = cfg.getValue(sect,"dgroup","IF0");
|
2005-05-18 12:20:04 +00:00
|
|
|
pri* p = ::pri_new_cb((int)INVALID_HANDLE_VALUE, netType, swType, wp_read, wp_write, 0);
|
2005-05-18 00:21:55 +00:00
|
|
|
if (!p)
|
|
|
|
return 0;
|
2005-05-18 12:20:04 +00:00
|
|
|
WpSpan *ps = new WpSpan(p,driver,span,first,chans,dchan,cfg,sect);
|
|
|
|
WpWriter* wr = new WpWriter(ps,card,dev);
|
|
|
|
WpReader* rd = new WpReader(ps,card,dev);
|
2005-05-20 23:08:16 +00:00
|
|
|
dev = cfg.getValue(sect,"bgroup","IF1");
|
2006-03-30 00:21:37 +00:00
|
|
|
WpData* dat = new WpData(ps,card,dev,cfg,sect);
|
2005-05-20 04:06:31 +00:00
|
|
|
wr->startup();
|
|
|
|
rd->startup();
|
2005-05-18 00:21:55 +00:00
|
|
|
dat->startup();
|
2005-05-20 04:06:31 +00:00
|
|
|
ps->startup();
|
2005-05-18 00:21:55 +00:00
|
|
|
return ps;
|
|
|
|
}
|
|
|
|
|
|
|
|
PriChan* WpDriver::createChan(const PriSpan* span, int chan, unsigned int bufsize)
|
|
|
|
{
|
|
|
|
Debug(this,DebugAll,"WpDriver::createChan(%p,%d,%u) [%p]",span,chan,bufsize,this);
|
|
|
|
return new WpChan(span,chan,bufsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
WpDriver::WpDriver()
|
|
|
|
: PriDriver("wp")
|
|
|
|
{
|
|
|
|
Output("Loaded module Wanpipe");
|
|
|
|
}
|
|
|
|
|
|
|
|
WpDriver::~WpDriver()
|
|
|
|
{
|
|
|
|
Output("Unloading module Wanpipe");
|
|
|
|
}
|
|
|
|
|
|
|
|
void WpDriver::initialize()
|
|
|
|
{
|
|
|
|
Output("Initializing module Wanpipe");
|
|
|
|
init("wpchan");
|
2005-05-20 04:06:31 +00:00
|
|
|
installRelay(Halt,110);
|
2005-05-18 00:21:55 +00:00
|
|
|
}
|
|
|
|
|
2005-05-20 04:06:31 +00:00
|
|
|
bool WpDriver::received(Message &msg, int id)
|
|
|
|
{
|
2005-05-30 13:51:38 +00:00
|
|
|
bool ok = PriDriver::received(msg,id);
|
2005-05-20 04:06:31 +00:00
|
|
|
if (id == Halt) {
|
|
|
|
Debug(this,DebugAll,"WpDriver clearing all spans [%p]",this);
|
2005-05-30 13:51:38 +00:00
|
|
|
lock();
|
2005-05-20 04:06:31 +00:00
|
|
|
const ObjList *l = &m_spans;
|
|
|
|
for (; l; l=l->next()) {
|
|
|
|
WpSpan *s = static_cast<WpSpan*>(l->get());
|
|
|
|
if (s)
|
|
|
|
s->cancel();
|
|
|
|
}
|
2005-05-30 13:51:38 +00:00
|
|
|
unlock();
|
|
|
|
Debug(this,DebugAll,"WpDriver waiting for spans to exit [%p]",this);
|
|
|
|
while (m_spans.get())
|
|
|
|
Thread::msleep(10);
|
2005-05-20 04:06:31 +00:00
|
|
|
}
|
2005-05-30 13:51:38 +00:00
|
|
|
return ok;
|
2005-05-20 04:06:31 +00:00
|
|
|
}
|
|
|
|
|
2006-05-27 14:53:18 +00:00
|
|
|
}; // anonymous namespace
|
2005-05-20 04:06:31 +00:00
|
|
|
|
2005-05-18 00:21:55 +00:00
|
|
|
#endif /* _WINDOWS */
|
|
|
|
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|