Emulated Onewire DS18b20 unable to be read by Teltonika FM1120 device

Is that a real or emulated DS2401 to Teltonika? From the voltage levels, I would guess it’s a real one. If it’s a real one, can you get the emulated DS2401?

Here’s a few notes regarding the traces:


  1. There’s something funny about the voltage levels between the Arduino and the Teltonika. There seems to be a ground offset. How are you powering the Arduino? I assume the Teltonika is just plugged into mains.

This is why I asked about the DS2401 video, because it appears to be signalling 0V-4.5V.

Hmmm, the Real DS18B20 to Teltonika shows 0V-4V signalling. In that case, the DS18B20 is certainly referenced to the Teltonika.

The emulated DS18B20 to Arduino is also 0V-4V. You can even see when the pullup lets the signal rise to 5V:

emulated to Arduino.jpg

This only happens for a short time, when both Arduinos have the digital pin set as INPUT.

  1. I have annotated the emulated DS18B20 (purple) to Teltonika (red) trace:

emulated to Teltonika.jpg

A RESET is sent, the Arduino responds, a SEARCH is transmitted, but the Arduino does not respond. There is a short glitch, but the Teltonika would almost certainly read that as a 1-1 response, which ends the search process. Then it goes back to doing a RESET.

  1. For debugging, it really helps to see the waveforms from the real starting point, and at a common scale. I would suggest using the 100uS/div scale, which is 20uS/tick. The configuration you want, emulated DS18B20 to Teltonika is too coarse at 500uS/div. Other traces were at 250uS/div.

I’m not familiar with this scope, but you might be able to do a SINGLE trigger to capture some data, then scroll through it. This was a problem for “Emulated DS18B20 to arduino” video… I really can’t tell what I’m looking at because there’s no RESET, SEARCH or MATCH command to start at. BTW, this scope does have a way to transfer scope screen shots to your PC, which could then be attached to the post (program download required). Pics or videos are still better than nothing, though.

  1. The Teltonika seems to detect that there is only one device attached, and it issues a SKIP to talk to the real DS18B20 without addressing:

real to Teltonika 0012.jpg

However, I do not think that OneWireHub correctly implements the SKIP command, at least according to this code:

       if (this->SelectElm != 0)
          this->SelectElm->duty( this );
        return TRUE; 
        break;
        
      // SKIP ROM
      case 0xCC:
Serial.println("CC");
        this->SelectElm = 0x00;
        return TRUE;

This means that even if the Arduino responds to the SEARCH command, it will ignore all the SKIP commands, without working on OneWireHub.


To summarize:

  1. There may be a grounding issue, as there seems to be some offsets in the traces. Please describe your setup, from the mains to the devices. The scope should be plugged into the same mains circuit as the Teltonika.

[edit]I see the Teltonika is an automotive system. Are you using an isolated 10V-30V power supply?[/edit]

There could also be some issue with the Teltonika signal ground. An isolated 5V power supply for the emulating Arduino would probably fix the offsets, and may let the Arduino get past the waitTimeSlot after the SEARCH command. You would have to disconnect the Arduino from the USB port, except when you’re programming it. This means you would not have Serial debug capability on your PC. Are you using the ground clip on the scope probe?

  1. Unfortunately, OneWireHub does not implement the SKIP command that is used by the Teltonika. I took a look at OneWireSlave, and I think it was the starting point for OneWireHub. It has the rollover problem, but it appears to implement the SKIP command.

  2. I am still suspicious of the Arduino timing code. You should pick a digital pin and use that to indicate when the wait begins (digitalWrite HIGH) and when it gives up (LOW). With a second channel probe hooked to that pin, we can see the actual time that it waits (I’m predicting that it’s too quick), and compare it with the rest of the waveform (and that glitch).

And now you know how hard it is to emulate a piece of HW! :slight_smile: If anybody else has some ideas, please chime in.

Cheers,
/dev

Is that a real or emulated DS2401 to Teltonika? From the voltage levels, I would guess it's a real one. If it's a real one, can you get the emulated DS2401?

