Logo Search packages:      
Sourcecode: baycomusb version File versions  Download package

bayusb_orb.c

/*****************************************************************************/

/*
 *    bayusb.c  --  FlexNet driver for Baycom USB modem.
 *
 *    Copyright (C) 1999-2000
 *          Thomas Sailer (sailer@ife.ee.ethz.ch)
 *
 *    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
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 *  History:
 *   0.1  23.06.1999  Created
 *   0.2  07.01.2000  Expanded to usbdevfs capabilities
 *
 */

/*****************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>

#include "flexdrv.h"
#include "resource.h"

/* --------------------------------------------------------------------- */

#include "trx.h"

#define VERBOSE

#ifdef VERBOSE
#define verbose(x) x
#else
#define verbose(x)
#endif

static CORBA_ORB trx_orb;

static inline Trx_Control ior_to_obj(const char *ior)
{
      CORBA_Environment ev;
      Trx_Control obj;
      Trx_TrxDescription *desc;

      CORBA_exception_init(&ev);
      obj = CORBA_ORB_string_to_object(trx_orb, (char *)ior, &ev);
      if (ev._major != CORBA_NO_EXCEPTION) {
            verbose(fprintf(stderr, "Error: trx_resolve_byindex: %s %s\n", ior, CORBA_exception_id(&ev)));
            CORBA_exception_free(&ev);
            return NULL;
      }
      Trx_Control_GetDescription(obj, &desc, &ev);
      if (ev._major != CORBA_NO_EXCEPTION) {
            verbose(fprintf(stderr, "Error: trx_resolve_byindex: (GetDescription) %s %s\n", ior, CORBA_exception_id(&ev)));
            CORBA_exception_free(&ev);
            CORBA_Object_release(obj, &ev);
            return NULL;
      }
      verbose(fprintf(stderr, "trx_resolve_byindex: %s mfg %s model %s instid %s\n", 
                  ior, desc->manufacturer, desc->model, desc->instid));
      CORBA_free(desc);
      CORBA_exception_free(&ev);
      return obj;
}

static inline void runserver(void)
{
        static unsigned int inited = 0;
        char name[512], cmdname[512], cmdline[512], *cp;
        STARTUPINFO sti;
        PROCESS_INFORMATION pi;

        if (inited)
                return;
        inited = 1;
        if (!GetModuleFileName(GetModuleHandle(NULL), name, sizeof(name))) {
                fprintf(stderr, "Cannot determine executable name\n");
                return;
        }
        if ((cp = strrchr(name, '\\')))
                *cp = 0;
        else
                name[0] = 0;
        snprintf(cmdname, sizeof(cmdname), "%s\\baycomusbserv.exe", name);
      /*
       * Database calls (getXbyY) seem to hang for a very looooong time under
       * w9x if DNS is not or misconfigured. So we set the binding address to
       * 127.0.0.1, which only accepts connections from 127.0.0.1
       * and does no database calls
       */
        snprintf(cmdline, sizeof(cmdline), "%s -v 9 -s -ORBBindAddr=127.0.0.1", cmdname);
        GetStartupInfo(&sti);
        if (!CreateProcess(cmdname, cmdline, NULL, NULL, FALSE,
                           DETACHED_PROCESS | CREATE_DEFAULT_ERROR_MODE | HIGH_PRIORITY_CLASS,
                           NULL, NULL, &sti, &pi)) {
                fprintf(stderr, "Cannot start command %s, Error %lu\n", cmdname, GetLastError());
        }        
}

static Trx_Control trx_resolve_byindex(unsigned int index)
{
      Trx_Control obj;
      HKEY key, key2;
        DWORD err, i, bufsz, dt;
      CORBA_Environment ev;
      char buf[512];

        runserver();
      if ((err = RegOpenKeyEx(IORREGHKEY, IORREGPATH, 0, KEY_ENUMERATE_SUB_KEYS, &key)) != ERROR_SUCCESS) {
                fprintf(stderr, "RegOpenKeyEx(" IORREGPATH ") returned 0x%lx\n", err);
                return CORBA_OBJECT_NIL;
        }
      for (i = 0;; i++) {
            bufsz = sizeof(buf);
            err =  RegEnumKeyEx(key, i, buf, &bufsz, NULL, NULL, NULL, NULL);
            if (err != ERROR_SUCCESS) {
                  RegCloseKey(key);
                  return NULL;
            }
            if (RegOpenKeyEx(key, buf, 0, KEY_ALL_ACCESS, &key2) != ERROR_SUCCESS)
                  continue;
            bufsz = sizeof(buf);
            if (RegQueryValueEx(key2, "IOR", NULL, &dt, buf, &bufsz) != ERROR_SUCCESS) {
                  RegCloseKey(key2);
                  continue;
            }
                RegCloseKey(key2);
            if (dt != REG_SZ) {
                  continue;
            }
            if ((obj = ior_to_obj(buf))) {
                        if (index) {
                                index--;
                                CORBA_exception_init(&ev);
                                CORBA_Object_release(obj, &ev);
                                CORBA_exception_free(&ev);
                                continue;
                        }
                  RegCloseKey(key);
                  return obj;
            }
      }
}

