#include "ds18b20_ds2480.h" #include #include #include #define CHECK(x) do { if (!(x)) { fprintf(stderr, "line %d: %s\n", __LINE__, #x); exit(1); } } while (0) enum { ROM_COMMAND, MATCH, FUNCTION, SEARCH, READ, CONFIG }; typedef struct { uint8_t rom[3][8], scratch[9]; unsigned count, active, state, phase, position, bits, value, match_index; unsigned prepared, calibrated, pending, reply, pulse, hold, convert, copy; unsigned fail_read, fail_write, fail_prepare, corrupt_reply, reset_reply; unsigned fail_power, fail_stop, reject_config; } fake; static void crc_scratch(fake *f) { f->scratch[8] = ds2480_crc8(f->scratch, 8); } static void setup(fake *f) { unsigned i; static const uint8_t scratch[9] = {0x91, 0x01, 0x4B, 0x46, 0x7F, 0xFF, 0x0C, 0x10, 0x70}; memset(f, 0, sizeof *f); f->count = 3; f->reset_reply = 0xCD; memcpy(f->scratch, scratch, 9); for (i = 0; i < 3; ++i) { f->rom[i][0] = i == 2 ? 0x10 : 0x28; f->rom[i][1] = (uint8_t)(i + 1); f->rom[i][7] = ds2480_crc8(f->rom[i], 7); } } static void byte_in(fake *f, uint8_t byte) { unsigned i; if (f->state == ROM_COMMAND) { if (byte == 0xF0) { f->state = SEARCH; f->position = f->phase = 0; } else if (byte == 0x55) { f->state = MATCH; f->match_index = 0; } else { CHECK(byte == 0xCC); f->state = FUNCTION; } } else if (f->state == MATCH) { for (i = 0; i < f->count; ++i) if (f->rom[i][f->match_index] != byte) f->active &= ~(1U << i); if (++f->match_index == 8) f->state = FUNCTION; } else if (f->state == FUNCTION) { CHECK(f->active != 0); switch (byte) { case 0xBE: f->state = READ; f->position = 0; break; case 0x4E: f->state = CONFIG; f->position = 2; break; case 0x44: ++f->convert; break; case 0x48: ++f->copy; break; default: CHECK(0); } } else { CHECK(f->state == CONFIG); if (!f->reject_config) f->scratch[f->position] = byte; if (++f->position == 5) { crc_scratch(f); f->state = FUNCTION; } } } static uint8_t wire_bit(fake *f, uint8_t bit) { unsigned i, result = 1; if (f->state == SEARCH) { for (i = 0; i < f->count; ++i) { unsigned v = (f->rom[i][f->position / 8] >> (f->position % 8)) & 1; if (!(f->active & (1U << i))) continue; if (f->phase < 2) result &= f->phase ? !v : v; else if (v != bit) f->active &= ~(1U << i); } if (++f->phase == 3) { f->phase = 0; ++f->position; } return (uint8_t)result; } if (f->state == READ) { CHECK(f->position < 72 && bit == 1); result = (f->scratch[f->position / 8] >> (f->position % 8)) & 1; ++f->position; return (uint8_t)result; } f->value |= (unsigned)bit << f->bits; if (++f->bits == 8) { uint8_t byte = (uint8_t)f->value; f->bits = f->value = 0; byte_in(f, byte); } return bit; } static int prepare(void *user) { fake *f = user; ++f->prepared; f->pending = f->pulse = f->calibrated = 0; return (int)f->fail_prepare; } static int transmit(void *user, const uint8_t *data, uint32_t size, uint32_t timeout) { fake *f = user; uint8_t command = *data, bit; CHECK(size == 1 && timeout == 20 && !f->pending); if (f->fail_write) return -1; if (!f->calibrated) { CHECK(command == 0xC1); f->calibrated = 1; return 0; } CHECK(!f->pulse || command == 0xF1); if (command == 0x3F) f->reply = 0x3E; else if (command == 0xC1) { f->reply = f->count ? f->reset_reply : 0xCF; f->state = ROM_COMMAND; f->bits = f->value = 0; f->active = (1U << f->count) - 1; } else if (command == 0xF1) { CHECK(f->pulse && (f->hold == 750 || f->hold == 12)); f->pulse = 0; f->reply = 0xEC; if (f->fail_stop) f->fail_read = 1; } else { CHECK(command == 0x81 || command == 0x91 || command == 0x83 || command == 0x93); bit = wire_bit(f, (uint8_t)((command >> 4) & 1)); f->reply = (command & 0xFC) | (bit ? 3U : 0U); if (command & 2) { CHECK(f->bits == 0 && (f->convert || f->copy)); f->pulse = 1; f->hold = 0; if (f->fail_power) f->fail_read = 1; } } f->pending = 1; return 0; } static int receive(void *user, uint8_t *data, uint32_t size, uint32_t timeout) { fake *f = user; CHECK(size == 1 && timeout == 20 && f->pending); if (f->fail_read) return -1; *data = (uint8_t)(f->corrupt_reply ? 0 : f->reply); f->pending = 0; return 0; } static void delay(void *user, uint32_t ms) { fake *f = user; if (f->pulse) f->hold += ms; else CHECK(ms == 2); } static void init(fake *f, ds2480 *bus) { ds2480_port port = { f, prepare, transmit, receive, delay }; CHECK(ds2480_init(bus, &port, 20) == DS2480_OK); CHECK(!f->pending); } int main(void) { fake f, other; ds2480 bus, second; ds2480_search search = {{0}, 0, 0}, saved; uint8_t bit, scratch[9], rom[8]; int16_t raw = 999; unsigned found = 0, i; setup(&f); init(&f, &bus); CHECK(ds2480_crc8(f.scratch, 9) == 0); /* Datasheet vector, not generated. */ while (ds18b20_ds2480_next(&bus, &search) == DS2480_OK) { if (!memcmp(search.rom, f.rom[0], 8)) found |= 1; else if (!memcmp(search.rom, f.rom[1], 8)) found |= 2; else CHECK(0); } CHECK(found == 3 && search.done); CHECK(ds18b20_ds2480_next(&bus, &search) == DS2480_DONE); CHECK(ds18b20_ds2480_convert(&bus, NULL) == DS2480_OK); CHECK(f.convert == 1 && f.hold == 750 && !f.pulse && !f.pending); CHECK(ds18b20_ds2480_temperature(&bus, f.rom[0], &raw) == DS2480_OK && raw == 401); CHECK(ds18b20_ds2480_convert(&bus, f.rom[1]) == DS2480_OK && f.active == 2); for (i = 9; i <= 12; ++i) { CHECK(ds18b20_ds2480_configure(&bus, f.rom[0], -5, -20, (uint8_t)i, 1) == DS2480_OK); CHECK(f.hold == 12 && !f.pulse && !f.pending); f.scratch[0] = 0x5F; f.scratch[1] = 0xFF; crc_scratch(&f); CHECK(ds18b20_ds2480_temperature(&bus, f.rom[0], &raw) == DS2480_OK); CHECK(raw == (i == 9 ? -168 : i == 10 ? -164 : i == 11 ? -162 : -161)); } CHECK(f.copy == 4); f.reject_config = 1; CHECK(ds18b20_ds2480_configure(&bus, f.rom[0], 1, 2, 9, 1) == DS2480_DATA && f.copy == 4); f.scratch[8] ^= 1; raw = 999; CHECK(ds18b20_ds2480_temperature(&bus, f.rom[0], &raw) == DS2480_CRC && raw == 999); memset(f.scratch, 0, 9); CHECK(ds18b20_ds2480_read(&bus, f.rom[0], scratch) == DS2480_DATA); memset(f.scratch, 0xFF, 9); CHECK(ds18b20_ds2480_temperature(&bus, f.rom[0], &raw) == DS2480_CRC); memcpy(rom, f.rom[0], 8); rom[7] ^= 1; CHECK(ds18b20_ds2480_convert(&bus, rom) == DS2480_ARGUMENT); CHECK(ds18b20_ds2480_read(&bus, NULL, scratch) == DS2480_ARGUMENT); CHECK(ds18b20_ds2480_configure(&bus, f.rom[0], 0, 0, 8, 0) == DS2480_ARGUMENT); CHECK(ds2480_bit(&bus, 1, NULL) == DS2480_ARGUMENT); f.reset_reply = 0xEC; CHECK(ds2480_reset(&bus) == DS2480_SHORT); f.reset_reply = 0xEE; CHECK(ds2480_reset(&bus) == DS2480_OK); f.count = 0; CHECK(ds2480_reset(&bus) == DS2480_NO_PRESENCE); memset(&search, 0, sizeof search); CHECK(ds2480_search_next(&bus, &search) == DS2480_NO_PRESENCE); setup(&f); init(&f, &bus); f.count = 1; f.rom[0][7] ^= 1; saved = search; CHECK(ds2480_search_next(&bus, &search) == DS2480_CRC); CHECK(!memcmp(&search, &saved, sizeof search)); f.fail_read = 1; CHECK(ds2480_reset(&bus) == DS2480_IO); CHECK(ds2480_reset(&bus) == DS2480_NOT_READY); setup(&f); init(&f, &bus); f.corrupt_reply = 1; CHECK(ds2480_reset(&bus) == DS2480_PROTOCOL && !bus.ready); setup(&f); init(&f, &bus); CHECK(ds2480_reset(&bus) == DS2480_OK); f.corrupt_reply = 1; CHECK(ds2480_bit(&bus, 1, &bit) == DS2480_PROTOCOL); setup(&f); init(&f, &bus); f.fail_write = 1; CHECK(ds2480_reset(&bus) == DS2480_IO && !bus.ready); setup(&f); init(&f, &bus); f.fail_power = 1; CHECK(ds18b20_ds2480_convert(&bus, NULL) == DS2480_IO); CHECK(!f.pulse && !bus.ready && f.prepared == 2); setup(&f); init(&f, &bus); f.fail_stop = 1; CHECK(ds18b20_ds2480_convert(&bus, NULL) == DS2480_IO); CHECK(!f.pulse && !bus.ready && f.prepared == 2); setup(&f); init(&f, &bus); setup(&other); init(&other, &second); CHECK(ds18b20_ds2480_convert(&second, other.rom[1]) == DS2480_OK); CHECK(f.convert == 0 && other.convert == 1); CHECK(ds18b20_ds2480_temperature(&bus, f.rom[0], &raw) == DS2480_OK && raw == 401); CHECK(ds2480_init(&bus, &bus.port, 20) == DS2480_OK); f.fail_prepare = 1; CHECK(ds2480_init(&bus, &bus.port, 20) == DS2480_IO && !bus.ready); CHECK(ds2480_init(&bus, NULL, 20) == DS2480_ARGUMENT); puts("DS18B20/DS2480: all host tests passed"); return 0; }