7
mirror of https://github.com/EEVengers/ThunderScope.git synced 2025-04-22 17:43:44 +00:00

Merge pull request from profezzorn/scope_link_linux_support

initial linux support
This commit is contained in:
Aleksa Bjelogrlic 2021-12-28 22:15:25 -05:00 committed by GitHub
commit 4e96caf224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 42 deletions
Software/waveview/scope_link

View File

@ -13,7 +13,7 @@ CPPOPT := -fopt-info-loop-optimized
CPPMISS := -fopt-info-vec-missed
CFLAGS := -Wall
LDFLAGS := -Llib
LDLIBS := -lm -lftd3xx -lstdc++ -pthread -lboost_system -lboost_thread
LDLIBS := -lm -lstdc++ -pthread -lboost_system -lboost_thread
LDLIBS += -lpthread -lboost_log_setup -lboost_log
.PHONY: all clean

View File

@ -1,5 +1,3 @@
#ifndef PCIe_HPP
#define PCIe_HPP
@ -7,17 +5,29 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <strsafe.h>
#include <thread>
#include <chrono>
#ifdef WIN32
#include <strsafe.h>
#include <Windows.h>
#include <SetupAPI.h>
#include <INITGUID.H>
#include <WinIoCtl.h>
#include "xdma_public.h"
#endif
#ifdef __linux__
#define HANDLE int
#define INVALID_HANDLE_VALUE -1
#endif
#include "common.hpp"
#ifdef WIN32
#pragma comment(lib, "setupapi.lib")
#endif
#define USER_DEVICE_PATH "user"
#define C2H_0_DEVICE_PATH "c2h_0"
@ -121,11 +131,10 @@ private:
char user_device[20] = USER_DEVICE_PATH; //write/read registers
char c2h_0_device[20] = C2H_0_DEVICE_PATH; //read memory
HANDLE user_handle;
HANDLE user_handle = INVALID_HANDLE_VALUE;
char user_connection_string[261] = "";
HANDLE c2h_0_handle;
HANDLE c2h_0_handle = INVALID_HANDLE_VALUE;
char c2h_0_connection_string[261] = "";
LARGE_INTEGER freq; //used for perforamnce testing
int64_t last_chunk_read;
//current state
@ -139,8 +148,8 @@ private:
boost::lockfree::queue<buffer*, boost::lockfree::fixed_sized<false>> *outputQueue;
//used for speed testing
LARGE_INTEGER tick1;
LARGE_INTEGER tick2;
std::chrono::high_resolution_clock::time_point tick1;
std::chrono::high_resolution_clock::time_point tick2;
void _Read(HANDLE hPCIE, long long address, uint8_t* buff, int bytesToRead);
void _Write(HANDLE hPCIE, long long address, uint8_t* buff, int bytesToWrite);
@ -165,4 +174,4 @@ protected:
};
#endif
#endif

View File

