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"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
||||
<ClCompile Include="SerialChannel.cpp" /> |
||||
<ClCompile Include="OneWireSlave.cpp" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<ClInclude Include="SerialChannel.h" /> |
||||
<ClInclude Include="LowLevel.h" /> |
||||
<ClInclude Include="OneWireSlave.h" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<CustomBuild Include="OneWireIO.ino" /> |
||||
<CustomBuild Include="OneWireIO_Demo.ino" /> |
||||
</ItemGroup> |
||||
</Project> |
@ -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