int trx_initorb(int *argc, char **argv)
{
      CORBA_Environment ev;

        CORBA_exception_init(&ev);
      trx_orb = CORBA_ORB_init(argc, argv, "orbit-local-orb", &ev);
      if (ev._major != CORBA_NO_EXCEPTION) {
            verbose(fprintf(stderr, "Error: trx_initorb: %s\n", CORBA_exception_id(&ev)));
            CORBA_exception_free(&ev);
            return -1;
      }
      return 0;
}

/* --------------------------------------------------------------------- */

#define DRIVER_NAME     "BaycomUSB"
#define DRIVER_VERSION  "0.2"

static struct state {
      unsigned int terminate;
      Trx_Control obj;
      HANDLE hobjmutex;
      HANDLE hdevlife;

            char serial[16];   /* device serial number, or NULL string for any device */
      char devname[32];

        byte baud;
      byte mode;
      byte status;

      unsigned int scale;
      unsigned int txdelay;
      unsigned int fullduplex;

      UINT calibtimer;

      Trx_FlexNetPollState *poll;
      unsigned int pollidx;

      L1FRAME txframe;
      L1FRAME rxframe;
      L1_STATISTICS stat;
} state = { 0, };

/* ----------------------------------------------------------------------- */

/*
 * Treiber-Init. Sofern mehrfach aufgerufen, kommt vorher jeweils l1_exit()
 * Hier also alle Ressourcen allokieren, aber noch nicht starten sofern
 * dazu die Parameter gebraucht werden. Die kommen spaeter per l1_init_kanal()
 */

int init_device(HKEY hKey)
{
      DWORD regtype, reglen, regval;
      int argc = 0;
      char *argv[1] = { NULL };
      static int orbinit = 1;
      

      verboselevel = ~0;
      syslogmsg = 1;

      /* initialize ORB */
      if (orbinit && trx_initorb(&argc, argv))
                return 0;
      orbinit = 0;
      /* get serial from registry */
      reglen = sizeof(state.serial);
      if (RegQueryValueEx(hKey, "SerialNumber", NULL, &regtype, state.serial, &reglen) != ERROR_SUCCESS ||
          regtype != REG_SZ)
            state.serial[0] = 0;
      state.serial[sizeof(state.serial)-1] = 0;
      reglen = sizeof(regval);
      if (RegQueryValueEx(hKey, "TxDelay", NULL, &regtype, (void *)&regval, &reglen) != ERROR_SUCCESS ||
          regtype != REG_DWORD)
            regval = 5;
      state.txdelay = regval;
      reglen = sizeof(regval);
      if (RegQueryValueEx(hKey, "FullDuplex", NULL, &regtype, (void *)&regval, &reglen) != ERROR_SUCCESS ||
          regtype != REG_DWORD)
            regval = 0;
      state.fullduplex = regval;
      state.terminate = 0;
        state.status = CH_DEAD;
      state.obj = CORBA_OBJECT_NIL;
      state.poll = NULL;
      state.hdevlife = CreateEvent(NULL, FALSE, FALSE, "FlexNet Device State");
      state.hobjmutex = CreateMutex(NULL, FALSE, NULL);
        return 1;
}

/* ------------------------------------------------------------------------- */

void l1_exit(HKEY hKey)
{
        CORBA_Environment ev;
      DWORD regval;
        
      WaitForSingleObject(state.hobjmutex, INFINITE);
      state.terminate = 1;
        if (state.obj) {
                CORBA_exception_init(&ev);
                Trx_Control_FlexNetUnlock(state.obj, &ev);
                CORBA_exception_free(&ev);
                CORBA_Object_release(state.obj, &ev);
                CORBA_exception_free(&ev);
                state.obj = CORBA_OBJECT_NIL;
        }
        if (state.poll)
                CORBA_free(state.poll);
        state.poll = NULL;
        ReleaseMutex(state.hobjmutex);
        l1_init_kanal(0, 0, MODE_off);
      RegSetValueEx(hKey, "SerialNumber", 0, REG_SZ, state.serial, strlen(state.serial)+1);
      regval = state.txdelay;
      RegSetValueEx(hKey, "TxDelay", 0, REG_DWORD, (void *)&regval, sizeof(regval));
      regval = state.fullduplex;
      RegSetValueEx(hKey, "FullDuplex", 0, REG_DWORD, (void *)&regval, sizeof(regval));   
      CloseHandle(state.hdevlife);
      CloseHandle(state.hobjmutex);
}

