forked from youen/OneWireArduinoSlave
Youen Toupin
9 years ago
27 changed files with 95 additions and 1781 deletions
@ -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; |
|
||||||
} |
|
@ -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: |
|
||||||
; |
|
||||||
} |
|
||||||
} |
|
@ -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> |
@ -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
|
||||||
|
} |
||||||
|
} |
@ -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
|
|
@ -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 |
|
||||||
|
|
@ -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 |
|
@ -1,6 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="utf-8" ?> |
|
||||||
<configuration> |
|
||||||
<startup> |
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> |
|
||||||
</startup> |
|
||||||
</configuration> |
|
@ -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> |
|
@ -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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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> |
|
@ -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); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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")] |
|
@ -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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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> |
|
@ -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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,7 +0,0 @@ |
|||||||
<?xml version='1.0' encoding='utf-8'?> |
|
||||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> |
|
||||||
<Profiles> |
|
||||||
<Profile Name="(Default)" /> |
|
||||||
</Profiles> |
|
||||||
<Settings /> |
|
||||||
</SettingsFile> |
|
@ -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); } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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> |
|
@ -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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Binary file not shown.
Loading…
Reference in new issue