#include #include #include #include #include #include #include #include #include #define I2CDEV "/dev/i2c/0" #define I2CADDR 0x18 static int i2cdev; /* I2C access functions */ void i2c_writebyte(unsigned char byte) { if (write(i2cdev, &byte, 1) != 1) { perror("i2c_writebyte"); } } void i2c_writeword(unsigned char byte1, unsigned char byte2) { unsigned char buf[2] = {byte1, byte2}; if (write(i2cdev, buf, 2) != 2) { perror("i2c_writeword"); } } unsigned char i2c_readbyte() { unsigned char result = 0x00; if (read(i2cdev, &result, 1) != 1) { perror("i2c_readbyte"); } return result; } /* DS2482 configuration access */ static unsigned char ds2482_confreg; void ds2482_config(unsigned char config) { config &= 0x0F; config |= 0xF0 ^ (config << 4); i2c_writeword(DS2482_WRITECONF, config); ds2482_confreg = config; } void ow_spu(int strong_pullup) { if (strong_pullup) ds2482_confreg |= CONFIG_SPU; else ds2482_confreg &= ~CONFIG_SPU; ds2482_config(ds2482_confreg); } /* 1-wire bus access functions */ unsigned char ow_wait() { unsigned char status; status = i2c_readbyte(); while (status & STATUS_1WB) { usleep(100); status = i2c_readbyte(); } return status; } unsigned char ow_reset() { i2c_writebyte(DS2482_1WRESET); return ow_wait(); } unsigned char ow_triplet(int direction) { i2c_writeword(DS2482_TRIPLET, direction ? 0x80 : 0x00); return ow_wait(); } void ow_readbytes(unsigned char *buf, int count) { int i; for (i = 0; i < count; i++) { i2c_writebyte(DS2482_READBYTE); ow_wait(); i2c_writeword(DS2482_READPOINTER, DS2482REG_READ); buf[i] = i2c_readbyte(); } } void ow_writebytes(unsigned char *buf, int count) { int i; for (i = 0; i < count; i++) { i2c_writeword(DS2482_WRITEBYTE, buf[i]); ow_wait(); } } void ow_writecommand(unsigned char command) { i2c_writeword(DS2482_WRITEBYTE, command); ow_wait(); } int ow_readbit() { unsigned char status; i2c_writeword(DS2482_WRITEBIT, 0x80); status = ow_wait(); if (status & STATUS_SBR) return 1; else return 0; } /* 1-wire CRC */ unsigned char ow_crc(unsigned char *buf, int count) { int byte, bit, bit_in; unsigned char crc = 0x00; for (byte = 0; byte < count; byte++) { for (bit = 0; bit < 8; bit++) { bit_in = (*(buf + byte) & (1 << bit)) >> bit; if (crc & 0x01) bit_in = 1 - bit_in; crc = crc >> 1; if (bit_in) crc ^= 0x80 | 0x08 | 0x04; } } return crc; } /* ROM access functions */ int owaddr_getbit(const struct owaddr *addr, int bitno) { int byte = bitno / 8; int bit = bitno % 8; unsigned char *p = ((unsigned char *) addr) + byte; if (*p & (1 << bit)) return 1; else return 0; } void owaddr_setbit(struct owaddr *addr, int bitno, int value) { int byte = bitno / 8; int bit = bitno % 8; unsigned char *p = ((unsigned char *) addr) + byte; if (value) *p |= 1 << bit; else *p &= ~ (1 << bit); } void owaddr_copy(struct owaddr *dest, const struct owaddr *src, int startbit, int count) { // Copy data from src to dest, starting from and // including startbit, total of count bits unsigned char *srcp = (unsigned char *) src; unsigned char *destp = (unsigned char *) dest; int byte = startbit / 8; int bit = startbit % 8; while (count > 0) { if (count >= 8 && bit == 0) { *(destp + byte) = *(srcp + byte); count -= 8; byte++; } else { if (*(srcp + byte) & (1 << bit)) *(destp + byte) |= 1 << bit; else *(destp + byte) &= ~ (1 << bit); count--; bit++; if (bit > 7) { byte++; bit = 0; } } } } int ow_bussearch(void (*resultfunc)(struct owaddr *)) { // Argument is the function to call on found addresses // Returns number of found devices or -1 on error struct owaddr path_here, path_follow, path_follow_next = {0}; int depth, status, done = 0, count = 0; while(!done) { status = ow_reset(); if (! status & STATUS_PPD) { // No presence pulse if (count == 0) return 0; else return -1; } depth = 0; memset(&path_here, 0, sizeof(path_here)); memcpy(&path_follow, &path_follow_next, sizeof(path_follow)); done = 1; ow_writecommand(OW_SEARCHROM); while (depth < 64) { status = ow_triplet(owaddr_getbit(&path_follow, depth)); if (status & STATUS_DIR) { owaddr_setbit(&path_here, depth, 1); } else if ((status & (STATUS_SBR | STATUS_TSB)) == 0x00) { // Two devices at this bit, and we went left // Next time: follow path this far, then turn right done = 0; memset(&path_follow_next, 0, sizeof(path_follow_next)); owaddr_copy(&path_follow_next, &path_here, 0, depth); owaddr_setbit(&path_follow_next, depth, 1); } if ((status & (STATUS_SBR | STATUS_TSB)) == (STATUS_SBR | STATUS_TSB)) return -2; // No devices answered depth++; } if (ow_crc((unsigned char *) &path_here, sizeof(path_here)) != 0) return -3; // CRC error count++; resultfunc(&path_here); } return count; } void ow_matchrom(const struct owaddr *addr) { ow_reset(); ow_writecommand(OW_MATCHROM); ow_writebytes((unsigned char *) addr, sizeof(struct owaddr)); } /* Public functions */ void ow_initialize() { i2cdev = open(I2CDEV, O_RDWR); if (i2cdev < 0) { perror(I2CDEV); exit(1); } ioctl(i2cdev, I2C_SLAVE, I2CADDR); i2c_writebyte(DS2482_DEVRESET); ds2482_config(0x00); }