/* ------------------------------------------------------------------------- */

byte *config_info(byte kanal)
{
      return state.devname;
}

/* ------------------------------------------------------------------------- */

static BOOL CALLBACK EdParmDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        CORBA_Environment ev;
        Trx_TrxDescription *desc;
        Trx_Control obj;
        HWND hcombo;
        char buf[32];
      unsigned int restart, i, index;
        int cursel;

      switch (uMsg) {
      case WM_INITDIALOG:
                hcombo = GetDlgItem(hDlg, IDC_SERIAL);
                SendMessage(hcombo, CB_ADDSTRING, 0, (LPARAM)"Any");
            cursel = state.serial[0] ? -1 : 0;
            WaitForSingleObject(state.hobjmutex, INFINITE);
            CORBA_exception_init(&ev);
            for (index = 0, i = 1;; index++) {
                      if (!(obj = trx_resolve_byindex(index)))
                        break;
                  Trx_Control_GetDescription(obj, &desc, &ev);
                  if (ev._major == CORBA_NO_EXCEPTION) {
                        SendMessage(hcombo, CB_ADDSTRING, 0, (LPARAM)desc->instid);
                        if (!strcmp(desc->instid, state.serial))
                              cursel = i;
                        CORBA_free(desc);
                        i++;
                  }
                        CORBA_exception_free(&ev);
                        CORBA_Object_release(obj, &ev);
                        CORBA_exception_free(&ev);
                }
            ReleaseMutex(state.hobjmutex);
            ComboBox_SetCurSel(hcombo, cursel);
                snprintf(buf, sizeof(buf), "%d", state.txdelay);
                SetDlgItemText(hDlg, IDC_TXDELAY, buf);
                CheckDlgButton(hDlg, IDC_FULLDUPLEX, state.fullduplex ? BST_CHECKED : BST_UNCHECKED);
            SetWindowText(hDlg, DRIVER_NAME" Configuration");
            break;
                
        case WM_COMMAND:
                switch (GET_WM_COMMAND_ID(wParam, lParam)) {
                case IDCANCEL:
                        EndDialog(hDlg, 0);
                        break;

                case IDOK:
                        GetDlgItemText(hDlg, IDC_SERIAL, buf, sizeof(buf));
                  if (!strcmp(buf, "Any"))
                        buf[0] = 0;
                        restart = strcmp(buf, state.serial);
                        strncpy(state.serial, buf, sizeof(state.serial));
                  GetDlgItemText(hDlg, IDC_TXDELAY, buf, sizeof(buf));
                        state.txdelay = strtoul(buf, NULL, 0);
                        state.fullduplex = IsDlgButtonChecked(hDlg, IDC_FULLDUPLEX) == BST_CHECKED;
            EndDialog(hDlg, restart);
                        break;
                        
                default:      
                        break;
                }
                break;
      
      default:
            return FALSE;
      }
      return TRUE;
}

/* ------------------------------------------------------------------------- */

int config_device(byte max_channels, HWND hDlg, byte channel)
{
        CORBA_Environment ev;
      int restart = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hDlg, EdParmDlgProc, 0);

      if (restart) {
            WaitForSingleObject(state.hobjmutex, INFINITE);
            CORBA_exception_init(&ev);
            if (state.obj) {
                        Trx_Control_FlexNetUnlock(state.obj, &ev);
                        CORBA_exception_free(&ev);
                  CORBA_Object_release(state.obj, &ev);
                }
            CORBA_exception_free(&ev);
            state.obj = CORBA_OBJECT_NIL;
            if (state.poll)
                  CORBA_free(state.poll);
            state.poll = NULL;
            ReleaseMutex(state.hobjmutex);
      }
      return restart;
}

/* ------------------------------------------------------------------------- */

u16 l1_get_ch_cnt(void)
{
      return 1;

}

/* ------------------------------------------------------------------------- */

byte get_txdelay(byte kanal)
{
      return state.txdelay / 10;
}

void set_txdelay(byte kanal, byte delay)
{
      state.txdelay = 10 * delay;
}

u16 get_mode(byte kanal)
{
      return (state.mode & ~MODE_d) | (state.fullduplex ? MODE_d : 0);
}

u16 get_baud(byte kanal)
{
      return state.baud;
}

