Browse Source

cleaned up project for public distribution (removed debug and unrelated stuff)

timer1
Youen Toupin 9 years ago
parent
commit
14711750d6
  1. 434
      OneWireIO-tmp.hpp
  2. 117
      OneWireIO.ino
  3. 15
      OneWireIO.sln
  4. 7
      OneWireIO.vcxproj
  5. 4
      OneWireIO.vcxproj.filters
  6. 75
      OneWireIO_Demo.ino
  7. 65
      OneWireSlave.cpp
  8. 4
      OneWireSlave.h
  9. 170
      SerialChannel.cpp
  10. 64
      SerialChannel.h
  11. 22
      SerialMonitor/SerialMonitor.sln
  12. 6
      SerialMonitor/SerialMonitor/App.config
  13. 18
      SerialMonitor/SerialMonitor/App.xaml
  14. 94
      SerialMonitor/SerialMonitor/App.xaml.cs
  15. 18
      SerialMonitor/SerialMonitor/MainWindow.xaml
  16. 62
      SerialMonitor/SerialMonitor/MainWindow.xaml.cs
  17. 222
      SerialMonitor/SerialMonitor/MainWindowContext.cs
  18. 21
      SerialMonitor/SerialMonitor/MathEx.cs
  19. 55
      SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs
  20. 71
      SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs
  21. 117
      SerialMonitor/SerialMonitor/Properties/Resources.resx
  22. 30
      SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs
  23. 7
      SerialMonitor/SerialMonitor/Properties/Settings.settings
  24. 26
      SerialMonitor/SerialMonitor/SerialMessage.cs
  25. 108
      SerialMonitor/SerialMonitor/SerialMonitor.csproj
  26. 44
      SerialMonitor/SerialMonitor/SerialPortExtensions.cs
  27. BIN
      traces/search-without-arduino.bewf

434
OneWireIO-tmp.hpp

@ -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;
}

117
OneWireIO.ino

@ -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:
;
}
}

15
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

7
OneWireIO.vcxproj

@ -13,6 +13,7 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{3B500971-1570-460F-81C3-22AC3B7764B9}</ProjectGuid>
<RootNamespace>OneWireIO</RootNamespace>
<ProjectName>OneWireIO_Demo</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -83,7 +84,7 @@ exit /B 1
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<CustomBuild Include="OneWireIO.ino">
<CustomBuild Include="OneWireIO_Demo.ino">
<FileType>Document</FileType>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf del $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf
@ -99,14 +100,10 @@ D:\Outils\Arduino\arduino.exe --pref build.path=$(ProjectDir)$(IntDir) --upload
<ClCompile Include="OneWireSlave.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="SerialChannel.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="LowLevel.h" />
<ClInclude Include="OneWireSlave.h" />
<ClInclude Include="SerialChannel.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

4
OneWireIO.vcxproj.filters

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

75
OneWireIO_Demo.ino

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

65
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_();
}
}

4
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_();

170
SerialChannel.cpp

@ -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

64
SerialChannel.h

@ -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

22
SerialMonitor/SerialMonitor.sln

@ -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

6
SerialMonitor/SerialMonitor/App.config

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

18
SerialMonitor/SerialMonitor/App.xaml

@ -1,18 +0,0 @@
<Application x:Class="SerialMonitor.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="Console" TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="TextTrimming" Value="None"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="Black"/>
</Style>
<Style x:Key="Oscilloscope" TargetType="{x:Type Canvas}">
<Setter Property="Background" Value="White"/>
</Style>
</Application.Resources>
</Application>

94
SerialMonitor/SerialMonitor/App.xaml.cs

@ -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
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private SerialPort Serial;
private IDictionary<int, string> Channels = new Dictionary<int, string>();
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 <channel id> ; short <length> ; byte[length] <channel name>
// regular message: byte <channel id> ; short <length> ; byte[length] <data>
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;
}
}
}
}

18
SerialMonitor/SerialMonitor/MainWindow.xaml

@ -1,18 +0,0 @@
<Window x:Class="SerialMonitor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Serial Monitor" Height="490.75" Width="923">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="290" />
<RowDefinition Height="5" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Canvas Name="Oscilloscope" Style="{DynamicResource Oscilloscope}" Margin="0,0,0,17" />
<ScrollBar Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Stretch" Height="17" VerticalAlignment="Bottom" Minimum="{Binding MinTime}" Maximum="{Binding MaxTime}" ViewportSize="{Binding ViewportTimeWidth}" Value="{Binding ScrollValue}"/>
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" />
<ScrollViewer Grid.Row="2">
<TextBlock TextWrapping="Wrap" Style="{DynamicResource Console}" Text="{Binding ConsoleText}"/>
</ScrollViewer>
</Grid>
</Window>

62
SerialMonitor/SerialMonitor/MainWindow.xaml.cs

@ -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
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
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);
}
}
}

222
SerialMonitor/SerialMonitor/MainWindowContext.cs

@ -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<string> Lines = new List<string>();
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<Sequence>
{
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<Sequence> Sequences<