/*
 * Copyright (c) 2001 Tommy Bohlin <tommy@gatespace.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
 */
/* irda.h
 */

#include <sys/types.h>

#ifdef __NetBSD__
#include <sys/param.h>
#if __NetBSD_Version__ >= 105260000
#include <dev/ir/irdaio.h>
#define IRDA_KERNEL_DRIVER
#endif
#endif /*__NetBSD__*/

typedef int bool;
#define FALSE                    0
#define TRUE                     1

/**********************************************************************
 * General utilities
 **********************************************************************/

void showBytes(const void* buf, int len);
void showChars(const void* buf, int len);

void putBELong(void* buf, int val);
void putBEShort(void* buf, int val);
int  getBELong(const void* buf);
int  getBEShort(const void* buf);
int  getBEVariable(const void* buf, int len);
int  getLEVariable(const void* buf, int len);

int  getLEParameter(int key, int deflt, const void* buf, int len);
int  getBEParameter(int key, int deflt, const void* buf, int len);

int  highestBit(int mask);
int  lowestBit(int mask);

/**********************************************************************
 * OS dependent utilities
 **********************************************************************/

void showResources(void);

bool setFileLog(const char* file);
void setSysLog(void);
void birda_log(const char* fmt, ...);

void* allocMem(const char* id, int size);
void* growMem(void* ptr, int size);
void  freeMem(void* ptr);

unsigned getRandom(unsigned max);

extern int evtDebug;
#define EVT_DEBUG_SELECT         1
#define EVT_DEBUG_TIMERS         2

void evtSetTimer(int delay, void (*func)(void*), void* handle);
void evtCancelTimer(void (*func)(void*), void* handle);
void evtLoop(void);

void evtRemoveSource(int fd);
void evtAddSource(int fd, void (*func)(void* handle), void* handle);

/**********************************************************************
 * Serial ports
 **********************************************************************/

typedef struct SerialPort {
  void (*close)(struct SerialPort* sp);
  void (*setSpeed)(struct SerialPort* sp, int speed);
  void (*setLine)(struct SerialPort* sp, int control);
#define LINE_DTR                 1
#define LINE_RTS                 2
  int  (*getSpeedMask)(struct SerialPort* sp);
  int  (*getChar)(struct SerialPort* sp);
#define SERIAL_INBUF_EMPTY       (-1)
  void (*putChar)(struct SerialPort* sp, int c);
  /*-- User fields ----------*/
  int debug;
#define SP_DEBUG_INPUT           1
  void *handle;
  void (*status)(struct SerialPort* sp, int event);
#define SERIAL_INPUT_AVAILABLE   1
} SerialPort;

SerialPort* createSerialPort(const char* dev, int maxspeed);

/**********************************************************************
 * Serial devices
 **********************************************************************/

typedef struct SerialDevice {
  void (*close)(struct SerialDevice* sd);
  int  (*setSpeed)(struct SerialDevice* sd, int speed);
  int  (*getSpeedMask)(struct SerialDevice* sd);
  int  (*getMinTurnaroundMask)(struct SerialDevice* sd);
  int  (*getChar)(struct SerialDevice* sd);
#define SERIAL_INBUF_EMPTY       (-1)
  void (*putChar)(struct SerialDevice* sd, int c);
  /*-- User fields ----------*/
  int debug;
  void* handle;
  void (*status)(struct SerialDevice* sd, int event);
#define SERIAL_INPUT_AVAILABLE   1
} SerialDevice;

SerialDevice* createRawDevice(SerialPort* sp);
SerialDevice* createTekram210Device(SerialPort* sp);
SerialDevice* createJetEyeDevice(SerialPort* sp);
SerialDevice* createACTiSYS220Device(SerialPort* sp, bool plus);
SerialDevice* createLiteLinkDevice(SerialPort* sp);
SerialDevice* createGIrBILDevice(SerialPort* sp);
SerialDevice* createRedlinkDevice(SerialPort* sp);

/**********************************************************************
 * Frame devices
 **********************************************************************/

