#ifdef ZAP_ZT_SUPPORT
#include "zap_zt.h"
#endif
+#ifdef ZAP_PIKA_SUPPORT
+#include "zap_pika.h"
+#endif
static int time_is_init = 0;
zap_log_level = level;
}
-static int equalkeys(void *k1, void *k2)
+int zap_hash_equalkeys(void *k1, void *k2)
{
return strcmp((char *) k1, (char *) k2) ? 0 : 1;
}
-static uint32_t hashfromstring(void *ky)
+uint32_t zap_hash_hashfromstring(void *ky)
{
unsigned char *str = (unsigned char *) ky;
uint32_t hash = 0;
}
+static zap_status_t zap_span_destroy(zap_span_t *span)
+{
+ zap_status_t status = ZAP_FAIL;
+
+ if (zap_test_flag(span, ZAP_SPAN_CONFIGURED) && span->zio && span->zio->span_destroy) {
+ zap_log(ZAP_LOG_INFO, "Destroying span %u type (%s)\n", span->span_id, span->type);
+ status = span->zio->span_destroy(span);
+ zap_safe_free(span->type);
+ }
+
+ return status;
+}
+
static zap_status_t zap_channel_destroy(zap_channel_t *zchan)
{
if (zchan->span->zio->channel_destroy) {
- zap_log(ZAP_LOG_INFO, "Closing channel %u:%u fd:%d\n", zchan->span_id, zchan->chan_id, zchan->sockfd);
+ zap_log(ZAP_LOG_INFO, "Closing channel %s:%u:%u fd:%d\n", zchan->span->type, zchan->span_id, zchan->chan_id, zchan->sockfd);
if (zchan->span->zio->channel_destroy(zchan) == ZAP_SUCCESS) {
zap_clear_flag_locked(zchan, ZAP_CHANNEL_CONFIGURED);
} else {
uint32_t i, j;
zap_mutex_lock(globals.mutex);
- for(i = 0; i < globals.span_index; i++) {
+ for(i = 1; i <= globals.span_index; i++) {
span = &globals.spans[i];
-
- for(j = 0; j < span->chan_count; j++) {
- zap_channel_destroy(&span->channels[i]);
- }
-
- zap_safe_free(span->signal_data);
+ if (zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+ for(j = 0; j < span->chan_count; j++) {
+ zap_channel_destroy(&span->channels[i]);
+ }
+ }
}
zap_mutex_unlock(globals.mutex);
zap_log(ZAP_LOG_DEBUG, "Created DTMF Buffer!\n");
}
}
+
if (!zchan->tone_session.buffer) {
memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
zchan->tone_session.rate = zchan->rate;
zchan->tone_session.duration = zchan->dtmf_on * (zchan->tone_session.rate / 1000);
zchan->tone_session.wait = zchan->dtmf_off * (zchan->tone_session.rate / 1000);
+ zchan->tone_session.volume = -7;
+
/*
zchan->tone_session.debug = 1;
zchan->tone_session.debug_stream = stdout;
case ZAP_COMMAND_ENABLE_PROGRESS_DETECT:
{
/* if they don't have thier own, use ours */
+ zap_channel_clear_detected_tones(zchan);
+ zap_channel_clear_needed_tones(zchan);
teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_DIAL], &zchan->span->tone_detect_map[ZAP_TONEMAP_DIAL]);
teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_RING], &zchan->span->tone_detect_map[ZAP_TONEMAP_RING]);
teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_BUSY], &zchan->span->tone_detect_map[ZAP_TONEMAP_BUSY]);
case ZAP_COMMAND_ENABLE_DTMF_DETECT:
{
/* if they don't have thier own, use ours */
- if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
if (tt == ZAP_TONE_DTMF) {
teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
break;
case ZAP_COMMAND_DISABLE_DTMF_DETECT:
{
- if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
if (tt == ZAP_TONE_DTMF) {
teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
}
case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
{
- if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
GOTO_STATUS(done, ZAP_SUCCESS);
}
break;
case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
{
- if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
GOTO_STATUS(done, ZAP_SUCCESS);
}
break;
case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
{
- if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
int val = ZAP_COMMAND_OBJ_INT;
if (val > 10 && val < 1000) {
zchan->dtmf_on = val;
break;
case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
{
- if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
int val = ZAP_COMMAND_OBJ_INT;
if (val > 10 && val < 1000) {
zchan->dtmf_off = val;
break;
case ZAP_COMMAND_SEND_DTMF:
{
- if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
+ if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
char *cur;
char *digits = ZAP_COMMAND_OBJ_CHAR_P;
int x = 0;
*(str+mlen) = '\0';
zap_copy_string(str, sp, ++mlen);
zap_clean_string(str);
- zap_log(ZAP_LOG_ERROR, "FSK: TYPE %s LEN %d VAL [%s]\n", zap_mdmf_type2str(type), mlen-1, str);
+ zap_log(ZAP_LOG_DEBUG, "FSK: TYPE %s LEN %d VAL [%s]\n", zap_mdmf_type2str(type), mlen-1, str);
switch(type) {
case MDMF_DDN:
if (zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT)) {
uint32_t i;
-
+
for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
if (zchan->span->tone_finder[i].tone_count) {
if (zchan->needed_tones[i] && teletone_multi_tone_detect(&zchan->span->tone_finder[i], sln, (int)slen)) {
- zchan->detected_tones[i] = 1;
- zchan->needed_tones[i] = 0;
- zchan->detected_tones[0]++;
+ if (++zchan->detected_tones[i]) {
+ zchan->needed_tones[i] = 0;
+ zchan->detected_tones[0]++;
+ }
}
}
}
static struct {
zap_io_interface_t *wanpipe_interface;
zap_io_interface_t *zt_interface;
+ zap_io_interface_t *pika_interface;
} interfaces;
continue;
}
+ if (!zio->configure_span) {
+ zap_log(ZAP_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type);
+ span = NULL;
+ continue;
+ }
+
if (zap_span_create(zio, &span) == ZAP_SUCCESS) {
+ span->type = strdup(type);
zap_log(ZAP_LOG_DEBUG, "created span %d of type %s\n", span->span_id, type);
d = 0;
} else {
zap_isdn_init();
memset(&interfaces, 0, sizeof(interfaces));
- globals.interface_hash = create_hashtable(16, hashfromstring, equalkeys);
+ globals.interface_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
modcount = 0;
zap_mutex_create(&globals.mutex);
}
#endif
+#ifdef ZAP_PIKA_SUPPORT
+ if (pika_init(&interfaces.pika_interface) == ZAP_SUCCESS) {
+ zap_mutex_lock(globals.mutex);
+ hashtable_insert(globals.interface_hash, (void *)interfaces.pika_interface->name, interfaces.pika_interface);
+ process_module_config(interfaces.pika_interface);
+ zap_mutex_unlock(globals.mutex);
+ modcount++;
+ } else {
+ zap_log(ZAP_LOG_ERROR, "Error initilizing pika.\n");
+ }
+#endif
+
+
if (!modcount) {
zap_log(ZAP_LOG_ERROR, "Error initilizing anything.\n");
return ZAP_FAIL;
if (cur_span->mutex) {
zap_mutex_destroy(&cur_span->mutex);
}
+
+ zap_safe_free(cur_span->signal_data);
+ zap_span_destroy(cur_span);
+
}
}
zt_destroy();
}
#endif
+
+#ifdef ZAP_PIKA_SUPPORT
+ if (interfaces.pika_interface) {
+ pika_destroy();
+ }
+#endif
+
#ifdef ZAP_WANPIPE_SUPPORT
if (interfaces.wanpipe_interface) {
wanpipe_destroy();
--- /dev/null
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "openzap.h"
+#include "zap_pika.h"
+#define MAX_NUMBER_OF_TRUNKS 64
+#define PIKA_BLOCK_SIZE 160
+#define PIKA_BLOCK_LEN 20
+
+struct pika_channel_profile {
+ char name[80];
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+};
+typedef struct pika_channel_profile pika_channel_profile_t;
+
+static struct {
+ PKH_TSystemDeviceList board_list;
+ TPikaHandle open_boards[MAX_NUMBER_OF_TRUNKS];
+ TPikaHandle system_handle;
+ PKH_TSystemConfig system_config;
+ zap_hash_t *profile_hash;
+} globals;
+
+
+struct pika_span_data {
+ TPikaHandle event_queue;
+ PKH_TPikaEvent last_oob_event;
+ uint32_t boardno;
+};
+typedef struct pika_span_data pika_span_data_t;
+
+struct pika_chan_data {
+ TPikaHandle handle;
+ TPikaHandle media_in;
+ TPikaHandle media_out;
+ TPikaHandle media_in_queue;
+ TPikaHandle media_out_queue;
+ PKH_TPikaEvent last_media_event;
+ PKH_TPikaEvent last_oob_event;
+ PKH_TRecordConfig record_config;
+ PKH_TPlayConfig play_config;
+ zap_buffer_t *digit_buffer;
+ zap_mutex_t *digit_mutex;
+ int dtmf_len;
+};
+typedef struct pika_chan_data pika_chan_data_t;
+
+static char *pika_board_type_string(PK_UINT type)
+{
+ if (type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+ return "digital_gateway";
+ }
+
+ if (type == PKH_BOARD_TYPE_ANALOG_GATEWAY) {
+ return "analog_gateway";
+ }
+
+ return "unknown";
+}
+
+static ZIO_CONFIGURE_FUNCTION(pika_configure)
+{
+ pika_channel_profile_t *profile = NULL;
+ int ok = 1;
+
+ if (!(profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+ profile = malloc(sizeof(*profile));
+ memset(profile, 0, sizeof(*profile));
+ zap_set_string(profile->name, category);
+ hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
+ zap_log(ZAP_LOG_INFO, "creating profile [%s]\n", category);
+ }
+
+ if (!strcasecmp(var, "rx-gain")) {
+ profile->record_config.gain = atof(val);
+ } else if (!strcasecmp(var, "rx-agc-enabled")) {
+ profile->record_config.AGC.enabled = zap_true(val);
+ } else if (!strcasecmp(var, "rx-agc-targetPower")) {
+ profile->record_config.AGC.targetPower = atof(val);
+ } else if (!strcasecmp(var, "rx-agc-minGain")) {
+ profile->record_config.AGC.minGain = atof(val);
+ } else if (!strcasecmp(var, "rx-agc-maxGain")) {
+ profile->record_config.AGC.maxGain = atof(val);
+ } else if (!strcasecmp(var, "rx-agc-attackRate")) {
+ profile->record_config.AGC.attackRate = atoi(val);
+ } else if (!strcasecmp(var, "rx-agc-decayRate")) {
+ profile->record_config.AGC.decayRate = atoi(val);
+ } else if (!strcasecmp(var, "rx-agc-speechThreshold")) {
+ profile->record_config.AGC.speechThreshold = atof(val);
+ } else if (!strcasecmp(var, "rx-vad-enabled")) {
+ profile->record_config.VAD.enabled = zap_true(val);
+ } else if (!strcasecmp(var, "rx-vad-activationThreshold")) {
+ profile->record_config.VAD.activationThreshold = atof(val);
+ } else if (!strcasecmp(var, "rx-vad-activationDebounceTime")) {
+ profile->record_config.VAD.activationDebounceTime = atoi(val);
+ } else if (!strcasecmp(var, "rx-vad-deactivationThreshold")) {
+ profile->record_config.VAD.deactivationThreshold = atof(val);
+ } else if (!strcasecmp(var, "rx-vad-deactivationDebounceTime")) {
+ profile->record_config.VAD.deactivationDebounceTime = atoi(val);
+ } else if (!strcasecmp(var, "rx-vad-preSpeechBufferSize")) {
+ profile->record_config.VAD.preSpeechBufferSize = atoi(val);
+ } else if (!strcasecmp(var, "tx-gain")) {
+ profile->play_config.gain = atof(val);
+ } else if (!strcasecmp(var, "tx-agc-enabled")) {
+ profile->play_config.AGC.enabled = zap_true(val);
+ } else if (!strcasecmp(var, "tx-agc-targetPower")) {
+ profile->play_config.AGC.targetPower = atof(val);
+ } else if (!strcasecmp(var, "tx-agc-minGain")) {
+ profile->play_config.AGC.minGain = atof(val);
+ } else if (!strcasecmp(var, "tx-agc-maxGain")) {
+ profile->play_config.AGC.maxGain = atof(val);
+ } else if (!strcasecmp(var, "tx-agc-attackRate")) {
+ profile->play_config.AGC.attackRate = atoi(val);
+ } else if (!strcasecmp(var, "tx-agc-decayRate")) {
+ profile->play_config.AGC.decayRate = atoi(val);
+ } else if (!strcasecmp(var, "tx-agc-speechThreshold")) {
+ profile->play_config.AGC.speechThreshold = atof(val);
+ } else {
+ ok = 0;
+ }
+
+ if (ok) {
+ zap_log(ZAP_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "unknown param [%s]\n", var);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event)
+{
+ PK_STATUS pk_status;
+ zap_channel_t *zchan = event->userData;
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+ //PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
+ //PKH_EVENT_GetText(event->id, g_EventText, sizeof(g_EventText));
+ //zap_log(ZAP_LOG_DEBUG, "Event: %s\n", g_EventText);
+
+ switch (event->id) {
+ case PKH_EVENT_PLAY_IDLE:
+ {
+ while (zap_buffer_inuse(chan_data->digit_buffer)) {
+ char dtmf[128] = "";
+ zap_mutex_lock(chan_data->digit_mutex);
+ chan_data->dtmf_len = zap_buffer_read(chan_data->digit_buffer, dtmf, sizeof(dtmf));
+ pk_status = PKH_TG_PlayDTMF(chan_data->media_out, dtmf);
+ zap_mutex_unlock(chan_data->digit_mutex);
+ }
+ }
+ break;
+ case PKH_EVENT_TG_TONE_PLAYED:
+ {
+
+ if (!event->p1) {
+ zap_mutex_lock(chan_data->digit_mutex);
+ PKH_PLAY_Start(chan_data->media_out);
+ chan_data->dtmf_len = 0;
+ zap_mutex_unlock(chan_data->digit_mutex);
+ }
+
+
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+
+static unsigned pika_open_range(zap_span_t *span, unsigned boardno, unsigned spanno, unsigned start, unsigned end,
+ zap_chan_type_t type, char *name, char *number, pika_channel_profile_t *profile)
+{
+ unsigned configured = 0, x;
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+ pika_span_data_t *span_data;
+
+ if (boardno >= globals.board_list.numberOfBoards) {
+ zap_log(ZAP_LOG_ERROR, "Board %u is not present!\n", boardno);
+ return 0;
+ }
+
+ if (!globals.open_boards[boardno]) {
+ status = PKH_BOARD_Open(globals.board_list.board[boardno].id,
+ NULL,
+ &globals.open_boards[boardno]);
+ if(status != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_BOARD_Open %d failed(%s)!\n", boardno,
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return 0;
+ }
+
+ zap_log(ZAP_LOG_DEBUG, "Open board %u\n", boardno);
+
+ //PKH_BOARD_SetDebugTrace(globals.open_boards[boardno], 1, 0);
+
+ }
+
+ if (!span->mod_data) {
+ span_data = malloc(sizeof(*span_data));
+ assert(span_data != NULL);
+ memset(span_data, 0, sizeof(*span_data));
+ span_data->boardno = boardno;
+
+ status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &span_data->event_queue);
+
+ if (status != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_QUEUE_Create failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ free(span_data);
+ return 0;
+ }
+
+ PKH_QUEUE_Attach(span_data->event_queue, globals.open_boards[boardno], NULL);
+
+ span->mod_data = span_data;
+ }
+ start--;
+ end--;
+ for(x = start; x < end; x++) {
+ zap_channel_t *chan;
+ pika_chan_data_t *chan_data = NULL;
+
+ chan_data = malloc(sizeof *chan_data);
+ assert(chan_data);
+ memset(chan_data, 0, sizeof(*chan_data));
+
+ if (type == ZAP_CHAN_TYPE_FXO) {
+ PKH_TTrunkConfig trunkConfig;
+
+ if((status = PKH_TRUNK_Open(globals.open_boards[boardno], x, &chan_data->handle)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_TRUNK_Seize(chan_data->handle) != PK_SUCCESS)) {
+ goto fail_fxo;
+ }
+
+ if (zap_span_add_channel(span, 0, type, &chan) != ZAP_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_TRUNK_GetConfig(chan_data->handle, &trunkConfig) != PK_SUCCESS)) {
+ goto fail_fxo;
+ }
+
+ trunkConfig.internationalControl = PKH_TRUNK_NA;
+ trunkConfig.audioFormat = PKH_AUDIO_MULAW;
+
+ if ((status = PKH_TRUNK_SetConfig(chan_data->handle, &trunkConfig) != PK_SUCCESS)) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_TRUNK_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out)) != ZAP_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ if ((status = PKH_TRUNK_Start(chan_data->handle)) != PK_SUCCESS) {
+ goto fail_fxo;
+ }
+
+ goto ok;
+
+ fail_fxo:
+ zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_TRUNK_Open %u failed(%s)!\n", x,
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ if (chan_data->handle) {
+ PKH_TRUNK_Close(chan_data->handle);
+ }
+ PKH_QUEUE_Destroy(chan_data->media_in_queue);
+
+ free(chan_data);
+ continue;
+
+ } else if (type == ZAP_CHAN_TYPE_FXS) {
+ if((status = PKH_PHONE_Open(globals.open_boards[boardno], x, &chan_data->handle)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_PHONE_Seize(chan_data->handle) != PK_SUCCESS)) {
+ goto fail_fxs;
+ }
+
+ if (zap_span_add_channel(span, 0, type, &chan) != ZAP_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_PHONE_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out)) != ZAP_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ if ((status = PKH_PHONE_Start(chan_data->handle)) != PK_SUCCESS) {
+ goto fail_fxs;
+ }
+
+ goto ok;
+
+
+ fail_fxs:
+ zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_PHONE_Open %u failed(%s)!\n", x,
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ if (chan_data->handle) {
+ PKH_PHONE_Close(chan_data->handle);
+ }
+ PKH_QUEUE_Destroy(chan_data->media_in_queue);
+ free(chan_data);
+
+
+ }
+
+ ok:
+
+ status = PKH_RECORD_GetConfig(chan_data->media_in, &chan_data->record_config);
+ chan_data->record_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+ chan_data->record_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+ chan_data->record_config.bufferSize = PIKA_BLOCK_SIZE;
+ chan_data->record_config.numberOfBuffers = chan_data->record_config.bufferSize;
+ chan_data->record_config.VAD.enabled = PK_FALSE;
+ //chan_data->record_config.speechSegmentEventsEnabled = PK_FALSE;
+ //chan_data->record_config.gain = rxgain;
+
+
+
+ status = PKH_PLAY_GetConfig(chan_data->media_out, &chan_data->play_config);
+ chan_data->play_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+ chan_data->play_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+ chan_data->play_config.AGC.enabled = PK_FALSE;
+ zap_log(ZAP_LOG_INFO, "configuring device b%ds%dc%d as OpenZAP device %d:%d\n", boardno, spanno, x, chan->span_id, chan->chan_id);
+
+ if (profile) {
+ zap_log(ZAP_LOG_INFO, "applying config profile %s to device %d:%d\n", profile->name, chan->span_id, chan->chan_id);
+ chan_data->record_config.gain = profile->record_config.gain;
+ chan_data->record_config.AGC.enabled = profile->record_config.AGC.enabled;
+ chan_data->record_config.AGC.targetPower = profile->record_config.AGC.targetPower;
+ chan_data->record_config.AGC.minGain = profile->record_config.AGC.minGain;
+ chan_data->record_config.AGC.maxGain = profile->record_config.AGC.maxGain;
+ chan_data->record_config.AGC.attackRate = profile->record_config.AGC.attackRate;
+ chan_data->record_config.AGC.decayRate = profile->record_config.AGC.decayRate;
+ chan_data->record_config.AGC.speechThreshold = profile->record_config.AGC.speechThreshold;
+ chan_data->record_config.VAD.enabled = profile->record_config.VAD.enabled;
+ chan_data->record_config.VAD.activationThreshold = profile->record_config.VAD.activationThreshold;
+ chan_data->record_config.VAD.activationDebounceTime = profile->record_config.VAD.activationDebounceTime;
+ chan_data->record_config.VAD.deactivationThreshold = profile->record_config.VAD.deactivationThreshold;
+ chan_data->record_config.VAD.deactivationDebounceTime = profile->record_config.VAD.deactivationDebounceTime;
+ chan_data->record_config.VAD.preSpeechBufferSize = profile->record_config.VAD.preSpeechBufferSize;
+ chan_data->play_config.gain = profile->play_config.gain;
+ chan_data->play_config.AGC.enabled = profile->play_config.AGC.enabled;
+ chan_data->play_config.AGC.targetPower = profile->play_config.AGC.targetPower;
+ chan_data->play_config.AGC.minGain = profile->play_config.AGC.minGain;
+ chan_data->play_config.AGC.maxGain = profile->play_config.AGC.maxGain;
+ chan_data->play_config.AGC.attackRate = profile->play_config.AGC.attackRate;
+ chan_data->play_config.AGC.decayRate = profile->play_config.AGC.decayRate;
+ chan_data->play_config.AGC.speechThreshold = profile->play_config.AGC.speechThreshold;
+ }
+
+ status = PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+ status = PKH_PLAY_SetConfig(chan_data->media_out, &chan_data->play_config);
+
+
+ chan->mod_data = chan_data;
+ chan->physical_span_id = spanno;
+ chan->physical_chan_id = x;
+
+ chan->rate = 8000;
+ chan->packet_len = chan_data->record_config.bufferSize;
+ chan->effective_interval = chan->native_interval = chan->packet_len / 8;
+
+ PKH_RECORD_Start(chan_data->media_in);
+ PKH_PLAY_Start(chan_data->media_out);
+
+ PKH_EC_Start(chan_data->media_in, chan_data->media_in, chan_data->media_out);
+
+ if (!zap_strlen_zero(name)) {
+ zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+ }
+
+ if (!zap_strlen_zero(number)) {
+ zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+ }
+
+ zap_channel_set_feature(chan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE);
+ zap_buffer_create(&chan_data->digit_buffer, 128, 128, 0);
+ zap_mutex_create(&chan_data->digit_mutex);
+
+ configured++;
+ }
+
+
+ return configured;
+}
+
+static ZIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
+{
+ int items, i;
+ char *mydata, *item_list[10];
+ char *bd, *sp, *ch, *mx;
+ int boardno;
+ int channo;
+ int spanno;
+ int top = 0;
+ unsigned configured = 0;
+ char *profile_name = NULL;
+ pika_channel_profile_t *profile = NULL;
+
+ assert(str != NULL);
+
+ mydata = strdup(str);
+ assert(mydata != NULL);
+
+ if ((profile_name = strchr(mydata, '@'))) {
+ *profile_name++ = '\0';
+ if (!zap_strlen_zero(profile_name)) {
+ profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)profile_name);
+ }
+ }
+
+ items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+ for(i = 0; i < items; i++) {
+ bd = item_list[i];
+ if ((sp = strchr(bd, ':'))) {
+ *sp++ = '\0';
+ }
+
+ if ((ch = strchr(sp, ':'))) {
+ *ch++ = '\0';
+ }
+
+ if (!(bd && sp && ch)) {
+ zap_log(ZAP_LOG_ERROR, "Invalid input\n");
+ continue;
+ }
+
+ boardno = atoi(bd);
+ channo = atoi(ch);
+ spanno = atoi(sp);
+
+
+ if (boardno < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid board number %d\n", boardno);
+ continue;
+ }
+
+ if (channo < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
+ continue;
+ }
+
+ if (spanno < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid span number %d\n", channo);
+ continue;
+ }
+
+ if ((mx = strchr(ch, '-'))) {
+ mx++;
+ top = atoi(mx) + 1;
+ } else {
+ top = channo + 1;
+ }
+
+
+ if (top < 0) {
+ zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
+ continue;
+ }
+
+ configured += pika_open_range(span, boardno, spanno, channo, top, type, name, number, profile);
+
+ }
+
+ free(mydata);
+
+ return configured;
+}
+
+static ZIO_OPEN_FUNCTION(pika_open)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ PKH_QUEUE_Flush(chan_data->media_in_queue);
+ PKH_PLAY_Start(chan_data->media_out);
+ return ZAP_SUCCESS;
+}
+
+static ZIO_CLOSE_FUNCTION(pika_close)
+{
+ return ZAP_SUCCESS;
+}
+
+static ZIO_WAIT_FUNCTION(pika_wait)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ PK_STATUS status;
+ zap_wait_flag_t myflags = *flags;
+ PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
+
+ *flags = ZAP_NO_FLAGS;
+
+ if (myflags & ZAP_READ) {
+ status = PKH_QUEUE_WaitOnEvent(chan_data->media_in_queue, to, &chan_data->last_media_event);
+
+ if (status == PK_SUCCESS) {
+ if (chan_data->last_media_event.id == PKH_EVENT_QUEUE_TIMEOUT || chan_data->last_media_event.id == PKH_EVENT_RECORD_BUFFER_OVERFLOW) {
+ return ZAP_TIMEOUT;
+ }
+
+ *flags |= ZAP_READ;
+ return ZAP_SUCCESS;
+ }
+
+ PKH_EVENT_GetText(chan_data->last_media_event.id, g_EventText, sizeof(g_EventText));
+ zap_log(ZAP_LOG_DEBUG, "Event: %s\n", g_EventText);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_READ_FUNCTION(pika_read)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ PK_STATUS status;
+ PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
+
+ if (zchan->packet_len < *datalen) {
+ *datalen = zchan->packet_len;
+ }
+
+ if ((status = PKH_RECORD_GetData(chan_data->media_in, data, *datalen)) == PK_SUCCESS) {
+ return ZAP_SUCCESS;
+ }
+
+
+ PKH_ERROR_GetText(status, g_EventText, sizeof(g_EventText));
+ zap_log(ZAP_LOG_DEBUG, "ERR: %s\n", g_EventText);
+ return ZAP_FAIL;
+}
+
+static ZIO_WRITE_FUNCTION(pika_write)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+ if (PKH_PLAY_AddData(chan_data->media_out, 0, data, *datalen) == PK_SUCCESS) {
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+static ZIO_COMMAND_FUNCTION(pika_command)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ //pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
+ PK_STATUS pk_status;
+ zap_status_t status = ZAP_SUCCESS;
+
+ switch(command) {
+ case ZAP_COMMAND_OFFHOOK:
+ {
+ if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_OFFHOOK)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ }
+ break;
+ case ZAP_COMMAND_ONHOOK:
+ {
+ if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_ONHOOK)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_ON:
+ {
+ if ((pk_status = PKH_PHONE_RingStart(chan_data->handle, 0, 0)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GENERATE_RING_OFF:
+ {
+ if ((pk_status = PKH_PHONE_RingStop(chan_data->handle)) != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ } else {
+ zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+ }
+ }
+ break;
+ case ZAP_COMMAND_GET_INTERVAL:
+ {
+
+ ZAP_COMMAND_OBJ_INT = zchan->native_interval;
+
+ }
+ break;
+ case ZAP_COMMAND_SET_INTERVAL:
+ {
+ int interval = ZAP_COMMAND_OBJ_INT;
+ int len = interval * 8;
+ chan_data->record_config.bufferSize = len;
+ chan_data->record_config.numberOfBuffers = chan_data->record_config.bufferSize;
+ zchan->packet_len = chan_data->record_config.bufferSize;
+ zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
+ PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
+ {
+
+ ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+
+ }
+ break;
+ case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
+ {
+ ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
+ {
+ int val = ZAP_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ zchan->dtmf_on = val;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ break;
+ case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
+ {
+ int val = ZAP_COMMAND_OBJ_INT;
+ if (val > 10 && val < 1000) {
+ zchan->dtmf_off = val;
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ } else {
+ snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ }
+ break;
+ case ZAP_COMMAND_SEND_DTMF:
+ {
+ char *digits = ZAP_COMMAND_OBJ_CHAR_P;
+ zap_log(ZAP_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
+ zap_mutex_lock(chan_data->digit_mutex);
+ zap_buffer_write(chan_data->digit_buffer, digits, strlen(digits));
+ zap_mutex_unlock(chan_data->digit_mutex);
+ pk_status = PKH_PLAY_Stop(chan_data->media_out);
+
+ if (pk_status != PK_SUCCESS) {
+ PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+ GOTO_STATUS(done, ZAP_FAIL);
+ }
+ GOTO_STATUS(done, ZAP_SUCCESS);
+ }
+ break;
+ default:
+ break;
+ };
+
+ done:
+ return status;
+}
+
+static ZIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
+{
+ pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+ PK_STATUS status;
+
+ status = PKH_QUEUE_WaitOnEvent(span_data->event_queue, ms, &span_data->last_oob_event);
+
+ if (status == PK_SUCCESS) {
+ zap_channel_t *zchan = span_data->last_oob_event.userData;
+ //PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
+
+ if (span_data->last_oob_event.id == PKH_EVENT_QUEUE_TIMEOUT) {
+ return ZAP_TIMEOUT;
+ }
+
+ //PKH_EVENT_GetText(span_data->last_oob_event.id, g_EventText, sizeof(g_EventText));
+ //zap_log(ZAP_LOG_DEBUG, "Event: %s\n", g_EventText);
+
+ if (zchan) {
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+ zchan->last_event_time = zap_current_time_in_ms();
+ chan_data->last_oob_event = span_data->last_oob_event;
+ }
+
+ return ZAP_SUCCESS;
+ }
+
+ return ZAP_FAIL;
+}
+
+static ZIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
+{
+ uint32_t i, event_id;
+
+ for(i = 1; i <= span->chan_count; i++) {
+ if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) span->channels[i].mod_data;
+ PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
+
+ zap_clear_flag((&span->channels[i]), ZAP_CHANNEL_EVENT);
+
+ PKH_EVENT_GetText(chan_data->last_oob_event.id, g_EventText, sizeof(g_EventText));
+ zap_log(ZAP_LOG_DEBUG, "Event %d on channel %d:%d [%s]\n",
+ chan_data->last_oob_event.id,
+ span->channels[i].span_id,
+ span->channels[i].chan_id,
+ g_EventText);
+
+ switch(chan_data->last_oob_event.id) {
+ case PKH_EVENT_TRUNK_HOOKFLASH:
+ event_id = ZAP_OOB_FLASH;
+ break;
+ case PKH_EVENT_TRUNK_RING_OFF:
+ event_id = ZAP_OOB_RING_STOP;
+ break;
+ case PKH_EVENT_TRUNK_RING_ON:
+ event_id = ZAP_OOB_RING_START;
+ break;
+
+ case PKH_EVENT_PHONE_OFFHOOK:
+ zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_OFFHOOK);
+ event_id = ZAP_OOB_OFFHOOK;
+ break;
+
+ case PKH_EVENT_TRUNK_BELOW_THRESHOLD:
+ case PKH_EVENT_TRUNK_ABOVE_THRESHOLD:
+ case PKH_EVENT_PHONE_ONHOOK:
+ zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_OFFHOOK);
+ event_id = ZAP_OOB_ONHOOK;
+ break;
+
+ case PKH_EVENT_TRUNK_ONHOOK:
+ case PKH_EVENT_TRUNK_OFFHOOK:
+ case PKH_EVENT_TRUNK_DIALED :
+ case PKH_EVENT_TRUNK_REVERSAL:
+ case PKH_EVENT_TRUNK_LCSO:
+ case PKH_EVENT_TRUNK_DROPOUT:
+ case PKH_EVENT_TRUNK_LOF:
+ case PKH_EVENT_TRUNK_RX_OVERLOAD:
+ default:
+ zap_log(ZAP_LOG_DEBUG, "Unhandled event %d on channel %d [%s]\n", chan_data->last_oob_event.id, i, g_EventText);
+ event_id = ZAP_OOB_INVALID;
+ break;
+ }
+
+ span->channels[i].last_event_time = 0;
+ span->event_header.e_type = ZAP_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = &span->channels[i];
+ *event = &span->event_header;
+ return ZAP_SUCCESS;
+ }
+ }
+
+ return ZAP_FAIL;
+}
+
+static ZIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)
+{
+ pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+
+ if (span_data) {
+ PKH_QUEUE_Destroy(span_data->event_queue);
+ free(span_data);
+ }
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)
+{
+ pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+ pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
+
+ if (zchan->type == ZAP_CHAN_TYPE_FXS || zchan->type == ZAP_CHAN_TYPE_FXO) {
+ PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+ PKH_TRUNK_Close(chan_data->handle);
+ }
+
+ PKH_RECORD_Stop(chan_data->media_in);
+ PKH_PLAY_Stop(chan_data->media_out);
+ PKH_QUEUE_Destroy(chan_data->media_in_queue);
+ PKH_QUEUE_Destroy(chan_data->media_out_queue);
+ zap_mutex_destroy(&chan_data->digit_mutex);
+ zap_buffer_destroy(&chan_data->digit_buffer);
+ zap_safe_free(chan_data);
+
+ return ZAP_SUCCESS;
+}
+
+static ZIO_GET_ALARMS_FUNCTION(pika_get_alarms)
+{
+ return ZAP_FAIL;
+}
+
+static zap_io_interface_t pika_interface;
+
+zap_status_t pika_init(zap_io_interface_t **zint)
+{
+
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+ uint32_t i;
+ int ok = 0;
+ PKH_TLogMasks m;
+
+
+ assert(zint != NULL);
+ memset(&pika_interface, 0, sizeof(pika_interface));
+ memset(&globals, 0, sizeof(globals));
+
+ globals.profile_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+
+ // Open the system object, to enumerate boards configured for this system
+ if ((status = PKH_SYSTEM_Open(&globals.system_handle)) != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Open failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return ZAP_FAIL;
+ }
+
+ // Retrieves a list of all boards in this system, existing,
+ // or listed in pika.cfg
+ if ((status = PKH_SYSTEM_Detect(globals.system_handle, &globals.board_list)) != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Detect failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ return ZAP_FAIL;
+ }
+
+ PKH_SYSTEM_GetConfig(globals.system_handle, &globals.system_config);
+ globals.system_config.maxAudioProcessBlockSize = PIKA_BLOCK_LEN;
+ globals.system_config.playBufferSize = PIKA_BLOCK_SIZE;
+ globals.system_config.recordBufferSize = PIKA_BLOCK_SIZE;
+ globals.system_config.recordNumberOfBuffers = 8;
+ PKH_SYSTEM_SetConfig(globals.system_handle, &globals.system_config);
+
+ zap_log(ZAP_LOG_DEBUG, "Found %u board%s\n", globals.board_list.numberOfBoards, globals.board_list.numberOfBoards == 1 ? "" : "s");
+ for(i = 0; i < globals.board_list.numberOfBoards; ++i) {
+ zap_log(ZAP_LOG_INFO, "Found PIKA board type:[%s] id:[%u] serno:[%u]\n",
+ pika_board_type_string(globals.board_list.board[i].type), globals.board_list.board[i].id, (uint32_t)
+ globals.board_list.board[i].serialNumber);
+
+ ok++;
+
+ }
+
+ if (!ok) {
+ return ZAP_FAIL;
+ }
+
+ pika_interface.name = "pika";
+ pika_interface.configure = pika_configure;
+ pika_interface.configure_span = pika_configure_span;
+ pika_interface.open = pika_open;
+ pika_interface.close = pika_close;
+ pika_interface.wait = pika_wait;
+ pika_interface.read = pika_read;
+ pika_interface.write = pika_write;
+ pika_interface.command = pika_command;
+ pika_interface.poll_event = pika_poll_event;
+ pika_interface.next_event = pika_next_event;
+ pika_interface.channel_destroy = pika_channel_destroy;
+ pika_interface.span_destroy = pika_span_destroy;
+ pika_interface.get_alarms = pika_get_alarms;
+ *zint = &pika_interface;
+
+
+
+
+ memset(&m, 0, sizeof(m));
+ //m.apiMask = 0xffffffff;
+ //PKH_LOG_SetMasks(&m);
+
+ return ZAP_SUCCESS;
+}
+
+zap_status_t pika_destroy(void)
+{
+ uint32_t x;
+ PK_STATUS status;
+ PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+
+ for (x = 0; x < MAX_NUMBER_OF_TRUNKS; x++) {
+ if (globals.open_boards[x]) {
+ zap_log(ZAP_LOG_INFO, "Closing board %u\n", x);
+ PKH_BOARD_Close(globals.open_boards[x]);
+ }
+ }
+
+ // The system can now be closed.
+ if ((status = PKH_SYSTEM_Close(globals.system_handle)) != PK_SUCCESS) {
+ zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Close failed(%s)!\n",
+ PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+ }
+
+ hashtable_destroy(globals.profile_hash, 0, 1);
+
+ return ZAP_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */
+