mirror of
https://github.com/JasonYANG170/logicanalyzer.git
synced 2024-11-27 05:56:30 +00:00
Updates for V5.0
This commit is contained in:
parent
7f96804d3e
commit
3a5e9bfee2
|
@ -10,6 +10,7 @@
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
#include "LogicAnalyzer.pio.h"
|
#include "LogicAnalyzer.pio.h"
|
||||||
#include "LogicAnalyzer_Structs.h"
|
#include "LogicAnalyzer_Structs.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
#ifdef WS2812_LED
|
#ifdef WS2812_LED
|
||||||
#include "LogicAnalyzer_W2812.h"
|
#include "LogicAnalyzer_W2812.h"
|
||||||
|
@ -85,6 +86,8 @@ CAPTURE_REQUEST* req;
|
||||||
|
|
||||||
#ifdef USE_CYGW_WIFI
|
#ifdef USE_CYGW_WIFI
|
||||||
|
|
||||||
|
/// @brief Stores a new WiFi configuration in the flash of the device
|
||||||
|
/// @param settings Settings to store
|
||||||
void storeSettings(WIFI_SETTINGS* settings)
|
void storeSettings(WIFI_SETTINGS* settings)
|
||||||
{
|
{
|
||||||
uint8_t buffer[FLASH_PAGE_SIZE];
|
uint8_t buffer[FLASH_PAGE_SIZE];
|
||||||
|
@ -129,6 +132,10 @@ void storeSettings(WIFI_SETTINGS* settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// @brief Sends a response message to the host application in string mode
|
||||||
|
/// @param response The message to be sent (null terminated)
|
||||||
|
/// @param toWiFi If true the message is sent to a WiFi endpoint, else to the USB connection through STDIO
|
||||||
void sendResponse(const char* response, bool toWiFi)
|
void sendResponse(const char* response, bool toWiFi)
|
||||||
{
|
{
|
||||||
#ifdef USE_CYGW_WIFI
|
#ifdef USE_CYGW_WIFI
|
||||||
|
@ -146,6 +153,10 @@ void sendResponse(const char* response, bool toWiFi)
|
||||||
printf(response);
|
printf(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Processes data received from the host application
|
||||||
|
/// @param data The received data
|
||||||
|
/// @param length Length of the data
|
||||||
|
/// @param fromWiFi If true the message comes from a WiFi connection
|
||||||
void processData(uint8_t* data, uint length, bool fromWiFi)
|
void processData(uint8_t* data, uint length, bool fromWiFi)
|
||||||
{
|
{
|
||||||
for(uint pos = 0; pos < length; pos++)
|
for(uint pos = 0; pos < length; pos++)
|
||||||
|
@ -208,7 +219,7 @@ void processData(uint8_t* data, uint length, bool fromWiFi)
|
||||||
else if(req->triggerType == 2) //start fast trigger capture
|
else if(req->triggerType == 2) //start fast trigger capture
|
||||||
started = startCaptureFast(req->frequency, req->preSamples, req->postSamples, (uint8_t*)&req->channels, req->channelCount, req->trigger, req->count, req->triggerValue, req->captureMode);
|
started = startCaptureFast(req->frequency, req->preSamples, req->postSamples, (uint8_t*)&req->channels, req->channelCount, req->trigger, req->count, req->triggerValue, req->captureMode);
|
||||||
else //Start simple trigger capture
|
else //Start simple trigger capture
|
||||||
started = startCaptureSimple(req->frequency, req->preSamples, req->postSamples, (uint8_t*)&req->channels, req->channelCount, req->trigger, req->inverted, req->captureMode);
|
started = startCaptureSimple(req->frequency, req->preSamples, req->postSamples, req->loopCount, (uint8_t*)&req->channels, req->channelCount, req->trigger, req->inverted, req->captureMode);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -301,6 +312,44 @@ void processData(uint8_t* data, uint length, bool fromWiFi)
|
||||||
//have any data, but the capture request has a CAPTURE_REQUEST struct as data.
|
//have any data, but the capture request has a CAPTURE_REQUEST struct as data.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Transfer a buffer of data through USB using the TinyUSB CDC functions
|
||||||
|
/// @param data Buffer of data to transfer
|
||||||
|
/// @param len Length of the buffer
|
||||||
|
void cdc_transfer(unsigned char* data, int len)
|
||||||
|
{
|
||||||
|
|
||||||
|
int left = len;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while(left > 0)
|
||||||
|
{
|
||||||
|
int avail = (int) tud_cdc_write_available();
|
||||||
|
|
||||||
|
if(avail > left)
|
||||||
|
avail = left;
|
||||||
|
|
||||||
|
if(avail)
|
||||||
|
{
|
||||||
|
int transferred = (int) tud_cdc_write(data + pos, avail);
|
||||||
|
tud_task();
|
||||||
|
tud_cdc_write_flush();
|
||||||
|
|
||||||
|
pos += transferred;
|
||||||
|
left -= transferred;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tud_task();
|
||||||
|
tud_cdc_write_flush();
|
||||||
|
if (!tud_cdc_connected())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Receive and process USB data from the host application
|
||||||
|
/// @param skipProcessing If true the received data is not processed (used for cleanup)
|
||||||
|
/// @return True if anything is received, false if not
|
||||||
bool processUSBInput(bool skipProcessing)
|
bool processUSBInput(bool skipProcessing)
|
||||||
{
|
{
|
||||||
//Try to get char
|
//Try to get char
|
||||||
|
@ -321,11 +370,14 @@ bool processUSBInput(bool skipProcessing)
|
||||||
|
|
||||||
#ifdef USE_CYGW_WIFI
|
#ifdef USE_CYGW_WIFI
|
||||||
|
|
||||||
|
/// @brief Purges any pending data in the USB input
|
||||||
void purgeUSBData()
|
void purgeUSBData()
|
||||||
{
|
{
|
||||||
while(getchar_timeout_us(0) != PICO_ERROR_TIMEOUT);
|
while(getchar_timeout_us(0) != PICO_ERROR_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Callback for the WiFi event queue
|
||||||
|
/// @param event Received event
|
||||||
void wifiEvent(void* event)
|
void wifiEvent(void* event)
|
||||||
{
|
{
|
||||||
EVENT_FROM_WIFI* wEvent = (EVENT_FROM_WIFI*)event;
|
EVENT_FROM_WIFI* wEvent = (EVENT_FROM_WIFI*)event;
|
||||||
|
@ -353,6 +405,9 @@ void wifiEvent(void* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Receives and processes input from the host application (when connected through WiFi)
|
||||||
|
/// @param skipProcessing /// @param skipProcessing If true the received data is not processed (used for cleanup)
|
||||||
|
/// @return True if anything is received, false if not
|
||||||
bool processWiFiInput(bool skipProcessing)
|
bool processWiFiInput(bool skipProcessing)
|
||||||
{
|
{
|
||||||
bool res = event_has_events(&wifiToFrontend);
|
bool res = event_has_events(&wifiToFrontend);
|
||||||
|
@ -372,6 +427,7 @@ bool processWiFiInput(bool skipProcessing)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// @brief Process input data from the host application if it is available
|
||||||
void processInput()
|
void processInput()
|
||||||
{
|
{
|
||||||
#ifdef USE_CYGW_WIFI
|
#ifdef USE_CYGW_WIFI
|
||||||
|
@ -384,6 +440,8 @@ void processInput()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Processes input data from the host application to check if there is any cancel capture request
|
||||||
|
/// @return True if there was input data
|
||||||
bool processCancel()
|
bool processCancel()
|
||||||
{
|
{
|
||||||
#ifdef USE_CYGW_WIFI
|
#ifdef USE_CYGW_WIFI
|
||||||
|
@ -397,6 +455,8 @@ bool processCancel()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Main app loop
|
||||||
|
/// @return Exit code
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
//Overclock Powerrrr!
|
//Overclock Powerrrr!
|
||||||
|
@ -454,18 +514,10 @@ int main()
|
||||||
event_push(&frontendToWifi, &evt);
|
event_push(&frontendToWifi, &evt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
cdc_transfer(lengthPointer, 4);
|
||||||
putchar_raw(lengthPointer[0]);
|
|
||||||
putchar_raw(lengthPointer[1]);
|
|
||||||
putchar_raw(lengthPointer[2]);
|
|
||||||
putchar_raw(lengthPointer[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
putchar_raw(lengthPointer[0]);
|
cdc_transfer(lengthPointer, 4);
|
||||||
putchar_raw(lengthPointer[1]);
|
|
||||||
putchar_raw(lengthPointer[2]);
|
|
||||||
putchar_raw(lengthPointer[3]);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sleep_ms(100);
|
sleep_ms(100);
|
||||||
|
@ -513,23 +565,24 @@ int main()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(int buc = 0; buc < length; buc++)
|
if(first + length > CAPTURE_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
putchar_raw(buffer[first++]);
|
cdc_transfer(buffer + first, CAPTURE_BUFFER_SIZE - first);
|
||||||
|
cdc_transfer(buffer, (first + length) - CAPTURE_BUFFER_SIZE);
|
||||||
if(first >= 131072)
|
|
||||||
first = 0;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
cdc_transfer(buffer + first, length);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
//Send the samples
|
|
||||||
for(int buc = 0; buc < length; buc++)
|
|
||||||
{
|
|
||||||
putchar_raw(buffer[first++]);
|
|
||||||
|
|
||||||
if(first >= 131072)
|
if(first + length > CAPTURE_BUFFER_SIZE)
|
||||||
first = 0;
|
{
|
||||||
|
cdc_transfer(buffer + first, CAPTURE_BUFFER_SIZE - first);
|
||||||
|
cdc_transfer(buffer, (first + length) - CAPTURE_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
cdc_transfer(buffer + first, length);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
//Done!
|
//Done!
|
||||||
capturing = false;
|
capturing = false;
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
.program POSITIVE_CAPTURE
|
.program POSITIVE_CAPTURE
|
||||||
|
|
||||||
pull
|
pull
|
||||||
out x 32 ;read capture length
|
out y 32 ;read loop count
|
||||||
|
pull
|
||||||
|
mov x, osr ;read capture length (use MOV instead of PULL so we can MOV it again on each loop)
|
||||||
|
|
||||||
.wrap_target
|
.wrap_target
|
||||||
|
|
||||||
|
@ -16,19 +18,28 @@ POST_CAPTURE:
|
||||||
in pins 32 ;read sample
|
in pins 32 ;read sample
|
||||||
jmp x-- POST_CAPTURE ;loop if more samples needed
|
jmp x-- POST_CAPTURE ;loop if more samples needed
|
||||||
|
|
||||||
|
jmp y-- LOOP ;jump to loop control
|
||||||
|
|
||||||
irq 0 ;notify to the main program that we have finished capturing
|
irq 0 ;notify to the main program that we have finished capturing
|
||||||
|
|
||||||
LOCK:
|
LOCK:
|
||||||
|
|
||||||
jmp LOCK ;block the program
|
jmp LOCK ;block the program
|
||||||
|
|
||||||
|
LOOP:
|
||||||
|
mov x, osr ;read loop count
|
||||||
|
INNER_LOOP:
|
||||||
|
|
||||||
|
jmp pin POST_CAPTURE ;wait for trigger
|
||||||
|
jmp INNER_LOOP
|
||||||
|
|
||||||
;--------------------------------------------------------------------------------------------
|
;--------------------------------------------------------------------------------------------
|
||||||
.program NEGATIVE_CAPTURE
|
.program NEGATIVE_CAPTURE
|
||||||
|
|
||||||
.wrap_target
|
|
||||||
|
|
||||||
pull
|
pull
|
||||||
out x 32 ;read capture length
|
out y 32 ;read loop count
|
||||||
|
pull
|
||||||
|
mov x, osr ;read capture length (use MOV instead of PULL so we can MOV it again on each loop)
|
||||||
|
|
||||||
PRE_CAPTURE:
|
PRE_CAPTURE:
|
||||||
|
|
||||||
|
@ -37,15 +48,24 @@ PRE_CAPTURE:
|
||||||
|
|
||||||
POST_CAPTURE:
|
POST_CAPTURE:
|
||||||
|
|
||||||
|
.wrap_target
|
||||||
|
|
||||||
in pins 32 ;read sample
|
in pins 32 ;read sample
|
||||||
jmp x-- POST_CAPTURE ;loop if more samples needed
|
jmp x-- POST_CAPTURE ;loop if more samples needed
|
||||||
|
|
||||||
|
jmp y-- LOOP ;jump to loop control
|
||||||
|
|
||||||
irq 0 ;notify to the main program that we have finished capturing
|
irq 0 ;notify to the main program that we have finished capturing
|
||||||
|
|
||||||
LOCK:
|
LOCK:
|
||||||
|
|
||||||
jmp LOCK ;block the program
|
jmp LOCK ;block the program
|
||||||
|
|
||||||
|
LOOP:
|
||||||
|
mov x, osr ;read loop count
|
||||||
|
INNER_LOOP:
|
||||||
|
jmp pin INNER_LOOP ;wait for trigger
|
||||||
|
|
||||||
.wrap
|
.wrap
|
||||||
|
|
||||||
;--------------------------------------------------------------------------------------------
|
;--------------------------------------------------------------------------------------------
|
||||||
|
@ -131,6 +151,8 @@ LOCK:
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "hardware/sync.h"
|
#include "hardware/sync.h"
|
||||||
|
|
||||||
|
#define CAPTURE_BUFFER_SIZE (128 * 1024)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
MODE_8_CHANNEL,
|
MODE_8_CHANNEL,
|
||||||
|
@ -161,6 +183,7 @@ static uint8_t lastCapturePinCount; //Count of captured pins
|
||||||
static uint32_t lastTriggerCapture; //Moment where the trigger happened inside the circular pre buffer
|
static uint32_t lastTriggerCapture; //Moment where the trigger happened inside the circular pre buffer
|
||||||
static uint32_t lastPreSize; //Pre-trigger buffer size
|
static uint32_t lastPreSize; //Pre-trigger buffer size
|
||||||
static uint32_t lastPostSize; //Post-trigger buffer size
|
static uint32_t lastPostSize; //Post-trigger buffer size
|
||||||
|
static uint32_t lastLoopCount; //Number of loops
|
||||||
static bool lastTriggerInverted; //Inverted?
|
static bool lastTriggerInverted; //Inverted?
|
||||||
static uint8_t lastTriggerPin;
|
static uint8_t lastTriggerPin;
|
||||||
static uint32_t lastStartPosition;
|
static uint32_t lastStartPosition;
|
||||||
|
@ -187,7 +210,7 @@ static bool captureProcessed;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Main capture buffer, aligned at a 32k boundary, to use the maxixmum ring size supported by DMA channels
|
//Main capture buffer, aligned at a 32k boundary, to use the maxixmum ring size supported by DMA channels
|
||||||
static uint8_t captureBuffer[128 * 1024] __attribute__((aligned(32768)));
|
static uint8_t captureBuffer[CAPTURE_BUFFER_SIZE] __attribute__((aligned(32768)));
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//--------------Complex trigger PIO program------------------------------------
|
//--------------Complex trigger PIO program------------------------------------
|
||||||
|
@ -330,8 +353,8 @@ uint32_t find_capture_tail()
|
||||||
if(busy_channel == 0xFFFFFFFF)
|
if(busy_channel == 0xFFFFFFFF)
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
|
|
||||||
//Ok, now we need to know at which transfer the DMA is. The value equals to MAX_TRANSFERS - TRANSFERS_LEFT.
|
//Ok, now we need to know at which transfer the DMA is. The value equals to MAX_TRANSFERS - TRANSFERS_LEFT - 1 (DMA channel decrements transfer_count when it starts :/).
|
||||||
int32_t transfer = transferCount - dma_channel_hw_addr(busy_channel)->transfer_count;
|
int32_t transfer = transferCount - dma_channel_hw_addr(busy_channel)->transfer_count - 1;
|
||||||
|
|
||||||
//Now compute the last capture position
|
//Now compute the last capture position
|
||||||
transfer = (transfer + busy_offset) - 1;
|
transfer = (transfer + busy_offset) - 1;
|
||||||
|
@ -636,6 +659,7 @@ bool startCaptureFast(uint32_t freq, uint32_t preLength, uint32_t postLength, co
|
||||||
//Store info about the capture
|
//Store info about the capture
|
||||||
lastPreSize = preLength;
|
lastPreSize = preLength;
|
||||||
lastPostSize = postLength;
|
lastPostSize = postLength;
|
||||||
|
lastLoopCount = 0;
|
||||||
lastCapturePinCount = capturePinCount;
|
lastCapturePinCount = capturePinCount;
|
||||||
lastCaptureComplexFast = true;
|
lastCaptureComplexFast = true;
|
||||||
lastCaptureMode = captureMode;
|
lastCaptureMode = captureMode;
|
||||||
|
@ -653,8 +677,8 @@ bool startCaptureFast(uint32_t freq, uint32_t preLength, uint32_t postLength, co
|
||||||
|
|
||||||
//Store the PIO units and clear program memory
|
//Store the PIO units and clear program memory
|
||||||
capturePIO = pio1; //Cannot clear it in PIO1 because the W uses PIO1 to transfer data
|
capturePIO = pio1; //Cannot clear it in PIO1 because the W uses PIO1 to transfer data
|
||||||
|
|
||||||
triggerPIO = pio0;
|
triggerPIO = pio0;
|
||||||
|
|
||||||
pio_clear_instruction_memory(triggerPIO);
|
pio_clear_instruction_memory(triggerPIO);
|
||||||
|
|
||||||
//Configure 24 + 2 IO's to be used by the PIO (24 channels + 2 trigger pins)
|
//Configure 24 + 2 IO's to be used by the PIO (24 channels + 2 trigger pins)
|
||||||
|
@ -802,6 +826,7 @@ bool startCaptureComplex(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
||||||
//Store info about the capture
|
//Store info about the capture
|
||||||
lastPreSize = preLength;
|
lastPreSize = preLength;
|
||||||
lastPostSize = postLength;
|
lastPostSize = postLength;
|
||||||
|
lastLoopCount = 0;
|
||||||
lastCapturePinCount = capturePinCount;
|
lastCapturePinCount = capturePinCount;
|
||||||
lastCaptureComplexFast = true;
|
lastCaptureComplexFast = true;
|
||||||
lastCaptureMode = captureMode;
|
lastCaptureMode = captureMode;
|
||||||
|
@ -910,7 +935,7 @@ bool startCaptureComplex(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength, const uint8_t* capturePins, uint8_t capturePinCount, uint8_t triggerPin, bool invertTrigger, CHANNEL_MODE captureMode)
|
bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength, uint8_t loopCount, const uint8_t* capturePins, uint8_t capturePinCount, uint8_t triggerPin, bool invertTrigger, CHANNEL_MODE captureMode)
|
||||||
{
|
{
|
||||||
|
|
||||||
int maxSamples;
|
int maxSamples;
|
||||||
|
@ -950,6 +975,7 @@ bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
||||||
//Store info about the capture
|
//Store info about the capture
|
||||||
lastPreSize = preLength;
|
lastPreSize = preLength;
|
||||||
lastPostSize = postLength;
|
lastPostSize = postLength;
|
||||||
|
lastLoopCount = loopCount;
|
||||||
lastCapturePinCount = capturePinCount;
|
lastCapturePinCount = capturePinCount;
|
||||||
lastTriggerInverted = invertTrigger;
|
lastTriggerInverted = invertTrigger;
|
||||||
lastCaptureComplexFast = false;
|
lastCaptureComplexFast = false;
|
||||||
|
@ -1028,9 +1054,11 @@ bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
||||||
//Enable state machine
|
//Enable state machine
|
||||||
pio_sm_set_enabled(capturePIO, sm_Capture, true);
|
pio_sm_set_enabled(capturePIO, sm_Capture, true);
|
||||||
|
|
||||||
//Write capture length to post program to start the capture process
|
//Write loop count and capture length to post program to start the capture process
|
||||||
|
pio_sm_put_blocking(capturePIO, sm_Capture, loopCount);
|
||||||
pio_sm_put_blocking(capturePIO, sm_Capture, postLength - 1);
|
pio_sm_put_blocking(capturePIO, sm_Capture, postLength - 1);
|
||||||
|
|
||||||
|
|
||||||
//Finally clear capture status, process flags and capture type
|
//Finally clear capture status, process flags and capture type
|
||||||
captureFinished = false;
|
captureFinished = false;
|
||||||
captureProcessed = false;
|
captureProcessed = false;
|
||||||
|
@ -1048,6 +1076,9 @@ bool IsCapturing()
|
||||||
|
|
||||||
uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* captureMode)
|
uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* captureMode)
|
||||||
{
|
{
|
||||||
|
//Compute total sample count
|
||||||
|
uint32_t totalSamples = lastPreSize + (lastPostSize * (lastLoopCount + 1));
|
||||||
|
|
||||||
//If we don't have processed the buffer...
|
//If we don't have processed the buffer...
|
||||||
if(!captureProcessed)
|
if(!captureProcessed)
|
||||||
{
|
{
|
||||||
|
@ -1066,11 +1097,13 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//Calculate start position
|
//Calculate start position
|
||||||
if(lastTail < lastPreSize + lastPostSize - 1)
|
if(lastTail < totalSamples - 1)
|
||||||
lastStartPosition = maxSize - ((lastPreSize + lastPostSize) - (lastTail - 1));
|
lastStartPosition = (maxSize - totalSamples) + lastTail + 1;
|
||||||
else
|
else
|
||||||
lastStartPosition = lastTail - (lastPreSize + lastPostSize) + 1;
|
lastStartPosition = lastTail - totalSamples + 1;
|
||||||
|
|
||||||
uint32_t currentPos = lastStartPosition;
|
uint32_t currentPos = lastStartPosition;
|
||||||
|
|
||||||
switch(lastCaptureMode)
|
switch(lastCaptureMode)
|
||||||
{
|
{
|
||||||
case MODE_24_CHANNEL:
|
case MODE_24_CHANNEL:
|
||||||
|
@ -1082,7 +1115,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
||||||
|
|
||||||
//Sort channels
|
//Sort channels
|
||||||
//(reorder captured bits based on the channels requested)
|
//(reorder captured bits based on the channels requested)
|
||||||
for(int buc = 0; buc < lastPreSize + lastPostSize; buc++)
|
for(int buc = 0; buc < totalSamples; buc++)
|
||||||
{
|
{
|
||||||
oldValue = buffer[currentPos]; //Store current value
|
oldValue = buffer[currentPos]; //Store current value
|
||||||
newValue = 0; //New value
|
newValue = 0; //New value
|
||||||
|
@ -1110,7 +1143,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
||||||
|
|
||||||
//Sort channels
|
//Sort channels
|
||||||
//(reorder captured bits based on the channels requested)
|
//(reorder captured bits based on the channels requested)
|
||||||
for(int buc = 0; buc < lastPreSize + lastPostSize; buc++)
|
for(int buc = 0; buc < totalSamples; buc++)
|
||||||
{
|
{
|
||||||
oldValue = buffer[currentPos]; //Store current value
|
oldValue = buffer[currentPos]; //Store current value
|
||||||
newValue = 0; //New value
|
newValue = 0; //New value
|
||||||
|
@ -1138,7 +1171,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
||||||
|
|
||||||
//Sort channels
|
//Sort channels
|
||||||
//(reorder captured bits based on the channels requested)
|
//(reorder captured bits based on the channels requested)
|
||||||
for(int buc = 0; buc < lastPreSize + lastPostSize; buc++)
|
for(int buc = 0; buc < totalSamples; buc++)
|
||||||
{
|
{
|
||||||
oldValue = buffer[currentPos]; //Store current value
|
oldValue = buffer[currentPos]; //Store current value
|
||||||
newValue = 0; //New value
|
newValue = 0; //New value
|
||||||
|
@ -1162,7 +1195,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
||||||
}
|
}
|
||||||
//Return data
|
//Return data
|
||||||
*captureMode = lastCaptureMode;
|
*captureMode = lastCaptureMode;
|
||||||
*bufferSize = lastPreSize + lastPostSize;
|
*bufferSize = totalSamples;
|
||||||
*firstSample = lastStartPosition;
|
*firstSample = lastStartPosition;
|
||||||
return captureBuffer;
|
return captureBuffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __BUILD_SETTINGS__
|
#ifndef __BUILD_SETTINGS__
|
||||||
#define __BUILD_SETTINGS__
|
#define __BUILD_SETTINGS__
|
||||||
|
|
||||||
#define FIRMWARE_VERSION "4_5"
|
#define FIRMWARE_VERSION "V5_0"
|
||||||
|
|
||||||
//Select the board type to build the firmware for
|
//Select the board type to build the firmware for
|
||||||
#define BUILD_PICO
|
#define BUILD_PICO
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
uint32_t preSamples;
|
uint32_t preSamples;
|
||||||
//Number of samples stored after the trigger
|
//Number of samples stored after the trigger
|
||||||
uint32_t postSamples;
|
uint32_t postSamples;
|
||||||
|
//Number of capture loops
|
||||||
|
uint8_t loopCount;
|
||||||
//Capture mode (0 = 8 channel, 1 = 16 channel, 2 = 24 channel)
|
//Capture mode (0 = 8 channel, 1 = 16 channel, 2 = 24 channel)
|
||||||
uint8_t captureMode;
|
uint8_t captureMode;
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
Binary file not shown.
|
@ -6,7 +6,7 @@
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ApplicationIcon>window.ico</ApplicationIcon>
|
<ApplicationIcon>window.ico</ApplicationIcon>
|
||||||
<Version>4.5.1.0</Version>
|
<Version>5.0.0.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -14,17 +14,25 @@ namespace CLCapture
|
||||||
{
|
{
|
||||||
[Value(0, Required = true, HelpText = "Device's serial port or IP address and port.")]
|
[Value(0, Required = true, HelpText = "Device's serial port or IP address and port.")]
|
||||||
public string? AddressPort { get; set; }
|
public string? AddressPort { get; set; }
|
||||||
|
|
||||||
[Value(1, Required = true, HelpText = "Desired sampling frequency.")]
|
[Value(1, Required = true, HelpText = "Desired sampling frequency.")]
|
||||||
public int SamplingFrequency { get; set; }
|
public int SamplingFrequency { get; set; }
|
||||||
|
|
||||||
[Value(2, Required = true, HelpText = "List of channels to capture (channels sepparated by comma, can contain a name adding a semicolon after the channel number, no spaces allowed).")]
|
[Value(2, Required = true, HelpText = "List of channels to capture (channels sepparated by comma, can contain a name adding a semicolon after the channel number, no spaces allowed).")]
|
||||||
public string? Channels { get; set; }
|
public string? Channels { get; set; }
|
||||||
|
|
||||||
[Value(3, Required = true, HelpText = "Number of samples to capture before the trigger.")]
|
[Value(3, Required = true, HelpText = "Number of samples to capture before the trigger.")]
|
||||||
public int PreSamples { get; set; }
|
public int PreSamples { get; set; }
|
||||||
|
|
||||||
[Value(4, Required = true, HelpText = "Number of samples to capture after the trigger.")]
|
[Value(4, Required = true, HelpText = "Number of samples to capture after the trigger.")]
|
||||||
public int PostSamples { get; set; }
|
public int PostSamples { get; set; }
|
||||||
[Value(5, Required = true, HelpText = "Trigger definition in the form of \"TriggerType:(Edge, Fast or Complex),Channel:(base trigger channel),Value:(string containing 1's and 0's indicating each trigger chanel state)\".")]
|
|
||||||
|
[Value(5, Required = true, HelpText = "Number of bursts to capture (0 or 1 to disable burst mode).")]
|
||||||
|
public int LoopCount { get; set; }
|
||||||
|
|
||||||
|
[Value(6, Required = true, HelpText = "Trigger definition in the form of \"TriggerType:(Edge, Fast or Complex),Channel:(base trigger channel),Value:(string containing 1's and 0's indicating each trigger chanel state)\".")]
|
||||||
public CLTrigger? Trigger { get; set; }
|
public CLTrigger? Trigger { get; set; }
|
||||||
[Value(6, Required = true, HelpText = "Name of the output file.")]
|
[Value(7, Required = true, HelpText = "Name of the output file.")]
|
||||||
public string? OutputFile { get; set; }
|
public string? OutputFile { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,8 +180,7 @@ async Task<int> Capture(CLCaptureOptions opts)
|
||||||
if (opts.Trigger.TriggerType == CLTriggerType.Edge)
|
if (opts.Trigger.TriggerType == CLTriggerType.Edge)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Starting edge triggered capture...");
|
Console.WriteLine("Starting edge triggered capture...");
|
||||||
var resStart = driver.StartCapture(opts.SamplingFrequency, opts.PreSamples, opts.PostSamples,
|
var resStart = driver.StartCapture(opts.SamplingFrequency, opts.PreSamples, opts.PostSamples, opts.LoopCount < 2 ? 0 : opts.LoopCount - 1, nChannels, opts.Trigger.Channel - 1, opts.Trigger.Value == "0", CaptureFinished);
|
||||||
nChannels, opts.Trigger.Channel - 1, opts.Trigger.Value == "0", CaptureFinished);
|
|
||||||
|
|
||||||
if (resStart != CaptureError.None)
|
if (resStart != CaptureError.None)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
|
@ -11,12 +11,18 @@ namespace LogicAnalyzer.Classes
|
||||||
public int Frequency { get; set; }
|
public int Frequency { get; set; }
|
||||||
public int PreTriggerSamples { get; set; }
|
public int PreTriggerSamples { get; set; }
|
||||||
public int PostTriggerSamples { get; set; }
|
public int PostTriggerSamples { get; set; }
|
||||||
|
public int LoopCount { get; set; }
|
||||||
public CaptureChannel[] CaptureChannels { get; set; } = new CaptureChannel[0];
|
public CaptureChannel[] CaptureChannels { get; set; } = new CaptureChannel[0];
|
||||||
public int TriggerType { get; set; }
|
public int TriggerType { get; set; }
|
||||||
public int TriggerChannel { get; set; }
|
public int TriggerChannel { get; set; }
|
||||||
public bool TriggerInverted { get; set; }
|
public bool TriggerInverted { get; set; }
|
||||||
public int TriggerBitCount { get; set; }
|
public int TriggerBitCount { get; set; }
|
||||||
public ushort TriggerPattern { get; set; }
|
public ushort TriggerPattern { get; set; }
|
||||||
|
|
||||||
|
public CaptureSettings Clone()
|
||||||
|
{
|
||||||
|
return (CaptureSettings)MemberwiseClone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CaptureChannel
|
public class CaptureChannel
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace LogicAnalyzer.Controls
|
||||||
|
|
||||||
newChannelLabel.Text = channels[buc].TextualChannelNumber;
|
newChannelLabel.Text = channels[buc].TextualChannelNumber;
|
||||||
|
|
||||||
newChannelLabel.Foreground = GraphicObjectsCache.GetBrush(AnalyzerColors.FgChannelColors[buc]);
|
newChannelLabel.Foreground = GraphicObjectsCache.GetBrush(AnalyzerColors.FgChannelColors[buc % 24]);
|
||||||
|
|
||||||
newChannelGrid.Children.Add(newChannelLabel);
|
newChannelGrid.Children.Add(newChannelLabel);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="LogicAnalyzer.Controls.SamplePreviewer">
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,102 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using LogicAnalyzer.Classes;
|
||||||
|
using MessageBox.Avalonia.DTO;
|
||||||
|
using SkiaSharp;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LogicAnalyzer.Controls
|
||||||
|
{
|
||||||
|
public partial class SamplePreviewer : UserControl
|
||||||
|
{
|
||||||
|
Bitmap? bmp;
|
||||||
|
int sampleCount = 0;
|
||||||
|
|
||||||
|
int viewPosition;
|
||||||
|
public int ViewPosition { get { return viewPosition; } set { viewPosition = value; InvalidateVisual(); } }
|
||||||
|
|
||||||
|
public SamplePreviewer()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSamples(UInt128[] Samples, int ChannelCount)
|
||||||
|
{
|
||||||
|
if (ChannelCount > 24)
|
||||||
|
ChannelCount = 24;
|
||||||
|
|
||||||
|
int width = Math.Max(Math.Min(Samples.Length, 4096), 1024);
|
||||||
|
|
||||||
|
float cHeight = 144 / (float)ChannelCount;
|
||||||
|
float sWidth = (float)width / (float)Samples.Length;
|
||||||
|
float high = cHeight / 6;
|
||||||
|
float low = cHeight - high;
|
||||||
|
|
||||||
|
using SKBitmap skb = new SKBitmap(width, 144);
|
||||||
|
|
||||||
|
SKPaint[] colors = new SKPaint[ChannelCount];
|
||||||
|
|
||||||
|
for (int buc = 0; buc < ChannelCount; buc++)
|
||||||
|
{
|
||||||
|
var avColor = AnalyzerColors.FgChannelColors[buc];
|
||||||
|
|
||||||
|
colors[buc] = new SKPaint
|
||||||
|
{
|
||||||
|
Style = SKPaintStyle.Stroke,
|
||||||
|
StrokeWidth = 1,
|
||||||
|
Color = new SKColor(avColor.R, avColor.G, avColor.B)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var canvas = new SKCanvas(skb))
|
||||||
|
{
|
||||||
|
for (int x = 0; x < Samples.Length; x++)
|
||||||
|
{
|
||||||
|
UInt128 sample = Samples[x];
|
||||||
|
UInt128 prevSample = Samples[x == 0 ? x : x - 1];
|
||||||
|
|
||||||
|
for (int chan = 0; chan < ChannelCount; chan++)
|
||||||
|
{
|
||||||
|
UInt128 curVal = sample & ((UInt128)1 << chan);
|
||||||
|
UInt128 prevVal = prevSample & ((UInt128)1 << chan);
|
||||||
|
|
||||||
|
float y = chan * cHeight + (curVal != 0 ? high : low);
|
||||||
|
|
||||||
|
canvas.DrawLine(x * sWidth, y, (x + 1) * sWidth, y, colors[chan]);
|
||||||
|
|
||||||
|
if (curVal != prevVal)
|
||||||
|
canvas.DrawLine(x * sWidth, chan * cHeight + high, x * sWidth, chan * cHeight + low, colors[chan]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using var encoded = skb.Encode(SKEncodedImageFormat.Png, 1);
|
||||||
|
using var stream = encoded.AsStream();
|
||||||
|
|
||||||
|
if (bmp != null)
|
||||||
|
bmp.Dispose();
|
||||||
|
|
||||||
|
bmp = new Bitmap(stream);
|
||||||
|
sampleCount = Samples.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Render(DrawingContext context)
|
||||||
|
{
|
||||||
|
//base.Render(context);
|
||||||
|
var bounds = new Avalonia.Rect(0, 0, this.Bounds.Width, this.Bounds.Height);
|
||||||
|
|
||||||
|
context.FillRectangle(GraphicObjectsCache.GetBrush(Color.Parse("#222222")), bounds);
|
||||||
|
|
||||||
|
if (sampleCount == 0 || bmp == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(bmp as IImage).Draw(context, new Avalonia.Rect(bmp.Size), bounds, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode.HighQuality);
|
||||||
|
|
||||||
|
float ratio = (float)bounds.Size.Width / (float)sampleCount;
|
||||||
|
float pos = viewPosition * ratio;
|
||||||
|
|
||||||
|
context.DrawLine(GraphicObjectsCache.GetPen(Colors.White, 1, DashStyle.Dash), new Avalonia.Point(pos, 0), new Avalonia.Point(pos, 143));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ namespace LogicAnalyzer.Controls
|
||||||
const int MIN_CHANNEL_HEIGHT = 48;
|
const int MIN_CHANNEL_HEIGHT = 48;
|
||||||
|
|
||||||
public int PreSamples { get; set; }
|
public int PreSamples { get; set; }
|
||||||
|
public int[]? Bursts { get; set; }
|
||||||
public UInt128[] Samples { get; set; }
|
public UInt128[] Samples { get; set; }
|
||||||
public int ChannelCount { get; set; }
|
public int ChannelCount { get; set; }
|
||||||
public int SamplesInScreen { get; set; }
|
public int SamplesInScreen { get; set; }
|
||||||
|
@ -32,7 +33,9 @@ namespace LogicAnalyzer.Controls
|
||||||
Color sampleLineColor = Color.FromRgb(60, 60, 60);
|
Color sampleLineColor = Color.FromRgb(60, 60, 60);
|
||||||
Color sampleDashColor = Color.FromArgb(60, 60, 60, 60);
|
Color sampleDashColor = Color.FromArgb(60, 60, 60, 60);
|
||||||
Color triggerLineColor = Colors.White;
|
Color triggerLineColor = Colors.White;
|
||||||
|
Color burstLineColor = Colors.Azure;
|
||||||
Color userLineColor = Colors.Cyan;
|
Color userLineColor = Colors.Cyan;
|
||||||
|
|
||||||
public SampleViewer()
|
public SampleViewer()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
@ -101,7 +104,7 @@ namespace LogicAnalyzer.Controls
|
||||||
{
|
{
|
||||||
//context.FillRectangle(GraphicObjectsCache.GetBrush(AnalyzerColors.BgChannelColors[0]), thisBounds);
|
//context.FillRectangle(GraphicObjectsCache.GetBrush(AnalyzerColors.BgChannelColors[0]), thisBounds);
|
||||||
|
|
||||||
if (PreSamples == 0 || Samples == null || ChannelCount == 0 || SamplesInScreen == 0 || updating)
|
if (Samples == null || ChannelCount == 0 || SamplesInScreen == 0 || updating)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double channelHeight = thisBounds.Height / (double)ChannelCount;
|
double channelHeight = thisBounds.Height / (double)ChannelCount;
|
||||||
|
@ -148,6 +151,14 @@ namespace LogicAnalyzer.Controls
|
||||||
if (buc == PreSamples)
|
if (buc == PreSamples)
|
||||||
context.DrawLine(GraphicObjectsCache.GetPen(triggerLineColor, 2), new Point(lineX, 0), new Point(lineX, thisBounds.Height));
|
context.DrawLine(GraphicObjectsCache.GetPen(triggerLineColor, 2), new Point(lineX, 0), new Point(lineX, thisBounds.Height));
|
||||||
|
|
||||||
|
if (Bursts != null)
|
||||||
|
{
|
||||||
|
if (Bursts.Any(b => b == buc))
|
||||||
|
{
|
||||||
|
context.DrawLine(GraphicObjectsCache.GetPen(burstLineColor, 2, DashStyle.DashDot), new Point(lineX, 0), new Point(lineX, thisBounds.Height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(UserMarker != null && UserMarker == buc)
|
if(UserMarker != null && UserMarker == buc)
|
||||||
context.DrawLine(GraphicObjectsCache.GetPen(userLineColor, 2, DashStyle.DashDot), new Point(lineX, 0), new Point(lineX, thisBounds.Height));
|
context.DrawLine(GraphicObjectsCache.GetPen(userLineColor, 2, DashStyle.DashDot), new Point(lineX, 0), new Point(lineX, thisBounds.Height));
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,12 @@
|
||||||
<RadioButton Name="rbTrigger23"></RadioButton>
|
<RadioButton Name="rbTrigger23"></RadioButton>
|
||||||
<RadioButton Name="rbTrigger24"></RadioButton>
|
<RadioButton Name="rbTrigger24"></RadioButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<CheckBox Name="ckNegativeTrigger" Margin="10,0,0,10">Negative edge</CheckBox>
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<CheckBox Name="ckNegativeTrigger" Margin="10,0,0,10">Negative edge</CheckBox>
|
||||||
|
<CheckBox Name="ckBurst" Margin="20,0,0,10">Burst mode</CheckBox>
|
||||||
|
<TextBlock Margin="20,10,0,10">Burst count:</TextBlock>
|
||||||
|
<NumericUpDown IsEnabled="{Binding #ckBurst.IsChecked}" Width="135" Margin="10,0,0,10" Height="35" Minimum="2" Maximum="10000" Value="2" Name="nudBurstCount"></NumericUpDown>
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<RadioButton Margin="15,0,0,0" Name="rbTriggerTypePattern">Pattern trigger</RadioButton>
|
<RadioButton Margin="15,0,0,0" Name="rbTriggerTypePattern">Pattern trigger</RadioButton>
|
||||||
<StackPanel Name="pnlPatternTrigger" Orientation="Horizontal" VerticalAlignment="Top" Margin="10,0,10,10" Background="#80303030">
|
<StackPanel Name="pnlPatternTrigger" Orientation="Horizontal" VerticalAlignment="Top" Margin="10,0,10,10" Background="#80303030">
|
||||||
|
|
|
@ -178,6 +178,7 @@ namespace LogicAnalyzer.Dialogs
|
||||||
Frequency = oldset.Frequency,
|
Frequency = oldset.Frequency,
|
||||||
PostTriggerSamples = oldset.PostTriggerSamples,
|
PostTriggerSamples = oldset.PostTriggerSamples,
|
||||||
PreTriggerSamples = oldset.PreTriggerSamples,
|
PreTriggerSamples = oldset.PreTriggerSamples,
|
||||||
|
LoopCount = 0,
|
||||||
TriggerBitCount = oldset.TriggerBitCount,
|
TriggerBitCount = oldset.TriggerBitCount,
|
||||||
TriggerChannel = oldset.TriggerChannel,
|
TriggerChannel = oldset.TriggerChannel,
|
||||||
TriggerInverted = oldset.TriggerInverted,
|
TriggerInverted = oldset.TriggerInverted,
|
||||||
|
@ -216,6 +217,8 @@ namespace LogicAnalyzer.Dialogs
|
||||||
|
|
||||||
triggerChannels[settings.TriggerChannel].IsChecked = true;
|
triggerChannels[settings.TriggerChannel].IsChecked = true;
|
||||||
ckNegativeTrigger.IsChecked = settings.TriggerInverted;
|
ckNegativeTrigger.IsChecked = settings.TriggerInverted;
|
||||||
|
ckBurst.IsChecked = settings.LoopCount > 0;
|
||||||
|
nudBurstCount.Value = settings.LoopCount > 0 ? settings.LoopCount : 1;
|
||||||
|
|
||||||
rbTriggerTypePattern.IsChecked = false;
|
rbTriggerTypePattern.IsChecked = false;
|
||||||
rbTriggerTypeEdge.IsChecked = true;
|
rbTriggerTypeEdge.IsChecked = true;
|
||||||
|
@ -280,7 +283,9 @@ namespace LogicAnalyzer.Dialogs
|
||||||
|
|
||||||
int max = driver.GetLimits(channelsToCapture.Select(c => c.ChannelNumber).ToArray()).MaxTotalSamples;
|
int max = driver.GetLimits(channelsToCapture.Select(c => c.ChannelNumber).ToArray()).MaxTotalSamples;
|
||||||
|
|
||||||
if (nudPreSamples.Value + nudPostSamples.Value > max)
|
int loops = (int)((ckBurst.IsChecked ?? false) ? nudBurstCount.Value - 1 : 0);
|
||||||
|
|
||||||
|
if (nudPreSamples.Value + (nudPostSamples.Value * (loops + 1)) > max)
|
||||||
{
|
{
|
||||||
await this.ShowError("Error", $"Total samples cannot exceed {max}.");
|
await this.ShowError("Error", $"Total samples cannot exceed {max}.");
|
||||||
return;
|
return;
|
||||||
|
@ -385,6 +390,7 @@ namespace LogicAnalyzer.Dialogs
|
||||||
settings.Frequency = (int)nudFrequency.Value;
|
settings.Frequency = (int)nudFrequency.Value;
|
||||||
settings.PreTriggerSamples = (int)nudPreSamples.Value;
|
settings.PreTriggerSamples = (int)nudPreSamples.Value;
|
||||||
settings.PostTriggerSamples = (int)nudPostSamples.Value;
|
settings.PostTriggerSamples = (int)nudPostSamples.Value;
|
||||||
|
settings.LoopCount = loops;
|
||||||
settings.TriggerInverted = ckNegativeTrigger.IsChecked == true;
|
settings.TriggerInverted = ckNegativeTrigger.IsChecked == true;
|
||||||
settings.CaptureChannels = channelsToCapture.ToArray();
|
settings.CaptureChannels = channelsToCapture.ToArray();
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||||
<ApplicationIcon>Assets\Ico40.ico</ApplicationIcon>
|
<ApplicationIcon>Assets\Ico40.ico</ApplicationIcon>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
<Version>4.5.1.0</Version>
|
<Version>5.0.0.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove=".gitignore" />
|
<None Remove=".gitignore" />
|
||||||
|
|
|
@ -47,7 +47,9 @@
|
||||||
<controls:SampleMarker Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Foreground="White" Background="Transparent" Name="sampleMarker"></controls:SampleMarker>
|
<controls:SampleMarker Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Foreground="White" Background="Transparent" Name="sampleMarker"></controls:SampleMarker>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
<ScrollBar VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Orientation="Horizontal" DockPanel.Dock="Bottom" Name="scrSamplePos" AllowAutoHide="False"></ScrollBar>
|
<ScrollBar VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Orientation="Horizontal" DockPanel.Dock="Bottom" Name="scrSamplePos" AllowAutoHide="False"></ScrollBar>
|
||||||
|
<controls:SamplePreviewer IsVisible="False" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="144" ZIndex="1000" Name="samplePreviewer" DockPanel.Dock="Bottom" Margin="0,-144,0,0"></controls:SamplePreviewer>
|
||||||
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ColumnDefinitions="*,240" DockPanel.Dock="Bottom">
|
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ColumnDefinitions="*,240" DockPanel.Dock="Bottom">
|
||||||
<ScrollViewer VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
<ScrollViewer VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||||
<Grid ColumnDefinitions="140,*" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
<Grid ColumnDefinitions="140,*" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using AvaloniaEdit.Utils;
|
using AvaloniaEdit.Utils;
|
||||||
|
@ -64,16 +65,115 @@ namespace LogicAnalyzer
|
||||||
|
|
||||||
tkInScreen.PropertyChanged += tkInScreen_ValueChanged;
|
tkInScreen.PropertyChanged += tkInScreen_ValueChanged;
|
||||||
scrSamplePos.Scroll += scrSamplePos_ValueChanged;
|
scrSamplePos.Scroll += scrSamplePos_ValueChanged;
|
||||||
|
scrSamplePos.PointerEnter += ScrSamplePos_PointerEnter;
|
||||||
|
scrSamplePos.PointerLeave += ScrSamplePos_PointerLeave;
|
||||||
mnuNew.Click += MnuNew_Click;
|
mnuNew.Click += MnuNew_Click;
|
||||||
mnuOpen.Click += mnuOpen_Click;
|
mnuOpen.Click += mnuOpen_Click;
|
||||||
mnuSave.Click += mnuSave_Click;
|
mnuSave.Click += mnuSave_Click;
|
||||||
mnuExit.Click += MnuExit_Click;
|
mnuExit.Click += MnuExit_Click;
|
||||||
mnuExport.Click += MnuExport_Click;
|
mnuExport.Click += MnuExport_Click;
|
||||||
mnuNetSettings.Click += MnuNetSettings_Click;
|
mnuNetSettings.Click += MnuNetSettings_Click;
|
||||||
|
|
||||||
|
AddHandler(InputElement.KeyDownEvent, MainWindow_KeyDown, handledEventsToo: true);
|
||||||
|
|
||||||
LoadAnalyzers();
|
LoadAnalyzers();
|
||||||
RefreshPorts();
|
RefreshPorts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MainWindow_KeyDown(object? sender, Avalonia.Input.KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.KeyModifiers == Avalonia.Input.KeyModifiers.Control)
|
||||||
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.Left:
|
||||||
|
{
|
||||||
|
var currentVal = scrSamplePos.Value;
|
||||||
|
var maxVal = sampleViewer.SamplesInScreen;
|
||||||
|
int newVal = (int)currentVal - (maxVal / 10);
|
||||||
|
|
||||||
|
if (newVal < 0)
|
||||||
|
newVal = 0;
|
||||||
|
|
||||||
|
scrSamplePos.Value = newVal;
|
||||||
|
scrSamplePos_ValueChanged(scrSamplePos, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Key.Right:
|
||||||
|
{
|
||||||
|
var currentVal = scrSamplePos.Value;
|
||||||
|
var maxVal = sampleViewer.SamplesInScreen;
|
||||||
|
int newVal = (int)currentVal + (maxVal / 10);
|
||||||
|
|
||||||
|
if (newVal > scrSamplePos.Maximum)
|
||||||
|
newVal = (int)scrSamplePos.Maximum;
|
||||||
|
|
||||||
|
scrSamplePos.Value = newVal;
|
||||||
|
scrSamplePos_ValueChanged(scrSamplePos, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Key.Down:
|
||||||
|
{
|
||||||
|
var currentVal = scrSamplePos.Value;
|
||||||
|
var maxVal = sampleViewer.SamplesInScreen;
|
||||||
|
int newVal = (int)currentVal - maxVal;
|
||||||
|
|
||||||
|
if (newVal < 0)
|
||||||
|
newVal = 0;
|
||||||
|
|
||||||
|
scrSamplePos.Value = newVal;
|
||||||
|
scrSamplePos_ValueChanged(scrSamplePos, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Key.Up:
|
||||||
|
{
|
||||||
|
var currentVal = scrSamplePos.Value;
|
||||||
|
var maxVal = sampleViewer.SamplesInScreen;
|
||||||
|
int newVal = (int)currentVal + maxVal;
|
||||||
|
|
||||||
|
if (newVal > scrSamplePos.Maximum)
|
||||||
|
newVal = (int)scrSamplePos.Maximum;
|
||||||
|
|
||||||
|
scrSamplePos.Value = newVal;
|
||||||
|
scrSamplePos_ValueChanged(scrSamplePos, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.KeyModifiers == KeyModifiers.Shift)
|
||||||
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.Left:
|
||||||
|
{
|
||||||
|
var currentVal = scrSamplePos.Value;
|
||||||
|
int newVal = (int)currentVal - 1;
|
||||||
|
|
||||||
|
if (newVal < 0)
|
||||||
|
newVal = 0;
|
||||||
|
|
||||||
|
scrSamplePos.Value = newVal;
|
||||||
|
scrSamplePos_ValueChanged(scrSamplePos, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Key.Right:
|
||||||
|
{
|
||||||
|
var currentVal = scrSamplePos.Value;
|
||||||
|
int newVal = (int)currentVal + 1;
|
||||||
|
|
||||||
|
if (newVal > scrSamplePos.Maximum)
|
||||||
|
newVal = (int)scrSamplePos.Maximum;
|
||||||
|
|
||||||
|
scrSamplePos.Value = newVal;
|
||||||
|
scrSamplePos_ValueChanged(scrSamplePos, null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void SampleMarker_ShiftSamples(object? sender, EventArgs e)
|
private async void SampleMarker_ShiftSamples(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var dlg = new ShiftChannelsDialog();
|
var dlg = new ShiftChannelsDialog();
|
||||||
|
@ -81,7 +181,7 @@ namespace LogicAnalyzer
|
||||||
|
|
||||||
if (await dlg.ShowDialog<bool>(this))
|
if (await dlg.ShowDialog<bool>(this))
|
||||||
{
|
{
|
||||||
var samples = sampleViewer.Samples;
|
var samples = sampleViewer.Samples;
|
||||||
|
|
||||||
foreach (var channel in dlg.ShiftedChannels)
|
foreach (var channel in dlg.ShiftedChannels)
|
||||||
{
|
{
|
||||||
|
@ -120,6 +220,8 @@ namespace LogicAnalyzer
|
||||||
sampleViewer.BeginUpdate();
|
sampleViewer.BeginUpdate();
|
||||||
sampleViewer.Samples = samples;
|
sampleViewer.Samples = samples;
|
||||||
sampleViewer.EndUpdate();
|
sampleViewer.EndUpdate();
|
||||||
|
samplePreviewer.UpdateSamples(samples, sampleViewer.ChannelCount);
|
||||||
|
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +297,9 @@ namespace LogicAnalyzer
|
||||||
|
|
||||||
sampleViewer.EndUpdate();
|
sampleViewer.EndUpdate();
|
||||||
|
|
||||||
|
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||||
|
samplePreviewer.UpdateSamples(samples, sampleViewer.ChannelCount);
|
||||||
|
|
||||||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||||
sampleMarker.ClearRegions();
|
sampleMarker.ClearRegions();
|
||||||
|
@ -331,14 +436,6 @@ namespace LogicAnalyzer
|
||||||
var lastSample = e.FirstSample + e.SampleCount - 1;
|
var lastSample = e.FirstSample + e.SampleCount - 1;
|
||||||
var triggerSample = sampleViewer.PreSamples - 1;
|
var triggerSample = sampleViewer.PreSamples - 1;
|
||||||
|
|
||||||
var containsTrigger = e.FirstSample <= triggerSample && lastSample >= triggerSample;
|
|
||||||
|
|
||||||
if (containsTrigger)
|
|
||||||
{
|
|
||||||
await this.ShowError("Error", "Cannot delete the trigger sample.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var preDelete = sampleViewer.Samples.Take(e.FirstSample);
|
var preDelete = sampleViewer.Samples.Take(e.FirstSample);
|
||||||
var postDelete = sampleViewer.Samples.Skip(e.FirstSample + e.SampleCount + 1);
|
var postDelete = sampleViewer.Samples.Skip(e.FirstSample + e.SampleCount + 1);
|
||||||
|
|
||||||
|
@ -412,7 +509,8 @@ namespace LogicAnalyzer
|
||||||
{
|
{
|
||||||
sampleViewer.BeginUpdate();
|
sampleViewer.BeginUpdate();
|
||||||
sampleViewer.Samples = finalSamples;
|
sampleViewer.Samples = finalSamples;
|
||||||
sampleViewer.PreSamples = finalPreSamples;
|
sampleViewer.PreSamples = 0;
|
||||||
|
sampleViewer.Bursts = null;
|
||||||
|
|
||||||
if (sampleViewer.FirstSample > finalSamples.Length - 1)
|
if (sampleViewer.FirstSample > finalSamples.Length - 1)
|
||||||
sampleViewer.FirstSample = finalSamples.Length - 1;
|
sampleViewer.FirstSample = finalSamples.Length - 1;
|
||||||
|
@ -425,6 +523,9 @@ namespace LogicAnalyzer
|
||||||
|
|
||||||
sampleViewer.EndUpdate();
|
sampleViewer.EndUpdate();
|
||||||
|
|
||||||
|
samplePreviewer.UpdateSamples(finalSamples, sampleViewer.ChannelCount);
|
||||||
|
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||||
|
|
||||||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||||
sampleMarker.ClearRegions();
|
sampleMarker.ClearRegions();
|
||||||
|
@ -569,10 +670,30 @@ namespace LogicAnalyzer
|
||||||
sampleViewer.SamplesInScreen = Math.Min(100, e.Samples.Length / 10);
|
sampleViewer.SamplesInScreen = Math.Min(100, e.Samples.Length / 10);
|
||||||
|
|
||||||
sampleViewer.FirstSample = Math.Max(e.PreSamples - 10, 0);
|
sampleViewer.FirstSample = Math.Max(e.PreSamples - 10, 0);
|
||||||
|
|
||||||
|
if (settings.LoopCount > 0)
|
||||||
|
{
|
||||||
|
int pos = e.PreSamples;
|
||||||
|
List<int> bursts = new List<int>();
|
||||||
|
|
||||||
|
for (int buc = 0; buc < settings.LoopCount; buc++)
|
||||||
|
{
|
||||||
|
pos = pos + settings.PostTriggerSamples;
|
||||||
|
bursts.Add(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleViewer.Bursts = bursts.ToArray();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sampleViewer.Bursts = null;
|
||||||
|
|
||||||
sampleViewer.ClearRegions();
|
sampleViewer.ClearRegions();
|
||||||
sampleViewer.ClearAnalyzedChannels();
|
sampleViewer.ClearAnalyzedChannels();
|
||||||
sampleViewer.EndUpdate();
|
sampleViewer.EndUpdate();
|
||||||
|
|
||||||
|
samplePreviewer.UpdateSamples(e.Samples, sampleViewer.ChannelCount);
|
||||||
|
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||||
|
|
||||||
scrSamplePos.Maximum = e.Samples.Length - 1;
|
scrSamplePos.Maximum = e.Samples.Length - 1;
|
||||||
scrSamplePos.Value = sampleViewer.FirstSample;
|
scrSamplePos.Value = sampleViewer.FirstSample;
|
||||||
tkInScreen.Value = sampleViewer.SamplesInScreen;
|
tkInScreen.Value = sampleViewer.SamplesInScreen;
|
||||||
|
@ -844,7 +965,7 @@ namespace LogicAnalyzer
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var error = driver.StartCapture(settings.Frequency, settings.PreTriggerSamples, settings.PostTriggerSamples, settings.CaptureChannels.Select(c => c.ChannelNumber).ToArray(), settings.TriggerChannel, settings.TriggerInverted);
|
var error = driver.StartCapture(settings.Frequency, settings.PreTriggerSamples, settings.PostTriggerSamples, settings.LoopCount, settings.CaptureChannels.Select(c => c.ChannelNumber).ToArray(), settings.TriggerChannel, settings.TriggerInverted);
|
||||||
|
|
||||||
if (error != CaptureError.None)
|
if (error != CaptureError.None)
|
||||||
{
|
{
|
||||||
|
@ -878,7 +999,15 @@ namespace LogicAnalyzer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void ScrSamplePos_PointerLeave(object? sender, Avalonia.Input.PointerEventArgs e)
|
||||||
|
{
|
||||||
|
samplePreviewer.IsVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScrSamplePos_PointerEnter(object? sender, Avalonia.Input.PointerEventArgs e)
|
||||||
|
{
|
||||||
|
samplePreviewer.IsVisible = true;
|
||||||
|
}
|
||||||
private void scrSamplePos_ValueChanged(object? sender, ScrollEventArgs e)
|
private void scrSamplePos_ValueChanged(object? sender, ScrollEventArgs e)
|
||||||
{
|
{
|
||||||
if (sampleViewer.Samples != null)
|
if (sampleViewer.Samples != null)
|
||||||
|
@ -886,6 +1015,7 @@ namespace LogicAnalyzer
|
||||||
sampleViewer.BeginUpdate();
|
sampleViewer.BeginUpdate();
|
||||||
sampleViewer.FirstSample = (int)scrSamplePos.Value;
|
sampleViewer.FirstSample = (int)scrSamplePos.Value;
|
||||||
sampleViewer.EndUpdate();
|
sampleViewer.EndUpdate();
|
||||||
|
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -927,7 +1057,11 @@ namespace LogicAnalyzer
|
||||||
if (string.IsNullOrWhiteSpace(file))
|
if (string.IsNullOrWhiteSpace(file))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ExportedCapture ex = new ExportedCapture { Settings = settings, Samples = sampleViewer.Samples, SelectedRegions = sampleViewer.SelectedRegions };
|
var sets = settings.Clone();
|
||||||
|
sets.PreTriggerSamples = sampleViewer.PreSamples;
|
||||||
|
sets.LoopCount = sampleViewer.Bursts?.Length ?? 0;
|
||||||
|
|
||||||
|
ExportedCapture ex = new ExportedCapture { Settings = sets, Samples = sampleViewer.Samples, SelectedRegions = sampleViewer.SelectedRegions };
|
||||||
|
|
||||||
File.WriteAllText(file, JsonConvert.SerializeObject(ex, new JsonConverter[] { new SampleRegion.SampleRegionConverter() }));
|
File.WriteAllText(file, JsonConvert.SerializeObject(ex, new JsonConverter[] { new SampleRegion.SampleRegionConverter() }));
|
||||||
}
|
}
|
||||||
|
@ -980,6 +1114,7 @@ namespace LogicAnalyzer
|
||||||
Frequency = oldset.Frequency,
|
Frequency = oldset.Frequency,
|
||||||
PostTriggerSamples = oldset.PostTriggerSamples,
|
PostTriggerSamples = oldset.PostTriggerSamples,
|
||||||
PreTriggerSamples = oldset.PreTriggerSamples,
|
PreTriggerSamples = oldset.PreTriggerSamples,
|
||||||
|
LoopCount = 0,
|
||||||
TriggerBitCount = oldset.TriggerBitCount,
|
TriggerBitCount = oldset.TriggerBitCount,
|
||||||
TriggerChannel = oldset.TriggerChannel,
|
TriggerChannel = oldset.TriggerChannel,
|
||||||
TriggerInverted = oldset.TriggerInverted,
|
TriggerInverted = oldset.TriggerInverted,
|
||||||
|
@ -1015,6 +1150,9 @@ namespace LogicAnalyzer
|
||||||
|
|
||||||
sampleViewer.EndUpdate();
|
sampleViewer.EndUpdate();
|
||||||
|
|
||||||
|
samplePreviewer.UpdateSamples(ex.Samples, sampleViewer.ChannelCount);
|
||||||
|
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||||
|
|
||||||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||||
sampleMarker.ClearRegions();
|
sampleMarker.ClearRegions();
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace SharedDriver
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int LoopCount, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace SharedDriver
|
||||||
public int Channels { get; }
|
public int Channels { get; }
|
||||||
public event EventHandler<CaptureEventArgs> CaptureCompleted;
|
public event EventHandler<CaptureEventArgs> CaptureCompleted;
|
||||||
public bool SendNetworkConfig(string AccesPointName, string Password, string IPAddress, ushort Port);
|
public bool SendNetworkConfig(string AccesPointName, string Password, string IPAddress, ushort Port);
|
||||||
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null);
|
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int LoopCount, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null);
|
||||||
public CaptureError StartPatternCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, int TriggerBitCount, UInt16 TriggerPattern, bool Fast, Action<CaptureEventArgs>? CaptureCompletedHandler = null);
|
public CaptureError StartPatternCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, int TriggerBitCount, UInt16 TriggerPattern, bool Fast, Action<CaptureEventArgs>? CaptureCompletedHandler = null);
|
||||||
public bool StopCapture();
|
public bool StopCapture();
|
||||||
public CaptureLimits GetLimits(int[] Channels);
|
public CaptureLimits GetLimits(int[] Channels);
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace SharedDriver
|
||||||
{
|
{
|
||||||
public class LogicAnalyzerDriver : IDisposable, IAnalizerDriver
|
public class LogicAnalyzerDriver : IDisposable, IAnalizerDriver
|
||||||
{
|
{
|
||||||
|
Regex regVersion = new Regex(".*?(V([0-9]+)_([0-9]+))$");
|
||||||
Regex regAddressPort = new Regex("([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)\\:([0-9]+)");
|
Regex regAddressPort = new Regex("([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)\\:([0-9]+)");
|
||||||
StreamReader readResponse;
|
StreamReader readResponse;
|
||||||
BinaryReader readData;
|
BinaryReader readData;
|
||||||
|
@ -74,7 +75,26 @@ namespace SharedDriver
|
||||||
|
|
||||||
baseStream.ReadTimeout = 10000;
|
baseStream.ReadTimeout = 10000;
|
||||||
DeviceVersion = readResponse.ReadLine();
|
DeviceVersion = readResponse.ReadLine();
|
||||||
|
|
||||||
|
var verMatch = regVersion.Match(DeviceVersion ?? "");
|
||||||
|
|
||||||
|
if (verMatch == null || !verMatch.Success || !verMatch.Groups[2].Success)
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
throw new DeviceConnectionException($"Invalid device version V{ (string.IsNullOrWhiteSpace(verMatch?.Value) ? "(unknown)" : verMatch?.Value) }, minimum supported version: V5_0");
|
||||||
|
}
|
||||||
|
|
||||||
|
int majorVer = int.Parse(verMatch.Groups[2].Value);
|
||||||
|
|
||||||
|
if (majorVer < 5)
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
throw new DeviceConnectionException($"Invalid device version V{verMatch.Value}, minimum supported version: V5_0");
|
||||||
|
}
|
||||||
|
|
||||||
baseStream.ReadTimeout = Timeout.Infinite;
|
baseStream.ReadTimeout = Timeout.Infinite;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
private void InitNetwork(string AddressPort)
|
private void InitNetwork(string AddressPort)
|
||||||
{
|
{
|
||||||
|
@ -138,7 +158,7 @@ namespace SharedDriver
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int LoopCount, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (capturing)
|
if (capturing)
|
||||||
|
@ -159,25 +179,27 @@ namespace SharedDriver
|
||||||
|
|
||||||
var captureMode = GetCaptureMode(Channels);
|
var captureMode = GetCaptureMode(Channels);
|
||||||
|
|
||||||
|
int requestedSamples = PreSamples + (PostSamples * ((byte)LoopCount + 1));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (captureMode)
|
switch (captureMode)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
|
||||||
if (PreSamples > 98303 || PostSamples > 131069 || PreSamples + PostSamples > 131071)
|
if (PreSamples > 98303 || PostSamples > 131069 || requestedSamples > 131071)
|
||||||
return CaptureError.BadParams;
|
return CaptureError.BadParams;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
|
|
||||||
if (PreSamples > 49151 || PostSamples > 65533 || PreSamples + PostSamples > 65535)
|
if (PreSamples > 49151 || PostSamples > 65533 || requestedSamples > 65535)
|
||||||
return CaptureError.BadParams;
|
return CaptureError.BadParams;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
|
||||||
if (PreSamples > 24576 || PostSamples > 32765 || PreSamples + PostSamples > 32767)
|
if (PreSamples > 24576 || PostSamples > 32765 || requestedSamples > 32767)
|
||||||
return CaptureError.BadParams;
|
return CaptureError.BadParams;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -197,6 +219,7 @@ namespace SharedDriver
|
||||||
frequency = (uint)Frequency,
|
frequency = (uint)Frequency,
|
||||||
preSamples = (uint)PreSamples,
|
preSamples = (uint)PreSamples,
|
||||||
postSamples = (uint)PostSamples,
|
postSamples = (uint)PostSamples,
|
||||||
|
loopCount = (byte)LoopCount,
|
||||||
captureMode = captureMode
|
captureMode = captureMode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -217,7 +240,7 @@ namespace SharedDriver
|
||||||
if (result == "CAPTURE_STARTED")
|
if (result == "CAPTURE_STARTED")
|
||||||
{
|
{
|
||||||
capturing = true;
|
capturing = true;
|
||||||
Task.Run(() => ReadCapture(PreSamples + PostSamples, captureMode));
|
Task.Run(() => ReadCapture(requestedSamples, captureMode));
|
||||||
return CaptureError.None;
|
return CaptureError.None;
|
||||||
}
|
}
|
||||||
return CaptureError.HardwareError;
|
return CaptureError.HardwareError;
|
||||||
|
@ -547,6 +570,7 @@ namespace SharedDriver
|
||||||
public UInt32 frequency;
|
public UInt32 frequency;
|
||||||
public UInt32 preSamples;
|
public UInt32 preSamples;
|
||||||
public UInt32 postSamples;
|
public UInt32 postSamples;
|
||||||
|
public byte loopCount;
|
||||||
public byte captureMode;
|
public byte captureMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace SharedDriver
|
||||||
{
|
{
|
||||||
public class MultiAnalizerDriver : IDisposable, IAnalizerDriver
|
public class MultiAnalizerDriver : IDisposable, IAnalizerDriver
|
||||||
{
|
{
|
||||||
Regex regVersion = new Regex(".*?(V[0-9]_[0-9])$");
|
Regex regVersion = new Regex(".*?(V([0-9]+)_([0-9]+))$");
|
||||||
LogicAnalyzerDriver[] connectedDevices;
|
LogicAnalyzerDriver[] connectedDevices;
|
||||||
|
|
||||||
UInt128[][]? tempCapture;
|
UInt128[][]? tempCapture;
|
||||||
|
@ -79,7 +79,24 @@ namespace SharedDriver
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ver == null)
|
if (ver == null)
|
||||||
|
{
|
||||||
ver = mVer.Groups[1].Value;
|
ver = mVer.Groups[1].Value;
|
||||||
|
|
||||||
|
if (mVer == null || !mVer.Success || !mVer.Groups[2].Success)
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
throw new DeviceConnectionException($"Invalid device version V{(string.IsNullOrWhiteSpace(mVer?.Value) ? "(unknown)" : mVer?.Value)}, minimum supported version: V5_0");
|
||||||
|
}
|
||||||
|
|
||||||
|
int majorVer = int.Parse(mVer.Groups[2].Value);
|
||||||
|
|
||||||
|
if (majorVer < 5)
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
throw new DeviceConnectionException($"Invalid device version V{mVer.Value}, minimum supported version: V5_0");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ver != mVer.Groups[1].Value)
|
if (ver != mVer.Groups[1].Value)
|
||||||
|
@ -96,7 +113,7 @@ namespace SharedDriver
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
public CaptureError StartCapture(int Frequency, int PreSamples, int PostSamples, int LoopCount, int[] Channels, int TriggerChannel, bool TriggerInverted, Action<CaptureEventArgs>? CaptureCompletedHandler = null)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
@ -163,7 +180,7 @@ namespace SharedDriver
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
connectedDevices[buc].Tag = channelsCapturing;
|
connectedDevices[buc].Tag = channelsCapturing;
|
||||||
var err = connectedDevices[buc].StartCapture(Frequency, PreSamples + offset, PostSamples - offset, chan, 24, false);
|
var err = connectedDevices[buc].StartCapture(Frequency, PreSamples + offset, PostSamples - offset, 0, chan, 24, false);
|
||||||
|
|
||||||
if (err != CaptureError.None)
|
if (err != CaptureError.None)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user