549 lines
14 KiB
C
549 lines
14 KiB
C
/* vim: ts=8 sts=2 sw=2 cindent
|
|
*/
|
|
#include "hware.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#define DEFAULT_DEVICE "dev2/port0"
|
|
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
#define DEVICE_ID_NUMBER "0x7085"
|
|
#define DAQmxFailed(e) ((e) != 0)
|
|
#define DAQmxGetExtendedErrorInfo(b, l) snprintf(b, l, "BAD")
|
|
#include <osiBus.h>
|
|
#include <tstaticDIO.h>
|
|
typedef unsigned long uInt32;
|
|
/**
|
|
* This structure contains the data for the PCI-6602 card
|
|
*/
|
|
typedef struct card_t
|
|
{
|
|
iBus* bus;
|
|
tAddressSpace Bar1;
|
|
tstaticDIO *board;
|
|
unsigned char dev_mask;
|
|
} CARD;
|
|
#else
|
|
#include <NIDAQmx.h>
|
|
|
|
#define SAMPLE_COUNT 1
|
|
#define PORT_RANGE "Dev2/port0"
|
|
#define READ_TIMEOUT 2.0
|
|
#define WRITE_TIMEOUT 2.0
|
|
|
|
#define DAQmxErrChk(functionCall) \
|
|
do { if( DAQmxFailed(error=(functionCall)) ) \
|
|
goto Error; } while(0)
|
|
#endif
|
|
|
|
#define BUFFER_SIZE 96
|
|
|
|
/**
|
|
* This structure encapsulates the data that is private to
|
|
* the implementation of the device
|
|
*/
|
|
typedef struct device_private_t
|
|
{
|
|
/** NIDAQ device number of card */
|
|
int card_number;
|
|
/** NI channel number on card */
|
|
int channel_number;
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
HWARE_VALUE value;
|
|
CARD* card;
|
|
#else
|
|
/** NIDAQ opaque task handle */
|
|
TaskHandle taskHandle;
|
|
/** NIDAQ opaque task handle for digital output */
|
|
TaskHandle taskHandle_dout;
|
|
/** Actual physical data value, as returned by NIDAQ read function */
|
|
uInt8 data[BUFFER_SIZE];
|
|
/** previous physical data value */
|
|
uInt8 old_data[BUFFER_SIZE];
|
|
/** number of samples read */
|
|
int32 numRead;
|
|
/** number of bytes per sample */
|
|
int32 bytesPerSamp;
|
|
#endif
|
|
} DEVICE_PRIVATE;
|
|
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
static void initMite(iBus *bus);
|
|
static void initCard(pHWARE ptr);
|
|
static void initChan(pHWARE ptr);
|
|
|
|
static CARD* card[10];
|
|
#else
|
|
#endif
|
|
|
|
int hware_ctor(const char* device_name, pHWARE* ptr)
|
|
{
|
|
pHWARE hware = NULL;
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
CARD* pci = NULL;
|
|
#endif
|
|
int error = 0;
|
|
bool flag = false;
|
|
char text_string[] = DEFAULT_DEVICE;
|
|
const char *name;
|
|
const char *text;
|
|
|
|
hware = (DEVICE_PRIVATE*) malloc(sizeof(DEVICE_PRIVATE));
|
|
*ptr = hware;
|
|
memset(hware, 0, sizeof(DEVICE_PRIVATE));
|
|
|
|
name = device_name;
|
|
text = text_string;
|
|
while (name && *name)
|
|
{
|
|
if (isspace(*name))
|
|
++name;
|
|
else if (*name >= '0' && *name <= '9')
|
|
{
|
|
if (flag)
|
|
{
|
|
hware->channel_number = *name - '0';
|
|
}
|
|
else
|
|
{
|
|
hware->card_number = *name - '0';
|
|
flag = true;
|
|
}
|
|
}
|
|
else if (tolower(*name) != *text)
|
|
{
|
|
/* TODO error */
|
|
printf("Device name error: %s (%d,%d)\n",
|
|
device_name,
|
|
hware->channel_number,
|
|
hware->card_number);
|
|
break;
|
|
}
|
|
++name;
|
|
++text;
|
|
}
|
|
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
if (card[hware->card_number] == NULL)
|
|
{
|
|
char local_name[40] = "PXI6::1::INSTR";
|
|
FILE* fd = fopen("/proc/nirlpk/lsdaq", "r");
|
|
if (fd)
|
|
{
|
|
bool found = false;
|
|
int count = 0;
|
|
char line[100];
|
|
while (fgets(line, 100, fd))
|
|
{
|
|
if (strstr(line, DEVICE_ID_NUMBER))
|
|
{
|
|
++count;
|
|
name = strstr(line, "PXI");
|
|
if (name && count == hware->card_number)
|
|
{
|
|
found = true;
|
|
strcpy(local_name, name);
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
// TODO error
|
|
}
|
|
}
|
|
fclose(fd);
|
|
}
|
|
|
|
card[hware->card_number] = (CARD*) malloc(sizeof(CARD));
|
|
memset(card[hware->card_number], 0, sizeof(CARD));
|
|
pci = card[hware->card_number];
|
|
hware->card = pci;
|
|
|
|
pci->bus = acquireBoard((tChar*) local_name /* "PXI6::1::INSTR" */);
|
|
|
|
if(pci->bus == NULL)
|
|
{
|
|
printf("Error accessing the PCI device \"%s\". Exiting.\n",
|
|
local_name);
|
|
error = 1;
|
|
goto Error;
|
|
}
|
|
|
|
//Intitialise Mite Chip.
|
|
|
|
initMite(pci->bus);
|
|
|
|
initCard(hware);
|
|
}
|
|
else
|
|
{
|
|
pci = card[hware->card_number];
|
|
hware->card = pci;
|
|
}
|
|
|
|
// Mark the counter on this card as in-use
|
|
if (pci->dev_mask & (1 << hware->channel_number))
|
|
{
|
|
// TODO error
|
|
}
|
|
pci->dev_mask |= 1 << hware->channel_number;
|
|
|
|
initChan(hware);
|
|
#else
|
|
do {
|
|
char local_name[40];
|
|
/*********************************************/
|
|
// Create a DAQmx task
|
|
/*********************************************/
|
|
DAQmxErrChk (DAQmxCreateTask("",&hware->taskHandle));
|
|
DAQmxErrChk (DAQmxCreateTask("",&hware->taskHandle_dout));
|
|
|
|
/*********************************************/
|
|
// Create a DAQmx device within the task
|
|
/*********************************************/
|
|
snprintf(local_name, sizeof(local_name),
|
|
"dev%d/line%d:%d",
|
|
hware->card_number,
|
|
hware->channel_number * 32,
|
|
hware->channel_number * 32 + 23);
|
|
DAQmxErrChk (
|
|
DAQmxCreateDIChan(hware->taskHandle,
|
|
local_name,
|
|
"",
|
|
DAQmx_Val_ChanForAllLines));
|
|
|
|
/*********************************************/
|
|
// Create the digital output channel within the task
|
|
/*********************************************/
|
|
snprintf(local_name, sizeof(local_name),
|
|
"dev%d/line%d:%d",
|
|
hware->card_number,
|
|
hware->channel_number * 32 + 24,
|
|
hware->channel_number * 32 + 31);
|
|
DAQmxErrChk (
|
|
DAQmxCreateDOChan(hware->taskHandle_dout,
|
|
local_name,
|
|
"",
|
|
DAQmx_Val_ChanForAllLines));
|
|
/*********************************************/
|
|
// Start the DAQmx task
|
|
/*********************************************/
|
|
DAQmxErrChk (DAQmxStartTask(hware->taskHandle));
|
|
DAQmxErrChk (DAQmxStartTask(hware->taskHandle_dout));
|
|
} while (0);
|
|
#endif
|
|
hware_write(hware, 0);
|
|
|
|
return 0;
|
|
Error:
|
|
free(hware);
|
|
*ptr = NULL;
|
|
return error;
|
|
}
|
|
|
|
int hware_read(pHWARE hware, HWARE_VALUE* value)
|
|
{
|
|
int error = 0;
|
|
*value = 0;
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
CARD* pci = hware->card;
|
|
HWARE_VALUE uPattern;
|
|
switch (hware->channel_number)
|
|
{
|
|
case 0:
|
|
uPattern = pci->board->IOPort0Data.readRegister();
|
|
uPattern |= pci->board->IOPort1Data.readRegister() << 8;
|
|
uPattern |= pci->board->IOPort2Data.readRegister() << 16;
|
|
break;
|
|
case 1:
|
|
uPattern = pci->board->IOPort4Data.readRegister();
|
|
uPattern |= pci->board->IOPort5Data.readRegister() << 8;
|
|
uPattern |= pci->board->IOPort6Data.readRegister() << 16;
|
|
break;
|
|
case 2:
|
|
uPattern = pci->board->IOPort8Data.readRegister();
|
|
uPattern |= pci->board->IOPort9Data.readRegister() << 8;
|
|
uPattern |= pci->board->IOPort10Data.readRegister() << 16;
|
|
break;
|
|
}
|
|
*value = uPattern;
|
|
#else
|
|
/*********************************************/
|
|
// DAQmx Read Code
|
|
/*********************************************/
|
|
hware->numRead = 0;
|
|
hware->bytesPerSamp = 0;
|
|
error = DAQmxReadDigitalLines (hware->taskHandle,
|
|
SAMPLE_COUNT,
|
|
READ_TIMEOUT,
|
|
DAQmx_Val_GroupByScanNumber,
|
|
hware->data,
|
|
BUFFER_SIZE,
|
|
&hware->numRead,
|
|
&hware->bytesPerSamp,
|
|
NULL);
|
|
#if 0
|
|
if (hware->channel_number == 0)
|
|
{
|
|
int i;
|
|
fprintf(stderr, "dev:%d.%d, numRead:%d, bytesPerSamp:%d",
|
|
hware->channel_number,
|
|
hware->channel_number,
|
|
(int) hware->numRead,
|
|
(int) hware->bytesPerSamp);
|
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
|
fprintf(stderr, ", %02x", hware->data[i]);
|
|
fprintf(stderr, "\n");
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
if (error == DAQmxErrorSamplesNotYetAvailable)
|
|
{
|
|
printf("Timeout, reading raw data\n");
|
|
error = 0;
|
|
}
|
|
else if (hware_failed(error))
|
|
goto Error;
|
|
else
|
|
{
|
|
int i;
|
|
HWARE_VALUE uPattern;
|
|
uPattern = 0;
|
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
|
if (hware->data[i])
|
|
uPattern |= 1 << i;
|
|
*value = uPattern;
|
|
}
|
|
|
|
return error;
|
|
Error:
|
|
#endif
|
|
return error;
|
|
} /* hware_read */
|
|
|
|
int hware_write(pHWARE hware, HWARE_VALUE value)
|
|
{
|
|
int error = 0;
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
CARD* pci = hware->card;
|
|
switch (hware->channel_number)
|
|
{
|
|
case 0:
|
|
pci->board->IOPort3Data.writeRegister(value & 0xFF);
|
|
break;
|
|
case 1:
|
|
pci->board->IOPort7Data.writeRegister(value & 0xFF);
|
|
break;
|
|
case 2:
|
|
pci->board->IOPort11Data.writeRegister(value & 0xFF);
|
|
break;
|
|
}
|
|
#else
|
|
/*********************************************/
|
|
// DAQmx Write Code
|
|
/*********************************************/
|
|
hware->bytesPerSamp = 8;
|
|
{
|
|
int i;
|
|
// copy the data
|
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
|
hware->data[i] = (value >> i) & 1;
|
|
}
|
|
error = DAQmxWriteDigitalLines(hware->taskHandle_dout,
|
|
1,
|
|
1,
|
|
WRITE_TIMEOUT,
|
|
DAQmx_Val_GroupByChannel,
|
|
hware->data,
|
|
NULL,
|
|
NULL);
|
|
#if 1
|
|
if (hware->channel_number == 0)
|
|
{
|
|
int i;
|
|
fprintf(stderr, "dev:%d.%d, Write: %d",
|
|
hware->card_number,
|
|
hware->channel_number,
|
|
(int) hware->bytesPerSamp);
|
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
|
fprintf(stderr, ", %02x", hware->data[i]);
|
|
fprintf(stderr, "\n");
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
if (hware_failed(error))
|
|
goto Error;
|
|
|
|
return error;
|
|
Error:
|
|
#endif
|
|
return error;
|
|
} /* hware_write */
|
|
|
|
/*
|
|
* Select the source
|
|
*/
|
|
|
|
/*
|
|
* Shut down the channel
|
|
*/
|
|
int hware_dtor(pHWARE* ptr)
|
|
{
|
|
if (ptr && *ptr)
|
|
{
|
|
pHWARE hware = *ptr;
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
CARD* pci = hware->card;
|
|
switch (hware->channel_number)
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
break;
|
|
case 5:
|
|
break;
|
|
}
|
|
|
|
pci->dev_mask &= ~(1 << hware->channel_number);
|
|
if (pci->dev_mask == 0)
|
|
{
|
|
delete pci->board;
|
|
pci->bus->destroyAddressSpace(pci->Bar1);
|
|
|
|
releaseBoard(pci->bus);
|
|
card[hware->card_number] = NULL;
|
|
free(pci);
|
|
}
|
|
#else
|
|
if (hware->taskHandle != 0)
|
|
{
|
|
/*********************************************/
|
|
// DAQmx Stop Code
|
|
/*********************************************/
|
|
DAQmxStopTask(hware->taskHandle);
|
|
DAQmxClearTask(hware->taskHandle);
|
|
hware->taskHandle = 0;
|
|
}
|
|
if (hware->taskHandle_dout != 0)
|
|
{
|
|
/*********************************************/
|
|
// DAQmx Stop Code
|
|
/*********************************************/
|
|
DAQmxStopTask(hware->taskHandle_dout);
|
|
DAQmxClearTask(hware->taskHandle_dout);
|
|
hware->taskHandle_dout = 0;
|
|
}
|
|
#endif
|
|
|
|
/* release the storage */
|
|
free(hware);
|
|
*ptr = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool hware_failed(int error)
|
|
{
|
|
if (DAQmxFailed(error))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void hware_errmsg(char* buff, int len)
|
|
{
|
|
*buff = '\0';
|
|
DAQmxGetExtendedErrorInfo(buff, len);
|
|
}
|
|
|
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
|
//
|
|
//Tell the MITE to link the BAR1 address to the DAQ Board
|
|
//You must initialize the MITE before you write to the rest of the PCI board
|
|
void initMite(iBus *bus)
|
|
{
|
|
tAddressSpace Bar0;
|
|
u32 physicalBar1;
|
|
|
|
//Skip MITE initialization for PCMCIA boards
|
|
//(which do not have a MITE DMA controller)
|
|
if(!bus->get(kIsPciPxiBus,0)) return;
|
|
|
|
Bar0 = bus->createAddressSpace(kPCI_BAR0);
|
|
|
|
//Get the physical address of the DAQ board
|
|
physicalBar1 = bus->get(kBusAddressPhysical,kPCI_BAR1);
|
|
|
|
// ***** Generic MITE initialization *****
|
|
// Tell the MITE to enable BAR1, where the rest of the board's registers are
|
|
Bar0.write32(0xC0, (physicalBar1 & 0xffffff00L) | 0x80);
|
|
|
|
bus->destroyAddressSpace(Bar0);
|
|
}
|
|
|
|
void initCard(pHWARE hware)
|
|
{
|
|
CARD* pci = hware->card;
|
|
pci->Bar1 = pci->bus->createAddressSpace(kPCI_BAR1);
|
|
pci->board = new tstaticDIO(pci->Bar1);
|
|
//
|
|
// Set All Digital lines as Input so we don't accidentally double drive an IO pin
|
|
|
|
pci->board->IOSelect0.writeDirection(pci->board->IOSelect0.kDirectionInput);
|
|
pci->board->IOSelect1.writeDirection(pci->board->IOSelect1.kDirectionInput);
|
|
pci->board->IOSelect2.writeDirection(pci->board->IOSelect2.kDirectionInput);
|
|
pci->board->IOSelect3.writeDirection(pci->board->IOSelect3.kDirectionInput);
|
|
|
|
pci->board->IOSelect4.writeDirection(pci->board->IOSelect4.kDirectionInput);
|
|
pci->board->IOSelect5.writeDirection(pci->board->IOSelect5.kDirectionInput);
|
|
pci->board->IOSelect6.writeDirection(pci->board->IOSelect6.kDirectionInput);
|
|
pci->board->IOSelect7.writeDirection(pci->board->IOSelect7.kDirectionInput);
|
|
|
|
pci->board->IOSelect8.writeDirection(pci->board->IOSelect8.kDirectionInput);
|
|
pci->board->IOSelect9.writeDirection(pci->board->IOSelect9.kDirectionInput);
|
|
pci->board->IOSelect10.writeDirection(pci->board->IOSelect10.kDirectionInput);
|
|
pci->board->IOSelect11.writeDirection(pci->board->IOSelect11.kDirectionInput);
|
|
}
|
|
|
|
void initChan(pHWARE hware)
|
|
{
|
|
CARD* pci = hware->card;
|
|
/*
|
|
* Set up the channel object
|
|
*/
|
|
switch (hware->channel_number)
|
|
{
|
|
case 0:
|
|
pci->board->IOSelect0.writeDirection(pci->board->IOSelect0.kDirectionInput);
|
|
pci->board->IOSelect1.writeDirection(pci->board->IOSelect1.kDirectionInput);
|
|
pci->board->IOSelect2.writeDirection(pci->board->IOSelect2.kDirectionInput);
|
|
pci->board->IOSelect3.writeDirection(pci->board->IOSelect3.kDirectionOutput);
|
|
break;
|
|
case 1:
|
|
pci->board->IOSelect4.writeDirection(pci->board->IOSelect4.kDirectionInput);
|
|
pci->board->IOSelect5.writeDirection(pci->board->IOSelect5.kDirectionInput);
|
|
pci->board->IOSelect6.writeDirection(pci->board->IOSelect6.kDirectionInput);
|
|
pci->board->IOSelect7.writeDirection(pci->board->IOSelect7.kDirectionOutput);
|
|
break;
|
|
case 2:
|
|
pci->board->IOSelect8.writeDirection(pci->board->IOSelect8.kDirectionInput);
|
|
pci->board->IOSelect9.writeDirection(pci->board->IOSelect9.kDirectionInput);
|
|
pci->board->IOSelect10.writeDirection(pci->board->IOSelect10.kDirectionInput);
|
|
pci->board->IOSelect11.writeDirection(pci->board->IOSelect11.kDirectionOutput);
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
#endif
|