That's a emulated one, using Arduino Uno.

There's something funny about the voltage levels between the Arduino and the Teltonika. There seems to be a ground offset. How are you powering the Arduino? I assume the Teltonika is just plugged into mains.

This is why I asked about the DS2401 video, because it appears to be signalling 0V-4.5V.

I powered the Arduino Uno by USB to my laptop. Teltonika's power source is a 12V adapter. The link below is the manual for the Teltonika device. See page 16 of the manual. The power source is 10-30 volts.

http://plantron.gr/sites/plantron.gr/files/pdf/FM1120%20User%20Manual%20v1.12.pdf

There may be a grounding issue, as there seems to be some offsets in the traces. Please describe your setup, from the mains to the devices. The scope should be plugged into the same mains circuit as the Teltonika.

The connections are: (Arduino Uno) (Teltonika) Arduino digital pin 9 - 1-wire Data ( pin 8 ) GND - GND

Arduino Uno is powered by a USB plugged into my laptop, while Teltonika is powered by a 12V adapter. The probe is connected to the data line (arduino digital pin 9/teltonika's 1-wire data). The probe's ground is connected together with Arduino's uno ground and teltonika's.

There could also be some issue with the Teltonika signal ground. An isolated 5V power supply for the emulating Arduino would probably fix the offsets, and may let the Arduino get past the waitTimeSlot after the SEARCH command. You would have to disconnect the Arduino from the USB port, except when you're programming it. This means you would not have Serial debug capability on your PC. Are you using the ground clip on the scope probe?

Yup~

Unfortunately, OneWireHub does not implement the SKIP command that is used by the Teltonika. I took a look at OneWireSlave, and I think it was the starting point for OneWireHub. It has the rollover problem, but it appears to implement the SKIP command.

I will take a look at the OneWireSlave again. Which version should I use?

And now you know how hard it is to emulate a piece of HW!

Very hard indeed.

The Arduino Uno is powered by a USB plugged into my laptop

If your laptop power adapter does not have a ground plug, and/or it connects with a two-conductor barrel plug , it is probably isolated. Same for the Teltonika 12V DC adapter.

I would say you could assume they are isolated, but we all know what that can make us... :) Some cheap adapters are not really isolated. Do you know how to check for that?

You know, if you don't have an isolated Power Supply for the Arduino, it can take 12V DC max. Could you power it with the Teltonika Power Supply and disconnect it from the USB? (Be sure to check the voltage before connecting the Arduino.) You could blink the LED or set some digital pins if the emulation test works, and then check those pins with the scope. That would eliminate any ground differences, and the scope should confirm that.

I will take a look at the OneWireSlave again. Which version should I use?

Oy! If it were me, I would start with the github version and diff it with newer versions I linked to earlier. Although it requires understanding why certain changes were made, at each step, you would not have to find a known bug again... and decide how to fix it.

Some of these changes are Teensy-specific, but they are probably wrapped with conditional compilation (#if et al), or they don't affect the standard Uno/Nano/Mega platforms.

I also think that reviewing the incremental changes will help you to understand the code, and that will help as you try to get OneWireSlave working. When you do get it to work, you can submit it back to the author, or fork your own version.

It will also give you a starting point for getting OneWireHub to work, if you ever need to emulate multiple devices. It's currently very wasteful with resources, though.

I hope that addresses your questions, and sorry if I am telling you something you already know.

IMO, the two things I would tackle first are:

1) Why is there a ground offset?

2) Why is there a glitch after the SEARCH command?

The first may fix the second. If not, you should start using that second channel and extra pins to figure out what OneWireHub (or OneWireSlave) is doing. Maybe it takes too long to get to sendBit? Maybe it doesn't really wait 120uS?

Cheers, /dev

You know, if you don't have an isolated Power Supply for the Arduino, it can take 12V DC max. Could you power it with the Teltonika Power Supply and disconnect it from the USB?

]