/* ------------------------------------------------------------------------- */

byte l1_init_kanal(byte kanal, u16 chbaud, u16 chmode)
{
      state.mode = chmode;
      return 1;
}

/* ------------------------------------------------------------------------- */

byte l1_ch_active(byte kanal)
{
      return 1;
}

/* ------------------------------------------------------------------------- */

char far *l1_ident(byte kanal)
{
      return DRIVER_NAME;
}

/* ------------------------------------------------------------------------- */

char far *l1_version(byte kanal)
{
      return DRIVER_VERSION;
}

/* ------------------------------------------------------------------------- */

L1_STATISTICS far *l1_stat(byte kanal, byte delete)
{
      L1_STATISTICS *p = &state.stat;
      
      if (delete)
            p->tx_error = p->rx_overrun = p->rx_bufferoverflow =
            p->tx_frames = p->rx_frames = p->io_error = 0;
      return p;
}

/* ------------------------------------------------------------------------- */

void set_led(byte kanal, byte ledcode)
{
        CORBA_Environment ev;

      WaitForSingleObject(state.hobjmutex, INFINITE);
      if (state.obj) {
            CORBA_exception_init(&ev);
            Trx_Control_FlexNetSetLEDS(state.obj, !!(ledcode & LED_CON), !!(ledcode & LED_STA), &ev);
            CORBA_exception_free(&ev);
      }
      ReleaseMutex(state.hobjmutex);
}

/* ------------------------------------------------------------------------- */

byte l1_ch_state(byte kanal)
{
      return state.status;
}

/* ------------------------------------------------------------------------- */

u16 l1_scale(byte kanal)
{
      return state.scale;
}

/* ------------------------------------------------------------------------- */

static void CALLBACK stopcalib(HWND hwnd, UINT umsg, UINT idevent, DWORD dwtime)
{
        CORBA_Environment ev;

      WaitForSingleObject(state.hobjmutex, INFINITE);
      if (state.obj) {
            CORBA_exception_init(&ev);
            Trx_Control_SetPTT(state.obj, CORBA_FALSE, &ev);
            CORBA_exception_free(&ev);
      }
      ReleaseMutex(state.hobjmutex);
}

void l1_tx_calib(byte kanal, byte minutes)
{
        CORBA_Environment ev;

      if (state.calibtimer)
            KillTimer(NULL, state.calibtimer);
      WaitForSingleObject(state.hobjmutex, INFINITE);
      if (state.obj) {
            CORBA_exception_init(&ev);
            Trx_Control_SetPTT(state.obj, CORBA_TRUE, &ev);
            CORBA_exception_free(&ev);
      }
      ReleaseMutex(state.hobjmutex);
      state.calibtimer = SetTimer(NULL, 0, minutes * 60000, stopcalib);
      if (!state.calibtimer)
            stopcalib(NULL, 0, 0, 0);
}


/* ------------------------------------------------------------------------- */

L1FRAME far *l1_get_framebuf(byte kanal)
{
      return &state.txframe;
}

byte l1_tx_frame(void)
{
        CORBA_Environment ev;
      Trx_FlexNetPacket pkt = { 0, };
      byte ret = 0;

        pkt.txdelay = state.txframe.txdelay;
        if (!pkt.txdelay)
                pkt.txdelay = state.txdelay / 10;
      pkt.data._buffer = state.txframe.frame;
      pkt.data._length = pkt.data._maximum = state.txframe.len;
      WaitForSingleObject(state.hobjmutex, INFINITE);
      if (!state.obj) {
            ReleaseMutex(state.hobjmutex);
            state.stat.io_error++;
            return 1;
      }
      CORBA_exception_init(&ev);
      Trx_Control_FlexNetSendPacket(state.obj, &pkt, &ev);
      if (ev._major == CORBA_NO_EXCEPTION) {
            ret = 1;
            state.stat.tx_frames++;
      }
      CORBA_exception_free(&ev);
      ReleaseMutex(state.hobjmutex);
      return ret;
}

/* ------------------------------------------------------------------------- */

/*
 * RX-Thread. Wartet auf RX-Bytes, verarbeitet sie und returned wenn
 * Handle zu oder Paket komplett
 */

