#include #include #include "/home/jeblack3/libusblinux300/ownet.h" #define rw(serialNum,src,dest) deviceRW(serialNum, src[0], src[1], buff, (int) sizeof(src[0])) // Family codes #define THERMOMETER 0x10 #define A_TO_D_CONVERTER 0x20 // ROM commands #define SEARCH_ROM_CMD 0xF0 #define READ_ROM_CMD 0x33 #define MATCH_ROM_CMD 0x55 #define SKIP_ROM_CMD 0xCC #define ALARM_SEARCH_CMD 0xEC #define RESUME_CMD 0xA5 #define OVERDRIVE_SKIP_ROM_CMD 0x3C #define OVERDRIVE_MATCH_ROM_CMD 0x69 // Thermometer commands #define CONVERT_T_CMD 0x44 #define WRITE_SCRATCHPAD_CMD 0x4E #define READ_SCRATCHPAD_CMD 0xBE #define COPY_SCRATCHPAD_CMD 0x48 #define RECALL_E2_CMD 0xB8 #define READ_POWER_SUPPLY_CMD 0xB4 // A-to-D converter commands #define READ_MEMORY_CMD 0xAA #define WRITE_MEMORY_CMD 0x55 #define CONVERT_A_TO_D_CMD 0x3C // Constants for echoFindDevices #define MAX_DEVICES 65536 #define FIND_ERROR -1 typedef struct { unsigned char SN[8]; unsigned int configError: 1; unsigned int convertError: 1; unsigned int alarmError: 1; } owDevice; int echoReadBit(); int echoWriteBit (int bit); void msg (char *s); void msgInt (const char *format, unsigned int n); void msgLong (const char *format, unsigned long n); void msgFloat (const char *format, float x); int checkCRC8 (unsigned char *ptr, int len); int checkCRC16 (unsigned char init1, unsigned char init2, unsigned char *ptr, int len); int echoFindDevices (unsigned char serialNum[][8], int isAlarmSearch); void setupTherm (owDevice *dev); void doConvertT (owDevice *dev); void readTherm (owDevice *dev, int printTemps); void setupAtoD (owDevice *dev); void doConvertAtoD (owDevice *dev); void readAtoD (owDevice *dev); int deviceRW (unsigned char serialNum[8], unsigned char const *src, unsigned char const *isWriting, unsigned char *dest, int len); int portnum, doOutputToFile; FILE *outputFile; time_t currTime, prevTime; int main (int argc, char *argv[]) { owDevice devList[MAX_DEVICES]; unsigned char serialNum[MAX_DEVICES][8]; unsigned char alarmSN[MAX_DEVICES][8]; long numDevices, numAlarming, n; char portname[] = "DS2490-1"; struct timespec delay; int i, j; delay.tv_sec = 1; delay.tv_nsec = 0; // Acquire adapter portnum = owAcquireEx (portname); if (portnum < 0) { printf ("ERROR: Adapter not found\n"); return 0; } // Open output file if (argc >= 2) { doOutputToFile = 1; outputFile = fopen (argv[1], "a"); if (outputFile == NULL) { printf ("ERROR: Output file '%s' could not be created\n", argv[1]); return 0; } } else { doOutputToFile = 0; } // Find Devices numDevices = echoFindDevices (serialNum, 0); if (numDevices <= 0) { fclose (outputFile); return 0; } else { for (n = 0; n < numDevices; n++) { for (i = 0; i < 8; i++) { devList[n].SN[i] = serialNum[n][i]; } devList[n].configError = 1; devList[n].convertError = 1; devList[n].alarmError = 1; } } // Get time prevTime = time (NULL); msg ("Time: "); msgLong (" %10lu\n", prevTime); while (1) { // Set up devices if needed for (n = 0; n < numDevices; n++) { if (devList[n].configError | devList[n].alarmError) { switch (devList[n].SN[0]) { case THERMOMETER: setupTherm (&devList[n]); break; case A_TO_D_CONVERTER: setupAtoD (&devList[n]); break; } } } // Initiate conversions for (n = 0; n < numDevices; n++) { if ( !(devList[n].configError) ) { switch (devList[n].SN[0]) { case THERMOMETER: doConvertT (&devList[n]); break; case A_TO_D_CONVERTER: doConvertAtoD (&devList[n]); break; } } } // Sleep 1 second if ( nanosleep(&delay, NULL) != 0) { msg ("ERROR: Sleep interrupted\n"); } // Check time currTime = time (NULL); msg ("Time: "); msgLong (" %10lu\n", prevTime); if (currTime != prevTime + 1 && currTime != prevTime + 2) { msg ("ERROR: Unexpected delay\n"); } prevTime = currTime; // Read devices for (n = 0; n < numDevices; n++) { if ( !(devList[n].configError | devList[n].convertError) ) { switch (devList[n].SN[0]) { case THERMOMETER: readTherm (&devList[n], 1); break; case A_TO_D_CONVERTER: readAtoD (&devList[n]); break; } } } // Search for alarming devices numAlarming = echoFindDevices (alarmSN, 1); if (numAlarming < 0) { for (n = 0; n < numDevices; n++) { devList[n].alarmError = 1; } } else { for (i = 0; i < numAlarming; i++) { msg ("ERROR: Device with SN "); for (j = 7; j >= 0; j--) { msgInt ("%02X", alarmSN[i][j]); } msg (" is alarming\n"); for (n = 0; n < numDevices; n++) { for (j = 0; j < 8; j++) { if (devList[n].SN[j] != alarmSN[i][j]) { break; } } if (j == 8) { devList[n].alarmError = 1; break; } } if (n >= numDevices) { msg ("ERROR: Alarming device not found on original list\n"); } } } } } int echoReadBit() { int bit; bit = owTouchBit (portnum, 1); msgInt ("%u", bit); return bit; } int echoWriteBit (int bit) { int bit2; msgInt ("%u", bit); bit2 = owTouchBit (portnum, bit); if (bit != bit2) { msgInt ("\nERROR: Wrote %u", bit); msgInt (" but read %u\n", bit2); return 0; } return 1; } void msg (char *s) { printf ("%s", s); if (doOutputToFile) { if ( fprintf(outputFile, "%s", s) < 0 ) { printf ("\nERROR: Could not write to file\n"); } fflush (outputFile); } return; } void msgInt (const char *format, unsigned int n) { printf (format, n); if (doOutputToFile) { if ( fprintf(outputFile, format, n) < 0 ) { printf ("\nERROR: Could not write to file\n"); } fflush (outputFile); } return; } void msgLong (const char *format, unsigned long n) { printf (format, n); if (doOutputToFile) { if ( fprintf(outputFile, format, n) < 0 ) { printf ("\nERROR: Could not write to file\n"); } fflush (outputFile); } return; } void msgFloat (const char *format, float x) { printf (format, x); if (doOutputToFile) { if ( fprintf(outputFile, format, x) < 0 ) { printf ("\nERROR: Could not write to file\n"); } fflush (outputFile); } return; } int checkCRC8 (unsigned char *ptr, int len) { unsigned int crc8 = 0; int i; setcrc8 (portnum, 0); for (i = 0; i < len; i++) { crc8 = docrc8 (portnum, ptr[i]); } if (ptr[len] == crc8) { return 1; } else { msgInt ("ERROR: CRC received = %02X", ptr[len]); msgInt (" but CRC calculated = %02X\n", crc8); return 0; } } int checkCRC16 (unsigned char init1, unsigned char init2, unsigned char *ptr, int len) { unsigned short calcCRC16, readCRC16; int i; calcCRC16 = init1 | ((unsigned short) init2 << 8); setcrc16 (portnum, calcCRC16); for (i = 0; i < len; i++) { calcCRC16 = docrc16 (portnum, ptr[i]); } readCRC16 = ~(ptr[len] | ((unsigned short) ptr[len + 1] << 8)); if (calcCRC16 == readCRC16) { return 1; } else { msgInt ("ERROR: CRC received = %04X", readCRC16); msgInt (" but CRC calculated = %04X", calcCRC16); return 0; } } int echoFindDevices (unsigned char serialNum[][8], int isAlarmSearch) { int bit[64], branch0[64], branch1[64], i, j, n, depth; unsigned char command, origCommand; n = 0; depth = 0; for (i = 0; i < 64; i++) { bit[i] = 0; } do { // Reset signal if ( !owTouchReset(portnum) ) { msg ("ERROR: No one-wire devices responded to reset signal\n"); return FIND_ERROR; } // SEARCH ROM or ALARM SEARCH command if (isAlarmSearch) { origCommand = ALARM_SEARCH_CMD; } else { origCommand = SEARCH_ROM_CMD; } command = origCommand; if ( !owBlock(portnum, FALSE, &command, 1) ) { msg ("ERROR: Could not write to devices\n"); return FIND_ERROR; } msgInt ("%02X ", command); if (command != origCommand) { msgInt ("ERROR: Wrote %02X", origCommand); msgInt (" but read %02X from bus\n", command); return FIND_ERROR; } // Traverse tree for (i = 0; i < 64; i++) { if (i % 8 == 0 && i != 0) { msg (" "); } if (i >= depth) { branch0[i] = !echoReadBit(); branch1[i] = !echoReadBit(); if (branch0[i]) { bit[i] = 0; } else if (branch1[i]) { bit[i] = 1; } else { if (n == 0 && i == 0) { if (!isAlarmSearch) { msg ("\nERROR: No devices found\n"); } else { msg ("\n"); } return 0; } else { msg ("\nERROR: During search, no devices found with either bit 0 or bit 1\n"); return FIND_ERROR; } } } else { if ( branch0[i] != (!echoReadBit()) || branch1[i] != (!echoReadBit()) ) { msg ("\nERROR: ROM bits read on different runs inconsistent\n"); return FIND_ERROR; } } if ( !echoWriteBit(bit[i]) ) { return FIND_ERROR; } if (i % 8 == 7) { msg ("\n"); } else { msg (" "); } } for (i = 0; i < 8; i++) { serialNum[n][i] = 0; for (j = 0; j < 8; j++) { serialNum[n][i] |= (bit[8 * i + j] << j); } } if ( !checkCRC8(serialNum[n], 7) ) { return FIND_ERROR; } for (i = 64 - 1; i >= 0; i--) { bit[i]++; if (bit[i] == 1 && branch1[i]) { depth = i + 1; break; } } n++; if (n >= MAX_DEVICES) { msgLong ("ERROR: Device limit of %lu exceeded\n", MAX_DEVICES); return FIND_ERROR; } } while (i >= 0); return n; } void setupTherm (owDevice *dev) { unsigned char const writeScratchPad[2][3] = { {WRITE_SCRATCHPAD_CMD, // WRITE SCRATCHPAD command 0x7F, // Max Temp = +127 C 0x80}, // Min Temp = -128 C {1, 1, 1} }; unsigned char buff[sizeof(writeScratchPad[0]) + 9]; // Send command if ( !rw(dev->SN, writeScratchPad, buff) ) { dev->alarmError = 1; return; } dev->configError = 0; // Check thermometer readTherm (dev, 0); return; } void doConvertT (owDevice *dev) { unsigned char const readPowerSupply[2][2] = { {READ_POWER_SUPPLY_CMD, // READ POWER SUPPLY command 0xFF}, // Read slots for response {1, 0} }; unsigned char const convertT[2][2] = { {CONVERT_T_CMD, // CONVERT T command 0xFF}, // Read slots for busy signal {1, 0} }; unsigned char buff[sizeof(convertT[0]) + 9]; // Check power supply if ( !rw(dev->SN, readPowerSupply, buff) ) { dev->convertError = 1; return; } switch (buff[10]) { case 0: msg ("ERROR: Thermometer is using parasitic power\n"); dev->convertError = 1; return; break; case 0xFF: break; default: msg ("ERROR: Response of thermometer to power supply query is inconsistent\n"); dev->convertError = 1; return; break; } // Send command if ( !rw(dev->SN, convertT, buff) ) { dev->convertError = 1; return; } if (buff[10] == 0xFF) { msg ("ERROR: No busy signal from thermometer after CONVERT T command\n"); dev->convertError = 1; return; } else if (buff[10] != 0) { msg ("ERROR: Inconsistent busy signal from thermometer after CONVERT T command\n"); } dev->convertError = 0; return; } void readTherm (owDevice *dev, int printTemps) { unsigned char const readScratchpad[2][10] = { {READ_SCRATCHPAD_CMD, // READ SCRATCHPAD command 0xFF, 0xFF, 0xFF, 0xFF, // Read slots for scratchpad data 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; unsigned char buff[sizeof(readScratchpad[0]) + 9], *scratchpad; int goodData = 1; int anyData, i; signed long tempInt; float temp; // Send READ SCRATCHPAD command if ( !rw(dev->SN, readScratchpad, buff) ) { return; } scratchpad = buff + 10; // Check whether any data was read anyData = 0; for (i = 0; i < 9 && !anyData; i++) { if (scratchpad[i] != 0xFF) { anyData = 1; } } if (!anyData) { msg ("ERROR: All ones read from thermometer\n"); return; } // Check cyclic redundancy code goodData &= checkCRC8 (scratchpad, 8); // Check consistency of temperature sign if (scratchpad[1] != 0x00 && scratchpad[1] != 0xFF) { msg ("ERROR: Sign bits inconsistent\n"); goodData = 0; } // Check bytes 4 and 5 if (scratchpad[4] != 0xFF) { msg ("ERROR: Scratchpad byte 4 is not FF\n"); goodData = 0; } if (scratchpad[5] != 0xFF) { msg ("ERROR: Scratchpad byte 5 is not FF\n"); goodData = 0; } // Check whether extended precision bits are in range if (scratchpad[6] == 0 || scratchpad[6] > 16) { msg ("ERROR: COUNT REMAIN out of range\n"); goodData = 0; } else { // Check consistency of extended-precision temperature with last bit of temperature if ( (scratchpad[6] < 9) != (scratchpad[0] & 1) ) { msg ("ERROR: COUNT REMAIN and Temperature inconsistent\n"); goodData = 0; } } // Check COUNT PER deg C if (scratchpad[7] != 16) { msg ("ERROR: COUNT PER deg C is not 16\n"); goodData = 0; } if (!goodData) { return; } // Check alarm settings dev->alarmError = 0; if (scratchpad[2] != 0x7F) { msg ("ERROR: Alarm feature's maximum temperature setting is not +127 C\n"); dev->alarmError = 1; } if (scratchpad[3] != 0x80) { msg ("ERROR: Alarm feature's minimum temperature setting is not -128 C\n"); dev->alarmError = 1; } if (printTemps) { // Convert temperature to human-readable format tempInt = scratchpad[1]; tempInt <<= 7; tempInt |= (scratchpad[0] >> 1); if (tempInt >= 0x4000) { tempInt -= 0x8000; } temp = tempInt - 0.25 + ((float) (16 - scratchpad[6])) / 16; if (temp < -55 || temp > 125) { msg ("ERROR: Temperature out of range\n"); } // Print data msg ("\nData: "); for (i = 7; i >= 0; i--) { msgInt ("%02X", dev->SN[i]); } msgLong (" %10lu", currTime); msgFloat (" %10.5f\n\n", temp); } return; } void setupAtoD (owDevice *dev) { unsigned char const writeMemory[2][67] = { {WRITE_MEMORY_CMD, // WRITE MEMORY command 0x08, 0x00, // Address of data to write 0x00, 0xFF, 0xFF, 0xFF, // Data to write followed 0x01, 0xFF, 0xFF, 0xFF, // by read slots for 0x00, 0xFF, 0xFF, 0xFF, // CRC16 (2 bytes) 0x01, 0xFF, 0xFF, 0xFF, // and readback of byte 0x00, 0xFF, 0xFF, 0xFF, // written (1 byte) 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, // Page 2 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,} }; unsigned char buff[sizeof(writeMemory[0]) + 9], *ptr; int i, anyData, passed; // Write settings to converter's memory if ( !rw(dev->SN, writeMemory, buff) ) { dev->configError = 1; dev->alarmError = 1; return; } ptr = buff + 9; // Check whether any data was read anyData = 0; for (i = 3; i < sizeof(writeMemory[0]) && !anyData; i++) { if ( (i & 3) != 3 && ptr[i] != 0xFF ) { anyData = 1; } } if (!anyData) { msg ("ERROR: All ones read from A-to-D converter\n"); dev->configError = 1; dev->alarmError = 1; return; } dev->configError = 0; dev->alarmError = 0; // Check that data was written okay for (i = 0; i < 16; i++, ptr += 4) { if (i == 0) { passed = checkCRC16 (0, 0, ptr, 4); ptr += 3; } else { passed = checkCRC16 (8 + i, 0, ptr, 1); } if (!passed) { msgInt (" (byte %u)\n", 8 + i); if (i < 8) { dev->configError = 1; } else { dev->alarmError = 1; } } if (ptr[0] != ptr[3]) { msgInt ("ERROR: Wrote %02X", ptr[0]); msgInt (" but read back %02X", ptr[3]); msgInt (" (byte %u)\n", 8 + i); if (i < 8) { dev->configError = 1; } else { dev->alarmError = 1; } } } return; } void doConvertAtoD (owDevice *dev) { unsigned char const convertAtoD[2][5] = { {CONVERT_A_TO_D_CMD, // CONVERT command 0x0F, // All channels 0x00, // No preset 0xFF, 0xFF}, // CRC16 {1, 1, 1, 0, 0} }; unsigned char buff[sizeof(convertAtoD[0]) + 9], *ptr; dev->convertError = 0; // Send CONVERT command if ( !rw(dev->SN, convertAtoD, buff) ) { dev->convertError = 1; } ptr = buff + 9; // Check whether any data was read if (ptr[3] == 0xFF && ptr[4] == 0xFF) { msg ("ERROR: All ones read from A-to-D converter\n"); dev->convertError = 1; } // Check CRC if ( !checkCRC16(0, 0, ptr, 3) ) { msg ("\n"); dev->convertError = 1; } return; } void readAtoD (owDevice *dev) { unsigned char const readMemory[2][33] = { {READ_MEMORY_CMD, // READ MEMORY command 0x00, 0x00, // Memory address 0xFF, 0xFF, 0xFF, 0xFF, // Memory page 0 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, // CRC16 0xFF, 0xFF, 0xFF, 0xFF, // Memory page 1 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, // CRC16 0xFF, 0xFF, 0xFF, 0xFF, // Memory page 2 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF,}, // CRC16 {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; unsigned char buff[sizeof(readMemory[0]) + 9], *ptr; unsigned short voltInt[4]; float voltage[4]; int i, anyData, resolution; int pageGood[3]; int goodData = 1; // Read converter's memory if ( !rw(dev->SN, readMemory, buff) ) { return; } ptr = buff + 9; // Check whether any data was read anyData = 0; for (i = 3; i < sizeof(readMemory[0]) && !anyData; i++) { if (ptr[i] != 0xFF) { anyData = 1; } } if (!anyData) { msg ("ERROR: All ones read from A-to-D converter\n"); return; } // Check CRC16 values pageGood[0] = checkCRC16 (0, 0, ptr, 11); if (!pageGood[0]) { msg (" (page 0)\n"); goodData = 0; } pageGood[1] = checkCRC16 (0, 0, ptr + 13, 8); if (!pageGood[1]) { msg (" (page 1)\n"); goodData = 0; } pageGood[2] = checkCRC16 (0, 0, ptr + 23, 8); if (!pageGood[2]) { msg (" (page 2)\n"); } ptr += 3; for (i = 0; i < 4; i++) { // Check bits on page 1 which should be zero if ( (ptr[2*i + 10] & 0x30) || (ptr[2*i + 11] & 0x42) ) { msg ("ERROR: Ones read in position where zeros were expected\n"); pageGood[1] = 0; } // Check for power failure flag if (ptr[2*i + 11] & 0x80) { msgInt ("ERROR: Data lost due to power failure (channel %c)\n", 'A' + i); pageGood[0] = 0; } } // Check for changes in settings if (pageGood[1]) { dev->configError = 0; for (i = 0; i < 4; i++) { if ( ((ptr[2*i + 10] & 0xCF) != 0) || ((ptr[2*i + 11] & 0x4D) != 1) ) { msgInt ("ERROR: Settings changed for channel %c\n", 'A' + i); dev->configError = 1; } } } if (pageGood[1] && pageGood[2]) { dev->alarmError = 0; for (i = 0; i < 4; i++) { // Check alarm flags if (ptr[2*i + 11] & 0x10) { msgInt ("ERROR: Low voltage alarm flag set (channel %c)\n", 'A' + i); dev->alarmError = 1; } if (ptr[2*i + 11] & 0x20) { msgInt ("ERROR: High voltage alarm flag set (channel %c)\n", 'A' + i); dev->alarmError = 1; } // Check for changes in alarm settings if ( (ptr[2*i + 20] != 0) || (ptr[2*i + 21] != 0xFF) ) { msgInt ("ERROR: Alarm settings changed for channel %c\n", 'A' + i); dev->alarmError = 1; } } } if (pageGood[0] && pageGood[1]) { // Calculate voltages for (i = 0; i < 4; i++) { voltInt[i] = ptr[2*i] | ((unsigned short) ptr[2*i + 1] << 8); resolution = ptr[2*i + 10] & 0xF; if (resolution == 0) { resolution = 16; } voltInt[i] &= (0xFFFF << (16 - resolution)); if (ptr[2*i + 11] & 0x01) { voltage[i] = (float) voltInt[i] / 12800; } else { voltage[i] = (float) voltInt[i] / 25600; } } // Print data msg ("\nData: "); for (i = 7; i >= 0; i--) { msgInt ("%02X", dev->SN[i]); } msgLong (" %10lu", currTime); for (i = 0; i < 4; i++) { msgFloat (" %10.5f", voltage[i]); } msg ("\n\n"); } return; } int deviceRW (unsigned char serialNum[8], unsigned char const *src, unsigned char const *isWriting, unsigned char *dest, int len) { int success = 1; unsigned char correct; int i; // MATCH ROM command dest[0] = MATCH_ROM_CMD; // Serial number for (i = 0; i < 8; i++) { dest[1 + i] = serialNum[i]; } // Data for device for (i = 0; i < len; i++) { dest[9 + i] = src[i]; } // Send reset signal if ( !owTouchReset(portnum) ) { msg ("ERROR: No one-wire devices responded to reset signal\n"); return 0; } // Read & Write if ( !owBlock(portnum, FALSE, dest, 9 + len) ) { msg ("ERROR: Could not write to device\n"); return 0; } // Get time currTime = time (NULL); if (currTime != prevTime && currTime != prevTime + 1) { msg ("ERROR: Unexpected delay\n"); } // Print, check writes for (i = 0; i < 9 + len; i++) { msgInt ("%02X", dest[i]); if (i == 8 && len > 20) { msg ("\n "); } else if (i == 0 || i == 8) { msg (" "); } if (i < 9 || isWriting[i - 9]) { if (i >= 9) { correct = src[i - 9]; } else if (i >= 1) { correct = serialNum[i - 1]; } else { correct = MATCH_ROM_CMD; } if (dest[i] != correct) { msgInt ("\nERROR: Wrote %02X", correct); msgInt (" but read %02X from data wire\n", dest[0]); success = 0; } } } msg ("\n"); return success; }