typedef struct FrameDevice {
  void (*close)(struct FrameDevice* fd);
  int  (*setParams)(struct FrameDevice* fd, int speed, int ebofs, int maxSize);
  void (*resetParams)(struct FrameDevice* fd);
#define DEFAULT_SPEED            9600
#define DEFAULT_EBOFS            10
#define DEFAULT_SIZE             386
  void (*sendFrame)(struct FrameDevice* fd, const void* buf, int len);
  int  (*getSpeedMask)(struct FrameDevice* fd);
/* SIR speeds */
#define SPEED_2400               0x001
#define SPEED_9600               0x002
#define SPEED_19200              0x004
#define SPEED_38400              0x008
#define SPEED_57600              0x010
#define SPEED_115200             0x020
/* MIR speeds */
#define SPEED_576000             0x040
#define SPEED_1152000            0x080
/* FIR speeds */
#define SPEED_4000000            0x100
/* VFIR speeds */
#define SPEED_16000000           0x200
  int  (*getMinTurnaroundMask)(struct FrameDevice* fd);
#define MIN_TA_10ms              0x01
#define MIN_TA_5ms               0x02
#define MIN_TA_1ms               0x04
#define MIN_TA_500us             0x08
#define MIN_TA_100us             0x10
#define MIN_TA_50us              0x20
#define MIN_TA_10us              0x40
#define MIN_TA_0                 0x80
  /*-- User fields ----------*/
  int  debug;
#define FRAME_DEBUG_INPUT        1
  void* handle;
  void (*frame)(struct FrameDevice* fd, void* buf, int len);
} FrameDevice;

int createSIRFrame(int ebofs, const u_char *src, int len, u_char *dst, int maxlen);

FrameDevice* createSIRFrameDevice(SerialDevice* dev);
FrameDevice* createKernelFrameDevice(char *dev, int maxspeed);

/**********************************************************************
 * LAP/LM
 **********************************************************************/

typedef struct Connection {
  /*-- User fields ----------*/
  int debug;
  void* handle;
  void (*status)(struct Connection* con, int event, void* buf, int len);
#define CONN_OPENED              1
#define CONN_CLOSED              2
  void (*data)(struct Connection* con, void* buf, int len);
} Connection;

void connClose(Connection* con);
int  connGetSendDataSize(Connection* con);
int  connGetRecvDataSize(Connection* con);
bool connWrite(Connection* con, const void* buf, int len);
bool connWrite2(Connection* con, const void* buf1, int len1, const void* buf2, int len2);

typedef struct LSAP {
  /*-- User fields ----------*/
  int debug;
  void* handle;
  bool (*accept)(struct LSAP* lsap, Connection* con, void* buf, int len);
} LSAP;

void lsapClose(LSAP* lsap);
u_char lsapGetSelector(LSAP* lsap);

typedef struct LAP {
  /*-- User fields ----------*/
  int flags;
#define HINT_PNP                 0x0001
#define HINT_PDA                 0x0002
#define HINT_COMPUTER            0x0004
#define HINT_PRINTER             0x0008
#define HINT_MODEM               0x0010
#define HINT_FAX                 0x0020
#define HINT_LAN_ACCESS          0x0040
#define HINT_TELEPHONY           0x0100
#define HINT_FILE_SERVER         0x0200
#define HINT_IRCOMM              0x0400
#define HINT_MESSAGE             0x0800
#define HINT_HTTP                0x1000
#define HINT_IROBEX              0x2000
  int debug;
#define LAP_DEBUG_INFO           0x01
#define LAP_DEBUG_FRAMES_IN      0x02
#define LAP_DEBUG_FRAMES_OUT     0x04
#define LAP_DEBUG_TIMERS         0x08
#define LAP_SNOOP                0x10
  void* handle;
  bool (*status)(struct LAP* lap, int event, int address, int hints, int charset, char* name, int len);
#define LAP_DISCOVERING          1
#define LAP_CONNECTING           2
#define LAP_DISCOVERED           3
#define LAP_DISCOVERY_END        4
#define LAP_CONNECTED            5
#define LAP_DISCONNECTED         6
} LAP;

LAP* createLAP(FrameDevice* fdev, int charSet, const char* name, int length);
#define CHARSET_ASCII            0
#define CHARSET_ISO_LATIN1       1
#define CHARSET_UNICODE          0xff

void lapClose(LAP* lap);
bool lapDiscover(LAP* lap);
bool lapConnect(LAP* lap, int address);
void lapDisconnect(LAP* lap);

LSAP* lapNewLSAP(LAP* lap, int flags);
#define LM_TINY_TP               1

Connection* lapNewConnection(LAP* lap, int rlsap, int flags, const void* buf, int len);

/**********************************************************************
 * IAS
 **********************************************************************/

typedef struct Attribute {
  /*-- User fields ----------*/
  int debug;
} Attribute;

void iasAttrDelete(Attribute* attr);

typedef struct Object {
  /*-- User fields ----------*/
  int debug;
} Object;

void iasObjDelete(Object* obj);
Attribute* iasObjNewInteger(Object*, const char* name, int value);
Attribute* iasObjNewString(Object*, const char* name, int charset, const char* value, int length);
Attribute* iasObjNewOctets(Object*, const char* name, const void* value, int length);

typedef struct IASServer {
  /*-- User fields ----------*/
  int debug;
#define IAS_DEBUG_INFO           1
} IASServer;

IASServer* createIASServer(LAP* lap, int charset, const char* name, int len);

