Rev 234 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/***************************************************************************
* Copyright (C) 2007 to 2009 by Andreas Theofilu *
* andreas@theosys.at *
* *
* 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 version 3 of the License. *
* *
* 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "gant.h"
#include <sys/select.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdlib.h>
#include <assert.h>
#include <kmessagebox.h>
#include <klocale.h>
static char G50_KEY[] = "A8A423B9F55E63C1"; // garmin network key
static char sendack1[] = "4402320499990000";
// 44 message from pc?
// ..02 message type
// ....32 don't know
// ......04 don't know
// ........9999 my id
// ............0000 maybe id is 4 bytes
static char sendack2[] = "4404010099990000";
// ..04 message type
// ....01 don't know
// ......00 don't know
static char sendack3[] = "4406010000000000";
// ..06 message type
// ....01 don't know
static char sendack4[] = "4403000000000000";
// ..03 message type, go to idle
// ....01 don't know
ant::ant ()
{
qFile = false;
commenabled = 1;
rfn = cfn = 0;
}
ant::~ant ()
{
if (qFile)
device.close ();
qFile = false;
rfn = cfn = 0;
}
/*
* Set the device and store it inside the class
*/
bool ant::setDevice (const QFile &fl)
{
if (qFile)
{
device.close();
qFile = false;
}
device.setName (fl.name ());
if (!device.exists ())
{
KMessageBox::error (0, i18n("Device %1 does not exist!").arg(fl.name()));
return false;
}
if (!device.open (IO_Raw | IO_ReadWrite))
{
KMessageBox::error (0, i18n("Error opening device %1.").arg(fl.name()),
device.errorString());
return false;
}
qFile = true;
return true;
}
bool ant::setDevice (const QString &fl)
{
QFile f;
if (qFile)
{
device.close ();
qFile = false;
}
f.setName (fl);
return setDevice (f);
}
/*
* Send a message to the opened device.
*/
bool ant::msg_send(uchar mesg, uchar *inbuf, uchar len)
{
uchar buf[MAXMSG];
ssize_t nw;
int i;
uchar chk = MESG_TX_SYNC;
buf[0] = MESG_TX_SYNC;
buf[1] = len;
chk ^= len;
buf[2] = mesg;
chk ^= mesg;
for (i = 0; i < len; i++)
{
buf[3+i] = inbuf[i];
chk ^= inbuf[i];
}
buf[3+i] = chk;
usleep (10 * 1000);
if ((4 + i) != (nw = write(device.handle(), buf, 4 + i)))
{
KMessageBox::error (0, i18n("Error writing to device %1").arg(device.name()));
return false;
}
return true;
}
// two argument send
bool ant::msg_send(uchar mesg, uchar data1, uchar data2)
{
uchar buf[2];
buf[0] = data1;
buf[1] = data2;
return msg_send(mesg, buf, 2);
}
// three argument send
bool ant::msg_send(uchar mesg, uchar data1, uchar data2, uchar data3)
{
uchar buf[3];
buf[0] = data1;
buf[1] = data2;
buf[2] = data3;
return msg_send(mesg, buf, 3);
}
bool ant::commfn ()
{
fd_set readfds, writefds, exceptfds;
int ready, fd;
struct timeval to;
fd = device.handle ();
for(;;)
{
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(fd, &readfds);
to.tv_sec = 1;
to.tv_usec = 0;
ready = select(fd+1, &readfds, &writefds, &exceptfds, &to);
if (ready)
{
if (!get_data(fd))
return false;
}
}
return true;
}
bool ant::get_data(int fd)
{
static uchar buf[500];
static int bufc = 0;
int nr;
int dlen;
int i;
int j;
unsigned char chk = 0;
uchar event;
int found;
int srch;
int next;
nr = read(fd, buf+bufc, 20);
if (nr > 0)
bufc += nr;
else
return true;
if (bufc > 300)
{
KMessageBox::error (0, i18n(">>buf<< too long!"));
return false;
}
// some data in buf
// search for possible valid messages
srch = 0;
while (srch < bufc)
{
found = 0;
for (i = srch; i < bufc; i++)
{
if (buf[i] == MESG_TX_SYNC)
{
if (i+1 < bufc && buf[i+1] >= 1 && buf[i+1] <= 13)
{
dlen = buf[i+1];
if ((i + 3 + dlen) < bufc)
{
chk = 0;
for (j = i; j <= i+3+dlen; j++)
chk ^= buf[j];
if (0 == chk)
{
found = 1; // got a valid message
break;
}
else
fprintf (stderr, "bad chk %02x\n", chk);
}
}
}
}
if (found)
{
next = j;
// got a valid message, see if any data needs to be discarded
event = 0;
switch (buf[i+2])
{
case MESG_RESPONSE_EVENT_ID:
if (rfn)
{
memcpy(rbufp, buf+i+3, dlen);
if (!(this->*rfn)(buf[i+3], buf[i+5]))
return false;
}
break;
case MESG_BROADCAST_DATA_ID:
event = EVENT_RX_BROADCAST;
break;
case MESG_ACKNOWLEDGED_DATA_ID:
event = EVENT_RX_ACKNOWLEDGED;
break;
case MESG_BURST_DATA_ID:
event = EVENT_RX_BURST_PACKET;
break;
case MESG_EXT_BROADCAST_DATA_ID:
event = EVENT_RX_EXT_BROADCAST;
break;
case MESG_EXT_ACKNOWLEDGED_DATA_ID:
event = EVENT_RX_EXT_ACKNOWLEDGED;
break;
case MESG_EXT_BURST_DATA_ID:
event = EVENT_RX_EXT_BURST_PACKET;
break;
default:
if (rfn)
{
// should be this according to the docs, but doesn't fit
if (dlen > MESG_DATA_SIZE)
{
KMessageBox::error(0, i18n("rresponse buffer too small!"));
return false;
}
memcpy(rbufp, buf+i+3, dlen);
if (!(this->*rfn)(buf[i+3], buf[i+2]))
return false;
}
}
if (event)
{
if (cfn)
{
if (dlen > MESG_DATA_SIZE)
{
KMessageBox::error(0, i18n("cresponse buffer too small!"));
return false;
}
memcpy(cbufp, buf+i+4, dlen);
if (!(this->*cfn)(buf[i+3], event))
return false;
}
}
srch = next;
}
else
break;
}
if (next < bufc)
{
memmove(buf, buf+next, bufc-next);
bufc -= next;
}
else
bufc = 0;
}
bool ant::ANT_ResetSystem()
{
uchar filler = 0;
return msg_send(MESG_SYSTEM_RESET_ID, &filler, 1);
}
bool ant::ANT_Cmd55(uchar chan)
{
return msg_send(0x55, &chan, 1);
}
bool ant::ANT_OpenRxScanMode (uchar chan)
{
return msg_send(MESG_OPEN_RX_SCAN_ID, &chan, 1);
}
bool ant::ANT_Init ()
{
//char dev[40];
struct termios tp;
if (!qFile)
return false;
if (tcgetattr(device.handle(), &tp) < 0)
{
KMessageBox::error(0, i18n("Error getting terminal attributes!"));
return false;
}
tp.c_iflag &=
~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|INPCK|IUCLC);
tp.c_oflag &= ~OPOST;
tp.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN|ECHOE);
tp.c_cflag &= ~(CSIZE|PARENB);
tp.c_cflag |= CS8 | CLOCAL | CREAD | CRTSCTS;
if (cfsetispeed(&tp, B115200) < 0)
{
KMessageBox::error(0, i18n("Error setting input speed of line terminal!"));
return false;
}
if (cfsetospeed(&tp, B115200) < 0)
{
KMessageBox::error(0, i18n("Error setting output speed of line terminal!"));
return false;
}
tp.c_cc[VMIN] = 1;
tp.c_cc[VTIME] = 0;
if (tcsetattr(device.handle (), TCSANOW, &tp) < 0)
{
KMessageBox::error(0, i18n("Error setting terminal attributes!"));
return false;
}
// return commfn ();
return true;
}
bool ant::ANT_RequestMessage (uchar chan, uchar mesg)
{
return msg_send(MESG_REQUEST_ID, chan, mesg);
}
bool ant::ANT_SetNetworkKeya (uchar net, uchar *key)
{
uchar buf[9];
int i;
if (strlen((char *)key) != 16)
{
fprintf(stderr, "Bad key length %s\n", key);
return 0;
}
buf[0] = net;
for (i = 0; i < 8; i++)
buf[1+i] = hexval(key[i*2])*16+hexval(key[i*2+1]);
return msg_send(MESG_NETWORK_KEY_ID, buf, 9);
}
bool ant::ANT_SetNetworkKey (uchar net, uchar *key)
{
uchar buf[9];
//int i;
buf[0] = net;
memcpy(buf+1, key, 8);
return msg_send(MESG_NETWORK_KEY_ID, buf, 9);
}
bool ant::ANT_AssignChannel (uchar chan, uchar chtype, uchar net)
{
return msg_send(MESG_ASSIGN_CHANNEL_ID, chan, chtype, net);
}
bool ant::ANT_UnAssignChannel (uchar chan)
{
return msg_send(MESG_UNASSIGN_CHANNEL_ID, &chan, 1);
}
bool ant::ANT_SetChannelId (uchar chan, ushort dev, uchar devtype, uchar manid)
{
uchar buf[5];
buf[0] = chan;
buf[1] = dev%256;
buf[2] = dev/256;
buf[3] = devtype;
buf[4] = manid;
return msg_send(MESG_CHANNEL_ID_ID, buf, 5);
}
bool ant::ANT_SetChannelRFFreq (uchar chan, uchar freq)
{
return msg_send(MESG_CHANNEL_RADIO_FREQ_ID, chan, freq);
}
bool ant::ANT_SetChannelPeriod (uchar chan, ushort period)
{
uchar buf[3];
buf[0] = chan;
buf[1] = period%256;
buf[2] = period/256;
return msg_send(MESG_CHANNEL_MESG_PERIOD_ID, buf, 3);
}
bool ant::ANT_SetChannelSearchTimeout (uchar chan, uchar timeout)
{
return msg_send(MESG_CHANNEL_SEARCH_TIMEOUT_ID, chan, timeout);
}
bool ant::ANT_SetSearchWaveform (uchar chan, ushort waveform)
{
uchar buf[3];
buf[0] = chan;
buf[1] = waveform % 256;
buf[2] = waveform / 256;
return msg_send(MESG_SEARCH_WAVEFORM_ID, buf, 3);
}
bool ant::ANT_SendAcknowledgedDataA (uchar chan, uchar *data) // ascii version
{
uchar buf[9];
int i;
if (strlen((char *)data) != 16)
{
fprintf(stderr, "Bad data length %s\n", data);
return false;
}
buf[0] = chan;
for (i = 0; i < 8; i++)
buf[1+i] = hexval (data[i*2]) * 16 + hexval(data[i*2+1]);
return msg_send(MESG_ACKNOWLEDGED_DATA_ID, buf, 9);
}
bool ant::ANT_SendAcknowledgedData (uchar chan, uchar *data)
{
uchar buf[9];
//int i;
buf[0] = chan;
memcpy(buf+1, data, 8);
return msg_send(MESG_ACKNOWLEDGED_DATA_ID, buf, 9);
}
unsigned short ant::ANT_SendBurstTransferA(uchar chan, uchar *data, unsigned short numpkts)
{
uchar buf[9];
int i;
int j;
int seq = 0;
fprintf(stderr, "numpkts %d data %s\n", numpkts, data);
if (strlen((char *)data) != (16 * numpkts))
{
fprintf(stderr, "Bad data length %s numpkts %d\n", data, numpkts);
return 0;
}
for (j = 0; j < numpkts; j++)
{
buf[0] = chan | (seq << 5) | ((j == (numpkts - 1)) ? 0x80 : 0);
for (i = 0; i < 8; i++)
buf[1+i] = hexval (data[j*16+i*2]) * 16 + hexval (data[j*16+i*2+1]);
usleep(20 * 1000);
msg_send(MESG_BURST_DATA_ID, buf, 9);
seq++;
if (seq > 3)
seq = 1;
}
return numpkts;
}
unsigned short ant::ANT_SendBurstTransfer (uchar chan, uchar *data, unsigned short numpkts)
{
uchar buf[9];
//int i;
int j;
int seq = 0;
for (j = 0; j < numpkts; j++)
{
buf[0] = chan | (seq << 5) | ((j == (numpkts - 1)) ? 0x80 : 0);
memcpy (buf+1, data+j*8, 8);
usleep (20*1000);
msg_send (MESG_BURST_DATA_ID, buf, 9);
seq++;
if (seq > 3)
seq = 1;
}
return numpkts;
}
bool ant::ANT_OpenChannel (uchar chan)
{
return msg_send(MESG_OPEN_CHANNEL_ID, &chan, 1);
}
bool ant::ANT_CloseChannel (uchar chan)
{
return msg_send(MESG_CLOSE_CHANNEL_ID, &chan, 1);
}
void ant::ANT_AssignResponseFunction (RESPONSE_FUNC rf, uchar* rbuf)
{
rfn = rf;
rbufp = rbuf;
}
void ant::ANT_AssignChannelEventFunction (uchar, CHANNEL_EVENT_FUNC rf, uchar* rbuf)
{
cfn = rf;
cbufp = rbuf;
}
int ant::ANT_fd()
{
return device.handle();
}
/*
* Following functions control the device and uses the class "ant".
* This is class "gant".
*/
gant::gant (const QString &af)
{
mydev = 0;
peerdev = 0;
myid = 0;
state = 0;
authfd = false;
faf.setName (af);
if (!faf.open (IO_Raw | IO_ReadWrite))
{
KMessageBox::error (0, i18n("Error opening device %1.").arg(af),
faf.errorString());
}
authfile = af;
authfd = true;
}
gant::~gant ()
{
if (authfd)
faf.close();
}
uint gant::randno ()
{
return (uint)random ();
}
bool gant::chevent (uchar chan, uchar event)
{
uchar seq;
uchar last;
uchar status = cbuf[1];
uchar phase = cbuf[2];
struct ack_msg ack;
struct auth_msg auth;
struct pair_msg pair;
uint id;
//int i;
//fprintf(stderr, "state %d\n", state);
/* if (dbg && event != EVENT_RX_BURST_PACKET) {
fprintf(stderr, "chan %d event %02x channel open: ", chan, event);
for (i = 0; i < 8; i++)
fprintf(stderr, "%02x", cbuf[i]);
fprintf(stderr, "\n");
}
*/
// transition between garmin phases handled via state machine
switch (event)
{
case EVENT_RX_BROADCAST:
memcpy((void *)&id, cbuf+4, 4);
if (state == 1 && (phase & 7) == 0)
{
// received broadcast from watch in phase 0
state++;
if ((status & 8) == 8)
{
// pairing
myid = randno();
fprintf(stderr, "pairing, generated id %08x\n", myid);
}
else
{
// garmin moved to phase 1 in response to sendack1
int nr;
// printf("reading auth data from %s\n", authfile);
authfd = open(authfile, O_RDONLY);
if (!authfd || faf.size () < 32)
{
KMessageBox::error(0, i18n("There is no authfile available or it has wrong size!"));
return false;
}
nr = read(faf.handle(), authdata, 32);
if (nr != 32)
{
KMessageBox::error(0, i18n ("Error reading auth file %1!").arg(authfile));
return false;
}
memcpy((void *)&myauth1, authdata+16, 4);
memcpy((void *)&myauth2, authdata+20, 4);
memcpy((void *)&mydev, authdata+12, 4);
memcpy((void *)&myid, authdata+4, 4);
}
if (status & 0x20)
fprintf(stderr, "watch contains NEW data\n");
ANT_RequestMessage(chan, MESG_CHANNEL_ID_ID); /* request sender id */
}
else if (state == 3 && phase == 1)
{
state++;
ack.code = 0x44;
ack.atype = 4;
ack.c1 = 0x01;
ack.c2 = 0x00;
ack.id = myid;
ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin to send id data
}
else if (state == 5 && phase == 1)
{
if ((status & 0x0f) == 4)
{
// received id/version or whatever
state++;
assert(sizeof auth == AUTHSIZE);
auth.code = 0x44;
auth.atype = 4;
auth.phase = 3;
auth.u1 = 8;
auth.id = myid;
auth.auth1 = myauth1;
auth.auth2 = myauth2;
auth.fill1 = auth.fill2 = 0;
ANT_SendBurstTransfer(chan, (uchar *)&auth, (sizeof auth)/8); // send our auth data
}
else if ((status & 0x0f) == 0x0c)
{
// pairing
assert(sizeof pair == PAIRSIZE);
state = 10;
pair.code = 0x44;
pair.atype = 4;
pair.phase = 2;
pair.u1 = 7;
pair.id = myid;
bzero(pair.devname, sizeof pair.devname);
if (peerdev <= 99999999) // only allow 8 digits
sprintf(pair.devname, "%d", peerdev);
else
fprintf(stderr, "pair dev name too large %08x \"%d\"\n", peerdev, peerdev);
// printf("sending pair data for dev %s\n", pair.devname);
ANT_SendBurstTransfer(chan, (uchar *)&pair, (sizeof pair)/8) ; // send pair data
}
else
{
fprintf(stderr, "error in gant.cpp on line %d\n", __LINE__);
return false;
}
}
else if (state == 6 && (status & 0x0f) == 4 && phase == 2)
{
// if our auth is ok, garmin has gone to phase 2
state++;
ack.code = 0x44;
ack.atype = 6;
ack.c1 = 0x01;
ack.c2 = 0x00;
ack.id = 0;
ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin to start upload
}
else if (state == 8 && phase == 2)
{
// upload finished. received broadcast that still in phase 2
state++;
ack.code = 0x44;
ack.atype = 3;
ack.c1 = 0x00;
ack.c2 = 0x00;
ack.id = 0;
ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin we're finished
}
else if (state == 9 && phase == 0)
{
// garmin replies it's back in phase 0
fprintf(stderr, "finished\n");
return true;
}
else if (state == 1 && phase != 0)
{
// don't know what phase we're in. let's try and reset
fprintf(stderr, "resetting\n");
ack.code = 0x44;
ack.atype = 3;
ack.c1 = 0x00;
ack.c2 = 0x00;
ack.id = 0;
ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell garmin we're finished
sleep(1);
return false;
}
else if (state == 20 && phase == 2)
{
// upload finished. tell garmin to delete logs
state++;
ack.code = 0x44;
ack.atype = 0x0b;
ack.c1 = 0x01;
ack.c2 = 0x00;
ack.id = 0;
ANT_SendAcknowledgedData(chan, (uchar *)&ack); // delete logs
}
else if (state == 21 && phase == 2)
{
state = 8;
}
break;
case EVENT_RX_BURST_PACKET:
seq = (chan & 0x60) >> 5;
last = (chan & 0x80) >> 7;
chan &= 0x1f;
if (state == 4)
{
static int once = 0;
// garmin sending authentication/identification data
if (!once)
once = 1;
memcpy(clientid[seq], cbuf, 8);
if (last)
{
state++;
memcpy(&peerdev, clientid[1]+4, 4);
if (mydev != 0 && peerdev != mydev)
{
fprintf(stderr, "Don't know this device %08x != %08x\n", peerdev, mydev);
return false;
}
}
}
else if (state == 7)
{
static int once = 0;
int nw;
// garmin uploading in response to sendack3
// in this state we're receiving the workout data
if (!once)
{
fprintf(stderr, "receiving\n");
once = 1;
}
nw = write(faf.handle(), cbuf, 8);
if (nw != 8)
{
KMessageBox::error(0, i18n ("Write to auth file %1 failed!").arg(authfile));
return false;
}
if (last)
{
state++; // just to exit
//state = 20; // to delete logs
}
}
else if (state == 10)
{
// receiving auth data
static int once = 0;
int nw;
if (!once)
{
// printf("storing auth data in %s\n", authfile);
once = 1;
// authfd = open(authfile, O_WRONLY|O_CREAT, 0644);
/* if (authfd < 0)
{
perror(authfile);
exit(1);
} */
}
nw = write(faf.handle(), cbuf, 8);
if (nw != 8)
{
KMessageBox::error(0, i18n ("Write to auth file %1 failed!").arg(authfile));
return false;
}
if (last)
{
//state = 6; // to download during pairing
state = 8; // to finish at end of pairing
}
}
else if (state == 6)
{
// response to authentication
static int once = 0;
// int i;
if (!once)
{
once = 1;
}
if (last)
{
if (cbuf[2] == 2)
{
fprintf(stderr, "authentication failed\n");
return false;
}
}
}
else
{
int i;
fprintf(stderr, "data in state %d: ", state);
for (i = 0; i < 8; i++)
fprintf(stderr, "%02x", cbuf[i]);
fprintf(stderr, "\n");
}
break;
}
return 1;
}
bool gant::revent (uchar chan, uchar event)
{
unsigned short devid;
struct ack_msg ack;
int i;
switch (event)
{
case EVENT_TRANSFER_TX_COMPLETED:
// ignore
// printf("Transfer complete %02x\n", ebuf[1]);
break;
case INVALID_MESSAGE:
fprintf(stderr, "Invalid message %02x\n", ebuf[1]);
break;
case RESPONSE_NO_ERROR:
switch (ebuf[1])
{
case MESG_ASSIGN_CHANNEL_ID:
ANT_AssignChannelEventFunction((uchar)chan, (CHANNEL_EVENT_FUNC)&gant::chevent, (uchar *)&cbuf);
break;
case MESG_OPEN_CHANNEL_ID:
state++;
fprintf(stderr, "channel open, waiting for broadcast\n", state);
break;
default:
// ignore
// printf("Message %02x NO_ERROR\n", ebuf[1]);
break;
}
break;
case MESG_CHANNEL_ID_ID:
devid = ebuf[1]+ebuf[2]*256;
if (mydev == 0 || devid == mydev%65536)
{
state++;
ack.code = 0x44; ack.atype = 2; ack.c1 = 0x32; ack.c2 = 0x04;
ack.id = myid;
ANT_SendAcknowledgedData(chan, (uchar *)&ack); // tell watch go to phase 1
}
else
{
fprintf(stderr, "Ignoring unknown device %08x, mydev %08x\n", devid, mydev);
}
break;
case MESG_NETWORK_KEY_ID:
case MESG_SEARCH_WAVEFORM_ID:
case MESG_OPEN_CHANNEL_ID:
fprintf(stderr, "response event %02x code %02x\n", event, ebuf[2]);
for (i = 0; i < 8; i++)
fprintf(stderr, "%02x", ebuf[i]);
fprintf(stderr, "\n");
break;
case MESG_CAPABILITIES_ID:
break;
case MESG_CHANNEL_STATUS_ID:
break;
default:
fprintf(stderr, "Unhandled response event %02x\n", event);
break;
}
return true;
}
bool gant::read_device ()
{
//int devnum = 0;
int chan = 0;
int net = 0;
int chtype = 0; // wildcard
int devno = 0; // wildcard
int devtype = 0; // wildcard
int manid = 0; // wildcard
int freq = 0x32; // garmin specific radio frequency
int period = 0x1000; // garmin specific broadcast period
int srchto = 255; // max timeout
int waveform = 0x0053; // aids search somehow
// Check if we already have a device set.
// if (!qFile)
// return false;
// TODO: Do this properly...
/* if (ac > 1) {
authfile = av[1];
}
else {
fprintf(stderr, "need auth file\n");
exit(1);
}
if (ac > 2)
fn = av[2]; // store the output filename for event function
if (ac > 3)
devnum = atoi(av[3]);
if (ac > 4)
myid = atoi(av[4]);
if (ac > 5)
mydev = atoi(av[5]);
*/
if (!ANT_Init())
return false;
if (!ANT_ResetSystem())
return false;
ANT_AssignResponseFunction((RESPONSE_FUNC)&gant::revent, (uchar *)&ebuf);
if (!ANT_RequestMessage(chan, MESG_CHANNEL_STATUS_ID)) //informative
return false;
if (!ANT_SetNetworkKeya(net, (uchar *)G50_KEY))
return false;
if (!ANT_AssignChannel(chan, chtype, net))
return false;
if (!ANT_SetChannelId(chan, devno, devtype, manid))
return false;
if (!ANT_RequestMessage(chan, MESG_CAPABILITIES_ID)) //informative
return false;
if (!ANT_SetChannelRFFreq(chan, freq))
return false;
if (!ANT_SetChannelPeriod(chan, period))
return false;
if (!ANT_SetChannelSearchTimeout(chan, srchto))
return false;
if (!ANT_SetSearchWaveform(chan, waveform))
return false;
if (!ANT_OpenChannel(chan)) // success for this bumps us to state 1
return false;
if (!ANT_RequestMessage(chan, MESG_CHANNEL_STATUS_ID)) //informative
return false;
// everything handled in event functions
// for(;;)
// sleep(10);
return commfn ();
}