mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add the skeleton of the new client app.
This commit is contained in:
107
lib/flags.cc
Normal file
107
lib/flags.cc
Normal file
@@ -0,0 +1,107 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
|
||||
static std::vector<Flag*> all_flags;
|
||||
static std::map<const std::string, Flag*> flags_by_name;
|
||||
|
||||
Flag::Flag(const std::vector<std::string>& names, const std::string helptext):
|
||||
_names(names),
|
||||
_helptext(helptext)
|
||||
{
|
||||
for (auto& name : names)
|
||||
{
|
||||
if (flags_by_name.find(name) != flags_by_name.end())
|
||||
Error() << "two flags use the name '" << name << "'";
|
||||
flags_by_name[name] = this;
|
||||
}
|
||||
|
||||
all_flags.push_back(this);
|
||||
}
|
||||
|
||||
void Flag::parseFlags(int argc, const char* argv[])
|
||||
{
|
||||
int index = 1;
|
||||
while (index < argc)
|
||||
{
|
||||
std::string thisarg = argv[index];
|
||||
std::string thatarg = (index < (argc-1)) ? argv[index+1] : "";
|
||||
|
||||
std::string key;
|
||||
std::string value;
|
||||
bool usesthat = false;
|
||||
|
||||
if ((thisarg.size() == 0) || (thisarg[0] != '-'))
|
||||
Error() << "non-option parameter " << thisarg << " seen (try --help)";
|
||||
if ((thisarg.size() > 1) && (thisarg[1] == '-'))
|
||||
{
|
||||
/* Long option. */
|
||||
|
||||
auto equals = thisarg.rfind('=');
|
||||
if (equals != std::string::npos)
|
||||
{
|
||||
key = thisarg.substr(0, equals);
|
||||
value = thisarg.substr(equals+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
key = thisarg;
|
||||
value = thatarg;
|
||||
usesthat = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Short option. */
|
||||
|
||||
if (thisarg.size() > 2)
|
||||
{
|
||||
key = thisarg.substr(0, 2);
|
||||
value = thisarg.substr(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
key = thisarg;
|
||||
value = thatarg;
|
||||
usesthat = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto flag = flags_by_name.find(key);
|
||||
if (flag == flags_by_name.end())
|
||||
Error() << "unknown flag '" << key << "'; try --help";
|
||||
|
||||
flag->second->set(value);
|
||||
|
||||
index++;
|
||||
if (usesthat && flag->second->hasArgument())
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void doHelp()
|
||||
{
|
||||
std::cout << "FluxEngine options:" << std::endl;
|
||||
for (auto flag : all_flags)
|
||||
{
|
||||
std::cout << " ";
|
||||
bool firstname = true;
|
||||
for (auto name : flag->names())
|
||||
{
|
||||
if (!firstname)
|
||||
std::cout << ", ";
|
||||
std::cout << name;
|
||||
firstname = false;
|
||||
}
|
||||
|
||||
if (flag->hasArgument())
|
||||
std::cout << " <default: \"" << flag->defaultValue() << "\">";
|
||||
std::cout << ": " << flag->helptext() << std::endl;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static ActionFlag helpFlag = ActionFlag(
|
||||
{ "--help", "-h" },
|
||||
"Shows the help.",
|
||||
doHelp);
|
||||
103
lib/flags.h
Normal file
103
lib/flags.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef FLAGS_H
|
||||
#define FLAGS_H
|
||||
|
||||
class Flag
|
||||
{
|
||||
public:
|
||||
static void parseFlags(int argc, const char* argv[]);
|
||||
|
||||
Flag(const std::vector<std::string>& names, const std::string helptext);
|
||||
virtual ~Flag() {};
|
||||
|
||||
const std::string& name() const { return _names[0]; }
|
||||
const std::vector<std::string> names() const { return _names; }
|
||||
const std::string& helptext() const { return _helptext; }
|
||||
|
||||
virtual bool hasArgument() const = 0;
|
||||
virtual const std::string defaultValue() const = 0;
|
||||
virtual void set(const std::string value) = 0;
|
||||
|
||||
private:
|
||||
const std::vector<std::string> _names;
|
||||
const std::string _helptext;
|
||||
};
|
||||
|
||||
class ActionFlag : Flag
|
||||
{
|
||||
public:
|
||||
ActionFlag(const std::vector<std::string>& names, const std::string helptext,
|
||||
std::function<void(void)> callback):
|
||||
Flag(names, helptext),
|
||||
_callback(callback)
|
||||
{}
|
||||
|
||||
bool hasArgument() const { return false; }
|
||||
const std::string defaultValue() const { return ""; }
|
||||
void set(const std::string value) { _callback(); }
|
||||
|
||||
private:
|
||||
const std::function<void(void)> _callback;
|
||||
};
|
||||
|
||||
class SettableFlag : public Flag
|
||||
{
|
||||
public:
|
||||
SettableFlag(const std::vector<std::string>& names, const std::string helptext):
|
||||
Flag(names, helptext)
|
||||
{}
|
||||
|
||||
operator bool() const { return _value; }
|
||||
|
||||
bool hasArgument() const { return false; }
|
||||
const std::string defaultValue() const { return "false"; }
|
||||
void set(const std::string value) { _value = true; }
|
||||
|
||||
private:
|
||||
bool _value = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ValueFlag : public Flag
|
||||
{
|
||||
public:
|
||||
ValueFlag(const std::vector<std::string>& names, const std::string helptext,
|
||||
const T defaultValue):
|
||||
Flag(names, helptext),
|
||||
_defaultValue(defaultValue),
|
||||
_value(defaultValue)
|
||||
{}
|
||||
|
||||
operator T() const { return _value; }
|
||||
|
||||
bool hasArgument() const { return true; }
|
||||
|
||||
protected:
|
||||
T _defaultValue;
|
||||
T _value;
|
||||
};
|
||||
|
||||
class StringFlag : public ValueFlag<std::string>
|
||||
{
|
||||
public:
|
||||
StringFlag(const std::vector<std::string>& names, const std::string helptext,
|
||||
const std::string defaultValue = ""):
|
||||
ValueFlag(names, helptext, defaultValue)
|
||||
{}
|
||||
|
||||
const std::string defaultValue() const { return _defaultValue; }
|
||||
void set(const std::string value) { _value = value; }
|
||||
};
|
||||
|
||||
class IntFlag : public ValueFlag<int>
|
||||
{
|
||||
public:
|
||||
IntFlag(const std::vector<std::string>& names, const std::string helptext,
|
||||
int defaultValue = 0):
|
||||
ValueFlag(names, helptext, defaultValue)
|
||||
{}
|
||||
|
||||
const std::string defaultValue() const { return std::to_string(_defaultValue); }
|
||||
void set(const std::string value) { _value = std::stoi(value); }
|
||||
};
|
||||
|
||||
#endif
|
||||
11
lib/globals.cc
Normal file
11
lib/globals.cc
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "globals.h"
|
||||
#include <sys/time.h>
|
||||
|
||||
double getCurrentTime(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
return double(tv.tv_sec) + tv.tv_usec/1000000.0;
|
||||
}
|
||||
|
||||
35
lib/globals.h
Normal file
35
lib/globals.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef GLOBALS_H
|
||||
#define GLOBALS_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
typedef int nanoseconds_t;
|
||||
|
||||
extern double getCurrentTime();
|
||||
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
~Error()
|
||||
{
|
||||
std::cerr << "Error: " << _stream.str() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Error& operator<<(T&& t)
|
||||
{
|
||||
_stream << t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::stringstream _stream;
|
||||
};
|
||||
|
||||
#endif
|
||||
23
lib/reader.cc
Normal file
23
lib/reader.cc
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "usb.h"
|
||||
|
||||
static StringFlag source(
|
||||
{ "--source", "-s" },
|
||||
"source for data",
|
||||
"");
|
||||
|
||||
static StringFlag destination(
|
||||
{ "--write-flux", "-f" },
|
||||
"write the raw magnetic flux to this file",
|
||||
"");
|
||||
|
||||
static SettableFlag justRead(
|
||||
{ "--just-read", "-R" },
|
||||
"just read the disk but do no further processing");
|
||||
|
||||
int allTracks()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
6
lib/reader.h
Normal file
6
lib/reader.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef READER_H
|
||||
#define READER_H
|
||||
|
||||
extern int allTracks();
|
||||
|
||||
#endif
|
||||
224
lib/usb.cc
Normal file
224
lib/usb.cc
Normal file
@@ -0,0 +1,224 @@
|
||||
#include "globals.h"
|
||||
#include "usb.h"
|
||||
#include "protocol.h"
|
||||
#include <libusb.h>
|
||||
|
||||
#define TIMEOUT 5000
|
||||
|
||||
static libusb_device_handle* device;
|
||||
|
||||
static uint8_t buffer[FRAME_SIZE];
|
||||
|
||||
static std::string usberror(int i)
|
||||
{
|
||||
return libusb_strerror((libusb_error) i);
|
||||
}
|
||||
|
||||
static void usb_init()
|
||||
{
|
||||
if (device)
|
||||
return;
|
||||
|
||||
int i = libusb_init(NULL);
|
||||
if (i < 0)
|
||||
Error() << "could not start libusb: " << usberror(i);
|
||||
|
||||
device = libusb_open_device_with_vid_pid(NULL, FLUXENGINE_VID, FLUXENGINE_PID);
|
||||
if (!device)
|
||||
Error() << "cannot find the FluxEngine (is it plugged in?)";
|
||||
|
||||
int cfg = -1;
|
||||
libusb_get_configuration(device, &cfg);
|
||||
if (cfg != 1)
|
||||
{
|
||||
i = libusb_set_configuration(device, 1);
|
||||
if (i < 0)
|
||||
Error() << "the FluxEngine would not accept configuration: " << usberror(i);
|
||||
}
|
||||
|
||||
i = libusb_claim_interface(device, 0);
|
||||
if (i < 0)
|
||||
Error() << "could not claim interface: " << usberror(i);
|
||||
|
||||
int version = usbGetVersion();
|
||||
if (version > FLUXENGINE_VERSION)
|
||||
Error() << "this version of the client is too old for this FluxEngine";
|
||||
}
|
||||
|
||||
static int usb_cmd_send(void* ptr, int len)
|
||||
{
|
||||
int i = libusb_interrupt_transfer(device, FLUXENGINE_CMD_OUT_EP,
|
||||
(uint8_t*) ptr, len, &len, TIMEOUT);
|
||||
if (i < 0)
|
||||
Error() << "failed to send command: " << usberror(i);
|
||||
return len;
|
||||
}
|
||||
|
||||
void usb_cmd_recv(void* ptr, int len)
|
||||
{
|
||||
int i = libusb_interrupt_transfer(device, FLUXENGINE_CMD_IN_EP,
|
||||
(uint8_t*) ptr, len, &len, TIMEOUT);
|
||||
if (i < 0)
|
||||
Error() << "failed to receive command reply: " << usberror(i);
|
||||
}
|
||||
|
||||
static void bad_reply(void)
|
||||
{
|
||||
struct error_frame* f = (struct error_frame*) buffer;
|
||||
if (f->f.type != F_FRAME_ERROR)
|
||||
Error() << "bad USB reply %d" << f->f.type;
|
||||
switch (f->error)
|
||||
{
|
||||
case F_ERROR_BAD_COMMAND:
|
||||
Error() << "device did not understand command";
|
||||
|
||||
case F_ERROR_UNDERRUN:
|
||||
Error() << "USB underrun (not enough bandwidth)";
|
||||
|
||||
default:
|
||||
Error() << "unknown device error " << f->error;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T* await_reply(int desired)
|
||||
{
|
||||
usb_cmd_recv(buffer, sizeof(buffer));
|
||||
struct any_frame* r = (struct any_frame*) buffer;
|
||||
if (r->f.type != desired)
|
||||
bad_reply();
|
||||
return (T*) r;
|
||||
}
|
||||
|
||||
int usbGetVersion(void)
|
||||
{
|
||||
usb_init();
|
||||
|
||||
struct any_frame f = { .f = {.type = F_FRAME_GET_VERSION_CMD, .size = sizeof(f)} };
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
auto r = await_reply<struct version_frame>(F_FRAME_GET_VERSION_REPLY);
|
||||
return r->version;
|
||||
}
|
||||
|
||||
void usbSeek(uint8_t track)
|
||||
{
|
||||
usb_init();
|
||||
|
||||
struct seek_frame f = {
|
||||
{ .type = F_FRAME_SEEK_CMD, .size = sizeof(f) },
|
||||
.track = track
|
||||
};
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
await_reply<struct any_frame>(F_FRAME_SEEK_REPLY);
|
||||
}
|
||||
|
||||
nanoseconds_t usbGetRotationalPeriod(void)
|
||||
{
|
||||
usb_init();
|
||||
|
||||
struct any_frame f = { .f = {.type = F_FRAME_MEASURE_SPEED_CMD, .size = sizeof(f)} };
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
|
||||
auto r = await_reply<struct speed_frame>(F_FRAME_MEASURE_SPEED_REPLY);
|
||||
return r->period_ms * 1000;
|
||||
}
|
||||
|
||||
static int large_bulk_transfer(int ep, void* buffer, int total_len)
|
||||
{
|
||||
int len;
|
||||
int i = libusb_bulk_transfer(device, ep, (uint8_t*) buffer, total_len, &len, TIMEOUT);
|
||||
if (i < 0)
|
||||
Error() << "data transfer failed: " << usberror(i);
|
||||
return len;
|
||||
}
|
||||
|
||||
void usbTestBulkTransport()
|
||||
{
|
||||
usb_init();
|
||||
|
||||
struct any_frame f = { .f = {.type = F_FRAME_BULK_TEST_CMD, .size = sizeof(f)} };
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
|
||||
/* These must match the device. */
|
||||
const int XSIZE = 64;
|
||||
const int YSIZE = 256;
|
||||
const int ZSIZE = 64;
|
||||
|
||||
uint8_t bulk_buffer[XSIZE*YSIZE*ZSIZE];
|
||||
int total_len = sizeof(bulk_buffer);
|
||||
double start_time = getCurrentTime();
|
||||
large_bulk_transfer(FLUXENGINE_DATA_IN_EP, bulk_buffer, total_len);
|
||||
double elapsed_time = getCurrentTime() - start_time;
|
||||
|
||||
std::cout << "Transferred "
|
||||
<< total_len
|
||||
<< " bytes in "
|
||||
<< int(elapsed_time * 1000.0)
|
||||
<< " ("
|
||||
<< int((total_len / 1024.0) / elapsed_time)
|
||||
<< " kB/s)"
|
||||
<< std::endl;
|
||||
|
||||
for (int x=0; x<XSIZE; x++)
|
||||
for (int y=0; y<YSIZE; y++)
|
||||
for (int z=0; z<ZSIZE; z++)
|
||||
{
|
||||
int offset = x*XSIZE*YSIZE + y*ZSIZE + z;
|
||||
if (bulk_buffer[offset] != uint8_t(x+y+z))
|
||||
Error() << "data transfer corrupted at 0x"
|
||||
<< std::hex << offset << std::dec
|
||||
<< " "
|
||||
<< x << '.' << y << '.' << z << '.';
|
||||
}
|
||||
|
||||
await_reply<struct any_frame>(F_FRAME_BULK_TEST_REPLY);
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct fluxmap* usb_read(int side, int revolutions)
|
||||
{
|
||||
struct read_frame f = {
|
||||
.f = { .type = F_FRAME_READ_CMD, .size = sizeof(f) },
|
||||
.side = side,
|
||||
.revolutions = revolutions
|
||||
};
|
||||
|
||||
struct fluxmap* fluxmap = create_fluxmap();
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
|
||||
uint8_t buffer[1024*1024];
|
||||
int len = large_bulk_transfer(FLUXENGINE_DATA_IN_EP, buffer, sizeof(buffer));
|
||||
|
||||
fluxmap_append_intervals(fluxmap, buffer, len);
|
||||
|
||||
await_reply(F_FRAME_READ_REPLY);
|
||||
return fluxmap;
|
||||
}
|
||||
|
||||
/* Returns number of bytes actually written */
|
||||
void usb_write(int side, struct fluxmap* fluxmap)
|
||||
{
|
||||
int safelen = fluxmap->bytes & ~(FRAME_SIZE-1);
|
||||
|
||||
/* Convert from intervals to absolute timestamps. */
|
||||
|
||||
uint8_t buffer[1024*1024];
|
||||
uint8_t clock = 0;
|
||||
for (int i=0; i<safelen; i++)
|
||||
{
|
||||
clock += fluxmap->intervals[i];
|
||||
buffer[i] = clock;
|
||||
}
|
||||
|
||||
struct write_frame f = {
|
||||
.f = { .type = F_FRAME_WRITE_CMD, .size = sizeof(f) },
|
||||
.side = side,
|
||||
.bytes_to_write = htole32(safelen),
|
||||
};
|
||||
usb_cmd_send(&f, f.f.size);
|
||||
|
||||
large_bulk_transfer(FLUXENGINE_DATA_OUT_EP, buffer, safelen);
|
||||
|
||||
await_reply(F_FRAME_WRITE_REPLY);
|
||||
}
|
||||
#endif
|
||||
9
lib/usb.h
Normal file
9
lib/usb.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef USB_H
|
||||
#define USB_H
|
||||
|
||||
extern int usbGetVersion();
|
||||
extern void usbSeek(uint8_t track);
|
||||
extern nanoseconds_t usbGetRotationalPeriod();
|
||||
extern void usbTestBulkTransport();
|
||||
|
||||
#endif
|
||||
11
src/fe-readibm.cc
Normal file
11
src/fe-readibm.cc
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "reader.h"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
Flag::parseFlags(argc, argv);
|
||||
allTracks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
13
src/fe-rpm.cc
Normal file
13
src/fe-rpm.cc
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "usb.h"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
Flag::parseFlags(argc, argv);
|
||||
|
||||
nanoseconds_t period = usbGetRotationalPeriod();
|
||||
std::cout << "Rotational period is " << period/1000 << " ms (" << 60e6/period << " rpm)" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
16
src/fe-seek.cc
Normal file
16
src/fe-seek.cc
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "usb.h"
|
||||
|
||||
static IntFlag track(
|
||||
{ "--track", "-t" },
|
||||
"track to seek to",
|
||||
0);
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
Flag::parseFlags(argc, argv);
|
||||
|
||||
usbSeek(track);
|
||||
return 0;
|
||||
}
|
||||
10
src/fe-testbulktransport.cc
Normal file
10
src/fe-testbulktransport.cc
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "usb.h"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
Flag::parseFlags(argc, argv);
|
||||
usbTestBulkTransport();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user