650 lines
19 KiB
C
650 lines
19 KiB
C
/************************************************************************
|
|
* Copyright (C) 2000 Thomas Schulz *
|
|
* */
|
|
static char rcsid[] =
|
|
"$Id: synproto.c,v 1.11 2001/06/17 23:37:36 tsch Rel $"; /*
|
|
* *
|
|
* IC35 synchronize protocol *
|
|
* *
|
|
*************************************************************************
|
|
* *
|
|
* ??? is "fixme" mark: sections of code needing fixes *
|
|
* *
|
|
************************************************************************/
|
|
|
|
#include <stdio.h> /* sprintf(), .. */
|
|
#include <stdarg.h> /* va_start(), .. */
|
|
#include <string.h> /* memcpy(), strlen() ..*/
|
|
#include <time.h> /* struct tm, time(),.. */
|
|
#include <sys/types.h> /* size_t, .. */
|
|
|
|
#include "util.h" /* ERR,OK, uchar, .. */
|
|
#include "comio.h" /* com_send(), .. */
|
|
#include "genproto.h" /* putxxx(),getxxx() .. */
|
|
#include "synproto.h" /* Level-4 commands, .. */
|
|
NOTUSED(rcsid)
|
|
|
|
|
|
/* Level-1 PDU Ids */
|
|
#define L1INIT 0x01 /* initialize 01 03 00 */
|
|
#define L1DSEL 0x02 /* data select 02 ll ll <data> cc cc */
|
|
#define L1DREQ 0x04 /* data request 04 03 00 */
|
|
#define L1EXIT 0x05 /* exit 05 03 00 */
|
|
#define L1ACK0 0xF0 /* ack to initialize */
|
|
#define L1ACK1 0xF1 /* ack to datasel,exit */
|
|
#define L1DATA 0xF2 /* data response F2 ll ll <data> cc cc */
|
|
|
|
/* Level-2 PDU Ids */
|
|
#define L2INIT 0x80 /* cmd,rsp: identification */
|
|
#define L2EXIT 0x81 /* cmd: disconnect */
|
|
#define L2WMORE 0x02 /* cmd: write non-last of multiblk record */
|
|
#define L2WLAST 0x82 /* cmd: write last of multi-block record */
|
|
#define L2READ 0x83 /* cmd: read more of multi-block record */
|
|
#define L2RMORE 0x20 /* rsp: non-last data of multi-block record */
|
|
#define L2RLAST 0xA0 /* rsp: last data of multi-block record */
|
|
#define L2RCONT 0x90 /* rsp: write more of multi-block record */
|
|
|
|
/* Level-3 PDU Ids */
|
|
#define L3MORE 0x48 /* non-last of multi-block */
|
|
#define L3LAST 0x49 /* last of multi-block or single */
|
|
#define L3IDENT 0x4A /* identification */
|
|
|
|
/* Level-4 PDU definitions */
|
|
|
|
#define pdulenof(type,first,last) \
|
|
( offsetof(type,last) + sizeof(((type*)0)->last) \
|
|
- offsetof(type,first) )
|
|
|
|
struct hdr {
|
|
uchar id; /* id */
|
|
uchar len[2]; /* ll ll */
|
|
};
|
|
union recid {
|
|
uchar recid[4]; /* re_cd_id fi IC35 record-ID */
|
|
struct {
|
|
uchar rec[3]; /* re_cd_id record-id part */
|
|
uchar file[1]; /* fi file-id part */
|
|
} id;
|
|
};
|
|
|
|
struct cmdident {
|
|
struct hdr l1head; /* 02 ll ll */
|
|
struct hdr l2head; /* 80 ll ll */
|
|
uchar magic[4]; /* 10 00 64 00 */
|
|
struct hdr l3head; /* 4A ll ll */
|
|
char text[28]; /* "INVENTEC CORPORATION PRODUCT" */
|
|
};
|
|
#define LCMDident pdulenof(struct cmdident, magic, text)
|
|
struct rspident {
|
|
struct hdr l1head; /* F2 ll ll */
|
|
struct hdr l2head; /* A0 ll ll */
|
|
uchar magic[4]; /* 10 00 D0 07 */
|
|
struct hdr l3head; /* 4A ll ll */
|
|
char text[31]; /* "INVENTEC CORPORATION DCS15 1.28" */
|
|
};
|
|
|
|
struct cmdgetpower {
|
|
uchar cmd[2]; /* 03 01 */
|
|
char text[5]; /* "Power" */
|
|
uchar zero[3]; /* 00 00 00 */
|
|
};
|
|
#define LCMDgetpower pdulenof(struct cmdgetpower, cmd, zero)
|
|
struct rspgetpower {
|
|
uchar rsp[2]; /* 03 01 */
|
|
};
|
|
struct cmdpassword {
|
|
uchar cmd[2]; /* 03 00 */
|
|
char text[8]; /* [password] */
|
|
};
|
|
#define LCMDpassword pdulenof(struct cmdpassword, cmd, text)
|
|
struct rsppassword {
|
|
uchar rsp[2]; /* 01 01 */
|
|
};
|
|
struct cmdcategory {
|
|
uchar cmd[2]; /* 03 02 */
|
|
char name[8]; /* [category] */
|
|
};
|
|
#define LCMDcategory pdulenof(struct cmdcategory, cmd, name)
|
|
struct rspcategory {
|
|
uchar rsp[2]; /* 00 01 */
|
|
};
|
|
struct cmdgetdtime {
|
|
uchar cmd[2]; /* 02 00 */
|
|
uchar zero[1]; /* 00 */
|
|
};
|
|
#define LCMDgetdtime pdulenof(struct cmdgetdtime, cmd, zero)
|
|
struct rspgetdtime {
|
|
uchar mdyhms[14]; /* [mmddyyyyhhmmss] */
|
|
uchar zero[2]; /* 00 00 */
|
|
};
|
|
struct cmdsetdtime {
|
|
uchar cmd[2]; /* 02 01 */
|
|
uchar zero1[1]; /* 00 */
|
|
char mdyhms[14]; /* [mmddyyyyhhmmss] */
|
|
uchar zero2[2]; /* 00 00 */
|
|
};
|
|
#define LCMDsetdtime pdulenof(struct cmdsetdtime, cmd, zero2)
|
|
/* rspsetdtime is done only */
|
|
|
|
struct cmdfopen {
|
|
uchar cmd[2]; /* 00 02 */
|
|
uchar zero[7]; /* 00 00 00 00 00 00 00 */
|
|
uchar lf2[4]; /* length+2 (dword) */
|
|
uchar lf[1]; /* length of filename */
|
|
uchar fname[10+1]; /* [filename] 02 */
|
|
};
|
|
#define LCMDfopen (pdulenof(struct cmdfopen, cmd, lf) + 1) /* dynamic */
|
|
struct rspfopen {
|
|
uchar fd[2]; /* fd __ */
|
|
};
|
|
struct cmdfclose {
|
|
uchar cmd[2]; /* 00 03 */
|
|
uchar fd[2]; /* fd __ */
|
|
uchar zero[4]; /* 00 00 00 00 */
|
|
};
|
|
#define LCMDfclose pdulenof(struct cmdfclose, cmd, zero)
|
|
/* rspfclose is done only */
|
|
|
|
struct cmdfgetlen {
|
|
uchar cmd[2]; /* 01 03 (or 01 04) */
|
|
uchar fd[2]; /* fd __ */
|
|
uchar zero[4]; /* 00 00 00 00 */
|
|
};
|
|
#define LCMDfgetlen pdulenof(struct cmdfgetlen, cmd, zero)
|
|
struct rspfgetlen {
|
|
uchar n[2]; /* n_ __ */
|
|
};
|
|
struct cmdfgetrec {
|
|
uchar cmd[2]; /* 01 06 (or 01 07) */
|
|
uchar fd[2]; /* fd __ */
|
|
uchar index[2]; /* id x_ (not 01 07) */
|
|
uchar zero[2]; /* 00 00 00 00 */
|
|
};
|
|
#define LCMDfgetrec pdulenof(struct cmdfgetrec, cmd, zero)
|
|
struct cmdfgetirec {
|
|
uchar cmd[2]; /* 01 05 */
|
|
uchar fd[2]; /* fd __ */
|
|
union recid uid; /* re c- id fi IC35 record-ID */
|
|
};
|
|
#define LCMDfgetirec pdulenof(struct cmdfgetirec, cmd, uid)
|
|
struct rspfgetrec {
|
|
union recid uid; /* re c. id fi IC35 record-ID */
|
|
uchar fx[1]; /* fx change-flag on IC35 ? */
|
|
uchar data[1]; /* flens,fdata.. (variable len) */
|
|
};
|
|
struct cmdfputrec { /* putrec or updrec */
|
|
uchar cmd[2]; /* 01 08 01 09 */
|
|
uchar fd[2]; /* fd __ */
|
|
union recid uid; /* 00 00 00 00 or re c- id fi */
|
|
uchar magic[3]; /* m1 m2 m3 */
|
|
uchar zero2[2]; /* 00 00 */
|
|
uchar lr[4]; /* length of record (dword) */
|
|
uchar data[1]; /* flens,fdata.. (variable len) */
|
|
};
|
|
#define LCMDfputrec pdulenof(struct cmdfputrec, cmd, lr) /* dynamic */
|
|
struct rspfputrec {
|
|
union recid uid; /* re_cd_id fi IC35 record-ID */
|
|
};
|
|
struct cmdfclrchg { /* clrchg or delrec */
|
|
uchar cmd[2]; /* 01 08 01 02 */
|
|
uchar fd[2]; /* fd __ */
|
|
union recid uid; /* re c- id fi IC35 record-ID */
|
|
};
|
|
#define LCMDfclrchg pdulenof(struct cmdfclrchg, cmd, uid)
|
|
/* rspfclrchg is done only */
|
|
|
|
struct cmdpdu {
|
|
struct hdr l1head; /* 01,02,04,05 */
|
|
struct hdr l2head; /* 80,02,82,83,81 */
|
|
struct hdr l3head; /* 48,49 */
|
|
union {
|
|
uchar cmd[2];
|
|
struct cmdgetpower getpower;
|
|
struct cmdpassword password;
|
|
struct cmdcategory category;
|
|
struct cmdgetdtime getdtime;
|
|
struct cmdsetdtime setdtime;
|
|
struct cmdfopen fopen;
|
|
struct cmdfclose fclose;
|
|
struct cmdfgetlen fgetlen;
|
|
struct cmdfgetrec fgetrec;
|
|
struct cmdfgetirec fgetirec;
|
|
struct cmdfputrec fputrec;
|
|
struct cmdfclrchg fclrchg;
|
|
} u;
|
|
};
|
|
struct rsppdu {
|
|
struct hdr l1head; /* F0,F1,F2 */
|
|
struct hdr l2head; /* 20,A0,90 */
|
|
struct hdr l3head; /* 48,49 */
|
|
union {
|
|
uchar rsp[2];
|
|
struct rspgetpower getpower;
|
|
struct rsppassword password;
|
|
struct rspcategory category;
|
|
struct rspgetdtime getdtime;
|
|
/* rspsetdtime response done only */
|
|
struct rspfopen fopen;
|
|
/* rspfclose response done only */
|
|
struct rspfgetlen fgetlen;
|
|
struct rspfgetrec fgetrec;
|
|
struct rspfputrec fputrec;
|
|
/* rspfclrchg response done only */
|
|
} u;
|
|
};
|
|
|
|
|
|
/* ============================================ */
|
|
/* utilities for PDU encode/decode */
|
|
/* ============================================ */
|
|
|
|
/* encode data items to PDU
|
|
* ------------------------
|
|
* putbyte() etc. imported from genproto.c
|
|
*/
|
|
static int
|
|
puthdr( uchar * pduptr, uchar id, int len )
|
|
{
|
|
putbyte( pduptr+0, id );
|
|
putword( pduptr+1, (ushort)(len+3) );
|
|
return len+3;
|
|
}
|
|
static void
|
|
putcmd( uchar * pduptr, ushort cmd )
|
|
{
|
|
putbyte( pduptr+0, (cmd & 0xFF00) >> 8 ); /* MSB first .. */
|
|
putbyte( pduptr+1, cmd & 0x00FF ); /* LSB second (!) */
|
|
}
|
|
|
|
/* decode data items from PDU
|
|
* --------------------------
|
|
* getbyte() etc. imported from genproto.c
|
|
*/
|
|
static ushort
|
|
getrsp( uchar * pduptr )
|
|
{
|
|
return (getbyte( pduptr+0 ) << 8) | getbyte( pduptr+1 );
|
|
}
|
|
|
|
|
|
/* ==================================== */
|
|
/* Level-1 protocol */
|
|
/* ==================================== */
|
|
/*
|
|
* the Level-1 protocol transports a command to IC35 (->)
|
|
* and receives a response from IC35 (<-):
|
|
* L2sendcmd:
|
|
* use default timeout (0.5 sec)
|
|
* -> 01 03 00 init
|
|
* <- F0 ack0
|
|
* -> 02 ll ll <L2cmd> cc cc command to IC35
|
|
* set timeout 2.0 sec for ack1 response
|
|
* <- F1 ack1
|
|
* restore previous timeout (0.5 sec)
|
|
* L2recvrsp:
|
|
* -> 04 03 00 request response
|
|
* <- F2 ll ll <L2rsp> cc cc response from IC35
|
|
* -> 05 03 00 exit
|
|
* <- F1 ack1
|
|
* longer timeout 2.0 sec for ack1 response to command is needed
|
|
* e.g. for get_modflen. experiments showed ack1 response times
|
|
* of 0.7 .. 0.9 sec for ca. 860 address records.
|
|
*/
|
|
|
|
static uchar xbuff[4096]; /* PDU transmit buffer */
|
|
|
|
/* send Level-1 PDU
|
|
* ----------------
|
|
*/
|
|
static int
|
|
L1send( uchar id, uchar* pdu, size_t l2len )
|
|
{
|
|
size_t slen;
|
|
uchar * spdu;
|
|
uchar sbuff[3];
|
|
|
|
if ( pdu != NULL ) { /* long PDU with data and checksum */
|
|
slen = puthdr( spdu = pdu, id, l2len+2 );
|
|
putword( spdu+slen-2, chksum( spdu, slen-2 ) );
|
|
} else { /* short PDU without data,checksum */
|
|
slen = puthdr( spdu = sbuff, id, 0 );
|
|
}
|
|
return com_send( spdu, slen );
|
|
}
|
|
|
|
/* receive Level-1 PDU
|
|
* -------------------
|
|
* returns:
|
|
* <= 0 receive error: timeout, bad checksum of long PDU
|
|
* == 0 short PDU received, *p_id = PDU-Id
|
|
* > 0 long PDU received, *p_id = PDU-Id, *buff = PDU-data
|
|
*/
|
|
static int
|
|
L1recv( uchar* prid, uchar * pdu, size_t blen )
|
|
{
|
|
int rlen, pdulen;
|
|
|
|
if ( prid == NULL )
|
|
return ERR; /* semantic error */
|
|
*prid = '\0';
|
|
rlen = com_recv( prid, sizeof(*prid) );
|
|
if ( rlen < 1 )
|
|
return rlen; /* recv.ERR, timeout */
|
|
if ( *prid != L1DATA )
|
|
return OK; /* received ack0,ack1 */
|
|
|
|
if ( pdu == NULL ) {
|
|
/*??? flush receive data */
|
|
return ERR; /* semantic error */
|
|
}
|
|
pdu[0] = *prid;
|
|
rlen = com_recv( pdu+1, 2 );
|
|
if ( rlen < 2 )
|
|
return ERR; /* miss length field */
|
|
pdulen = getword( pdu+1 );
|
|
if ( pdulen <= 3 )
|
|
return ERR; /* too short data resp */
|
|
rlen = com_recv( pdu+3, min(pdulen,blen)-3 );
|
|
if ( rlen < pdulen - 3 )
|
|
return ERR; /* length mismatch */
|
|
if ( chksum( pdu, pdulen-2 ) != getword( pdu+pdulen-2 ) )
|
|
return ERR; /* checksum mismatch */
|
|
|
|
return pdulen - 3 - 2; /* length of L2data */
|
|
}
|
|
|
|
|
|
/* send command with Level-1 protocol
|
|
* ----------------------------------
|
|
*/
|
|
static int
|
|
L2sendcmd( uchar* pdu, size_t l2len )
|
|
{
|
|
uchar rid;
|
|
int old_tmo;
|
|
int rval;
|
|
|
|
rval = OK;
|
|
L1send( L1INIT, NULL, 0 ); /* -> 01 03 00 */
|
|
L1recv( &rid, NULL, 0 ); /* <- F0 */
|
|
if ( rid != L1ACK0 ) /* missing ack0 */
|
|
return ERR;
|
|
L1send( L1DSEL, pdu, l2len ); /* -> 02 ll ll <L2data> cc cc */
|
|
old_tmo = com_settimeout( 2000 ); /* timeout 2.0 sec for ack1resp */
|
|
L1recv( &rid, NULL, 0 ); /* <- F1 */
|
|
com_settimeout( old_tmo ); /* restore previous timeout */
|
|
if ( rid != L1ACK1 ) /* missing ack1 */
|
|
return ERR;
|
|
return rval;
|
|
}
|
|
|
|
/* receive response with Level-1 protocol
|
|
* --------------------------------------
|
|
*/
|
|
static int
|
|
L2recvrsp( uchar* rsp, size_t lrsp )
|
|
{
|
|
int rlen, rval;
|
|
uchar rid;
|
|
|
|
rval = ERR;
|
|
L1send( L1DREQ, NULL, 0 ); /* -> 04 03 00 */
|
|
rlen = L1recv( &rid, rsp, lrsp ); /* <- F2 ll ll <L2data> cc cc */
|
|
if ( rid == L1DATA )
|
|
rval = rlen; /* return length of L2data */
|
|
L1send( L1EXIT, NULL, 0 ); /* -> 05 03 00 */
|
|
L1recv( &rid, NULL, 0 ); /* <- F1 */
|
|
/*??? ignore if missing ack1 to exit */
|
|
return rval;
|
|
}
|
|
|
|
|
|
/* ==================================== */
|
|
/* Level-4 commands,responses */
|
|
/* ==================================== */
|
|
|
|
/* encode command and send it
|
|
* --------------------------
|
|
* depending on the command-id 'cmd' zero, one or more parameters
|
|
* are encoded.
|
|
*/
|
|
int
|
|
sendcmd( ushort cmd, ... )
|
|
{
|
|
va_list argp;
|
|
struct cmdpdu * pdu = (struct cmdpdu *)&xbuff[0];
|
|
size_t pdusize = sizeof(xbuff);
|
|
size_t pdulen;
|
|
uchar l2id, l3id;
|
|
|
|
memset( pdu, 0, pdusize );
|
|
putcmd( pdu->u.cmd, cmd );
|
|
va_start( argp, cmd );
|
|
switch ( cmd ) {
|
|
default:
|
|
return ERR; /* invalid 'cmd' */
|
|
case CMDident:
|
|
{ struct cmdident *idpdu = (struct cmdident *)pdu;
|
|
char * inventec = "INVENTEC CORPORATION PRODUCT";
|
|
putbtxt( idpdu->magic, "\x10\x00\x64\x00", sizeof(idpdu->magic) );
|
|
puttext( idpdu->text, inventec );
|
|
puthdr( (uchar*)&idpdu->l3head, L3IDENT, strlen(inventec) );
|
|
pdulen = LCMDident;
|
|
l2id = L2INIT; l3id = 0;
|
|
} break;
|
|
case CMDdisconn:
|
|
pdulen = 0;
|
|
l2id = L2EXIT; l3id = 0;
|
|
break;
|
|
case CMDgetpower:
|
|
puttext( pdu->u.getpower.text, "Power" );
|
|
pdulen = LCMDgetpower;
|
|
l2id = L2WLAST; l3id = L3LAST;
|
|
break;
|
|
case CMDpassword:
|
|
puttext( pdu->u.password.text, va_arg( argp, char* ) );
|
|
pdulen = LCMDpassword;
|
|
l2id = L2WLAST; l3id = L3LAST;
|
|
break;
|
|
case CMDcategory:
|
|
puttext( pdu->u.category.name, va_arg( argp, char* ) );
|
|
pdulen = LCMDcategory;
|
|
l2id = L2WLAST; l3id = L3LAST;
|
|
break;
|
|
case CMDgetdtime:
|
|
pdulen = LCMDgetdtime;
|
|
l2id = L2READ; l3id = L3LAST;
|
|
break;
|
|
case CMDsetdtime:
|
|
puttext( pdu->u.setdtime.mdyhms, va_arg( argp, char* ) );
|
|
pdulen = LCMDsetdtime;
|
|
l2id = L2WLAST; l3id = L3LAST;
|
|
break;
|
|
case CMDfopen:
|
|
{ char * strarg = va_arg( argp, char* );
|
|
putdword( pdu->u.fopen.lf2, (ulong)(strlen(strarg) + 2) );
|
|
putbyte( pdu->u.fopen.lf, (uchar)strlen(strarg) );
|
|
puttext( pdu->u.fopen.fname, strarg );
|
|
putbyte( pdu->u.fopen.fname+strlen(strarg), '\x02' );
|
|
pdulen = LCMDfopen + strlen(strarg);
|
|
l2id = L2WLAST; l3id = L3LAST;
|
|
} break;
|
|
case CMDfclose:
|
|
putword( pdu->u.fclose.fd, (ushort)va_arg( argp, int ) );
|
|
pdulen = LCMDfclose;
|
|
l2id = L2WLAST; l3id = L3LAST;
|
|
break;
|
|
case CMDfgetlen:
|
|
case CMDfgetmlen:
|
|
putword( pdu->u.fgetlen.fd, (ushort)va_arg( argp, int ) );
|
|
pdulen = LCMDfgetlen;
|
|
l2id = L2READ; l3id = L3LAST;
|
|
break;
|
|
case CMDfgetirec:
|
|
putword( pdu->u.fgetirec.fd, (ushort)va_arg( argp, int ) );
|
|
putdword( pdu->u.fgetirec.uid.recid, va_arg( argp, ulong ) );
|
|
pdulen = LCMDfgetirec;
|
|
l2id = L2READ; l3id = L3LAST;
|
|
break;
|
|
case CMDfgetrec:
|
|
putword( pdu->u.fgetrec.fd, (ushort)va_arg( argp, int ) );
|
|
putword( pdu->u.fgetrec.index, (ushort)va_arg( argp, int ) );
|
|
pdulen = LCMDfgetrec;
|
|
l2id = L2READ; l3id = L3LAST;
|
|
break;
|
|
case CMDfgetmrec:
|
|
putword( pdu->u.fgetrec.fd, (ushort)va_arg( argp, int ) );
|
|
pdulen = LCMDfgetrec;
|
|
l2id = L2READ; l3id = L3LAST;
|
|
break;
|
|
case CMDfgetmore:
|
|
pdulen = 0;
|
|
l2id = L2READ; l3id = 0;
|
|
break;
|
|
case CMDfputrec:
|
|
case CMDfupdrec:
|
|
{ bool last = va_arg( argp, bool );
|
|
uchar * bstrarg;
|
|
size_t bstrlen;
|
|
putword( pdu->u.fputrec.fd, (ushort)va_arg( argp, int ) );
|
|
putdword( pdu->u.fputrec.uid.recid, va_arg( argp, ulong ) );
|
|
putbtxt( pdu->u.fputrec.magic, va_arg( argp, uchar* ),
|
|
sizeof(pdu->u.fputrec.magic) );
|
|
putdword( pdu->u.fputrec.lr, va_arg( argp, size_t ) );
|
|
bstrarg = va_arg( argp, uchar* );
|
|
bstrlen = va_arg( argp, size_t );
|
|
putbtxt( pdu->u.fputrec.data, bstrarg, bstrlen );
|
|
pdulen = LCMDfputrec + bstrlen;
|
|
if ( ! last )
|
|
l2id = L2WMORE, l3id = L3MORE;
|
|
else
|
|
l2id = L2WLAST, l3id = L3LAST;
|
|
} break;
|
|
case CMDfputmore:
|
|
{ bool last = va_arg( argp, bool );
|
|
uchar * bstrarg = va_arg( argp, uchar* );
|
|
size_t bstrlen = va_arg( argp, size_t );
|
|
putbtxt( pdu->u.cmd, bstrarg, bstrlen );
|
|
pdulen = bstrlen;
|
|
if ( ! last )
|
|
l2id = L2WMORE, l3id = L3MORE;
|
|
else
|
|
l2id = L2WLAST, l3id = L3LAST;
|
|
} break;
|
|
case CMDfdelrec:
|
|
case CMDfclrchg:
|
|
putword( pdu->u.fclrchg.fd, (ushort)va_arg( argp, int ) );
|
|
putdword( pdu->u.fclrchg.uid.recid, va_arg( argp, ulong ) );
|
|
pdulen = LCMDfclrchg;
|
|
l2id = L2WLAST; l3id = L3LAST;
|
|
break;
|
|
}
|
|
va_end( argp );
|
|
if ( l3id )
|
|
pdulen = puthdr( (uchar*)&pdu->l3head, l3id, pdulen );
|
|
pdulen = puthdr( (uchar*)&pdu->l2head, l2id, pdulen );
|
|
return L2sendcmd( (uchar*)pdu, pdulen );
|
|
}
|
|
|
|
/* receive response and decode it
|
|
* ------------------------------
|
|
* ??? check received l2id,l3id match with cmd acc.to protocol
|
|
*/
|
|
int
|
|
recvrsp( ushort cmd, ... )
|
|
{
|
|
va_list argp;
|
|
uchar l2id, l3id;
|
|
ushort rsp;
|
|
int pdulen;
|
|
size_t pdusize = sizeof(xbuff);
|
|
struct rsppdu * pdu = (struct rsppdu *)&xbuff[0];
|
|
|
|
va_start( argp, cmd );
|
|
memset( pdu, 0, pdusize );
|
|
if ( (pdulen = L2recvrsp( (uchar*)pdu, pdusize )) < 0 )
|
|
return pdulen;
|
|
l2id = getbyte( (uchar*)&pdu->l2head );
|
|
l3id = 0x00;
|
|
if ( pdulen >= sizeof(pdu->l2head) ) {
|
|
pdulen -= sizeof(pdu->l2head);
|
|
l3id = getbyte( (uchar*)&pdu->l3head );
|
|
if ( pdulen >= sizeof(pdu->l3head) )
|
|
pdulen -= sizeof(pdu->l3head);
|
|
}
|
|
rsp = getrsp( pdu->u.rsp );
|
|
switch ( cmd ) {
|
|
default:
|
|
return ERR; /* invalid 'cmd' */
|
|
case CMDident:
|
|
{ struct rspident *idpdu = (struct rspident *)pdu;
|
|
char * ptext = va_arg( argp, char* );
|
|
size_t lptext = va_arg( argp, size_t );
|
|
pdulen -= sizeof(idpdu->magic);
|
|
gettext( idpdu->text, ptext, min(pdulen, lptext) );
|
|
} break;
|
|
case CMDdisconn:
|
|
break;
|
|
case CMDgetpower:
|
|
{ ushort * pstate = va_arg( argp, ushort* );
|
|
*pstate = rsp;
|
|
} break;
|
|
case CMDpassword:
|
|
{ ushort * pstate = va_arg( argp, ushort* );
|
|
*pstate = rsp;
|
|
} break;
|
|
case CMDgetdtime:
|
|
{ char * pdtime = va_arg( argp, char* );
|
|
size_t lpdtime = va_arg( argp, size_t );
|
|
gettext( pdu->u.getdtime.mdyhms, pdtime,
|
|
min(sizeof(pdu->u.getdtime.mdyhms), lpdtime) );
|
|
} break;
|
|
case CMDsetdtime:
|
|
break;
|
|
case CMDcategory:
|
|
{ ushort * pstate = va_arg( argp, ushort* );
|
|
*pstate = rsp;
|
|
} break;
|
|
case CMDfopen:
|
|
{ ushort * pfd = va_arg( argp, ushort* );
|
|
*pfd = getword( pdu->u.fopen.fd );
|
|
} break;
|
|
case CMDfclose:
|
|
break;
|
|
case CMDfgetlen:
|
|
case CMDfgetmlen:
|
|
{ ushort * pflen = va_arg( argp, ushort* );
|
|
*pflen = getword( pdu->u.fgetlen.n );
|
|
} break;
|
|
case CMDfgetrec:
|
|
{ bool * plast = va_arg( argp, bool* );
|
|
ulong * prid = va_arg( argp, ulong* );
|
|
uchar * pchg = va_arg( argp, uchar* );
|
|
uchar * buff = va_arg( argp, uchar* );
|
|
size_t blen = va_arg( argp, size_t );
|
|
*plast = (bool)( l2id == L2RLAST );
|
|
*prid = getdword( pdu->u.fgetrec.uid.recid );
|
|
*pchg = getbyte( pdu->u.fgetrec.fx );
|
|
memcpy( buff, pdu->u.fgetrec.data, min(blen,pdulen) );
|
|
pdulen -= offsetof(struct rspfgetrec, data); /* length of record data */
|
|
} break;
|
|
case CMDfgetmore:
|
|
{ bool * plast = va_arg( argp, bool* );
|
|
uchar * buff = va_arg( argp, uchar* );
|
|
size_t blen = va_arg( argp, size_t );
|
|
*plast = (bool)( l2id == L2RLAST );
|
|
memcpy( buff, pdu->u.rsp, min(blen,pdulen) );
|
|
} break;
|
|
case CMDfputrec:
|
|
if ( l2id == L2RLAST && l3id == L3LAST ) {
|
|
ulong * prid = va_arg( argp, ulong* );
|
|
*prid = getdword( pdu->u.fputrec.uid.recid );
|
|
}
|
|
break;
|
|
case CMDfdelrec:
|
|
case CMDfclrchg:
|
|
break;
|
|
}
|
|
return pdulen;
|
|
}
|