Device-LaCrosse-WS23xx
view release on metacpan or search on metacpan
if (read_device(fh, readdata, byte_count+1) != byte_count+1) {
#ifdef DEBUG
fprintf(stderr,"read_data:read_device(3)\n");
#endif
return -1;
}
if (readdata[byte_count] != data_checksum(readdata, byte_count)) {
#ifdef DEBUG
fprintf(stderr,"read_data:data_checksum(1)\n");
#endif
return -1;
}
// Success
return byte_count;
}
int
read_safe(int fh, ushort address, ushort byte_count, uchar *buf)
{
int i;
for (i=0; i < 10; i++) {
// If we get the expected number of bytes, we're done.
if (read_data(fh, address, byte_count, buf) == byte_count)
return 1;
// FIXME: warn? Reset?
// _ws_reset(fh);
trace("**",0,0," read_data failed");
tcflush(fh, TCIOFLUSH);
}
return 0;
}
MODULE = Device::LaCrosse::WS23xx PACKAGE = Device::LaCrosse::WS23xx
void
_ws_trace_path(path)
char * path
CODE:
trace_path = malloc(strlen(path));
if (trace_path == 0)
croak("malloc failed");
strcpy(trace_path,path);
int
_ws_open(path)
char * path
INIT:
int fh;
struct termios adtio;
int portstatus, fdflags;
PPCODE:
//Setup serial port
if ((fh = open(path, O_RDWR | O_NONBLOCK | O_SYNC)) < 0)
{
// fprintf(stderr,"\nUnable to open serial device %s\n", path);
XSRETURN_UNDEF;
}
if ( flock(fh, LOCK_EX|LOCK_NB) < 0 ) {
fprintf(stderr,"Serial device is locked by other program\n");
close(fh);
XSRETURN_UNDEF;
}
if ((fdflags = fcntl(fh, F_GETFL)) == -1 ||
fcntl(fh, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
{
perror("couldn't reset non-blocking mode");
exit(EXIT_FAILURE);
}
tcgetattr(fh, &adtio);
// Serial control options
adtio.c_cflag &= ~PARENB; // No parity
adtio.c_cflag &= ~CSTOPB; // One stop bit
adtio.c_cflag &= ~CSIZE; // Character size mask
adtio.c_cflag |= CS8; // Character size 8 bits
adtio.c_cflag |= CREAD; // Enable Receiver
adtio.c_cflag &= ~HUPCL; // No "hangup"
adtio.c_cflag &= ~CRTSCTS; // No flowcontrol
adtio.c_cflag |= CLOCAL; // Ignore modem control lines
// Baudrate, for newer systems
cfsetispeed(&adtio, B2400);
cfsetospeed(&adtio, B2400);
// Serial local options: adtio.c_lflag
// Raw input = clear ICANON, ECHO, ECHOE, and ISIG
// Disable misc other local features = clear FLUSHO, NOFLSH, TOSTOP, PENDIN, and IEXTEN
// So we actually clear all flags in adtio.c_lflag
adtio.c_lflag = 0;
// Serial input options: adtio.c_iflag
// Disable parity check = clear INPCK, PARMRK, and ISTRIP
// Disable software flow control = clear IXON, IXOFF, and IXANY
// Disable any translation of CR and LF = clear INLCR, IGNCR, and ICRNL
// Ignore break condition on input = set IGNBRK
// Ignore parity errors just in case = set IGNPAR;
// So we can clear all flags except IGNBRK and IGNPAR
adtio.c_iflag = IGNBRK|IGNPAR;
// Serial output options
// Raw output should disable all other output options
adtio.c_oflag &= ~OPOST;
adtio.c_cc[VTIME] = 10; // timer 1s
adtio.c_cc[VMIN] = 0; // blocking read until 1 char
if (tcsetattr(fh, TCSANOW, &adtio) < 0)
{
// fprintf(stderr,"Unable to initialize serial device");
XSRETURN_UNDEF;
}
tcflush(fh, TCIOFLUSH);
// Set DTR low and RTS high and leave other ctrl lines untouched
ioctl(fh, TIOCMGET, &portstatus); // get current port status
portstatus &= ~TIOCM_DTR;
portstatus |= TIOCM_RTS;
ioctl(fh, TIOCMSET, &portstatus); // set current port status
// Reset the device, just once
_ws_reset(fh);
// Return the filehandle as a perl scalar
XPUSHs(sv_2mortal(newSVnv(fh)));
int
_ws_close(fh)
int fh
CODE:
flock(fh, LOCK_UN);
RETVAL = close(fh);
void
_ws_read(fh, addr, nybble_count)
int fh
unsigned short addr
unsigned char nybble_count
PREINIT:
uchar buf[40];
PPCODE:
#if DEBUG
printf("got here: fh=%d addr=%04X nybbles=%d\n",fh,addr,nybble_count);
#endif
if (read_safe(fh, addr, (nybble_count+1)/2, buf)) {
int i;
for (i=0; i < nybble_count; i += 2) {
XPUSHs(sv_2mortal(newSVnv(buf[i/2] & 0x0F)));
if (i < nybble_count-1)
XPUSHs(sv_2mortal(newSVnv(buf[i/2] >> 4)));
}
}
else {
croak("read_safe failed");
}
( run in 0.728 second using v1.01-cache-2.11-cpan-5511b514fd6 )