Added initial support for HID DMM
This commit is contained in:
parent
426976cbde
commit
023b9a3100
2
98-hidraw.rules
Normal file
2
98-hidraw.rules
Normal file
@ -0,0 +1,2 @@
|
||||
#Allow all to read hidraws
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"
|
||||
448
DMM_HID.cpp
Normal file
448
DMM_HID.cpp
Normal file
@ -0,0 +1,448 @@
|
||||
#include "DMM_HID.h"
|
||||
|
||||
#include <linux/hidraw.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <poll.h>
|
||||
#include <limits>
|
||||
|
||||
#define VENDOR_ID 0x2571
|
||||
#define PRODUCT_ID 0x4100
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
constexpr int DMM_BUFSIZE = 8;
|
||||
|
||||
// Checks if a hidraw device matches the vendor id and product id
|
||||
// If *_id is < 0 - it is not checked
|
||||
bool check_hidraw_device(string dev, int vendor_id, int product_id)
|
||||
{
|
||||
int fd;
|
||||
int res;
|
||||
struct hidraw_devinfo info;
|
||||
bool result = false;
|
||||
bool vendor = true;
|
||||
bool product = true;
|
||||
|
||||
fd = open(dev.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
// Get Raw Info
|
||||
res = ioctl(fd, HIDIOCGRAWINFO, &info);
|
||||
if (res >= 0)
|
||||
{
|
||||
if ((vendor_id > 0) && (vendor_id != info.vendor))
|
||||
{
|
||||
vendor = false;
|
||||
}
|
||||
|
||||
if ((product_id > 0) && (product_id != info.product))
|
||||
{
|
||||
product = false;
|
||||
}
|
||||
|
||||
if (vendor && product)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Reads exact number of bytes from a fd for X milisec
|
||||
bool read_exact(int fd, uint8_t *buf, int size, int timeout_ms)
|
||||
{
|
||||
struct pollfd poll_fd;
|
||||
int bytes;
|
||||
int bytes_read;
|
||||
|
||||
if ((fd < 0) || (nullptr == buf) || (size <= 0) || (timeout_ms <= 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
poll_fd.fd = fd;
|
||||
poll_fd.events = POLLIN;
|
||||
|
||||
bytes_read = 0;
|
||||
while (bytes_read < size)
|
||||
{
|
||||
bytes = poll(&poll_fd, 1, timeout_ms);
|
||||
if (bytes < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes = read(fd, buf + bytes_read, size - bytes_read);
|
||||
if (bytes < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_read += bytes;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
vector<string> DMM_HID::get_dmm_devices()
|
||||
{
|
||||
vector<string> result;
|
||||
struct udev *udev_handle = nullptr;
|
||||
struct udev_enumerate *udev_enum_handle = nullptr;
|
||||
struct udev_list_entry *udev_entry = nullptr;
|
||||
struct udev_device *device = nullptr;
|
||||
const char *syspath = nullptr;
|
||||
string path;
|
||||
int err;
|
||||
|
||||
// Create udev
|
||||
udev_handle = udev_new();
|
||||
if (nullptr == udev_handle)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create enumerator
|
||||
udev_enum_handle = udev_enumerate_new(udev_handle);
|
||||
if (nullptr == udev_enum_handle)
|
||||
{
|
||||
goto udev_out;
|
||||
}
|
||||
|
||||
// Search only for "hidraw" devices
|
||||
err = udev_enumerate_add_match_subsystem(udev_enum_handle, "hidraw");
|
||||
if (err < 0)
|
||||
{
|
||||
goto udev_out;
|
||||
}
|
||||
|
||||
// Scan devices
|
||||
err = udev_enumerate_scan_devices(udev_enum_handle);
|
||||
if (err < 0)
|
||||
{
|
||||
goto udev_out;
|
||||
}
|
||||
|
||||
udev_entry = udev_enumerate_get_list_entry(udev_enum_handle);
|
||||
if (nullptr == udev_entry)
|
||||
{
|
||||
goto udev_out;
|
||||
}
|
||||
|
||||
// Iterate through devices
|
||||
while (nullptr != udev_entry)
|
||||
{
|
||||
// Name is syspath
|
||||
syspath = udev_list_entry_get_name(udev_entry);
|
||||
if (nullptr != syspath)
|
||||
{
|
||||
device = udev_device_new_from_syspath(udev_handle, syspath);
|
||||
if (nullptr != device)
|
||||
{
|
||||
// devnode is needed /dev/hidraw* path
|
||||
path = udev_device_get_devnode(device);
|
||||
|
||||
// Check vendor id and product id pair
|
||||
// There's no exit from the loop
|
||||
// so it will return the last found device
|
||||
if (check_hidraw_device(path, VENDOR_ID, PRODUCT_ID))
|
||||
{
|
||||
result.push_back(path);
|
||||
}
|
||||
|
||||
udev_device_unref(device);
|
||||
}
|
||||
}
|
||||
udev_entry = udev_list_entry_get_next(udev_entry);
|
||||
}
|
||||
|
||||
udev_out:
|
||||
// Cleanup
|
||||
if (nullptr != udev_enum_handle)
|
||||
{
|
||||
udev_enumerate_unref(udev_enum_handle);
|
||||
}
|
||||
udev_unref(udev_handle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DMM_HID::DMM_HID()
|
||||
:m_fd(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DMM_HID::~DMM_HID()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void DMM_HID::Open(const std::string& dev)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (is_open())
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
fd = open(dev.c_str(), O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_fd = fd;
|
||||
}
|
||||
|
||||
void DMM_HID::Close()
|
||||
{
|
||||
if (is_open())
|
||||
{
|
||||
close(m_fd);
|
||||
}
|
||||
|
||||
m_fd = -1;
|
||||
}
|
||||
|
||||
bool DMM_HID::is_open()
|
||||
{
|
||||
if (m_fd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<Reading> DMM_HID::get_readings(int timeout_ms)
|
||||
{
|
||||
vector<Reading> result;
|
||||
uint8_t buf[DMM_BUFSIZE];
|
||||
Reading reading;
|
||||
|
||||
if (m_fd < 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
while(read_exact(m_fd, buf, DMM_BUFSIZE, timeout_ms))
|
||||
{
|
||||
reading.value[0] = 0;
|
||||
reading.value[1] = 0;
|
||||
reading.value[2] = 0;
|
||||
reading.value[3] = 0;
|
||||
reading.modifier = 0;
|
||||
reading.dot_pos = 0;
|
||||
reading.is_inf = false;
|
||||
reading.is_neg = false;
|
||||
reading.is_DC = false;
|
||||
reading.is_rel = false;
|
||||
reading.is_hold = false;
|
||||
reading.is_min = false;
|
||||
reading.is_max = false;
|
||||
reading.type = Reading::reading_type_max;
|
||||
|
||||
// Check for infinity
|
||||
if ((0x4F == buf[1]) && (0x4C == buf[2]))
|
||||
{
|
||||
reading.is_inf = true;
|
||||
}
|
||||
|
||||
// BCD 4-bit values
|
||||
reading.value[0] = (buf[1] >> 4);
|
||||
reading.value[1] = (buf[1] & 0x0F);
|
||||
reading.value[2] = (buf[2] >> 4);
|
||||
reading.value[3] = (buf[2] & 0x0F);
|
||||
|
||||
// Byte 0 Bit 6 - Negative
|
||||
if (buf[0] & 0x40)
|
||||
{
|
||||
reading.is_neg = true;
|
||||
}
|
||||
|
||||
// Byte 0 second half - Dot position
|
||||
{
|
||||
switch (buf[0] & 0x0F)
|
||||
{
|
||||
case 0:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case 1:
|
||||
reading.dot_pos = 1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
reading.dot_pos = 2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
reading.dot_pos = 3;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
reading.dot_pos = 3;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
// Assuming 3&4 overlap
|
||||
reading.dot_pos = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Unit Modifier
|
||||
{
|
||||
// Byte 4 Bit 1
|
||||
if (buf[4] & 0x02)
|
||||
{
|
||||
// nano = 10^-9
|
||||
reading.modifier = -9;
|
||||
}
|
||||
// Byte 5 Bit 7
|
||||
else if (buf[5] & 0x80)
|
||||
{
|
||||
// micro = 10^-6
|
||||
reading.modifier = -6;
|
||||
}
|
||||
// Byte 5 Bit 6
|
||||
else if (buf[5] & 0x40)
|
||||
{
|
||||
// mili = 10^-3
|
||||
reading.modifier = -3;
|
||||
}
|
||||
// Byte 5 Bit 5
|
||||
else if (buf[5] & 0x20)
|
||||
{
|
||||
// kilo = 10^3
|
||||
reading.modifier = 3;
|
||||
}
|
||||
// Byte 5 Bit 4
|
||||
else if (buf[5] & 0x10)
|
||||
{
|
||||
// mega = 10^6
|
||||
reading.modifier = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// AC/DC
|
||||
// Byte 3 Bit 4
|
||||
if (buf[3] & 0x10)
|
||||
{
|
||||
reading.is_DC = true;
|
||||
}
|
||||
|
||||
// Hold / min / max / rel
|
||||
{
|
||||
// Byte 3 Bit 1
|
||||
if (buf[3] & 0x02)
|
||||
{
|
||||
reading.is_hold = true;
|
||||
}
|
||||
|
||||
// Byte 3 Bit 2
|
||||
if (buf[3] & 0x04)
|
||||
{
|
||||
reading.is_rel = true;
|
||||
}
|
||||
|
||||
// Byte 4 Bit 5
|
||||
if (buf[4] & 0x20)
|
||||
{
|
||||
reading.is_max = true;
|
||||
}
|
||||
|
||||
// Byte 4 Bit 4
|
||||
if (buf[4] & 0x10)
|
||||
{
|
||||
reading.is_min = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Reading type
|
||||
{
|
||||
// if (buf[5] & 0x08)
|
||||
// {
|
||||
// reading.type = Reading::reading_continuity;
|
||||
// }
|
||||
// else if (buf[5] & 0x04)
|
||||
// {
|
||||
// reading.type = Reading::reading_diode;
|
||||
// }
|
||||
// else
|
||||
if (buf[5] & 0x02)
|
||||
{
|
||||
reading.type = Reading::reading_percent;
|
||||
}
|
||||
else if (buf[6] & 0x80)
|
||||
{
|
||||
reading.type = Reading::reading_volts;
|
||||
}
|
||||
else if (buf[6] & 0x40)
|
||||
{
|
||||
reading.type = Reading::reading_amps;
|
||||
}
|
||||
else if (buf[6] & 0x20)
|
||||
{
|
||||
reading.type = Reading::reading_ohms;
|
||||
}
|
||||
else if (buf[6] & 0x10)
|
||||
{
|
||||
reading.type = Reading::reading_hFE;
|
||||
}
|
||||
else if (buf[6] & 0x08)
|
||||
{
|
||||
reading.type = Reading::reading_hertz;
|
||||
}
|
||||
else if (buf[6] & 0x04)
|
||||
{
|
||||
reading.type = Reading::reading_farads;
|
||||
}
|
||||
else if (buf[6] & 0x02)
|
||||
{
|
||||
reading.type = Reading::reading_celsius;
|
||||
}
|
||||
else if (buf[6] & 0x01)
|
||||
{
|
||||
reading.type = Reading::reading_fahrenheit;
|
||||
}
|
||||
}
|
||||
|
||||
result.push_back(reading);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DMM_HID::lock()
|
||||
{
|
||||
m_mutex.lock();
|
||||
}
|
||||
|
||||
void DMM_HID::unlock()
|
||||
{
|
||||
m_mutex.unlock();
|
||||
}
|
||||
75
DMM_HID.h
Normal file
75
DMM_HID.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef DMM_HID_H_
|
||||
#define DMM_HID_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
constexpr int DMM_TIMEOUT_MS = 100;
|
||||
|
||||
struct Reading
|
||||
{
|
||||
enum reading_type
|
||||
{
|
||||
reading_continuity,
|
||||
reading_diode,
|
||||
reading_percent,
|
||||
reading_volts,
|
||||
reading_amps,
|
||||
reading_ohms,
|
||||
reading_hFE,
|
||||
reading_hertz,
|
||||
reading_farads,
|
||||
reading_celsius,
|
||||
reading_fahrenheit,
|
||||
reading_type_max
|
||||
};
|
||||
|
||||
uint8_t value[4];
|
||||
int8_t modifier;
|
||||
uint8_t dot_pos;
|
||||
bool is_inf;
|
||||
bool is_neg;
|
||||
bool is_DC;
|
||||
bool is_rel;
|
||||
bool is_hold;
|
||||
bool is_min;
|
||||
bool is_max;
|
||||
reading_type type;
|
||||
};
|
||||
|
||||
class DMM_HID
|
||||
{
|
||||
private:
|
||||
// File descriptor to DMM device
|
||||
int m_fd;
|
||||
|
||||
std::mutex m_mutex;
|
||||
|
||||
public:
|
||||
DMM_HID();
|
||||
~DMM_HID();
|
||||
|
||||
// Opens the dev file and prepares to get readings
|
||||
// Returns true on success, false on failure
|
||||
void Open(const std::string& dev);
|
||||
|
||||
// Closes the dev file
|
||||
void Close();
|
||||
|
||||
bool is_open();
|
||||
|
||||
// Returns all readings since opening or since last call
|
||||
std::vector<Reading> get_readings(int timeout_ms = DMM_TIMEOUT_MS);
|
||||
|
||||
// Returns all devpaths to DMM devices
|
||||
static std::vector<std::string> get_dmm_devices();
|
||||
|
||||
// Locks the mutex
|
||||
void lock();
|
||||
|
||||
// Unlocks the mutex
|
||||
void unlock();
|
||||
};
|
||||
|
||||
#endif // DMM_H_
|
||||
24
Makefile
Normal file
24
Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
src_hid += main_hid.cpp
|
||||
src_hid += DMM_HID.cpp
|
||||
src_hid += common.cpp
|
||||
|
||||
#src_serial += main_serial.cpp
|
||||
#src_serial += DMM_Serial.cpp
|
||||
#src_serial += common.cpp
|
||||
|
||||
libs += -lSDL2
|
||||
libs += -lSDL2_ttf
|
||||
|
||||
libs_hid += -ludev
|
||||
|
||||
all:
|
||||
make hid
|
||||
# make serial
|
||||
|
||||
hid:
|
||||
g++ -o dmm_hid ${src_hid} ${libs} ${libs_hid} -DUSE_HID -Wall -Wextra -Wpedantic
|
||||
|
||||
#serial:
|
||||
# g++ -o dmm_serial ${src_serial} ${libs} -DUSE_Serial -Wall -Wextra -Wpedantic
|
||||
|
||||
.PHONY: all hid serial
|
||||
23
README.md
23
README.md
@ -1,3 +1,22 @@
|
||||
# dmm_display
|
||||
# DMM Display
|
||||
Reads measurements from PeakTech 2025 and uses SDL to display it on screen
|
||||
The DMM has 2 types of interfaces:
|
||||
* HID
|
||||
* Serial
|
||||
|
||||
Reads measurements from PeakTech 2025 and uses SDL to display it on screen
|
||||
# Requirements
|
||||
`sudo apt install libsdl2-dev libsdl2-ttf-dev`
|
||||
|
||||
# Compiling
|
||||
`make hid`
|
||||
or
|
||||
`make serial`
|
||||
|
||||
# Notes
|
||||
When using HID you need to add hidraw rules in order to use without sudo
|
||||
`sudo cp 98-hidraw.rules /etc/udev/rules.d/`
|
||||
`sudo udevadm control --reload-rules`
|
||||
`sudo udevadm trigger`
|
||||
|
||||
# TODO
|
||||
No serial support yet
|
||||
|
||||
207
common.cpp
Normal file
207
common.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
bool init_sdl(SDL_Window **window)
|
||||
{
|
||||
if (nullptr == window)
|
||||
{
|
||||
cout << "Nowhere to store window" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// SDL Initialization
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
{
|
||||
cout << "SDL could not initialize! SDL - " << SDL_GetError() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
(*window) = SDL_CreateWindow("DMM Display",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
1280, 720,
|
||||
SDL_WINDOW_SHOWN);
|
||||
if (nullptr == (*window))
|
||||
{
|
||||
cout << "Window could not be created! SDL - " << SDL_GetError() << endl;
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != TTF_Init())
|
||||
{
|
||||
cout << "Could not init TTF! SDL - "<< SDL_GetError() << endl;
|
||||
SDL_DestroyWindow(*window);
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void quit_sdl(SDL_Window *window)
|
||||
{
|
||||
TTF_Quit();
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
bool check_quit()
|
||||
{
|
||||
SDL_Event e;
|
||||
|
||||
while(SDL_PollEvent(&e))
|
||||
{
|
||||
if (SDL_QUIT == e.type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void calc_text(std::string& text, std::vector<Reading>& readings)
|
||||
{
|
||||
if (readings.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Reading last = *(readings.rbegin());
|
||||
text = "";
|
||||
|
||||
if (last.is_neg)
|
||||
{
|
||||
text += '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
text += ' ';
|
||||
}
|
||||
|
||||
if (last.is_inf)
|
||||
{
|
||||
text += " O L ";
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
text += ('0' + last.value[i]);
|
||||
text += ' ';
|
||||
}
|
||||
text.erase(text.size() - 1);
|
||||
}
|
||||
|
||||
if (last.dot_pos != 0)
|
||||
{
|
||||
text[last.dot_pos * 2] = '.';
|
||||
}
|
||||
|
||||
switch (last.modifier)
|
||||
{
|
||||
case -9:
|
||||
text += 'n';
|
||||
break;
|
||||
|
||||
case -6:
|
||||
text += "μ";
|
||||
break;
|
||||
|
||||
case -3:
|
||||
text += 'm';
|
||||
break;
|
||||
|
||||
case 0:
|
||||
text += ' ';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
text += 'k';
|
||||
break;
|
||||
|
||||
case 6:
|
||||
text += 'M';
|
||||
break;
|
||||
|
||||
default:
|
||||
text += ' ';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (last.type)
|
||||
{
|
||||
case Reading::reading_percent:
|
||||
text += "% ";
|
||||
break;
|
||||
|
||||
case Reading::reading_volts:
|
||||
text += "V ";
|
||||
break;
|
||||
|
||||
case Reading::reading_amps:
|
||||
text += "A ";
|
||||
break;
|
||||
|
||||
case Reading::reading_ohms:
|
||||
text += "Ω ";
|
||||
break;
|
||||
|
||||
case Reading::reading_hFE:
|
||||
text += "hFE";
|
||||
break;
|
||||
|
||||
case Reading::reading_hertz:
|
||||
text += "Hz ";
|
||||
break;
|
||||
|
||||
case Reading::reading_farads:
|
||||
text += "F ";
|
||||
break;
|
||||
|
||||
case Reading::reading_celsius:
|
||||
text += "°C ";
|
||||
break;
|
||||
|
||||
case Reading::reading_fahrenheit:
|
||||
text += "°F ";
|
||||
break;
|
||||
|
||||
default:
|
||||
text += "???";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_text(const std::string& text, SDL_Surface *surface, TTF_Font *font)
|
||||
{
|
||||
SDL_Surface *txt_surface;
|
||||
SDL_Rect rect;
|
||||
SDL_Color fg;
|
||||
SDL_Color bg;
|
||||
|
||||
fg.r = 0;
|
||||
fg.g = 0;
|
||||
fg.b = 0;
|
||||
|
||||
bg.r = 255;
|
||||
bg.g = 255;
|
||||
bg.b = 255;
|
||||
|
||||
if ((NULL == surface) || (NULL == font) || (0 == text.size()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
txt_surface = TTF_RenderUTF8_Shaded(font, text.c_str(), fg, bg);
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = surface->h / 2 - txt_surface->h / 2;
|
||||
|
||||
SDL_BlitSurface(txt_surface, NULL, surface, &rect);
|
||||
SDL_FreeSurface(txt_surface);
|
||||
}
|
||||
22
common.h
Normal file
22
common.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef COMMON_H_
|
||||
#define COMMON_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#ifdef USE_HID
|
||||
# include "DMM_HID.h"
|
||||
#endif
|
||||
|
||||
#define UI_FPS 30
|
||||
|
||||
bool init_sdl(SDL_Window **window);
|
||||
void quit_sdl(SDL_Window *window);
|
||||
bool check_quit();
|
||||
void calc_text(std::string& text, std::vector<Reading>& readings);
|
||||
void draw_text(const std::string& text, SDL_Surface *surface, TTF_Font *font);
|
||||
|
||||
#endif // COMMON_H_
|
||||
113
main_hid.cpp
Normal file
113
main_hid.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include "DMM_HID.h"
|
||||
#include "common.h"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
bool open_dmm(DMM_HID& dmm)
|
||||
{
|
||||
vector<string> devs = DMM_HID::get_dmm_devices();
|
||||
vector<Reading> readings;
|
||||
|
||||
if (0 == devs.size())
|
||||
{
|
||||
cout << "DMM not found" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (devs.size() > 1)
|
||||
{
|
||||
cout << "Multiple DMMs found" << endl;
|
||||
cout << "Using: " << devs[0] << endl;
|
||||
}
|
||||
|
||||
dmm.Open(devs[0]);
|
||||
|
||||
// Wait a sec
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
// DMM is open. Now check its config
|
||||
readings = dmm.get_readings(1);
|
||||
|
||||
if (readings.empty())
|
||||
{
|
||||
cout << "DMM communication is not ON - Press and hold USB/REL key" << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool ok;
|
||||
bool quit = false;
|
||||
|
||||
DMM_HID dmm;
|
||||
vector<Reading> readings;
|
||||
|
||||
Uint32 next_draw = 0;
|
||||
Uint32 ms;
|
||||
|
||||
SDL_Window *window;
|
||||
SDL_Surface *surface;
|
||||
TTF_Font *font;
|
||||
|
||||
string text;
|
||||
|
||||
// Keep compiler happy
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
ok = open_dmm(dmm);
|
||||
if (!ok)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ok = init_sdl(&window);
|
||||
if (!ok)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
font = TTF_OpenFont("./font.ttf", 100);
|
||||
|
||||
while (!quit)
|
||||
{
|
||||
ms = SDL_GetTicks();
|
||||
if (next_draw - ms > 1000 / UI_FPS)
|
||||
{
|
||||
surface = SDL_GetWindowSurface(window);
|
||||
|
||||
// Fill the surface white
|
||||
SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, 255, 255, 255));
|
||||
|
||||
// Get Readings
|
||||
readings = dmm.get_readings();
|
||||
|
||||
// Calculate Text
|
||||
calc_text(text, readings);
|
||||
|
||||
// TODO: Draw Text
|
||||
draw_text(text, surface, font);
|
||||
|
||||
next_draw = ms + 1000 / UI_FPS;
|
||||
|
||||
// Update the window
|
||||
SDL_UpdateWindowSurface(window);
|
||||
|
||||
quit = check_quit();
|
||||
}
|
||||
}
|
||||
|
||||
TTF_CloseFont(font);
|
||||
quit_sdl(window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user