This article describes how implement a onewire slave device into an Arduino Nano
The simple implementation makes the Arduino Nano able to use i2c to communicate with the ultrasonic distance sensor SRF02, and present the result to the OWFS environment
The implemntation also includes two ports to control LED on the Arduino nano.

The project includes the following steps:

To accomplice this, I have made use of greate work from:

Modify OWFS to accept new Onewire Slave:

Overview:

Getting started

Change to source directory:

cd /usr/src

Get source from sourceforge.net and unpack:

wget http://sourceforge.net/projects/owfs/files/owfs/3.1p0/owfs-3.1p0.tar.gz/download
tar zxf download
goto top

Prepare for compilation:

Go into source directory:

cd owfs_3.1p0

For compilation, update and install requirements:

apt-get update
apt-get upgrade -y
apt-get -y install automake autoconf autotools-dev gcc-4.7 libavahi-client-dev libtool libusb-dev
apt-get -y install libusb-1.0-0-dev libfuse-dev swig python2.7-dev tcl8.5-dev php5-dev i2c-tools

Find the file libusb.h and copy to /usr/src/owfs_3.1p0/module/owlib/src/include.

Obs!

At this point, make sure you can compile the original source

./configure
make -j 4
make install

The executable modules are now in /opt/owfs

goto top

Make changes and additions to source:

To accomodate a new OneWire device,
the following files needs to be created:

module/owlib/src/c/ow_arduino.c

Create file in editor:

node /usr/src/owfs_3.1p0/module/owlib/src/c/ow_arduino.c

insert the following into the file:

/*
    OWFS -- One-Wire filesystem
    OWHTTPD -- One-Wire Web Server
    Written 2003 Paul H Alfille
	email: paul.alfille@gmail.com
	Released under the GPL
	See the header file: ow.h for full attribution
	1wire/iButton system from Dallas Semiconductor
*/

/* General Device File format:
    This device file corresponds to a specific 1wire/iButton chip type
	( or a closely related family of chips )

	The connection to the larger program is through the "device" data structure,
	  which must be declared in the acompanying header file.

	The device structure holds the
	  family code,
	  name,
	  number of properties,
	  list of property structures, called "filetype".

	Each filetype structure holds the
	  name,
	  estimated length (in bytes),
	  aggregate structure pointer,
	  data format,
	  read function,
	  write funtion,
	  generic data pointer

	The aggregate structure, is present for properties that several members
	(e.g. pages of memory or entries in a temperature log. It holds:
	  number of elements
	  whether the members are lettered or numbered
	  whether the elements are stored together and split, or separately and joined
*/

/* Changes
    7/2004 Extensive improvements based on input from Serg Oskin
*/

#include 
#include "owfs_config.h"
#include "ow_arduino.h"

/* ------- Prototypes ----------- */

/* ARDUINO switch */
READ_FUNCTION(FS_r_ledstate);
WRITE_FUNCTION(FS_w_ledstate);
READ_FUNCTION(FS_r_pio);
WRITE_FUNCTION(FS_w_pio);
READ_FUNCTION(FS_r_dist);


/* DS2423 counter */
//READ_FUNCTION(FS_r_memory);
//WRITE_FUNCTION(FS_w_memory);
//READ_FUNCTION(FS_r_status);
//READ_FUNCTION(FS_r_application);
//WRITE_FUNCTION(FS_w_application);

#define _DS2430A_MEM_SIZE 4

/* ------- Structures ----------- */

static struct aggregate A2413 = { 2, ag_letters, ag_aggregate };

static struct filetype ARDUINO[] = {
	F_STANDARD,
	{"ledstate", PROPERTY_LENGTH_UNSIGNED, NON_AGGREGATE, ft_unsigned, fc_volatile, FS_r_ledstate, FS_w_ledstate, INVISIBLE, NO_FILETYPE_DATA, },
	{"LED", PROPERTY_LENGTH_BITFIELD, &A2413, ft_bitfield, fc_link, FS_r_pio, FS_w_pio, VISIBLE, NO_FILETYPE_DATA, },
	{ "DIST", PROPERTY_LENGTH_UNSIGNED, NON_AGGREGATE, ft_unsigned, fc_link, FS_r_dist, NO_WRITE_FUNCTION, VISIBLE, NO_FILETYPE_DATA, },
};

DeviceEntryExtended(E2, ARDUINO, DEV_resume | DEV_ovdr, NO_GENERIC_READ, NO_GENERIC_WRITE);

