From 8be66217ddcf6235f43bb5745a30ea8fdae93b3e Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 11 Apr 2015 12:49:46 +0200 Subject: [PATCH 01/32] Empty Arduino sketch with OWSlave library downloaded from http://forum.arduino.cc/index.php?topic=65706.msg1756727#msg1756727 --- OWSlave.cpp | 382 ++++++++++++++++++++++++++++++++++++++++++++++++++ OWSlave.h | 64 +++++++++ OneWireIO.ino | 7 + 3 files changed, 453 insertions(+) create mode 100644 OWSlave.cpp create mode 100644 OWSlave.h create mode 100644 OneWireIO.ino diff --git a/OWSlave.cpp b/OWSlave.cpp new file mode 100644 index 0000000..c498aa5 --- /dev/null +++ b/OWSlave.cpp @@ -0,0 +1,382 @@ +/* +OWSlave v1.0 by Alexander Gordeyev + +It is based on Jim's Studt OneWire library v2.0 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Much of the code was inspired by Derek Yerger's code, though I don't +think much of that remains. In any event that was.. + (copyleft) 2006 by Derek Yerger - Free to distribute freely. + +The CRC code was excerpted and inspired by the Dallas Semiconductor +sample code bearing this copyright. +//--------------------------------------------------------------------------- +// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES +// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// Except as contained in this notice, the name of Dallas Semiconductor +// shall not be used except as stated in the Dallas Semiconductor +// Branding Policy. +//-------------------------------------------------------------------------- +*/ + +#include "OWSlave.h" +#include "pins_arduino.h" + +extern "C" { +// #include "WConstants.h" +#include +#include +#include +} + +#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)) + +#define TIMESLOT_WAIT_RETRY_COUNT microsecondsToClockCycles(120) / 10L + +OWSlave::OWSlave(uint8_t pin) { + pin_bitmask = digitalPinToBitMask(pin); + baseReg = portInputRegister(digitalPinToPort(pin)); +} + +void OWSlave::setRom(unsigned char rom[8]) { + for (int i=0; i<7; i++) + this->rom[i] = rom[i]; + this->rom[7] = crc8(this->rom, 7); +} + +void OWSlave::setRomnc(unsigned char rom[8]) { + for (int i=0; i<8; i++) + this->rom[i] = rom[i]; +} + +bool OWSlave::waitForRequest(bool ignore_errors) { + errno = ONEWIRE_NO_ERROR; + for (;;) { + if (!waitReset(0) ) + continue; + if (!presence() ) + continue; + if (recvAndProcessCmd() ) + return TRUE; + else if ((errno == ONEWIRE_NO_ERROR) || ignore_errors) + continue; + else + return FALSE; + } +} + +bool OWSlave::recvAndProcessCmd() { + char addr[8]; + + for (;;) { + switch (recv() ) { + case 0xF0: // SEARCH ROM + search(); + return FALSE; + case 0x33: // READ ROM + sendData(rom, 8); + if (errno != ONEWIRE_NO_ERROR) + return FALSE; + break; + case 0x55: // MATCH ROM + recvData(addr, 8); + if (errno != ONEWIRE_NO_ERROR) + return FALSE; + for (int i=0; i<8; i++) + if (rom[i] != addr[i]) + return FALSE; + return TRUE; + case 0xCC: // SKIP ROM + return TRUE; + default: // Unknown command + if (errno == ONEWIRE_NO_ERROR) + return FALSE; + else + return FALSE; + } + } +} + +bool OWSlave::search() { + uint8_t bitmask; + uint8_t bit_send, bit_recv; + + for (int i=0; i<8; i++) { + for (bitmask = 0x01; bitmask; bitmask <<= 1) { + bit_send = (bitmask & rom[i])?1:0; + sendBit(bit_send); + sendBit(!bit_send); + bit_recv = recvBit(); + if (errno != ONEWIRE_NO_ERROR) + return FALSE; + if (bit_recv != bit_send) + return FALSE; + } + } + return TRUE; +} + +bool OWSlave::waitReset(uint16_t timeout_ms) { + uint8_t mask = pin_bitmask; + volatile uint8_t *reg asm("r30") = baseReg; + unsigned long time_stamp; + + errno = ONEWIRE_NO_ERROR; + cli(); + DIRECT_MODE_INPUT(reg, mask); + sei(); + if (timeout_ms != 0) { + time_stamp = micros() + timeout_ms*1000; + while (DIRECT_READ(reg, mask)) { + if (micros() > time_stamp) { + errno = ONEWIRE_WAIT_RESET_TIMEOUT; + return FALSE; + } + } + } else + while (DIRECT_READ(reg, mask)) {}; + time_stamp = micros() + 540; + while (DIRECT_READ(reg, mask) == 0) { + if (micros() > time_stamp) { + errno = ONEWIRE_VERY_LONG_RESET; + return FALSE; + } + } + if ((time_stamp - micros()) > 70) { + errno = ONEWIRE_VERY_SHORT_RESET; + return FALSE; + } + delayMicroseconds(30); + return TRUE; +} +bool OWSlave::waitReset() { + return waitReset(1000); +} + +bool OWSlave::presence(uint8_t delta) { + uint8_t mask = pin_bitmask; + volatile uint8_t *reg asm("r30") = baseReg; + + errno = ONEWIRE_NO_ERROR; + cli(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + sei(); + delayMicroseconds(120); + cli(); + DIRECT_MODE_INPUT(reg, mask); // allow it to float + sei(); + delayMicroseconds(300 - delta); + if ( !DIRECT_READ(reg, mask)) { + errno = ONEWIRE_PRESENCE_LOW_ON_LINE; + return FALSE; + } else + return TRUE; +} +bool OWSlave::presence() { + return presence(25); +} + +uint8_t OWSlave::sendData(char buf[], uint8_t len) { + uint8_t bytes_sended = 0; + + for (int i=0; i>= 1; + if (mix) crc ^= 0x8C; + inbyte >>= 1; + } + } + return crc; +} +#endif + +#endif diff --git a/OWSlave.h b/OWSlave.h new file mode 100644 index 0000000..f054858 --- /dev/null +++ b/OWSlave.h @@ -0,0 +1,64 @@ +#ifndef iButton_h +#define iButton_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include + +// You can exclude CRC checks altogether by defining this to 0 +#ifndef OWSlave_CRC +#define OWSlave_CRC 1 +#endif + +// Select the table-lookup method of computing the 8-bit CRC +// by setting this to 1. The lookup table no longer consumes +// limited RAM, but enlarges total code size by about 250 bytes +#ifndef OWSlave_CRC8_TABLE +#define OWSlave_CRC8_TABLE 0 +#endif + +#define FALSE 0 +#define TRUE 1 + +#define ONEWIRE_NO_ERROR 0 +#define ONEWIRE_READ_TIMESLOT_TIMEOUT 1 +#define ONEWIRE_WRITE_TIMESLOT_TIMEOUT 2 +#define ONEWIRE_WAIT_RESET_TIMEOUT 3 +#define ONEWIRE_VERY_LONG_RESET 4 +#define ONEWIRE_VERY_SHORT_RESET 5 +#define ONEWIRE_PRESENCE_LOW_ON_LINE 6 + +class OWSlave { + private: + bool waitTimeSlot(); + uint8_t pin_bitmask; + volatile uint8_t *baseReg; + char rom[8]; + public: + bool recvAndProcessCmd(); + OWSlave(uint8_t pin); + void setRom(unsigned char rom[8]); + void setRomnc(unsigned char rom[8]); + bool waitForRequest(bool ignore_errors); + bool waitReset(uint16_t timeout_ms); + bool waitReset(); + bool presence(uint8_t delta); + bool presence(); + bool search(); + uint8_t sendData(char buf[], uint8_t data_len); + uint8_t recvData(char buf[], uint8_t data_len); + void send(uint8_t v); + uint8_t recv(void); + void sendBit(uint8_t v); + uint8_t recvBit(void); +#if OWSlave_CRC + static uint8_t crc8(char addr[], uint8_t len); +#endif + uint8_t errno; +}; + +#endif diff --git a/OneWireIO.ino b/OneWireIO.ino new file mode 100644 index 0000000..4b64f3d --- /dev/null +++ b/OneWireIO.ino @@ -0,0 +1,7 @@ +void setup() { + +} + +void loop() { + +} From 16dbbc37e45b26ab528df5cc724d14dd971098eb Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 11 Apr 2015 13:18:12 +0200 Subject: [PATCH 02/32] Device identification and simple command listening (not tested yet) --- OneWireIO.ino | 61 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 4b64f3d..5f04bc0 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -1,7 +1,62 @@ -void setup() { +#include "OWSlave.h" +#define LEDPin 13 +#define OWPin 2 +#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 + +unsigned char rom[8] = {0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; + +volatile long prevInt = 0; // Previous Interrupt micros +volatile boolean owReset = false; + +OWSlave oneWire(OWPin); + +void setup() +{ + pinMode(LEDPin, OUTPUT); + pinMode(OWPin, INPUT); + + digitalWrite(LEDPin, LOW); + + attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); + + oneWire.setRom(rom); } -void loop() { +void loop() +{ + if (owReset) owHandler(); +} -} +void owHandler(void) +{ + detachInterrupt(InterruptNumber); + owReset=false; + + if (oneWire.presence()) { + if (oneWire.recvAndProcessCmd()) { + uint8_t cmd = oneWire.recv(); + if (cmd == 0x44) { + digitalWrite(LEDPin, HIGH); + } + if (cmd == 0xBE) { + for( int i = 0; i < 9; i++) { + oneWire.send((byte)0); + } + } + } + } + attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); +} + +void onewireInterrupt(void) +{ + volatile long lastMicros = micros() - prevInt; + prevInt = micros(); + if (lastMicros >= 410 && lastMicros <= 550) + { + // OneWire Reset Detected + owReset=true; + } +} + From a7ae407b6cf583113d5092026f42da59139b6815 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 11 Apr 2015 20:28:53 +0200 Subject: [PATCH 03/32] - removed the OWSlave library (that just doesn't work, at least on Arduino Uno when talking to a DS9490 master) - added debugging tools (oscilloscope and debug messages through serial port ; work in progress) - empty C# application for displaying debug data (work in progress) --- .gitattributes | 63 +++ .gitignore | 189 +++++++++ OWSlave.cpp | 382 ------------------ OWSlave.h | 64 --- OneWireIO.ino | 100 +++-- SerialChannel.cpp | 29 ++ SerialChannel.h | 21 + SerialMonitor/SerialMonitor.sln | 22 + SerialMonitor/SerialMonitor/App.config | 6 + SerialMonitor/SerialMonitor/App.xaml | 8 + SerialMonitor/SerialMonitor/App.xaml.cs | 17 + SerialMonitor/SerialMonitor/MainWindow.xaml | 8 + .../SerialMonitor/MainWindow.xaml.cs | 28 ++ .../SerialMonitor/Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 71 ++++ .../SerialMonitor/Properties/Resources.resx | 117 ++++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 7 + .../SerialMonitor/SerialMonitor.csproj | 104 +++++ 19 files changed, 841 insertions(+), 480 deletions(-) create mode 100644 .gitattributes create mode 100644 .gitignore delete mode 100644 OWSlave.cpp delete mode 100644 OWSlave.h create mode 100644 SerialChannel.cpp create mode 100644 SerialChannel.h create mode 100644 SerialMonitor/SerialMonitor.sln create mode 100644 SerialMonitor/SerialMonitor/App.config create mode 100644 SerialMonitor/SerialMonitor/App.xaml create mode 100644 SerialMonitor/SerialMonitor/App.xaml.cs create mode 100644 SerialMonitor/SerialMonitor/MainWindow.xaml create mode 100644 SerialMonitor/SerialMonitor/MainWindow.xaml.cs create mode 100644 SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs create mode 100644 SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs create mode 100644 SerialMonitor/SerialMonitor/Properties/Resources.resx create mode 100644 SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs create mode 100644 SerialMonitor/SerialMonitor/Properties/Settings.settings create mode 100644 SerialMonitor/SerialMonitor/SerialMonitor.csproj diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7964536 --- /dev/null +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/OWSlave.cpp b/OWSlave.cpp deleted file mode 100644 index c498aa5..0000000 --- a/OWSlave.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* -OWSlave v1.0 by Alexander Gordeyev - -It is based on Jim's Studt OneWire library v2.0 - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Much of the code was inspired by Derek Yerger's code, though I don't -think much of that remains. In any event that was.. - (copyleft) 2006 by Derek Yerger - Free to distribute freely. - -The CRC code was excerpted and inspired by the Dallas Semiconductor -sample code bearing this copyright. -//--------------------------------------------------------------------------- -// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES -// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// Except as contained in this notice, the name of Dallas Semiconductor -// shall not be used except as stated in the Dallas Semiconductor -// Branding Policy. -//-------------------------------------------------------------------------- -*/ - -#include "OWSlave.h" -#include "pins_arduino.h" - -extern "C" { -// #include "WConstants.h" -#include -#include -#include -} - -#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)) - -#define TIMESLOT_WAIT_RETRY_COUNT microsecondsToClockCycles(120) / 10L - -OWSlave::OWSlave(uint8_t pin) { - pin_bitmask = digitalPinToBitMask(pin); - baseReg = portInputRegister(digitalPinToPort(pin)); -} - -void OWSlave::setRom(unsigned char rom[8]) { - for (int i=0; i<7; i++) - this->rom[i] = rom[i]; - this->rom[7] = crc8(this->rom, 7); -} - -void OWSlave::setRomnc(unsigned char rom[8]) { - for (int i=0; i<8; i++) - this->rom[i] = rom[i]; -} - -bool OWSlave::waitForRequest(bool ignore_errors) { - errno = ONEWIRE_NO_ERROR; - for (;;) { - if (!waitReset(0) ) - continue; - if (!presence() ) - continue; - if (recvAndProcessCmd() ) - return TRUE; - else if ((errno == ONEWIRE_NO_ERROR) || ignore_errors) - continue; - else - return FALSE; - } -} - -bool OWSlave::recvAndProcessCmd() { - char addr[8]; - - for (;;) { - switch (recv() ) { - case 0xF0: // SEARCH ROM - search(); - return FALSE; - case 0x33: // READ ROM - sendData(rom, 8); - if (errno != ONEWIRE_NO_ERROR) - return FALSE; - break; - case 0x55: // MATCH ROM - recvData(addr, 8); - if (errno != ONEWIRE_NO_ERROR) - return FALSE; - for (int i=0; i<8; i++) - if (rom[i] != addr[i]) - return FALSE; - return TRUE; - case 0xCC: // SKIP ROM - return TRUE; - default: // Unknown command - if (errno == ONEWIRE_NO_ERROR) - return FALSE; - else - return FALSE; - } - } -} - -bool OWSlave::search() { - uint8_t bitmask; - uint8_t bit_send, bit_recv; - - for (int i=0; i<8; i++) { - for (bitmask = 0x01; bitmask; bitmask <<= 1) { - bit_send = (bitmask & rom[i])?1:0; - sendBit(bit_send); - sendBit(!bit_send); - bit_recv = recvBit(); - if (errno != ONEWIRE_NO_ERROR) - return FALSE; - if (bit_recv != bit_send) - return FALSE; - } - } - return TRUE; -} - -bool OWSlave::waitReset(uint16_t timeout_ms) { - uint8_t mask = pin_bitmask; - volatile uint8_t *reg asm("r30") = baseReg; - unsigned long time_stamp; - - errno = ONEWIRE_NO_ERROR; - cli(); - DIRECT_MODE_INPUT(reg, mask); - sei(); - if (timeout_ms != 0) { - time_stamp = micros() + timeout_ms*1000; - while (DIRECT_READ(reg, mask)) { - if (micros() > time_stamp) { - errno = ONEWIRE_WAIT_RESET_TIMEOUT; - return FALSE; - } - } - } else - while (DIRECT_READ(reg, mask)) {}; - time_stamp = micros() + 540; - while (DIRECT_READ(reg, mask) == 0) { - if (micros() > time_stamp) { - errno = ONEWIRE_VERY_LONG_RESET; - return FALSE; - } - } - if ((time_stamp - micros()) > 70) { - errno = ONEWIRE_VERY_SHORT_RESET; - return FALSE; - } - delayMicroseconds(30); - return TRUE; -} -bool OWSlave::waitReset() { - return waitReset(1000); -} - -bool OWSlave::presence(uint8_t delta) { - uint8_t mask = pin_bitmask; - volatile uint8_t *reg asm("r30") = baseReg; - - errno = ONEWIRE_NO_ERROR; - cli(); - DIRECT_WRITE_LOW(reg, mask); - DIRECT_MODE_OUTPUT(reg, mask); // drive output low - sei(); - delayMicroseconds(120); - cli(); - DIRECT_MODE_INPUT(reg, mask); // allow it to float - sei(); - delayMicroseconds(300 - delta); - if ( !DIRECT_READ(reg, mask)) { - errno = ONEWIRE_PRESENCE_LOW_ON_LINE; - return FALSE; - } else - return TRUE; -} -bool OWSlave::presence() { - return presence(25); -} - -uint8_t OWSlave::sendData(char buf[], uint8_t len) { - uint8_t bytes_sended = 0; - - for (int i=0; i>= 1; - if (mix) crc ^= 0x8C; - inbyte >>= 1; - } - } - return crc; -} -#endif - -#endif diff --git a/OWSlave.h b/OWSlave.h deleted file mode 100644 index f054858..0000000 --- a/OWSlave.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef iButton_h -#define iButton_h - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -#include - -// You can exclude CRC checks altogether by defining this to 0 -#ifndef OWSlave_CRC -#define OWSlave_CRC 1 -#endif - -// Select the table-lookup method of computing the 8-bit CRC -// by setting this to 1. The lookup table no longer consumes -// limited RAM, but enlarges total code size by about 250 bytes -#ifndef OWSlave_CRC8_TABLE -#define OWSlave_CRC8_TABLE 0 -#endif - -#define FALSE 0 -#define TRUE 1 - -#define ONEWIRE_NO_ERROR 0 -#define ONEWIRE_READ_TIMESLOT_TIMEOUT 1 -#define ONEWIRE_WRITE_TIMESLOT_TIMEOUT 2 -#define ONEWIRE_WAIT_RESET_TIMEOUT 3 -#define ONEWIRE_VERY_LONG_RESET 4 -#define ONEWIRE_VERY_SHORT_RESET 5 -#define ONEWIRE_PRESENCE_LOW_ON_LINE 6 - -class OWSlave { - private: - bool waitTimeSlot(); - uint8_t pin_bitmask; - volatile uint8_t *baseReg; - char rom[8]; - public: - bool recvAndProcessCmd(); - OWSlave(uint8_t pin); - void setRom(unsigned char rom[8]); - void setRomnc(unsigned char rom[8]); - bool waitForRequest(bool ignore_errors); - bool waitReset(uint16_t timeout_ms); - bool waitReset(); - bool presence(uint8_t delta); - bool presence(); - bool search(); - uint8_t sendData(char buf[], uint8_t data_len); - uint8_t recvData(char buf[], uint8_t data_len); - void send(uint8_t v); - uint8_t recv(void); - void sendBit(uint8_t v); - uint8_t recvBit(void); -#if OWSlave_CRC - static uint8_t crc8(char addr[], uint8_t len); -#endif - uint8_t errno; -}; - -#endif diff --git a/OneWireIO.ino b/OneWireIO.ino index 5f04bc0..fa2253e 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -1,15 +1,21 @@ -#include "OWSlave.h" +#include "Arduino.h" +#include "SerialChannel.h" #define LEDPin 13 #define OWPin 2 #define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 -unsigned char rom[8] = {0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; +const int SkipSamples = 8; // how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) +const int BufferSize = 128; +byte buffer1[BufferSize]; +byte buffer2[BufferSize]; +byte* backBuffer = buffer1; +byte backBufferPos = 0; +byte samplesSkipped = SkipSamples; +unsigned long backBufferStartTime = micros(); -volatile long prevInt = 0; // Previous Interrupt micros -volatile boolean owReset = false; - -OWSlave oneWire(OWPin); +SerialChannel oscilloscope; +SerialChannel debug; void setup() { @@ -20,43 +26,69 @@ void setup() attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); - oneWire.setRom(rom); + cli();//disable interrupts + + //set up continuous sampling of analog pin 0 + //clear ADCSRA and ADCSRB registers + ADCSRA = 0; + ADCSRB = 0; + + ADMUX |= (1 << REFS0); //set reference voltage + ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only + + ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); //set ADC clock with 128 prescaler- 16mHz/128=125kHz ; 13 cycles for a conversion which means 9600 samples per second + ADCSRA |= (1 << ADATE); //enabble auto trigger + ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete + ADCSRA |= (1 << ADEN); //enable ADC + ADCSRA |= (1 << ADSC); //start ADC measurements + + sei();//enable interrupts + + Serial.begin(9600); + oscilloscope.init("oscilloscope"); + debug.init("debug"); } void loop() { - if (owReset) owHandler(); + cli();//disable interrupts + byte* currentBuffer = backBuffer; + unsigned long currentBufferStartTime = backBufferStartTime; + byte currentBufferSize = backBufferPos; + backBuffer = (backBuffer == buffer1 ? buffer2 : buffer1); + backBufferPos = 0; + backBufferStartTime = micros(); + sei();//enable interrupts + + unsigned long now = micros(); + debug.write((byte*)&now, 4); + debug.write("Starting buffer transmission"); + + oscilloscope.write((byte*)¤tBufferStartTime, 4); + oscilloscope.write(currentBuffer, currentBufferSize); + + now = micros(); + debug.write((byte*)&now, 4); + debug.write("Buffer transmitted"); } -void owHandler(void) -{ - detachInterrupt(InterruptNumber); - owReset=false; - - if (oneWire.presence()) { - if (oneWire.recvAndProcessCmd()) { - uint8_t cmd = oneWire.recv(); - if (cmd == 0x44) { - digitalWrite(LEDPin, HIGH); - } - if (cmd == 0xBE) { - for( int i = 0; i < 9; i++) { - oneWire.send((byte)0); - } - } - } +ISR(ADC_vect) {//when new ADC value ready + byte sample = ADCH; //store 8 bit value from analog pin 0 + + if(samplesSkipped++ < SkipSamples) + return; + samplesSkipped = 0; + + backBuffer[backBufferPos++] = sample; + if(backBufferPos >= BufferSize) + { + // overflow of back buffer, we loose the current sample + backBufferPos = BufferSize - 1; } - attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); } void onewireInterrupt(void) { - volatile long lastMicros = micros() - prevInt; - prevInt = micros(); - if (lastMicros >= 410 && lastMicros <= 550) - { - // OneWire Reset Detected - owReset=true; - } + //digitalWrite(LEDPin, digitalRead(OWPin)); } - + diff --git a/SerialChannel.cpp b/SerialChannel.cpp new file mode 100644 index 0000000..64b57f5 --- /dev/null +++ b/SerialChannel.cpp @@ -0,0 +1,29 @@ +#include "Arduino.h" +#include "SerialChannel.h" + +short SerialChannel::nextId = 0; + +SerialChannel::SerialChannel() +{ +} + +void SerialChannel::init(const char* name) +{ + id = nextId++; + Serial.write((short)0); + Serial.write(id); + Serial.write(strlen(name)); + Serial.write(name); +} + +void SerialChannel::write(byte* data, short byteCount) +{ + Serial.write(byteCount); + Serial.write(id); + Serial.write(data, byteCount); +} + +void SerialChannel::write(const char* text) +{ + Serial.write((byte*)text, strlen(text)); +} diff --git a/SerialChannel.h b/SerialChannel.h new file mode 100644 index 0000000..3c66d7d --- /dev/null +++ b/SerialChannel.h @@ -0,0 +1,21 @@ +#ifndef _SerialChannel_h_ +#define _SerialChannel_h_ + +class SerialChannel +{ +private: + static short nextId; + short id; + +public: + SerialChannel(); + + void init(const char* name); + + void write(byte* data, short byteCount); + + void write(const char* text); +}; + +#endif + diff --git a/SerialMonitor/SerialMonitor.sln b/SerialMonitor/SerialMonitor.sln new file mode 100644 index 0000000..f11d68b --- /dev/null +++ b/SerialMonitor/SerialMonitor.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialMonitor", "SerialMonitor\SerialMonitor.csproj", "{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/SerialMonitor/SerialMonitor/App.config b/SerialMonitor/SerialMonitor/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/SerialMonitor/SerialMonitor/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SerialMonitor/SerialMonitor/App.xaml b/SerialMonitor/SerialMonitor/App.xaml new file mode 100644 index 0000000..cc3b030 --- /dev/null +++ b/SerialMonitor/SerialMonitor/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs new file mode 100644 index 0000000..0ea20d1 --- /dev/null +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SerialMonitor +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml b/SerialMonitor/SerialMonitor/MainWindow.xaml new file mode 100644 index 0000000..51b1a8f --- /dev/null +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs new file mode 100644 index 0000000..11f2c90 --- /dev/null +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SerialMonitor +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs b/SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e61c9f3 --- /dev/null +++ b/SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SerialMonitor")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("SerialMonitor")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs b/SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs new file mode 100644 index 0000000..b6091de --- /dev/null +++ b/SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SerialMonitor.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SerialMonitor.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/SerialMonitor/SerialMonitor/Properties/Resources.resx b/SerialMonitor/SerialMonitor/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/SerialMonitor/SerialMonitor/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs b/SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs new file mode 100644 index 0000000..098d3a4 --- /dev/null +++ b/SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SerialMonitor.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/SerialMonitor/SerialMonitor/Properties/Settings.settings b/SerialMonitor/SerialMonitor/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/SerialMonitor/SerialMonitor/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SerialMonitor/SerialMonitor/SerialMonitor.csproj b/SerialMonitor/SerialMonitor/SerialMonitor.csproj new file mode 100644 index 0000000..6cb916e --- /dev/null +++ b/SerialMonitor/SerialMonitor/SerialMonitor.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B} + WinExe + Properties + SerialMonitor + SerialMonitor + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + \ No newline at end of file From b728db1e262bdaa64b031c95f35d76d151459352 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 12 Apr 2015 12:16:54 +0200 Subject: [PATCH 04/32] first version of debug messages display in Serial Monitor console --- OneWireIO.ino | 13 +-- SerialChannel.cpp | 69 ++++++++++++--- SerialChannel.h | 19 +++-- SerialMonitor/SerialMonitor/App.xaml | 12 ++- SerialMonitor/SerialMonitor/App.xaml.cs | 83 +++++++++++++++++++ SerialMonitor/SerialMonitor/MainWindow.xaml | 7 +- .../SerialMonitor/MainWindow.xaml.cs | 3 + .../SerialMonitor/MainWindowContext.cs | 40 +++++++++ SerialMonitor/SerialMonitor/SerialMessage.cs | 26 ++++++ .../SerialMonitor/SerialMonitor.csproj | 3 + .../SerialMonitor/SerialPortExtensions.cs | 44 ++++++++++ 11 files changed, 287 insertions(+), 32 deletions(-) create mode 100644 SerialMonitor/SerialMonitor/MainWindowContext.cs create mode 100644 SerialMonitor/SerialMonitor/SerialMessage.cs create mode 100644 SerialMonitor/SerialMonitor/SerialPortExtensions.cs diff --git a/OneWireIO.ino b/OneWireIO.ino index fa2253e..9bdce34 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -14,8 +14,8 @@ byte backBufferPos = 0; byte samplesSkipped = SkipSamples; unsigned long backBufferStartTime = micros(); -SerialChannel oscilloscope; -SerialChannel debug; +SerialChannel oscilloscope("oscilloscope"); +SerialChannel debug("debug"); void setup() { @@ -45,8 +45,6 @@ void setup() sei();//enable interrupts Serial.begin(9600); - oscilloscope.init("oscilloscope"); - debug.init("debug"); } void loop() @@ -60,15 +58,10 @@ void loop() backBufferStartTime = micros(); sei();//enable interrupts - unsigned long now = micros(); - debug.write((byte*)&now, 4); debug.write("Starting buffer transmission"); - oscilloscope.write((byte*)¤tBufferStartTime, 4); - oscilloscope.write(currentBuffer, currentBufferSize); + oscilloscope.write(currentBuffer, currentBufferSize, currentBufferStartTime); - now = micros(); - debug.write((byte*)&now, 4); debug.write("Buffer transmitted"); } diff --git a/SerialChannel.cpp b/SerialChannel.cpp index 64b57f5..51c716e 100644 --- a/SerialChannel.cpp +++ b/SerialChannel.cpp @@ -1,29 +1,72 @@ #include "Arduino.h" #include "SerialChannel.h" -short SerialChannel::nextId = 0; +byte SerialChannel::nextId = 1; +SerialChannel* SerialChannel::first = 0; -SerialChannel::SerialChannel() +SerialChannel::SerialChannel(const char* name_) + : next(0) + , id((byte)-1) + , name(name_) { + if(first == 0) + first = this; + else + { + SerialChannel* c = first; + while(c->next != 0) c = c->next; + c->next = this; + } + + id = nextId++; } -void SerialChannel::init(const char* name) +void SerialChannel::write(byte* data, short byteCount, unsigned long time) { - id = nextId++; - Serial.write((short)0); + if (time == (unsigned long)-1) + time = micros(); + + handleConnection(); + + Serial.write("START"); Serial.write(id); - Serial.write(strlen(name)); - Serial.write(name); + writeULong(time); + writeShort(byteCount); + Serial.write(data, byteCount); } -void SerialChannel::write(byte* data, short byteCount) +void SerialChannel::write(const char* text, unsigned long time) { - Serial.write(byteCount); - Serial.write(id); - Serial.write(data, byteCount); + write((byte*)text, strlen(text), time); } -void SerialChannel::write(const char* text) +void SerialChannel::writeShort(short num) { - Serial.write((byte*)text, strlen(text)); + Serial.write((byte*)&num, 2); } + +void SerialChannel::writeULong(unsigned long num) +{ + Serial.write((byte*)&num, 4); +} + +void SerialChannel::handleConnection() +{ + int b = Serial.read(); + if(b == (int)'C') + { + Serial.write("CONNECTION"); + SerialChannel* c = first; + while(c) + { + Serial.write("START"); + Serial.write(0); + Serial.write("ChannelInit"); + Serial.write(c->id); + writeShort(strlen(c->name)); + Serial.write(c->name); + c = c->next; + } + } +} + diff --git a/SerialChannel.h b/SerialChannel.h index 3c66d7d..7a2d5f8 100644 --- a/SerialChannel.h +++ b/SerialChannel.h @@ -4,17 +4,24 @@ class SerialChannel { private: - static short nextId; - short id; + static SerialChannel* first; + SerialChannel* next; + + static byte nextId; + byte id; + const char* name; public: - SerialChannel(); + SerialChannel(const char* name_); - void init(const char* name); + void write(byte* data, short byteCount, unsigned long time = (unsigned long)-1); - void write(byte* data, short byteCount); + void write(const char* text, unsigned long time = (unsigned long)-1); - void write(const char* text); +private: + void handleConnection(); + void writeShort(short num); + void writeULong(unsigned long num); }; #endif diff --git a/SerialMonitor/SerialMonitor/App.xaml b/SerialMonitor/SerialMonitor/App.xaml index cc3b030..a998b86 100644 --- a/SerialMonitor/SerialMonitor/App.xaml +++ b/SerialMonitor/SerialMonitor/App.xaml @@ -3,6 +3,16 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml"> - + + + + diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs index 0ea20d1..24feecc 100644 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -2,9 +2,14 @@ using System.Collections.Generic; using System.Configuration; using System.Data; +using System.Diagnostics; +using System.IO.Ports; using System.Linq; +using System.Text; using System.Threading.Tasks; using System.Windows; +using System.Windows.Shapes; +using System.Windows.Threading; namespace SerialMonitor { @@ -13,5 +18,83 @@ namespace SerialMonitor /// public partial class App : Application { + private SerialPort Serial; + private IDictionary Channels = new Dictionary(); + private bool Connected = false; + + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + + Serial = new SerialPort(); + Serial.PortName = "COM4"; + Serial.BaudRate = 9600; + + Serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(OnDataReceived); + + Serial.Open(); + } + + private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) + { + if (!Connected) + { + Serial.Write("C"); + Serial.ReadTo("CONNECTION"); + Connected = true; + } + + // channel declaration message: byte 0 ; string "ChannelInit" ; byte ; short ; byte[length] + // regular message: byte ; short ; byte[length] + + SerialMessage message = null; + + Serial.ReadTo("START"); + + int id = Serial.ReadByte(); + if (id == 0) + { + string check = Encoding.UTF8.GetString(Serial.ReadBytes(11)); + if (check != "ChannelInit") + throw new Exception("Incorrect data check for channel initialization"); + id = Serial.ReadByte(); + int length = Serial.ReadShort(); + string name = Encoding.UTF8.GetString(Serial.ReadBytes(length)); + Channels[id] = name; + message = new SerialMessage { ChannelName = "debug", StringData = "Channel " + name + " opened", SendTime = 0 }; + } + else + { + ulong sendTime = Serial.ReadULong(); + int length = Serial.ReadShort(); + byte[] data = Serial.ReadBytes(length); + message = new SerialMessage { ChannelName = Channels[id], Data = data, SendTime = sendTime }; + } + + if(message != null) + Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => OnMessageReceived(message))); + } + + private void OnMessageReceived(SerialMessage message) + { + switch (message.ChannelName) + { + case "debug": + string text = ((float)message.SendTime / 1000000).ToString("0.000") + "s " + message.StringData; + //Debug.WriteLine(text); + MainWindowContext.Get.WriteLine(text); + break; + case "oscilloscope": + /*float visibleDuration = 10.0f; + float sampleDelay = 0.000936f; + float startOffset = (float)message.SendTime / 1000000; + for (int i = 1; i < message.Data.Length; ++i ) + { + var line = new Line(); + canvas.Children.Add(line); + }*/ + break; + } + } } } diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml b/SerialMonitor/SerialMonitor/MainWindow.xaml index 51b1a8f..765f627 100644 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml @@ -1,8 +1,11 @@  + Title="Serial Monitor" Height="396" Width="629"> - + + + + diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs index 11f2c90..d0f0a1d 100644 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs @@ -23,6 +23,9 @@ namespace SerialMonitor public MainWindow() { InitializeComponent(); + var context = new MainWindowContext(); + context.WriteLine("Connecting..."); + this.DataContext = context; } } } diff --git a/SerialMonitor/SerialMonitor/MainWindowContext.cs b/SerialMonitor/SerialMonitor/MainWindowContext.cs new file mode 100644 index 0000000..b16f54f --- /dev/null +++ b/SerialMonitor/SerialMonitor/MainWindowContext.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SerialMonitor +{ + public class MainWindowContext : INotifyPropertyChanged + { + public MainWindowContext() + { + Get = this; + } + + public static MainWindowContext Get { get; private set; } + + private List Lines = new List(); + public string ConsoleText { get { return String.Join("\n", Lines); } } + + public void WriteLine(string line) + { + Lines.Add(line); + if (Lines.Count > 9) + Lines.RemoveAt(0); + OnPropertyChanged("ConsoleText"); + } + + public event PropertyChangedEventHandler PropertyChanged; + protected void OnPropertyChanged(string name) + { + PropertyChangedEventHandler handler = PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(name)); + } + } + } +} diff --git a/SerialMonitor/SerialMonitor/SerialMessage.cs b/SerialMonitor/SerialMonitor/SerialMessage.cs new file mode 100644 index 0000000..4e4ed5a --- /dev/null +++ b/SerialMonitor/SerialMonitor/SerialMessage.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SerialMonitor +{ + public class SerialMessage + { + public string ChannelName { get; set; } + + /// + /// Time at which the message was sent, in microseconds since the start of the remote executable + /// + public ulong SendTime { get; set; } + + public byte[] Data { get; set; } + + public string StringData + { + get { return Encoding.UTF8.GetString(Data); } + set { Data = Encoding.UTF8.GetBytes(value); } + } + } +} diff --git a/SerialMonitor/SerialMonitor/SerialMonitor.csproj b/SerialMonitor/SerialMonitor/SerialMonitor.csproj index 6cb916e..1638f28 100644 --- a/SerialMonitor/SerialMonitor/SerialMonitor.csproj +++ b/SerialMonitor/SerialMonitor/SerialMonitor.csproj @@ -53,6 +53,9 @@ MSBuild:Compile Designer + + + MSBuild:Compile Designer diff --git a/SerialMonitor/SerialMonitor/SerialPortExtensions.cs b/SerialMonitor/SerialMonitor/SerialPortExtensions.cs new file mode 100644 index 0000000..91e98bc --- /dev/null +++ b/SerialMonitor/SerialMonitor/SerialPortExtensions.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SerialMonitor +{ + public static class SerialPortExtensions + { + public static int ReadShort(this SerialPort port) + { + int b1 = port.ReadByte(); + int b2 = port.ReadByte(); + return b2 * 256 + b1; + } + + public static ulong ReadULong(this SerialPort port) + { + ulong b1 = (ulong)port.ReadByte(); + ulong b2 = (ulong)port.ReadByte(); + ulong b3 = (ulong)port.ReadByte(); + ulong b4 = (ulong)port.ReadByte(); + return b4 * 256 * 256 * 256 + b3 * 256 * 256 + b2 * 256 + b1; + } + + public static byte[] ReadBytes(this SerialPort port, int numBytes) + { + var bytes = new byte[numBytes]; + int remaining = numBytes; + int pos = 0; + while (remaining > 0) + { + int read = port.Read(bytes, pos, remaining); + if (read < 0) + throw new Exception("Connection closed"); + remaining -= read; + pos += read; + } + return bytes; + } + } +} From 691ce28d9563178a5569d0b06c10d9636f4af870 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 12 Apr 2015 19:49:17 +0200 Subject: [PATCH 05/32] basic display of oscilloscope values in SerialMonitor (no zoom or scroll yet) --- OneWireIO.ino | 9 +-- SerialMonitor/SerialMonitor/App.xaml.cs | 11 +-- SerialMonitor/SerialMonitor/MainWindow.xaml | 2 +- .../SerialMonitor/MainWindow.xaml.cs | 2 +- .../SerialMonitor/MainWindowContext.cs | 80 ++++++++++++++++++- 5 files changed, 86 insertions(+), 18 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 9bdce34..925f199 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -10,7 +10,7 @@ const int BufferSize = 128; byte buffer1[BufferSize]; byte buffer2[BufferSize]; byte* backBuffer = buffer1; -byte backBufferPos = 0; +volatile byte backBufferPos = 0; byte samplesSkipped = SkipSamples; unsigned long backBufferStartTime = micros(); @@ -44,11 +44,12 @@ void setup() sei();//enable interrupts - Serial.begin(9600); + Serial.begin(200000); } void loop() { + while(backBufferPos < BufferSize / 2) ; cli();//disable interrupts byte* currentBuffer = backBuffer; unsigned long currentBufferStartTime = backBufferStartTime; @@ -58,11 +59,7 @@ void loop() backBufferStartTime = micros(); sei();//enable interrupts - debug.write("Starting buffer transmission"); - oscilloscope.write(currentBuffer, currentBufferSize, currentBufferStartTime); - - debug.write("Buffer transmitted"); } ISR(ADC_vect) {//when new ADC value ready diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs index 24feecc..ac44671 100644 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -28,7 +28,7 @@ namespace SerialMonitor Serial = new SerialPort(); Serial.PortName = "COM4"; - Serial.BaudRate = 9600; + Serial.BaudRate = 200000; Serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(OnDataReceived); @@ -85,14 +85,7 @@ namespace SerialMonitor MainWindowContext.Get.WriteLine(text); break; case "oscilloscope": - /*float visibleDuration = 10.0f; - float sampleDelay = 0.000936f; - float startOffset = (float)message.SendTime / 1000000; - for (int i = 1; i < message.Data.Length; ++i ) - { - var line = new Line(); - canvas.Children.Add(line); - }*/ + MainWindowContext.Get.AddSequence(message.SendTime, message.Data); break; } } diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml b/SerialMonitor/SerialMonitor/MainWindow.xaml index 765f627..98617aa 100644 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml @@ -5,7 +5,7 @@ - + diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs index d0f0a1d..9a6318d 100644 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs @@ -23,7 +23,7 @@ namespace SerialMonitor public MainWindow() { InitializeComponent(); - var context = new MainWindowContext(); + var context = new MainWindowContext(this); context.WriteLine("Connecting..."); this.DataContext = context; } diff --git a/SerialMonitor/SerialMonitor/MainWindowContext.cs b/SerialMonitor/SerialMonitor/MainWindowContext.cs index b16f54f..e329a90 100644 --- a/SerialMonitor/SerialMonitor/MainWindowContext.cs +++ b/SerialMonitor/SerialMonitor/MainWindowContext.cs @@ -4,13 +4,19 @@ using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Shapes; namespace SerialMonitor { public class MainWindowContext : INotifyPropertyChanged { - public MainWindowContext() + private MainWindow Window; + + public MainWindowContext(MainWindow window) { + Window = window; Get = this; } @@ -27,6 +33,78 @@ namespace SerialMonitor OnPropertyChanged("ConsoleText"); } + private class Sequence + { + public ulong StartTime { get; set; } + public byte[] Data { get; set; } + + public class Comparer : IComparer + { + public int Compare(Sequence x, Sequence y) + { + return x.StartTime.CompareTo(y.StartTime); + } + } + } + double ValueToHeight(byte value) { return (double)value + 10; } + private SortedSet Sequences = new SortedSet(new Sequence.Comparer()); + public IEnumerable Oscilloscope + { + get + { + if(!Sequences.Any()) + yield break; + + ulong startTime = Sequences.ElementAt(0).StartTime; + + foreach (var sequence in Sequences) + { + foreach (var line in ConvertToLines(sequence, startTime)) + yield return line; + } + } + } + + private IEnumerable ConvertToLines(Sequence sequence, ulong displayStartTime) + { + double sampleDelay = 0.000936; // in seconds + double scale = 10; // in pixels per second + + double pos = (sequence.StartTime - displayStartTime) / 1000000.0 * scale; + if (pos > 1000) + yield break; + double prevHeight = ValueToHeight(sequence.Data[0]); + for (int idx = 1; idx < sequence.Data.Length; ++idx) + { + byte value = sequence.Data[idx]; + var line = new Line(); + line.Stroke = System.Windows.Media.Brushes.LightSteelBlue; + line.X1 = pos; + pos += sampleDelay * scale; + line.X2 = pos; + line.Y1 = prevHeight; + prevHeight = ValueToHeight(value); + line.Y2 = prevHeight; + line.HorizontalAlignment = HorizontalAlignment.Left; + line.VerticalAlignment = VerticalAlignment.Center; + line.StrokeThickness = 1; + yield return line; + } + } + + public void AddSequence(ulong startTime, byte[] data) + { + var sequence = new Sequence { StartTime = startTime, Data = data }; + Sequences.Add(sequence); + OnPropertyChanged("Oscilloscope"); + var canvas = (Canvas)Window.FindName("Oscilloscope"); + /*canvas.Children.Clear(); + foreach (var line in Oscilloscope) + canvas.Children.Add(line);*/ + foreach (var line in ConvertToLines(sequence, Sequences.ElementAt(0).StartTime)) + canvas.Children.Add(line); + } + public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string name) { From d0ef4ee9f9a33d8619cac85e3a55900ae44edb90 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Tue, 14 Apr 2015 00:16:48 +0200 Subject: [PATCH 06/32] finished basic oscilloscope functionalities (max sampling rate seems to be 38KHz) --- OneWireIO.ino | 27 ++-- SerialMonitor/SerialMonitor/App.xaml.cs | 2 +- SerialMonitor/SerialMonitor/MainWindow.xaml | 15 +- .../SerialMonitor/MainWindow.xaml.cs | 31 ++++ .../SerialMonitor/MainWindowContext.cs | 152 ++++++++++++++---- SerialMonitor/SerialMonitor/MathEx.cs | 21 +++ .../SerialMonitor/SerialMonitor.csproj | 1 + 7 files changed, 204 insertions(+), 45 deletions(-) create mode 100644 SerialMonitor/SerialMonitor/MathEx.cs diff --git a/OneWireIO.ino b/OneWireIO.ino index 925f199..c6bf7b7 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -5,12 +5,14 @@ #define OWPin 2 #define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 -const int SkipSamples = 8; // how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) -const int BufferSize = 128; +// how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) +#define SkipSamples 0 + +const int BufferSize = 512; byte buffer1[BufferSize]; byte buffer2[BufferSize]; byte* backBuffer = buffer1; -volatile byte backBufferPos = 0; +volatile short backBufferPos = 0; byte samplesSkipped = SkipSamples; unsigned long backBufferStartTime = micros(); @@ -24,7 +26,7 @@ void setup() digitalWrite(LEDPin, LOW); - attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); + //attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); cli();//disable interrupts @@ -36,7 +38,7 @@ void setup() ADMUX |= (1 << REFS0); //set reference voltage ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only - ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); //set ADC clock with 128 prescaler- 16mHz/128=125kHz ; 13 cycles for a conversion which means 9600 samples per second + ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second ADCSRA |= (1 << ADATE); //enabble auto trigger ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete ADCSRA |= (1 << ADEN); //enable ADC @@ -44,7 +46,7 @@ void setup() sei();//enable interrupts - Serial.begin(200000); + Serial.begin(400000); } void loop() @@ -52,27 +54,32 @@ void loop() while(backBufferPos < BufferSize / 2) ; cli();//disable interrupts byte* currentBuffer = backBuffer; - unsigned long currentBufferStartTime = backBufferStartTime; - byte currentBufferSize = backBufferPos; + short currentBufferSize = backBufferPos; backBuffer = (backBuffer == buffer1 ? buffer2 : buffer1); backBufferPos = 0; - backBufferStartTime = micros(); sei();//enable interrupts + unsigned long currentBufferStartTime = backBufferStartTime; + backBufferStartTime = micros(); + digitalWrite(LEDPin, LOW); + //Serial.write(currentBuffer, currentBufferSize); oscilloscope.write(currentBuffer, currentBufferSize, currentBufferStartTime); } ISR(ADC_vect) {//when new ADC value ready byte sample = ADCH; //store 8 bit value from analog pin 0 - + + #if SkipSamples > 0 if(samplesSkipped++ < SkipSamples) return; samplesSkipped = 0; + #endif backBuffer[backBufferPos++] = sample; if(backBufferPos >= BufferSize) { // overflow of back buffer, we loose the current sample + digitalWrite(LEDPin, HIGH); backBufferPos = BufferSize - 1; } } diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs index ac44671..74db570 100644 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -28,7 +28,7 @@ namespace SerialMonitor Serial = new SerialPort(); Serial.PortName = "COM4"; - Serial.BaudRate = 200000; + Serial.BaudRate = 400000; Serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(OnDataReceived); diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml b/SerialMonitor/SerialMonitor/MainWindow.xaml index 98617aa..7cb7936 100644 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml @@ -1,11 +1,18 @@  + Title="Serial Monitor" Height="490.75" Width="923"> - - - + + + + + + + + + + diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs index 9a6318d..82c9d9f 100644 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs +++ b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs @@ -26,6 +26,37 @@ namespace SerialMonitor var context = new MainWindowContext(this); context.WriteLine("Connecting..."); this.DataContext = context; + + this.MouseWheel += OnMouseWheel; + } + + private void OnMouseWheel(object sender, MouseWheelEventArgs e) + { + MainWindowContext context = (MainWindowContext)this.DataContext; + Point cursorPos = e.GetPosition(context.OscilloscopeCanvas); + if (cursorPos.X < 0 || cursorPos.X > context.OscilloscopeCanvas.ActualWidth || cursorPos.Y < 0 || cursorPos.Y > context.OscilloscopeCanvas.ActualHeight) + return; + + double cursorPosRatio = cursorPos.X / context.OscilloscopeCanvas.ActualWidth; + double cursorTime = context.ViewportStartTime + cursorPosRatio * context.ViewportTimeWidth; + + double newTimeWidth = context.ViewportTimeWidth; + if (e.Delta > 0) + newTimeWidth /= e.Delta * 0.01; + else if (e.Delta < 0) + newTimeWidth *= -e.Delta * 0.01; + + double totalTimeWidth = Math.Max(0.1, context.MaxTime - context.MinTime); + if (newTimeWidth > totalTimeWidth) + newTimeWidth = totalTimeWidth; + + double newStartTime = cursorTime - cursorPosRatio * newTimeWidth; + if (newStartTime < context.MinTime) + newStartTime = context.MinTime; + if (newStartTime + newTimeWidth > context.MaxTime) + newStartTime = context.MaxTime - newTimeWidth; + + context.SetViewport(newStartTime, newTimeWidth); } } } diff --git a/SerialMonitor/SerialMonitor/MainWindowContext.cs b/SerialMonitor/SerialMonitor/MainWindowContext.cs index e329a90..33d40ec 100644 --- a/SerialMonitor/SerialMonitor/MainWindowContext.cs +++ b/SerialMonitor/SerialMonitor/MainWindowContext.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Input; using System.Windows.Shapes; namespace SerialMonitor @@ -28,11 +30,14 @@ namespace SerialMonitor public void WriteLine(string line) { Lines.Add(line); - if (Lines.Count > 9) + if (Lines.Count > 100) Lines.RemoveAt(0); OnPropertyChanged("ConsoleText"); } + public double SampleDelay { get { return 0.000026; } } + public int MaxSequenceSize { get { return 2048; } } + private class Sequence { public ulong StartTime { get; set; } @@ -46,7 +51,11 @@ namespace SerialMonitor } } } - double ValueToHeight(byte value) { return (double)value + 10; } + double ValueToHeight(double time, byte value) + { + //value = (byte)(Math.Sin(time * 100.0) * 127.0 + 128.0); + return 256.0 - (double)value + 10; + } private SortedSet Sequences = new SortedSet(new Sequence.Comparer()); public IEnumerable Oscilloscope { @@ -54,64 +63,147 @@ namespace SerialMonitor { if(!Sequences.Any()) yield break; - - ulong startTime = Sequences.ElementAt(0).StartTime; foreach (var sequence in Sequences) { - foreach (var line in ConvertToLines(sequence, startTime)) - yield return line; + double seqStartTime = (double)sequence.StartTime/1000000.0; + if (seqStartTime + (double)sequence.Data.Length * SampleDelay > ViewportStartTime && seqStartTime < ViewportStartTime + ViewportTimeWidth) + { + foreach (var line in ConvertToLines(sequence)) + yield return line; + } } } } - private IEnumerable ConvertToLines(Sequence sequence, ulong displayStartTime) + private IEnumerable ConvertToLines(Sequence sequence) { - double sampleDelay = 0.000936; // in seconds - double scale = 10; // in pixels per second + double viewportWidth = OscilloscopeCanvas.ActualWidth; + double scale = viewportWidth / ViewportTimeWidth; // in pixels per second - double pos = (sequence.StartTime - displayStartTime) / 1000000.0 * scale; + ulong displayStartTime = (ulong)(viewportStartTime_ * 1000000.0); + + double pos = ((double)sequence.StartTime - (double)displayStartTime) / 1000000.0 * scale; if (pos > 1000) yield break; - double prevHeight = ValueToHeight(sequence.Data[0]); + double prevPos = pos; + byte minValue = sequence.Data[0]; + byte maxValue = minValue; + int prevIdx = 0; + double prevHeight = ValueToHeight(sequence.StartTime / 1000000.0, minValue); for (int idx = 1; idx < sequence.Data.Length; ++idx) { byte value = sequence.Data[idx]; - var line = new Line(); - line.Stroke = System.Windows.Media.Brushes.LightSteelBlue; - line.X1 = pos; - pos += sampleDelay * scale; - line.X2 = pos; - line.Y1 = prevHeight; - prevHeight = ValueToHeight(value); - line.Y2 = prevHeight; - line.HorizontalAlignment = HorizontalAlignment.Left; - line.VerticalAlignment = VerticalAlignment.Center; - line.StrokeThickness = 1; - yield return line; + pos += SampleDelay * scale; + if (value > maxValue) maxValue = value; + if (value < minValue) minValue = value; + + if (pos > 0 && pos < viewportWidth && pos - prevPos >= 5 || idx == sequence.Data.Length - 1) + { + var line = new Line(); + line.Stroke = System.Windows.Media.Brushes.LightSteelBlue; + line.HorizontalAlignment = HorizontalAlignment.Left; + line.VerticalAlignment = VerticalAlignment.Center; + line.StrokeThickness = 1; + + line.X1 = prevPos; + prevPos = pos; + line.X2 = pos; + + double time = (double)sequence.StartTime / 1000000.0 + (double)idx * SampleDelay; + double lastHeight = ValueToHeight(time, value); + + if (idx == prevIdx + 1) + { + line.Y1 = prevHeight; + line.Y2 = lastHeight; + } + else + { + if (value - minValue > maxValue - value) + { + line.Y1 = ValueToHeight(time, minValue); + line.Y2 = ValueToHeight(time, maxValue); + } + else + { + line.Y1 = ValueToHeight(time, maxValue); + line.Y2 = ValueToHeight(time, minValue); + } + } + + prevHeight = lastHeight; + minValue = value; + maxValue = value; + prevIdx = idx; + + yield return line; + } } } public void AddSequence(ulong startTime, byte[] data) { + // TODO: merge sequences if total size is lower than MaxSequenceSize var sequence = new Sequence { StartTime = startTime, Data = data }; Sequences.Add(sequence); OnPropertyChanged("Oscilloscope"); - var canvas = (Canvas)Window.FindName("Oscilloscope"); - /*canvas.Children.Clear(); + OnPropertyChanged("MinTime"); + OnPropertyChanged("MaxTime"); + if (Sequences.Count == 1) + { + ViewportStartTime = MinTime; + } + + var canvas = OscilloscopeCanvas; + foreach (var line in ConvertToLines(sequence)) + canvas.Children.Add(line); + } + + void RefreshOscilloscope() + { + var canvas = OscilloscopeCanvas; + canvas.Children.Clear(); foreach (var line in Oscilloscope) - canvas.Children.Add(line);*/ - foreach (var line in ConvertToLines(sequence, Sequences.ElementAt(0).StartTime)) canvas.Children.Add(line); } + private Canvas oscilloscopeCanvas_; + public Canvas OscilloscopeCanvas { get { if (oscilloscopeCanvas_ == null) oscilloscopeCanvas_ = (Canvas)Window.FindName("Oscilloscope"); return oscilloscopeCanvas_; } } + + public double MinTime { get { return Sequences.Any() ? (double)Sequences.First().StartTime / 1000000.0 : 0.0; } } + public double MaxTime { get { return Sequences.Any() ? Math.Max(MinTime + 0.1, (double)Sequences.Last().StartTime / 1000000.0) : 0.1; } } + private double viewportTimeWidth_ = 0.1; + public double ViewportTimeWidth + { + get { return viewportTimeWidth_; } + set { viewportTimeWidth_ = value; OnPropertyChanged("ViewportTimeWidth"); RefreshOscilloscope(); } + } + + private double viewportStartTime_ = 0; + public double ViewportStartTime + { + get { return viewportStartTime_; } + set { viewportStartTime_ = value; OnPropertyChanged("ViewportStartTime"); RefreshOscilloscope(); } + } + public double ScrollValue + { + get { return MathEx.Unproject(MathEx.Project(ViewportStartTime, MinTime, MaxTime - ViewportTimeWidth), MinTime, MaxTime); } + set { ViewportStartTime = MathEx.Unproject(MathEx.Project(value, MinTime, MaxTime), MinTime, MaxTime - ViewportTimeWidth); } + } + + public void SetViewport(double startTime, double timeWidth) + { + viewportStartTime_ = startTime; + ViewportTimeWidth = timeWidth; + } + public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string name) { - PropertyChangedEventHandler handler = PropertyChanged; - if (handler != null) + if (PropertyChanged != null) { - handler(this, new PropertyChangedEventArgs(name)); + PropertyChanged(this, new PropertyChangedEventArgs(name)); } } } diff --git a/SerialMonitor/SerialMonitor/MathEx.cs b/SerialMonitor/SerialMonitor/MathEx.cs new file mode 100644 index 0000000..4d6e1e6 --- /dev/null +++ b/SerialMonitor/SerialMonitor/MathEx.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SerialMonitor +{ + public static class MathEx + { + public static double Project(double value, double rangeMin, double rangeMax) + { + return (value - rangeMin) / (rangeMax - rangeMin); + } + + public static double Unproject(double ratio, double rangeMin, double rangeMax) + { + return rangeMin + ratio * (rangeMax - rangeMin); + } + } +} diff --git a/SerialMonitor/SerialMonitor/SerialMonitor.csproj b/SerialMonitor/SerialMonitor/SerialMonitor.csproj index 1638f28..6f58ec6 100644 --- a/SerialMonitor/SerialMonitor/SerialMonitor.csproj +++ b/SerialMonitor/SerialMonitor/SerialMonitor.csproj @@ -54,6 +54,7 @@ Designer + From ef01fe74bb546bea01efcbd3854848627fa6acb6 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Thu, 16 Apr 2015 19:30:57 +0200 Subject: [PATCH 07/32] added code to transmit sample frequency along with sample data (more compatibility between arduino and PC, and possibility to change sampling rate at run-time) --- OneWireIO.ino | 15 ++++++++-- SerialChannel.cpp | 28 +++++++++++++------ SerialChannel.h | 3 ++ SerialMonitor/SerialMonitor/App.xaml.cs | 3 +- .../SerialMonitor/MainWindowContext.cs | 26 ++++++++++++----- 5 files changed, 56 insertions(+), 19 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index c6bf7b7..5ee71f9 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -7,6 +7,7 @@ // how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) #define SkipSamples 0 +byte regularEncodedFrequency; const int BufferSize = 512; byte buffer1[BufferSize]; @@ -38,11 +39,19 @@ void setup() ADMUX |= (1 << REFS0); //set reference voltage ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only - ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second + int ADPS = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); + ADCSRA |= ADPS; //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second ADCSRA |= (1 << ADATE); //enabble auto trigger ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete ADCSRA |= (1 << ADEN); //enable ADC ADCSRA |= (1 << ADSC); //start ADC measurements + + regularEncodedFrequency = (byte)ADPS; + byte skipSamples = 0; + #if SkipSamples > 0 + skipSamples = SkipSamples; + #endif + regularEncodedFrequency |= skipSamples << 3; sei();//enable interrupts @@ -63,7 +72,9 @@ void loop() digitalWrite(LEDPin, LOW); //Serial.write(currentBuffer, currentBufferSize); - oscilloscope.write(currentBuffer, currentBufferSize, currentBufferStartTime); + oscilloscope.beginWrite(currentBufferSize + 1, currentBufferStartTime); + oscilloscope.continueWrite(®ularEncodedFrequency, 1); + oscilloscope.continueWrite(currentBuffer, currentBufferSize); } ISR(ADC_vect) {//when new ADC value ready diff --git a/SerialChannel.cpp b/SerialChannel.cpp index 51c716e..4c8c51d 100644 --- a/SerialChannel.cpp +++ b/SerialChannel.cpp @@ -23,16 +23,26 @@ SerialChannel::SerialChannel(const char* name_) void SerialChannel::write(byte* data, short byteCount, unsigned long time) { - if (time == (unsigned long)-1) - time = micros(); - - handleConnection(); + beginWrite(byteCount, time); + continueWrite(data, byteCount); +} + +void SerialChannel::beginWrite(short byteCount, unsigned long time) +{ + if (time == (unsigned long)-1) + time = micros(); + + handleConnection(); - Serial.write("START"); - Serial.write(id); - writeULong(time); - writeShort(byteCount); - Serial.write(data, byteCount); + Serial.write("START"); + Serial.write(id); + writeULong(time); + writeShort(byteCount); +} + +void SerialChannel::continueWrite(byte* data, short byteCount) +{ + Serial.write(data, byteCount); } void SerialChannel::write(const char* text, unsigned long time) diff --git a/SerialChannel.h b/SerialChannel.h index 7a2d5f8..c58aa4c 100644 --- a/SerialChannel.h +++ b/SerialChannel.h @@ -17,6 +17,9 @@ public: void write(byte* data, short byteCount, unsigned long time = (unsigned long)-1); void write(const char* text, unsigned long time = (unsigned long)-1); + + void beginWrite(short byteCount, unsigned long time = (unsigned long)-1); + void continueWrite(byte* data, short byteCount); private: void handleConnection(); diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs index 74db570..bd2b9f2 100644 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -85,7 +85,8 @@ namespace SerialMonitor MainWindowContext.Get.WriteLine(text); break; case "oscilloscope": - MainWindowContext.Get.AddSequence(message.SendTime, message.Data); + byte frequency = message.Data[0]; + MainWindowContext.Get.AddSequence(message.SendTime, frequency, message.Data.Skip(1).ToArray()); break; } } diff --git a/SerialMonitor/SerialMonitor/MainWindowContext.cs b/SerialMonitor/SerialMonitor/MainWindowContext.cs index 33d40ec..1c34255 100644 --- a/SerialMonitor/SerialMonitor/MainWindowContext.cs +++ b/SerialMonitor/SerialMonitor/MainWindowContext.cs @@ -35,13 +35,13 @@ namespace SerialMonitor OnPropertyChanged("ConsoleText"); } - public double SampleDelay { get { return 0.000026; } } public int MaxSequenceSize { get { return 2048; } } private class Sequence { - public ulong StartTime { get; set; } + public ulong StartTime { get; set; } // time in microseconds of the first sample public byte[] Data { get; set; } + public double Frequency { get; set; } // sampling rate (in samples per second) public class Comparer : IComparer { @@ -67,7 +67,8 @@ namespace SerialMonitor foreach (var sequence in Sequences) { double seqStartTime = (double)sequence.StartTime/1000000.0; - if (seqStartTime + (double)sequence.Data.Length * SampleDelay > ViewportStartTime && seqStartTime < ViewportStartTime + ViewportTimeWidth) + double sampleDelay = 1.0 / sequence.Frequency; + if (seqStartTime + (double)sequence.Data.Length * sampleDelay > ViewportStartTime && seqStartTime < ViewportStartTime + ViewportTimeWidth) { foreach (var line in ConvertToLines(sequence)) yield return line; @@ -82,6 +83,7 @@ namespace SerialMonitor double scale = viewportWidth / ViewportTimeWidth; // in pixels per second ulong displayStartTime = (ulong)(viewportStartTime_ * 1000000.0); + double sampleDelay = 1.0 / sequence.Frequency; double pos = ((double)sequence.StartTime - (double)displayStartTime) / 1000000.0 * scale; if (pos > 1000) @@ -94,7 +96,7 @@ namespace SerialMonitor for (int idx = 1; idx < sequence.Data.Length; ++idx) { byte value = sequence.Data[idx]; - pos += SampleDelay * scale; + pos += sampleDelay * scale; if (value > maxValue) maxValue = value; if (value < minValue) minValue = value; @@ -110,7 +112,7 @@ namespace SerialMonitor prevPos = pos; line.X2 = pos; - double time = (double)sequence.StartTime / 1000000.0 + (double)idx * SampleDelay; + double time = (double)sequence.StartTime / 1000000.0 + (double)idx * sampleDelay; double lastHeight = ValueToHeight(time, value); if (idx == prevIdx + 1) @@ -142,10 +144,20 @@ namespace SerialMonitor } } - public void AddSequence(ulong startTime, byte[] data) + public void AddSequence(ulong startTime, byte frequency, byte[] data) { // TODO: merge sequences if total size is lower than MaxSequenceSize - var sequence = new Sequence { StartTime = startTime, Data = data }; + double cpuClock = 16000000.0; + int adsp0 = (frequency & (1 << 0)) != 0 ? 1 : 0; + int adsp1 = (frequency & (1 << 1)) != 0 ? 1 : 0; + int adsp2 = (frequency & (1 << 2)) != 0 ? 1 : 0; + int skipBit0 = (frequency & (1 << 3)) != 0 ? 1 : 0; + int skipBit1 = (frequency & (1 << 4)) != 0 ? 1 : 0; + int skipBit2 = (frequency & (1 << 5)) != 0 ? 1 : 0; + int adcDivider = 1 << Math.Max(1, adsp0 + adsp1*2 + adsp2*4); + int skip = skipBit0 + skipBit1 * 2 + skipBit2 * 4; + double freq = cpuClock / (double)adcDivider / 13.0 / (double)(1 + skip); + var sequence = new Sequence { StartTime = startTime, Frequency = freq, Data = data }; Sequences.Add(sequence); OnPropertyChanged("Oscilloscope"); OnPropertyChanged("MinTime"); From a474a381f9864ed5aa264534a0f7f6adcd6c1bbf Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Thu, 23 Apr 2015 10:39:45 +0200 Subject: [PATCH 08/32] start of actual OneWireIO project --- OneWireIO.ino | 75 ++-------------------------------- Oscilloscope.ino | 102 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 72 deletions(-) create mode 100644 Oscilloscope.ino diff --git a/OneWireIO.ino b/OneWireIO.ino index 5ee71f9..ad39056 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -5,19 +5,6 @@ #define OWPin 2 #define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 -// how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) -#define SkipSamples 0 -byte regularEncodedFrequency; - -const int BufferSize = 512; -byte buffer1[BufferSize]; -byte buffer2[BufferSize]; -byte* backBuffer = buffer1; -volatile short backBufferPos = 0; -byte samplesSkipped = SkipSamples; -unsigned long backBufferStartTime = micros(); - -SerialChannel oscilloscope("oscilloscope"); SerialChannel debug("debug"); void setup() @@ -27,76 +14,20 @@ void setup() digitalWrite(LEDPin, LOW); - //attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); - - cli();//disable interrupts - - //set up continuous sampling of analog pin 0 - //clear ADCSRA and ADCSRB registers - ADCSRA = 0; - ADCSRB = 0; - - ADMUX |= (1 << REFS0); //set reference voltage - ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only - - int ADPS = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); - ADCSRA |= ADPS; //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second - ADCSRA |= (1 << ADATE); //enabble auto trigger - ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete - ADCSRA |= (1 << ADEN); //enable ADC - ADCSRA |= (1 << ADSC); //start ADC measurements - - regularEncodedFrequency = (byte)ADPS; - byte skipSamples = 0; - #if SkipSamples > 0 - skipSamples = SkipSamples; - #endif - regularEncodedFrequency |= skipSamples << 3; - - sei();//enable interrupts + attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); Serial.begin(400000); } void loop() { - while(backBufferPos < BufferSize / 2) ; cli();//disable interrupts - byte* currentBuffer = backBuffer; - short currentBufferSize = backBufferPos; - backBuffer = (backBuffer == buffer1 ? buffer2 : buffer1); - backBufferPos = 0; - sei();//enable interrupts - unsigned long currentBufferStartTime = backBufferStartTime; - backBufferStartTime = micros(); - digitalWrite(LEDPin, LOW); - //Serial.write(currentBuffer, currentBufferSize); - oscilloscope.beginWrite(currentBufferSize + 1, currentBufferStartTime); - oscilloscope.continueWrite(®ularEncodedFrequency, 1); - oscilloscope.continueWrite(currentBuffer, currentBufferSize); -} - -ISR(ADC_vect) {//when new ADC value ready - byte sample = ADCH; //store 8 bit value from analog pin 0 + sei();//enable interrupts - #if SkipSamples > 0 - if(samplesSkipped++ < SkipSamples) - return; - samplesSkipped = 0; - #endif - - backBuffer[backBufferPos++] = sample; - if(backBufferPos >= BufferSize) - { - // overflow of back buffer, we loose the current sample - digitalWrite(LEDPin, HIGH); - backBufferPos = BufferSize - 1; - } } void onewireInterrupt(void) { - //digitalWrite(LEDPin, digitalRead(OWPin)); + digitalWrite(LEDPin, digitalRead(OWPin)); } - diff --git a/Oscilloscope.ino b/Oscilloscope.ino new file mode 100644 index 0000000..5ee71f9 --- /dev/null +++ b/Oscilloscope.ino @@ -0,0 +1,102 @@ +#include "Arduino.h" +#include "SerialChannel.h" + +#define LEDPin 13 +#define OWPin 2 +#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 + +// how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) +#define SkipSamples 0 +byte regularEncodedFrequency; + +const int BufferSize = 512; +byte buffer1[BufferSize]; +byte buffer2[BufferSize]; +byte* backBuffer = buffer1; +volatile short backBufferPos = 0; +byte samplesSkipped = SkipSamples; +unsigned long backBufferStartTime = micros(); + +SerialChannel oscilloscope("oscilloscope"); +SerialChannel debug("debug"); + +void setup() +{ + pinMode(LEDPin, OUTPUT); + pinMode(OWPin, INPUT); + + digitalWrite(LEDPin, LOW); + + //attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); + + cli();//disable interrupts + + //set up continuous sampling of analog pin 0 + //clear ADCSRA and ADCSRB registers + ADCSRA = 0; + ADCSRB = 0; + + ADMUX |= (1 << REFS0); //set reference voltage + ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only + + int ADPS = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); + ADCSRA |= ADPS; //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second + ADCSRA |= (1 << ADATE); //enabble auto trigger + ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete + ADCSRA |= (1 << ADEN); //enable ADC + ADCSRA |= (1 << ADSC); //start ADC measurements + + regularEncodedFrequency = (byte)ADPS; + byte skipSamples = 0; + #if SkipSamples > 0 + skipSamples = SkipSamples; + #endif + regularEncodedFrequency |= skipSamples << 3; + + sei();//enable interrupts + + Serial.begin(400000); +} + +void loop() +{ + while(backBufferPos < BufferSize / 2) ; + cli();//disable interrupts + byte* currentBuffer = backBuffer; + short currentBufferSize = backBufferPos; + backBuffer = (backBuffer == buffer1 ? buffer2 : buffer1); + backBufferPos = 0; + sei();//enable interrupts + unsigned long currentBufferStartTime = backBufferStartTime; + backBufferStartTime = micros(); + digitalWrite(LEDPin, LOW); + + //Serial.write(currentBuffer, currentBufferSize); + oscilloscope.beginWrite(currentBufferSize + 1, currentBufferStartTime); + oscilloscope.continueWrite(®ularEncodedFrequency, 1); + oscilloscope.continueWrite(currentBuffer, currentBufferSize); +} + +ISR(ADC_vect) {//when new ADC value ready + byte sample = ADCH; //store 8 bit value from analog pin 0 + + #if SkipSamples > 0 + if(samplesSkipped++ < SkipSamples) + return; + samplesSkipped = 0; + #endif + + backBuffer[backBufferPos++] = sample; + if(backBufferPos >= BufferSize) + { + // overflow of back buffer, we loose the current sample + digitalWrite(LEDPin, HIGH); + backBufferPos = BufferSize - 1; + } +} + +void onewireInterrupt(void) +{ + //digitalWrite(LEDPin, digitalRead(OWPin)); +} + From 3359c244ebf03ce89a24a8d1d0c275ba6157112d Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Thu, 23 Apr 2015 15:06:13 +0200 Subject: [PATCH 09/32] oscilloscope burst mode test --- OneWireIO.ino | 90 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 5ee71f9..2c0f6d3 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -8,14 +8,20 @@ // how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) #define SkipSamples 0 byte regularEncodedFrequency; +byte burstEncodedFrequency; -const int BufferSize = 512; +int regularADCSRA; +int burstADCSRA; + +const int BufferSize = 128; +const int BurstBufferSize = 1024; byte buffer1[BufferSize]; byte buffer2[BufferSize]; -byte* backBuffer = buffer1; +byte burstBuffer[BurstBufferSize]; +volatile byte* backBuffer = buffer1; volatile short backBufferPos = 0; byte samplesSkipped = SkipSamples; -unsigned long backBufferStartTime = micros(); +volatile unsigned long backBufferStartTime = micros(); SerialChannel oscilloscope("oscilloscope"); SerialChannel debug("debug"); @@ -39,19 +45,34 @@ void setup() ADMUX |= (1 << REFS0); //set reference voltage ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only - int ADPS = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); - ADCSRA |= ADPS; //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second - ADCSRA |= (1 << ADATE); //enabble auto trigger - ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete - ADCSRA |= (1 << ADEN); //enable ADC - ADCSRA |= (1 << ADSC); //start ADC measurements + byte skipSamples = 0; + #if SkipSamples > 0 + skipSamples = SkipSamples; + #endif + + int ADPS = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); + regularADCSRA = 0; + regularADCSRA |= ADPS; //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second + regularADCSRA |= (1 << ADATE); //enabble auto trigger + regularADCSRA |= (1 << ADIE); //enable interrupts when measurement complete + regularADCSRA |= (1 << ADEN); //enable ADC + regularADCSRA |= (1 << ADSC); //start ADC measurements + + regularEncodedFrequency = (byte)ADPS; + regularEncodedFrequency |= skipSamples << 3; + + ADCSRA = regularADCSRA; + + ADPS = (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); + burstADCSRA = 0; + burstADCSRA |= ADPS; //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second + burstADCSRA |= (1 << ADATE); //enabble auto trigger + burstADCSRA |= (1 << ADIE); //enable interrupts when measurement complete + burstADCSRA |= (1 << ADEN); //enable ADC + burstADCSRA |= (1 << ADSC); //start ADC measurements - regularEncodedFrequency = (byte)ADPS; - byte skipSamples = 0; - #if SkipSamples > 0 - skipSamples = SkipSamples; - #endif - regularEncodedFrequency |= skipSamples << 3; + burstEncodedFrequency = (byte)ADPS; + burstEncodedFrequency |= skipSamples << 3; sei();//enable interrupts @@ -60,20 +81,26 @@ void setup() void loop() { - while(backBufferPos < BufferSize / 2) ; + while(backBufferPos < BufferSize / 2 || (backBuffer == burstBuffer && backBufferPos < BurstBufferSize - 1)) ; cli();//disable interrupts - byte* currentBuffer = backBuffer; + byte* currentBuffer = (byte*)backBuffer; short currentBufferSize = backBufferPos; backBuffer = (backBuffer == buffer1 ? buffer2 : buffer1); backBufferPos = 0; + if(currentBuffer == burstBuffer) + { + ADCSRA = regularADCSRA; + } sei();//enable interrupts unsigned long currentBufferStartTime = backBufferStartTime; backBufferStartTime = micros(); digitalWrite(LEDPin, LOW); + byte encodedFrequency = currentBuffer == burstBuffer ? burstEncodedFrequency : regularEncodedFrequency; + //Serial.write(currentBuffer, currentBufferSize); oscilloscope.beginWrite(currentBufferSize + 1, currentBufferStartTime); - oscilloscope.continueWrite(®ularEncodedFrequency, 1); + oscilloscope.continueWrite(&encodedFrequency, 1); oscilloscope.continueWrite(currentBuffer, currentBufferSize); } @@ -87,12 +114,31 @@ ISR(ADC_vect) {//when new ADC value ready #endif backBuffer[backBufferPos++] = sample; - if(backBufferPos >= BufferSize) + if(backBuffer == burstBuffer) { - // overflow of back buffer, we loose the current sample - digitalWrite(LEDPin, HIGH); - backBufferPos = BufferSize - 1; + if(backBufferPos >= BurstBufferSize) + { + backBufferPos = BurstBufferSize - 1; + } } + else + { + if(backBufferPos >= BufferSize) + { + // overflow of back buffer, we loose the current sample + digitalWrite(LEDPin, HIGH); + backBufferPos = BufferSize - 1; + } + } + + // switch to burst mode if the trigger condition is met + /*if(backBuffer != burstBuffer && sample < 127) + { + backBuffer = burstBuffer; + ADCSRA = burstADCSRA; + backBufferPos = 0; + backBufferStartTime = micros(); + }*/ } void onewireInterrupt(void) From 03c2f0afd3cfeb83868714cd0f01123f2cad870b Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Thu, 23 Apr 2015 17:26:33 +0200 Subject: [PATCH 10/32] implemented reset detection --- LowLevel.h | 93 ++++++++++++++++++++++++++++++++++ OneWireIO.ino | 38 +++++++++++--- OneWireIO.sln | 44 ++++++++++++++++ OneWireIO.vcxproj | 81 ++++++++++++++++++++++++++++++ OneWireIO.vcxproj.filters | 13 +++++ Oscilloscope.ino | 102 -------------------------------------- 6 files changed, 263 insertions(+), 108 deletions(-) create mode 100644 LowLevel.h create mode 100644 OneWireIO.sln create mode 100644 OneWireIO.vcxproj create mode 100644 OneWireIO.vcxproj.filters delete mode 100644 Oscilloscope.ino diff --git a/LowLevel.h b/LowLevel.h new file mode 100644 index 0000000..41ad123 --- /dev/null +++ b/LowLevel.h @@ -0,0 +1,93 @@ +#ifndef _LowLevel_h +#define _LowLevel_h + +#include + +#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: + IO_REG_TYPE mask; + volatile IO_REG_TYPE *reg; + +public: + inline Pin(uint8_t pin) + { + mask = PIN_TO_BITMASK(pin); + reg = PIN_TO_BASEREG(pin); + } + + inline void inputMode() { DIRECT_MODE_INPUT(reg, mask); } + inline void outputMode() { DIRECT_MODE_OUTPUT(reg, mask); } + + inline bool read() { return DIRECT_READ(reg, mask); } + 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(); } +}; + +#endif diff --git a/OneWireIO.ino b/OneWireIO.ino index ad39056..72920bd 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -1,18 +1,27 @@ #include "Arduino.h" +#include "LowLevel.h" #include "SerialChannel.h" #define LEDPin 13 -#define OWPin 2 +#define OWPin 2 #define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 +#define ResetMinDuration 360 +#define ResetMaxDuration 900 + SerialChannel debug("debug"); +Pin owPin(OWPin); +Pin ledPin(LEDPin); + +unsigned long resetStart = (unsigned long)-1; + void setup() { - pinMode(LEDPin, OUTPUT); - pinMode(OWPin, INPUT); + ledPin.outputMode(); + owPin.inputMode(); - digitalWrite(LEDPin, LOW); + ledPin.writeLow(); attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); @@ -23,11 +32,28 @@ void loop() { cli();//disable interrupts - sei();//enable interrupts + sei();//enable interrupts } void onewireInterrupt(void) { - digitalWrite(LEDPin, digitalRead(OWPin)); + bool state = owPin.read(); + unsigned long now = micros(); + + //ledPin.write(state); + + if (!state) + resetStart = now; + + if (state) + { + unsigned long resetDuration = now - resetStart; + if (resetStart != (unsigned long)-1 && resetDuration >= ResetMinDuration && resetDuration <= ResetMaxDuration) + { + debug.write("reset"); + ledPin.writeHigh(); + } + resetStart = (unsigned long)-1; + } } diff --git a/OneWireIO.sln b/OneWireIO.sln new file mode 100644 index 0000000..873e73d --- /dev/null +++ b/OneWireIO.sln @@ -0,0 +1,44 @@ + +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 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialMonitor", "SerialMonitor\SerialMonitor\SerialMonitor.csproj", "{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}" +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 + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Win32.ActiveCfg = Debug|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.Build.0 = Release|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Win32.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/OneWireIO.vcxproj b/OneWireIO.vcxproj new file mode 100644 index 0000000..c0bc860 --- /dev/null +++ b/OneWireIO.vcxproj @@ -0,0 +1,81 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {3B500971-1570-460F-81C3-22AC3B7764B9} + OneWireIO + + + + Application + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + + + Level3 + Disabled + true + D:\Outils\Arduino\hardware\arduino\avr\cores\arduino + _MBCS;%(PreprocessorDefinitions);ARDUINO=160;__AVR__ + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OneWireIO.vcxproj.filters b/OneWireIO.vcxproj.filters new file mode 100644 index 0000000..f361281 --- /dev/null +++ b/OneWireIO.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Oscilloscope.ino b/Oscilloscope.ino deleted file mode 100644 index 5ee71f9..0000000 --- a/Oscilloscope.ino +++ /dev/null @@ -1,102 +0,0 @@ -#include "Arduino.h" -#include "SerialChannel.h" - -#define LEDPin 13 -#define OWPin 2 -#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 - -// how many samples we want to skip between two samples we keep (can be used to lower the sampling frequency) -#define SkipSamples 0 -byte regularEncodedFrequency; - -const int BufferSize = 512; -byte buffer1[BufferSize]; -byte buffer2[BufferSize]; -byte* backBuffer = buffer1; -volatile short backBufferPos = 0; -byte samplesSkipped = SkipSamples; -unsigned long backBufferStartTime = micros(); - -SerialChannel oscilloscope("oscilloscope"); -SerialChannel debug("debug"); - -void setup() -{ - pinMode(LEDPin, OUTPUT); - pinMode(OWPin, INPUT); - - digitalWrite(LEDPin, LOW); - - //attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); - - cli();//disable interrupts - - //set up continuous sampling of analog pin 0 - //clear ADCSRA and ADCSRB registers - ADCSRA = 0; - ADCSRB = 0; - - ADMUX |= (1 << REFS0); //set reference voltage - ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only - - int ADPS = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); - ADCSRA |= ADPS; //set ADC clock with 32 prescaler- 16mHz/32=500KHz ; 13 cycles for a conversion which means 38000 samples per second - ADCSRA |= (1 << ADATE); //enabble auto trigger - ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete - ADCSRA |= (1 << ADEN); //enable ADC - ADCSRA |= (1 << ADSC); //start ADC measurements - - regularEncodedFrequency = (byte)ADPS; - byte skipSamples = 0; - #if SkipSamples > 0 - skipSamples = SkipSamples; - #endif - regularEncodedFrequency |= skipSamples << 3; - - sei();//enable interrupts - - Serial.begin(400000); -} - -void loop() -{ - while(backBufferPos < BufferSize / 2) ; - cli();//disable interrupts - byte* currentBuffer = backBuffer; - short currentBufferSize = backBufferPos; - backBuffer = (backBuffer == buffer1 ? buffer2 : buffer1); - backBufferPos = 0; - sei();//enable interrupts - unsigned long currentBufferStartTime = backBufferStartTime; - backBufferStartTime = micros(); - digitalWrite(LEDPin, LOW); - - //Serial.write(currentBuffer, currentBufferSize); - oscilloscope.beginWrite(currentBufferSize + 1, currentBufferStartTime); - oscilloscope.continueWrite(®ularEncodedFrequency, 1); - oscilloscope.continueWrite(currentBuffer, currentBufferSize); -} - -ISR(ADC_vect) {//when new ADC value ready - byte sample = ADCH; //store 8 bit value from analog pin 0 - - #if SkipSamples > 0 - if(samplesSkipped++ < SkipSamples) - return; - samplesSkipped = 0; - #endif - - backBuffer[backBufferPos++] = sample; - if(backBufferPos >= BufferSize) - { - // overflow of back buffer, we loose the current sample - digitalWrite(LEDPin, HIGH); - backBufferPos = BufferSize - 1; - } -} - -void onewireInterrupt(void) -{ - //digitalWrite(LEDPin, digitalRead(OWPin)); -} - From 8fb20ab065dfe50cf0e92da85fd2c1fda30ddcdb Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Thu, 23 Apr 2015 18:56:18 +0200 Subject: [PATCH 11/32] =?UTF-8?q?improved=20debugging=20messages=20on=20se?= =?UTF-8?q?rial=20port=20(approximate=20measured=20time=20to=20append=20a?= =?UTF-8?q?=20message=20:=2010=C2=B5s=20;=20messages=20are=20actually=20se?= =?UTF-8?q?nt=20later,=20from=20the=20main=20loop)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OneWireIO.ino | 31 ++++++++++--- SerialChannel.cpp | 58 +++++++++++++++++++++++-- SerialChannel.h | 32 ++++++++++++-- SerialMonitor/SerialMonitor/App.xaml.cs | 2 +- 4 files changed, 107 insertions(+), 16 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 72920bd..604a01e 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -6,9 +6,12 @@ #define OWPin 2 #define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 -#define ResetMinDuration 360 +#define ResetMinDuration 480 #define ResetMaxDuration 900 +#define PresenceWaitDuration 30 +#define PresenceDuration 150 + SerialChannel debug("debug"); Pin owPin(OWPin); @@ -16,6 +19,16 @@ Pin ledPin(LEDPin); unsigned long resetStart = (unsigned long)-1; +enum Status +{ + S_WaitReset, + S_WaitPresence, + S_Presence, +}; + +Status status = S_WaitReset; +unsigned long statusChangeTime = (unsigned long)-1; + void setup() { ledPin.outputMode(); @@ -31,9 +44,10 @@ void setup() void loop() { cli();//disable interrupts - + SerialChannel::swap(); sei();//enable interrupts + SerialChannel::flush(); } void onewireInterrupt(void) @@ -48,12 +62,15 @@ void onewireInterrupt(void) if (state) { - unsigned long resetDuration = now - resetStart; - if (resetStart != (unsigned long)-1 && resetDuration >= ResetMinDuration && resetDuration <= ResetMaxDuration) + unsigned long resetDuration = resetStart == (unsigned long)-1 ? (unsigned long)-1 : now - resetStart; + resetStart = (unsigned long)-1; + + if (resetDuration >= ResetMinDuration && resetDuration <= ResetMaxDuration) { - debug.write("reset"); - ledPin.writeHigh(); + debug.SC_APPEND_STR_TIME("reset", now); + status = S_WaitPresence; + statusChangeTime = now; + return; } - resetStart = (unsigned long)-1; } } diff --git a/SerialChannel.cpp b/SerialChannel.cpp index 4c8c51d..73720ae 100644 --- a/SerialChannel.cpp +++ b/SerialChannel.cpp @@ -4,6 +4,12 @@ byte SerialChannel::nextId = 1; SerialChannel* SerialChannel::first = 0; +SerialChannel::Message SerialChannel::buffer1[SerialChannel::MaxPendingMessages]; +SerialChannel::Message SerialChannel::buffer2[SerialChannel::MaxPendingMessages]; +SerialChannel::Message* SerialChannel::backBuffer; +byte SerialChannel::backBufferPos; +byte SerialChannel::frontBufferSize; + SerialChannel::SerialChannel(const char* name_) : next(0) , id((byte)-1) @@ -21,6 +27,14 @@ SerialChannel::SerialChannel(const char* name_) id = nextId++; } +void SerialChannel::beginWriteInChannel(byte id, short byteCount, unsigned long time) +{ + Serial.write("START"); + Serial.write(id); + writeULong(time); + writeShort(byteCount); +} + void SerialChannel::write(byte* data, short byteCount, unsigned long time) { beginWrite(byteCount, time); @@ -34,10 +48,7 @@ void SerialChannel::beginWrite(short byteCount, unsigned long time) handleConnection(); - Serial.write("START"); - Serial.write(id); - writeULong(time); - writeShort(byteCount); + beginWriteInChannel(id, byteCount, time); } void SerialChannel::continueWrite(byte* data, short byteCount) @@ -50,6 +61,44 @@ void SerialChannel::write(const char* text, unsigned long time) write((byte*)text, strlen(text), time); } +void SerialChannel::append(byte* data, short byteCount, unsigned long time) +{ + if (time == (unsigned long)-1) + time = micros(); + + Message& msg = backBuffer[backBufferPos++]; + if (backBufferPos >= MaxPendingMessages) + backBufferPos = MaxPendingMessages - 1; + msg.id = id; + msg.data = data; + msg.byteCount = byteCount; + msg.time = time; +} + +void SerialChannel::append(const char* text, unsigned long time) +{ + append((byte*)text, strlen(text), time); +} + +void SerialChannel::swap() +{ + backBuffer = backBuffer == buffer1 ? buffer2 : buffer1; + frontBufferSize = backBufferPos; + backBufferPos = 0; +} + +void SerialChannel::flush() +{ + handleConnection(); + + Message* frontBuffer = backBuffer == buffer1 ? buffer2 : buffer1; + for (Message* msg = frontBuffer; msg < frontBuffer + frontBufferSize; ++msg) + { + beginWriteInChannel(msg->id, msg->byteCount, msg->time); + Serial.write(msg->data, msg->byteCount); + } +} + void SerialChannel::writeShort(short num) { Serial.write((byte*)&num, 2); @@ -77,6 +126,7 @@ void SerialChannel::handleConnection() Serial.write(c->name); c = c->next; } + Serial.flush(); } } diff --git a/SerialChannel.h b/SerialChannel.h index c58aa4c..116a53c 100644 --- a/SerialChannel.h +++ b/SerialChannel.h @@ -1,9 +1,22 @@ #ifndef _SerialChannel_h_ #define _SerialChannel_h_ +#define SC_APPEND_STR(str) append((byte*)str, sizeof(str)-1) +#define SC_APPEND_STR_TIME(str, time) append((byte*)str, sizeof(str)-1, time) + class SerialChannel { private: + static const byte MaxPendingMessages = 16; + + struct Message + { + byte* data; + unsigned long time; + short byteCount; + byte id; + }; + static SerialChannel* first; SerialChannel* next; @@ -11,20 +24,31 @@ private: byte id; const char* name; + static Message buffer1[MaxPendingMessages]; + static Message buffer2[MaxPendingMessages]; + static Message* backBuffer; + static byte backBufferPos; + static byte frontBufferSize; + public: SerialChannel(const char* name_); + static void beginWriteInChannel(byte id, short byteCount, unsigned long time); void write(byte* data, short byteCount, unsigned long time = (unsigned long)-1); - void write(const char* text, unsigned long time = (unsigned long)-1); void beginWrite(short byteCount, unsigned long time = (unsigned long)-1); void continueWrite(byte* data, short byteCount); + + void append(byte* data, short byteCount, unsigned long time = (unsigned long)-1); + void append(const char* text, unsigned long time = (unsigned long)-1); + static void swap(); + static void flush(); private: - void handleConnection(); - void writeShort(short num); - void writeULong(unsigned long num); + static void handleConnection(); + static void writeShort(short num); + static void writeULong(unsigned long num); }; #endif diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs index bd2b9f2..897717c 100644 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -80,7 +80,7 @@ namespace SerialMonitor switch (message.ChannelName) { case "debug": - string text = ((float)message.SendTime / 1000000).ToString("0.000") + "s " + message.StringData; + string text = ((float)message.SendTime / 1000000).ToString("0.000000") + "s " + message.StringData; //Debug.WriteLine(text); MainWindowContext.Get.WriteLine(text); break; From 8c473f50e445cbe1315c2d979ddecc89fea57631 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Fri, 24 Apr 2015 10:30:11 +0200 Subject: [PATCH 12/32] implemented presence with timer interrupts --- OneWireIO.ino | 96 ++++++++++++++++++++----- OneWireIO.vcxproj | 8 ++- OneWireIO.vcxproj.filters | 6 +- SerialChannel.cpp | 27 ++++++- SerialChannel.h | 8 ++- SerialMonitor/SerialMonitor/App.xaml.cs | 2 +- 6 files changed, 119 insertions(+), 28 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 604a01e..46f43ce 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -10,39 +10,67 @@ #define ResetMaxDuration 900 #define PresenceWaitDuration 30 -#define PresenceDuration 150 +#define PresenceDuration 300 SerialChannel debug("debug"); Pin owPin(OWPin); -Pin ledPin(LEDPin); +Pin owOutTestPin(3); +Pin led(LEDPin); -unsigned long resetStart = (unsigned long)-1; +void owPullLow() +{ + owPin.outputMode(); + owPin.writeLow(); + owOutTestPin.writeLow(); +} -enum Status +void owRelease() { - S_WaitReset, - S_WaitPresence, - S_Presence, -}; + owPin.inputMode(); + owOutTestPin.writeHigh(); +} -Status status = S_WaitReset; -unsigned long statusChangeTime = (unsigned long)-1; +void owWrite(bool value) +{ + if (value) + owRelease(); + else + owPullLow(); +} + +unsigned long resetStart = (unsigned long)-1; void setup() { - ledPin.outputMode(); + led.outputMode(); owPin.inputMode(); + owOutTestPin.outputMode(); + owOutTestPin.writeHigh(); - ledPin.writeLow(); + led.writeLow(); + cli(); // disable interrupts attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); + + // set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A) + // 4us between each tick + TCCR1A = 0; + TCCR1B = 0; + TCNT1 = 0; // initialize counter value to 0 + //TCCR1B |= (1 << WGM12); // turn on CTC mode + //TCCR1B |= (1 << CS11) | (1 << CS10); // Set 64 prescaler + TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt + sei(); // enable interrupts Serial.begin(400000); } +//int count = 0; void loop() { + //if ((count++) % 1000 == 0) + // led.write(!led.read()); cli();//disable interrupts SerialChannel::swap(); sei();//enable interrupts @@ -50,12 +78,26 @@ void loop() SerialChannel::flush(); } +void(*timerEvent)() = 0; +void setTimerEvent(short microSecondsDelay, void(*event)()) +{ + microSecondsDelay -= 10; // this seems to be the typical time taken to initialize the timer on Arduino Uno + + short skipTicks = (microSecondsDelay - 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; + //debug.SC_APPEND_STR_INT("setTimerEvent", (long)skipTicks); + TCNT1 = 0; + OCR1A = skipTicks; + timerEvent = event; + TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler +} + void onewireInterrupt(void) { bool state = owPin.read(); unsigned long now = micros(); - //ledPin.write(state); + //led.write(state); if (!state) resetStart = now; @@ -67,10 +109,32 @@ void onewireInterrupt(void) if (resetDuration >= ResetMinDuration && resetDuration <= ResetMaxDuration) { - debug.SC_APPEND_STR_TIME("reset", now); - status = S_WaitPresence; - statusChangeTime = now; + //debug.SC_APPEND_STR_TIME("reset", now); + setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); return; } } } + +void beginPresence() +{ + //debug.SC_APPEND_STR("beginPresence"); + owPullLow(); + owOutTestPin.writeLow(); + setTimerEvent(PresenceDuration, &endPresence); +} + +void endPresence() +{ + //debug.SC_APPEND_STR("endPresence"); + owRelease(); +} + +ISR(TIMER1_COMPA_vect) // timer1 interrupt +{ + TCCR1B = 0; // disable clock + void(*event)() = timerEvent; + timerEvent = 0; + if (event != 0) + event(); +} diff --git a/OneWireIO.vcxproj b/OneWireIO.vcxproj index c0bc860..5125aed 100644 --- a/OneWireIO.vcxproj +++ b/OneWireIO.vcxproj @@ -44,8 +44,8 @@ Level3 Disabled true - D:\Outils\Arduino\hardware\arduino\avr\cores\arduino - _MBCS;%(PreprocessorDefinitions);ARDUINO=160;__AVR__ + D:\Outils\Arduino\hardware\arduino\avr\cores\arduino;D:\Outils\Arduino\hardware\tools\avr\avr\include + _MBCS;%(PreprocessorDefinitions);ARDUINO=160;__AVR__;UBRRH;__AVR_ATmega328__ true @@ -66,7 +66,9 @@ - + + Document + diff --git a/OneWireIO.vcxproj.filters b/OneWireIO.vcxproj.filters index f361281..ba1919b 100644 --- a/OneWireIO.vcxproj.filters +++ b/OneWireIO.vcxproj.filters @@ -1,8 +1,5 @@  - - - @@ -10,4 +7,7 @@ + + + \ No newline at end of file diff --git a/SerialChannel.cpp b/SerialChannel.cpp index 73720ae..bcf7346 100644 --- a/SerialChannel.cpp +++ b/SerialChannel.cpp @@ -61,7 +61,7 @@ void SerialChannel::write(const char* text, unsigned long time) write((byte*)text, strlen(text), time); } -void SerialChannel::append(byte* data, short byteCount, unsigned long time) +SerialChannel::Message& SerialChannel::append(byte* data, short byteCount, unsigned long time) { if (time == (unsigned long)-1) time = micros(); @@ -73,6 +73,9 @@ void SerialChannel::append(byte* data, short byteCount, unsigned long time) msg.data = data; msg.byteCount = byteCount; msg.time = time; + msg.longArg0 = 0; + + return msg; } void SerialChannel::append(const char* text, unsigned long time) @@ -80,6 +83,12 @@ void SerialChannel::append(const char* text, unsigned long time) append((byte*)text, strlen(text), time); } +void SerialChannel::appendInt(const char* text, short textLength, int arg0, unsigned long time) +{ + Message& msg = append((byte*)text, textLength, time); + msg.longArg0 = arg0 | 0x40000000; +} + void SerialChannel::swap() { backBuffer = backBuffer == buffer1 ? buffer2 : buffer1; @@ -94,9 +103,21 @@ void SerialChannel::flush() Message* frontBuffer = backBuffer == buffer1 ? buffer2 : buffer1; for (Message* msg = frontBuffer; msg < frontBuffer + frontBufferSize; ++msg) { - beginWriteInChannel(msg->id, msg->byteCount, msg->time); + char params[32]; + params[0] = 0; + + if ((msg->longArg0 & 0x40000000) != 0) + sprintf(params, ";arg0=%ld", msg->longArg0 & ~0x40000000); + + short paramsSize = strlen(params); + + beginWriteInChannel(msg->id, msg->byteCount + paramsSize, msg->time); Serial.write(msg->data, msg->byteCount); + if (paramsSize > 0) + Serial.write(params, paramsSize); } + + Serial.flush(); } void SerialChannel::writeShort(short num) @@ -114,7 +135,7 @@ void SerialChannel::handleConnection() int b = Serial.read(); if(b == (int)'C') { - Serial.write("CONNECTION"); + Serial.write("CONNECTION"); SerialChannel* c = first; while(c) { diff --git a/SerialChannel.h b/SerialChannel.h index 116a53c..0231f24 100644 --- a/SerialChannel.h +++ b/SerialChannel.h @@ -2,6 +2,8 @@ #define _SerialChannel_h_ #define SC_APPEND_STR(str) append((byte*)str, sizeof(str)-1) +#define SC_APPEND_STR_INT(str, arg0) appendInt(str, sizeof(str)-1, arg0) + #define SC_APPEND_STR_TIME(str, time) append((byte*)str, sizeof(str)-1, time) class SerialChannel @@ -11,8 +13,9 @@ private: struct Message { - byte* data; unsigned long time; + long longArg0; + byte* data; short byteCount; byte id; }; @@ -40,8 +43,9 @@ public: void beginWrite(short byteCount, unsigned long time = (unsigned long)-1); void continueWrite(byte* data, short byteCount); - void append(byte* data, short byteCount, unsigned long time = (unsigned long)-1); + Message& append(byte* data, short byteCount, unsigned long time = (unsigned long)-1); void append(const char* text, unsigned long time = (unsigned long)-1); + void appendInt(const char* text, short textLength, int arg0, unsigned long time = (unsigned long)-1); static void swap(); static void flush(); diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs index 897717c..b0509e2 100644 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -33,13 +33,13 @@ namespace SerialMonitor Serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(OnDataReceived); Serial.Open(); + Serial.Write("C"); } private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { if (!Connected) { - Serial.Write("C"); Serial.ReadTo("CONNECTION"); Connected = true; } From b236a684ca4449b11daec9a8379c44537f291196 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Fri, 24 Apr 2015 11:29:59 +0200 Subject: [PATCH 13/32] implemented reading of bytes sent by the 1-wire master --- OneWireIO.ino | 108 +++++++++++++++++++++++- SerialChannel.cpp | 40 ++++++--- SerialChannel.h | 11 +-- SerialMonitor/SerialMonitor/App.xaml.cs | 2 +- 4 files changed, 139 insertions(+), 22 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 46f43ce..5540e80 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -12,12 +12,24 @@ #define PresenceWaitDuration 30 #define PresenceDuration 300 +#define BitZeroMinDuration 20 +#define BitZeroMaxDuration 75 + SerialChannel debug("debug"); Pin owPin(OWPin); Pin owOutTestPin(3); Pin led(LEDPin); +enum OwStatus +{ + OS_WaitReset, + OS_Presence, + OS_AfterPresence, + OS_WaitCommand, +}; +OwStatus status; + void owPullLow() { owPin.outputMode(); @@ -40,6 +52,10 @@ void owWrite(bool value) } unsigned long resetStart = (unsigned long)-1; +unsigned long lastReset = (unsigned long)-1; +unsigned long bitStart = (unsigned long)-1; +byte receivingByte = 0; +byte receivingBitPos = 0; void setup() { @@ -63,7 +79,7 @@ void setup() TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt sei(); // enable interrupts - Serial.begin(400000); + Serial.begin(9600); } //int count = 0; @@ -92,6 +108,17 @@ void setTimerEvent(short microSecondsDelay, void(*event)()) TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler } +void owError(const char* message) +{ + debug.append(message); + led.writeHigh(); +} + +void owResetError() +{ + led.writeLow(); +} + void onewireInterrupt(void) { bool state = owPin.read(); @@ -102,32 +129,107 @@ void onewireInterrupt(void) if (!state) resetStart = now; + // handle reset if (state) { unsigned long resetDuration = resetStart == (unsigned long)-1 ? (unsigned long)-1 : now - resetStart; resetStart = (unsigned long)-1; + lastReset = now; if (resetDuration >= ResetMinDuration && resetDuration <= ResetMaxDuration) { //debug.SC_APPEND_STR_TIME("reset", now); + owResetError(); + status = OS_Presence; setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); return; } } + + if (status == OS_AfterPresence) + { + status = OS_WaitCommand; + receivingByte = 0; + receivingBitPos = 0; + + if (state) + { + // this is the rising edge of end-of-presence ; don't try to interpret it as a bit + return; + } + } + + // read bytes + if (status == OS_WaitCommand) + { + if (!state) + { + // master just pulled low, this is a bit start + //debug.SC_APPEND_STR_TIME("bit start", now); + bitStart = now; + } + else + { + if (bitStart == (unsigned long)-1) + { + //owError("Invalid read sequence"); + //return; + + // we missed the falling edge, we emulate one here (this can happen if handling of rising edge interrupt takes too long) + bitStart = now; + } + + // master released the line, we interpret it as a bit 1 or 0 depending on timing + unsigned long bitLength = now - bitStart; + bitStart = (unsigned long)-1; + + if (bitLength < BitZeroMinDuration) + { + // received bit = 1 + //debug.SC_APPEND_STR_TIME("received bit 1", now); + receivingByte |= (1 << receivingBitPos); + ++receivingBitPos; + } + else if (bitLength < BitZeroMaxDuration) + { + // received bit = 0 + //debug.SC_APPEND_STR_TIME("received bit 0", now); + ++receivingBitPos; + } + else + { + // this is not a valid bit + owError("Invalid read timing"); + return; + } + + if (receivingBitPos == 8) + { + debug.SC_APPEND_STR_INT("received byte", (long)receivingByte); + receivingBitPos = 0; + receivingByte = 0; + } + } + } } void beginPresence() { - //debug.SC_APPEND_STR("beginPresence"); + unsigned long now = micros(); owPullLow(); owOutTestPin.writeLow(); setTimerEvent(PresenceDuration, &endPresence); + debug.SC_APPEND_STR_TIME("reset", lastReset); + debug.SC_APPEND_STR_TIME("beginPresence", now); } void endPresence() { - //debug.SC_APPEND_STR("endPresence"); + unsigned long now = micros(); owRelease(); + debug.SC_APPEND_STR_TIME("endPresence", now); + + status = OS_AfterPresence; } ISR(TIMER1_COMPA_vect) // timer1 interrupt diff --git a/SerialChannel.cpp b/SerialChannel.cpp index bcf7346..63537b6 100644 --- a/SerialChannel.cpp +++ b/SerialChannel.cpp @@ -6,10 +6,12 @@ SerialChannel* SerialChannel::first = 0; SerialChannel::Message SerialChannel::buffer1[SerialChannel::MaxPendingMessages]; SerialChannel::Message SerialChannel::buffer2[SerialChannel::MaxPendingMessages]; -SerialChannel::Message* SerialChannel::backBuffer; -byte SerialChannel::backBufferPos; +volatile SerialChannel::Message* SerialChannel::backBuffer; +volatile byte SerialChannel::backBufferPos; byte SerialChannel::frontBufferSize; +SerialChannel::Message dummyMessage; + SerialChannel::SerialChannel(const char* name_) : next(0) , id((byte)-1) @@ -66,16 +68,28 @@ SerialChannel::Message& SerialChannel::append(byte* data, short byteCount, unsig if (time == (unsigned long)-1) time = micros(); - Message& msg = backBuffer[backBufferPos++]; if (backBufferPos >= MaxPendingMessages) - backBufferPos = MaxPendingMessages - 1; - msg.id = id; - msg.data = data; - msg.byteCount = byteCount; - msg.time = time; - msg.longArg0 = 0; - - return msg; + { + Message& msg = ((Message*)backBuffer)[MaxPendingMessages-1]; + msg.id = id; + msg.data = (byte*)"OVERFLOW"; + msg.byteCount = 8; + msg.time = time; + msg.longArg0 = 0; + + return dummyMessage; + } + else + { + Message& msg = ((Message*)backBuffer)[backBufferPos++]; + msg.id = id; + msg.data = data; + msg.byteCount = byteCount; + msg.time = time; + msg.longArg0 = 0; + + return msg; + } } void SerialChannel::append(const char* text, unsigned long time) @@ -115,9 +129,9 @@ void SerialChannel::flush() Serial.write(msg->data, msg->byteCount); if (paramsSize > 0) Serial.write(params, paramsSize); - } - Serial.flush(); + Serial.flush(); + } } void SerialChannel::writeShort(short num) diff --git a/SerialChannel.h b/SerialChannel.h index 0231f24..53e1bd3 100644 --- a/SerialChannel.h +++ b/SerialChannel.h @@ -8,9 +8,7 @@ class SerialChannel { -private: - static const byte MaxPendingMessages = 16; - +public: struct Message { unsigned long time; @@ -20,6 +18,9 @@ private: byte id; }; +private: + static const byte MaxPendingMessages = 32; + static SerialChannel* first; SerialChannel* next; @@ -29,8 +30,8 @@ private: static Message buffer1[MaxPendingMessages]; static Message buffer2[MaxPendingMessages]; - static Message* backBuffer; - static byte backBufferPos; + static volatile Message* backBuffer; + static volatile byte backBufferPos; static byte frontBufferSize; public: diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs index b0509e2..3fa11b0 100644 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ b/SerialMonitor/SerialMonitor/App.xaml.cs @@ -28,7 +28,7 @@ namespace SerialMonitor Serial = new SerialPort(); Serial.PortName = "COM4"; - Serial.BaudRate = 400000; + Serial.BaudRate = 9600; Serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(OnDataReceived); From 68f4fce8783561a892af47b68cb89bf992b75940 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Fri, 24 Apr 2015 12:13:29 +0200 Subject: [PATCH 14/32] attempt to implement search ROM algorithm (doesn't work at this time) --- OneWireIO.ino | 177 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 144 insertions(+), 33 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 5540e80..4a54161 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -15,6 +15,11 @@ #define BitZeroMinDuration 20 #define BitZeroMaxDuration 75 +#define SendBitDuration 30 + +const byte InvalidBit = (byte)-1; +const byte IncompleteBit = (byte)-2; + SerialChannel debug("debug"); Pin owPin(OWPin); @@ -27,9 +32,16 @@ enum OwStatus OS_Presence, OS_AfterPresence, OS_WaitCommand, + OS_SearchRom, }; OwStatus status; +byte owROM[8] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; +byte searchROMCurrentByte = 0; +byte searchROMCurrentBit = 0; +bool searchROMSendingInverse = false; +bool searchROMReadingMasterResponseBit = false; + void owPullLow() { owPin.outputMode(); @@ -112,6 +124,7 @@ void owError(const char* message) { debug.append(message); led.writeHigh(); + status = OS_WaitReset; } void owResetError() @@ -151,6 +164,7 @@ void onewireInterrupt(void) status = OS_WaitCommand; receivingByte = 0; receivingBitPos = 0; + bitStart = (unsigned long)-1; if (state) { @@ -162,57 +176,154 @@ void onewireInterrupt(void) // read bytes if (status == OS_WaitCommand) { - if (!state) - { - // master just pulled low, this is a bit start - //debug.SC_APPEND_STR_TIME("bit start", now); - bitStart = now; - } - else + byte bit = interpretReceivedEdgeAsBit(state, now); + if (bit != IncompleteBit) { - if (bitStart == (unsigned long)-1) + if (bit == InvalidBit) + return; + + receivingByte |= (bit << receivingBitPos); + ++receivingBitPos; + + if (receivingBitPos == 8) { - //owError("Invalid read sequence"); - //return; + debug.SC_APPEND_STR_INT("received byte", (long)receivingByte); + + if (status == OS_WaitCommand && receivingByte == 0xF0) + { + status = OS_SearchRom; + searchROMReadingMasterResponseBit = false; + searchROMSendingInverse = false; + searchROMCurrentByte = 0; + searchROMCurrentBit = 0; + return; + } - // we missed the falling edge, we emulate one here (this can happen if handling of rising edge interrupt takes too long) - bitStart = now; + receivingBitPos = 0; + receivingByte = 0; } + } + } - // master released the line, we interpret it as a bit 1 or 0 depending on timing - unsigned long bitLength = now - bitStart; - bitStart = (unsigned long)-1; + if (status == OS_SearchRom) + { + byte currentByte = owROM[searchROMCurrentByte]; + bool currentBit = bitRead(currentByte, searchROMCurrentBit); - if (bitLength < BitZeroMinDuration) + if (searchROMReadingMasterResponseBit) + { + byte bit = interpretReceivedEdgeAsBit(state, now); + if (bit != IncompleteBit) { - // received bit = 1 - //debug.SC_APPEND_STR_TIME("received bit 1", now); - receivingByte |= (1 << receivingBitPos); - ++receivingBitPos; + searchROMReadingMasterResponseBit = false; + if (bit == InvalidBit) + return; + if ((bit == 1) != currentBit) + { + debug.SC_APPEND_STR_TIME("Master didn't send our bit, leaving ROM search", now); + status = OS_WaitReset; + } } - else if (bitLength < BitZeroMaxDuration) + } + else + { + if (!state) { - // received bit = 0 - //debug.SC_APPEND_STR_TIME("received bit 0", now); - ++receivingBitPos; + // master is pulling low, we must send our bit + bool bitToSend = searchROMSendingInverse ? !currentBit : currentBit; + sendBit(bitToSend); + if (bitToSend) + debug.SC_APPEND_STR_TIME("Sent ROM search bit : 1", now); + else + debug.SC_APPEND_STR_TIME("Sent ROM search bit : 0", now); + + if (searchROMSendingInverse) + { + searchROMSendingInverse = false; + searchROMReadingMasterResponseBit = true; + } + else + { + searchROMSendingInverse = true; + } + + if (searchROMCurrentBit == 8) + { + ++searchROMCurrentByte; + searchROMCurrentBit = 0; + debug.SC_APPEND_STR_TIME("sent another ROM byte", now); + } + + if (searchROMCurrentByte == 8) + { + searchROMCurrentByte = 0; + status = OS_WaitReset; + debug.SC_APPEND_STR_TIME("ROM sent entirely", now); + } } else { - // this is not a valid bit - owError("Invalid read timing"); - return; + debug.SC_APPEND_STR_TIME("Search ROM : seen rising edge", now); } + } + } +} - if (receivingBitPos == 8) - { - debug.SC_APPEND_STR_INT("received byte", (long)receivingByte); - receivingBitPos = 0; - receivingByte = 0; - } +byte interpretReceivedEdgeAsBit(bool wireState, unsigned long now) +{ + if (!wireState) + { + // master just pulled low, this is a bit start + //debug.SC_APPEND_STR_TIME("bit start", now); + bitStart = now; + return IncompleteBit; + } + else + { + if (bitStart == (unsigned long)-1) + { + //owError("Invalid read sequence"); + //return InvalidBit; + + // we missed the falling edge, we emulate one here (this can happen if handling of rising edge interrupt takes too long) + bitStart = now; + } + + // master released the line, we interpret it as a bit 1 or 0 depending on timing + unsigned long bitLength = now - bitStart; + bitStart = (unsigned long)-1; + + if (bitLength < BitZeroMinDuration) + { + // received bit = 1 + //debug.SC_APPEND_STR_TIME("received bit 1", now); + return 1; + } + else if (bitLength < BitZeroMaxDuration) + { + // received bit = 0 + //debug.SC_APPEND_STR_TIME("received bit 0", now); + return 0; + } + else + { + // this is not a valid bit + owError("Invalid read timing"); + return InvalidBit; } } } +void sendBit(bool bit) +{ + if (!bit) + { + owPullLow(); + delayMicroseconds(SendBitDuration); + owRelease(); + } +} + void beginPresence() { unsigned long now = micros(); From 74b3f2100e67f38dd9e314f2e90219677d162d5a Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Fri, 24 Apr 2015 20:17:29 +0200 Subject: [PATCH 15/32] search rom algorithm almost working (but code is in an awful state, and master doesn't recognize the ROM yet, maybe a CRC issue) --- OneWireIO.ino | 309 ++++++++++++++++++++++++-------------------------- 1 file changed, 149 insertions(+), 160 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 4a54161..ffe1143 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -12,10 +12,9 @@ #define PresenceWaitDuration 30 #define PresenceDuration 300 -#define BitZeroMinDuration 20 -#define BitZeroMaxDuration 75 +#define ReadBitSamplingTime 13 // the theorical time is about 30us, but given various overhead, this is the empirical delay I've found works best (on Arduino Uno) -#define SendBitDuration 30 +#define SendBitDuration 35 const byte InvalidBit = (byte)-1; const byte IncompleteBit = (byte)-2; @@ -30,7 +29,6 @@ enum OwStatus { OS_WaitReset, OS_Presence, - OS_AfterPresence, OS_WaitCommand, OS_SearchRom, }; @@ -55,15 +53,7 @@ void owRelease() owOutTestPin.writeHigh(); } -void owWrite(bool value) -{ - if (value) - owRelease(); - else - owPullLow(); -} - -unsigned long resetStart = (unsigned long)-1; +volatile unsigned long resetStart = (unsigned long)-1; unsigned long lastReset = (unsigned long)-1; unsigned long bitStart = (unsigned long)-1; byte receivingByte = 0; @@ -79,7 +69,7 @@ void setup() led.writeLow(); cli(); // disable interrupts - attachInterrupt(InterruptNumber,onewireInterrupt,CHANGE); + attachInterrupt(InterruptNumber,onewireInterrupt,FALLING); // set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A) // 4us between each tick @@ -99,11 +89,13 @@ void loop() { //if ((count++) % 1000 == 0) // led.write(!led.read()); - cli();//disable interrupts + cli();//disable interrupts SerialChannel::swap(); - sei();//enable interrupts - + sei();//enable interrupts + SerialChannel::flush(); + + owHandleReset(); } void(*timerEvent)() = 0; @@ -127,200 +119,195 @@ void owError(const char* message) status = OS_WaitReset; } -void owResetError() +void owClearError() { led.writeLow(); } -void onewireInterrupt(void) +void owHandleReset() { - bool state = owPin.read(); - unsigned long now = micros(); - - //led.write(state); - - if (!state) - resetStart = now; - - // handle reset - if (state) + unsigned long localResetStart = resetStart; + if (owPin.read()) { - unsigned long resetDuration = resetStart == (unsigned long)-1 ? (unsigned long)-1 : now - resetStart; resetStart = (unsigned long)-1; - lastReset = now; - - if (resetDuration >= ResetMinDuration && resetDuration <= ResetMaxDuration) - { - //debug.SC_APPEND_STR_TIME("reset", now); - owResetError(); - status = OS_Presence; - setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); - return; - } } - - if (status == OS_AfterPresence) + else if (localResetStart != (unsigned long)-1) { - status = OS_WaitCommand; - receivingByte = 0; - receivingBitPos = 0; - bitStart = (unsigned long)-1; - - if (state) + unsigned long resetDuration = micros() - localResetStart; + if (resetDuration >= ResetMinDuration) { - // this is the rising edge of end-of-presence ; don't try to interpret it as a bit - return; - } - } - - // read bytes - if (status == OS_WaitCommand) - { - byte bit = interpretReceivedEdgeAsBit(state, now); - if (bit != IncompleteBit) - { - if (bit == InvalidBit) - return; - - receivingByte |= (bit << receivingBitPos); - ++receivingBitPos; - - if (receivingBitPos == 8) + // wait for master to release the pin (or timeout if the pin is pulled low for too long) + unsigned long now = micros(); + while (!owPin.read()) { - debug.SC_APPEND_STR_INT("received byte", (long)receivingByte); - - if (status == OS_WaitCommand && receivingByte == 0xF0) + if (resetStart != localResetStart) + return; + now = micros(); + if (now - localResetStart > ResetMaxDuration) { - status = OS_SearchRom; - searchROMReadingMasterResponseBit = false; - searchROMSendingInverse = false; - searchROMCurrentByte = 0; - searchROMCurrentBit = 0; + owError("Reset too long"); return; } - - receivingBitPos = 0; - receivingByte = 0; } + + cli(); + owClearError(); + lastReset = now; + status = OS_Presence; + setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); + sei(); } } +} - if (status == OS_SearchRom) +void onewireInterrupt() +{ + //owOutTestPin.writeLow(); + onewireInterruptImpl(); + //owOutTestPin.writeHigh(); +} + +//bool debugState = false; +volatile unsigned long lastInterrupt = 0; +void onewireInterruptImpl(void) +{ + unsigned long now = micros(); + if (now < lastInterrupt + 20) + return; // don't react to our own actions + lastInterrupt = now; + + //debugState = !debugState; + //owOutTestPin.write(debugState); + + //led.write(state); + + resetStart = now; + + // read bytes + switch (status) { + case OS_WaitCommand: { - byte currentByte = owROM[searchROMCurrentByte]; - bool currentBit = bitRead(currentByte, searchROMCurrentBit); + bool bit = readBit(); - if (searchROMReadingMasterResponseBit) + receivingByte |= ((bit ? 1 : 0) << receivingBitPos); + ++receivingBitPos; + + if (receivingBitPos == 8) { - byte bit = interpretReceivedEdgeAsBit(state, now); - if (bit != IncompleteBit) + byte receivedByte = receivingByte; + receivingBitPos = 0; + receivingByte = 0; + //debug.SC_APPEND_STR_INT("received byte", (long)receivedByte); + + if (status == OS_WaitCommand && receivedByte == 0xF0) { + status = OS_SearchRom; searchROMReadingMasterResponseBit = false; - if (bit == InvalidBit) - return; - if ((bit == 1) != currentBit) - { - debug.SC_APPEND_STR_TIME("Master didn't send our bit, leaving ROM search", now); - status = OS_WaitReset; - } + searchROMSendingInverse = false; + searchROMCurrentByte = 0; + searchROMCurrentBit = 0; + attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); + return; } } - else - { - if (!state) - { - // master is pulling low, we must send our bit - bool bitToSend = searchROMSendingInverse ? !currentBit : currentBit; - sendBit(bitToSend); - if (bitToSend) - debug.SC_APPEND_STR_TIME("Sent ROM search bit : 1", now); - else - debug.SC_APPEND_STR_TIME("Sent ROM search bit : 0", now); - - if (searchROMSendingInverse) - { - searchROMSendingInverse = false; - searchROMReadingMasterResponseBit = true; - } - else - { - searchROMSendingInverse = true; - } + } break; - if (searchROMCurrentBit == 8) - { - ++searchROMCurrentByte; - searchROMCurrentBit = 0; - debug.SC_APPEND_STR_TIME("sent another ROM byte", now); - } - - if (searchROMCurrentByte == 8) - { - searchROMCurrentByte = 0; - status = OS_WaitReset; - debug.SC_APPEND_STR_TIME("ROM sent entirely", now); - } - } - else - { - debug.SC_APPEND_STR_TIME("Search ROM : seen rising edge", now); - } - } + case OS_SearchRom: + { + + } break; } } -byte interpretReceivedEdgeAsBit(bool wireState, unsigned long now) +bool ignoreNextFallingEdge = false; +void onewireInterruptSearchROM() { - if (!wireState) + /*unsigned long now = micros(); + if (now < lastInterrupt + 20) + return; // don't react to our own actions + lastInterrupt = now;*/ + if (ignoreNextFallingEdge) { - // master just pulled low, this is a bit start - //debug.SC_APPEND_STR_TIME("bit start", now); - bitStart = now; - return IncompleteBit; + ignoreNextFallingEdge = false; + return; } - else + + if (searchROMReadingMasterResponseBit) { - if (bitStart == (unsigned long)-1) - { - //owError("Invalid read sequence"); - //return InvalidBit; + bool bit = readBit(); + + byte currentByte = owROM[searchROMCurrentByte]; + bool currentBit = bitRead(currentByte, searchROMCurrentBit); - // we missed the falling edge, we emulate one here (this can happen if handling of rising edge interrupt takes too long) - bitStart = now; + if (bit != currentBit) + { + debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); + status = OS_WaitReset; + attachInterrupt(InterruptNumber, onewireInterrupt, FALLING); + return; } - // master released the line, we interpret it as a bit 1 or 0 depending on timing - unsigned long bitLength = now - bitStart; - bitStart = (unsigned long)-1; + searchROMReadingMasterResponseBit = false; + ++searchROMCurrentBit; + if (searchROMCurrentBit == 8) + { + ++searchROMCurrentByte; + searchROMCurrentBit = 0; + debug.SC_APPEND_STR("sent another ROM byte"); + } - if (bitLength < BitZeroMinDuration) + if (searchROMCurrentByte == 8) { - // received bit = 1 - //debug.SC_APPEND_STR_TIME("received bit 1", now); - return 1; + searchROMCurrentByte = 0; + status = OS_WaitReset; + debug.SC_APPEND_STR("ROM sent entirely"); + attachInterrupt(InterruptNumber, onewireInterrupt, FALLING); + return; } - else if (bitLength < BitZeroMaxDuration) + } + else + { + byte currentByte = owROM[searchROMCurrentByte]; + bool currentBit = bitRead(currentByte, searchROMCurrentBit); + //bool currentBit = 0; + + bool bitToSend = searchROMSendingInverse ? !currentBit : currentBit; + sendBit(bitToSend); + /*if (bitToSend) + debug.SC_APPEND_STR("sent ROM search bit : 1"); + else + debug.SC_APPEND_STR("sent ROM search bit : 0");*/ + + if (searchROMSendingInverse) { - // received bit = 0 - //debug.SC_APPEND_STR_TIME("received bit 0", now); - return 0; + searchROMSendingInverse = false; + searchROMReadingMasterResponseBit = true; } else { - // this is not a valid bit - owError("Invalid read timing"); - return InvalidBit; + searchROMSendingInverse = true; } } } +bool readBit() +{ + delayMicroseconds(ReadBitSamplingTime); + return owPin.read(); +} + void sendBit(bool bit) { - if (!bit) + if (bit) + { + delayMicroseconds(SendBitDuration); + } + else { owPullLow(); delayMicroseconds(SendBitDuration); owRelease(); + ignoreNextFallingEdge = true; } } @@ -328,7 +315,6 @@ void beginPresence() { unsigned long now = micros(); owPullLow(); - owOutTestPin.writeLow(); setTimerEvent(PresenceDuration, &endPresence); debug.SC_APPEND_STR_TIME("reset", lastReset); debug.SC_APPEND_STR_TIME("beginPresence", now); @@ -340,7 +326,10 @@ void endPresence() owRelease(); debug.SC_APPEND_STR_TIME("endPresence", now); - status = OS_AfterPresence; + status = OS_WaitCommand; + receivingByte = 0; + receivingBitPos = 0; + bitStart = (unsigned long)-1; } ISR(TIMER1_COMPA_vect) // timer1 interrupt From 6b4f76c5f4acf32ffaa022300f6ef2224b72a48c Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Fri, 24 Apr 2015 22:34:55 +0200 Subject: [PATCH 16/32] search rom works, but not completely reliable yet --- OneWireIO.ino | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index ffe1143..00acf93 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -61,6 +61,8 @@ byte receivingBitPos = 0; void setup() { + owROM[7] = crc8((char*)owROM, 7); + led.outputMode(); owPin.inputMode(); owOutTestPin.outputMode(); @@ -183,11 +185,14 @@ void onewireInterruptImpl(void) resetStart = now; - // read bytes switch (status) { case OS_WaitCommand: { bool bit = readBit(); + /*if (bit) + debug.SC_APPEND_STR("received bit 1"); + else + debug.SC_APPEND_STR("received bit 0");*/ receivingByte |= ((bit ? 1 : 0) << receivingBitPos); ++receivingBitPos; @@ -211,21 +216,12 @@ void onewireInterruptImpl(void) } } } break; - - case OS_SearchRom: - { - - } break; } } bool ignoreNextFallingEdge = false; void onewireInterruptSearchROM() { - /*unsigned long now = micros(); - if (now < lastInterrupt + 20) - return; // don't react to our own actions - lastInterrupt = now;*/ if (ignoreNextFallingEdge) { ignoreNextFallingEdge = false; @@ -340,3 +336,18 @@ ISR(TIMER1_COMPA_vect) // timer1 interrupt if (event != 0) event(); } + +uint8_t crc8(char addr[], uint8_t len) { + uint8_t crc = 0; + + while (len--) { + uint8_t inbyte = *addr++; + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) crc ^= 0x8C; + inbyte >>= 1; + } + } + return crc; +} From f53e2adae8c1af5d058a11f814eadb0f787f2b2d Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Fri, 24 Apr 2015 22:55:29 +0200 Subject: [PATCH 17/32] small optimization --- OneWireIO.ino | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 00acf93..a597e0d 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -58,6 +58,8 @@ unsigned long lastReset = (unsigned long)-1; unsigned long bitStart = (unsigned long)-1; byte receivingByte = 0; byte receivingBitPos = 0; +bool searchRomNextBit = false; +bool searchRomNextBitToSend = false; void setup() { @@ -211,6 +213,9 @@ void onewireInterruptImpl(void) searchROMSendingInverse = false; searchROMCurrentByte = 0; searchROMCurrentBit = 0; + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); return; } @@ -232,10 +237,7 @@ void onewireInterruptSearchROM() { bool bit = readBit(); - byte currentByte = owROM[searchROMCurrentByte]; - bool currentBit = bitRead(currentByte, searchROMCurrentBit); - - if (bit != currentBit) + if (bit != searchRomNextBit) { debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); status = OS_WaitReset; @@ -263,12 +265,7 @@ void onewireInterruptSearchROM() } else { - byte currentByte = owROM[searchROMCurrentByte]; - bool currentBit = bitRead(currentByte, searchROMCurrentBit); - //bool currentBit = 0; - - bool bitToSend = searchROMSendingInverse ? !currentBit : currentBit; - sendBit(bitToSend); + sendBit(searchRomNextBitToSend); /*if (bitToSend) debug.SC_APPEND_STR("sent ROM search bit : 1"); else @@ -284,6 +281,10 @@ void onewireInterruptSearchROM() searchROMSendingInverse = true; } } + + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; } bool readBit() From c0250f685b64e4325295a48296d880a6a0ba1766 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 25 Apr 2015 00:06:00 +0200 Subject: [PATCH 18/32] more reliable search rom (but also with more active waiting) --- OneWireIO.ino | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index a597e0d..c26a458 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -216,7 +216,9 @@ void onewireInterruptImpl(void) byte currentByte = owROM[searchROMCurrentByte]; searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); + //attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); + setTimerEvent(10, owSearchSendBit); + detachInterrupt(InterruptNumber); return; } } @@ -225,6 +227,57 @@ void onewireInterruptImpl(void) } bool ignoreNextFallingEdge = false; + +void owSearchSendBit() +{ + // wait for a falling edge (active wait is more reliable than interrupts to send the bit fast enough) + while (!owPin.read()); + while (owPin.read()); + + //sendBit(searchRomNextBitToSend); + if (searchRomNextBitToSend) + { + //delayMicroseconds(SendBitDuration); + ignoreNextFallingEdge = false; + } + else + { + owPullLow(); + //delayMicroseconds(SendBitDuration); + //owRelease(); + ignoreNextFallingEdge = true; + } + + unsigned long sendBitStart = micros(); + + if (searchROMSendingInverse) + { + searchROMSendingInverse = false; + searchROMReadingMasterResponseBit = true; + } + else + { + searchROMSendingInverse = true; + } + + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + + if (searchROMReadingMasterResponseBit) + { + ignoreNextFallingEdge = true; + attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); + } + else + { + setTimerEvent(10, owSearchSendBit); + } + + delayMicroseconds(SendBitDuration - (micros() - sendBitStart)); + owRelease(); +} + void onewireInterruptSearchROM() { if (ignoreNextFallingEdge) @@ -262,6 +315,14 @@ void onewireInterruptSearchROM() attachInterrupt(InterruptNumber, onewireInterrupt, FALLING); return; } + + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + + setTimerEvent(10, owSearchSendBit); + detachInterrupt(InterruptNumber); + return; } else { @@ -290,7 +351,10 @@ void onewireInterruptSearchROM() bool readBit() { delayMicroseconds(ReadBitSamplingTime); - return owPin.read(); + bool bit = owPin.read(); + //owOutTestPin.write(!owOutTestPin.read()); + //owOutTestPin.write(!owOutTestPin.read()); + return bit; } void sendBit(bool bit) @@ -298,6 +362,7 @@ void sendBit(bool bit) if (bit) { delayMicroseconds(SendBitDuration); + ignoreNextFallingEdge = false; } else { From cf3f309ade0ee2e68a6a8d038dccb57cbc0fb4ea Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 25 Apr 2015 00:19:47 +0200 Subject: [PATCH 19/32] added code to monitor time spent in interrupt handlers --- OneWireIO.ino | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index c26a458..400880b 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -44,12 +44,22 @@ void owPullLow() { owPin.outputMode(); owPin.writeLow(); - owOutTestPin.writeLow(); + //owOutTestPin.writeLow(); } void owRelease() { owPin.inputMode(); + //owOutTestPin.writeHigh(); +} + +void onEnterInterrupt() +{ + owOutTestPin.writeLow(); +} + +void onLeaveInterrupt() +{ owOutTestPin.writeHigh(); } @@ -166,9 +176,9 @@ void owHandleReset() void onewireInterrupt() { - //owOutTestPin.writeLow(); + onEnterInterrupt(); onewireInterruptImpl(); - //owOutTestPin.writeHigh(); + onLeaveInterrupt(); } //bool debugState = false; @@ -230,6 +240,8 @@ bool ignoreNextFallingEdge = false; void owSearchSendBit() { + onEnterInterrupt(); + // wait for a falling edge (active wait is more reliable than interrupts to send the bit fast enough) while (!owPin.read()); while (owPin.read()); @@ -276,13 +288,18 @@ void owSearchSendBit() delayMicroseconds(SendBitDuration - (micros() - sendBitStart)); owRelease(); + + onLeaveInterrupt(); } void onewireInterruptSearchROM() { + onEnterInterrupt(); + if (ignoreNextFallingEdge) { ignoreNextFallingEdge = false; + onLeaveInterrupt(); return; } @@ -295,6 +312,7 @@ void onewireInterruptSearchROM() debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); status = OS_WaitReset; attachInterrupt(InterruptNumber, onewireInterrupt, FALLING); + onLeaveInterrupt(); return; } @@ -304,7 +322,7 @@ void onewireInterruptSearchROM() { ++searchROMCurrentByte; searchROMCurrentBit = 0; - debug.SC_APPEND_STR("sent another ROM byte"); + //debug.SC_APPEND_STR("sent another ROM byte"); } if (searchROMCurrentByte == 8) @@ -313,6 +331,7 @@ void onewireInterruptSearchROM() status = OS_WaitReset; debug.SC_APPEND_STR("ROM sent entirely"); attachInterrupt(InterruptNumber, onewireInterrupt, FALLING); + onLeaveInterrupt(); return; } @@ -322,6 +341,7 @@ void onewireInterruptSearchROM() setTimerEvent(10, owSearchSendBit); detachInterrupt(InterruptNumber); + onLeaveInterrupt(); return; } else @@ -346,6 +366,8 @@ void onewireInterruptSearchROM() byte currentByte = owROM[searchROMCurrentByte]; searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + + onLeaveInterrupt(); } bool readBit() From 55d1bbf127ee16e5c6cbc9bb7f12488d3045879b Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 25 Apr 2015 12:19:31 +0200 Subject: [PATCH 20/32] more robust reset detection, now purely implemented in interrupts, that allows the match rom algorithm to work even if our rom is not the first one --- OneWireIO.ino | 141 ++++++++++++++++++++++++-------------------------- 1 file changed, 67 insertions(+), 74 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index 400880b..904de41 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -34,7 +34,7 @@ enum OwStatus }; OwStatus status; -byte owROM[8] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; +byte owROM[8] = { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; byte searchROMCurrentByte = 0; byte searchROMCurrentBit = 0; bool searchROMSendingInverse = false; @@ -44,23 +44,23 @@ void owPullLow() { owPin.outputMode(); owPin.writeLow(); - //owOutTestPin.writeLow(); + owOutTestPin.writeLow(); } void owRelease() { owPin.inputMode(); - //owOutTestPin.writeHigh(); + owOutTestPin.writeHigh(); } void onEnterInterrupt() { - owOutTestPin.writeLow(); + //owOutTestPin.writeLow(); } void onLeaveInterrupt() { - owOutTestPin.writeHigh(); + //owOutTestPin.writeHigh(); } volatile unsigned long resetStart = (unsigned long)-1; @@ -83,7 +83,7 @@ void setup() led.writeLow(); cli(); // disable interrupts - attachInterrupt(InterruptNumber,onewireInterrupt,FALLING); + attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); // set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A) // 4us between each tick @@ -98,18 +98,16 @@ void setup() Serial.begin(9600); } -//int count = 0; +int count = 0; void loop() { - //if ((count++) % 1000 == 0) - // led.write(!led.read()); + if ((count++) % 1000 == 0) + led.write(!led.read()); cli();//disable interrupts SerialChannel::swap(); sei();//enable interrupts SerialChannel::flush(); - - owHandleReset(); } void(*timerEvent)() = 0; @@ -138,56 +136,54 @@ void owClearError() led.writeLow(); } -void owHandleReset() +void owWaitResetInterrupt() { - unsigned long localResetStart = resetStart; - if (owPin.read()) - { - resetStart = (unsigned long)-1; - } - else if (localResetStart != (unsigned long)-1) + onEnterInterrupt(); + bool state = owPin.read(); + unsigned long now = micros(); + if (state) { - unsigned long resetDuration = micros() - localResetStart; + if (resetStart == (unsigned int)-1) + { + onLeaveInterrupt(); + return; + } + + unsigned long resetDuration = now - resetStart; + resetStart = (unsigned int)-1; if (resetDuration >= ResetMinDuration) { - // wait for master to release the pin (or timeout if the pin is pulled low for too long) - unsigned long now = micros(); - while (!owPin.read()) + if (resetDuration > ResetMaxDuration) { - if (resetStart != localResetStart) - return; - now = micros(); - if (now - localResetStart > ResetMaxDuration) - { - owError("Reset too long"); - return; - } + owError("Reset too long"); + onLeaveInterrupt(); + return; } - cli(); owClearError(); lastReset = now; status = OS_Presence; setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); - sei(); } } -} - -void onewireInterrupt() -{ - onEnterInterrupt(); - onewireInterruptImpl(); + else + { + resetStart = now; + } onLeaveInterrupt(); } //bool debugState = false; volatile unsigned long lastInterrupt = 0; -void onewireInterruptImpl(void) +void owReceiveCommandInterrupt(void) { + onEnterInterrupt(); unsigned long now = micros(); if (now < lastInterrupt + 20) + { + onLeaveInterrupt(); return; // don't react to our own actions + } lastInterrupt = now; //debugState = !debugState; @@ -195,45 +191,41 @@ void onewireInterruptImpl(void) //led.write(state); - resetStart = now; + bool bit = readBit(); + /*if (bit) + debug.SC_APPEND_STR("received bit 1"); + else + debug.SC_APPEND_STR("received bit 0");*/ - switch (status) { - case OS_WaitCommand: - { - bool bit = readBit(); - /*if (bit) - debug.SC_APPEND_STR("received bit 1"); - else - debug.SC_APPEND_STR("received bit 0");*/ + receivingByte |= ((bit ? 1 : 0) << receivingBitPos); + ++receivingBitPos; - receivingByte |= ((bit ? 1 : 0) << receivingBitPos); - ++receivingBitPos; + if (receivingBitPos == 8) + { + byte receivedByte = receivingByte; + receivingBitPos = 0; + receivingByte = 0; + //debug.SC_APPEND_STR_INT("received byte", (long)receivedByte); - if (receivingBitPos == 8) + if (status == OS_WaitCommand && receivedByte == 0xF0) { - byte receivedByte = receivingByte; - receivingBitPos = 0; - receivingByte = 0; - //debug.SC_APPEND_STR_INT("received byte", (long)receivedByte); - - if (status == OS_WaitCommand && receivedByte == 0xF0) - { - status = OS_SearchRom; - searchROMReadingMasterResponseBit = false; - searchROMSendingInverse = false; - searchROMCurrentByte = 0; - searchROMCurrentBit = 0; - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - //attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); - setTimerEvent(10, owSearchSendBit); - detachInterrupt(InterruptNumber); - return; - } + status = OS_SearchRom; + searchROMReadingMasterResponseBit = false; + searchROMSendingInverse = false; + searchROMCurrentByte = 0; + searchROMCurrentBit = 0; + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + //attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); + setTimerEvent(10, owSearchSendBit); + detachInterrupt(InterruptNumber); + onLeaveInterrupt(); + return; } - } break; } + + onLeaveInterrupt(); } bool ignoreNextFallingEdge = false; @@ -311,7 +303,7 @@ void onewireInterruptSearchROM() { debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); status = OS_WaitReset; - attachInterrupt(InterruptNumber, onewireInterrupt, FALLING); + attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); onLeaveInterrupt(); return; } @@ -330,7 +322,7 @@ void onewireInterruptSearchROM() searchROMCurrentByte = 0; status = OS_WaitReset; debug.SC_APPEND_STR("ROM sent entirely"); - attachInterrupt(InterruptNumber, onewireInterrupt, FALLING); + attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); onLeaveInterrupt(); return; } @@ -411,6 +403,7 @@ void endPresence() debug.SC_APPEND_STR_TIME("endPresence", now); status = OS_WaitCommand; + attachInterrupt(InterruptNumber, owReceiveCommandInterrupt, FALLING); receivingByte = 0; receivingBitPos = 0; bitStart = (unsigned long)-1; From b6f8497f64c60b9c275feecaaa6897cca9b5c578 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 25 Apr 2015 13:04:10 +0200 Subject: [PATCH 21/32] start of code refactoring (OneWireSlave class) --- OneWireIO-tmp.hpp | 434 ++++++++++++++++++++++++++++++++++++++++++++++ OneWireIO.ino | 417 ++------------------------------------------ OneWireSlave.cpp | 31 ++++ OneWireSlave.h | 28 +++ 4 files changed, 509 insertions(+), 401 deletions(-) create mode 100644 OneWireIO-tmp.hpp create mode 100644 OneWireSlave.cpp create mode 100644 OneWireSlave.h diff --git a/OneWireIO-tmp.hpp b/OneWireIO-tmp.hpp new file mode 100644 index 0000000..c187bde --- /dev/null +++ b/OneWireIO-tmp.hpp @@ -0,0 +1,434 @@ +#include "Arduino.h" +#include "LowLevel.h" +#include "SerialChannel.h" + +#define LEDPin 13 +#define OWPin 2 +#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 + +#define ResetMinDuration 480 +#define ResetMaxDuration 900 + +#define PresenceWaitDuration 30 +#define PresenceDuration 300 + +#define ReadBitSamplingTime 13 // the theorical time is about 30us, but given various overhead, this is the empirical delay I've found works best (on Arduino Uno) + +#define SendBitDuration 35 + +const byte InvalidBit = (byte)-1; +const byte IncompleteBit = (byte)-2; + +SerialChannel debug("debug"); + +Pin owPin(OWPin); +Pin owOutTestPin(3); +Pin led(LEDPin); + +enum OwStatus +{ + OS_WaitReset, + OS_Presence, + OS_WaitCommand, + OS_SearchRom, +}; +OwStatus status; + +byte owROM[8] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; +byte searchROMCurrentByte = 0; +byte searchROMCurrentBit = 0; +bool searchROMSendingInverse = false; +bool searchROMReadingMasterResponseBit = false; + +void owPullLow() +{ + owPin.outputMode(); + owPin.writeLow(); + owOutTestPin.writeLow(); +} + +void owRelease() +{ + owPin.inputMode(); + owOutTestPin.writeHigh(); +} + +void onEnterInterrupt() +{ + //owOutTestPin.writeLow(); +} + +void onLeaveInterrupt() +{ + //owOutTestPin.writeHigh(); +} + +volatile unsigned long resetStart = (unsigned long)-1; +unsigned long lastReset = (unsigned long)-1; +unsigned long bitStart = (unsigned long)-1; +byte receivingByte = 0; +byte receivingBitPos = 0; +bool searchRomNextBit = false; +bool searchRomNextBitToSend = false; + +void setup() +{ + owROM[7] = crc8((char*)owROM, 7); + + led.outputMode(); + owPin.inputMode(); + owOutTestPin.outputMode(); + owOutTestPin.writeHigh(); + + led.writeLow(); + + cli(); // disable interrupts + attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); + + // set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A) + // 4us between each tick + TCCR1A = 0; + TCCR1B = 0; + TCNT1 = 0; // initialize counter value to 0 + //TCCR1B |= (1 << WGM12); // turn on CTC mode + //TCCR1B |= (1 << CS11) | (1 << CS10); // Set 64 prescaler + TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt + sei(); // enable interrupts + + Serial.begin(9600); +} + +int count = 0; +void loop() +{ + if ((count++) % 1000 == 0) + led.write(!led.read()); + cli();//disable interrupts + SerialChannel::swap(); + sei();//enable interrupts + + SerialChannel::flush(); +} + +void(*timerEvent)() = 0; +void setTimerEvent(short microSecondsDelay, void(*event)()) +{ + microSecondsDelay -= 10; // this seems to be the typical time taken to initialize the timer on Arduino Uno + + short skipTicks = (microSecondsDelay - 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; + //debug.SC_APPEND_STR_INT("setTimerEvent", (long)skipTicks); + TCNT1 = 0; + OCR1A = skipTicks; + timerEvent = event; + TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler +} + +void owError(const char* message) +{ + debug.append(message); + led.writeHigh(); + status = OS_WaitReset; +} + +void owClearError() +{ + led.writeLow(); +} + +void owWaitResetInterrupt() +{ + onEnterInterrupt(); + bool state = owPin.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) + { + owError("Reset too long"); + onLeaveInterrupt(); + return; + } + + owClearError(); + lastReset = now; + status = OS_Presence; + setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); + } + } + else + { + resetStart = now; + } + onLeaveInterrupt(); +} + +//bool debugState = false; +volatile unsigned long lastInterrupt = 0; +void owReceiveCommandInterrupt(void) +{ + onEnterInterrupt(); + unsigned long now = micros(); + if (now < lastInterrupt + 20) + { + onLeaveInterrupt(); + return; // don't react to our own actions + } + lastInterrupt = now; + + //debugState = !debugState; + //owOutTestPin.write(debugState); + + //led.write(state); + + bool bit = readBit(); + /*if (bit) + debug.SC_APPEND_STR("received bit 1"); + else + debug.SC_APPEND_STR("received bit 0");*/ + + receivingByte |= ((bit ? 1 : 0) << receivingBitPos); + ++receivingBitPos; + + if (receivingBitPos == 8) + { + byte receivedByte = receivingByte; + receivingBitPos = 0; + receivingByte = 0; + //debug.SC_APPEND_STR_INT("received byte", (long)receivedByte); + + if (status == OS_WaitCommand && receivedByte == 0xF0) + { + status = OS_SearchRom; + searchROMReadingMasterResponseBit = false; + searchROMSendingInverse = false; + searchROMCurrentByte = 0; + searchROMCurrentBit = 0; + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + //attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); + setTimerEvent(10, owSearchSendBit); + detachInterrupt(InterruptNumber); + onLeaveInterrupt(); + return; + } + } + + onLeaveInterrupt(); +} + +bool ignoreNextFallingEdge = false; + +void owSearchSendBit() +{ + onEnterInterrupt(); + + // wait for a falling edge (active wait is more reliable than interrupts to send the bit fast enough) + while (!owPin.read()); + while (owPin.read()); + + //sendBit(searchRomNextBitToSend); + if (searchRomNextBitToSend) + { + //delayMicroseconds(SendBitDuration); + ignoreNextFallingEdge = false; + } + else + { + owPullLow(); + //delayMicroseconds(SendBitDuration); + //owRelease(); + ignoreNextFallingEdge = true; + } + + unsigned long sendBitStart = micros(); + + if (searchROMSendingInverse) + { + searchROMSendingInverse = false; + searchROMReadingMasterResponseBit = true; + } + else + { + searchROMSendingInverse = true; + } + + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + + if (searchROMReadingMasterResponseBit) + { + ignoreNextFallingEdge = true; + attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); + } + else + { + setTimerEvent(10, owSearchSendBit); + } + + delayMicroseconds(SendBitDuration - (micros() - sendBitStart)); + owRelease(); + + onLeaveInterrupt(); +} + +void onewireInterruptSearchROM() +{ + onEnterInterrupt(); + + if (ignoreNextFallingEdge) + { + ignoreNextFallingEdge = false; + onLeaveInterrupt(); + return; + } + + if (searchROMReadingMasterResponseBit) + { + bool bit = readBit(); + + if (bit != searchRomNextBit) + { + debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); + status = OS_WaitReset; + attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); + onLeaveInterrupt(); + return; + } + + searchROMReadingMasterResponseBit = false; + ++searchROMCurrentBit; + if (searchROMCurrentBit == 8) + { + ++searchROMCurrentByte; + searchROMCurrentBit = 0; + //debug.SC_APPEND_STR("sent another ROM byte"); + } + + if (searchROMCurrentByte == 8) + { + searchROMCurrentByte = 0; + status = OS_WaitReset; + debug.SC_APPEND_STR("ROM sent entirely"); + attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); + onLeaveInterrupt(); + return; + } + + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + + setTimerEvent(10, owSearchSendBit); + detachInterrupt(InterruptNumber); + onLeaveInterrupt(); + return; + } + else + { + sendBit(searchRomNextBitToSend); + /*if (bitToSend) + debug.SC_APPEND_STR("sent ROM search bit : 1"); + else + debug.SC_APPEND_STR("sent ROM search bit : 0");*/ + + if (searchROMSendingInverse) + { + searchROMSendingInverse = false; + searchROMReadingMasterResponseBit = true; + } + else + { + searchROMSendingInverse = true; + } + } + + byte currentByte = owROM[searchROMCurrentByte]; + searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); + searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; + + onLeaveInterrupt(); +} + +bool readBit() +{ + delayMicroseconds(ReadBitSamplingTime); + bool bit = owPin.read(); + //owOutTestPin.write(!owOutTestPin.read()); + //owOutTestPin.write(!owOutTestPin.read()); + return bit; +} + +void sendBit(bool bit) +{ + if (bit) + { + delayMicroseconds(SendBitDuration); + ignoreNextFallingEdge = false; + } + else + { + owPullLow(); + delayMicroseconds(SendBitDuration); + owRelease(); + ignoreNextFallingEdge = true; + } +} + +void beginPresence() +{ + unsigned long now = micros(); + owPullLow(); + setTimerEvent(PresenceDuration, &endPresence); + debug.SC_APPEND_STR_TIME("reset", lastReset); + debug.SC_APPEND_STR_TIME("beginPresence", now); +} + +void endPresence() +{ + unsigned long now = micros(); + owRelease(); + debug.SC_APPEND_STR_TIME("endPresence", now); + + status = OS_WaitCommand; + attachInterrupt(InterruptNumber, owReceiveCommandInterrupt, FALLING); + receivingByte = 0; + receivingBitPos = 0; + bitStart = (unsigned long)-1; +} + +ISR(TIMER1_COMPA_vect) // timer1 interrupt +{ + TCCR1B = 0; // disable clock + void(*event)() = timerEvent; + timerEvent = 0; + if (event != 0) + event(); +} + +uint8_t crc8(char addr[], uint8_t len) { + uint8_t crc = 0; + + while (len--) { + uint8_t inbyte = *addr++; + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) crc ^= 0x8C; + inbyte >>= 1; + } + } + return crc; +} diff --git a/OneWireIO.ino b/OneWireIO.ino index 904de41..b6e1ced 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -1,434 +1,49 @@ #include "Arduino.h" #include "LowLevel.h" #include "SerialChannel.h" +#include "OneWireSlave.h" #define LEDPin 13 #define OWPin 2 -#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 - -#define ResetMinDuration 480 -#define ResetMaxDuration 900 - -#define PresenceWaitDuration 30 -#define PresenceDuration 300 - -#define ReadBitSamplingTime 13 // the theorical time is about 30us, but given various overhead, this is the empirical delay I've found works best (on Arduino Uno) - -#define SendBitDuration 35 - -const byte InvalidBit = (byte)-1; -const byte IncompleteBit = (byte)-2; SerialChannel debug("debug"); -Pin owPin(OWPin); -Pin owOutTestPin(3); Pin led(LEDPin); -enum OwStatus -{ - OS_WaitReset, - OS_Presence, - OS_WaitCommand, - OS_SearchRom, -}; -OwStatus status; - -byte owROM[8] = { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; -byte searchROMCurrentByte = 0; -byte searchROMCurrentBit = 0; -bool searchROMSendingInverse = false; -bool searchROMReadingMasterResponseBit = false; - -void owPullLow() -{ - owPin.outputMode(); - owPin.writeLow(); - owOutTestPin.writeLow(); -} - -void owRelease() -{ - owPin.inputMode(); - owOutTestPin.writeHigh(); -} - -void onEnterInterrupt() -{ - //owOutTestPin.writeLow(); -} - -void onLeaveInterrupt() -{ - //owOutTestPin.writeHigh(); -} - -volatile unsigned long resetStart = (unsigned long)-1; -unsigned long lastReset = (unsigned long)-1; -unsigned long bitStart = (unsigned long)-1; -byte receivingByte = 0; -byte receivingBitPos = 0; -bool searchRomNextBit = false; -bool searchRomNextBitToSend = false; +byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; +OneWireSlave oneWire(owROM, OWPin); void setup() { - owROM[7] = crc8((char*)owROM, 7); - led.outputMode(); - owPin.inputMode(); - owOutTestPin.outputMode(); - owOutTestPin.writeHigh(); - + led.writeLow(); - cli(); // disable interrupts - attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); - - // set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A) - // 4us between each tick - TCCR1A = 0; - TCCR1B = 0; - TCNT1 = 0; // initialize counter value to 0 - //TCCR1B |= (1 << WGM12); // turn on CTC mode - //TCCR1B |= (1 << CS11) | (1 << CS10); // Set 64 prescaler - TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt - sei(); // enable interrupts + oneWire.enable(); Serial.begin(9600); } -int count = 0; +//int count = 0; void loop() { - if ((count++) % 1000 == 0) + /*if (count++ == 10000) + { led.write(!led.read()); + count = 0; + }*/ + cli();//disable interrupts SerialChannel::swap(); sei();//enable interrupts SerialChannel::flush(); -} - -void(*timerEvent)() = 0; -void setTimerEvent(short microSecondsDelay, void(*event)()) -{ - microSecondsDelay -= 10; // this seems to be the typical time taken to initialize the timer on Arduino Uno - - short skipTicks = (microSecondsDelay - 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; - //debug.SC_APPEND_STR_INT("setTimerEvent", (long)skipTicks); - TCNT1 = 0; - OCR1A = skipTicks; - timerEvent = event; - TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler -} - -void owError(const char* message) -{ - debug.append(message); - led.writeHigh(); - status = OS_WaitReset; -} - -void owClearError() -{ - led.writeLow(); -} - -void owWaitResetInterrupt() -{ - onEnterInterrupt(); - bool state = owPin.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) - { - owError("Reset too long"); - onLeaveInterrupt(); - return; - } - - owClearError(); - lastReset = now; - status = OS_Presence; - setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); - } - } - else - { - resetStart = now; - } - onLeaveInterrupt(); -} - -//bool debugState = false; -volatile unsigned long lastInterrupt = 0; -void owReceiveCommandInterrupt(void) -{ - onEnterInterrupt(); - unsigned long now = micros(); - if (now < lastInterrupt + 20) - { - onLeaveInterrupt(); - return; // don't react to our own actions - } - lastInterrupt = now; - - //debugState = !debugState; - //owOutTestPin.write(debugState); - - //led.write(state); - - bool bit = readBit(); - /*if (bit) - debug.SC_APPEND_STR("received bit 1"); - else - debug.SC_APPEND_STR("received bit 0");*/ - - receivingByte |= ((bit ? 1 : 0) << receivingBitPos); - ++receivingBitPos; - - if (receivingBitPos == 8) - { - byte receivedByte = receivingByte; - receivingBitPos = 0; - receivingByte = 0; - //debug.SC_APPEND_STR_INT("received byte", (long)receivedByte); - - if (status == OS_WaitCommand && receivedByte == 0xF0) - { - status = OS_SearchRom; - searchROMReadingMasterResponseBit = false; - searchROMSendingInverse = false; - searchROMCurrentByte = 0; - searchROMCurrentBit = 0; - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - //attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); - setTimerEvent(10, owSearchSendBit); - detachInterrupt(InterruptNumber); - onLeaveInterrupt(); - return; - } - } - - onLeaveInterrupt(); -} - -bool ignoreNextFallingEdge = false; -void owSearchSendBit() -{ - onEnterInterrupt(); - - // wait for a falling edge (active wait is more reliable than interrupts to send the bit fast enough) - while (!owPin.read()); - while (owPin.read()); - - //sendBit(searchRomNextBitToSend); - if (searchRomNextBitToSend) - { - //delayMicroseconds(SendBitDuration); - ignoreNextFallingEdge = false; - } - else - { - owPullLow(); - //delayMicroseconds(SendBitDuration); - //owRelease(); - ignoreNextFallingEdge = true; - } - - unsigned long sendBitStart = micros(); - - if (searchROMSendingInverse) - { - searchROMSendingInverse = false; - searchROMReadingMasterResponseBit = true; - } - else - { - searchROMSendingInverse = true; - } - - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - - if (searchROMReadingMasterResponseBit) - { - ignoreNextFallingEdge = true; - attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); - } - else - { - setTimerEvent(10, owSearchSendBit); - } - - delayMicroseconds(SendBitDuration - (micros() - sendBitStart)); - owRelease(); - - onLeaveInterrupt(); -} - -void onewireInterruptSearchROM() -{ - onEnterInterrupt(); - - if (ignoreNextFallingEdge) - { - ignoreNextFallingEdge = false; - onLeaveInterrupt(); - return; - } - - if (searchROMReadingMasterResponseBit) - { - bool bit = readBit(); - - if (bit != searchRomNextBit) - { - debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); - status = OS_WaitReset; - attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); - onLeaveInterrupt(); - return; - } - - searchROMReadingMasterResponseBit = false; - ++searchROMCurrentBit; - if (searchROMCurrentBit == 8) - { - ++searchROMCurrentByte; - searchROMCurrentBit = 0; - //debug.SC_APPEND_STR("sent another ROM byte"); - } - - if (searchROMCurrentByte == 8) - { - searchROMCurrentByte = 0; - status = OS_WaitReset; - debug.SC_APPEND_STR("ROM sent entirely"); - attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); - onLeaveInterrupt(); - return; - } - - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - - setTimerEvent(10, owSearchSendBit); - detachInterrupt(InterruptNumber); - onLeaveInterrupt(); - return; - } - else - { - sendBit(searchRomNextBitToSend); - /*if (bitToSend) - debug.SC_APPEND_STR("sent ROM search bit : 1"); - else - debug.SC_APPEND_STR("sent ROM search bit : 0");*/ - - if (searchROMSendingInverse) - { - searchROMSendingInverse = false; - searchROMReadingMasterResponseBit = true; - } - else - { - searchROMSendingInverse = true; - } - } - - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - - onLeaveInterrupt(); -} - -bool readBit() -{ - delayMicroseconds(ReadBitSamplingTime); - bool bit = owPin.read(); - //owOutTestPin.write(!owOutTestPin.read()); - //owOutTestPin.write(!owOutTestPin.read()); - return bit; -} - -void sendBit(bool bit) -{ - if (bit) + byte b; + if (oneWire.read(b)) { - delayMicroseconds(SendBitDuration); - ignoreNextFallingEdge = false; - } - else - { - owPullLow(); - delayMicroseconds(SendBitDuration); - owRelease(); - ignoreNextFallingEdge = true; - } -} - -void beginPresence() -{ - unsigned long now = micros(); - owPullLow(); - setTimerEvent(PresenceDuration, &endPresence); - debug.SC_APPEND_STR_TIME("reset", lastReset); - debug.SC_APPEND_STR_TIME("beginPresence", now); -} - -void endPresence() -{ - unsigned long now = micros(); - owRelease(); - debug.SC_APPEND_STR_TIME("endPresence", now); - - status = OS_WaitCommand; - attachInterrupt(InterruptNumber, owReceiveCommandInterrupt, FALLING); - receivingByte = 0; - receivingBitPos = 0; - bitStart = (unsigned long)-1; -} - -ISR(TIMER1_COMPA_vect) // timer1 interrupt -{ - TCCR1B = 0; // disable clock - void(*event)() = timerEvent; - timerEvent = 0; - if (event != 0) - event(); -} - -uint8_t crc8(char addr[], uint8_t len) { - uint8_t crc = 0; - - while (len--) { - uint8_t inbyte = *addr++; - for (uint8_t i = 8; i; i--) { - uint8_t mix = (crc ^ inbyte) & 0x01; - crc >>= 1; - if (mix) crc ^= 0x8C; - inbyte >>= 1; - } + char msg[32]; + sprintf(msg, "Received byte : %d", (int)b); + debug.write(msg); } - return crc; } diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp new file mode 100644 index 0000000..4a98e55 --- /dev/null +++ b/OneWireSlave.cpp @@ -0,0 +1,31 @@ +#include "OneWireSlave.h" + +OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) +{ + +} + +void OneWireSlave::enable() +{ + +} + +void OneWireSlave::disable() +{ + +} + +bool OneWireSlave::read(byte& b) +{ + return false; +} + +void OneWireSlave::setReceiveCallback(void(*callback)()) +{ + +} + +void OneWireSlave::write(byte* bytes, short numBytes, void(*complete)(bool error)) +{ + +} diff --git a/OneWireSlave.h b/OneWireSlave.h new file mode 100644 index 0000000..3483cea --- /dev/null +++ b/OneWireSlave.h @@ -0,0 +1,28 @@ +#ifndef _OneWireSlave_h_ +#define _OneWireSlave_h_ + +#include "Arduino.h" + +class OneWireSlave +{ +public: + ///! Constructs a 1-wire slave that will be identified by the specified ROM (7 bytes, starting from the family code, CRC will be computed internally). Call enable to actually start listening for the 1-wire master. + OneWireSlave(byte* rom, byte pinNumber); + + ///! Starts listening for the 1-wire master. Reset, Presence and SearchRom are handled automatically. The library will use interrupts on the pin specified in the constructor, 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 enable(); + + ///! Stops all 1-wire activities, which frees hardware resources for other purposes. + void disable(); + + ///! Pops one byte from the receive buffer, or returns false if no byte has been received. + bool read(byte& b); + + ///! Sets (or replaces) a function to be called when at least one byte has been received. Callbacks are executed from interrupts and should be as short as possible. + void setReceiveCallback(void(*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)); +}; + +#endif From 0f941a85fb1e270a68473f6ebaebce4074a1a821 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 25 Apr 2015 13:04:32 +0200 Subject: [PATCH 22/32] missing files --- OneWireIO.vcxproj | 2 ++ OneWireIO.vcxproj.filters | 2 ++ 2 files changed, 4 insertions(+) diff --git a/OneWireIO.vcxproj b/OneWireIO.vcxproj index 5125aed..3194aa6 100644 --- a/OneWireIO.vcxproj +++ b/OneWireIO.vcxproj @@ -71,10 +71,12 @@ + + diff --git a/OneWireIO.vcxproj.filters b/OneWireIO.vcxproj.filters index ba1919b..5960a2f 100644 --- a/OneWireIO.vcxproj.filters +++ b/OneWireIO.vcxproj.filters @@ -2,10 +2,12 @@ + + From 22e5d690a034c63f11747dd8f3063d116c48576e Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 25 Apr 2015 21:40:38 +0200 Subject: [PATCH 23/32] refactoring (wip) --- LowLevel.h | 31 ++++-- OneWireIO.ino | 8 +- OneWireIO.sln | 3 + OneWireIO.vcxproj | 37 ++++++- OneWireIO.vcxproj.filters | 2 +- OneWireSlave.cpp | 196 +++++++++++++++++++++++++++++++++++++- OneWireSlave.h | 35 +++++++ 7 files changed, 292 insertions(+), 20 deletions(-) diff --git a/LowLevel.h b/LowLevel.h index 41ad123..4f86264 100644 --- a/LowLevel.h +++ b/LowLevel.h @@ -71,23 +71,34 @@ class Pin { private: - IO_REG_TYPE mask; - volatile IO_REG_TYPE *reg; + IO_REG_TYPE mask_; + volatile IO_REG_TYPE *reg_; + byte interruptNumber_; public: - inline Pin(uint8_t pin) + Pin(uint8_t pin) { - mask = PIN_TO_BITMASK(pin); - reg = PIN_TO_BASEREG(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 void inputMode() { DIRECT_MODE_INPUT(reg_, mask_); } + inline void outputMode() { DIRECT_MODE_OUTPUT(reg_, mask_); } - inline bool read() { return DIRECT_READ(reg, mask); } - inline void writeLow() { DIRECT_WRITE_LOW(reg, mask); } - inline void writeHigh() { DIRECT_WRITE_HIGH(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) { ::attachInterrupt(interruptNumber_, handler, mode); } + inline void detachInterrupt() { ::detachInterrupt(interruptNumber_); } }; #endif diff --git a/OneWireIO.ino b/OneWireIO.ino index b6e1ced..af35fbb 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -16,7 +16,6 @@ OneWireSlave oneWire(owROM, OWPin); void setup() { led.outputMode(); - led.writeLow(); oneWire.enable(); @@ -24,14 +23,15 @@ void setup() Serial.begin(9600); } -//int count = 0; +int count = 0; void loop() { - /*if (count++ == 10000) + delay(1); + if (count++ == 1000) { led.write(!led.read()); count = 0; - }*/ + } cli();//disable interrupts SerialChannel::swap(); diff --git a/OneWireIO.sln b/OneWireIO.sln index 873e73d..1efede9 100644 --- a/OneWireIO.sln +++ b/OneWireIO.sln @@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OneWireIO", "OneWireIO.vcxproj", "{3B500971-1570-460F-81C3-22AC3B7764B9}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialMonitor", "SerialMonitor\SerialMonitor\SerialMonitor.csproj", "{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}" + ProjectSection(ProjectDependencies) = postProject + {3B500971-1570-460F-81C3-22AC3B7764B9} = {3B500971-1570-460F-81C3-22AC3B7764B9} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/OneWireIO.vcxproj b/OneWireIO.vcxproj index 3194aa6..308080d 100644 --- a/OneWireIO.vcxproj +++ b/OneWireIO.vcxproj @@ -50,6 +50,23 @@ true + + if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf ( +echo Elf generated +) else ( +echo no output +exit /B 1 +) + + + + if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf ( +echo Elf generated +) else ( +echo no output +exit /B 1 +) + @@ -66,13 +83,25 @@ - + Document - + false + 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) + + always_build_$(ProjectConfiguration).dummy + + + Building and uploading sketch... + - - + + true + + + true + diff --git a/OneWireIO.vcxproj.filters b/OneWireIO.vcxproj.filters index 5960a2f..22a782b 100644 --- a/OneWireIO.vcxproj.filters +++ b/OneWireIO.vcxproj.filters @@ -10,6 +10,6 @@ - + \ No newline at end of file diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index 4a98e55..c8eb5a8 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -1,18 +1,77 @@ #include "OneWireSlave.h" -OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) +#define DEBUG_LOG + +#ifdef DEBUG_LOG +#include "SerialChannel.h" +extern SerialChannel debug; +Pin dbgOutput(3); +#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 = 30; + + const unsigned long SendBitDuration = 35; + + void(*timerEvent)() = 0; +} + +OneWireSlave* OneWireSlave::inst_ = 0; + +ISR(TIMER1_COMPA_vect) // timer1 interrupt +{ + TCCR1B = 0; // disable clock + void(*event)() = timerEvent; + timerEvent = 0; + event(); +} + +OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) + : pin_(pinNumber) + , resetStart_((unsigned long)-1) + , lastReset_(0) +{ + inst_ = this; // we can have only one instance in the current implementation + memcpy(rom_, rom, 7); + rom_[7] = crc8_(rom_, 7); } void OneWireSlave::enable() { + #ifdef DEBUG_LOG + debug.append("Enabling 1-wire library"); + #endif + + cli(); // disable interrupts + pin_.inputMode(); + // 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 + beginWaitReset_(); + sei(); // enable interrupts } void OneWireSlave::disable() { + #ifdef DEBUG_LOG + debug.append("Disabling 1-wire library"); + #endif + cli(); + disableTimer_(); + pin_.detachInterrupt(); + releaseBus_(); + sei(); } bool OneWireSlave::read(byte& b) @@ -29,3 +88,138 @@ void OneWireSlave::write(byte* bytes, short numBytes, void(*complete)(bool error { } + +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_() +{ + dbgOutput.outputMode(); + dbgOutput.writeLow(); +} + +void OneWireSlave::onLeaveInterrupt_() +{ + dbgOutput.writeHigh(); +} + +void OneWireSlave::error_(const char* message) +{ +#ifdef DEBUG_LOG + debug.append(message); +#endif + beginWaitReset_(); +} + +void OneWireSlave::pullLow_() +{ + pin_.outputMode(); + pin_.writeLow(); +} + +void OneWireSlave::releaseBus_() +{ + pin_.inputMode(); +} + +void OneWireSlave::beginWaitReset_() +{ + disableTimer_(); + pin_.attachInterrupt(&OneWireSlave::waitResetHandler_, 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; + setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresenceHandler_); + } + } + else + { + resetStart_ = now; + } + onLeaveInterrupt_(); +} + +void OneWireSlave::beginPresence_() +{ + unsigned long now = micros(); + pullLow_(); + setTimerEvent_(PresenceDuration, &OneWireSlave::endPresenceHandler_); + #ifdef DEBUG_LOG + debug.SC_APPEND_STR_TIME("reset", lastReset_); + debug.SC_APPEND_STR_TIME("beginPresence", now); + #endif +} + +void OneWireSlave::endPresence_() +{ + unsigned long now = micros(); + releaseBus_(); + #ifdef DEBUG_LOG + debug.SC_APPEND_STR_TIME("endPresence", now); + #endif + + beginWaitCommand_(); +} + +void OneWireSlave::beginWaitCommand_() +{ + /*pin_.attachInterrupt(&OneWireSlave::waitCommand_, FALLING); + receivingByte = 0; + receivingBitPos = 0; + bitStart = (unsigned long)-1;*/ +} diff --git a/OneWireSlave.h b/OneWireSlave.h index 3483cea..ccb46e2 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -2,6 +2,7 @@ #define _OneWireSlave_h_ #include "Arduino.h" +#include "LowLevel.h" class OneWireSlave { @@ -23,6 +24,40 @@ public: ///! 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)); + +private: + byte crc8_(byte* data, short numBytes); + + void setTimerEvent_(short delayMicroSeconds, void(*handler)()); + void disableTimer_(); + + void onEnterInterrupt_(); + void onLeaveInterrupt_(); + + void error_(const char* message); + + void pullLow_(); + void releaseBus_(); + + void beginWaitReset_(); + void beginWaitCommand_(); + + // interrupt handlers + inline static void waitResetHandler_() { inst_->waitReset_(); } + void waitReset_(); + inline static void beginPresenceHandler_() { inst_->beginPresence_(); } + void beginPresence_(); + inline static void endPresenceHandler_() { inst_->endPresence_(); } + void endPresence_(); + +private: + static OneWireSlave* inst_; + byte rom_[8]; + Pin pin_; + byte tccr1bEnable_; + + unsigned long resetStart_; + unsigned long lastReset_; }; #endif From dedc44d9d7ee989961cc152d7a48cd8533b3edef Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 26 Apr 2015 01:08:37 +0200 Subject: [PATCH 24/32] refactoring wip : read bytes --- OneWireSlave.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++---- OneWireSlave.h | 12 +++++++ 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index c8eb5a8..6e406bc 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -16,10 +16,12 @@ namespace const unsigned long PresenceWaitDuration = 30; const unsigned long PresenceDuration = 300; - //const unsigned long ReadBitSamplingTime = 30; + const unsigned long ReadBitSamplingTime = 30; const unsigned long SendBitDuration = 35; + const byte ReceiveCommand = (byte)-1; + void(*timerEvent)() = 0; } @@ -37,6 +39,7 @@ OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) : pin_(pinNumber) , resetStart_((unsigned long)-1) , lastReset_(0) + , ignoreNextEdge_(false) { inst_ = this; // we can have only one instance in the current implementation memcpy(rom_, rom, 7); @@ -47,6 +50,8 @@ void OneWireSlave::enable() { #ifdef DEBUG_LOG debug.append("Enabling 1-wire library"); + dbgOutput.outputMode(); + dbgOutput.writeHigh(); #endif @@ -124,7 +129,6 @@ void OneWireSlave::disableTimer_() void OneWireSlave::onEnterInterrupt_() { - dbgOutput.outputMode(); dbgOutput.writeLow(); } @@ -145,11 +149,17 @@ void OneWireSlave::pullLow_() { pin_.outputMode(); pin_.writeLow(); +#ifdef DEBUG_LOG + //dbgOutput.writeLow(); +#endif } void OneWireSlave::releaseBus_() { pin_.inputMode(); +#ifdef DEBUG_LOG + //dbgOutput.writeHigh(); +#endif } void OneWireSlave::beginWaitReset_() @@ -184,6 +194,7 @@ void OneWireSlave::waitReset_() } lastReset_ = now; + pin_.detachInterrupt(); setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresenceHandler_); } } @@ -218,8 +229,69 @@ void OneWireSlave::endPresence_() void OneWireSlave::beginWaitCommand_() { - /*pin_.attachInterrupt(&OneWireSlave::waitCommand_, FALLING); - receivingByte = 0; - receivingBitPos = 0; - bitStart = (unsigned long)-1;*/ + receiveTarget_ = ReceiveCommand; + beginReceive_(); +} + +void OneWireSlave::beginReceive_() +{ + ignoreNextEdge_ = true; + pin_.attachInterrupt(&OneWireSlave::receiveHandler_, FALLING); + receivingByte_ = 0; + receivingBitPos_ = 0; } + +void OneWireSlave::receive_() +{ + onEnterInterrupt_(); + + if (!ignoreNextEdge_) + setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::receiveBitHandler_); + + ignoreNextEdge_ = false; + + onLeaveInterrupt_(); +} + +void OneWireSlave::receiveBit_() +{ + onEnterInterrupt_(); + + bool bit = pin_.read(); + //dbgOutput.writeLow(); + //dbgOutput.writeHigh(); + + receivingByte_ |= ((bit ? 1 : 0) << receivingBitPos_); + ++receivingBitPos_; + + if (receivingBitPos_ == 8) + { + #ifdef DEBUG_LOG + debug.SC_APPEND_STR_INT("received byte", (long)receivingByte_); + #endif + if (receiveTarget_ == ReceiveCommand) + { + if (receivingByte_ == 0xF0) + { + beginSearchRom_(); + } + else + { + // TODO: send command to client code + beginWaitReset_(); + } + } + else + { + // TODO: add byte in receive buffer + beginWaitReset_(); + } + } + + onLeaveInterrupt_(); +} + +void OneWireSlave::beginSearchRom_() +{ + pin_.detachInterrupt(); +} \ No newline at end of file diff --git a/OneWireSlave.h b/OneWireSlave.h index ccb46e2..390693f 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -41,6 +41,8 @@ private: void beginWaitReset_(); void beginWaitCommand_(); + void beginReceive_(); + void beginSearchRom_(); // interrupt handlers inline static void waitResetHandler_() { inst_->waitReset_(); } @@ -49,6 +51,10 @@ private: void beginPresence_(); inline static void endPresenceHandler_() { inst_->endPresence_(); } void endPresence_(); + inline static void receiveHandler_() { inst_->receive_(); } + void receive_(); + inline static void receiveBitHandler_() { inst_->receiveBit_(); } + void receiveBit_(); private: static OneWireSlave* inst_; @@ -58,6 +64,12 @@ private: unsigned long resetStart_; unsigned long lastReset_; + + byte receivingByte_; + byte receivingBitPos_; + byte receiveTarget_; + + bool ignoreNextEdge_; }; #endif From b492dc675c554cbd5eb6589d895b56283b6948af Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 26 Apr 2015 19:46:52 +0200 Subject: [PATCH 25/32] refactoring wip : search rom (doesn't work yet) --- OneWireSlave.cpp | 169 ++++++++++++++++++++++++++++++++++++++++++++--- OneWireSlave.h | 28 +++++++- 2 files changed, 187 insertions(+), 10 deletions(-) diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index 6e406bc..417231e 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -224,6 +224,7 @@ void OneWireSlave::endPresence_() debug.SC_APPEND_STR_TIME("endPresence", now); #endif + ignoreNextEdge_ = true; beginWaitCommand_(); } @@ -235,10 +236,15 @@ void OneWireSlave::beginWaitCommand_() void OneWireSlave::beginReceive_() { - ignoreNextEdge_ = true; - pin_.attachInterrupt(&OneWireSlave::receiveHandler_, FALLING); receivingByte_ = 0; receivingBitPos_ = 0; + beginReceiveBit_(&OneWireSlave::onBitReceivedHandler_); +} + +void OneWireSlave::beginReceiveBit_(void(*completeCallback)(bool bit, bool error)) +{ + receiveBitCallback_ = completeCallback; + pin_.attachInterrupt(&OneWireSlave::receiveHandler_, FALLING); } void OneWireSlave::receive_() @@ -246,21 +252,90 @@ void OneWireSlave::receive_() onEnterInterrupt_(); if (!ignoreNextEdge_) - setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::receiveBitHandler_); + { + pin_.detachInterrupt(); + setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::readBitHandler_); + } + + ignoreNextEdge_ = false; + + onLeaveInterrupt_(); +} + +void OneWireSlave::beginSendBit_(bool bit, void(*completeCallback)(bool error)) +{ + bitSentCallback_ = completeCallback; + if (bit) + { + pin_.attachInterrupt(&OneWireSlave::sendBitOneHandler_, FALLING); + } + else + { + pin_.attachInterrupt(&OneWireSlave::sendBitZeroHandler_, FALLING); + } +} + +void OneWireSlave::sendBitOne_() +{ + onEnterInterrupt_(); + bool ignoreEdge = ignoreNextEdge_; ignoreNextEdge_ = false; + if (!ignoreEdge) + bitSentCallback_(false); + + onLeaveInterrupt_(); +} + +void OneWireSlave::sendBitZero_() +{ + onEnterInterrupt_(); + + if (ignoreNextEdge_) + { + ignoreNextEdge_ = false; + return; + } + + pullLow_(); + pin_.detachInterrupt(); + setTimerEvent_(SendBitDuration, &OneWireSlave::endSendBitZeroHandler_); + onLeaveInterrupt_(); } -void OneWireSlave::receiveBit_() +void OneWireSlave::endSendBitZero_() +{ + onEnterInterrupt_(); + + releaseBus_(); + bitSentCallback_(false); + + onLeaveInterrupt_(); +} + +void OneWireSlave::readBit_() { onEnterInterrupt_(); bool bit = pin_.read(); + receiveBitCallback_(bit, false); //dbgOutput.writeLow(); //dbgOutput.writeHigh(); + onLeaveInterrupt_(); +} + +void OneWireSlave::onBitReceived_(bool bit, bool error) +{ + if (error) + { + error_("Invalid bit"); + beginWaitReset_(); + return; + } + receivingByte_ |= ((bit ? 1 : 0) << receivingBitPos_); ++receivingBitPos_; @@ -274,24 +349,102 @@ void OneWireSlave::receiveBit_() if (receivingByte_ == 0xF0) { beginSearchRom_(); + return; } else { // TODO: send command to client code beginWaitReset_(); + return; } } else { // TODO: add byte in receive buffer beginWaitReset_(); + return; } } - - onLeaveInterrupt_(); + + beginReceiveBit_(&OneWireSlave::onBitReceivedHandler_); } void OneWireSlave::beginSearchRom_() { - pin_.detachInterrupt(); -} \ No newline at end of file + 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::continueSearchRomHandler_); +} + +void OneWireSlave::continueSearchRom_(bool error) +{ + if (error) + { + error_("Failed to send bit"); + beginWaitReset_(); + return; + } + + searchRomInverse_ = !searchRomInverse_; + if (searchRomInverse_) + { + beginSearchRomSendBit_(); + } + else + { + beginReceiveBit_(&OneWireSlave::searchRomOnBitReceivedHandler_); + } +} + +void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) +{ + if (error) + { + error_("Bit read error during ROM search"); + beginWaitReset_(); + return; + } + + byte currentByte = rom_[searchRomBytePos_]; + bool currentBit = bitRead(currentByte, searchRomBitPos_); + + if (bit == currentBit) + { + ++searchRomBitPos_; + if (searchRomBitPos_ == 8) + { + searchRomBitPos_ = 0; + ++searchRomBytePos_; + } + + if (searchRomBytePos_ == 8) + { + #ifdef DEBUG_LOG + debug.SC_APPEND_STR("ROM sent entirely"); + #endif + beginWaitReset_(); + } + else + { + beginSearchRomSendBit_(); + } + } + else + { + #ifdef DEBUG_LOG + debug.SC_APPEND_STR("Leaving ROM search"); + #endif + beginWaitReset_(); + } +} diff --git a/OneWireSlave.h b/OneWireSlave.h index 390693f..0b999ca 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -42,7 +42,16 @@ private: void beginWaitReset_(); void beginWaitCommand_(); void beginReceive_(); + + void beginReceiveBit_(void(*completeCallback)(bool bit, bool error)); + void beginSendBit_(bool bit, void(*completeCallback)(bool error)); + void beginSearchRom_(); + void beginSearchRomSendBit_(); + inline static void continueSearchRomHandler_(bool error) { inst_->continueSearchRom_(error); } + void continueSearchRom_(bool error); + inline static void searchRomOnBitReceivedHandler_(bool bit, bool error) { inst_->searchRomOnBitReceived_(bit, error); } + void searchRomOnBitReceived_(bool bit, bool error); // interrupt handlers inline static void waitResetHandler_() { inst_->waitReset_(); } @@ -53,8 +62,16 @@ private: void endPresence_(); inline static void receiveHandler_() { inst_->receive_(); } void receive_(); - inline static void receiveBitHandler_() { inst_->receiveBit_(); } - void receiveBit_(); + inline static void readBitHandler_() { inst_->readBit_(); } + void readBit_(); + inline static void onBitReceivedHandler_(bool bit, bool error) { inst_->onBitReceived_(bit, error); } + void onBitReceived_(bool bit, bool error); + inline static void sendBitOneHandler_() { inst_->sendBitOne_(); } + void sendBitOne_(); + inline static void sendBitZeroHandler_() { inst_->sendBitZero_(); } + void sendBitZero_(); + inline static void endSendBitZeroHandler_() { inst_->endSendBitZero_(); } + void endSendBitZero_(); private: static OneWireSlave* inst_; @@ -65,11 +82,18 @@ private: unsigned long resetStart_; unsigned long lastReset_; + void(*receiveBitCallback_)(bool bit, bool error); + void(*bitSentCallback_)(bool error); + byte receivingByte_; byte receivingBitPos_; byte receiveTarget_; bool ignoreNextEdge_; + + byte searchRomBytePos_; + byte searchRomBitPos_; + bool searchRomInverse_; }; #endif From 229459599518260d72ebb932fdc2535eefa77c92 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 26 Apr 2015 20:24:11 +0200 Subject: [PATCH 26/32] - fixed bug in Pin::attachInterrupt (this is an arduino bug : interrupts that have been triggered before the handler is attached will cause it to be called immediately ; but only interrupts happening after should call the handler) - changed OneWireSlave interface to make it completely static (there is an instance, but it's only a wrapper to the static stuff, so that the syntax looks nice) - the search rom algorithm works fine most of the time, but sometimes it fails, probably because of interrupts being blocked at the wrong time (small delay to respond to the master to send a zero) --- LowLevel.h | 12 +++++- OneWireIO.ino | 5 +-- OneWireSlave.cpp | 88 ++++++++++++++++++++-------------------- OneWireSlave.h | 103 ++++++++++++++++++++--------------------------- 4 files changed, 102 insertions(+), 106 deletions(-) diff --git a/LowLevel.h b/LowLevel.h index 4f86264..3e695af 100644 --- a/LowLevel.h +++ b/LowLevel.h @@ -76,6 +76,12 @@ private: byte interruptNumber_; public: + Pin() + : mask_(0) + , reg_(0) + , interruptNumber_((byte)-1) + { } + Pin(uint8_t pin) { mask_ = PIN_TO_BITMASK(pin); @@ -97,7 +103,11 @@ public: 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) { ::attachInterrupt(interruptNumber_, handler, mode); } + 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_); } }; diff --git a/OneWireIO.ino b/OneWireIO.ino index af35fbb..aa70a0b 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -11,14 +11,13 @@ SerialChannel debug("debug"); Pin led(LEDPin); byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; -OneWireSlave oneWire(owROM, OWPin); void setup() { led.outputMode(); led.writeLow(); - oneWire.enable(); + OneWire.begin(owROM, OWPin); Serial.begin(9600); } @@ -40,7 +39,7 @@ void loop() SerialChannel::flush(); byte b; - if (oneWire.read(b)) + if (OneWire.read(b)) { char msg[32]; sprintf(msg, "Received byte : %d", (int)b); diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index 417231e..ca8deba 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -25,7 +25,25 @@ namespace void(*timerEvent)() = 0; } -OneWireSlave* OneWireSlave::inst_ = 0; +OneWireSlave OneWire; + +byte OneWireSlave::rom_[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); + +byte OneWireSlave::receivingByte_; +byte OneWireSlave::receivingBitPos_; +byte OneWireSlave::receiveTarget_; + +byte OneWireSlave::searchRomBytePos_; +byte OneWireSlave::searchRomBitPos_; +bool OneWireSlave::searchRomInverse_; ISR(TIMER1_COMPA_vect) // timer1 interrupt { @@ -35,38 +53,37 @@ ISR(TIMER1_COMPA_vect) // timer1 interrupt event(); } -OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) - : pin_(pinNumber) - , resetStart_((unsigned long)-1) - , lastReset_(0) - , ignoreNextEdge_(false) +void OneWireSlave::begin(byte* rom, byte pinNumber) { - inst_ = this; // we can have only one instance in the current implementation + pin_ = Pin(pinNumber); + resetStart_ = (unsigned long)-1; + lastReset_ = 0; + memcpy(rom_, rom, 7); rom_[7] = crc8_(rom_, 7); -} -void OneWireSlave::enable() -{ #ifdef DEBUG_LOG debug.append("Enabling 1-wire library"); dbgOutput.outputMode(); dbgOutput.writeHigh(); #endif - 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::disable() +void OneWireSlave::end() { #ifdef DEBUG_LOG debug.append("Disabling 1-wire library"); @@ -165,7 +182,7 @@ void OneWireSlave::releaseBus_() void OneWireSlave::beginWaitReset_() { disableTimer_(); - pin_.attachInterrupt(&OneWireSlave::waitResetHandler_, CHANGE); + pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE); resetStart_ = (unsigned int)-1; } @@ -195,7 +212,7 @@ void OneWireSlave::waitReset_() lastReset_ = now; pin_.detachInterrupt(); - setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresenceHandler_); + setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresence_); } } else @@ -209,7 +226,7 @@ void OneWireSlave::beginPresence_() { unsigned long now = micros(); pullLow_(); - setTimerEvent_(PresenceDuration, &OneWireSlave::endPresenceHandler_); + setTimerEvent_(PresenceDuration, &OneWireSlave::endPresence_); #ifdef DEBUG_LOG debug.SC_APPEND_STR_TIME("reset", lastReset_); debug.SC_APPEND_STR_TIME("beginPresence", now); @@ -224,7 +241,6 @@ void OneWireSlave::endPresence_() debug.SC_APPEND_STR_TIME("endPresence", now); #endif - ignoreNextEdge_ = true; beginWaitCommand_(); } @@ -238,26 +254,21 @@ void OneWireSlave::beginReceive_() { receivingByte_ = 0; receivingBitPos_ = 0; - beginReceiveBit_(&OneWireSlave::onBitReceivedHandler_); + beginReceiveBit_(&OneWireSlave::onBitReceived_); } void OneWireSlave::beginReceiveBit_(void(*completeCallback)(bool bit, bool error)) { receiveBitCallback_ = completeCallback; - pin_.attachInterrupt(&OneWireSlave::receiveHandler_, FALLING); + pin_.attachInterrupt(&OneWireSlave::receive_, FALLING); } void OneWireSlave::receive_() { onEnterInterrupt_(); - if (!ignoreNextEdge_) - { - pin_.detachInterrupt(); - setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::readBitHandler_); - } - - ignoreNextEdge_ = false; + pin_.detachInterrupt(); + setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::readBit_); onLeaveInterrupt_(); } @@ -267,11 +278,11 @@ void OneWireSlave::beginSendBit_(bool bit, void(*completeCallback)(bool error)) bitSentCallback_ = completeCallback; if (bit) { - pin_.attachInterrupt(&OneWireSlave::sendBitOneHandler_, FALLING); + pin_.attachInterrupt(&OneWireSlave::sendBitOne_, FALLING); } else { - pin_.attachInterrupt(&OneWireSlave::sendBitZeroHandler_, FALLING); + pin_.attachInterrupt(&OneWireSlave::sendBitZero_, FALLING); } } @@ -279,28 +290,19 @@ void OneWireSlave::sendBitOne_() { onEnterInterrupt_(); - bool ignoreEdge = ignoreNextEdge_; - ignoreNextEdge_ = false; - - if (!ignoreEdge) - bitSentCallback_(false); + bitSentCallback_(false); onLeaveInterrupt_(); } void OneWireSlave::sendBitZero_() { - onEnterInterrupt_(); + pullLow_(); // this must be executed first because the timing is very tight with some master devices - if (ignoreNextEdge_) - { - ignoreNextEdge_ = false; - return; - } + onEnterInterrupt_(); - pullLow_(); pin_.detachInterrupt(); - setTimerEvent_(SendBitDuration, &OneWireSlave::endSendBitZeroHandler_); + setTimerEvent_(SendBitDuration, &OneWireSlave::endSendBitZero_); onLeaveInterrupt_(); } @@ -366,7 +368,7 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) } } - beginReceiveBit_(&OneWireSlave::onBitReceivedHandler_); + beginReceiveBit_(&OneWireSlave::onBitReceived_); } void OneWireSlave::beginSearchRom_() @@ -384,7 +386,7 @@ void OneWireSlave::beginSearchRomSendBit_() bool currentBit = bitRead(currentByte, searchRomBitPos_); bool bitToSend = searchRomInverse_ ? !currentBit : currentBit; - beginSendBit_(bitToSend, &OneWireSlave::continueSearchRomHandler_); + beginSendBit_(bitToSend, &OneWireSlave::continueSearchRom_); } void OneWireSlave::continueSearchRom_(bool error) @@ -403,7 +405,7 @@ void OneWireSlave::continueSearchRom_(bool error) } else { - beginReceiveBit_(&OneWireSlave::searchRomOnBitReceivedHandler_); + beginReceiveBit_(&OneWireSlave::searchRomOnBitReceived_); } } diff --git a/OneWireSlave.h b/OneWireSlave.h index 0b999ca..0275698 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -7,14 +7,11 @@ class OneWireSlave { public: - ///! Constructs a 1-wire slave that will be identified by the specified ROM (7 bytes, starting from the family code, CRC will be computed internally). Call enable to actually start listening for the 1-wire master. - OneWireSlave(byte* rom, byte pinNumber); - - ///! Starts listening for the 1-wire master. Reset, Presence and SearchRom are handled automatically. The library will use interrupts on the pin specified in the constructor, 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 enable(); + ///! 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 disable(); + void end(); ///! Pops one byte from the receive buffer, or returns false if no byte has been received. bool read(byte& b); @@ -26,74 +23,62 @@ public: void write(byte* bytes, short numBytes, void(*complete)(bool error)); private: - byte crc8_(byte* data, short numBytes); + static byte crc8_(byte* data, short numBytes); - void setTimerEvent_(short delayMicroSeconds, void(*handler)()); - void disableTimer_(); + static void setTimerEvent_(short delayMicroSeconds, void(*handler)()); + static void disableTimer_(); - void onEnterInterrupt_(); - void onLeaveInterrupt_(); + static void onEnterInterrupt_(); + static void onLeaveInterrupt_(); - void error_(const char* message); + static void error_(const char* message); - void pullLow_(); - void releaseBus_(); + static void pullLow_(); + static void releaseBus_(); - void beginWaitReset_(); - void beginWaitCommand_(); - void beginReceive_(); + static void beginReceiveBit_(void(*completeCallback)(bool bit, bool error)); + static void beginSendBit_(bool bit, void(*completeCallback)(bool error)); - void beginReceiveBit_(void(*completeCallback)(bool bit, bool error)); - void beginSendBit_(bool bit, void(*completeCallback)(bool error)); + static void beginWaitReset_(); + static void beginWaitCommand_(); + static void beginReceive_(); + static void onBitReceived_(bool bit, bool error); - void beginSearchRom_(); - void beginSearchRomSendBit_(); - inline static void continueSearchRomHandler_(bool error) { inst_->continueSearchRom_(error); } - void continueSearchRom_(bool error); - inline static void searchRomOnBitReceivedHandler_(bool bit, bool error) { inst_->searchRomOnBitReceived_(bit, error); } - void searchRomOnBitReceived_(bool bit, bool error); + static void beginSearchRom_(); + static void beginSearchRomSendBit_(); + static void continueSearchRom_(bool error); + static void searchRomOnBitReceived_(bool bit, bool error); // interrupt handlers - inline static void waitResetHandler_() { inst_->waitReset_(); } - void waitReset_(); - inline static void beginPresenceHandler_() { inst_->beginPresence_(); } - void beginPresence_(); - inline static void endPresenceHandler_() { inst_->endPresence_(); } - void endPresence_(); - inline static void receiveHandler_() { inst_->receive_(); } - void receive_(); - inline static void readBitHandler_() { inst_->readBit_(); } - void readBit_(); - inline static void onBitReceivedHandler_(bool bit, bool error) { inst_->onBitReceived_(bit, error); } - void onBitReceived_(bool bit, bool error); - inline static void sendBitOneHandler_() { inst_->sendBitOne_(); } - void sendBitOne_(); - inline static void sendBitZeroHandler_() { inst_->sendBitZero_(); } - void sendBitZero_(); - inline static void endSendBitZeroHandler_() { inst_->endSendBitZero_(); } - void endSendBitZero_(); + static void waitReset_(); + static void beginPresence_(); + static void endPresence_(); + static void receive_(); + static void readBit_(); + static void sendBitOne_(); + static void sendBitZero_(); + static void endSendBitZero_(); private: - static OneWireSlave* inst_; - byte rom_[8]; - Pin pin_; - byte tccr1bEnable_; - - unsigned long resetStart_; - unsigned long lastReset_; + static byte rom_[8]; + static Pin pin_; + static byte tccr1bEnable_; - void(*receiveBitCallback_)(bool bit, bool error); - void(*bitSentCallback_)(bool error); + static unsigned long resetStart_; + static unsigned long lastReset_; - byte receivingByte_; - byte receivingBitPos_; - byte receiveTarget_; + static void(*receiveBitCallback_)(bool bit, bool error); + static void(*bitSentCallback_)(bool error); - bool ignoreNextEdge_; + static byte receivingByte_; + static byte receivingBitPos_; + static byte receiveTarget_; - byte searchRomBytePos_; - byte searchRomBitPos_; - bool searchRomInverse_; + static byte searchRomBytePos_; + static byte searchRomBitPos_; + static bool searchRomInverse_; }; +extern OneWireSlave OneWire; + #endif From 300a6be90f0428911c3376d6e655a4bd0333b4f8 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 26 Apr 2015 21:09:30 +0200 Subject: [PATCH 27/32] added background reset check (in case the master sends a reset while another operation had started) --- OneWireSlave.cpp | 174 +++++++++++++++++++++++++++-------------------- OneWireSlave.h | 4 ++ 2 files changed, 106 insertions(+), 72 deletions(-) diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index ca8deba..0ae7cdb 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -179,84 +179,31 @@ void OneWireSlave::releaseBus_() #endif } -void OneWireSlave::beginWaitReset_() +void OneWireSlave::beginResetDetection_() +{ + setTimerEvent_(ResetMinDuration - 50, &OneWireSlave::resetCheck_); + resetStart_ = micros() - 50; +} + +void OneWireSlave::cancelResetDetection_() { disableTimer_(); - pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE); - resetStart_ = (unsigned int)-1; + resetStart_ = (unsigned long)-1; } -void OneWireSlave::waitReset_() +void OneWireSlave::resetCheck_() { onEnterInterrupt_(); - bool state = pin_.read(); - unsigned long now = micros(); - if (state) + if (!pin_.read()) { - 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_); - } - } - else - { - resetStart_ = now; + pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE); + #ifdef DEBUG_LOG + debug.SC_APPEND_STR("Reset detected during another operation"); + #endif } onLeaveInterrupt_(); } -void OneWireSlave::beginPresence_() -{ - unsigned long now = micros(); - pullLow_(); - setTimerEvent_(PresenceDuration, &OneWireSlave::endPresence_); - #ifdef DEBUG_LOG - debug.SC_APPEND_STR_TIME("reset", lastReset_); - debug.SC_APPEND_STR_TIME("beginPresence", now); - #endif -} - -void OneWireSlave::endPresence_() -{ - unsigned long now = micros(); - releaseBus_(); - #ifdef DEBUG_LOG - debug.SC_APPEND_STR_TIME("endPresence", now); - #endif - - beginWaitCommand_(); -} - -void OneWireSlave::beginWaitCommand_() -{ - receiveTarget_ = ReceiveCommand; - beginReceive_(); -} - -void OneWireSlave::beginReceive_() -{ - receivingByte_ = 0; - receivingBitPos_ = 0; - beginReceiveBit_(&OneWireSlave::onBitReceived_); -} - void OneWireSlave::beginReceiveBit_(void(*completeCallback)(bool bit, bool error)) { receiveBitCallback_ = completeCallback; @@ -273,6 +220,22 @@ void OneWireSlave::receive_() 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; @@ -290,6 +253,7 @@ void OneWireSlave::sendBitOne_() { onEnterInterrupt_(); + beginResetDetection_(); bitSentCallback_(false); onLeaveInterrupt_(); @@ -317,18 +281,84 @@ void OneWireSlave::endSendBitZero_() onLeaveInterrupt_(); } -void OneWireSlave::readBit_() +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; + } - bool bit = pin_.read(); - receiveBitCallback_(bit, false); - //dbgOutput.writeLow(); - //dbgOutput.writeHigh(); + 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_); + } + } + else + { + resetStart_ = now; + } onLeaveInterrupt_(); } +void OneWireSlave::beginPresence_() +{ + unsigned long now = micros(); + pullLow_(); + setTimerEvent_(PresenceDuration, &OneWireSlave::endPresence_); + #ifdef DEBUG_LOG + debug.SC_APPEND_STR_TIME("reset", lastReset_); + debug.SC_APPEND_STR_TIME("beginPresence", now); + #endif +} + +void OneWireSlave::endPresence_() +{ + unsigned long now = micros(); + releaseBus_(); + #ifdef DEBUG_LOG + debug.SC_APPEND_STR_TIME("endPresence", now); + #endif + + beginWaitCommand_(); +} + +void OneWireSlave::beginWaitCommand_() +{ + receiveTarget_ = ReceiveCommand; + beginReceive_(); +} + +void OneWireSlave::beginReceive_() +{ + receivingByte_ = 0; + receivingBitPos_ = 0; + beginReceiveBit_(&OneWireSlave::onBitReceived_); +} + void OneWireSlave::onBitReceived_(bool bit, bool error) { if (error) diff --git a/OneWireSlave.h b/OneWireSlave.h index 0275698..73ecee7 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -39,6 +39,9 @@ private: 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_(); @@ -58,6 +61,7 @@ private: static void sendBitOne_(); static void sendBitZero_(); static void endSendBitZero_(); + static void resetCheck_(); private: static byte rom_[8]; From b5fa47249d1b9493b415a66707d904dcbfdb2859 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 26 Apr 2015 22:01:30 +0200 Subject: [PATCH 28/32] ROM commands, read/write bytes (wip) --- OneWireSlave.cpp | 104 +++++++++++++++++++++++++++++++++++++++++------ OneWireSlave.h | 22 +++++++--- 2 files changed, 108 insertions(+), 18 deletions(-) diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index 0ae7cdb..965d349 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -16,7 +16,7 @@ namespace const unsigned long PresenceWaitDuration = 30; const unsigned long PresenceDuration = 300; - const unsigned long ReadBitSamplingTime = 30; + const unsigned long ReadBitSamplingTime = 25; const unsigned long SendBitDuration = 35; @@ -28,6 +28,7 @@ namespace OneWireSlave OneWire; byte OneWireSlave::rom_[8]; +byte OneWireSlave::scratchpad_[8]; Pin OneWireSlave::pin_; byte OneWireSlave::tccr1bEnable_; @@ -45,6 +46,10 @@ byte OneWireSlave::searchRomBytePos_; byte OneWireSlave::searchRomBitPos_; bool OneWireSlave::searchRomInverse_; +byte* OneWireSlave::receiveBytesBuffer_; +short OneWireSlave::receiveBytesLength_; +void(*OneWireSlave::receiveBytesCallback_)(bool error); + ISR(TIMER1_COMPA_vect) // timer1 interrupt { TCCR1B = 0; // disable clock @@ -364,7 +369,8 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) if (error) { error_("Invalid bit"); - beginWaitReset_(); + if (receiveTarget_ >= 0) + receiveBytesCallback_(true); return; } @@ -378,23 +384,39 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) #endif if (receiveTarget_ == ReceiveCommand) { - if (receivingByte_ == 0xF0) + receiveTarget_ = 0; + switch (receivingByte_) { + case 0xF0: // SEARCH ROM beginSearchRom_(); return; - } - else - { - // TODO: send command to client code - beginWaitReset_(); + 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 { - // TODO: add byte in receive buffer - beginWaitReset_(); - return; + receiveBytesBuffer_[receiveTarget_++] = receivingByte_; + receivingByte_ = 0; + receivingBitPos_ = 0; + if (receiveTarget_ == receiveBytesLength_) + { + beginWaitReset_(); + receiveBytesCallback_(false); + return; + } } } @@ -424,7 +446,6 @@ void OneWireSlave::continueSearchRom_(bool error) if (error) { error_("Failed to send bit"); - beginWaitReset_(); return; } @@ -444,7 +465,6 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) if (error) { error_("Bit read error during ROM search"); - beginWaitReset_(); return; } @@ -480,3 +500,61 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) beginWaitReset_(); } } + +void OneWireSlave::beginWriteBytes_(byte* data, short numBytes, void(*complete)(bool error)) +{ + // TODO + beginWaitReset_(); +} + +void OneWireSlave::beginReceiveBytes_(byte* buffer, short numBytes, void(*complete)(bool error)) +{ + receiveBytesBuffer_ = buffer; + receiveBytesLength_ = numBytes; + receiveTarget_ = 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) + { + #ifdef DEBUG_LOG + debug.SC_APPEND_STR("ROM matched"); + #endif + beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_); + } + else + { + #ifdef DEBUG_LOG + debug.SC_APPEND_STR("ROM not matched"); + #endif + beginWaitReset_(); + } +} + +void OneWireSlave::notifyClientByteReceived_(bool error) +{ + if (error) + { + error_("error receiving device specific bytes"); + return; + } + + beginWaitReset_(); + + // TODO +} diff --git a/OneWireSlave.h b/OneWireSlave.h index 73ecee7..a310c33 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -7,19 +7,19 @@ class OneWireSlave { public: - ///! 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. + //! 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. + //! Stops all 1-wire activities, which frees hardware resources for other purposes. void end(); - ///! Pops one byte from the receive buffer, or returns false if no byte has been received. + //! Pops one byte from the receive buffer, or returns false if no byte has been received. bool read(byte& b); - ///! Sets (or replaces) a function to be called when at least one byte has been received. Callbacks are executed from interrupts and should be as short as possible. + //! Sets (or replaces) a function to be called when at least one byte has been received. Callbacks are executed from interrupts and should be as short as possible. void setReceiveCallback(void(*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. + //! 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)); private: @@ -52,6 +52,13 @@ private: 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); + // interrupt handlers static void waitReset_(); static void beginPresence_(); @@ -65,6 +72,7 @@ private: private: static byte rom_[8]; + static byte scratchpad_[8]; static Pin pin_; static byte tccr1bEnable_; @@ -81,6 +89,10 @@ private: static byte searchRomBytePos_; static byte searchRomBitPos_; static bool searchRomInverse_; + + static byte* receiveBytesBuffer_; + static short receiveBytesLength_; + static void(*receiveBytesCallback_)(bool error); }; extern OneWireSlave OneWire; From c0a183c76988962c33f9aab63a0ba3b8fbcae638 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Mon, 27 Apr 2015 21:53:31 +0200 Subject: [PATCH 29/32] finished implementation of most important 1-wire functionalities --- LowLevel.h | 2 +- OneWireIO.ino | 42 +++++++++++++-- OneWireSlave.cpp | 134 ++++++++++++++++++++++++++++++++--------------- OneWireSlave.h | 26 +++++---- 4 files changed, 147 insertions(+), 57 deletions(-) diff --git a/LowLevel.h b/LowLevel.h index 3e695af..35ed948 100644 --- a/LowLevel.h +++ b/LowLevel.h @@ -71,8 +71,8 @@ class Pin { private: - IO_REG_TYPE mask_; volatile IO_REG_TYPE *reg_; + IO_REG_TYPE mask_; byte interruptNumber_; public: diff --git a/OneWireIO.ino b/OneWireIO.ino index aa70a0b..b3a9b16 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -12,11 +12,21 @@ Pin led(LEDPin); byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; +byte buffer1[8]; +byte buffer2[8]; +volatile byte* backBuffer = buffer1; +volatile byte bufferPos = 0; + +byte sendBuffer[8]; + +void owReceive(OneWireSlave::ReceiveEvent evt, byte data); + void setup() { led.outputMode(); led.writeLow(); + OneWire.setReceiveCallback(&owReceive); OneWire.begin(owROM, OWPin); Serial.begin(9600); @@ -34,15 +44,39 @@ void loop() cli();//disable interrupts SerialChannel::swap(); + byte* frontBuffer = (byte*)backBuffer; + byte frontBufferSize = bufferPos; + backBuffer = backBuffer == buffer1 ? buffer2 : buffer1; + bufferPos = 0; sei();//enable interrupts SerialChannel::flush(); - byte b; - if (OneWire.read(b)) + for (int i = 0; i < frontBufferSize; ++i) { - char msg[32]; - sprintf(msg, "Received byte : %d", (int)b); + char msg[16]; + sprintf(msg, "Received byte: %d", (int)frontBuffer[i]); debug.write(msg); + + if (frontBuffer[i] == 0x42) + { + sendBuffer[0] = 0xBA; + sendBuffer[1] = 0xAD; + sendBuffer[2] = 0xF0; + sendBuffer[3] = 0x0D; + OneWire.write(sendBuffer, 4, 0); + } + } +} + +void owReceive(OneWireSlave::ReceiveEvent evt, byte data) +{ + switch (evt) + { + case OneWireSlave::RE_Byte: + backBuffer[bufferPos++] = data; + break; + default: + ; } } diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index 965d349..ec1c55d 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -1,11 +1,20 @@ #include "OneWireSlave.h" #define DEBUG_LOG +#define ERROR_MESSAGES #ifdef DEBUG_LOG #include "SerialChannel.h" extern SerialChannel debug; Pin dbgOutput(3); +#else +#undef ERROR_MESSAGES +#endif + +#ifdef ERROR_MESSAGES +#define ERROR(msg) error_(msg) +#else +#define ERROR(msg) error_(0) #endif namespace @@ -37,18 +46,21 @@ 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::receivingBitPos_; -byte OneWireSlave::receiveTarget_; byte OneWireSlave::searchRomBytePos_; byte OneWireSlave::searchRomBitPos_; bool OneWireSlave::searchRomInverse_; -byte* OneWireSlave::receiveBytesBuffer_; -short OneWireSlave::receiveBytesLength_; +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 { @@ -101,19 +113,11 @@ void OneWireSlave::end() sei(); } -bool OneWireSlave::read(byte& b) -{ - return false; -} - -void OneWireSlave::setReceiveCallback(void(*callback)()) -{ - -} - 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) @@ -151,18 +155,25 @@ void OneWireSlave::disableTimer_() 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 - debug.append(message); + if (message == 0) + debug.append("unspecified error"); + else + debug.append(message); #endif beginWaitReset_(); } @@ -312,7 +323,7 @@ void OneWireSlave::waitReset_() { if (resetDuration > ResetMaxDuration) { - error_("Reset too long"); + ERROR("Reset too long"); onLeaveInterrupt_(); return; } @@ -320,6 +331,8 @@ void OneWireSlave::waitReset_() lastReset_ = now; pin_.detachInterrupt(); setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresence_); + if (clientReceiveCallback_ != 0) + clientReceiveCallback_(RE_Reset, 0); } } else @@ -353,14 +366,14 @@ void OneWireSlave::endPresence_() void OneWireSlave::beginWaitCommand_() { - receiveTarget_ = ReceiveCommand; + bufferPos_ = ReceiveCommand; beginReceive_(); } void OneWireSlave::beginReceive_() { receivingByte_ = 0; - receivingBitPos_ = 0; + bufferBitPos_ = 0; beginReceiveBit_(&OneWireSlave::onBitReceived_); } @@ -368,23 +381,23 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) { if (error) { - error_("Invalid bit"); - if (receiveTarget_ >= 0) + ERROR("Invalid bit"); + if (bufferPos_ >= 0) receiveBytesCallback_(true); return; } - receivingByte_ |= ((bit ? 1 : 0) << receivingBitPos_); - ++receivingBitPos_; + receivingByte_ |= ((bit ? 1 : 0) << bufferBitPos_); + ++bufferBitPos_; - if (receivingBitPos_ == 8) + if (bufferBitPos_ == 8) { #ifdef DEBUG_LOG debug.SC_APPEND_STR_INT("received byte", (long)receivingByte_); #endif - if (receiveTarget_ == ReceiveCommand) + if (bufferPos_ == ReceiveCommand) { - receiveTarget_ = 0; + bufferPos_ = 0; switch (receivingByte_) { case 0xF0: // SEARCH ROM @@ -402,16 +415,16 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) matchRomBytesReceived_(false); return; default: - error_("Unknown command"); + ERROR("Unknown command"); return; } } else { - receiveBytesBuffer_[receiveTarget_++] = receivingByte_; + buffer_[bufferPos_++] = receivingByte_; receivingByte_ = 0; - receivingBitPos_ = 0; - if (receiveTarget_ == receiveBytesLength_) + bufferBitPos_ = 0; + if (bufferPos_ == bufferLength_) { beginWaitReset_(); receiveBytesCallback_(false); @@ -445,7 +458,7 @@ void OneWireSlave::continueSearchRom_(bool error) { if (error) { - error_("Failed to send bit"); + ERROR("Failed to send bit"); return; } @@ -464,7 +477,7 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) { if (error) { - error_("Bit read error during ROM search"); + ERROR("Bit read error during ROM search"); return; } @@ -503,15 +516,48 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) void OneWireSlave::beginWriteBytes_(byte* data, short numBytes, void(*complete)(bool error)) { - // TODO - beginWaitReset_(); + 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)) { - receiveBytesBuffer_ = buffer; - receiveBytesLength_ = numBytes; - receiveTarget_ = 0; + buffer_ = buffer; + bufferLength_ = numBytes; + bufferPos_ = 0; receiveBytesCallback_ = complete; beginReceive_(); } @@ -519,14 +565,14 @@ void OneWireSlave::beginReceiveBytes_(byte* buffer, short numBytes, void(*comple void OneWireSlave::noOpCallback_(bool error) { if (error) - error_("error during an internal 1-wire operation"); + ERROR("error during an internal 1-wire operation"); } void OneWireSlave::matchRomBytesReceived_(bool error) { if (error) { - error_("error receiving match rom bytes"); + ERROR("error receiving match rom bytes"); return; } @@ -550,11 +596,13 @@ void OneWireSlave::notifyClientByteReceived_(bool error) { if (error) { - error_("error receiving device specific bytes"); + if (clientReceiveCallback_ != 0) + clientReceiveCallback_(RE_Error, 0); + ERROR("error receiving custom bytes"); return; } - beginWaitReset_(); - - // TODO + beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_); + if (clientReceiveCallback_ != 0) + clientReceiveCallback_(RE_Byte, scratchpad_[0]); } diff --git a/OneWireSlave.h b/OneWireSlave.h index a310c33..b1dbc94 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -7,17 +7,21 @@ 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(); - //! Pops one byte from the receive buffer, or returns false if no byte has been received. - bool read(byte& b); - - //! Sets (or replaces) a function to be called when at least one byte has been received. Callbacks are executed from interrupts and should be as short as possible. - void setReceiveCallback(void(*callback)()); + //! 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)); @@ -58,6 +62,7 @@ private: 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_(); @@ -83,16 +88,19 @@ private: static void(*bitSentCallback_)(bool error); static byte receivingByte_; - static byte receivingBitPos_; - static byte receiveTarget_; static byte searchRomBytePos_; static byte searchRomBitPos_; static bool searchRomInverse_; - static byte* receiveBytesBuffer_; - static short receiveBytesLength_; + 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; From 4d94761fd5939d06dd6c8d44d9a99389a97ba42e Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Mon, 27 Apr 2015 23:17:45 +0200 Subject: [PATCH 30/32] - implemented simple protocol to turn an output on/off - disabled debug code --- OneWireIO.ino | 45 ++++++++++++--------------------------------- OneWireSlave.cpp | 2 +- SerialChannel.cpp | 3 +++ SerialChannel.h | 4 ++++ 4 files changed, 20 insertions(+), 34 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index b3a9b16..e3abba5 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -6,18 +6,15 @@ #define LEDPin 13 #define OWPin 2 +#ifdef ENABLE_SERIAL_CHANNEL SerialChannel debug("debug"); +#endif Pin led(LEDPin); byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; -byte buffer1[8]; -byte buffer2[8]; -volatile byte* backBuffer = buffer1; -volatile byte bufferPos = 0; - -byte sendBuffer[8]; +byte acknowledge = 0x42; void owReceive(OneWireSlave::ReceiveEvent evt, byte data); @@ -32,41 +29,19 @@ void setup() Serial.begin(9600); } -int count = 0; void loop() { delay(1); - if (count++ == 1000) - { - led.write(!led.read()); - count = 0; - } cli();//disable interrupts + #ifdef ENABLE_SERIAL_CHANNEL SerialChannel::swap(); - byte* frontBuffer = (byte*)backBuffer; - byte frontBufferSize = bufferPos; - backBuffer = backBuffer == buffer1 ? buffer2 : buffer1; - bufferPos = 0; + #endif sei();//enable interrupts + #ifdef ENABLE_SERIAL_CHANNEL SerialChannel::flush(); - - for (int i = 0; i < frontBufferSize; ++i) - { - char msg[16]; - sprintf(msg, "Received byte: %d", (int)frontBuffer[i]); - debug.write(msg); - - if (frontBuffer[i] == 0x42) - { - sendBuffer[0] = 0xBA; - sendBuffer[1] = 0xAD; - sendBuffer[2] = 0xF0; - sendBuffer[3] = 0x0D; - OneWire.write(sendBuffer, 4, 0); - } - } + #endif } void owReceive(OneWireSlave::ReceiveEvent evt, byte data) @@ -74,7 +49,11 @@ void owReceive(OneWireSlave::ReceiveEvent evt, byte data) switch (evt) { case OneWireSlave::RE_Byte: - backBuffer[bufferPos++] = data; + if (data == 0x01) + led.writeHigh(); + else if (data == 0x02) + led.writeLow(); + OneWire.write(&acknowledge, 1, 0); break; default: ; diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index ec1c55d..d4d05b5 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -1,6 +1,6 @@ #include "OneWireSlave.h" -#define DEBUG_LOG +//#define DEBUG_LOG #define ERROR_MESSAGES #ifdef DEBUG_LOG diff --git a/SerialChannel.cpp b/SerialChannel.cpp index 63537b6..951f390 100644 --- a/SerialChannel.cpp +++ b/SerialChannel.cpp @@ -1,6 +1,8 @@ #include "Arduino.h" #include "SerialChannel.h" +#ifdef ENABLE_SERIAL_CHANNEL + byte SerialChannel::nextId = 1; SerialChannel* SerialChannel::first = 0; @@ -165,3 +167,4 @@ void SerialChannel::handleConnection() } } +#endif //ENABLE_SERIAL_CHANNEL diff --git a/SerialChannel.h b/SerialChannel.h index 53e1bd3..2da7bf1 100644 --- a/SerialChannel.h +++ b/SerialChannel.h @@ -1,6 +1,9 @@ #ifndef _SerialChannel_h_ #define _SerialChannel_h_ +//#define ENABLE_SERIAL_CHANNEL + +#ifdef ENABLE_SERIAL_CHANNEL #define SC_APPEND_STR(str) append((byte*)str, sizeof(str)-1) #define SC_APPEND_STR_INT(str, arg0) appendInt(str, sizeof(str)-1, arg0) @@ -55,6 +58,7 @@ private: static void writeShort(short num); static void writeULong(unsigned long num); }; +#endif // ENABLE_SERIAL_CHANNEL #endif From cf5f36b50339f8ee8530503dada04b70ca6480d7 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sat, 8 Aug 2015 22:36:24 +0200 Subject: [PATCH 31/32] improved high-level protocol --- OneWireIO.ino | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/OneWireIO.ino b/OneWireIO.ino index e3abba5..1e65415 100644 --- a/OneWireIO.ino +++ b/OneWireIO.ino @@ -15,6 +15,19 @@ Pin led(LEDPin); byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; byte acknowledge = 0x42; +byte commandCheckError = 0xF1; + +int turnOnTimeoutSeconds = 5 * 60; + +const byte CMD_TurnOn = 0x01; +const byte CMD_TurnOff = 0x02; +const byte CMD_ReadState = 0x03; + +const byte ANS_StateIsOn = 0x01; +const byte ANS_StateIsOff = 0x02; + +volatile byte command = 0x0; +volatile long turnOnStartTime = 0; void owReceive(OneWireSlave::ReceiveEvent evt, byte data); @@ -33,6 +46,13 @@ void loop() { delay(1); + long now = millis(); + if (now > turnOnStartTime + (long)turnOnTimeoutSeconds * 1000 || now < turnOnStartTime) + { + led.writeLow(); + turnOnStartTime = 0; + } + cli();//disable interrupts #ifdef ENABLE_SERIAL_CHANNEL SerialChannel::swap(); @@ -49,11 +69,47 @@ void owReceive(OneWireSlave::ReceiveEvent evt, byte data) switch (evt) { case OneWireSlave::RE_Byte: - if (data == 0x01) - led.writeHigh(); - else if (data == 0x02) - led.writeLow(); - OneWire.write(&acknowledge, 1, 0); + if (command == 0x00) + { + command = data; + } + else + { + if (data == (0xFF-command)) // to check there is no communication error, the master must send the command, and then its inverse + { + byte receivedCommand = command; + command = 0x0; + switch (receivedCommand) + { + case CMD_TurnOn: + turnOnStartTime = millis(); + led.writeHigh(); + OneWire.write(&acknowledge, 1, NULL); + break; + case CMD_TurnOff: + led.writeLow(); + turnOnStartTime = 0; + OneWire.write(&acknowledge, 1, NULL); + break; + case CMD_ReadState: + bool state = led.read(); + static byte response[2]; + response[0] = state ? ANS_StateIsOn : ANS_StateIsOff; + response[1] = 0xFF - response[0]; + OneWire.write(response, 2, NULL); + break; + } + } + else + { + command = 0x0; + OneWire.write(&commandCheckError, 1, NULL); + } + } + break; + case OneWireSlave::RE_Reset: + case OneWireSlave::RE_Error: + command = 0x0; break; default: ; From 14711750d6c02996a28252e12710a32513cdb1c4 Mon Sep 17 00:00:00 2001 From: Youen Toupin Date: Sun, 9 Aug 2015 09:15:32 +0200 Subject: [PATCH 32/32] cleaned up project for public distribution (removed debug and unrelated stuff) --- OneWireIO-tmp.hpp | 434 ------------------ OneWireIO.ino | 117 ----- OneWireIO.sln | 15 - OneWireIO.vcxproj | 7 +- OneWireIO.vcxproj.filters | 4 +- OneWireIO_Demo.ino | 75 +++ OneWireSlave.cpp | 65 +-- OneWireSlave.h | 4 +- SerialChannel.cpp | 170 ------- SerialChannel.h | 64 --- SerialMonitor/SerialMonitor.sln | 22 - SerialMonitor/SerialMonitor/App.config | 6 - SerialMonitor/SerialMonitor/App.xaml | 18 - SerialMonitor/SerialMonitor/App.xaml.cs | 94 ---- SerialMonitor/SerialMonitor/MainWindow.xaml | 18 - .../SerialMonitor/MainWindow.xaml.cs | 62 --- .../SerialMonitor/MainWindowContext.cs | 222 --------- SerialMonitor/SerialMonitor/MathEx.cs | 21 - .../SerialMonitor/Properties/AssemblyInfo.cs | 55 --- .../Properties/Resources.Designer.cs | 71 --- .../SerialMonitor/Properties/Resources.resx | 117 ----- .../Properties/Settings.Designer.cs | 30 -- .../Properties/Settings.settings | 7 - SerialMonitor/SerialMonitor/SerialMessage.cs | 26 -- .../SerialMonitor/SerialMonitor.csproj | 108 ----- .../SerialMonitor/SerialPortExtensions.cs | 44 -- traces/search-without-arduino.bewf | Bin 260137 -> 0 bytes 27 files changed, 95 insertions(+), 1781 deletions(-) delete mode 100644 OneWireIO-tmp.hpp delete mode 100644 OneWireIO.ino create mode 100644 OneWireIO_Demo.ino delete mode 100644 SerialChannel.cpp delete mode 100644 SerialChannel.h delete mode 100644 SerialMonitor/SerialMonitor.sln delete mode 100644 SerialMonitor/SerialMonitor/App.config delete mode 100644 SerialMonitor/SerialMonitor/App.xaml delete mode 100644 SerialMonitor/SerialMonitor/App.xaml.cs delete mode 100644 SerialMonitor/SerialMonitor/MainWindow.xaml delete mode 100644 SerialMonitor/SerialMonitor/MainWindow.xaml.cs delete mode 100644 SerialMonitor/SerialMonitor/MainWindowContext.cs delete mode 100644 SerialMonitor/SerialMonitor/MathEx.cs delete mode 100644 SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs delete mode 100644 SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs delete mode 100644 SerialMonitor/SerialMonitor/Properties/Resources.resx delete mode 100644 SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs delete mode 100644 SerialMonitor/SerialMonitor/Properties/Settings.settings delete mode 100644 SerialMonitor/SerialMonitor/SerialMessage.cs delete mode 100644 SerialMonitor/SerialMonitor/SerialMonitor.csproj delete mode 100644 SerialMonitor/SerialMonitor/SerialPortExtensions.cs delete mode 100644 traces/search-without-arduino.bewf diff --git a/OneWireIO-tmp.hpp b/OneWireIO-tmp.hpp deleted file mode 100644 index c187bde..0000000 --- a/OneWireIO-tmp.hpp +++ /dev/null @@ -1,434 +0,0 @@ -#include "Arduino.h" -#include "LowLevel.h" -#include "SerialChannel.h" - -#define LEDPin 13 -#define OWPin 2 -#define InterruptNumber 0 // Must correspond to the OWPin to correctly detect state changes. On Arduino Uno, interrupt 0 is for digital pin 2 - -#define ResetMinDuration 480 -#define ResetMaxDuration 900 - -#define PresenceWaitDuration 30 -#define PresenceDuration 300 - -#define ReadBitSamplingTime 13 // the theorical time is about 30us, but given various overhead, this is the empirical delay I've found works best (on Arduino Uno) - -#define SendBitDuration 35 - -const byte InvalidBit = (byte)-1; -const byte IncompleteBit = (byte)-2; - -SerialChannel debug("debug"); - -Pin owPin(OWPin); -Pin owOutTestPin(3); -Pin led(LEDPin); - -enum OwStatus -{ - OS_WaitReset, - OS_Presence, - OS_WaitCommand, - OS_SearchRom, -}; -OwStatus status; - -byte owROM[8] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 }; -byte searchROMCurrentByte = 0; -byte searchROMCurrentBit = 0; -bool searchROMSendingInverse = false; -bool searchROMReadingMasterResponseBit = false; - -void owPullLow() -{ - owPin.outputMode(); - owPin.writeLow(); - owOutTestPin.writeLow(); -} - -void owRelease() -{ - owPin.inputMode(); - owOutTestPin.writeHigh(); -} - -void onEnterInterrupt() -{ - //owOutTestPin.writeLow(); -} - -void onLeaveInterrupt() -{ - //owOutTestPin.writeHigh(); -} - -volatile unsigned long resetStart = (unsigned long)-1; -unsigned long lastReset = (unsigned long)-1; -unsigned long bitStart = (unsigned long)-1; -byte receivingByte = 0; -byte receivingBitPos = 0; -bool searchRomNextBit = false; -bool searchRomNextBitToSend = false; - -void setup() -{ - owROM[7] = crc8((char*)owROM, 7); - - led.outputMode(); - owPin.inputMode(); - owOutTestPin.outputMode(); - owOutTestPin.writeHigh(); - - led.writeLow(); - - cli(); // disable interrupts - attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); - - // set timer0 interrupt at 250KHz (actually depends on compare match register OCR0A) - // 4us between each tick - TCCR1A = 0; - TCCR1B = 0; - TCNT1 = 0; // initialize counter value to 0 - //TCCR1B |= (1 << WGM12); // turn on CTC mode - //TCCR1B |= (1 << CS11) | (1 << CS10); // Set 64 prescaler - TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt - sei(); // enable interrupts - - Serial.begin(9600); -} - -int count = 0; -void loop() -{ - if ((count++) % 1000 == 0) - led.write(!led.read()); - cli();//disable interrupts - SerialChannel::swap(); - sei();//enable interrupts - - SerialChannel::flush(); -} - -void(*timerEvent)() = 0; -void setTimerEvent(short microSecondsDelay, void(*event)()) -{ - microSecondsDelay -= 10; // this seems to be the typical time taken to initialize the timer on Arduino Uno - - short skipTicks = (microSecondsDelay - 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; - //debug.SC_APPEND_STR_INT("setTimerEvent", (long)skipTicks); - TCNT1 = 0; - OCR1A = skipTicks; - timerEvent = event; - TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler -} - -void owError(const char* message) -{ - debug.append(message); - led.writeHigh(); - status = OS_WaitReset; -} - -void owClearError() -{ - led.writeLow(); -} - -void owWaitResetInterrupt() -{ - onEnterInterrupt(); - bool state = owPin.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) - { - owError("Reset too long"); - onLeaveInterrupt(); - return; - } - - owClearError(); - lastReset = now; - status = OS_Presence; - setTimerEvent(PresenceWaitDuration - (micros() - now), &beginPresence); - } - } - else - { - resetStart = now; - } - onLeaveInterrupt(); -} - -//bool debugState = false; -volatile unsigned long lastInterrupt = 0; -void owReceiveCommandInterrupt(void) -{ - onEnterInterrupt(); - unsigned long now = micros(); - if (now < lastInterrupt + 20) - { - onLeaveInterrupt(); - return; // don't react to our own actions - } - lastInterrupt = now; - - //debugState = !debugState; - //owOutTestPin.write(debugState); - - //led.write(state); - - bool bit = readBit(); - /*if (bit) - debug.SC_APPEND_STR("received bit 1"); - else - debug.SC_APPEND_STR("received bit 0");*/ - - receivingByte |= ((bit ? 1 : 0) << receivingBitPos); - ++receivingBitPos; - - if (receivingBitPos == 8) - { - byte receivedByte = receivingByte; - receivingBitPos = 0; - receivingByte = 0; - //debug.SC_APPEND_STR_INT("received byte", (long)receivedByte); - - if (status == OS_WaitCommand && receivedByte == 0xF0) - { - status = OS_SearchRom; - searchROMReadingMasterResponseBit = false; - searchROMSendingInverse = false; - searchROMCurrentByte = 0; - searchROMCurrentBit = 0; - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - //attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); - setTimerEvent(10, owSearchSendBit); - detachInterrupt(InterruptNumber); - onLeaveInterrupt(); - return; - } - } - - onLeaveInterrupt(); -} - -bool ignoreNextFallingEdge = false; - -void owSearchSendBit() -{ - onEnterInterrupt(); - - // wait for a falling edge (active wait is more reliable than interrupts to send the bit fast enough) - while (!owPin.read()); - while (owPin.read()); - - //sendBit(searchRomNextBitToSend); - if (searchRomNextBitToSend) - { - //delayMicroseconds(SendBitDuration); - ignoreNextFallingEdge = false; - } - else - { - owPullLow(); - //delayMicroseconds(SendBitDuration); - //owRelease(); - ignoreNextFallingEdge = true; - } - - unsigned long sendBitStart = micros(); - - if (searchROMSendingInverse) - { - searchROMSendingInverse = false; - searchROMReadingMasterResponseBit = true; - } - else - { - searchROMSendingInverse = true; - } - - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - - if (searchROMReadingMasterResponseBit) - { - ignoreNextFallingEdge = true; - attachInterrupt(InterruptNumber, onewireInterruptSearchROM, FALLING); - } - else - { - setTimerEvent(10, owSearchSendBit); - } - - delayMicroseconds(SendBitDuration - (micros() - sendBitStart)); - owRelease(); - - onLeaveInterrupt(); -} - -void onewireInterruptSearchROM() -{ - onEnterInterrupt(); - - if (ignoreNextFallingEdge) - { - ignoreNextFallingEdge = false; - onLeaveInterrupt(); - return; - } - - if (searchROMReadingMasterResponseBit) - { - bool bit = readBit(); - - if (bit != searchRomNextBit) - { - debug.SC_APPEND_STR("Master didn't send our bit, leaving ROM search"); - status = OS_WaitReset; - attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); - onLeaveInterrupt(); - return; - } - - searchROMReadingMasterResponseBit = false; - ++searchROMCurrentBit; - if (searchROMCurrentBit == 8) - { - ++searchROMCurrentByte; - searchROMCurrentBit = 0; - //debug.SC_APPEND_STR("sent another ROM byte"); - } - - if (searchROMCurrentByte == 8) - { - searchROMCurrentByte = 0; - status = OS_WaitReset; - debug.SC_APPEND_STR("ROM sent entirely"); - attachInterrupt(InterruptNumber, owWaitResetInterrupt, CHANGE); - onLeaveInterrupt(); - return; - } - - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - - setTimerEvent(10, owSearchSendBit); - detachInterrupt(InterruptNumber); - onLeaveInterrupt(); - return; - } - else - { - sendBit(searchRomNextBitToSend); - /*if (bitToSend) - debug.SC_APPEND_STR("sent ROM search bit : 1"); - else - debug.SC_APPEND_STR("sent ROM search bit : 0");*/ - - if (searchROMSendingInverse) - { - searchROMSendingInverse = false; - searchROMReadingMasterResponseBit = true; - } - else - { - searchROMSendingInverse = true; - } - } - - byte currentByte = owROM[searchROMCurrentByte]; - searchRomNextBit = bitRead(currentByte, searchROMCurrentBit); - searchRomNextBitToSend = searchROMSendingInverse ? !searchRomNextBit : searchRomNextBit; - - onLeaveInterrupt(); -} - -bool readBit() -{ - delayMicroseconds(ReadBitSamplingTime); - bool bit = owPin.read(); - //owOutTestPin.write(!owOutTestPin.read()); - //owOutTestPin.write(!owOutTestPin.read()); - return bit; -} - -void sendBit(bool bit) -{ - if (bit) - { - delayMicroseconds(SendBitDuration); - ignoreNextFallingEdge = false; - } - else - { - owPullLow(); - delayMicroseconds(SendBitDuration); - owRelease(); - ignoreNextFallingEdge = true; - } -} - -void beginPresence() -{ - unsigned long now = micros(); - owPullLow(); - setTimerEvent(PresenceDuration, &endPresence); - debug.SC_APPEND_STR_TIME("reset", lastReset); - debug.SC_APPEND_STR_TIME("beginPresence", now); -} - -void endPresence() -{ - unsigned long now = micros(); - owRelease(); - debug.SC_APPEND_STR_TIME("endPresence", now); - - status = OS_WaitCommand; - attachInterrupt(InterruptNumber, owReceiveCommandInterrupt, FALLING); - receivingByte = 0; - receivingBitPos = 0; - bitStart = (unsigned long)-1; -} - -ISR(TIMER1_COMPA_vect) // timer1 interrupt -{ - TCCR1B = 0; // disable clock - void(*event)() = timerEvent; - timerEvent = 0; - if (event != 0) - event(); -} - -uint8_t crc8(char addr[], uint8_t len) { - uint8_t crc = 0; - - while (len--) { - uint8_t inbyte = *addr++; - for (uint8_t i = 8; i; i--) { - uint8_t mix = (crc ^ inbyte) & 0x01; - crc >>= 1; - if (mix) crc ^= 0x8C; - inbyte >>= 1; - } - } - return crc; -} diff --git a/OneWireIO.ino b/OneWireIO.ino deleted file mode 100644 index 1e65415..0000000 --- a/OneWireIO.ino +++ /dev/null @@ -1,117 +0,0 @@ -#include "Arduino.h" -#include "LowLevel.h" -#include "SerialChannel.h" -#include "OneWireSlave.h" - -#define LEDPin 13 -#define OWPin 2 - -#ifdef ENABLE_SERIAL_CHANNEL -SerialChannel debug("debug"); -#endif - -Pin led(LEDPin); - -byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; - -byte acknowledge = 0x42; -byte commandCheckError = 0xF1; - -int turnOnTimeoutSeconds = 5 * 60; - -const byte CMD_TurnOn = 0x01; -const byte CMD_TurnOff = 0x02; -const byte CMD_ReadState = 0x03; - -const byte ANS_StateIsOn = 0x01; -const byte ANS_StateIsOff = 0x02; - -volatile byte command = 0x0; -volatile long turnOnStartTime = 0; - -void owReceive(OneWireSlave::ReceiveEvent evt, byte data); - -void setup() -{ - led.outputMode(); - led.writeLow(); - - OneWire.setReceiveCallback(&owReceive); - OneWire.begin(owROM, OWPin); - - Serial.begin(9600); -} - -void loop() -{ - delay(1); - - long now = millis(); - if (now > turnOnStartTime + (long)turnOnTimeoutSeconds * 1000 || now < turnOnStartTime) - { - led.writeLow(); - turnOnStartTime = 0; - } - - cli();//disable interrupts - #ifdef ENABLE_SERIAL_CHANNEL - SerialChannel::swap(); - #endif - sei();//enable interrupts - - #ifdef ENABLE_SERIAL_CHANNEL - SerialChannel::flush(); - #endif -} - -void owReceive(OneWireSlave::ReceiveEvent evt, byte data) -{ - switch (evt) - { - case OneWireSlave::RE_Byte: - if (command == 0x00) - { - command = data; - } - else - { - if (data == (0xFF-command)) // to check there is no communication error, the master must send the command, and then its inverse - { - byte receivedCommand = command; - command = 0x0; - switch (receivedCommand) - { - case CMD_TurnOn: - turnOnStartTime = millis(); - led.writeHigh(); - OneWire.write(&acknowledge, 1, NULL); - break; - case CMD_TurnOff: - led.writeLow(); - turnOnStartTime = 0; - OneWire.write(&acknowledge, 1, NULL); - break; - case CMD_ReadState: - bool state = led.read(); - static byte response[2]; - response[0] = state ? ANS_StateIsOn : ANS_StateIsOff; - response[1] = 0xFF - response[0]; - OneWire.write(response, 2, NULL); - break; - } - } - else - { - command = 0x0; - OneWire.write(&commandCheckError, 1, NULL); - } - } - break; - case OneWireSlave::RE_Reset: - case OneWireSlave::RE_Error: - command = 0x0; - break; - default: - ; - } -} diff --git a/OneWireIO.sln b/OneWireIO.sln index 1efede9..f10e9f5 100644 --- a/OneWireIO.sln +++ b/OneWireIO.sln @@ -5,11 +5,6 @@ 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 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialMonitor", "SerialMonitor\SerialMonitor\SerialMonitor.csproj", "{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}" - ProjectSection(ProjectDependencies) = postProject - {3B500971-1570-460F-81C3-22AC3B7764B9} = {3B500971-1570-460F-81C3-22AC3B7764B9} - EndProjectSection -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,16 +25,6 @@ Global {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 - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Win32.ActiveCfg = Debug|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.Build.0 = Release|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Win32.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/OneWireIO.vcxproj b/OneWireIO.vcxproj index 308080d..e27473d 100644 --- a/OneWireIO.vcxproj +++ b/OneWireIO.vcxproj @@ -13,6 +13,7 @@ {3B500971-1570-460F-81C3-22AC3B7764B9} OneWireIO + OneWireIO_Demo @@ -83,7 +84,7 @@ exit /B 1 - + Document false if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf del $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf @@ -99,14 +100,10 @@ D:\Outils\Arduino\arduino.exe --pref build.path=$(ProjectDir)$(IntDir) --upload true - - true - - diff --git a/OneWireIO.vcxproj.filters b/OneWireIO.vcxproj.filters index 22a782b..fbe64d9 100644 --- a/OneWireIO.vcxproj.filters +++ b/OneWireIO.vcxproj.filters @@ -1,15 +1,13 @@  - - - + \ No newline at end of file diff --git a/OneWireIO_Demo.ino b/OneWireIO_Demo.ino new file mode 100644 index 0000000..cc2c9f6 --- /dev/null +++ b/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 + } +} diff --git a/OneWireSlave.cpp b/OneWireSlave.cpp index d4d05b5..916ae28 100644 --- a/OneWireSlave.cpp +++ b/OneWireSlave.cpp @@ -1,15 +1,7 @@ #include "OneWireSlave.h" -//#define DEBUG_LOG -#define ERROR_MESSAGES - -#ifdef DEBUG_LOG -#include "SerialChannel.h" -extern SerialChannel debug; -Pin dbgOutput(3); -#else -#undef ERROR_MESSAGES -#endif +// 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) @@ -77,13 +69,9 @@ void OneWireSlave::begin(byte* rom, byte pinNumber) lastReset_ = 0; memcpy(rom_, rom, 7); - rom_[7] = crc8_(rom_, 7); + rom_[7] = crc8(rom_, 7); - #ifdef DEBUG_LOG - debug.append("Enabling 1-wire library"); - dbgOutput.outputMode(); - dbgOutput.writeHigh(); - #endif + // log("Enabling 1-wire library") cli(); // disable interrupts pin_.inputMode(); @@ -120,7 +108,7 @@ void OneWireSlave::write(byte* bytes, short numBytes, void(*complete)(bool error sei(); } -byte OneWireSlave::crc8_(byte* data, short numBytes) +byte OneWireSlave::crc8(byte* data, short numBytes) { byte crc = 0; @@ -182,17 +170,11 @@ void OneWireSlave::pullLow_() { pin_.outputMode(); pin_.writeLow(); -#ifdef DEBUG_LOG - //dbgOutput.writeLow(); -#endif } void OneWireSlave::releaseBus_() { pin_.inputMode(); -#ifdef DEBUG_LOG - //dbgOutput.writeHigh(); -#endif } void OneWireSlave::beginResetDetection_() @@ -213,9 +195,7 @@ void OneWireSlave::resetCheck_() if (!pin_.read()) { pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE); - #ifdef DEBUG_LOG - debug.SC_APPEND_STR("Reset detected during another operation"); - #endif + // log("Reset detected during another operation"); } onLeaveInterrupt_(); } @@ -344,22 +324,13 @@ void OneWireSlave::waitReset_() void OneWireSlave::beginPresence_() { - unsigned long now = micros(); pullLow_(); setTimerEvent_(PresenceDuration, &OneWireSlave::endPresence_); - #ifdef DEBUG_LOG - debug.SC_APPEND_STR_TIME("reset", lastReset_); - debug.SC_APPEND_STR_TIME("beginPresence", now); - #endif } void OneWireSlave::endPresence_() { - unsigned long now = micros(); releaseBus_(); - #ifdef DEBUG_LOG - debug.SC_APPEND_STR_TIME("endPresence", now); - #endif beginWaitCommand_(); } @@ -392,9 +363,8 @@ void OneWireSlave::onBitReceived_(bool bit, bool error) if (bufferBitPos_ == 8) { - #ifdef DEBUG_LOG - debug.SC_APPEND_STR_INT("received byte", (long)receivingByte_); - #endif + // log("received byte", (long)receivingByte_); + if (bufferPos_ == ReceiveCommand) { bufferPos_ = 0; @@ -495,9 +465,8 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) if (searchRomBytePos_ == 8) { - #ifdef DEBUG_LOG - debug.SC_APPEND_STR("ROM sent entirely"); - #endif + // log("ROM sent entirely"); + beginWaitReset_(); } else @@ -507,9 +476,7 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error) } else { - #ifdef DEBUG_LOG - debug.SC_APPEND_STR("Leaving ROM search"); - #endif + // log("Leaving ROM search"); beginWaitReset_(); } } @@ -578,16 +545,14 @@ void OneWireSlave::matchRomBytesReceived_(bool error) if (memcmp(rom_, scratchpad_, 8) == 0) { - #ifdef DEBUG_LOG - debug.SC_APPEND_STR("ROM matched"); - #endif + // log("ROM matched"); + beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_); } else { - #ifdef DEBUG_LOG - debug.SC_APPEND_STR("ROM not matched"); - #endif + // log("ROM not matched"); + beginWaitReset_(); } } diff --git a/OneWireSlave.h b/OneWireSlave.h index b1dbc94..9eb279d 100644 --- a/OneWireSlave.h +++ b/OneWireSlave.h @@ -26,9 +26,9 @@ public: //! 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)); -private: - static byte crc8_(byte* data, short numBytes); + static byte crc8(byte* data, short numBytes); +private: static void setTimerEvent_(short delayMicroSeconds, void(*handler)()); static void disableTimer_(); diff --git a/SerialChannel.cpp b/SerialChannel.cpp deleted file mode 100644 index 951f390..0000000 --- a/SerialChannel.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "Arduino.h" -#include "SerialChannel.h" - -#ifdef ENABLE_SERIAL_CHANNEL - -byte SerialChannel::nextId = 1; -SerialChannel* SerialChannel::first = 0; - -SerialChannel::Message SerialChannel::buffer1[SerialChannel::MaxPendingMessages]; -SerialChannel::Message SerialChannel::buffer2[SerialChannel::MaxPendingMessages]; -volatile SerialChannel::Message* SerialChannel::backBuffer; -volatile byte SerialChannel::backBufferPos; -byte SerialChannel::frontBufferSize; - -SerialChannel::Message dummyMessage; - -SerialChannel::SerialChannel(const char* name_) - : next(0) - , id((byte)-1) - , name(name_) -{ - if(first == 0) - first = this; - else - { - SerialChannel* c = first; - while(c->next != 0) c = c->next; - c->next = this; - } - - id = nextId++; -} - -void SerialChannel::beginWriteInChannel(byte id, short byteCount, unsigned long time) -{ - Serial.write("START"); - Serial.write(id); - writeULong(time); - writeShort(byteCount); -} - -void SerialChannel::write(byte* data, short byteCount, unsigned long time) -{ - beginWrite(byteCount, time); - continueWrite(data, byteCount); -} - -void SerialChannel::beginWrite(short byteCount, unsigned long time) -{ - if (time == (unsigned long)-1) - time = micros(); - - handleConnection(); - - beginWriteInChannel(id, byteCount, time); -} - -void SerialChannel::continueWrite(byte* data, short byteCount) -{ - Serial.write(data, byteCount); -} - -void SerialChannel::write(const char* text, unsigned long time) -{ - write((byte*)text, strlen(text), time); -} - -SerialChannel::Message& SerialChannel::append(byte* data, short byteCount, unsigned long time) -{ - if (time == (unsigned long)-1) - time = micros(); - - if (backBufferPos >= MaxPendingMessages) - { - Message& msg = ((Message*)backBuffer)[MaxPendingMessages-1]; - msg.id = id; - msg.data = (byte*)"OVERFLOW"; - msg.byteCount = 8; - msg.time = time; - msg.longArg0 = 0; - - return dummyMessage; - } - else - { - Message& msg = ((Message*)backBuffer)[backBufferPos++]; - msg.id = id; - msg.data = data; - msg.byteCount = byteCount; - msg.time = time; - msg.longArg0 = 0; - - return msg; - } -} - -void SerialChannel::append(const char* text, unsigned long time) -{ - append((byte*)text, strlen(text), time); -} - -void SerialChannel::appendInt(const char* text, short textLength, int arg0, unsigned long time) -{ - Message& msg = append((byte*)text, textLength, time); - msg.longArg0 = arg0 | 0x40000000; -} - -void SerialChannel::swap() -{ - backBuffer = backBuffer == buffer1 ? buffer2 : buffer1; - frontBufferSize = backBufferPos; - backBufferPos = 0; -} - -void SerialChannel::flush() -{ - handleConnection(); - - Message* frontBuffer = backBuffer == buffer1 ? buffer2 : buffer1; - for (Message* msg = frontBuffer; msg < frontBuffer + frontBufferSize; ++msg) - { - char params[32]; - params[0] = 0; - - if ((msg->longArg0 & 0x40000000) != 0) - sprintf(params, ";arg0=%ld", msg->longArg0 & ~0x40000000); - - short paramsSize = strlen(params); - - beginWriteInChannel(msg->id, msg->byteCount + paramsSize, msg->time); - Serial.write(msg->data, msg->byteCount); - if (paramsSize > 0) - Serial.write(params, paramsSize); - - Serial.flush(); - } -} - -void SerialChannel::writeShort(short num) -{ - Serial.write((byte*)&num, 2); -} - -void SerialChannel::writeULong(unsigned long num) -{ - Serial.write((byte*)&num, 4); -} - -void SerialChannel::handleConnection() -{ - int b = Serial.read(); - if(b == (int)'C') - { - Serial.write("CONNECTION"); - SerialChannel* c = first; - while(c) - { - Serial.write("START"); - Serial.write(0); - Serial.write("ChannelInit"); - Serial.write(c->id); - writeShort(strlen(c->name)); - Serial.write(c->name); - c = c->next; - } - Serial.flush(); - } -} - -#endif //ENABLE_SERIAL_CHANNEL diff --git a/SerialChannel.h b/SerialChannel.h deleted file mode 100644 index 2da7bf1..0000000 --- a/SerialChannel.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _SerialChannel_h_ -#define _SerialChannel_h_ - -//#define ENABLE_SERIAL_CHANNEL - -#ifdef ENABLE_SERIAL_CHANNEL -#define SC_APPEND_STR(str) append((byte*)str, sizeof(str)-1) -#define SC_APPEND_STR_INT(str, arg0) appendInt(str, sizeof(str)-1, arg0) - -#define SC_APPEND_STR_TIME(str, time) append((byte*)str, sizeof(str)-1, time) - -class SerialChannel -{ -public: - struct Message - { - unsigned long time; - long longArg0; - byte* data; - short byteCount; - byte id; - }; - -private: - static const byte MaxPendingMessages = 32; - - static SerialChannel* first; - SerialChannel* next; - - static byte nextId; - byte id; - const char* name; - - static Message buffer1[MaxPendingMessages]; - static Message buffer2[MaxPendingMessages]; - static volatile Message* backBuffer; - static volatile byte backBufferPos; - static byte frontBufferSize; - -public: - SerialChannel(const char* name_); - - static void beginWriteInChannel(byte id, short byteCount, unsigned long time); - void write(byte* data, short byteCount, unsigned long time = (unsigned long)-1); - void write(const char* text, unsigned long time = (unsigned long)-1); - - void beginWrite(short byteCount, unsigned long time = (unsigned long)-1); - void continueWrite(byte* data, short byteCount); - - Message& append(byte* data, short byteCount, unsigned long time = (unsigned long)-1); - void append(const char* text, unsigned long time = (unsigned long)-1); - void appendInt(const char* text, short textLength, int arg0, unsigned long time = (unsigned long)-1); - static void swap(); - static void flush(); - -private: - static void handleConnection(); - static void writeShort(short num); - static void writeULong(unsigned long num); -}; -#endif // ENABLE_SERIAL_CHANNEL - -#endif - diff --git a/SerialMonitor/SerialMonitor.sln b/SerialMonitor/SerialMonitor.sln deleted file mode 100644 index f11d68b..0000000 --- a/SerialMonitor/SerialMonitor.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialMonitor", "SerialMonitor\SerialMonitor.csproj", "{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/SerialMonitor/SerialMonitor/App.config b/SerialMonitor/SerialMonitor/App.config deleted file mode 100644 index 8e15646..0000000 --- a/SerialMonitor/SerialMonitor/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/SerialMonitor/SerialMonitor/App.xaml b/SerialMonitor/SerialMonitor/App.xaml deleted file mode 100644 index a998b86..0000000 --- a/SerialMonitor/SerialMonitor/App.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - diff --git a/SerialMonitor/SerialMonitor/App.xaml.cs b/SerialMonitor/SerialMonitor/App.xaml.cs deleted file mode 100644 index 3fa11b0..0000000 --- a/SerialMonitor/SerialMonitor/App.xaml.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Diagnostics; -using System.IO.Ports; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Shapes; -using System.Windows.Threading; - -namespace SerialMonitor -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - private SerialPort Serial; - private IDictionary Channels = new Dictionary(); - private bool Connected = false; - - protected override void OnStartup(StartupEventArgs e) - { - base.OnStartup(e); - - Serial = new SerialPort(); - Serial.PortName = "COM4"; - Serial.BaudRate = 9600; - - Serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(OnDataReceived); - - Serial.Open(); - Serial.Write("C"); - } - - private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) - { - if (!Connected) - { - Serial.ReadTo("CONNECTION"); - Connected = true; - } - - // channel declaration message: byte 0 ; string "ChannelInit" ; byte ; short ; byte[length] - // regular message: byte ; short ; byte[length] - - SerialMessage message = null; - - Serial.ReadTo("START"); - - int id = Serial.ReadByte(); - if (id == 0) - { - string check = Encoding.UTF8.GetString(Serial.ReadBytes(11)); - if (check != "ChannelInit") - throw new Exception("Incorrect data check for channel initialization"); - id = Serial.ReadByte(); - int length = Serial.ReadShort(); - string name = Encoding.UTF8.GetString(Serial.ReadBytes(length)); - Channels[id] = name; - message = new SerialMessage { ChannelName = "debug", StringData = "Channel " + name + " opened", SendTime = 0 }; - } - else - { - ulong sendTime = Serial.ReadULong(); - int length = Serial.ReadShort(); - byte[] data = Serial.ReadBytes(length); - message = new SerialMessage { ChannelName = Channels[id], Data = data, SendTime = sendTime }; - } - - if(message != null) - Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => OnMessageReceived(message))); - } - - private void OnMessageReceived(SerialMessage message) - { - switch (message.ChannelName) - { - case "debug": - string text = ((float)message.SendTime / 1000000).ToString("0.000000") + "s " + message.StringData; - //Debug.WriteLine(text); - MainWindowContext.Get.WriteLine(text); - break; - case "oscilloscope": - byte frequency = message.Data[0]; - MainWindowContext.Get.AddSequence(message.SendTime, frequency, message.Data.Skip(1).ToArray()); - break; - } - } - } -} diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml b/SerialMonitor/SerialMonitor/MainWindow.xaml deleted file mode 100644 index 7cb7936..0000000 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs b/SerialMonitor/SerialMonitor/MainWindow.xaml.cs deleted file mode 100644 index 82c9d9f..0000000 --- a/SerialMonitor/SerialMonitor/MainWindow.xaml.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace SerialMonitor -{ - /// - /// Interaction logic for MainWindow.xaml - /// - public partial class MainWindow : Window - { - public MainWindow() - { - InitializeComponent(); - var context = new MainWindowContext(this); - context.WriteLine("Connecting..."); - this.DataContext = context; - - this.MouseWheel += OnMouseWheel; - } - - private void OnMouseWheel(object sender, MouseWheelEventArgs e) - { - MainWindowContext context = (MainWindowContext)this.DataContext; - Point cursorPos = e.GetPosition(context.OscilloscopeCanvas); - if (cursorPos.X < 0 || cursorPos.X > context.OscilloscopeCanvas.ActualWidth || cursorPos.Y < 0 || cursorPos.Y > context.OscilloscopeCanvas.ActualHeight) - return; - - double cursorPosRatio = cursorPos.X / context.OscilloscopeCanvas.ActualWidth; - double cursorTime = context.ViewportStartTime + cursorPosRatio * context.ViewportTimeWidth; - - double newTimeWidth = context.ViewportTimeWidth; - if (e.Delta > 0) - newTimeWidth /= e.Delta * 0.01; - else if (e.Delta < 0) - newTimeWidth *= -e.Delta * 0.01; - - double totalTimeWidth = Math.Max(0.1, context.MaxTime - context.MinTime); - if (newTimeWidth > totalTimeWidth) - newTimeWidth = totalTimeWidth; - - double newStartTime = cursorTime - cursorPosRatio * newTimeWidth; - if (newStartTime < context.MinTime) - newStartTime = context.MinTime; - if (newStartTime + newTimeWidth > context.MaxTime) - newStartTime = context.MaxTime - newTimeWidth; - - context.SetViewport(newStartTime, newTimeWidth); - } - } -} diff --git a/SerialMonitor/SerialMonitor/MainWindowContext.cs b/SerialMonitor/SerialMonitor/MainWindowContext.cs deleted file mode 100644 index 1c34255..0000000 --- a/SerialMonitor/SerialMonitor/MainWindowContext.cs +++ /dev/null @@ -1,222 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Shapes; - -namespace SerialMonitor -{ - public class MainWindowContext : INotifyPropertyChanged - { - private MainWindow Window; - - public MainWindowContext(MainWindow window) - { - Window = window; - Get = this; - } - - public static MainWindowContext Get { get; private set; } - - private List Lines = new List(); - public string ConsoleText { get { return String.Join("\n", Lines); } } - - public void WriteLine(string line) - { - Lines.Add(line); - if (Lines.Count > 100) - Lines.RemoveAt(0); - OnPropertyChanged("ConsoleText"); - } - - public int MaxSequenceSize { get { return 2048; } } - - private class Sequence - { - public ulong StartTime { get; set; } // time in microseconds of the first sample - public byte[] Data { get; set; } - public double Frequency { get; set; } // sampling rate (in samples per second) - - public class Comparer : IComparer - { - public int Compare(Sequence x, Sequence y) - { - return x.StartTime.CompareTo(y.StartTime); - } - } - } - double ValueToHeight(double time, byte value) - { - //value = (byte)(Math.Sin(time * 100.0) * 127.0 + 128.0); - return 256.0 - (double)value + 10; - } - private SortedSet Sequences = new SortedSet(new Sequence.Comparer()); - public IEnumerable Oscilloscope - { - get - { - if(!Sequences.Any()) - yield break; - - foreach (var sequence in Sequences) - { - double seqStartTime = (double)sequence.StartTime/1000000.0; - double sampleDelay = 1.0 / sequence.Frequency; - if (seqStartTime + (double)sequence.Data.Length * sampleDelay > ViewportStartTime && seqStartTime < ViewportStartTime + ViewportTimeWidth) - { - foreach (var line in ConvertToLines(sequence)) - yield return line; - } - } - } - } - - private IEnumerable ConvertToLines(Sequence sequence) - { - double viewportWidth = OscilloscopeCanvas.ActualWidth; - double scale = viewportWidth / ViewportTimeWidth; // in pixels per second - - ulong displayStartTime = (ulong)(viewportStartTime_ * 1000000.0); - double sampleDelay = 1.0 / sequence.Frequency; - - double pos = ((double)sequence.StartTime - (double)displayStartTime) / 1000000.0 * scale; - if (pos > 1000) - yield break; - double prevPos = pos; - byte minValue = sequence.Data[0]; - byte maxValue = minValue; - int prevIdx = 0; - double prevHeight = ValueToHeight(sequence.StartTime / 1000000.0, minValue); - for (int idx = 1; idx < sequence.Data.Length; ++idx) - { - byte value = sequence.Data[idx]; - pos += sampleDelay * scale; - if (value > maxValue) maxValue = value; - if (value < minValue) minValue = value; - - if (pos > 0 && pos < viewportWidth && pos - prevPos >= 5 || idx == sequence.Data.Length - 1) - { - var line = new Line(); - line.Stroke = System.Windows.Media.Brushes.LightSteelBlue; - line.HorizontalAlignment = HorizontalAlignment.Left; - line.VerticalAlignment = VerticalAlignment.Center; - line.StrokeThickness = 1; - - line.X1 = prevPos; - prevPos = pos; - line.X2 = pos; - - double time = (double)sequence.StartTime / 1000000.0 + (double)idx * sampleDelay; - double lastHeight = ValueToHeight(time, value); - - if (idx == prevIdx + 1) - { - line.Y1 = prevHeight; - line.Y2 = lastHeight; - } - else - { - if (value - minValue > maxValue - value) - { - line.Y1 = ValueToHeight(time, minValue); - line.Y2 = ValueToHeight(time, maxValue); - } - else - { - line.Y1 = ValueToHeight(time, maxValue); - line.Y2 = ValueToHeight(time, minValue); - } - } - - prevHeight = lastHeight; - minValue = value; - maxValue = value; - prevIdx = idx; - - yield return line; - } - } - } - - public void AddSequence(ulong startTime, byte frequency, byte[] data) - { - // TODO: merge sequences if total size is lower than MaxSequenceSize - double cpuClock = 16000000.0; - int adsp0 = (frequency & (1 << 0)) != 0 ? 1 : 0; - int adsp1 = (frequency & (1 << 1)) != 0 ? 1 : 0; - int adsp2 = (frequency & (1 << 2)) != 0 ? 1 : 0; - int skipBit0 = (frequency & (1 << 3)) != 0 ? 1 : 0; - int skipBit1 = (frequency & (1 << 4)) != 0 ? 1 : 0; - int skipBit2 = (frequency & (1 << 5)) != 0 ? 1 : 0; - int adcDivider = 1 << Math.Max(1, adsp0 + adsp1*2 + adsp2*4); - int skip = skipBit0 + skipBit1 * 2 + skipBit2 * 4; - double freq = cpuClock / (double)adcDivider / 13.0 / (double)(1 + skip); - var sequence = new Sequence { StartTime = startTime, Frequency = freq, Data = data }; - Sequences.Add(sequence); - OnPropertyChanged("Oscilloscope"); - OnPropertyChanged("MinTime"); - OnPropertyChanged("MaxTime"); - if (Sequences.Count == 1) - { - ViewportStartTime = MinTime; - } - - var canvas = OscilloscopeCanvas; - foreach (var line in ConvertToLines(sequence)) - canvas.Children.Add(line); - } - - void RefreshOscilloscope() - { - var canvas = OscilloscopeCanvas; - canvas.Children.Clear(); - foreach (var line in Oscilloscope) - canvas.Children.Add(line); - } - - private Canvas oscilloscopeCanvas_; - public Canvas OscilloscopeCanvas { get { if (oscilloscopeCanvas_ == null) oscilloscopeCanvas_ = (Canvas)Window.FindName("Oscilloscope"); return oscilloscopeCanvas_; } } - - public double MinTime { get { return Sequences.Any() ? (double)Sequences.First().StartTime / 1000000.0 : 0.0; } } - public double MaxTime { get { return Sequences.Any() ? Math.Max(MinTime + 0.1, (double)Sequences.Last().StartTime / 1000000.0) : 0.1; } } - private double viewportTimeWidth_ = 0.1; - public double ViewportTimeWidth - { - get { return viewportTimeWidth_; } - set { viewportTimeWidth_ = value; OnPropertyChanged("ViewportTimeWidth"); RefreshOscilloscope(); } - } - - private double viewportStartTime_ = 0; - public double ViewportStartTime - { - get { return viewportStartTime_; } - set { viewportStartTime_ = value; OnPropertyChanged("ViewportStartTime"); RefreshOscilloscope(); } - } - public double ScrollValue - { - get { return MathEx.Unproject(MathEx.Project(ViewportStartTime, MinTime, MaxTime - ViewportTimeWidth), MinTime, MaxTime); } - set { ViewportStartTime = MathEx.Unproject(MathEx.Project(value, MinTime, MaxTime), MinTime, MaxTime - ViewportTimeWidth); } - } - - public void SetViewport(double startTime, double timeWidth) - { - viewportStartTime_ = startTime; - ViewportTimeWidth = timeWidth; - } - - public event PropertyChangedEventHandler PropertyChanged; - protected void OnPropertyChanged(string name) - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs(name)); - } - } - } -} diff --git a/SerialMonitor/SerialMonitor/MathEx.cs b/SerialMonitor/SerialMonitor/MathEx.cs deleted file mode 100644 index 4d6e1e6..0000000 --- a/SerialMonitor/SerialMonitor/MathEx.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SerialMonitor -{ - public static class MathEx - { - public static double Project(double value, double rangeMin, double rangeMax) - { - return (value - rangeMin) / (rangeMax - rangeMin); - } - - public static double Unproject(double ratio, double rangeMin, double rangeMax) - { - return rangeMin + ratio * (rangeMax - rangeMin); - } - } -} diff --git a/SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs b/SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs deleted file mode 100644 index e61c9f3..0000000 --- a/SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SerialMonitor")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("SerialMonitor")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs b/SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs deleted file mode 100644 index b6091de..0000000 --- a/SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SerialMonitor.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SerialMonitor.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/SerialMonitor/SerialMonitor/Properties/Resources.resx b/SerialMonitor/SerialMonitor/Properties/Resources.resx deleted file mode 100644 index af7dbeb..0000000 --- a/SerialMonitor/SerialMonitor/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs b/SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs deleted file mode 100644 index 098d3a4..0000000 --- a/SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SerialMonitor.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/SerialMonitor/SerialMonitor/Properties/Settings.settings b/SerialMonitor/SerialMonitor/Properties/Settings.settings deleted file mode 100644 index 033d7a5..0000000 --- a/SerialMonitor/SerialMonitor/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/SerialMonitor/SerialMonitor/SerialMessage.cs b/SerialMonitor/SerialMonitor/SerialMessage.cs deleted file mode 100644 index 4e4ed5a..0000000 --- a/SerialMonitor/SerialMonitor/SerialMessage.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SerialMonitor -{ - public class SerialMessage - { - public string ChannelName { get; set; } - - /// - /// Time at which the message was sent, in microseconds since the start of the remote executable - /// - public ulong SendTime { get; set; } - - public byte[] Data { get; set; } - - public string StringData - { - get { return Encoding.UTF8.GetString(Data); } - set { Data = Encoding.UTF8.GetBytes(value); } - } - } -} diff --git a/SerialMonitor/SerialMonitor/SerialMonitor.csproj b/SerialMonitor/SerialMonitor/SerialMonitor.csproj deleted file mode 100644 index 6f58ec6..0000000 --- a/SerialMonitor/SerialMonitor/SerialMonitor.csproj +++ /dev/null @@ -1,108 +0,0 @@ - - - - - Debug - AnyCPU - {97704F53-6CA1-4155-9E8F-AEBFEEC20A8B} - WinExe - Properties - SerialMonitor - SerialMonitor - v4.5 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - - - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - - - - \ No newline at end of file diff --git a/SerialMonitor/SerialMonitor/SerialPortExtensions.cs b/SerialMonitor/SerialMonitor/SerialPortExtensions.cs deleted file mode 100644 index 91e98bc..0000000 --- a/SerialMonitor/SerialMonitor/SerialPortExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO.Ports; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SerialMonitor -{ - public static class SerialPortExtensions - { - public static int ReadShort(this SerialPort port) - { - int b1 = port.ReadByte(); - int b2 = port.ReadByte(); - return b2 * 256 + b1; - } - - public static ulong ReadULong(this SerialPort port) - { - ulong b1 = (ulong)port.ReadByte(); - ulong b2 = (ulong)port.ReadByte(); - ulong b3 = (ulong)port.ReadByte(); - ulong b4 = (ulong)port.ReadByte(); - return b4 * 256 * 256 * 256 + b3 * 256 * 256 + b2 * 256 + b1; - } - - public static byte[] ReadBytes(this SerialPort port, int numBytes) - { - var bytes = new byte[numBytes]; - int remaining = numBytes; - int pos = 0; - while (remaining > 0) - { - int read = port.Read(bytes, pos, remaining); - if (read < 0) - throw new Exception("Connection closed"); - remaining -= read; - pos += read; - } - return bytes; - } - } -} diff --git a/traces/search-without-arduino.bewf b/traces/search-without-arduino.bewf deleted file mode 100644 index c86be4147c6b6cbf5f91d3e4b7c89f0e665afafb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 260137 zcmeI*dy^zZ8O7n+UBysTLPZfTD0syi7ZFz!aA6k^fr&7T@caMghtL@7^y#y2R#nz+ z_Bw5c5x<_;uDn%czE5V=bj@_nzWM6wufO+T`rEyKOs~E+JvAL4uY5Kq{&{D9`q!=L z{=L87o38jm009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_Kd z69oP^{bc&wbZh=vKCX`smnP@!G$nuQVM=9c>*r}cUfQ};<^GozDQWjo+9Rpjw9m2I zy!y~SdL&(u_!xD(q|(y+Bmj>r4fQPz>PdAC~b(RwPahk8uglvLj1ae1EAK97pWCEI)=a!*yi zE>C{jqF2*K+SaERmsPG(>zehE*7-X6I;DtHrc`p-rl)0o+3wZ}SBk4n+uO%0hpr!W z4N)IHk8{Q;*PfS3S6;2Rd6)KT>iCuFwW}jIl^)x%c)!%tC^ACVB$r;Cue$2VW$913 zcRFr8OUe*H009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**E+ue(`pxw1#V2C*c~O5d*PqsPzAee8c~h28 z^=41+uUw_HkMg}ZHHPO7W6&p#)hdtdrM!DoKw9qJeXcN%*Fl~yzjcl^taxswaQZNy(|ByG4$%rS(ez(*+=i# zAI#>@&-31^J7?Jk)2oNMK4%~OW2@)yTp;4BDLv~m@AYYYt>%0RzCHhZ7PKW!>se>9 zj?s^BTl(R}V*YS??Vzm)^OaBbS0s*g8?j2%O3^wszEaimcjvvg8s{!a&l-LE$n~h* z*44;Yr(CPH+qT5%{C$c~yD@4M-+O3o`;11KkAGNR?UcIH?WJe=(e(PE=g)@s=pE%r z%08NY`!MEye2!e|^(c9jIp-FYZd28!KSswdwe^?wR3GcvP<~yic9!qIYUuTy_ z#=i0@>G!iO{djs~df|lj+ao+_$zP8>YqagyEvx5Tp;NNXXYFrWdXK7Csz1(*qFwWz z2fNl>)J(X>`I?pF`~7T7KbhnI!A0cL^Lp&HUL&sPlU97rx2dXKo7ZeT=&r_3rr%vC z{!foRXU;v}(y)kArBf+Io>r9_KijURx2K;?Uz-0;-F7{kyCnDO=k8~FeBGV-4&ATY zeYNeWx-8#oEZtrmT>qtEy-VE}UQOw_?p4}#b67^lr@F#8Rdsf7%;PI2J#XjX+$9g@ z`=saR`zk#W%l6vr>q1>u*4K@7zOEy=)@ZB!`>)*F`$V7Nk&kp%na1h#GNoKY`;}s)w5Qv&E!%xl+n3KM&K>Rc__|xu&k5SE%yv9tVG%`|RJ+Yy z+dldwm%LB*9s2Uxo@l)eoJ&mGm{pUrkV{mr#Y&px-O<4;}l z>dX-);$<$SCE=3Mu|<2d{Y|#})AZBn^Yi?)Gw9c#Ub~+2q`i*S*6TRmW1VyDvTe$| z-TxlfyEDy9Xg#&!>S0}$HCHvGO1d+<%+Cbs&U6`{uPBPd&aJYgtIn>O56d{Gn&nJ> z*gXq9it(%RsO#g~t?x`d->pUBalCP9Td1bi#^d{Ri}c)oeKC5JCu#TT^yc)#!+Nf0 zYy8{Ds;&%FRxL+I@!7HG54x*h^e9i(E-_aOo=dM@J*%d2NmZFs%e|K8McPi&FLxsR z{q*AO_NSfNCyQ)suQv}pXT~#op2v3m+GjiGam#kBSG97?Z(JZ|_x#EQdcHfo^zaO` zuH~cGiracEzRZtnyXT)@DCWFoNwnEk+&a%x>hq{|@EKTfpBD4&`DdHsd)!pZL6&p$pWEv+S&M~SDTzxAuK-i-Fk?#Dew;UbAU(s_mAZLT%T(&g)uWnCSq zFXDSbDd$TgTA#@_Rg0uN617cPYWn?bOD}gfn%~aq=M8!|TBX`GB*)~_!ZOb3S#5lT zq+F(4J+`r{q(;%o$6iOxV=1iCw!~>Y_xstF<{o%kbM6w|1L_{w4{zgGlB%`dvEjpw z+oV3lX}dkb$6b?*;?6vh=xLjA<+$sukH2oE{HWXIe>>a8qAUe-F^)oN%kPSIjHgNMi&$IVvRV$q~>PMyPnK@m4Z$&)X?!T**{QCcb&1zRvk!!b!*k#o!t*fNu zJvV#rNBiS({$rYzP^M1h?k(EO`Ki|9CjP&0_g2LCaZYc!{9kz6HDoI(E+1{V?4zJo z@$qpoLp39NzdhCOaCOh5Bjn4y`iQP+OPubP+?vKei{alM@2!Z_J;(P@&rco25{*}C z+_tM-4(n3o+ZFElQEA$0yZ3n(jUwW;U9a$R_I%W=JMWoSdR+ePx#us;U*lpo)zUrt z`r?sGtM#&+qE2Zn-O|scUa7X;`|MqT_0D2B=PPHAt@G?!=URKEllOM~H^J)pix+uM z^V`$U=XX6|?e<<-Y83xIT(`M^ zGxz-T37;(+Kl0;RK6v=a@5EtyMdmeLlBFxh)W_6iDfRwo=QeuYACC-{>t4sus5}G8 z=~3fz-p?6*a(ic2um5+am#44Hz4YqNTc)1Bx{9xjO6iI>DQmi&(o1udOT#tFrN!Qg z)F}Lu$*lW`*H*{T!}F1mSiS5$f8%EAS$CAJ%-GY_8h;~tLLxHd-TV3&eD5_o-=Akq~}sh z+VO46U6PqeefH9vReCQ%{pL~e+ud9D=QTc8&5xdUzkd8@t?K#f7g_W9ZL4Fmkz?E% zdPdwPwf$|iNh;g^Dtd4F)!}!(miJs~L`vzO_C9Rpr(Rz3uKKk9{qP!2&;4%BA9a6$GRs&+WCw zCFAeUanF~K&+mMf@x-g$Mp3c5yh_@3y>wb$U+@36ul<`&nFEh1&$Z^4qutJi>c29) zj_)5otJ+@`=PXUn>v)#FbvDGdJS(-{CvDqpKbCxYG^^h0-(ynW<(~DvF3I@49hXnf z{c)YMG=IgZBB^*~>VI`+m!iv}tz6Qcr^>f2`>}WwS?ylOWto(ZlaZ#hwysfr{AZB* z^ynr2idFkJog7!5qu0u(Y`wK{T3SMF+)nwLlm2~*Qui^@&ma9WOm1>iDGPvbb3=W!b8g_OJFnR`S`peP2GGTh)<#tk!t@ zT{PBdm3+>J&ktYc)AP+}o^q6r9?EC*WoYsG=|S?bbl##{?P{Gmwe0@{J)fSHT)woI zAMMCgQu)35@z*Qqxj(K`Bu{Odo*hG?ikkA}n^K<(m1|R;x3*-N?vKx(q*ZV2m-A)q zpGL^t|CZ-ytpL^c``MP}z02F0bC)P){e3Hc#oyaRR@5>`)+dHhq1;i9w!gV{`3$edUk@oM7qv=9wQAfp`Q^5b;90u9zSot{r)q7k zYr4N|zSLj8+DX10{rH;CyNLTM;^v&UNAl-+{k|vrI)X^$yKF>T`EqSbmvff=vh9D8 zGw)@7zdJA6QQu_A^0TcuXR@`%{@LYd)yjK}f0xNSir>0e%)h%>&pNMs2WPj~Ezh*f zfwyaE&&>Er@H=XMb%B_-?;=)2%a|QatC13KEBf)P%GKnUe|nLaUphwE#^I}gN|LIr z%Gz@0mu=T=w71IkeqO70)5