It's 12.11V. Sorry for the dumb question, should I try it?

4) The Teltonika seems to detect that there is only one device attached, and it issues a SKIP to talk to the real DS18B20 without addressing:

I have just realised something... In post 21, you have mentioned that the Teltonika device uses the SKIP ROM command to talk with the real DS18B20.

The oscillogram shows 0011 0011... isn't that 0x33 (READ ROM command)? Correct me if I am wrong...

Some update…

I changed

#define TIMESLOT_WAIT_RETRY_COUNT microsecondsToClockCycles(120) / 10L

to

#define TIMESLOT_WAIT_RETRY_COUNT microsecondsToClockCycles(650) / 10L

The errno becomes 0, however it is still stuck at 0xF0. Below shows the serial:

F0
errno==0
F0
errno==0
F0
errno==0
F0
errno==0

If your laptop power adapter does not have a ground plug, and/or it connects with a two-conductor barrel plug , it is probably isolated. Same for the Teltonika 12V DC adapter.

I would say you could assume they are isolated, but we all know what that can make us… :slight_smile: Some cheap adapters are not really isolated. Do you know how to check for that?

My laptop power adapter connects with a two-conductor barrel plug. For the Teltonika, the adapter’s output is two crocodile clips (one gnd and one +12V).

OneWireHub.cpp (22.6 KB)

Chaps,

I had a similar problem with the FM1120. Using a protocol analyser, it turned out that the 1120 was sending reset pulses that were too short -- Outside the Dallas one wire spec (430 microSeconds -- should be greater than 480). As a result the arduino library did not register a reset pulse and consequently did not send back a presence signal.

I had to mod the OneWire arduino library to get it to work --

Cheers

I had a similar problem with the FM1120. Using a protocol analyser, it turned out that the 1120 was sending reset pulses that were too short -- Outside the Dallas one wire spec (430 microSeconds -- should be greater than 480). As a result the arduino library did not register a reset pulse and consequently did not send back a presence signal.

I had to mod the OneWire arduino library to get it to work --

Hi defjam,

Mind sharing your modded library? :)

Are you also emulating a DS18B20?

the 1120 was sending reset pulses that were too short

Dang, I wish that was it. As you can see from the traces, the 1120 reset pulse looks like about 500uS. And the OneWireHub does recognize the pulse as a reset, because it announces presence and proceeds to recvAndProcessCmd. Thanks for the suggestion, though.

Something I just thought of… the debug prints could be affecting the timing. In general, you can only set a variable in the timing-critical section, then check the variable somewhere else. For example:

uint8_t lastCmd = 0; // global

