/* vim: ts=8 sts=2 sw=2 cindent */ #include "hware.h" #include #include #include #include #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 #include 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 #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