Browse Source

Merge branch 'master' of ssh://thor:22/OneWireIO

pull/5/head
Youen Toupin 10 years ago
parent
commit
baaf4c474b
  1. 63
      .gitattributes
  2. 189
      .gitignore
  3. 114
      LowLevel.h
  4. 32
      OneWireIO.sln
  5. 111
      OneWireIO.vcxproj
  6. 13
      OneWireIO.vcxproj.filters
  7. 75
      OneWireIO_Demo.ino
  8. 573
      OneWireSlave.cpp
  9. 108
      OneWireSlave.h

63
.gitattributes vendored

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

189
.gitignore vendored

@ -0,0 +1,189 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
x64/
build/
bld/
[Bb]in/
[Oo]bj/
# Roslyn cache directories
*.ide/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
#*.pubxml
# NuGet Packages Directory
packages/*
## TODO: If the tool you use requires repositories.config
## uncomment the next line
#!packages/repositories.config
# Enable "build/" folder in the NuGet Packages folder since
# NuGet packages use it for MSBuild targets.
# This line needs to be after the ignore of the build folder
# (and the packages folder if the line above has been uncommented)
!packages/build/
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml

114
LowLevel.h

@ -0,0 +1,114 @@
#ifndef _LowLevel_h
#define _LowLevel_h
#include <inttypes.h>
#if ARDUINO >= 100
#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc
#else
#include "WProgram.h" // for delayMicroseconds
#include "pins_arduino.h" // for digitalPinToBitMask, etc
#endif
#if defined(__AVR__)
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint8_t
#define IO_REG_ASM asm("r30")
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
#elif defined(__MK20DX128__) || defined(__MK20DX256__)
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
#define PIN_TO_BITMASK(pin) (1)
#define IO_REG_TYPE uint8_t
#define IO_REG_ASM
#define DIRECT_READ(base, mask) (*((base)+512))
#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0)
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1)
#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1)
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1)
#elif defined(__SAM3X8E__)
// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due.
// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268
// If you have trouble with OneWire on Arduino Due, please check the
// status of delayMicroseconds() before reporting a bug in OneWire!
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_ASM
#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask))
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask))
#ifndef PROGMEM
#define PROGMEM
#endif
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
#endif
#elif defined(__PIC32MX__)
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_ASM
#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10
#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04
#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28
#else
#error "Please define I/O register types here"
#endif
class Pin
{
private:
volatile IO_REG_TYPE *reg_;
IO_REG_TYPE mask_;
byte interruptNumber_;
public:
Pin()
: mask_(0)
, reg_(0)
, interruptNumber_((byte)-1)
{ }
Pin(uint8_t pin)
{
mask_ = PIN_TO_BITMASK(pin);
reg_ = PIN_TO_BASEREG(pin);
switch (pin)
{
case 2: interruptNumber_ = 0; break;
case 3: interruptNumber_ = 1; break;
default: interruptNumber_ = (byte)-1;
}
}
inline void inputMode() { DIRECT_MODE_INPUT(reg_, mask_); }
inline void outputMode() { DIRECT_MODE_OUTPUT(reg_, mask_); }
inline bool read() { return DIRECT_READ(reg_, mask_) == 1; }
inline void writeLow() { DIRECT_WRITE_LOW(reg_, mask_); }
inline void writeHigh() { DIRECT_WRITE_HIGH(reg_, mask_); }
inline void write(bool value) { if (value) writeHigh(); else writeLow(); }
inline void attachInterrupt(void (*handler)(), int mode)
{
EIFR |= (1 << INTF0); // clear any pending interrupt (we want to call the handler only for interrupts happending after it is attached)
::attachInterrupt(interruptNumber_, handler, mode);
}
inline void detachInterrupt() { ::detachInterrupt(interruptNumber_); }
};
#endif

32
OneWireIO.sln

@ -0,0 +1,32 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OneWireIO", "OneWireIO.vcxproj", "{3B500971-1570-460F-81C3-22AC3B7764B9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3B500971-1570-460F-81C3-22AC3B7764B9}.Debug|Any CPU.ActiveCfg = Debug|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Debug|Win32.ActiveCfg = Debug|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Debug|Win32.Build.0 = Debug|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Any CPU.ActiveCfg = Release|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Mixed Platforms.Build.0 = Release|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Win32.ActiveCfg = Release|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

111
OneWireIO.vcxproj

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{3B500971-1570-460F-81C3-22AC3B7764B9}</ProjectGuid>
<RootNamespace>OneWireIO</RootNamespace>
<ProjectName>OneWireIO_Demo</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>D:\Outils\Arduino\hardware\arduino\avr\cores\arduino;D:\Outils\Arduino\hardware\tools\avr\avr\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);ARDUINO=160;__AVR__;UBRRH;__AVR_ATmega328__</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf (
echo Elf generated
) else (
echo no output
exit /B 1
)</Command>
</PostBuildEvent>
<PostBuildEvent />
<CustomBuild>
<Command>if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf (
echo Elf generated
) else (
echo no output
exit /B 1
)</Command>
</CustomBuild>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<CustomBuild Include="OneWireIO_Demo.ino">
<FileType>Document</FileType>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf del $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf
D:\Outils\Arduino\arduino.exe --pref build.path=$(ProjectDir)$(IntDir) --upload %(FullPath)
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">always_build_$(ProjectConfiguration).dummy</Outputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Building and uploading sketch...</Message>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClCompile Include="OneWireSlave.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="LowLevel.h" />
<ClInclude Include="OneWireSlave.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

13
OneWireIO.vcxproj.filters

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="OneWireSlave.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="LowLevel.h" />
<ClInclude Include="OneWireSlave.h" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="OneWireIO_Demo.ino" />
</ItemGroup>
</Project>

75
OneWireIO_Demo.ino

@ -0,0 +1,75 @@
#include "Arduino.h"
#include "LowLevel.h"
#include "OneWireSlave.h"
#define LEDPin 13
// This is the pin that will be used for one-wire data (depending on your arduino model, you are limited to a few choices, because some pins don't have complete interrupt support)
// On Arduino Uno, you can use pin 2 or pin 3
#define OWPin 2
Pin led(LEDPin);
// This is the ROM the arduino will respond to, make sure it doesn't conflict with another device
byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
byte acknowledge = 0x42;
// This sample implements a simple protocol : sending match ROM, then the ROM, then 0x01 will turn the arduino light on. Sending 0x02 will turn it off. In each case, the byte 0x42 is sent as acknowledgement.
const byte CMD_TurnOn = 0x01;
const byte CMD_TurnOff = 0x02;
// This function will be called each time the OneWire library has an event to notify (reset, error, byte received)
void owReceive(OneWireSlave::ReceiveEvent evt, byte data);
void setup()
{
led.outputMode();
led.writeLow();
// Setup the OneWire library
OneWire.setReceiveCallback(&owReceive);
OneWire.begin(owROM, OWPin);
}
void loop()
{
delay(1);
// You can do anything you want here, the OneWire library works entirely in background, using interrupts.
cli();//disable interrupts
// Be sure to not block interrupts for too long, OneWire timing is very tight for some operations. 1 or 2 microseconds (yes, microseconds, not milliseconds) can be too much depending on your master controller, but then it's equally unlikely that you block exactly at the moment where it matters.
// This can be mitigated by using error checking and retry in your high-level communication protocol. A good thing to do anyway.
sei();//enable interrupts
}
void owReceive(OneWireSlave::ReceiveEvent evt, byte data)
{
switch (evt)
{
case OneWireSlave::RE_Byte:
if (data == CMD_TurnOn)
{
led.writeHigh();
}
else if (data == CMD_TurnOff)
{
led.writeLow();
}
else
{
break;
}
// in this simple example we just reply with one byte to say we've processed the command
// a real application should have a CRC system to ensure messages are not corrupt, for both directions
// you can use the static OneWireSlave::crc8 method to add CRC checks in your communication protocol (it conforms to standard one-wire CRC checks, that is used to compute the ROM last byte for example)
OneWire.write(&acknowledge, 1, NULL);
break;
default:
; // we could also react to reset and error notifications, but not in this sample
}
}

573
OneWireSlave.cpp

@ -0,0 +1,573 @@
#include "OneWireSlave.h"
// uncomment this line to enable sending messages along with errors (but takes more program memory)
//#define ERROR_MESSAGES
#ifdef ERROR_MESSAGES
#define ERROR(msg) error_(msg)
#else
#define ERROR(msg) error_(0)
#endif
namespace
{
const unsigned long ResetMinDuration = 480;
const unsigned long ResetMaxDuration = 900;
const unsigned long PresenceWaitDuration = 30;
const unsigned long PresenceDuration = 300;
const unsigned long ReadBitSamplingTime = 25;
const unsigned long SendBitDuration = 35;
const byte ReceiveCommand = (byte)-1;
void(*timerEvent)() = 0;
}
OneWireSlave OneWire;
byte OneWireSlave::rom_[8];
byte OneWireSlave::scratchpad_[8];
Pin OneWireSlave::pin_;
byte OneWireSlave::tccr1bEnable_;
unsigned long OneWireSlave::resetStart_;
unsigned long OneWireSlave::lastReset_;
void(*OneWireSlave::receiveBitCallback_)(bool bit, bool error);
void(*OneWireSlave::bitSentCallback_)(bool error);
void(*OneWireSlave::clientReceiveCallback_)(ReceiveEvent evt, byte data);
byte OneWireSlave::receivingByte_;
byte OneWireSlave::searchRomBytePos_;
byte OneWireSlave::searchRomBitPos_;
bool OneWireSlave::searchRomInverse_;
byte* OneWireSlave::buffer_;
short OneWireSlave::bufferLength_;
byte OneWireSlave::bufferBitPos_;
short OneWireSlave::bufferPos_;
void(*OneWireSlave::receiveBytesCallback_)(bool error);
void(*OneWireSlave::sendBytesCallback_)(bool error);
ISR(TIMER1_COMPA_vect) // timer1 interrupt
{
TCCR1B = 0; // disable clock
void(*event)() = timerEvent;
timerEvent = 0;
event();
}
void OneWireSlave::begin(byte* rom, byte pinNumber)
{
pin_ = Pin(pinNumber);
resetStart_ = (unsigned long)-1;
lastReset_ = 0;
memcpy(rom_, rom, 7);
rom_[7] = crc8(rom_, 7);
// log("Enabling 1-wire library")
cli(); // disable interrupts
pin_.inputMode();
pin_.writeLow(); // make sure the internal pull-up resistor is disabled
// prepare hardware timer
TCCR1A = 0;
TCCR1B = 0;
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
tccr1bEnable_ = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler
// start 1-wire activity
beginWaitReset_();
sei(); // enable interrupts
}
void OneWireSlave::end()
{
#ifdef DEBUG_LOG
debug.append("Disabling 1-wire library");
#endif
cli();
disableTimer_();
pin_.detachInterrupt();
releaseBus_();
sei();
}
void OneWireSlave::write(byte* bytes, short numBytes, void(*complete)(bool error))
{
cli();
beginWriteBytes_(bytes, numBytes, complete == 0 ? noOpCallback_ : complete);
sei();
}
byte OneWireSlave::crc8(byte* data, short numBytes)
{
byte crc = 0;
while (numBytes--) {
byte inbyte = *data++;
for (byte i = 8; i; i--) {
byte mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
void OneWireSlave::setTimerEvent_(short delayMicroSeconds, void(*handler)())
{
delayMicroSeconds -= 10; // remove overhead (tuned on Arduino Uno)
short skipTicks = (delayMicroSeconds - 3) / 4; // round the micro seconds delay to a number of ticks to skip (4us per tick, so 4us must skip 0 tick, 8us must skip 1 tick, etc.)
if (skipTicks < 1) skipTicks = 1;
TCNT1 = 0;
OCR1A = skipTicks;
timerEvent = handler;
TCCR1B = tccr1bEnable_;
}
void OneWireSlave::disableTimer_()
{
TCCR1B = 0;
}
void OneWireSlave::onEnterInterrupt_()
{
#ifdef DEBUG_LOG
dbgOutput.writeLow();
#endif
}
void OneWireSlave::onLeaveInterrupt_()
{
#ifdef DEBUG_LOG
dbgOutput.writeHigh();
#endif
}
void OneWireSlave::error_(const char* message)
{
#ifdef DEBUG_LOG
if (message == 0)
debug.append("unspecified error");
else
debug.append(message);
#endif
beginWaitReset_();
}
void OneWireSlave::pullLow_()
{
pin_.outputMode();
pin_.writeLow();
}
void OneWireSlave::releaseBus_()
{
pin_.inputMode();
}
void OneWireSlave::beginResetDetection_()
{
setTimerEvent_(ResetMinDuration - 50, &OneWireSlave::resetCheck_);
resetStart_ = micros() - 50;
}
void OneWireSlave::cancelResetDetection_()
{
disableTimer_();
resetStart_ = (unsigned long)-1;
}
void OneWireSlave::resetCheck_()
{
onEnterInterrupt_();
if (!pin_.read())
{
pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE);
// log("Reset detected during another operation");
}
onLeaveInterrupt_();
}
void OneWireSlave::beginReceiveBit_(void(*completeCallback)(bool bit, bool error))
{
receiveBitCallback_ = completeCallback;
pin_.attachInterrupt(&OneWireSlave::receive_, FALLING);
}
void OneWireSlave::receive_()
{
onEnterInterrupt_();
pin_.detachInterrupt();
setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::readBit_);
onLeaveInterrupt_();
}
void OneWireSlave::readBit_()
{
onEnterInterrupt_();
bool bit = pin_.read();
if (bit)
cancelResetDetection_();
else
beginResetDetection_();
receiveBitCallback_(bit, false);
//dbgOutput.writeLow();
//dbgOutput.writeHigh();
onLeaveInterrupt_();
}
void OneWireSlave::beginSendBit_(bool bit, void(*completeCallback)(bool error))
{
bitSentCallback_ = completeCallback;
if (bit)
{
pin_.attachInterrupt(&OneWireSlave::sendBitOne_, FALLING);
}
else
{
pin_.attachInterrupt(&OneWireSlave::sendBitZero_, FALLING);
}
}
void OneWireSlave::sendBitOne_()
{
onEnterInterrupt_();
beginResetDetection_();
bitSentCallback_(false);
onLeaveInterrupt_();
}
void OneWireSlave::sendBitZero_()
{
pullLow_(); // this must be executed first because the timing is very tight with some master devices
onEnterInterrupt_();
pin_.detachInterrupt();
setTimerEvent_(SendBitDuration, &OneWireSlave::endSendBitZero_);
onLeaveInterrupt_();
}
void OneWireSlave::endSendBitZero_()
{
onEnterInterrupt_();
releaseBus_();
bitSentCallback_(false);
onLeaveInterrupt_();
}
void OneWireSlave::beginWaitReset_()
{
disableTimer_();
pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE);
resetStart_ = (unsigned int)-1;
}
void OneWireSlave::waitReset_()
{
onEnterInterrupt_();
bool state = pin_.read();
unsigned long now = micros();
if (state)
{
if (resetStart_ == (unsigned int)-1)
{
onLeaveInterrupt_();
return;
}
unsigned long resetDuration = now - resetStart_;
resetStart_ = (unsigned int)-1;
if (resetDuration >= ResetMinDuration)
{
if (resetDuration > ResetMaxDuration)
{
ERROR("Reset too long");
onLeaveInterrupt_();
return;
}
lastReset_ = now;
pin_.detachInterrupt();
setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresence_);
if (clientReceiveCallback_ != 0)
clientReceiveCallback_(RE_Reset, 0);
}
}
else
{
resetStart_ = now;
}
onLeaveInterrupt_();
}
void OneWireSlave::beginPresence_()
{
pullLow_();
setTimerEvent_(PresenceDuration, &OneWireSlave::endPresence_);
}
void OneWireSlave::endPresence_()
{
releaseBus_();
beginWaitCommand_();
}
void OneWireSlave::beginWaitCommand_()
{
bufferPos_ = ReceiveCommand;
beginReceive_();
}
void OneWireSlave::beginReceive_()
{
receivingByte_ = 0;
bufferBitPos_ = 0;
beginReceiveBit_(&OneWireSlave::onBitReceived_);
}
void OneWireSlave::onBitReceived_(bool bit, bool error)
{
if (error)
{
ERROR("Invalid bit");
if (bufferPos_ >= 0)
receiveBytesCallback_(true);
return;
}
receivingByte_ |= ((bit ? 1 : 0) << bufferBitPos_);
++bufferBitPos_;
if (bufferBitPos_ == 8)
{
// log("received byte", (long)receivingByte_);
if (bufferPos_ == ReceiveCommand)
{
bufferPos_ = 0;
switch (receivingByte_)
{
case 0xF0: // SEARCH ROM
beginSearchRom_();
return;
case 0x33: // READ ROM
beginWriteBytes_(rom_, 8, &OneWireSlave::noOpCallback_);
return;
case 0x55: // MATCH ROM
beginReceiveBytes_(scratchpad_, 8, &OneWireSlave::matchRomBytesReceived_);
return;
case 0xCC: // SKIP ROM
// emulate a match rom operation
memcpy(scratchpad_, rom_, 8);
matchRomBytesReceived_(false);
return;
default:
ERROR("Unknown command");
return;
}
}
else
{
buffer_[bufferPos_++] = receivingByte_;
receivingByte_ = 0;
bufferBitPos_ = 0;
if (bufferPos_ == bufferLength_)
{
beginWaitReset_();
receiveBytesCallback_(false);
return;
}
}
}
beginReceiveBit_(&OneWireSlave::onBitReceived_);
}
void OneWireSlave::beginSearchRom_()
{
searchRomBytePos_ = 0;
searchRomBitPos_ = 0;
searchRomInverse_ = false;
beginSearchRomSendBit_();
}
void OneWireSlave::beginSearchRomSendBit_()
{
byte currentByte = rom_[searchRomBytePos_];
bool currentBit = bitRead(currentByte, searchRomBitPos_);
bool bitToSend = searchRomInverse_ ? !currentBit : currentBit;
beginSendBit_(bitToSend, &OneWireSlave::continueSearchRom_);
}
void OneWireSlave::continueSearchRom_(bool error)
{
if (error)
{
ERROR("Failed to send bit");
return;
}
searchRomInverse_ = !searchRomInverse_;
if (searchRomInverse_)
{
beginSearchRomSendBit_();
}
else
{
beginReceiveBit_(&OneWireSlave::searchRomOnBitReceived_);
}
}
void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error)
{
if (error)
{
ERROR("Bit read error during ROM search");
return;
}
byte currentByte = rom_[searchRomBytePos_];
bool currentBit = bitRead(currentByte, searchRomBitPos_);
if (bit == currentBit)
{
++searchRomBitPos_;
if (searchRomBitPos_ == 8)
{
searchRomBitPos_ = 0;
++searchRomBytePos_;
}
if (searchRomBytePos_ == 8)
{
// log("ROM sent entirely");
beginWaitReset_();
}
else
{
beginSearchRomSendBit_();
}
}
else
{
// log("Leaving ROM search");
beginWaitReset_();
}
}
void OneWireSlave::beginWriteBytes_(byte* data, short numBytes, void(*complete)(bool error))
{
buffer_ = data;
bufferLength_ = numBytes;
bufferPos_ = 0;
bufferBitPos_ = 0;
sendBytesCallback_ = complete;
bool bit = bitRead(buffer_[0], 0);
beginSendBit_(bit, &OneWireSlave::bitSent_);
}
void OneWireSlave::bitSent_(bool error)
{
if (error)
{
ERROR("error sending a bit");
sendBytesCallback_(true);
return;
}
++bufferBitPos_;
if (bufferBitPos_ == 8)
{
bufferBitPos_ = 0;
++bufferPos_;
}
if (bufferPos_ == bufferLength_)
{
beginWaitReset_();
sendBytesCallback_(false);
return;
}
bool bit = bitRead(buffer_[bufferPos_], bufferBitPos_);
beginSendBit_(bit, &OneWireSlave::bitSent_);
}
void OneWireSlave::beginReceiveBytes_(byte* buffer, short numBytes, void(*complete)(bool error))
{
buffer_ = buffer;
bufferLength_ = numBytes;
bufferPos_ = 0;
receiveBytesCallback_ = complete;
beginReceive_();
}
void OneWireSlave::noOpCallback_(bool error)
{
if (error)
ERROR("error during an internal 1-wire operation");
}
void OneWireSlave::matchRomBytesReceived_(bool error)
{
if (error)
{
ERROR("error receiving match rom bytes");
return;
}
if (memcmp(rom_, scratchpad_, 8) == 0)
{
// log("ROM matched");
beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_);
}
else
{
// log("ROM not matched");
beginWaitReset_();
}
}
void OneWireSlave::notifyClientByteReceived_(bool error)
{
if (error)
{
if (clientReceiveCallback_ != 0)
clientReceiveCallback_(RE_Error, 0);
ERROR("error receiving custom bytes");
return;
}
beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_);
if (clientReceiveCallback_ != 0)
clientReceiveCallback_(RE_Byte, scratchpad_[0]);
}

108
OneWireSlave.h

@ -0,0 +1,108 @@
#ifndef _OneWireSlave_h_
#define _OneWireSlave_h_
#include "Arduino.h"
#include "LowLevel.h"
class OneWireSlave
{
public:
enum ReceiveEvent
{
RE_Reset, //!< The master has sent a general reset
RE_Byte, //!< The master just sent a byte of data
RE_Error //!< A communication error happened (such as a timeout) ; the library will stop all 1-wire activities until the next reset
};
//! Starts listening for the 1-wire master, on the specified pin, as a virtual slave device identified by the specified ROM (7 bytes, starting from the family code, CRC will be computed internally). Reset, Presence, SearchRom and MatchRom are handled automatically. The library will use the external interrupt on the specified pin (note that this is usually not possible with all pins, depending on the board), as well as one hardware timer. Blocking interrupts (either by disabling them explicitely with sei/cli, or by spending time in another interrupt) can lead to malfunction of the library, due to tight timing for some 1-wire operations.
void begin(byte* rom, byte pinNumber);
//! Stops all 1-wire activities, which frees hardware resources for other purposes.
void end();
//! Sets (or replaces) a function to be called when something is received. The callback is executed from interrupts and should be as short as possible. Failure to return quickly can prevent the library from correctly reading the next byte.
void setReceiveCallback(void(*callback)(ReceiveEvent evt, byte data)) { clientReceiveCallback_ = callback; }
//! Enqueues the specified bytes in the send buffer. They will be sent in the background. The optional callback is used to notify when the bytes are sent, or if an error occured. Callbacks are executed from interrupts and should be as short as possible.
void write(byte* bytes, short numBytes, void(*complete)(bool error));
static byte crc8(byte* data, short numBytes);
private:
static void setTimerEvent_(short delayMicroSeconds, void(*handler)());
static void disableTimer_();
static void onEnterInterrupt_();
static void onLeaveInterrupt_();
static void error_(const char* message);
static void pullLow_();
static void releaseBus_();
static void beginReceiveBit_(void(*completeCallback)(bool bit, bool error));
static void beginSendBit_(bool bit, void(*completeCallback)(bool error));
static void beginResetDetection_();
static void cancelResetDetection_();
static void beginWaitReset_();
static void beginWaitCommand_();
static void beginReceive_();
static void onBitReceived_(bool bit, bool error);
static void beginSearchRom_();
static void beginSearchRomSendBit_();
static void continueSearchRom_(bool error);
static void searchRomOnBitReceived_(bool bit, bool error);
static void beginWriteBytes_(byte* data, short numBytes, void(*complete)(bool error));
static void beginReceiveBytes_(byte* buffer, short numBytes, void(*complete)(bool error));
static void noOpCallback_(bool error);
static void matchRomBytesReceived_(bool error);
static void notifyClientByteReceived_(bool error);
static void bitSent_(bool error);
// interrupt handlers
static void waitReset_();
static void beginPresence_();
static void endPresence_();
static void receive_();
static void readBit_();
static void sendBitOne_();
static void sendBitZero_();
static void endSendBitZero_();
static void resetCheck_();
private:
static byte rom_[8];
static byte scratchpad_[8];
static Pin pin_;
static byte tccr1bEnable_;
static unsigned long resetStart_;
static unsigned long lastReset_;
static void(*receiveBitCallback_)(bool bit, bool error);
static void(*bitSentCallback_)(bool error);
static byte receivingByte_;
static byte searchRomBytePos_;
static byte searchRomBitPos_;
static bool searchRomInverse_;
static byte* buffer_;
static short bufferLength_;
static short bufferPos_;
static byte bufferBitPos_;
static void(*receiveBytesCallback_)(bool error);
static void(*sendBytesCallback_)(bool error);
static void(*clientReceiveCallback_)(ReceiveEvent evt, byte data);
};
extern OneWireSlave OneWire;
#endif
Loading…
Cancel
Save