i/o fixes for debugger
This commit is contained in:
parent
9c7632fb1c
commit
ab268f5ca6
13 changed files with 255 additions and 131 deletions
|
@ -10,26 +10,17 @@
|
|||
|
||||
#define NEOPIXELS_PIN 25
|
||||
|
||||
console_esp32::console_esp32(std::atomic_bool *const terminate, bus *const b) :
|
||||
console(terminate, b)
|
||||
console_esp32::console_esp32(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b) :
|
||||
console(terminate, interrupt_emulation, b)
|
||||
{
|
||||
}
|
||||
|
||||
console_esp32::~console_esp32()
|
||||
{
|
||||
if (th) {
|
||||
th->join();
|
||||
|
||||
delete th;
|
||||
}
|
||||
stop_thread();
|
||||
}
|
||||
|
||||
void console_esp32::start_thread()
|
||||
{
|
||||
th = new std::thread(std::ref(*this));
|
||||
}
|
||||
|
||||
int console_esp32::wait_for_char(const short timeout)
|
||||
int console_esp32::wait_for_char_ll(const short timeout)
|
||||
{
|
||||
for(short i=0; i<timeout / 10; i++) {
|
||||
if (Serial.available())
|
||||
|
|
|
@ -6,16 +6,14 @@
|
|||
class console_esp32 : public console
|
||||
{
|
||||
protected:
|
||||
int wait_for_char(const short timeout) override;
|
||||
int wait_for_char_ll(const short timeout) override;
|
||||
|
||||
void put_char_ll(const char c) override;
|
||||
|
||||
public:
|
||||
console_esp32(std::atomic_bool *const terminate, bus *const b);
|
||||
console_esp32(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b);
|
||||
virtual ~console_esp32();
|
||||
|
||||
void start_thread() override;
|
||||
|
||||
void put_string_lf(const std::string & what) override;
|
||||
|
||||
void resize_terminal() override;
|
||||
|
|
|
@ -38,6 +38,7 @@ uint32_t start_ts = 0;
|
|||
SdFat32 sd;
|
||||
|
||||
std::atomic_bool terminate { false };
|
||||
std::atomic_bool interrupt_emulation { false };
|
||||
|
||||
std::atomic_bool *running { nullptr };
|
||||
|
||||
|
@ -185,7 +186,7 @@ void setup() {
|
|||
c->setEmulateMFPT(true);
|
||||
|
||||
Serial.println(F("Init console"));
|
||||
cnsl = new console_esp32(&terminate, b);
|
||||
cnsl = new console_esp32(&terminate, &interrupt_emulation, b);
|
||||
|
||||
running = cnsl->get_running_flag();
|
||||
|
||||
|
@ -215,7 +216,7 @@ void setup() {
|
|||
Serial.println(F("Press <enter> to start"));
|
||||
|
||||
for(;;) {
|
||||
int c = cnsl->wait_for_char(1000);
|
||||
int c = cnsl->wait_char(1000);
|
||||
if (c == 13 || c == 10)
|
||||
break;
|
||||
}
|
||||
|
|
70
console.cpp
70
console.cpp
|
@ -1,3 +1,4 @@
|
|||
#include <chrono>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -9,8 +10,9 @@
|
|||
#include "utils.h"
|
||||
|
||||
|
||||
console::console(std::atomic_bool *const terminate, bus *const b) :
|
||||
console::console(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b) :
|
||||
terminate(terminate),
|
||||
interrupt_emulation(interrupt_emulation),
|
||||
b(b)
|
||||
{
|
||||
memset(screen_buffer, ' ', sizeof screen_buffer);
|
||||
|
@ -20,15 +22,38 @@ console::~console()
|
|||
{
|
||||
}
|
||||
|
||||
void console::start_thread()
|
||||
{
|
||||
stop_thread_flag = false;
|
||||
|
||||
th = new std::thread(std::ref(*this));
|
||||
}
|
||||
|
||||
void console::stop_thread()
|
||||
{
|
||||
if (th) {
|
||||
stop_thread_flag = true;
|
||||
|
||||
th->join();
|
||||
delete th;
|
||||
|
||||
th = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool console::poll_char()
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(input_lock);
|
||||
|
||||
return input_buffer.empty() == false;
|
||||
}
|
||||
|
||||
uint8_t console::get_char()
|
||||
int console::get_char()
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(input_lock);
|
||||
|
||||
if (input_buffer.empty())
|
||||
return 0x00;
|
||||
return -1;
|
||||
|
||||
char c = input_buffer.at(0);
|
||||
|
||||
|
@ -37,6 +62,23 @@ uint8_t console::get_char()
|
|||
return c;
|
||||
}
|
||||
|
||||
int console::wait_char(const int timeout_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(input_lock);
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
if (input_buffer.empty() == false || have_data.wait_for(lck, timeout_ms * 1ms) == std::cv_status::no_timeout) {
|
||||
int c = input_buffer.at(0);
|
||||
|
||||
input_buffer.erase(input_buffer.begin() + 0);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void console::flush_input()
|
||||
{
|
||||
input_buffer.clear();
|
||||
|
@ -50,7 +92,7 @@ std::string console::read_line(const std::string & prompt)
|
|||
std::string str;
|
||||
|
||||
for(;;) {
|
||||
char c = wait_for_char(500);
|
||||
char c = wait_char(500);
|
||||
|
||||
if (c == -1)
|
||||
continue;
|
||||
|
@ -134,29 +176,29 @@ void console::put_string(const std::string & what)
|
|||
put_char(what.at(x));
|
||||
}
|
||||
|
||||
void console::put_string_lf(const std::string & what)
|
||||
{
|
||||
put_string(what);
|
||||
|
||||
put_string("\n");
|
||||
}
|
||||
|
||||
void console::operator()()
|
||||
{
|
||||
D(fprintf(stderr, "Console thread started\n");)
|
||||
|
||||
while(!*terminate) {
|
||||
int c = wait_for_char(500);
|
||||
set_thread_name("kek:console");
|
||||
|
||||
while(!*terminate && !stop_thread_flag) {
|
||||
int c = wait_for_char_ll(100);
|
||||
|
||||
if (c == -1)
|
||||
continue;
|
||||
|
||||
if (c == 3) // ^c
|
||||
*terminate = true;
|
||||
else if (c == 5) // ^e
|
||||
*interrupt_emulation = true;
|
||||
else if (c == 12) // ^l
|
||||
refresh_virtual_terminal();
|
||||
else
|
||||
else {
|
||||
input_buffer.push_back(c);
|
||||
|
||||
have_data.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
D(fprintf(stderr, "Console thread terminating\n");)
|
||||
|
|
20
console.h
20
console.h
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
|
@ -14,9 +15,12 @@ class console
|
|||
{
|
||||
private:
|
||||
std::vector<char> input_buffer;
|
||||
std::condition_variable have_data;
|
||||
std::mutex input_lock;
|
||||
|
||||
protected:
|
||||
std::atomic_bool *const terminate { nullptr };
|
||||
std::atomic_bool *const interrupt_emulation { nullptr };
|
||||
|
||||
bus *const b { nullptr };
|
||||
std::thread *th { nullptr };
|
||||
|
@ -24,28 +28,32 @@ protected:
|
|||
std::atomic_bool disk_write_activity_flag { false };
|
||||
std::atomic_bool running_flag { false };
|
||||
|
||||
bool stop_thread_flag { false };
|
||||
|
||||
char screen_buffer[t_height][t_width];
|
||||
uint8_t tx { 0 };
|
||||
uint8_t ty { 0 };
|
||||
|
||||
virtual int wait_for_char_ll(const short timeout) = 0;
|
||||
|
||||
virtual void put_char_ll(const char c) = 0;
|
||||
|
||||
public:
|
||||
console(std::atomic_bool *const terminate, bus *const b);
|
||||
console(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b);
|
||||
virtual ~console();
|
||||
|
||||
virtual void start_thread() = 0;
|
||||
|
||||
virtual int wait_for_char(const short timeout) = 0;
|
||||
void start_thread();
|
||||
void stop_thread();
|
||||
|
||||
bool poll_char();
|
||||
uint8_t get_char();
|
||||
int get_char();
|
||||
int wait_char(const int timeout_ms);
|
||||
std::string read_line(const std::string & prompt);
|
||||
void flush_input();
|
||||
|
||||
void put_char(const char c);
|
||||
void put_string(const std::string & what);
|
||||
virtual void put_string_lf(const std::string & what);
|
||||
virtual void put_string_lf(const std::string & what) = 0;
|
||||
|
||||
void debug(const std::string fmt, ...);
|
||||
|
||||
|
|
|
@ -9,32 +9,26 @@
|
|||
#include "utils.h"
|
||||
|
||||
|
||||
console_ncurses::console_ncurses(std::atomic_bool *const terminate, bus *const b) :
|
||||
console(terminate, b)
|
||||
console_ncurses::console_ncurses(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b) :
|
||||
console(terminate, interrupt_emulation, b)
|
||||
{
|
||||
init_ncurses(true);
|
||||
|
||||
resize_terminal();
|
||||
|
||||
th = new std::thread(std::ref(*this));
|
||||
|
||||
th_panel = new std::thread(&console_ncurses::panel_update_thread, this);
|
||||
}
|
||||
|
||||
console_ncurses::~console_ncurses()
|
||||
{
|
||||
stop_thread();
|
||||
|
||||
if (th_panel) {
|
||||
th_panel->join();
|
||||
|
||||
delete th_panel;
|
||||
}
|
||||
|
||||
if (th) {
|
||||
th->join();
|
||||
|
||||
delete th;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lck(ncurses_mutex);
|
||||
|
||||
wattron(w_main->win, A_BOLD);
|
||||
|
@ -54,12 +48,7 @@ console_ncurses::~console_ncurses()
|
|||
endwin();
|
||||
}
|
||||
|
||||
void console_ncurses::start_thread()
|
||||
{
|
||||
th = new std::thread(std::ref(*this));
|
||||
}
|
||||
|
||||
int console_ncurses::wait_for_char(const short timeout)
|
||||
int console_ncurses::wait_for_char_ll(const short timeout)
|
||||
{
|
||||
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, 0 } };
|
||||
|
||||
|
@ -90,6 +79,13 @@ void console_ncurses::put_char_ll(const char c)
|
|||
}
|
||||
}
|
||||
|
||||
void console_ncurses::put_string_lf(const std::string & what)
|
||||
{
|
||||
put_string(what);
|
||||
|
||||
put_string("\n");
|
||||
}
|
||||
|
||||
void console_ncurses::resize_terminal()
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(ncurses_mutex);
|
||||
|
@ -126,6 +122,8 @@ void console_ncurses::resize_terminal()
|
|||
|
||||
void console_ncurses::panel_update_thread()
|
||||
{
|
||||
set_thread_name("kek:c-panel");
|
||||
|
||||
cpu *const c = b->getCpu();
|
||||
|
||||
uint64_t prev_instr_cnt = c->get_instructions_executed_count();
|
||||
|
|
|
@ -21,15 +21,15 @@ private:
|
|||
int ty { 0 };
|
||||
|
||||
protected:
|
||||
int wait_for_char(const short timeout) override;
|
||||
int wait_for_char_ll(const short timeout) override;
|
||||
|
||||
void put_char_ll(const char c) override;
|
||||
|
||||
public:
|
||||
console_ncurses(std::atomic_bool *const terminate, bus *const b);
|
||||
console_ncurses(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b);
|
||||
virtual ~console_ncurses();
|
||||
|
||||
void start_thread() override;
|
||||
void put_string_lf(const std::string & what) override;
|
||||
|
||||
void resize_terminal() override;
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include "error.h"
|
||||
|
||||
|
||||
console_posix::console_posix(std::atomic_bool *const terminate, bus *const b) :
|
||||
console(terminate, b)
|
||||
console_posix::console_posix(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b) :
|
||||
console(terminate, interrupt_emulation, b)
|
||||
{
|
||||
if (tcgetattr(STDIN_FILENO, &org_tty_opts) == -1)
|
||||
error_exit(true, "console_posix: tcgetattr failed");
|
||||
|
@ -18,29 +18,17 @@ console_posix::console_posix(std::atomic_bool *const terminate, bus *const b) :
|
|||
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_opts_raw) == -1)
|
||||
error_exit(true, "console_posix: tcsetattr failed");
|
||||
|
||||
th = new std::thread(std::ref(*this));
|
||||
}
|
||||
|
||||
console_posix::~console_posix()
|
||||
{
|
||||
if (th) {
|
||||
th->join();
|
||||
|
||||
delete th;
|
||||
}
|
||||
stop_thread();
|
||||
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &org_tty_opts) == -1)
|
||||
error_exit(true, "~console_posix: tcsetattr failed");
|
||||
|
||||
}
|
||||
|
||||
void console_posix::start_thread()
|
||||
{
|
||||
th = new std::thread(std::ref(*this));
|
||||
}
|
||||
|
||||
int console_posix::wait_for_char(const short timeout)
|
||||
int console_posix::wait_for_char_ll(const short timeout)
|
||||
{
|
||||
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } };
|
||||
|
||||
|
@ -61,7 +49,7 @@ void console_posix::put_string_lf(const std::string & what)
|
|||
{
|
||||
put_string(what);
|
||||
|
||||
put_string("\n");
|
||||
put_string("\r\n");
|
||||
}
|
||||
|
||||
void console_posix::resize_terminal()
|
||||
|
|
|
@ -9,16 +9,14 @@ private:
|
|||
struct termios org_tty_opts { 0 };
|
||||
|
||||
protected:
|
||||
int wait_for_char(const short timeout) override;
|
||||
int wait_for_char_ll(const short timeout) override;
|
||||
|
||||
void put_char_ll(const char c) override;
|
||||
|
||||
public:
|
||||
console_posix(std::atomic_bool *const terminate, bus *const b);
|
||||
console_posix(std::atomic_bool *const terminate, std::atomic_bool *const interrupt_emulation, bus *const b);
|
||||
virtual ~console_posix();
|
||||
|
||||
void start_thread() override;
|
||||
|
||||
void resize_terminal() override;
|
||||
|
||||
void put_string_lf(const std::string & what) override;
|
||||
|
|
29
cpu.cpp
29
cpu.cpp
|
@ -1922,35 +1922,6 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
|
|||
return out;
|
||||
}
|
||||
|
||||
void cpu::disassemble() const
|
||||
{
|
||||
#if !defined(ESP32)
|
||||
auto data = disassemble(pc);
|
||||
|
||||
auto registers = data["registers"];
|
||||
auto psw = data["psw"][0];
|
||||
|
||||
std::string instruction_values;
|
||||
for(auto iv : data["instruction-values"])
|
||||
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
||||
|
||||
std::string work_values;
|
||||
for(auto wv : data["work-values"])
|
||||
work_values += (work_values.empty() ? "" : ",") + wv;
|
||||
|
||||
std::string instruction = data["instruction-text"].at(0);
|
||||
|
||||
D(fprintf(stderr, "R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %s, PSW: %s, instr: %s: %s - %s\n",
|
||||
registers[0].c_str(), registers[1].c_str(), registers[2].c_str(), registers[3].c_str(), registers[4].c_str(), registers[5].c_str(),
|
||||
registers[6].c_str(), registers[7].c_str(),
|
||||
psw.c_str(),
|
||||
instruction_values.c_str(),
|
||||
instruction.c_str(),
|
||||
work_values.c_str()
|
||||
);)
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpu::step()
|
||||
{
|
||||
instruction_count++;
|
||||
|
|
111
main.cpp
111
main.cpp
|
@ -127,6 +127,40 @@ uint16_t loadTape(bus *const b, const char *const file)
|
|||
return start;
|
||||
}
|
||||
|
||||
void disassemble(cpu *const c, console *const cnsl)
|
||||
{
|
||||
#if !defined(ESP32)
|
||||
auto data = c->disassemble(c->getPC());
|
||||
|
||||
auto registers = data["registers"];
|
||||
auto psw = data["psw"][0];
|
||||
|
||||
std::string instruction_values;
|
||||
for(auto iv : data["instruction-values"])
|
||||
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
||||
|
||||
std::string work_values;
|
||||
for(auto wv : data["work-values"])
|
||||
work_values += (work_values.empty() ? "" : ",") + wv;
|
||||
|
||||
std::string instruction = data["instruction-text"].at(0);
|
||||
|
||||
std::string result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %s, PSW: %s, instr: %s: %s - %s",
|
||||
registers[0].c_str(), registers[1].c_str(), registers[2].c_str(), registers[3].c_str(), registers[4].c_str(), registers[5].c_str(),
|
||||
registers[6].c_str(), registers[7].c_str(),
|
||||
psw.c_str(),
|
||||
instruction_values.c_str(),
|
||||
instruction.c_str(),
|
||||
work_values.c_str()
|
||||
);
|
||||
|
||||
if (cnsl)
|
||||
cnsl->debug(result);
|
||||
else
|
||||
fprintf(stderr, "%s\n", result.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
volatile bool sw = false;
|
||||
void sw_handler(int s)
|
||||
{
|
||||
|
@ -167,7 +201,7 @@ int main(int argc, char *argv[])
|
|||
bool debugger = false;
|
||||
bool tracing = false;
|
||||
int opt = -1;
|
||||
while((opt = getopt(argc, argv, "hm:T:R:p:ndL:")) != -1)
|
||||
while((opt = getopt(argc, argv, "hm:T:R:p:ndtL:")) != -1)
|
||||
{
|
||||
switch(opt) {
|
||||
case 'h':
|
||||
|
@ -220,14 +254,16 @@ int main(int argc, char *argv[])
|
|||
|
||||
console *cnsl = nullptr;
|
||||
|
||||
std::atomic_bool interrupt_emulation { false };
|
||||
|
||||
if (withUI)
|
||||
cnsl = new console_ncurses(&terminate, b);
|
||||
cnsl = new console_ncurses(&terminate, &interrupt_emulation, b);
|
||||
else {
|
||||
fprintf(stderr, "This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden.\n");
|
||||
|
||||
fprintf(stderr, "Built on: " __DATE__ " " __TIME__ "\n");
|
||||
|
||||
cnsl = new console_posix(&terminate, b);
|
||||
cnsl = new console_posix(&terminate, &interrupt_emulation, b);
|
||||
}
|
||||
|
||||
if (rk05_files.empty() == false) {
|
||||
|
@ -252,9 +288,8 @@ int main(int argc, char *argv[])
|
|||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
if (withUI) {
|
||||
if (withUI)
|
||||
sigaction(SIGWINCH, &sa, nullptr);
|
||||
}
|
||||
|
||||
sigaction(SIGTERM, &sa, nullptr);
|
||||
sigaction(SIGINT , &sa, nullptr);
|
||||
|
@ -264,22 +299,72 @@ int main(int argc, char *argv[])
|
|||
// loadbin(b, 0, "test.dat");
|
||||
// c->setRegister(7, 0);
|
||||
|
||||
cnsl->start_thread();
|
||||
|
||||
c->emulation_start(); // for statistics
|
||||
|
||||
if (debugger) {
|
||||
while(!event && !terminate) {
|
||||
if (tracing)
|
||||
c->disassemble();
|
||||
cnsl->start_thread();
|
||||
|
||||
if (c->check_breakpoint())
|
||||
if (debugger) {
|
||||
bool single_step = false;
|
||||
|
||||
while(!terminate) {
|
||||
bool temp = terminate;
|
||||
std::string cmd = cnsl->read_line(format("%d%d", event, temp));
|
||||
auto parts = split(cmd, " ");
|
||||
|
||||
if (cmd == "go")
|
||||
single_step = false;
|
||||
else if (cmd == "single" || cmd == "s")
|
||||
single_step = true;
|
||||
else if (cmd == "disassemble" || cmd == "d") {
|
||||
disassemble(c, single_step ? cnsl : nullptr);
|
||||
continue;
|
||||
}
|
||||
else if (cmd == "reset" || cmd == "r") {
|
||||
terminate = false;
|
||||
|
||||
event = 0;
|
||||
|
||||
c->reset();
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (cmd == "quit" || cmd == "q")
|
||||
break;
|
||||
else if (cmd == "help") {
|
||||
cnsl->put_string_lf("disassemble/d - show current instruction");
|
||||
cnsl->put_string_lf("go - run until trap or ^e");
|
||||
cnsl->put_string_lf("quit/q - stop emulator");
|
||||
cnsl->put_string_lf("reset/r - reset cpu/bus/etc");
|
||||
cnsl->put_string_lf("single/s - run 1 instruction (implicit 'disassemble' command)");
|
||||
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
cnsl->put_string_lf("?");
|
||||
continue;
|
||||
}
|
||||
|
||||
while(!event && !terminate && !interrupt_emulation) {
|
||||
if (tracing || single_step)
|
||||
disassemble(c, single_step ? cnsl : nullptr);
|
||||
|
||||
if (c->check_breakpoint() && !single_step)
|
||||
break;
|
||||
|
||||
c->step();
|
||||
|
||||
if (single_step)
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: some menu
|
||||
if (interrupt_emulation) {
|
||||
single_step = true;
|
||||
|
||||
event = 0;
|
||||
|
||||
interrupt_emulation = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(!event && !terminate)
|
||||
|
|
39
utils.cpp
39
utils.cpp
|
@ -8,6 +8,7 @@
|
|||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <sys/time.h>
|
||||
|
||||
void setBit(uint16_t & v, const int bit, const bool vb)
|
||||
|
@ -74,3 +75,41 @@ void myusleep(uint64_t us)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string in, std::string splitter)
|
||||
{
|
||||
std::vector<std::string> out;
|
||||
size_t splitter_size = splitter.size();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
size_t pos = in.find(splitter);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string before = in.substr(0, pos);
|
||||
if (!before.empty())
|
||||
out.push_back(before);
|
||||
|
||||
size_t bytes_left = in.size() - (pos + splitter_size);
|
||||
if (bytes_left == 0)
|
||||
return out;
|
||||
|
||||
in = in.substr(pos + splitter_size);
|
||||
}
|
||||
|
||||
if (in.size() > 0)
|
||||
out.push_back(in);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void set_thread_name(std::string name)
|
||||
{
|
||||
#if !defined(ESP32)
|
||||
if (name.length() > 15)
|
||||
name = name.substr(0, 15);
|
||||
|
||||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
|
7
utils.h
7
utils.h
|
@ -1,7 +1,8 @@
|
|||
// (C) 2018 by Folkert van Heusden
|
||||
// (C) 2018-2022 by Folkert van Heusden
|
||||
// Released under Apache License v2.0
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
void setBit(uint16_t & v, const int bit, const bool vb);
|
||||
int parity(int v);
|
||||
|
@ -10,5 +11,9 @@ int parity(int v);
|
|||
|
||||
std::string format(const char *const fmt, ...);
|
||||
|
||||
std::vector<std::string> split(std::string in, std::string splitter);
|
||||
|
||||
unsigned long get_ms();
|
||||
void myusleep(uint64_t us);
|
||||
|
||||
void set_thread_name(std::string name);
|
||||
|
|
Loading…
Add table
Reference in a new issue