bool OneWireHub::recvAndProcessCmd() { 
  byte addr[8]; 
  bool flag;
  
  for (;;) {
    uint8_t cmd = recv();
    lastCmd = cmd; // save it for later

    switch (cmd) {
      // Search rom
      case 0xF0:
//	Serial.println("F0");   can't do this now!
        search();
        delayMicroseconds(6900); //1100 - 6900

The lastCmd declaration will have to be above the place where you use it (e.g., waitForRequest), or externed in the .INO:

extern uint8_t lastCmd;

void loop()
{
    ...existing code...
  if (lastCmd != 0) {
    Serial.print( F("cmd = ") );
    Serial.println( lastCmd );
    lastCmd = 0;
  }
    ...
}

I think I’d do it in waitForRequest, like this:

uint8_t lastCmd = 0; // global, declared up here   <--------

bool OneWireHub::waitForRequest(bool ignore_errors)
{
  errno = ONEWIRE_NO_ERROR;

  for (;;) {
    //delayMicroseconds(40);
    //Once reset is done, it waits another 30 micros
    //Master wait is 65, so we have 35 more to send our presence now that reset is done
    if (!waitReset(0) ) {
      Serial.println( F("!waitreset") );
      continue;
    }

    //Reset is complete, tell the master we are prsent
    // This will pull the line low for 125 micros (155 micros since the reset) and 
    //  then wait another 275 plus whatever wait for the line to go high to a max of 480
    // This has been modified from original to wait for the line to go high to a max of 480.
    if (!presence() ) {
      Serial.println( F("!presence") );
      continue;
    }

    //Now that the master should know we are here, we will get a command from the line
    //Because of our changes to the presence code, the line should be guranteed to be high
    if (recvAndProcessCmd() ) {
      Serial.println( F("OK") );
      return TRUE;
    }

    if ((errno == ONEWIRE_NO_ERROR) ) {
      Serial.println( F("no err") );
      continue;
    }

    if (lastCmd != 0) {          //  <----
      Serial.print( F("cmd = ") );
      Serial.println( lastCmd );
      lastCmd = 0;
    }

    Serial.println(errno);
    Serial.println("RESTART");
    return FALSE;
  }
}

I formatted a little, used the F macro to save RAM, and got rid of some of the unnecessary else clauses. eew.

This could explain why it doesn’t respond. Or not… :frowning:

Cheers,
/dev

wongsm7:
It’s 12.11V… should I try it?

If that’s the no-load voltage (i.e., not connected to the Teltonika), you’re probably ok, as Power Supplies tend to float high. If it’s connected to the Teltonika, you’re still probably ok, but to be perfectly safe, you could add a series diode to drop it to 11.4V or so. Almost any diode will work here, as it’s only dissipating ~100mW: anything from the 1N4000 series, or even a 1N4148 which is rated for 200mA.

Regarding the retry count, 650 is too long, try just 10% higher:

#define TIMESLOT_WAIT_RETRY_COUNT microsecondsToClockCycles(132) / 10L

I have just realised something… In post 21, you have mentioned that the Teltonika device uses the SKIP ROM command to talk with the real DS18B20.

The oscillogram shows 0011 0011… isn’t that 0x33 (READ ROM command)? Correct me if I am wrong…

Oh yes, LSB gets sent first, so they’re in reverse order. I couldn’t remember what 1-wire specifies, then I saw the SEARCH command bits were coming out as 00001111. It’s at the end of section 1 in the TI document:

When transferring a byte, the least significant bit is transferred first.

Cheers,
/dev

Oh yes, LSB gets sent first, so they’re in reverse order. I couldn’t remember what 1-wire specifies, then I saw the SEARCH command bits were coming out as 00001111. It’s at the end of section 1 in the TI document:

Ahh, I see. So it’s 1100 1100 (0xCC).

Something I just thought of… the debug prints could be affecting the timing. In general, you can only set a variable in the timing-critical section, then check the variable somewhere else.

I have tried that way, it shows the same results when plugged to the Teltonika.

cmd = F0
7
RESTART
cmd = F0
7
RESTART
cmd = F0
7
RESTART
cmd = F0
7
RESTART

OneWireHub.cpp (22.6 KB)

it shows the same results

-_- Fine. Well, I guess it's down to timing.

As I was finishing up this post, I uncovered something:

    //Wait for a fall form 1 to 0 on the line for timeout duration
    retries = TIMESLOT_WAIT_RETRY_COUNT;
    while ( DIRECT_READ(reg, mask));
        if (--retries == 0)
            return 20;

Yes, there's a serious error RIGHT THERE. Look closer:

    while ( DIRECT_READ(reg, mask));

Sheesh! That extra semicolon means it does not decrement the retry count in the loop. So, delete that and try it. It is in both waitTimeSlot and waitTimeSlotRead. It is also in OneWireSlave! You might try OneWireSlave to see if it works without the semicolon.

If that doesn't work, here's a few more suggestions...

After it receives the SEARCH cmd, it should be trying to send its address. 0x28 is the first byte, so it should be trying to respond with a 01 sequence. That's the LSB (a 0) and its complement (a 1).

I started writing down the call nesting, and I think there is an ambiguity in the code. Here's where I started:

waitForRequest
  recvAndProcessCmd case 0xF0:
    search case 2:
      sendBit(FALSE)
        waitTimeSlot
          ...
          while (line is low)
            if (--retries == 0)
              return 10;

        if (wait == 10)
          errno = 7

      sendBit(TRUE)
        waitTimeSlot
          ...
          while (line is low)
            if (--retries == 0)
              return 10;

        if (wait == 10)
          errno = 7

      bit_recv = recvBit();
        waitTimeSlot[b]Read[/b]
          ...
          while (line is low)
            if (--retries == 0)
              return 10;

        if (wait == 10)
          errno = 7

      if (errno != ONEWIRE_NO_ERROR)
        return FALSE;

I noticed that both sendBit and recvBit are setting the same error code 7, and it's not checked in search until after sendBit. I remembered seeing a separate error code for WRITE timeout in the H file, but it's never used!

First, add another errno to the H file:

#define ONEWIRE_NO_ERROR 0
#define ONEWIRE_READ_TIMESLOT_TIMEOUT 1
#define ONEWIRE_WRITE_TIMESLOT_TIMEOUT_LOW 2
#define ONEWIRE_WRITE_TIMESLOT_TIMEOUT_HIGH 3
#define ONEWIRE_WAIT_RESET_TIMEOUT 4
#define ONEWIRE_VERY_LONG_RESET 5
#define ONEWIRE_VERY_SHORT_RESET 6
#define ONEWIRE_PRESENCE_LOW_ON_LINE 7
#define ONEWIRE_READ_TIMESLOT_TIMEOUT_LOW 8
#define ONEWIRE_READ_TIMESLOT_TIMEOUT_HIGH 9

Instead of just "ONEWIRE_WRITE_TIMESLOT_TIMEOUT 2", we now have a LOW and a HIGH error code, and be sure renumber all the later codes up by one. Next, return the WRITE error code from sendBit:

void OneWireHub::sendBit(uint8_t v) {
    ...
      if (wt == 10) {
        errno = ONEWIRE_WRITE_TIMESLOT_TIMEOUT_LOW;
      } else {
        errno = ONEWIRE_WRITE_TIMESLOT_TIMEOUT_HIGH;

And finally, modify search so it checks the error code more frequently, and remembers where it failed:

uint8_t seach_step;

bool OneWireHub::search() {
  ...
    switch (this->bits[n]){
        case 0:
          sendBit( FALSE );
          if (errno) { search_step = 0; return FALSE; }
          sendBit( FALSE );
          if (errno) { search_step = 1; return FALSE; }
          break;
        case 1:
          sendBit( TRUE );
          if (errno) { search_step = 2; return FALSE; }
          sendBit( FALSE );
          if (errno) { search_step = 3; return FALSE; }
          break;
        case 2:
          sendBit( FALSE );
          if (errno) { search_step = 4; return FALSE; }
          sendBit( TRUE );
          if (errno) { search_step = 5; return FALSE; }
          break;
        default:   
          search_step = 6;
          return FALSE;
      }

Then when you print out an errno and the search_step, it can be traced unambiguously. If you want to do that in the .INO, do forget to add the "extern uint8_t search_step;" there.

One more thing. Let's look at the call trace again:

waitForRequest
  recvAndProcessCmd case 0xF0:
    search case 2:
    ...

This ASSUMES that the bits array has been set properly: bits[0] should be 2. Use the technique of setting a global to save the bits[n] value, and then print it along with the errno. This will confirm that the bits array has been properly initialized.

Now to verify the timing. One way is to set an extra digital pin high when the interval starts, the set it low when the code thinks the interval is over. waitTimeSlot will need a little restructuring:

#define DEBUG_PIN 8

uint8_t OneWireHub::waitTimeSlot() {
    uint8_t err = 1;
    uint8_t mask = pin_bitmask;
    volatile uint8_t *reg asm("r30") = baseReg;
    uint16_t retries;

digitalWrite(DEBUG_PIN,HIGH);

    //Wait for a 0 to rise to 1 on the line for timeout duration
    //If the line is already high, this is basically skipped
    retries = TIMESLOT_WAIT_RETRY_COUNT;

    //While line is low, retry
    while ( !DIRECT_READ(reg, mask))
        if (--retries == 0) {
            err = 10;
            break;
        }

    if (err == 1) {
      //Wait for a fall form 1 to 0 on the line for timeout duration
      retries = TIMESLOT_WAIT_RETRY_COUNT;
      while ( DIRECT_READ(reg, mask)) //  be sure BAD semi-colon is gone!
          if (--retries == 0) {
              err = 20;
              break;
          }
    }

digitalWrite(DEBUG_PIN,LOW);

    return err;
}

Note: Don't forget to set digitalMode(DEBUG_PIN,OUTPUT) somewhere. I used digitalWrite, but it is a little slower than the DIRECT_WRITE macros. You could set up a debug pin base reg and mask in ::OneWireHub and use the macro here, too.

Now this line will toggle when it's in waitTimeSlot, so hook that pin to channel 2 of the scope. You should be able to see how it relates to the end of the SEARCH command, and if it waits long enough. OTOH, the bits array could be wrong...

Sigh, /dev

Sheesh! That extra semicolon means it does not decrement the retry count in the loop. So, delete that and try it. It is in both waitTimeSlot and waitTimeSlotRead. It is also in OneWireSlave! You might try OneWireSlave to see if it works without the semicolon.

Ahh… After deleting the semicolon,

cmd = F0
8
RESTART
cmd = F0
8
RESTART
cmd = F0
8
RESTART
cmd = F0
8
RESTART
cmd = F0
8
RESTART

After modifying and adding the new errno, search() :

cmd = F0
3
4
RESTART
cmd = F0
3
4
RESTART
cmd = F0
3
4
RESTART
cmd = F0
3
4
RESTART

The declarations are done in the .h file.

OneWireHub.cpp (23 KB)

OneWireHub.h (2.34 KB)

This ASSUMES that the bits array has been set properly: bits[0] should be 2. Use the technique of setting a global to save the bits[n] value, and then print it along with the errno. This will confirm that the bits array has been properly initialized.

After adding in the global variable to save the bits[n] value:

cmd = F0
3
4
2
RESTART
cmd = F0
3
4
2
RESTART
cmd = F0
3
4
2
RESTART

Value_bits saves the bits[n].

Serial.println(errno);
    Serial.println(search_step);
    Serial.println(value_bits);
    Serial.println("RESTART");
      return FALSE;

So bits[0] is 2.

Now this line will toggle when it's in waitTimeSlot, so hook that pin to channel 2 of the scope. You should be able to see how it relates to the end of the SEARCH command, and if it waits long enough. OTOH, the bits array could be wrong...

Are there other ways other than using an oscilloscope? My office doesn't have a scope... -.- Borrowing one requires a lot of effort :slightly_frowning_face:

Ops… I realised I was still using :

#define TIMESLOT_WAIT_RETRY_COUNT microsecondsToClockCycles(650) / 10L

I changed it back to 132/10L , and the errno became 2.

cmd = F0
2
4ur
2
RESTART
cmd = F0
2
4
2
RESTART
cmd = F0
2
4
2
RESTART

So bits[0] is 2.

Great, that means the complicated calck and Analize methods are working, at least for the first bit. :)

wongsm7: Are there other ways other than using an oscilloscope? My office doesn't have a scope... -.- Borrowing one requires a lot of effort :slightly_frowning_face:

Hmmm... you're trying to emulate a piece of hardware, and you have to do it without hardware debugging tools? That's a tough one.

We're mostly doing "logic" analysis, not "electrical" analysis, so a logic analyzer would be sufficient. Some possibilities:

  • Spend only $10 and get a cheap USB analyzer that has 8 channels (you need 2 or more), it's more than fast enough (0.042us sampling), it can interpret the 1-wire protocol (among others), and it gets mostly decent reviews.
  • Spend $70 or more and get a 2-channel USB scope (sometimes fragile or flakey).
  • Spend $300 or more and get a real scope.
  • Use your second Arduino as a 4-channel logic analyzer with this. It requires installing the SUMP client on your PC. I've never tried it. If your time is money, you've easily spent $10 over the past week.

OTOH, people have been debugging electronics for a long time, without fancy tools:

"I am endeavoring, ma'am, to construct a mnemonic memory circuit using stone knives and bearskins."

So, yes, it can be done. Usually it's not cost-effective, except for those who have more time than money.

The basic idea is to use micros() to gather timestamps. In the curious waitTimeSlot() we could do this instead of digitalWrite+scope:

uint32_t ts1, ts2, ts3, ts4, ts5;

uint8_t OneWireHub::waitTimeSlot() {
    uint8_t err = 1;
    uint8_t mask = pin_bitmask;
    volatile uint8_t *reg asm("r30") = baseReg;
    uint16_t retries;

ts1 = micros();
ts2 = t1;
ts3 = t1;
ts4 = t1;

    //Wait for a 0 to rise to 1 on the line for timeout duration
    //If the line is already high, this is basically skipped
    retries = TIMESLOT_WAIT_RETRY_COUNT;

    //While line is low, retry
    while ( !DIRECT_READ(reg, mask))
        if (--retries == 0) {
            err = 10;
ts2 = micros();
// just for debugging, let's see how long it does stay low
while ( !DIRECT_READ(reg, mask))
    ; // really do nothing!
ts3 = micros();
             break;
        }

    if (err == 1) {
      //Wait for a fall form 1 to 0 on the line for timeout duration
      retries = TIMESLOT_WAIT_RETRY_COUNT;
      while ( DIRECT_READ(reg, mask)) //  be sure BAD semi-colon is gone!
          if (--retries == 0) {
              err = 20;
ts4 = micros();
              break;
          }
    }

ts5 = micros();

    return err;
}

Then print them out on one line:

        Serial.print(errno);
        Serial.print( ' ' );
    Serial.print(search_step);
        Serial.print( ' ' );
    Serial.print(value_bits);
        Serial.print( ' ' );
    Serial.print( ts2-ts1 );
        Serial.print( ' ' );
    Serial.print( ts3-ts2 );
        Serial.print( ' ' );
    Serial.print( ts4-ts3 );
        Serial.print( ' ' );
    Serial.print( ts5-ts4 );
        Serial.print( ' ' );
    Serial.println( F("RESTART") );
      return FALSE;

Because micros() takes some time, we are changing the timing of the system to measure it. This means that these "debug" statements may actually make the program start working!

Well, this should tell us how long the line stays LOW after the SEARCH command. I was thinking about how the DS2401 emulation does work... The first byte it would send is a 0x01 instead of a 0x28, which means it will try to send a "10" bit sequence instead of "01". Does that matter? I'm not sure... Considering the time it takes to write these posts, it might be quicker if I just rewrote OneWireSlave and Hub. :D

Cheers, /dev

Oh, yes... I forgot to grab a timestamp at the end of the SEARCH command:

  for (;;) {
    uint8_t cmd = recv();
ts0 = micros();
lastcmd = cmd; // save it for later
    switch (cmd) {
      // Search rom
      case 0xF0:
        search();
        delayMicroseconds(6900); //1100 - 6900
        return FALSE;

Add it to the declaration:

uint32_t ts0, ts1, ts2, ts3, ts4, ts5;

And also print it:

        Serial.print(errno);
        Serial.print( ' ' );
    Serial.print(search_step);
        Serial.print( ' ' );
    Serial.print(value_bits);
        Serial.print( ' ' );
    Serial.print( ts1-ts0 );
        Serial.print( ' ' );
    Serial.print( ts2-ts1 );
        Serial.print( ' ' );
    Serial.print( ts3-ts2 );
        Serial.print( ' ' );
    Serial.print( ts4-ts3 );
        Serial.print( ' ' );
    Serial.print( ts5-ts4 );
        Serial.print( ' ' );
    Serial.println( F("RESTART") );
      return FALSE;