code_device/sdk/hginclude/utils.cpp

1104 lines
22 KiB
C++

#include "utils.h"
#include "huagao/brand.h"
#include "ini_file.h"
#include <mutex>
#include <algorithm>
#if OS_WIN
#include <direct.h>
#include <Windows.h>
#include <time.h>
#include <Psapi.h>
#include <Tlhelp32.h>
#pragma comment(lib, "Psapi.lib")
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 // microseconds from '1601-01-01 00:00:00' to '1970-01-01 00:00:00'
int gettimeofday(TIMEV* tv, struct timezone* tz)
{
FILETIME ft = { 0 };
uint64_t ui64 = 0;
static bool set_tz = true;
GetSystemTimeAsFileTime(&ft); // 100 ns - from 1601-01-01 00:00:00
ui64 = ft.dwHighDateTime;
ui64 <<= 32;
ui64 |= ft.dwLowDateTime;
// convert to microseconds ...
ui64 += 5;
ui64 /= 10;
// move to 1970-01-01 00:00:00
ui64 -= DELTA_EPOCH_IN_MICROSECS;
if (tv)
{
tv->tv_sec = ui64 / 1000000;
tv->tv_usec = ui64 % 1000000;
}
if (tz)
{
if (set_tz)
{
set_tz = false;
_tzset();
}
tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
}
return 0;
}
#else
#include <map>
#include <sys/sysinfo.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <thread>
#include <iconv.h>
#include <sys/vfs.h>
static std::mutex ini_lock_;
static std::map<std::string, simple_ini*> ini_files_;
static simple_ini* get_ini_object(const char* file)
{
std::lock_guard<std::mutex> lock(ini_lock_);
if (ini_files_.count(file) == 0)
{
simple_ini* ini = new simple_ini();
ini->load(file);
ini_files_[file] = ini;
}
return ini_files_[file];
}
DWORD GetPrivateProfileStringA(const char* lpAppName, const char* lpKeyName, const char* lpDefault, char* lpReturnedString, DWORD nSize, const char* lpFileName)
{
simple_ini* ini = get_ini_object(lpFileName);
std::string str(ini->get(lpAppName, lpKeyName, lpDefault));
if (nSize)
{
if (nSize < str.length())
{
memcpy(lpReturnedString, str.c_str(), nSize);
}
else
{
strcpy(lpReturnedString, str.c_str());
nSize = str.length();
}
}
return nSize;
}
BOOL WritePrivateProfileStringA(const char* lpAppName, const char* lpKeyName, const char* lpString, const char* lpFileName)
{
simple_ini* ini = get_ini_object(lpFileName);
ini->set(lpAppName, lpKeyName, lpString);
ini->save(lpFileName);
return TRUE;
}
DWORD GetLastError(void)
{
return errno;
}
DWORD GetPrivateProfileIntA(const char* app, const char* key, DWORD def, const char* file)
{
std::string val(get_ini_object(file)->get(app, key));
return val.empty() ? def : atoi(val.c_str());
}
DWORD GetPrivateProfileStringA(const char* app, const char* key, const char* init, char* buf, size_t len, const char* file)
{
std::string val(get_ini_object(file)->get(app, key));
if(val.empty())
{
if(init)
{
strcpy(buf, init);
len = strlen(init);
}
else
{
len = 0;
}
}
else
{
if(len < val.length())
memcpy(buf, val.c_str(), len);
else
{
strcpy(buf, val.c_str());
len = val.length();
}
}
return len;
}
void Sleep(DWORD milliseconds)
{
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}
int GetModuleFileNameA(HMODULE module, char* buf, size_t len)
{
std::string name(""),
val(utils::get_module_full_path((char*)module));
val += PATH_SEPARATOR + name;
if(len < val.length())
memcpy(buf, val.c_str(), len);
else
{
strcpy(buf, val.c_str());
len = val.length();
}
return len;
}
int GetCurrentThreadId(void)
{
return pthread_self();
}
int GetCurrentProcessId(void)
{
return getpid();
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// log class
#define MAX_LOG_FILE_SIZE SIZE_MB(10)
class log_cls
{
void(*log_)(const char*, void*, void*);
std::string path_file_;
FILE* file_;
int level_;
int type_;
std::mutex lock_;
static log_cls* inst_;
static FILE* create_log_file(const char* path_file, bool truncate)
{
FILE* file_ = fopen(path_file, "a+b");
if (file_)
{
fseek(file_, 0, SEEK_END);
if (ftell(file_) == 0)
{
unsigned char bom[] = { 0x0ef, 0x0bb, 0x0bf };
fwrite(bom, sizeof(bom), 1, file_);
}
else
{
std::string sep("\n\n===================================================================================================================\n");
fwrite(sep.c_str(), sizeof(sep[0]), sep.length(), file_);
}
std::string now("[" + utils::format_current_time() + "]: =====================================");
now += truncate ? "--truncated--=====================================\n" : "--started--=====================================\n";
fwrite(now.c_str(), sizeof(now[0]), now.length(), file_);
}
return file_;
}
static void log_none(const char* info, void* param, void* param2)
{}
static void log_consonle(const char* info, void* param, void* param2)
{
printf(info);
}
static void log_file(const char* info, void* param, void* param2)
{
FILE** file = (FILE**)param;
if (*file == nullptr)
*file = create_log_file(((std::string*)param2)->c_str(), false);
if (*file)
{
fwrite(info, 1, strlen(info), *file);
fflush(*file);
if (ftell(*file) >= MAX_LOG_FILE_SIZE)
{
fclose(*file);
remove(((std::string*)param2)->c_str());
*file = create_log_file(((std::string*)param2)->c_str(), true);
}
}
}
protected:
log_cls() : path_file_(""), file_(0), log_(&log_cls::log_consonle), level_(LOG_LEVEL_ALL)
{}
~log_cls()
{
if (file_)
{
fclose(file_);
file_ = 0;
}
}
public:
static log_cls* instance(void)
{
if (!log_cls::inst_)
log_cls::inst_ = new log_cls();
return log_cls::inst_;
}
static void clear(void)
{
if(log_cls::inst_)
{
delete log_cls::inst_;
log_cls::inst_ = nullptr;
}
}
int set_log_type(int type, void* param)
{
int ret = 0;
if (file_)
{
fclose(file_);
file_ = 0;
}
type_ = type;
if (type == LOG_TYPE_NONE)
log_ = &log_cls::log_none;
else if (type == LOG_TYPE_CONSOLE)
log_ = &log_cls::log_consonle;
else if (type == LOG_TYPE_FILE)
{
log_ = &log_cls::log_file;
ret = -1;
if (param)
{
path_file_ = (char*)param;
file_ = create_log_file(path_file_.c_str(), false);
if (file_)
ret = 0;
}
}
if (ret != 0)
{
log_ = &log_cls::log_none;
type_ = LOG_TYPE_NONE;
}
return ret;
}
void set_log_level(int level)
{
level_ = level;
}
int level(void)
{
return level_;
}
int type(void)
{
return type_;
}
void log(const char* info)
{
std::lock_guard<std::mutex> lock(lock_);
log_(info, &file_, &path_file_);
}
std::string get_log_file_path(const char* dst = nullptr)
{
std::string file("");
if (log_ == &log_cls::log_file && file_)
{
file = path_file_;
if (dst)
{
file = dst;
FILE* dst = fopen(file.c_str(), "wb");
if (!dst)
file = "";
else
{
std::lock_guard<std::mutex> lock(lock_);
char buf[1024] = { 0 };
size_t l = 0;
fseek(file_, 0, SEEK_SET);
while ((l = fread(buf, 1, sizeof(buf), file_)))
fwrite(buf, 1, l, dst);
fclose(dst);
}
}
}
return file;
}
void clear_log(void)
{
if (log_ == &log_cls::log_file && file_)
{
std::lock_guard<std::mutex> lock(lock_);
fclose(file_);
remove(path_file_.c_str());
file_ = create_log_file(path_file_.c_str(), true);
}
}
};
log_cls* log_cls::inst_ = NULL;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// util
namespace utils
{
static bool STDCALL match_part_filename(const char* path_name, bool dir, void* param)
{
std::string* partn = (std::string*)param;
if (!dir)
{
if (partn[0].empty())
{
partn[1] = path_name;
}
else
{
const char* name = strrchr(path_name, PATH_SEPARATOR[0]);
if (name++ == nullptr)
name = path_name;
std::string n(name);
to_lower(n);
if (strstr(n.c_str(), partn[0].c_str()))
partn[1] = path_name;
else
dir = true;
}
}
return dir;
}
#if OS_WIN
static std::string u2m(const wchar_t* u, int page)
{
char* ansi = NULL;
int len = 0;
std::string mb("");
len = WideCharToMultiByte(page, 0, u, lstrlenW(u), NULL, 0, NULL, NULL);
ansi = new char[len + 2];
len = WideCharToMultiByte(page, 0, u, lstrlenW(u), ansi, len, NULL, NULL);
ansi[len--] = 0;
mb = ansi;
delete[] ansi;
return mb;
}
static std::wstring m2u(const char* m, int page)
{
wchar_t* unic = NULL;
int len = 0;
std::wstring u(L"");
len = MultiByteToWideChar(page, 0, m, lstrlenA(m), NULL, 0);
unic = new wchar_t[len + 2];
len = MultiByteToWideChar(page, 0, m, lstrlenA(m), unic, len);
unic[len--] = 0;
u = unic;
delete[] unic;
return u;
}
std::string utf82ansi(const char* utf8)
{
return u2m(m2u(utf8, CP_UTF8).c_str(), CP_ACP);
}
std::string ansi2utf8(const char* ansi)
{
return u2m(m2u(ansi, CP_ACP).c_str(), CP_UTF8);
}
#else
// This function will return 'in' string if failed !
static std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int *err)
{
size_t len = strlen(in) + 8, ol = len * 2;
char *buf = (char*)malloc(len), *oper = buf, *out = nullptr, *oper1 = nullptr;
iconv_t conv;
memset(buf, 0, len);
strcpy(buf, in);
if(to_utf8)
conv = iconv_open("UTF-8", "GBK");
else
conv = iconv_open("GBK", "UTF-8");
if(conv == (iconv_t)-1)
{
if(err)
*err = errno;
free(buf);
return in;
}
oper1 = out = (char*)malloc(ol);
memset(out, 0, ol);
len -= 8;
if(iconv(conv, &oper, &len, &oper1, &ol))
{
if(err)
*err = errno;
}
else if(err)
*err = 0;
std::string ret(out);
free(buf);
free(out);
iconv_close(conv);
return ret.empty() ? in : std::move(ret);
}
std::string utf82ansi(const char* utf8)
{
// fix me ...
return transform_between_gbk_and_utf8(utf8, false, nullptr);
}
std::string ansi2utf8(const char* ansi)
{
// fix me ...
return transform_between_gbk_and_utf8(ansi, true, nullptr);
}
#endif
std::string get_command_result(const char* cmd, int len)
{
std::string result("");
#if OS_WIN
#else
FILE* src = popen(cmd, "r");
if (src)
{
char buf[128] = { 0 };
int rv = fread(buf, 1, sizeof(buf) - 1, src);
while (rv > 0)
{
buf[rv] = 0;
result += buf;
if (len != -1 && result.length() >= len)
{
result.erase(len);
break;
}
rv = fread(buf, 1, sizeof(buf) - 1, src);
}
pclose(src);
}
#endif
return std::move(result);
}
std::string get_local_data_path(void)
{
static std::string ldp("");
if (ldp.empty())
{
#if OS_WIN
const char* path(getenv("LOCALAPPDATA"));
if (path)
{
ldp = path;
ldp += PATH_SEPARATOR;
}
#else
const char* path(getenv("HOME"));
if (path)
{
if (strstr(path, "/root"))
{
std::string usr(get_command_result("logname"));
ldp = std::string("/home/") + trim(usr);
if (!opendir(ldp.c_str()))
{
printf("opendir(%s) failed: %s\n", ldp.c_str(), strerror(errno));
ldp = path;
}
}
else
{
ldp = path;
}
ldp += std::string(PATH_SEPARATOR) + ".";
}
#endif
ldp += PRODUCT_VENDOR;
ldp += "Scan";
create_folder(ldp.c_str());
std::string first("[" + format_current_time() + "]: Process "),
ff(temporary_path() + PATH_SEPARATOR + "scanner-first.log");
first += std::to_string(GetCurrentProcessId()) + " root of local data path is " + ldp + "\n";
save_2_file(&first[0], first.length(), ff.c_str(), true);
}
return ldp;
}
std::string temporary_path(void)
{
return std::move(simple_ini::temporary_path());
}
std::string format_current_time(void)
{
return std::move(chronograph::now());
}
std::string get_module_full_path(const char* part_name/*nullptr to get main-pe/first module's full path*/)
{
std::string file[] = { part_name ? part_name : "", ""};
to_lower(file[0]);
#if OS_WIN
if (part_name && *part_name)
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32W pei = { 0 };
if (h != INVALID_HANDLE_VALUE)
{
pei.dwSize = sizeof(pei);
if (Module32FirstW(h, &pei))
{
do
{
char path[256] = { 0 };
GetModuleFileNameA(pei.hModule, path, _countof(path) - 1);
if (!match_part_filename(path, false, (void*)file))
break;
pei.dwSize = sizeof(pei);
} while (Module32NextW(h, &pei));
}
CloseHandle(h);
}
}
else
{
char path[256] = { 0 };
GetModuleFileNameA(NULL, path, _countof(path) - 1);
file[1] = path;
}
#else
char path[128] = { 0 };
sprintf(path, "/proc/%u/map_files/", getpid());
enum_file(path, false, match_part_filename, (void*)file);
#endif
return std::move(file[1]);
}
std::string target_file_from_link(const char* lnk_file)
{
#if OS_WIN
std::string ret("");
return ret;
#else
char path[256] = { 0 };
int len = readlink(lnk_file, path, sizeof(path) - 1);
return len > 0 ? path : lnk_file;
#endif
}
std::string get_ini_value(const char* seg, const char* key, const char* cfg_file)
{
char buf[512] = { 0 };
GetPrivateProfileStringA(seg, key, "", buf, sizeof(buf) - 1, cfg_file);
return buf;
}
std::string load_mini_file(const char* file, int* err)
{
std::string cont("");
FILE* src = fopen(file, "rb");
if (src)
{
long len = 0;
fseek(src, 0, SEEK_END);
len = ftell(src);
fseek(src, 0, SEEK_SET);
if (len > SIZE_MB(1))
{
if (err)
*err = E2BIG;
}
else
{
char* buf = new char[len];
if (buf)
{
len = fread(buf, 1, len, src);
cont = std::string(buf, len);
if (err)
*err = 0;
delete[] buf;
}
else if (err)
*err = ENOMEM;
}
fclose(src);
}
else if (err)
*err = errno;
return std::move(cont);
}
int save_2_file(void* data, size_t len, const char* file, bool append)
{
FILE* dst = fopen(file, append ? "w+b" : "wb");
int err = 0;
if (!dst)
return errno;
if (fwrite(data, 1, len, dst) < len)
err = ENOSPC;
fclose(dst);
return err;
}
const char* to_lower(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), tolower);
return str.c_str();
}
const char* trim(std::string& str, const char* sp)
{
int pos = 0;
char ch[2] = { 0 };
for (; pos < str.length(); ++pos)
{
ch[0] = str[pos];
if (!strstr(sp, ch))
break;
}
if (pos)
str.erase(0, pos);
pos = str.length() - 1;
for (; pos >= 0; --pos)
{
ch[0] = str[pos];
if (!strstr(sp, ch))
break;
}
if (++pos < str.length())
str.erase(pos);
return str.c_str();
}
bool create_folder(const char* folder)
{
int ret = MKDIR(folder, S_IREAD | S_IWRITE | S_IEXEC);
return ret == 0 || errno == EEXIST;
}
void set_ini_value(const char* seg, const char* key, const char* val, const char* cfg_file)
{
WritePrivateProfileStringA(seg, key, val, cfg_file);
}
int enum_file(const char* folder, bool recursive, bool(STDCALL* found)(const char* path_name, bool dir, void* param), void* param)
{
int ret = EACCES;
#if OS_WIN
WIN32_FIND_DATAA fd = { 0 };
HANDLE hf = FindFirstFileA(folder, &fd);
if (hf == INVALID_HANDLE_VALUE)
ret = GetLastError();
else
{
do
{
bool is_dir = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
if (!found(fd.cFileName, is_dir, param))
{
ret = ERROR_CANCELLED;
break;
}
if (is_dir && recursive)
{
char* name = strrchr(fd.cFileName, PATH_SEPARATOR[0]);
if (name++ == NULL)
name = fd.cFileName;
if (strcmp(name, ".") && strcmp(name, ".."))
{
if (enum_file(fd.cFileName, recursive, found, param) == ERROR_CANCELLED)
{
ret = ERROR_CANCELLED;
break;
}
}
}
} while (FindNextFileA(hf, &fd));
FindClose(hf);
}
#else
DIR* pdir = nullptr;
struct dirent* ent = nullptr;
pdir = opendir(folder);
if (!pdir)
ret = errno;
else
{
while ((ent = readdir(pdir)))
{
std::string file(folder);
file += PATH_SEPARATOR;
file += ent->d_name;
if (!found(target_file_from_link(file.c_str()).c_str(), ent->d_type & DT_DIR, param))
{
ret = ERROR_CANCELLED;
break;
}
if (ent->d_type & DT_DIR)
{
if (recursive)
{
if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, ".."))
{
std::string sub(folder);
sub += PATH_SEPARATOR;
sub += ent->d_name;
if (enum_file(sub.c_str(), recursive, found, param) == ERROR_CANCELLED)
{
ret = ERROR_CANCELLED;
break;
}
}
}
}
}
}
#endif
return ret;
}
int move_file(const char* from, const char* to)
{
return rename(from, to);
}
int get_disk_space(const char* path, unsigned long long* total, unsigned long long* avail, unsigned long long* block)
{
int ret = 0;
#if defined(WIN32) || defined(_WIN64)
ULARGE_INTEGER av = { 0 },
all = { 0 };
if (GetDiskFreeSpaceExA(path, &av, &all, NULL))
{
if (total)
*total = all.QuadPart;
if (avail)
*avail = av.QuadPart;
if (block)
{
DWORD sec = 0,
clu = 0;
std::string root(path);
size_t pos = root.find(":\\");
if (pos != std::string::npos)
root.erase(pos + 2);
if (GetDiskFreeSpaceA(root.c_str(), &clu, &sec, NULL, NULL))
{
*block = clu * sec;
}
}
}
else
ret = GetLastError();
#else
struct statfs fs = { 0 };
ret = statfs(path, &fs);
if (ret == 0)
{
utils::to_log(LOG_LEVEL_DEBUG, " Total: %lld, Free: %lld, Avail: %lld, block size: %lld\n",
fs.f_blocks, fs.f_bfree, fs.f_bavail, fs.f_bsize);
if (total)
*total = fs.f_blocks * fs.f_bsize;
if (avail)
*avail = fs.f_bavail * fs.f_bsize;
if (block)
*block = fs.f_bsize;
}
#endif
return ret;
}
unsigned int get_page_size(unsigned int* map_unit)
{
unsigned int ps = 1024;
#if defined(WIN32) || defined(_WIN64)
SYSTEM_INFO si = { 0 };
GetSystemInfo(&si);
ps = si.dwPageSize;
if (map_unit)
*map_unit = si.dwAllocationGranularity;
#else
ps = sysconf(_SC_PAGESIZE);
if(ps < 1024 || (ps & 0x0fe0000ff)) // nKB && < 16MB
ps = getpagesize();
if (map_unit)
*map_unit = ps;
#endif
if (ps < 1024 || (ps & 0x0fe0000ff)) // nKB && < 16MB
ps = 1024;
return ps;
}
void init_log(log_type type, log_level level, const char* fn_appendix)
{
std::string file("");
if (type == LOG_TYPE_FILE)
{
file = get_local_data_path() + PATH_SEPARATOR + "Log";
create_folder(file.c_str());
std::string pe(get_module_full_path());
size_t pos = pe.rfind(PATH_SEPARATOR[0]);
if (pos++ == std::string::npos)
pos = 0;
file += PATH_SEPARATOR + pe.substr(pos);
if (fn_appendix)
file += fn_appendix;
file += ".log";
}
log_cls::instance()->set_log_type(type, &file[0]);
log_cls::instance()->set_log_level(level);
}
void uninit(void)
{
log_cls::clear();
}
void log_info(const char* info, int level)
{
if (get_log_type() != LOG_TYPE_NONE && get_log_level() <= level)
{
log_cls::instance()->log(("[" + format_current_time() + "]: " + info).c_str());
}
}
void log_mem_info(const char* desc, const void* data, size_t bytes, int level)
{
if (get_log_type() == LOG_TYPE_NONE || get_log_level() > level)
return;
std::string line(desc);
char buf[40] = {0};
utils::log_info((line + "\n").c_str(), level);
line = "";
for(size_t i = 0; i < bytes; ++i)
{
if((i % 16) == 0)
{
if(line.length())
utils::log_info((line + "\n").c_str(), level);
sprintf(buf, "%p ", (const char*)data + i);
line = buf;
}
else if((i % 8) == 0)
line += " ";
sprintf(buf, "%02x ", ((const unsigned char*)data)[i]);
line += buf;
}
if(line.length())
utils::log_info((line + "\n").c_str(), level);
}
int get_log_type(void)
{
return log_cls::instance()->type();
}
int get_log_level(void)
{
return log_cls::instance()->level();
}
int copy_log_file_to(const char* dst)
{
log_cls::instance()->get_log_file_path(dst);
return 0;
}
int clear_log_file(void)
{
log_cls::instance()->clear_log();
return 0;
}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// util
chronograph::chronograph()
{
reset();
}
chronograph::~chronograph()
{}
bool chronograph::now(TIMEV* tv)
{
struct timezone tz = { 0 };
return gettimeofday(tv, &tz) == 0;
}
bool chronograph::now(uint64_t* seconds, uint64_t* u_seconds)
{
TIMEV tv = { 0 };
struct timezone tz = { 0 };
if (gettimeofday(&tv, &tz) == 0)
{
if (seconds)
*seconds = tv.tv_sec;
if (u_seconds)
*u_seconds = tv.tv_usec;
return true;
}
else
{
return false;
}
}
std::string chronograph::now(bool with_ms/*whether with milliseconds*/) // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false
{
TIMEV tv = { 0 };
if (!chronograph::now(&tv))
return "";
char buf[40] = { 0 };
time_t t = tv.tv_sec;
struct tm* l = localtime(&t);
if (with_ms)
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday
, l->tm_hour, l->tm_min, l->tm_sec, tv.tv_usec);
else
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday
, l->tm_hour, l->tm_min, l->tm_sec);
return buf;
}
uint64_t chronograph::elapse_s(void)
{
TIMEV tv = { 0 };
chronograph::now(&tv);
return tv.tv_sec - bgn_.tv_sec;
}
uint64_t chronograph::elapse_ms(void)
{
TIMEV tv = { 0 };
uint64_t dif = 0;
chronograph::now(&tv);
dif = SEC_2_MS(tv.tv_sec - bgn_.tv_sec);
dif += tv.tv_usec / MSEC_2_US(1);
dif -= bgn_.tv_usec / MSEC_2_US(1);
return dif;
}
uint64_t chronograph::elapse_us(void)
{
TIMEV tv = { 0 };
uint64_t dif = 0;
chronograph::now(&tv);
dif = SEC_2_US(tv.tv_sec - bgn_.tv_sec);
dif += tv.tv_usec;
dif -= bgn_.tv_usec;
return dif;
}
void chronograph::reset()
{
chronograph::now(&bgn_);
}