Browse Source

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

pull/5/head
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 MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OneWireIO", "OneWireIO.vcxproj", "{3B500971-1570-460F-81C3-22AC3B7764B9}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OneWireIO", "OneWireIO.vcxproj", "{3B500971-1570-460F-81C3-22AC3B7764B9}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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|Mixed Platforms.Build.0 = Release|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Win32.ActiveCfg = Release|Win32 {3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Win32.ActiveCfg = Release|Win32
{3B500971-1570-460F-81C3-22AC3B7764B9}.Release|Win32.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

7
OneWireIO.vcxproj

@ -13,6 +13,7 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{3B500971-1570-460F-81C3-22AC3B7764B9}</ProjectGuid> <ProjectGuid>{3B500971-1570-460F-81C3-22AC3B7764B9}</ProjectGuid>
<RootNamespace>OneWireIO</RootNamespace> <RootNamespace>OneWireIO</RootNamespace>
<ProjectName>OneWireIO_Demo</ProjectName>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -83,7 +84,7 @@ exit /B 1
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="OneWireIO.ino"> <CustomBuild Include="OneWireIO_Demo.ino">
<FileType>Document</FileType> <FileType>Document</FileType>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild> <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 <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"> <ClCompile Include="OneWireSlave.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="SerialChannel.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="LowLevel.h" /> <ClInclude Include="LowLevel.h" />
<ClInclude Include="OneWireSlave.h" /> <ClInclude Include="OneWireSlave.h" />
<ClInclude Include="SerialChannel.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

4
OneWireIO.vcxproj.filters

@ -1,15 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<ClCompile Include="SerialChannel.cpp" />
<ClCompile Include="OneWireSlave.cpp" /> <ClCompile Include="OneWireSlave.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="SerialChannel.h" />
<ClInclude Include="LowLevel.h" /> <ClInclude Include="LowLevel.h" />
<ClInclude Include="OneWireSlave.h" /> <ClInclude Include="OneWireSlave.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="OneWireIO.ino" /> <CustomBuild Include="OneWireIO_Demo.ino" />
</ItemGroup> </ItemGroup>
</Project> </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" #include "OneWireSlave.h"
//#define DEBUG_LOG // uncomment this line to enable sending messages along with errors (but takes more program memory)
#define ERROR_MESSAGES //#define ERROR_MESSAGES
#ifdef DEBUG_LOG
#include "SerialChannel.h"
extern SerialChannel debug;
Pin dbgOutput(3);
#else
#undef ERROR_MESSAGES
#endif
#ifdef ERROR_MESSAGES #ifdef ERROR_MESSAGES
#define ERROR(msg) error_(msg) #define ERROR(msg) error_(msg)
@ -77,13 +69,9 @@ void OneWireSlave::begin(byte* rom, byte pinNumber)
lastReset_ = 0; lastReset_ = 0;
memcpy(rom_, rom, 7); memcpy(rom_, rom, 7);
rom_[7] = crc8_(rom_, 7); rom_[7] = crc8(rom_, 7);
#ifdef DEBUG_LOG // log("Enabling 1-wire library")
debug.append("Enabling 1-wire library");
dbgOutput.outputMode();
dbgOutput.writeHigh();
#endif
cli(); // disable interrupts cli(); // disable interrupts
pin_.inputMode(); pin_.inputMode();
@ -120,7 +108,7 @@ void OneWireSlave::write(byte* bytes, short numBytes, void(*complete)(bool error
sei(); sei();
} }
byte OneWireSlave::crc8_(byte* data, short numBytes) byte OneWireSlave::crc8(byte* data, short numBytes)
{ {
byte crc = 0; byte crc = 0;
@ -182,17 +170,11 @@ void OneWireSlave::pullLow_()
{ {
pin_.outputMode(); pin_.outputMode();
pin_.writeLow(); pin_.writeLow();
#ifdef DEBUG_LOG
//dbgOutput.writeLow();
#endif
} }
void OneWireSlave::releaseBus_() void OneWireSlave::releaseBus_()
{ {
pin_.inputMode(); pin_.inputMode();
#ifdef DEBUG_LOG
//dbgOutput.writeHigh();
#endif
} }
void OneWireSlave::beginResetDetection_() void OneWireSlave::beginResetDetection_()
@ -213,9 +195,7 @@ void OneWireSlave::resetCheck_()
if (!pin_.read()) if (!pin_.read())
{ {
pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE); pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE);
#ifdef DEBUG_LOG // log("Reset detected during another operation");
debug.SC_APPEND_STR("Reset detected during another operation");
#endif
} }
onLeaveInterrupt_(); onLeaveInterrupt_();
} }
@ -344,22 +324,13 @@ void OneWireSlave::waitReset_()
void OneWireSlave::beginPresence_() void OneWireSlave::beginPresence_()
{ {
unsigned long now = micros();
pullLow_(); pullLow_();
setTimerEvent_(PresenceDuration, &OneWireSlave::endPresence_); 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_() void OneWireSlave::endPresence_()
{ {
unsigned long now = micros();
releaseBus_(); releaseBus_();
#ifdef DEBUG_LOG
debug.SC_APPEND_STR_TIME("endPresence", now);
#endif
beginWaitCommand_(); beginWaitCommand_();
} }
@ -392,9 +363,8 @@ void OneWireSlave::onBitReceived_(bool bit, bool error)
if (bufferBitPos_ == 8) if (bufferBitPos_ == 8)
{ {
#ifdef DEBUG_LOG // log("received byte", (long)receivingByte_);
debug.SC_APPEND_STR_INT("received byte", (long)receivingByte_);
#endif
if (bufferPos_ == ReceiveCommand) if (bufferPos_ == ReceiveCommand)
{ {
bufferPos_ = 0; bufferPos_ = 0;
@ -495,9 +465,8 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error)
if (searchRomBytePos_ == 8) if (searchRomBytePos_ == 8)
{ {
#ifdef DEBUG_LOG // log("ROM sent entirely");
debug.SC_APPEND_STR("ROM sent entirely");
#endif
beginWaitReset_(); beginWaitReset_();
} }
else else
@ -507,9 +476,7 @@ void OneWireSlave::searchRomOnBitReceived_(bool bit, bool error)
} }
else else
{ {
#ifdef DEBUG_LOG // log("Leaving ROM search");
debug.SC_APPEND_STR("Leaving ROM search");
#endif
beginWaitReset_(); beginWaitReset_();
} }
} }
@ -578,16 +545,14 @@ void OneWireSlave::matchRomBytesReceived_(bool error)
if (memcmp(rom_, scratchpad_, 8) == 0) if (memcmp(rom_, scratchpad_, 8) == 0)
{ {
#ifdef DEBUG_LOG // log("ROM matched");
debug.SC_APPEND_STR("ROM matched");
#endif
beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_); beginReceiveBytes_(scratchpad_, 1, &OneWireSlave::notifyClientByteReceived_);
} }
else else
{ {
#ifdef DEBUG_LOG // log("ROM not matched");
debug.SC_APPEND_STR("ROM not matched");
#endif
beginWaitReset_(); 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. //! 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)); 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 setTimerEvent_(short delayMicroSeconds, void(*handler)());
static void disableTimer_(); 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 = new SortedSet<Sequence>(new Sequence.Comparer());
public IEnumerable<Line> 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<Line> 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));
}
}
}
}

