mirror of
https://github.com/JasonYANG170/logicanalyzer.git
synced 2024-11-26 21:46:27 +00:00
Updates for V5.0
This commit is contained in:
parent
7f96804d3e
commit
3a5e9bfee2
|
@ -10,6 +10,7 @@
|
|||
#include "pico/multicore.h"
|
||||
#include "LogicAnalyzer.pio.h"
|
||||
#include "LogicAnalyzer_Structs.h"
|
||||
#include "tusb.h"
|
||||
|
||||
#ifdef WS2812_LED
|
||||
#include "LogicAnalyzer_W2812.h"
|
||||
|
@ -85,6 +86,8 @@ CAPTURE_REQUEST* req;
|
|||
|
||||
#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)
|
||||
{
|
||||
uint8_t buffer[FLASH_PAGE_SIZE];
|
||||
|
@ -129,6 +132,10 @@ void storeSettings(WIFI_SETTINGS* settings)
|
|||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
#ifdef USE_CYGW_WIFI
|
||||
|
@ -146,6 +153,10 @@ void sendResponse(const char* response, bool toWiFi)
|
|||
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)
|
||||
{
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -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.
|
||||
}
|
||||
|
||||
/// @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)
|
||||
{
|
||||
//Try to get char
|
||||
|
@ -321,11 +370,14 @@ bool processUSBInput(bool skipProcessing)
|
|||
|
||||
#ifdef USE_CYGW_WIFI
|
||||
|
||||
/// @brief Purges any pending data in the USB input
|
||||
void purgeUSBData()
|
||||
{
|
||||
while(getchar_timeout_us(0) != PICO_ERROR_TIMEOUT);
|
||||
}
|
||||
|
||||
/// @brief Callback for the WiFi event queue
|
||||
/// @param event Received event
|
||||
void wifiEvent(void* 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 res = event_has_events(&wifiToFrontend);
|
||||
|
@ -372,6 +427,7 @@ bool processWiFiInput(bool skipProcessing)
|
|||
|
||||
#endif
|
||||
|
||||
/// @brief Process input data from the host application if it is available
|
||||
void processInput()
|
||||
{
|
||||
#ifdef USE_CYGW_WIFI
|
||||
|
@ -384,6 +440,8 @@ void processInput()
|
|||
#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()
|
||||
{
|
||||
#ifdef USE_CYGW_WIFI
|
||||
|
@ -397,6 +455,8 @@ bool processCancel()
|
|||
#endif
|
||||
}
|
||||
|
||||
/// @brief Main app loop
|
||||
/// @return Exit code
|
||||
int main()
|
||||
{
|
||||
//Overclock Powerrrr!
|
||||
|
@ -454,18 +514,10 @@ int main()
|
|||
event_push(&frontendToWifi, &evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
putchar_raw(lengthPointer[0]);
|
||||
putchar_raw(lengthPointer[1]);
|
||||
putchar_raw(lengthPointer[2]);
|
||||
putchar_raw(lengthPointer[3]);
|
||||
}
|
||||
cdc_transfer(lengthPointer, 4);
|
||||
|
||||
#else
|
||||
putchar_raw(lengthPointer[0]);
|
||||
putchar_raw(lengthPointer[1]);
|
||||
putchar_raw(lengthPointer[2]);
|
||||
putchar_raw(lengthPointer[3]);
|
||||
cdc_transfer(lengthPointer, 4);
|
||||
#endif
|
||||
|
||||
sleep_ms(100);
|
||||
|
@ -513,23 +565,24 @@ int main()
|
|||
}
|
||||
else
|
||||
{
|
||||
for(int buc = 0; buc < length; buc++)
|
||||
if(first + length > CAPTURE_BUFFER_SIZE)
|
||||
{
|
||||
putchar_raw(buffer[first++]);
|
||||
|
||||
if(first >= 131072)
|
||||
first = 0;
|
||||
cdc_transfer(buffer + first, CAPTURE_BUFFER_SIZE - first);
|
||||
cdc_transfer(buffer, (first + length) - CAPTURE_BUFFER_SIZE);
|
||||
}
|
||||
else
|
||||
cdc_transfer(buffer + first, length);
|
||||
}
|
||||
#else
|
||||
//Send the samples
|
||||
for(int buc = 0; buc < length; buc++)
|
||||
{
|
||||
putchar_raw(buffer[first++]);
|
||||
|
||||
if(first >= 131072)
|
||||
first = 0;
|
||||
if(first + length > CAPTURE_BUFFER_SIZE)
|
||||
{
|
||||
cdc_transfer(buffer + first, CAPTURE_BUFFER_SIZE - first);
|
||||
cdc_transfer(buffer, (first + length) - CAPTURE_BUFFER_SIZE);
|
||||
}
|
||||
else
|
||||
cdc_transfer(buffer + first, length);
|
||||
|
||||
#endif
|
||||
//Done!
|
||||
capturing = false;
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
.program POSITIVE_CAPTURE
|
||||
|
||||
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
|
||||
|
||||
|
@ -16,19 +18,28 @@ POST_CAPTURE:
|
|||
in pins 32 ;read sample
|
||||
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
|
||||
|
||||
LOCK:
|
||||
|
||||
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
|
||||
|
||||
.wrap_target
|
||||
|
||||
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:
|
||||
|
||||
|
@ -37,15 +48,24 @@ PRE_CAPTURE:
|
|||
|
||||
POST_CAPTURE:
|
||||
|
||||
.wrap_target
|
||||
|
||||
in pins 32 ;read sample
|
||||
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
|
||||
|
||||
LOCK:
|
||||
|
||||
jmp LOCK ;block the program
|
||||
|
||||
LOOP:
|
||||
mov x, osr ;read loop count
|
||||
INNER_LOOP:
|
||||
jmp pin INNER_LOOP ;wait for trigger
|
||||
|
||||
.wrap
|
||||
|
||||
;--------------------------------------------------------------------------------------------
|
||||
|
@ -131,6 +151,8 @@ LOCK:
|
|||
#include "string.h"
|
||||
#include "hardware/sync.h"
|
||||
|
||||
#define CAPTURE_BUFFER_SIZE (128 * 1024)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
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 lastPreSize; //Pre-trigger buffer size
|
||||
static uint32_t lastPostSize; //Post-trigger buffer size
|
||||
static uint32_t lastLoopCount; //Number of loops
|
||||
static bool lastTriggerInverted; //Inverted?
|
||||
static uint8_t lastTriggerPin;
|
||||
static uint32_t lastStartPosition;
|
||||
|
@ -187,7 +210,7 @@ static bool captureProcessed;
|
|||
#endif
|
||||
|
||||
//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------------------------------------
|
||||
|
@ -330,8 +353,8 @@ uint32_t find_capture_tail()
|
|||
if(busy_channel == 0xFFFFFFFF)
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
//Ok, now we need to know at which transfer the DMA is. The value equals to MAX_TRANSFERS - TRANSFERS_LEFT.
|
||||
int32_t transfer = transferCount - dma_channel_hw_addr(busy_channel)->transfer_count;
|
||||
//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 - 1;
|
||||
|
||||
//Now compute the last capture position
|
||||
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
|
||||
lastPreSize = preLength;
|
||||
lastPostSize = postLength;
|
||||
lastLoopCount = 0;
|
||||
lastCapturePinCount = capturePinCount;
|
||||
lastCaptureComplexFast = true;
|
||||
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
|
||||
capturePIO = pio1; //Cannot clear it in PIO1 because the W uses PIO1 to transfer data
|
||||
|
||||
triggerPIO = pio0;
|
||||
|
||||
pio_clear_instruction_memory(triggerPIO);
|
||||
|
||||
//Configure 24 + 2 IO's to be used by the PIO (24 channels + 2 trigger pins)
|
||||
|
@ -665,7 +689,7 @@ bool startCaptureFast(uint32_t freq, uint32_t preLength, uint32_t postLength, co
|
|||
pio_gpio_init(capturePIO, pinMap[i]);
|
||||
|
||||
//Configure capture SM
|
||||
sm_Capture = pio_claim_unused_sm(capturePIO, true);
|
||||
sm_Capture = pio_claim_unused_sm(capturePIO, true);
|
||||
pio_sm_clear_fifos(capturePIO, sm_Capture);
|
||||
pio_sm_restart(capturePIO, sm_Capture);
|
||||
captureOffset = pio_add_program(capturePIO, &FAST_CAPTURE_program);
|
||||
|
@ -802,6 +826,7 @@ bool startCaptureComplex(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
|||
//Store info about the capture
|
||||
lastPreSize = preLength;
|
||||
lastPostSize = postLength;
|
||||
lastLoopCount = 0;
|
||||
lastCapturePinCount = capturePinCount;
|
||||
lastCaptureComplexFast = true;
|
||||
lastCaptureMode = captureMode;
|
||||
|
@ -910,7 +935,7 @@ bool startCaptureComplex(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
|||
|
||||
#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;
|
||||
|
@ -950,6 +975,7 @@ bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
|||
//Store info about the capture
|
||||
lastPreSize = preLength;
|
||||
lastPostSize = postLength;
|
||||
lastLoopCount = loopCount;
|
||||
lastCapturePinCount = capturePinCount;
|
||||
lastTriggerInverted = invertTrigger;
|
||||
lastCaptureComplexFast = false;
|
||||
|
@ -1028,8 +1054,10 @@ bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength,
|
|||
//Enable state machine
|
||||
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);
|
||||
|
||||
|
||||
//Finally clear capture status, process flags and capture type
|
||||
captureFinished = false;
|
||||
|
@ -1048,6 +1076,9 @@ bool IsCapturing()
|
|||
|
||||
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(!captureProcessed)
|
||||
{
|
||||
|
@ -1066,11 +1097,13 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
|||
break;
|
||||
}
|
||||
//Calculate start position
|
||||
if(lastTail < lastPreSize + lastPostSize - 1)
|
||||
lastStartPosition = maxSize - ((lastPreSize + lastPostSize) - (lastTail - 1));
|
||||
if(lastTail < totalSamples - 1)
|
||||
lastStartPosition = (maxSize - totalSamples) + lastTail + 1;
|
||||
else
|
||||
lastStartPosition = lastTail - (lastPreSize + lastPostSize) + 1;
|
||||
lastStartPosition = lastTail - totalSamples + 1;
|
||||
|
||||
uint32_t currentPos = lastStartPosition;
|
||||
|
||||
switch(lastCaptureMode)
|
||||
{
|
||||
case MODE_24_CHANNEL:
|
||||
|
@ -1082,7 +1115,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
|||
|
||||
//Sort channels
|
||||
//(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
|
||||
newValue = 0; //New value
|
||||
|
@ -1110,7 +1143,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
|||
|
||||
//Sort channels
|
||||
//(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
|
||||
newValue = 0; //New value
|
||||
|
@ -1138,7 +1171,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
|||
|
||||
//Sort channels
|
||||
//(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
|
||||
newValue = 0; //New value
|
||||
|
@ -1162,7 +1195,7 @@ uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* ca
|
|||
}
|
||||
//Return data
|
||||
*captureMode = lastCaptureMode;
|
||||
*bufferSize = lastPreSize + lastPostSize;
|
||||
*bufferSize = totalSamples;
|
||||
*firstSample = lastStartPosition;
|
||||
return captureBuffer;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __BUILD_SETTINGS__
|
||||
#define __BUILD_SETTINGS__
|
||||
|
||||
#define FIRMWARE_VERSION "4_5"
|
||||
#define FIRMWARE_VERSION "V5_0"
|
||||
|
||||
//Select the board type to build the firmware for
|
||||
#define BUILD_PICO
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
uint32_t preSamples;
|
||||
//Number of samples stored after the trigger
|
||||
uint32_t postSamples;
|
||||
//Number of capture loops
|
||||
uint8_t loopCount;
|
||||
//Capture mode (0 = 8 channel, 1 = 16 channel, 2 = 24 channel)
|
||||
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>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationIcon>window.ico</ApplicationIcon>
|
||||
<Version>4.5.1.0</Version>
|
||||
<Version>5.0.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -14,17 +14,25 @@ namespace CLCapture
|
|||
{
|
||||
[Value(0, Required = true, HelpText = "Device's serial port or IP address and port.")]
|
||||
public string? AddressPort { get; set; }
|
||||
|
||||
[Value(1, Required = true, HelpText = "Desired sampling frequency.")]
|
||||
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).")]
|
||||
public string? Channels { get; set; }
|
||||
|
||||
[Value(3, Required = true, HelpText = "Number of samples to capture before the trigger.")]
|
||||
public int PreSamples { get; set; }
|
||||
|
||||
[Value(4, Required = true, HelpText = "Number of samples to capture after the trigger.")]
|
||||
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; }
|
||||
[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; }
|
||||
}
|
||||
|
||||
|
|
|
@ -180,8 +180,7 @@ async Task<int> Capture(CLCaptureOptions opts)
|
|||
if (opts.Trigger.TriggerType == CLTriggerType.Edge)
|
||||
{
|
||||
Console.WriteLine("Starting edge triggered capture...");
|
||||
var resStart = driver.StartCapture(opts.SamplingFrequency, opts.PreSamples, opts.PostSamples,
|
||||
nChannels, opts.Trigger.Channel - 1, opts.Trigger.Value == "0", CaptureFinished);
|
||||
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);
|
||||
|
||||
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 PreTriggerSamples { get; set; }
|
||||
public int PostTriggerSamples { get; set; }
|
||||
public int LoopCount { get; set; }
|
||||
public CaptureChannel[] CaptureChannels { get; set; } = new CaptureChannel[0];
|
||||
public int TriggerType { get; set; }
|
||||
public int TriggerChannel { get; set; }
|
||||
public bool TriggerInverted { get; set; }
|
||||
public int TriggerBitCount { get; set; }
|
||||
public ushort TriggerPattern { get; set; }
|
||||
|
||||
public CaptureSettings Clone()
|
||||
{
|
||||
return (CaptureSettings)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
|
||||
public class CaptureChannel
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace LogicAnalyzer.Controls
|
|||
|
||||
newChannelLabel.Text = channels[buc].TextualChannelNumber;
|
||||
|
||||
newChannelLabel.Foreground = GraphicObjectsCache.GetBrush(AnalyzerColors.FgChannelColors[buc]);
|
||||
newChannelLabel.Foreground = GraphicObjectsCache.GetBrush(AnalyzerColors.FgChannelColors[buc % 24]);
|
||||
|
||||
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;
|
||||
|
||||
public int PreSamples { get; set; }
|
||||
public int[]? Bursts { get; set; }
|
||||
public UInt128[] Samples { get; set; }
|
||||
public int ChannelCount { get; set; }
|
||||
public int SamplesInScreen { get; set; }
|
||||
|
@ -32,7 +33,9 @@ namespace LogicAnalyzer.Controls
|
|||
Color sampleLineColor = Color.FromRgb(60, 60, 60);
|
||||
Color sampleDashColor = Color.FromArgb(60, 60, 60, 60);
|
||||
Color triggerLineColor = Colors.White;
|
||||
Color burstLineColor = Colors.Azure;
|
||||
Color userLineColor = Colors.Cyan;
|
||||
|
||||
public SampleViewer()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
@ -101,7 +104,7 @@ namespace LogicAnalyzer.Controls
|
|||
{
|
||||
//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;
|
||||
|
||||
double channelHeight = thisBounds.Height / (double)ChannelCount;
|
||||
|
@ -148,6 +151,14 @@ namespace LogicAnalyzer.Controls
|
|||
if (buc == PreSamples)
|
||||
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)
|
||||
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="rbTrigger24"></RadioButton>
|
||||
</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>
|
||||
<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">
|
||||
|
|
|
@ -178,6 +178,7 @@ namespace LogicAnalyzer.Dialogs
|
|||
Frequency = oldset.Frequency,
|
||||
PostTriggerSamples = oldset.PostTriggerSamples,
|
||||
PreTriggerSamples = oldset.PreTriggerSamples,
|
||||
LoopCount = 0,
|
||||
TriggerBitCount = oldset.TriggerBitCount,
|
||||
TriggerChannel = oldset.TriggerChannel,
|
||||
TriggerInverted = oldset.TriggerInverted,
|
||||
|
@ -216,6 +217,8 @@ namespace LogicAnalyzer.Dialogs
|
|||
|
||||
triggerChannels[settings.TriggerChannel].IsChecked = true;
|
||||
ckNegativeTrigger.IsChecked = settings.TriggerInverted;
|
||||
ckBurst.IsChecked = settings.LoopCount > 0;
|
||||
nudBurstCount.Value = settings.LoopCount > 0 ? settings.LoopCount : 1;
|
||||
|
||||
rbTriggerTypePattern.IsChecked = false;
|
||||
rbTriggerTypeEdge.IsChecked = true;
|
||||
|
@ -280,7 +283,9 @@ namespace LogicAnalyzer.Dialogs
|
|||
|
||||
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}.");
|
||||
return;
|
||||
|
@ -385,6 +390,7 @@ namespace LogicAnalyzer.Dialogs
|
|||
settings.Frequency = (int)nudFrequency.Value;
|
||||
settings.PreTriggerSamples = (int)nudPreSamples.Value;
|
||||
settings.PostTriggerSamples = (int)nudPostSamples.Value;
|
||||
settings.LoopCount = loops;
|
||||
settings.TriggerInverted = ckNegativeTrigger.IsChecked == true;
|
||||
settings.CaptureChannels = channelsToCapture.ToArray();
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationIcon>Assets\Ico40.ico</ApplicationIcon>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<Version>4.5.1.0</Version>
|
||||
<Version>5.0.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove=".gitignore" />
|
||||
|
|
|
@ -46,8 +46,10 @@
|
|||
</TextBlock>
|
||||
<controls:SampleMarker Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Foreground="White" Background="Transparent" Name="sampleMarker"></controls:SampleMarker>
|
||||
</Grid>
|
||||
|
||||
|
||||
<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">
|
||||
<ScrollViewer VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<Grid ColumnDefinitions="140,*" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Threading;
|
||||
using AvaloniaEdit.Utils;
|
||||
|
@ -64,16 +65,115 @@ namespace LogicAnalyzer
|
|||
|
||||
tkInScreen.PropertyChanged += tkInScreen_ValueChanged;
|
||||
scrSamplePos.Scroll += scrSamplePos_ValueChanged;
|
||||
scrSamplePos.PointerEnter += ScrSamplePos_PointerEnter;
|
||||
scrSamplePos.PointerLeave += ScrSamplePos_PointerLeave;
|
||||
mnuNew.Click += MnuNew_Click;
|
||||
mnuOpen.Click += mnuOpen_Click;
|
||||
mnuSave.Click += mnuSave_Click;
|
||||
mnuExit.Click += MnuExit_Click;
|
||||
mnuExport.Click += MnuExport_Click;
|
||||
mnuNetSettings.Click += MnuNetSettings_Click;
|
||||
|
||||
AddHandler(InputElement.KeyDownEvent, MainWindow_KeyDown, handledEventsToo: true);
|
||||
|
||||
LoadAnalyzers();
|
||||
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)
|
||||
{
|
||||
var dlg = new ShiftChannelsDialog();
|
||||
|
@ -81,7 +181,7 @@ namespace LogicAnalyzer
|
|||
|
||||
if (await dlg.ShowDialog<bool>(this))
|
||||
{
|
||||
var samples = sampleViewer.Samples;
|
||||
var samples = sampleViewer.Samples;
|
||||
|
||||
foreach (var channel in dlg.ShiftedChannels)
|
||||
{
|
||||
|
@ -120,6 +220,8 @@ namespace LogicAnalyzer
|
|||
sampleViewer.BeginUpdate();
|
||||
sampleViewer.Samples = samples;
|
||||
sampleViewer.EndUpdate();
|
||||
samplePreviewer.UpdateSamples(samples, sampleViewer.ChannelCount);
|
||||
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,6 +297,9 @@ namespace LogicAnalyzer
|
|||
|
||||
sampleViewer.EndUpdate();
|
||||
|
||||
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||
samplePreviewer.UpdateSamples(samples, sampleViewer.ChannelCount);
|
||||
|
||||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
sampleMarker.ClearRegions();
|
||||
|
@ -331,14 +436,6 @@ namespace LogicAnalyzer
|
|||
var lastSample = e.FirstSample + e.SampleCount - 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 postDelete = sampleViewer.Samples.Skip(e.FirstSample + e.SampleCount + 1);
|
||||
|
||||
|
@ -412,7 +509,8 @@ namespace LogicAnalyzer
|
|||
{
|
||||
sampleViewer.BeginUpdate();
|
||||
sampleViewer.Samples = finalSamples;
|
||||
sampleViewer.PreSamples = finalPreSamples;
|
||||
sampleViewer.PreSamples = 0;
|
||||
sampleViewer.Bursts = null;
|
||||
|
||||
if (sampleViewer.FirstSample > finalSamples.Length - 1)
|
||||
sampleViewer.FirstSample = finalSamples.Length - 1;
|
||||
|
@ -425,6 +523,9 @@ namespace LogicAnalyzer
|
|||
|
||||
sampleViewer.EndUpdate();
|
||||
|
||||
samplePreviewer.UpdateSamples(finalSamples, sampleViewer.ChannelCount);
|
||||
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||
|
||||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
sampleMarker.ClearRegions();
|
||||
|
@ -569,10 +670,30 @@ namespace LogicAnalyzer
|
|||
sampleViewer.SamplesInScreen = Math.Min(100, e.Samples.Length / 10);
|
||||
|
||||
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.ClearAnalyzedChannels();
|
||||
sampleViewer.EndUpdate();
|
||||
|
||||
samplePreviewer.UpdateSamples(e.Samples, sampleViewer.ChannelCount);
|
||||
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||
|
||||
scrSamplePos.Maximum = e.Samples.Length - 1;
|
||||
scrSamplePos.Value = sampleViewer.FirstSample;
|
||||
tkInScreen.Value = sampleViewer.SamplesInScreen;
|
||||
|
@ -844,7 +965,7 @@ namespace LogicAnalyzer
|
|||
}
|
||||
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)
|
||||
{
|
||||
|
@ -878,7 +999,15 @@ namespace LogicAnalyzer
|
|||
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)
|
||||
{
|
||||
if (sampleViewer.Samples != null)
|
||||
|
@ -886,6 +1015,7 @@ namespace LogicAnalyzer
|
|||
sampleViewer.BeginUpdate();
|
||||
sampleViewer.FirstSample = (int)scrSamplePos.Value;
|
||||
sampleViewer.EndUpdate();
|
||||
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
}
|
||||
}
|
||||
|
@ -927,7 +1057,11 @@ namespace LogicAnalyzer
|
|||
if (string.IsNullOrWhiteSpace(file))
|
||||
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() }));
|
||||
}
|
||||
|
@ -980,6 +1114,7 @@ namespace LogicAnalyzer
|
|||
Frequency = oldset.Frequency,
|
||||
PostTriggerSamples = oldset.PostTriggerSamples,
|
||||
PreTriggerSamples = oldset.PreTriggerSamples,
|
||||
LoopCount = 0,
|
||||
TriggerBitCount = oldset.TriggerBitCount,
|
||||
TriggerChannel = oldset.TriggerChannel,
|
||||
TriggerInverted = oldset.TriggerInverted,
|
||||
|
@ -1015,6 +1150,9 @@ namespace LogicAnalyzer
|
|||
|
||||
sampleViewer.EndUpdate();
|
||||
|
||||
samplePreviewer.UpdateSamples(ex.Samples, sampleViewer.ChannelCount);
|
||||
samplePreviewer.ViewPosition = sampleViewer.FirstSample;
|
||||
|
||||
sampleMarker.VisibleSamples = sampleViewer.SamplesInScreen;
|
||||
sampleMarker.FirstSample = sampleViewer.FirstSample;
|
||||
sampleMarker.ClearRegions();
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace SharedDriver
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace SharedDriver
|
|||
public int Channels { get; }
|
||||
public event EventHandler<CaptureEventArgs> CaptureCompleted;
|
||||
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 bool StopCapture();
|
||||
public CaptureLimits GetLimits(int[] Channels);
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace SharedDriver
|
|||
{
|
||||
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]+)");
|
||||
StreamReader readResponse;
|
||||
BinaryReader readData;
|
||||
|
@ -74,7 +75,26 @@ namespace SharedDriver
|
|||
|
||||
baseStream.ReadTimeout = 10000;
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
private void InitNetwork(string AddressPort)
|
||||
{
|
||||
|
@ -138,7 +158,7 @@ namespace SharedDriver
|
|||
|
||||
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)
|
||||
|
@ -159,25 +179,27 @@ namespace SharedDriver
|
|||
|
||||
var captureMode = GetCaptureMode(Channels);
|
||||
|
||||
int requestedSamples = PreSamples + (PostSamples * ((byte)LoopCount + 1));
|
||||
|
||||
try
|
||||
{
|
||||
switch (captureMode)
|
||||
{
|
||||
case 0:
|
||||
|
||||
if (PreSamples > 98303 || PostSamples > 131069 || PreSamples + PostSamples > 131071)
|
||||
if (PreSamples > 98303 || PostSamples > 131069 || requestedSamples > 131071)
|
||||
return CaptureError.BadParams;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
if (PreSamples > 49151 || PostSamples > 65533 || PreSamples + PostSamples > 65535)
|
||||
if (PreSamples > 49151 || PostSamples > 65533 || requestedSamples > 65535)
|
||||
return CaptureError.BadParams;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
if (PreSamples > 24576 || PostSamples > 32765 || PreSamples + PostSamples > 32767)
|
||||
if (PreSamples > 24576 || PostSamples > 32765 || requestedSamples > 32767)
|
||||
return CaptureError.BadParams;
|
||||
break;
|
||||
}
|
||||
|
@ -197,6 +219,7 @@ namespace SharedDriver
|
|||
frequency = (uint)Frequency,
|
||||
preSamples = (uint)PreSamples,
|
||||
postSamples = (uint)PostSamples,
|
||||
loopCount = (byte)LoopCount,
|
||||
captureMode = captureMode
|
||||
};
|
||||
|
||||
|
@ -217,7 +240,7 @@ namespace SharedDriver
|
|||
if (result == "CAPTURE_STARTED")
|
||||
{
|
||||
capturing = true;
|
||||
Task.Run(() => ReadCapture(PreSamples + PostSamples, captureMode));
|
||||
Task.Run(() => ReadCapture(requestedSamples, captureMode));
|
||||
return CaptureError.None;
|
||||
}
|
||||
return CaptureError.HardwareError;
|
||||
|
@ -547,6 +570,7 @@ namespace SharedDriver
|
|||
public UInt32 frequency;
|
||||
public UInt32 preSamples;
|
||||
public UInt32 postSamples;
|
||||
public byte loopCount;
|
||||
public byte captureMode;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace SharedDriver
|
|||
{
|
||||
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;
|
||||
|
||||
UInt128[][]? tempCapture;
|
||||
|
@ -79,7 +79,24 @@ namespace SharedDriver
|
|||
}
|
||||
|
||||
if (ver == null)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (ver != mVer.Groups[1].Value)
|
||||
|
@ -96,7 +113,7 @@ namespace SharedDriver
|
|||
{
|
||||
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();
|
||||
}
|
||||
|
@ -163,7 +180,7 @@ namespace SharedDriver
|
|||
continue;
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user