void iasSrvClose(IASServer* ias);
Object* iasSrvNewObject(IASServer* ias, const char* class);

typedef struct IASClient {
  /*-- User fields ----------*/
  int debug;
#define IAS_DEBUG_INFO           1
  void* handle;
  void (*status)(struct IASClient* ic, int event);
#define IAS_QUERY_COMPLETE       1
#define IAS_QUERY_FAILED         2
} IASClient;

IASClient* createIASClient(LAP* lap);

void iasCltClose(IASClient* ias);
bool iasCltGetValueByClass(IASClient* ias, const char* class, const char* name);
int  iasCltResType(IASClient* ias);
#define IAS_NONE                 0
#define IAS_INT                  1
#define IAS_OCTETS               2
#define IAS_STRING               3
int  iasCltResId(IASClient* ias);
int  iasCltResInt(IASClient* ias);
int  iasCltResLength(IASClient* ias);
int  iasCltResCharSet(IASClient* ias);
void* iasCltResPtr(IASClient* ias);
void iasCltResNext(IASClient* ias);
void iasCltShowResult(IASClient* ias);

/**********************************************************************
 * OBEX
 **********************************************************************/

typedef struct OBEXServer {
  /*-- User fields ----------*/
  int debug;
#define OBEX_DEBUG_INFO          1
  void* handle;
  void (*object)(struct OBEXServer* obex, void* buf, int len);
} OBEXServer;

OBEXServer* createOBEXServer(LAP* lap, IASServer* ias);

void obexSrvClose(OBEXServer* obex);

typedef struct OBEXClient {
  /*-- User fields ----------*/
  int debug;
#define OBEX_DEBUG_INFO          1
  void* handle;
  void (*status)(struct OBEXClient* obex, int event);
#define OBEX_SUCCESS             1
#define OBEX_FAILURE             2
} OBEXClient;

OBEXClient* createOBEXClient(LAP* lap);

void obexCltClose(OBEXClient* obex);
bool obexCltPut(OBEXClient* obex, const void* buf, int len);

void createOBEXSender(int port);

/**********************************************************************
 * COMM
 **********************************************************************/

typedef struct COMMPort {
  /*-- User fields ----------*/
  int debug;
  void* handle;
  void (*status)(struct COMMPort* comm, int event);
#define COMM_CONNECTED           1
#define COMM_DISCONNECTED        2
  void (*data)(struct COMMPort* comm, void* buf, int len);
} COMMPort;

void commPortClose(COMMPort* cp);
void commPortWrite(COMMPort* cp, const void* buf, int len);

typedef struct COMMServer {
  /*-- User fields ----------*/
  int debug;
#define COMM_DEBUG_INFO          1
} COMMServer;

COMMServer* createCOMMServer(LAP* lap, IASServer* ias);

COMMPort* commSrvNewPort(COMMServer* comm);
void commSrvClose(COMMServer* comm);

typedef struct COMMClient {
  /*-- User fields ----------*/
  int debug;
#define COMM_DEBUG_INFO          1
  void* handle;
  void (*status)(struct COMMClient* comm, int event);
  void (*data)(struct COMMClient* comm, void* buf, int len);
} COMMClient;

COMMClient* createCOMMClient(LAP* lap, int serviceMask, int portMask, bool isDCE);
#define COMM_ST_3WIRE_RAW        1
#define COMM_ST_3WIRE            2
#define COMM_ST_9WIRE            4
#define COMM_ST_CENTRONICS       8
#define COMM_PT_SERIAL           1
#define COMM_PT_PARALLEL         2

void commCltClose(COMMClient* comm);
void commCltWrite(COMMClient* comm, const void* buf, int len);
void commCltSetParams(COMMClient* comm, int dataRate, int dataFormat);
#define COMM_8N1                 0x3
void commCltSetDCE(COMMClient* comm, int dce);
#define COMM_CTS                 0x10
#define COMM_DSR                 0x20
#define COMM_RI                  0x40
#define COMM_CD                  0x80
void commCltSetDTE(COMMClient* comm, int dte);
#define COMM_DTR                 0x04
#define COMM_RTS                 0x08

/**********************************************************************
 * Options processing utility
 **********************************************************************/

typedef struct Option {
  const char type;
#define OPTION_BOOL              0
#define OPTION_INT               1
#define OPTION_STRING            2
  const char opt;
  const char* arg;
  const char* desc;
  union {
    bool b;
    int i;
    char* s;
  } val;
} Option;

void doOptions(int argc, char* const argv[],
	       int optc, Option* options,
	       int* verbosityp, const char* desc);
void doConnect(void);

LAP* optLap;
IASServer* optIas;

void (*optLapConnected)(LAP* lap);
void (*optLapDisconnected)(LAP* lap);