21
SerialMonitor/SerialMonitor/MathEx.cs

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

55
SerialMonitor/SerialMonitor/Properties/AssemblyInfo.cs

@ -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
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> 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")]

71
SerialMonitor/SerialMonitor/Properties/Resources.Designer.cs generated

@ -1,71 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SerialMonitor.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

117
SerialMonitor/SerialMonitor/Properties/Resources.resx

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

30
SerialMonitor/SerialMonitor/Properties/Settings.Designer.cs generated

@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
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;
}
}
}
}

7
SerialMonitor/SerialMonitor/Properties/Settings.settings

@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

26
SerialMonitor/SerialMonitor/SerialMessage.cs

@ -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; }
/// <summary>
/// Time at which the message was sent, in microseconds since the start of the remote executable
/// </summary>
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); }
}
}
}

108
SerialMonitor/SerialMonitor/SerialMonitor.csproj

@ -1,108 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SerialMonitor</RootNamespace>
<AssemblyName>SerialMonitor</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="MainWindowContext.cs" />
<Compile Include="MathEx.cs" />
<Compile Include="SerialMessage.cs" />
<Compile Include="SerialPortExtensions.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

44
SerialMonitor/SerialMonitor/SerialPortExtensions.cs

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

BIN
traces/search-without-arduino.bewf

Binary file not shown.
Loading…
Cancel
Save