@ -1,15 +1,23 @@
#include "PCIe.hpp"
#include "logger.hpp"
#ifdef __linux__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#endif
#ifdef WIN32
/*
* get_devices -- Ripped from Xilinx examples
* returns the number of XDMA devices
*/
static int get_devices(GUID guid, char* devpath, size_t len_devpath) {
HDEVINFO device_info = SetupDiGetClassDevs((LPGUID)&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (device_info == INVALID_HANDLE_VALUE) {
fprintf(stderr, "GetDevices INVALID_HANDLE_VALUE\n");
@ -22,7 +30,6 @@ static int get_devices(GUID guid, char* devpath, size_t len_devpath) {
// enumerate through devices
DWORD index;
for (index = 0; SetupDiEnumDeviceInterfaces(device_info, NULL, &guid, index, &device_interface); ++index) {
#ifdef WIN32 //So i dont know how to change this is work on unix, since HeapAlloc is windows specific, so since Unix does not work with PCIe yet, just ingore this code
// get required buffer size
ULONG detailLength = 0;
if (!SetupDiGetDeviceInterfaceDetail(device_info, &device_interface, NULL, 0, &detailLength, NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
@ -45,7 +52,6 @@ static int get_devices(GUID guid, char* devpath, size_t len_devpath) {
}
StringCchCopy(devpath, len_devpath, dev_detail->DevicePath);
HeapFree(GetProcessHeap(), 0, dev_detail);
#endif
}
SetupDiDestroyDeviceInfoList(device_info);
@ -111,9 +117,38 @@ int PCIeLink::Connect() {
}
return status;
}
#endif
#ifdef __linux__
#define CloseHandle(X) close(X)
static int OpenHelper(int n, const char* postfix) {
char device_path[128];
snprintf(device_path, sizeof(device_path), "/dev/xdma%d_%s", n, postfix);
int fd = open(device_path, O_RDWR);
if (fd < 0) {
perror("open");
fprintf(stderr, "failed to open: %s, errno=%d\n", device_path, errno);
}
return fd;
}
int PCIeLink::Connect() {
int device_num = 0;
connected = false;
user_handle = OpenHelper(device_num, USER_DEVICE_PATH);
if (user_handle <= 0) return -1;
c2h_0_handle = OpenHelper(device_num, C2H_0_DEVICE_PATH);
if (c2h_0_handle <= 0) return -1;
connected = true;
return 0;
}
#endif
/************************************************************
* Read()
* Takes in an 8MegaByte buffer (2^23 bytes) and fills it with adc data read from the board
@ -480,7 +515,9 @@ void PCIeLink::_FIFO_WRITE(HANDLE hPCIE, uint8_t* data, uint8_t bytesToWrite) {
_Read(user_handle,SERIAL_FIFO_TDFV_ADDRESS,tdfvBuff,4);
}
void PCIeLink::_Read(HANDLE hPCIE, int64_t address, uint8_t* buff, int bytesToRead) {
#ifdef WIN32
void PCIeLink::_Read(HANDLE hPCIE, long long address, uint8_t* buff, int bytesToRead) {
if(hPCIE == INVALID_HANDLE_VALUE) {
ERROR << "INVALID HANDLE PASSED INTO PCIeLink::_Read(): " << hPCIE;
return;
@ -500,7 +537,7 @@ void PCIeLink::_Read(HANDLE hPCIE, int64_t address, uint8_t* buff, int bytesToRe
}
}
void PCIeLink::_Write(HANDLE hPCIE, int64_t address, uint8_t* buff, int bytesToWrite) {
void PCIeLink::_Write(HANDLE hPCIE, long long address, uint8_t* buff, int bytesToWrite) {
if(hPCIE == INVALID_HANDLE_VALUE) {
ERROR << "INVALID HANDLE PASSED INTO PCIeLink::_Write(): " << hPCIE;
return;
@ -519,35 +556,43 @@ void PCIeLink::_Write(HANDLE hPCIE, int64_t address, uint8_t* buff, int bytesToW
ERROR << "_Write() failed with Win32 error code: " << GetLastError();
}
}
#endif
#ifdef __linux__
void PCIeLink::_Read(HANDLE hPCIE, long long address, uint8_t* buff, int bytesToRead) {
// TODO: EINTR handling if needed.
ssize_t ret = pread(hPCIE, buff, bytesToRead, address);
if (ret != bytesToRead) {
perror("pread");
}
}
void PCIeLink::_Write(HANDLE hPCIE, long long address, uint8_t* buff, int bytesToWrite) {
// TODO: EINTR handling if needed.
ssize_t ret = pwrite(hPCIE, buff, bytesToWrite, address);
if (ret != bytesToWrite) {
perror("pwrite");
}
}
#endif
void PCIeLink::_Write32(HANDLE hPCIE, long long address, uint32_t val) {
if(hPCIE == INVALID_HANDLE_VALUE) {
ERROR << "INVALID HANDLE PASSED INTO PCIeLink::_Write(): " << hPCIE;
return;
}
LARGE_INTEGER offset;
offset.QuadPart = address;
// set file pointer to offset of target address within PCIe BAR
if (INVALID_SET_FILE_POINTER == SetFilePointerEx(hPCIE, offset, NULL, FILE_BEGIN)) {
ERROR << "Error setting file pointer for PCIeLink::_Write(), win32 error code: " << GetLastError();
}
// write from buffer to device
DWORD bytesWritten;
uint8_t bytes[4];
bytes[3] = (uint8_t)( (val & 0xFF000000) >> 24);
bytes[2] = (uint8_t)( (val & 0x00FF0000) >> 16);
bytes[1] = (uint8_t)( (val & 0x0000FF00) >> 8);
bytes[0] = (uint8_t)( (val & 0x000000FF));
if (!WriteFile(hPCIE, bytes, 4, &bytesWritten, NULL)) {
ERROR << "_Write() failed with Win32 error code: " << GetLastError();
}
_Write(hPCIE, address, bytes, 4);
}
void PCIeLink::_Job() {
bool priority = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
#ifdef WIN32
bool priority = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
INFO << "THREAD_PRIORITY_TIME_CRITICAL: " << priority;
#endif
while(_run.load()) {
while(_pause.load()) {
std::this_thread::sleep_for(std::chrono::microseconds(100));
@ -573,7 +618,6 @@ PCIeLink::PCIeLink(boost::lockfree::queue<buffer*, boost::lockfree::fixed_sized<
user_handle = INVALID_HANDLE_VALUE;
c2h_0_handle = INVALID_HANDLE_VALUE;
last_chunk_read = -1;
QueryPerformanceFrequency(&freq);
this->outputQueue = outputQueue;
//keep the read thread alive but paused
_run = true;
@ -660,11 +704,11 @@ PCIeLink::~PCIeLink() {
}
void PCIeLink::ClockTick1() {
QueryPerformanceCounter(&tick1);
tick1 = std::chrono::high_resolution_clock::now();
}
void PCIeLink::ClockTick2() {
QueryPerformanceCounter(&tick2);
tick2 = std::chrono::high_resolution_clock::now();
}
/************************************************************
@ -675,15 +719,13 @@ void PCIeLink::ClockTick2() {
*
*************************************************************/
void PCIeLink::PrintTimeDelta() {
double time_sec = (unsigned long long)(tick2.QuadPart - tick1.QuadPart) / (double)freq.QuadPart;
INFO << "Time Delta is: " << time_sec;
INFO << "Time Delta is: " << GetTimeDelta();
}
double PCIeLink::GetTimeDelta() {
return (unsigned long long)(tick2.QuadPart - tick1.QuadPart) / (double)freq.QuadPart;
return std::chrono::duration_cast<std::chrono::nanoseconds>(tick2 - tick1).count() / 1000000000.0;
}
/************************************************************************ SCOPE CONTROL STUFF ***********************************************/
int PCIeLink::_ch_on(int ch_num){