L1FRAME far *l1_rx_frame(void)
{
        CORBA_Environment ev;
      CORBA_unsigned_long bitrate;
        Trx_TrxDescription *desc;
        Trx_Control obj;
      Trx_FlexNetPacket *pkt;
      unsigned int i;
        byte st;
        
      WaitForSingleObject(state.hobjmutex, INFINITE);
      for (;;) {
            if (state.terminate) {
                  ReleaseMutex(state.hobjmutex);
                  return NULL;
            }
            if (!state.obj) {
                  state.status = CH_DEAD;
                  SetEvent(state.hdevlife);
                  for (i = 0; i < 20; i++) {
                        if (state.terminate)
                              break;
                        ReleaseMutex(state.hobjmutex);
                        Sleep(50);
                        WaitForSingleObject(state.hobjmutex, INFINITE);
                  }
                  if (state.terminate)
                        continue;
                  for (i = 0;; i++) {
                        CORBA_exception_init(&ev);
                        if (!(obj = trx_resolve_byindex(i)))
                              break;
                        Trx_Control_GetDescription(obj, &desc, &ev);
                        if (ev._major == CORBA_NO_EXCEPTION && 
                            (!state.serial[0] || !strcmp(desc->instid, state.serial)))
                              break;
                        CORBA_exception_free(&ev);
                        CORBA_Object_release(obj, &ev);
                        CORBA_exception_free(&ev);
                  }
                  if (!obj)
                        goto wait;
                  snprintf(state.devname, sizeof(state.devname), "%s (%s)", desc->model, desc->instid);
                  CORBA_free(desc);
                        if (!Trx_Control_FlexNetLock(obj, &ev) || ev._major != CORBA_NO_EXCEPTION) {
                                CORBA_exception_free(&ev);
                                CORBA_Object_release(obj, &ev);
                        CORBA_exception_free(&ev);
                                goto wait;        
                        }
                        Trx_Control_FlexNetGetBitrate(obj, &bitrate, &ev);
                  if (ev._major != CORBA_NO_EXCEPTION)
                        bitrate = 1;
                  CORBA_exception_free(&ev);
                  if (bitrate < 1)
                        bitrate = 1;
                  state.scale = 614400 / bitrate;
                  state.baud = bitrate / 100;
                  state.status = 0;
                  SetEvent(state.hdevlife);
                  state.obj = obj;
                }
            if (!state.poll) {
                  CORBA_exception_init(&ev);
                  Trx_Control_FlexNetPoll(state.obj, &state.poll, &ev);
                  if (ev._major != CORBA_NO_EXCEPTION) {
                        CORBA_exception_free(&ev);
                                Trx_Control_FlexNetUnlock(state.obj, &ev);
                                CORBA_exception_free(&ev);
                        CORBA_Object_release(state.obj, &ev);
                        CORBA_exception_free(&ev);
                        state.obj = CORBA_OBJECT_NIL;
                        state.poll = NULL;
                        goto wait;
                  }
                  CORBA_exception_free(&ev);
                  state.pollidx = 0;
                        st = state.status;
                  if (state.poll->ptt)
                        state.status |= CH_PTT;
                  else
                        state.status &= ~CH_PTT;
                  if (state.poll->dcd)
                        state.status |= CH_DCD;
                  else
                        state.status &= ~CH_DCD;
                  if (state.poll->pkt._length > 0)
                        state.status |= CH_RXB;
                  else
                        state.status &= ~CH_RXB;
                        if (state.poll->dead)
                        state.status |= CH_DEAD;
                  else
                        state.status &= ~CH_DEAD;
                        if ((state.status ^ st) & CH_DEAD)
                                SetEvent(state.hdevlife);
                        if (!state.poll->pkt._length) {
                                CORBA_free(state.poll);
                        state.poll = NULL;
                                goto wait;
                        }
            }
            if (state.pollidx < state.poll->pkt._length) {
                  pkt = &state.poll->pkt._buffer[state.pollidx++];
                        state.rxframe.kanal = 0;
                  state.rxframe.txdelay = pkt->txdelay;
                  state.rxframe.len = pkt->data._length;
                  memcpy(state.rxframe.frame, pkt->data._buffer, state.rxframe.len);
                  if (state.pollidx >= state.poll->pkt._length) {
                        state.status &= ~CH_RXB;
                        CORBA_free(state.poll);
                        state.poll = NULL;
                  }
                  ReleaseMutex(state.hobjmutex);
                  return &state.rxframe;
            }
          wait:
            ReleaseMutex(state.hobjmutex);
            Sleep(10);
            WaitForSingleObject(state.hobjmutex, INFINITE);
      }
}

/* ------------------------------------------------------------------------- */

/* KB Q164787 */

void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
      lprintf(0, "Hello World!\ncmdline: %s\n", lpszCmdLine);
      printf("Hello World!\ncmdline: %s\n", lpszCmdLine);
      Sleep(30000);
      lprintf(0, "End\n");
} 

/* ------------------------------------------------------------------------- */

Generated by  Doxygen 1.6.0   Back to index