/* 2413 Commands */
#define _1W_PIO_ACCESS_READ 0xF5
#define _1W_PIO_ACCESS_WRITE 0x5A
#define _1W_DIST_ACCESS_READ 0x55
#define _1W_2413_LATCH_MASK 0x0A
#define _1W_2413_CONFIRMATION 0xAA
#define _1W_COUNTER_FILL 0x00

/* Persistent storage */
Make_SlaveSpecificTag(CUM, fc_persistent);	// cumulative

/* ------- Functions ------------ */

/* ARDUINO */

//-----------------------------------------------------------------
/* 2413 */
//-----------------------------------------------------------------

static GOOD_OR_BAD OW_write(BYTE data, const struct parsedname *pn);
static GOOD_OR_BAD OW_read(BYTE * data, const struct parsedname *pn);
static GOOD_OR_BAD OW_readdist(BYTE * data, const struct parsedname *pn);
static UINT SENSED_state(UINT status_bits);
static UINT LATCH_state(UINT status_bits);

static ZERO_OR_ERROR FS_r_ledstate(struct one_wire_query *owq)
{
	/* surrogate property
	bit 0 PIOA pin state
	bit 1 PIOA latch state
	bit 2 PIOB pin state
	bit 3 PIOB latch state
	*/
	BYTE ledstate ;

	if ( OW_read( &ledstate, PN(owq) ) ) {
		return -EINVAL ;
	}

	OWQ_U(owq) = ledstate ;
	return 0 ;
}

static ZERO_OR_ERROR FS_r_diststate(struct one_wire_query *owq)
{
	BYTE diststate;

	if (OW_readdist(&diststate, PN(owq))) {
		return -EINVAL;
	}

	OWQ_U(owq) = diststate;
	return 0;
}

static ZERO_OR_ERROR FS_w_ledstate(struct one_wire_query *owq)
{
	UINT pio = OWQ_U(owq) ;

	return OW_write( pio, PN(owq) ) ? -EINVAL : 0 ;
}

/* bites 1 and 3 */
static ZERO_OR_ERROR FS_r_pio(struct one_wire_query *owq)
{
	UINT ledstate = 0 ;
	ZERO_OR_ERROR z_or_e = FS_r_sibling_U( &ledstate, "ledstate", owq ) ;

	// bits 1>0 and 3->1
	// complement
	OWQ_U(owq) = LATCH_state( ledstate ) ^ 0x03 ;
	return z_or_e ;
}

static ZERO_OR_ERROR FS_r_dist(struct one_wire_query *owq)
{
	UINT diststate = 0;
	ZERO_OR_ERROR z_or_e = OW_readdist(&diststate, PN(owq));
	OWQ_U(owq) = diststate;
	return z_or_e;
}

/* write ARDUINO switch -- 2 values*/
static ZERO_OR_ERROR FS_w_pio(struct one_wire_query *owq)
{
	// complement
	ZERO_OR_ERROR ret = FS_w_sibling_U( OWQ_U(owq) ^ 0x03 , "ledstate", owq );
	
	if ( ret == 0 ) {
		// Able to write, but ledstate is potentially now incorrect 
		// since we use a different method to set pios
		FS_del_sibling( "ledstate", owq ) ;
		return 0 ;
	}
	return ret ;
}

static GOOD_OR_BAD OW_readdist(BYTE * data, const struct parsedname *pn)
{
	BYTE cmd[] = { _1W_DIST_ACCESS_READ, };
	BYTE resp[1];
	struct transaction_log t[] = {
		TRXN_START,
		TRXN_WRITE1(cmd),
		TRXN_READ1(resp),
		TRXN_END,
	};

	RETURN_BAD_IF_BAD(BUS_transaction(t, pn));

	data[0] = resp[0];
	return gbGOOD;
}

static GOOD_OR_BAD OW_read(BYTE * data, const struct parsedname *pn)
{
	BYTE cmd[] = { _1W_PIO_ACCESS_READ, };
	BYTE resp[1] ;
	struct transaction_log t[] = {
		TRXN_START,
		TRXN_WRITE1(cmd),
		TRXN_READ1(resp),
		TRXN_END,
	};

	RETURN_BAD_IF_BAD(BUS_transaction(t, pn)) ;

	// High nibble the complement of low nibble?
	// Fix thanks to josef_heiler
	if ((resp[0] & 0x0F) != ((~resp[0] >> 4) & 0x0F)) {
		return gbBAD;
	}

	data[0] = resp[0] & 0x0F ;
	return gbGOOD;
}

