An experimental timer interrupt driven software based 1-Wire master interface that was created by Robert David Brinzer for a University of Glasgow Level 4 Electronic and Software Engineering Final Year project. This implementation requires mbed RTOS and does not use NOP waits. Perfect for programs that require multi-tasking. Includes the Read and Search network commands and can be easily extended to support new network and transport commands.

Interface/OneWire.cpp

Committer:
sroy
Date:
2013-04-15
Revision:
0:7c6dd6bc20e4

File content as of revision 0:7c6dd6bc20e4:

#include "OneWire.h"

const OneWire_MicroInstruction OneWire::_OneWire_MicroProgram[10] = {&OneWire::_io_low,&OneWire::_io_high,
                                                                    &OneWire::_io_low,&OneWire::_io_high,
                                                                    &OneWire::_io_low,&OneWire::_io_high,&OneWire::_io_read,
                                                                    &OneWire::_io_low,&OneWire::_io_high,&OneWire::_io_read};
                                                                    
const unsigned short DEFAULT_TIMES[10] = {ONEWIRE_WRITE1LOW, ONEWIRE_TIMESLOT+ONEWIRE_RECOVER-ONEWIRE_WRITE1LOW+ONEWIRE_RECOVER,
                                                ONEWIRE_WRITE0LOW, ONEWIRE_TIMESLOT+ONEWIRE_RECOVER-ONEWIRE_WRITE0LOW+ONEWIRE_RECOVER,
                                                ONEWIRE_READLOW, ONEWIRE_READDURATION-ONEWIRE_READLOW-1, ONEWIRE_TIMESLOT-ONEWIRE_READDURATION-ONEWIRE_READLOW-1+ONEWIRE_RECOVER,
                                                ONEWIRE_TIMESLOT*8, ONEWIRE_PULSEHIGH+ONEWIRE_PULSELOW/2, ONEWIRE_TIMESLOT*8-(ONEWIRE_PULSEHIGH+ONEWIRE_PULSELOW/2)+ONEWIRE_RECOVER};

void OneWire::_nextmicroinst(){
    if(_microinstn == 0){
        _resumeinst();
    }else{
        _timer.attach_us(this, &OneWire::_nextmicroinst, timeing[_microinstc]);
        (this->*_OneWire_MicroProgram[_microinstc++])();
        _microinstn-= 1;
    }
}

void OneWire::_resumeinst(){
    unsigned char offset = _inststate & 0x0F;
    if(offset < 8){
        if((execute.code>>offset) & 0x01) op_send1();
        else op_send0();
        _inststate+= 1;
    }else{
        if(execute.inst == NULL) endInstruction();
        else (*(execute.inst))(this);
    }
    
}

void OneWire::_nextinst(){
    if(_instn > 0){
        execute = (*_instruction).network;
        if(execute.inst == NULL) _inststate = 0x08; // skip network and transport command but allow reset
        else _inststate = 0x10;
        
        // send reset pulse
        readhandle = &OneWire::_presencedetect;
        op_reset();
    }else{
        error = SUCCESS;
        osSignalSet(_caller, 1);
    }
}

void OneWire::_presencedetect(OneWire * which, char bit){
    if(bit) which->abort(NO_PRESENCE); // it is pointless to continue when there is no device attached
}

void OneWire::_ei_detect(){
    if(detecthandle != NULL) (*detecthandle)(this);
}

// Private pin I/O methods

void OneWire::_io_high(){
    _pin = 1;
}

void OneWire::_io_low(){
    _pin = 0;
}

void OneWire::_io_read(){
    _pin.input();
    (*readhandle)(this, _pin);
    _pin.output();
}

// Public utility methods

OneWire::OneWire(PinName pin) : _pin(pin), _detect(pin){
    _pin.output();
    _pin = 1; // turn on devices to allow them to start working
    _pin.mode(PullUp); 
    _detect.mode(PullUp);
    _detect.fall(this, &OneWire::_ei_detect);
    timeing = DEFAULT_TIMES;
    detecthandle = NULL;
}

int OneWire::send(OneWire_Instruction * inst, unsigned char instnum){
    _detect.fall(NULL);
    _instruction = inst;
    _instn = instnum;
    _nextinst();
    _caller = Thread::gettid();
    Thread::signal_wait(0);
    osSignalSet(_caller, 0);
    _detect.fall(this, &OneWire::_ei_detect);
    return error != SUCCESS;
}

void OneWire::endInstruction(){
    if(_inststate>>4 && _instruction->transport.inst != NULL){
        execute = _instruction->transport;
        _inststate = 0x00;
        _timer.attach_us(this, &OneWire::_resumeinst, 1); // MAKE TIMING CONFIGURABLE
    }else{
        _instruction+= 1;
        _instn-= 1;
        _timer.attach_us(this, &OneWire::_nextinst, 1); // MAKE TIMING CONFIGURABLE
    }
}

// depricated, use at own risk
void OneWire::repeatInstruction(){
    execute = (*_instruction).network;
    _inststate = 0x10;
    // send reset pulse
    readhandle = &OneWire::_presencedetect;
    op_reset();
}

void OneWire::abort(OneWire_Error err){
    _timer.detach();
    error = err;
    osSignalSet(_caller, 1);
}

// Public IO methods

void OneWire::op_send1(){
    _microinstn = 2;
    _microinstc = 0;
    _nextmicroinst();
}

void OneWire::op_send0(){
    _microinstn = 2;
    _microinstc = 2;
    _nextmicroinst();
}

void OneWire::op_read(){
    _microinstn = 3;
    _microinstc = 4;
    _nextmicroinst();
}

void OneWire::op_reset(){
    _microinstn = 3;
    _microinstc = 7;
    _nextmicroinst();
}