Files
bouwhuim.nikhef.nl dee2668a61 newest version WRPC
2013-09-10 08:08:59 +00:00

174 lines
3.6 KiB
C

/*
* Onewire generic interface
* Alessandro Rubini, 2013 GNU GPL2 or later
*/
#include <wrc.h>
#include <string.h>
#include <shell.h>
#include <w1.h>
static const struct w1_ops *ops = &wrpc_w1_ops; /* local shorter name */
void w1_write_byte(struct w1_bus *bus, int byte)
{
int i;
for (i = 1; i < 0x100; i <<= 1)
ops->write_bit(bus, byte & i ? 1 : 0);
}
int w1_read_byte(struct w1_bus *bus)
{
int i, res = 0;
for (i = 1; i < 0x100; i <<= 1)
res |= ops->read_bit(bus) ? i : 0;
usleep(100); /* inter-byte, for my eyes only */
return res;
}
/* scan_bus requires this di-bit helper */
enum __bits {B_0, B_1, B_BOTH};
/* return what we get, select it if unambiguous or the one passed */
static enum __bits __get_dibit(struct w1_bus *bus, int select)
{
int a, b;
a = ops->read_bit(bus);
b = ops->read_bit(bus);
if (a != b) {
ops->write_bit(bus, a);
return a ? B_1 : B_0;
}
ops->write_bit(bus, select);
return B_BOTH;
}
/*
* This identifies one. Returns 0 if not found, -1 on error. The current mask
* is used to return the conflicts we found: on each conflict, we follow
* what's already in our id->rom, but remember it for later scans.
*/
static int __w1_scan_one(struct w1_bus *bus, uint64_t *rom, uint64_t *cmask)
{
uint64_t mask;
int select;
enum __bits b;
if (ops->reset(bus) != 1)
return -1;
w1_write_byte(bus, 0xf0); /* search rom */
/*
* Send all bits we have (initially, zero).
* On a conflict, follow what we have in rom and possibly mark it.
*/
*cmask = 0;
for (mask = 1; mask; mask <<= 1) {
select = *rom & mask;
b = __get_dibit(bus, select);
switch(b) {
case B_1:
*rom |= mask;
case B_0:
break;
case B_BOTH:
/* if we follow 1, it's resolved, else mark it */
if (!select)
*cmask |= mask;
break;
}
}
return 0;
}
int w1_scan_bus(struct w1_bus *bus)
{
uint64_t mask;
uint64_t cmask; /* current */
struct w1_dev *d;
int i;
memset(bus->devs, 0, sizeof(bus->devs));
if (!ops->reset)
return 0; /* no devices */
for (i = 0, cmask = 0; i < W1_MAX_DEVICES; i++) {
d = bus->devs + i;
d->bus = bus;
if (i) { /* Not first: scan conflicts and resolve last */
d->rom = bus->devs[i-1].rom;
for (mask = (1ULL<<63); mask; mask >>= 1) {
/*
* Warning: lm32 compiter treats as signed!
*
* Even if mask is uint64_t, the shift in the
* for loop above is signed, so fix it.
* I prefer not to change the loop, as the
* code is in use elsewhere and I prefer to
* keep differences to a minimum
*/
if (mask & (1ULL<<62))
mask = (1ULL<<62);
if (cmask & mask)
break;
d->rom &= ~mask;
}
if (!mask) {
/* no conflicts to solve: done */
return i;
}
d->rom |= mask; /* we'll reply 1 next loop */
cmask &= ~mask;
}
if (__w1_scan_one(bus, &d->rom, &cmask)) {
/* error on this one */
return i;
}
pp_printf("W1: %08x%08x\n", (int)(d->rom >> 32), (int)d->rom);
}
return i;
}
void w1_match_rom(struct w1_dev *dev)
{
int i;
ops->reset(dev->bus);
w1_write_byte(dev->bus, W1_CMD_MATCH_ROM); /* match rom */
for (i = 0; i < 64; i+=8) {
w1_write_byte(dev->bus, (int)(dev->rom >> i) );
}
}
/* A shell command, for checking */
static int cmd_w1(const char *args[])
{
int i;
struct w1_dev *d;
int32_t temp;
w1_scan_bus(&wrpc_w1_bus);
for (i = 0; i < W1_MAX_DEVICES; i++) {
d = wrpc_w1_bus.devs + i;
if (d->rom) {
pp_printf("device %i: %08x%08x\n", i,
(int)(d->rom >> 32), (int)d->rom);
temp = w1_read_temp(d, 0);
pp_printf("temp: %d.%04d\n", temp >> 16,
(int)((temp & 0xffff) * 10 * 1000 >> 16));
}
}
return 0;
}
DEFINE_WRC_COMMAND(w1) = {
.name = "w1",
.exec = cmd_w1,
};