/* write status byte */
/* top 6 bits are set to 1, complement then sent */
static GOOD_OR_BAD OW_write(BYTE data, const struct parsedname *pn)
{
	BYTE data_masked = data | 0xFC ;
	BYTE cmd[] = { _1W_PIO_ACCESS_WRITE, data_masked, ~data_masked, };
	BYTE chk[1];
	BYTE confirm[] = { _1W_2413_CONFIRMATION, } ;
	struct transaction_log t[] = {
		TRXN_START,
		TRXN_WRITE3(cmd),
		TRXN_READ1(chk),
		TRXN_COMPARE(chk,confirm,1),
		TRXN_END,
	};

	return BUS_transaction(t, pn) ;
}

// ledstate -> sense
static UINT SENSED_state(UINT status_bits)
{
	return ((status_bits & 0x01) >> 0) | ((status_bits & 0x04) >>1);
}

// ledstate -> latch
static UINT LATCH_state(UINT status_bits)
{
	return ((status_bits & 0x02) >> 1) | ((status_bits & 0x08) >>2);
}

save and exit editor

goto top

module/owlib/src/include/ow_arduino.h

Create file in editor:

node /usr/src/owfs_3.1p0/module/owlib/src/include/ow_arduino.h

insert the following into the file:

/*
    OWFS -- One-Wire filesystem
    OWHTTPD -- One-Wire Web Server
    Written 2003 Paul H Alfille
	email: paul.alfille@gmail.com
	Released under the GPL
	See the header file: ow.h for full attribution
	1wire/iButton system from Dallas Semiconductor
*/

#ifndef OW_ARDU_H
#define OW_ARDU_H

#ifndef OWFS_CONFIG_H
#error Please make sure owfs_config.h is included *before* this header file
#endif
#include "ow_standard.h"

/* ------- Structures ----------- */

DeviceHeader(ARDUINO);

#endif

save and exit editor

  • module/owlib/src/include/ow_arduino.h
  • The following source files needs to be modified:

    goto top

    module/owlib/src/c/ow_tree.c

    Modify file in editor:

    node /usr/src/owfs_3.1p0/module/owlib/src/c/ow_tree.c

    Modify the following into the file:

    find in file:

    Device2Tree( & d_Example_slave, ePN_real);

    Insert after that line:

    Device2Tree( & d_ARDUINO, ePN_real);

    save and exit editor

    goto top

    module/owlib/src/include/ow_devices.h

    Modify file in editor:

    node /usr/src/owfs_3.1p0/module/owlib/src/include/ow_devices.h

    Modify the following into the file:

    find in file:

    #include "ow_bae.h" // Pascal Baerten's PIC-based device

    Insert after that line:

    #include "ow_arduino.h" // My arduino-based slave

    save and exit editor

    goto top

    module/owlib/src/include/Makefile

    Modify file in editor:

    node /usr/src/owfs_3.1p0/module/owlib/src/include/Makefile

    Modify the following into the file:

    find line in file:

    ow_arg.h \

    Insert new line after that line:

    ow_arduino.h \

    save and exit editor

    goto top

    module/owlib/src/include/Makefile.in

    Modify file in editor:

    node /usr/src/owfs_3.1p0/module/owlib/src/include/Makefile

    Modify the following into the file:

    find line in file:

    ow_arg.h \

    Insert line after that line:

    ow_arduino.h \ 

    save and exit editor

    goto top

    module/owlib/src/c/Makefile

    Modify file in editor:

    node /usr/src/owfs_3.1p0/module/owlib/src/c/Makefile

    Modify the following into the file:

    find line in file:

    ow_api.lo ow_avahi_announce.lo ow_avahi_browse.lo \

    Change that line to:

    ow_api.lo ow_arduino.lo ow_avahi_announce.lo ow_avahi_browse.lo \

    find line in file:

    ow_arg.c \

    Insert new line after that line:

    ow_arduino.c \

    find line in file:

    include ./$(DEPDIR)/ow_api.Plo

    Insert new line after that line:

    include ./$(DEPDIR)/ow_arduino.Plo 

    save and exit editor

    goto top

    module/owlib/src/c/Makefile.in

    Modify file in editor:

    node /usr/src/owfs_3.1p0/module/owlib/src/c/Makefile.in

    Modify the following into the file:

    find line in file:

    ow_api.lo ow_avahi_announce.lo ow_avahi_browse.lo \

    Change that line to:

    ow_api.lo ow_arduino.lo ow_avahi_announce.lo ow_avahi_browse.lo \

    find line in file:

    ow_api.c \

    Insert new line after that line:

    ow_arduino.c \

    find line in file:

    @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ow_api.Plo@am__quote@

    Insert new line after that line:

    @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ow_arduino.Plo@am__quote@

    save and exit editor

    goto top

    module/owlib/src/c/Makefile.am

    Modify file in editor:

    node /usr/src/owfs_3.1p0/module/owlib/src/c/Makefile.am

    Modify the following into the file:

    find line in file:

    ow_api.c \

    Insert line after that line:

    ow_arduino.c \ 

    save and exit editor

    goto top

    Compile OWFS

    ./configure
    make -j 4
    make install	

    Arduino program

    Create a new Arduino project

    Insert into the main file:

    #include 
    #include "Arduino.h"
    #include "LowLevel.h"
    #include "OneWireSlave.h"
    #include 
    
    //-------------------------------------------------------
    //	Definitions and constants
    //-------------------------------------------------------
    
    #define SRF_ADDRESS 0x70		// Address of the SRF02
    #define CMD         0x00		// Command byte, values of 0 being sent with write have to be masked as a byte to stop them being misinterpreted as NULL this is a bug with arduino 1.0
    #define RANGEBYTE   0x02		// Byte for start of ranging data
    #define CMD_LedRead 0xF5
    #define CMD_LedWrite 0x5A
    #define CMD_ReadScratchpad 0xBE
    #define CMD_WriteScratchpad 0x4E
    #define CMD_CopyScratchpad 0x48
    #define CMD_RecallMemory 0xB8
    
    #define A 13
    #define B 12
    #define OW 2
    
    Pin oneWireData(OW);	//	OneWire input
    Pin ledA(A);		    //	LED A
    Pin ledB(B);		    //	LED B
    
    const int i2c_interval = 1000;
    const byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
    
    //-------------------------------------------------------
    //	Variables
    //-------------------------------------------------------
    
    class tankClass {
      public:
        float radius;
        float length;
        float height;
        int offset;
        int volume;
        int range;
        int level;
    }  tank;
    
    tankClass tankDefault  = { 32.5, 150.0, 137.0, 19, 0, 0, 0 }; //  radius, length, height, offset, ....-
    
    byte LedStatus = 0;
    byte buffer[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    byte CurrCmd = 0x00;
    int pointer = 0;
    int loopcounter = 0;
    int newRange = 0;
    int lastRange = 0;
    
    String msg = "Starting";
    
    byte memory[15];
    
    //-------------------------------------------------------
    //	Functions
    //-------------------------------------------------------
    
    byte * Int2Bytes(int val) {
      byte * buf = new byte[2];
      buf[0] = (byte)(val & 255);
      buf[1] = (byte)(val >> 8);
      return buf;
    }
    
    void Int2Buf(byte * buf, int val) {
      buf[0] = (byte)(val & 255);
      buf[1] = (byte)(val >> 8);
    }
    
    int toInt(byte buf[]) {
      return (buf[0] + (buf[1] << 8));
    }
    
    float toFloat(byte buf[]) {
      return (buf[0] + (buf[1] << 8));
    }
    
    float area(float height, float radius) {
      float v = acos(1 - height / radius) * 2;	// i radianer
      float retval = radius * radius / 2 * (v - sin(v));
      return (retval);
    }
    
    void setLed(byte x) {
      byte a = x & 1;
      byte b = (x & 2) >> 1;
      if (a == 0) { a = 2; }
      if (b == 0) { b = 2; }
      byte c = (b << 2) + a;
      LedStatus = ((~c) << 4) + c;
      if (a & 1) { ledA.writeHigh(); }
      else { ledA.writeLow(); };
      if (b & 1) { ledB.writeHigh(); }
      else { ledB.writeLow(); };
    }
    
    void do_i2c() {
      lastRange = newRange;
      Wire.beginTransmission(SRF_ADDRESS);
      Wire.write(CMD);
      Wire.write(0x51);
      Wire.endTransmission();
      delay(100);
      Wire.beginTransmission(SRF_ADDRESS);
      Wire.write(RANGEBYTE);
      Wire.endTransmission();
      Wire.requestFrom(SRF_ADDRESS, 2);
      while (Wire.available() < 2);
      byte highByte = Wire.read();
      byte lowByte = Wire.read();
      newRange = ((highByte << 8) + lowByte);
      //newRange = getRange();
      if ((newRange < lastRange * 1.2) && (newRange > lastRange * .8)) { tank.range = (newRange); }
      tank.level = tank.height + tank.offset - tank.range;
      float a =
        area(min(tank.level, tank.radius), tank.radius) +
        max(min(tank.level - tank.radius, tank.height - 2 * tank.radius), 0) * 2 * tank.radius +
        area(tank.radius, tank.radius) - area(min((tank.height - tank.level), tank.radius), tank.radius);
      tank.volume = round(a * tank.length / 1000);
    }
    
    //-------------------------------------------------------
    //	Events and event Functions
    //-------------------------------------------------------
    
    void ow_reset() {			//	Reset receive state and buffer
      CurrCmd = 0x00;
      pointer = 0;
    }
    
    void owReceive(OneWireSlave::ReceiveEvent evt, byte data) {
      switch (evt) {
        case OneWireSlave::RE_Reset: ow_reset(); break;
        case OneWireSlave::RE_Error: ow_reset(); break;
        case OneWireSlave::RE_Byte:
          if (CurrCmd == 0x00) {
            switch (data) {
              case CMD_LedRead: OneWire.write(&LedStatus, 1, NULL); break;
              case CMD_LedWrite:
              case CMD_RecallMemory:
              case CMD_ReadScratchpad:
              case CMD_WriteScratchpad:
              case CMD_CopyScratchpad:
                CurrCmd = data; break;
              default: ow_reset(); break;
            }
          }
          else {
            buffer[pointer++] = data;
            switch (CurrCmd) {
              case CMD_LedWrite: if (pointer == 2) { setLed(buffer[1]); ow_reset(); }; break;
              case CMD_ReadScratchpad:		//	master will read
                if (pointer == 1) {
                  Int2Buf(&memory[0], (int)(tank.offset * 10));
                  Int2Buf(&memory[2], (int)(tank.radius * 10));
                  Int2Buf(&memory[4], (int)(tank.height * 10));
                  Int2Buf(&memory[6], (int)(tank.length * 10));
                  Int2Buf(&memory[8], (int)(tank.volume * 10));
                  Int2Buf(&memory[10], (int)(tank.level * 10));
                  Int2Buf(&memory[12], (int)(tank.range * 10));
                  memory[14] = OneWire.crc8(&memory[0], 14);
                  OneWire.write(&memory[0], 15, NULL);
                  ow_reset();
                };
                break;
              case CMD_WriteScratchpad:		//	master will write
                if (pointer == 15) {
                  tank.offset = (int) toInt(&buffer[1]) / 10;
                  tank.radius = (float) toFloat(&buffer[3])/10;
                  tank.height = (float) toFloat(&buffer[5])/10;
                  tank.length = (float) toFloat(&buffer[7])/10;
                  EEPROM.put(0, tank);
                  ow_reset();
                }
                break;
              case CMD_CopyScratchpad: if (pointer == 1) { ow_reset(); }; break;
              case CMD_RecallMemory: if (pointer == 1) { ow_reset(); }; break;
              default: ow_reset(); break;
            }
          }
      }
    }
    
    //-------------------------------------------------------
    //	Setup
    //-------------------------------------------------------
    
    void setup()
    {
      ledA.outputMode();		//	Init Led A
      ledB.outputMode();		//	Init Led B
      Serial.begin(9600);
      LedStatus = (digitalRead(B)<<1) + digitalRead(A);
      setLed(LedStatus);		//	Set LED's to LedStatus
      //Serial.println(digitalRead(12));
      //Serial.println(digitalRead(13)); 
    
      EEPROM.get(0, tank);
      if ( isnan(tank.radius)) {
        tank = tankDefault;
        EEPROM.put(0, tank);
      }
      if ((tank.radius < 25.0) || (tank.length < 100.0) || (tank.height < 100.0)) {
        tank  = tankDefault;
        EEPROM.put(0, tank);
      }
    
      Wire.begin();			//	Init I2C
      OneWire.setReceiveCallback(&owReceive);				//	Set Onewire callback
      OneWire.begin(owROM, oneWireData.getPinNumber());	//	Init Onewire listener
      delay(100);				//	Settle status
    
      //tank = { tankRadius, tankLength, tankHeight, Offset };
      //newRange = getRange();
      //tank.range = newRange;
      do_i2c();
    }
    
    //-------------------------------------------------------
    //	Main Loop
    //-------------------------------------------------------
    
    void loop() {
      //if (msg.length() > 0) {
      //	clear();
      //	msg = "";
      //}
      if (loopcounter == 0) {
        do_i2c();
        /*
        		Serial.write(0x0C);
        		//Serial.write(01);
        		delay(100);
        		msg = "Volume:   " + String(tank.volume, DEC);
        		Serial.println( msg);
        		msg = "Level:    " + String (tank.level, DEC);
        		Serial.println(msg);
        		msg = "Range:    " + String(tank.range, DEC);
        		Serial.println(msg);
        		msg = "Offset:   " + String(tank.offset, DEC);
        		Serial.println(msg);
        		Serial.println("-----");
        */
      }
      if (loopcounter++ >= i2c_interval) loopcounter = 0;
      delay(1);
    }

    exit, compile and upload

    ----------------------------------------------------------