fork download
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <stdlib.h>
  4.  
  5. #include <unistd.h>
  6. #include <pthread.h>
  7.  
  8. #ifdef __QNX__
  9. #include <sys/neutrino.h>
  10. #include <sys/netmgr.h>
  11. #include <atomic.h>
  12. #elif defined (__linux__)
  13. #include <sys/timerfd.h>
  14. #ifdef __cplusplus
  15. #include <atomic>
  16. //#define _Atomic(X) std::atomic< X >
  17. using namespace std;
  18. #else
  19. #ifndef __STDC_NO_ATOMICS__
  20. #include <stdatomic.h>
  21. #endif
  22. #endif
  23. #endif
  24.  
  25. #include "utilites.h" //Лог, конфигурация, работа со строками
  26. #include "../sw_emka2_sil2_bur_utilites/can2udp/cfilter.h"
  27. #include "impl/defines.h" //Типы данных
  28. #include "impl/routines.h" //Прикладные функции программы
  29. #include "../sw_emka2_sil1_bur_canlib/can_lib.h" //Библиотека CAN
  30.  
  31. #include "svnrevision.h"
  32.  
  33. //
  34. volatile bool b_doExit = false; //Признак завершения программы
  35. #ifdef __QNX__
  36. volatile unsigned g_n_tickCnt = 0; ///Количество тиков
  37. #elif defined (__linux__)
  38. volatile atomic_uint g_n_tickCnt(0); ///Количество тиков
  39. #endif
  40. volatile unsigned g_n_tickItvMs = 1; ///Интервал между тиками, миллисекунды.
  41.  
  42. char g_sz_hbPath[] = "/tmp/sw_emka2_sil1_bur_can2udp_hb.txt";
  43.  
  44. #define MY_PULSE_CODE_CONTROLBUO _PULSE_CODE_MINAVAIL
  45. #define MAX_HB 65536
  46. #define FLUSH_LOG_ITV 100
  47. #define FLUSH_LOG_TICK (FLUSH_LOG_ITV < g_n_tickItvMs ? 1 : FLUSH_LOG_ITV / g_n_tickItvMs)
  48.  
  49. #ifdef __QNX__
  50. typedef union
  51. {
  52.  
  53. struct _pulse pulse;
  54.  
  55. /* your other message structures would go here too */
  56.  
  57. } my_message_t;
  58. #endif
  59.  
  60. /**
  61.  * @brief Структура, содержащая данные по параметрам командной строки
  62.  */
  63. typedef struct SCmdParams
  64. {
  65. char m_sz_cfgFile[MAX_STRLEN];///Путь к файлу конфигурации.
  66. char m_sz_logFile[MAX_STRLEN];///Путь к файлу лога.
  67. bool m_b_help;///Запрос на вывод справки.
  68. } DTCmdParams;
  69.  
  70. /**
  71.  * @brief Функция вывода справки в стандартный вывод.
  72.  *
  73.  * @param sz_name -- название программы.
  74.  */
  75. void usage(const char* sz_name);
  76.  
  77. /**
  78.  * @brief Функция разбора параметров командной строки.
  79.  *
  80.  * @param s32_argc -- количество параметров командной строки;
  81.  * @param p_sz_argv -- указатель на массив параметров командной строки.
  82.  * @param h_cmd -- струкута с параметрами командной строки.
  83.  *
  84.  * @return
  85.  * @arg true -- параметры командной строки распознаны, ошибок нет.
  86.  * @arg false -- не заданы требуемые параметры.
  87.  */
  88. bool parseArgs(int32_t s32_argc,
  89. char* p_sz_argv[],
  90. DTCmdParams& h_cmd);
  91.  
  92. /**
  93.  * @brief Функция сохранения данных о номере версии ПО устройство разделяемой памяти.
  94.  *
  95.  * @param u32_version -- номер версии ПО.
  96.  */
  97. void saveVersion(uint32_t u32_version);
  98.  
  99. /**
  100.  * @brief Функция записи счетчика жизни в файл.
  101.  *
  102.  * @param u64_tickCnt -- счетчик циклов;
  103.  * @param sz_path -- полный или относительный путь к целефому файлу.
  104.  */
  105. void WriteHB(uint64_t u64_tickCnt,
  106. const char* sz_path);
  107.  
  108. /**
  109.  * @brief Точка входа в программу.
  110.  *
  111.  * @param s32_argc -- количество параметров командной строки;
  112.  * @param p_sz_argv -- указатель на массив параметров командной строки.
  113.  *
  114.  * @return
  115.  * @arg EXIT_FAILURE -- в случае ошибки.
  116.  * @arg EXIT_SUCCESS -- при отсутствии ошибок.
  117.  */
  118. int main(int32_t s32_argc,
  119. char* p_sz_argv[])
  120. {
  121. int32_t s32_res = EXIT_SUCCESS;
  122.  
  123. DTRoute v_route[MAX_ROUTES];
  124. DTCanInfo v_canInfo[MAX_CAN];
  125. DTGroupInfo v_grpInfo[MAX_GROUPS];
  126. int32_t v_canFds[MAX_CAN];
  127. int32_t v_grpFds[MAX_GROUPS];
  128. CFilter* v_filterCan[MAX_FILTERS];
  129. for (int i = 0; i < MAX_FILTERS; i++) {
  130. v_filterCan[i] = NewFilter();
  131. }
  132.  
  133. DTCmdParams h_cmd;
  134. h_cmd.m_b_help = false;
  135. h_cmd.m_sz_cfgFile[0] = '\0';
  136. snprintf(&h_cmd.m_sz_logFile[0], sizeof(h_cmd.m_sz_logFile), "/var/log/%s.log", p_sz_argv[0]);
  137.  
  138. saveVersion(u32_svn_revision);
  139.  
  140. if (!parseArgs(s32_argc, p_sz_argv, h_cmd))
  141. {
  142. usage(p_sz_argv[0]);
  143. s32_res = EXIT_FAILURE;
  144. }
  145. else
  146. {
  147. doLog(h_cmd.m_sz_logFile, "Запуск программы.");
  148.  
  149. if (h_cmd.m_b_help)
  150. {
  151. usage(p_sz_argv[0]);
  152. }
  153. else //Читаем конфигурационный файл
  154. {
  155. CConfig h_cfg;
  156.  
  157. int32_t s32_errCode = 0;//Код ошибки
  158. int32_t n_canChannels = 0;//Количество каналов шины CAN
  159. int32_t n_udpChannels = 0;//Количество групп UDP-multicast
  160. int32_t n_filters = 0;//Количество фильтров в конфигурации
  161.  
  162. if (0 == (s32_errCode = h_cfg.Load(h_cmd.m_sz_cfgFile)))
  163. {
  164. //Чтение фильтров
  165. n_filters = readIdFilter(&h_cfg, v_filterCan, MAX_ROUTES, h_cmd.m_sz_logFile);
  166. //Заполнение данных по линиям шины CAN
  167. n_canChannels = readCanInfo(&h_cfg, &v_canInfo[0], MAX_CAN);
  168. //Заполнение данных по группам Multicast
  169. n_udpChannels = readGroupInfo(&h_cfg, &v_grpInfo[0], MAX_GROUPS);
  170. //Запуск портов CAN (получение дескрипторов CAN-портов)
  171. int32_t s32_res = runCanChannels(&v_canInfo[0], MAX_CAN, &v_canFds[0], n_canChannels);
  172. //Присоединение к группам UDP-multicast(получение дескрипторов Multicast-групп)
  173. s32_res = runMulticastChannels(&v_grpInfo[0], MAX_GROUPS, &v_grpFds[0], n_udpChannels);
  174. //Составление маршрутов
  175. int32_t s32_nRoutes = MAX_ROUTES;
  176. s32_errCode = readAndBuildRoutes(&h_cfg, &v_canFds[0], n_canChannels, &v_grpFds[0],
  177. n_udpChannels, v_grpInfo, n_udpChannels, v_filterCan, n_filters, &v_route[0],
  178. &s32_nRoutes);
  179.  
  180. if (-1 == s32_errCode)
  181. {
  182. doLog(h_cmd.m_sz_logFile, "Ошибка конфигурации: имеются некорректные маршруты.");
  183. }
  184. else
  185. {
  186. struct itimerspec itime;
  187. itime.it_value.tv_sec = 0;
  188. itime.it_value.tv_nsec = 1000000 * g_n_tickItvMs;
  189. itime.it_interval.tv_sec = 0;
  190. itime.it_interval.tv_nsec = 1000000 * g_n_tickItvMs;
  191.  
  192. #ifdef __QNX__
  193. struct sigevent event;
  194. timer_t timer_id;
  195. int chid;
  196. int rcvid;
  197. my_message_t msg;
  198.  
  199. chid = ChannelCreate(0);
  200. event.sigev_notify = SIGEV_PULSE;
  201. event.sigev_coid = ConnectAttach(ND_LOCAL_NODE, 0, chid, _NTO_SIDE_CHANNEL, 0);
  202. event.sigev_priority = getprio(0);
  203. event.sigev_code = MY_PULSE_CODE_CONTROLBUO;
  204. timer_create(CLOCK_REALTIME, &event, &timer_id);
  205. timer_settime(timer_id, 0, &itime, NULL);
  206. #elif defined (__linux__)
  207. // int timerfd = timerfd_create(CLOCK_MONOTONIC, 0); // создаёт новый объект таймера и возвращает файловый дескриптор, который ссылается на таймер. CLOCK_MONOTONIC/CLOCK_REALTIME -
  208. // if (timerfd == -1)
  209. // {
  210. // perror("timerfd_create");
  211. // exit(EXIT_FAILURE);
  212. // }
  213. // if (timerfd_settime(timerfd, 0, &itime, NULL) == -1) // запускает таймер
  214. // {
  215. // close(timerfd);
  216. // perror("timerfd_settime");
  217. // exit(EXIT_FAILURE);
  218. // }
  219. #endif
  220.  
  221. //Маршрутизация
  222. while (!b_doExit)
  223. {
  224.  
  225. #ifdef __QNX__
  226. rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL);
  227. if (rcvid == 0)
  228. {
  229. if (msg.pulse.code == MY_PULSE_CODE_CONTROLBUO)
  230. {
  231. atomic_add(&g_n_tickCnt, 1U);
  232. #elif defined (__linux__)
  233. // {
  234. // uint64_t expirationsNumber = 0; //
  235. // ssize_t s = read(timerfd, &expirationsNumber, sizeof(uint64_t)); // wait of timer
  236. // if (s != sizeof(uint64_t))
  237. // {
  238. // //perror("read");
  239. // continue; //
  240. // }
  241. // else
  242. // {
  243. // ++g_n_tickCnt;
  244. #endif
  245.  
  246. uint8_t u8_hiMask = 0;
  247. //Получение маски (1-й раз через 15-16 секун после запуска, далее -- каждые 5-6 секунд)
  248. parseProps(&h_cfg, &u8_hiMask);
  249. //Передача данных по всем маршрутам
  250. for (int i = 0; i < s32_nRoutes && !b_doExit; ++i)
  251. {
  252. if (!b_doExit)
  253. broadcastCAN(&v_route[i], u8_hiMask, &v_canFds[0], n_canChannels, &v_grpFds[0],
  254. n_udpChannels, &v_filterCan[0], n_filters);
  255.  
  256. if (!b_doExit)
  257. broadcastUDP(&v_route[i], u8_hiMask, &v_canFds[0], n_canChannels, &v_grpFds[0],
  258. n_udpChannels, &v_filterCan[0], n_filters);
  259. }
  260. WriteHB(g_n_tickCnt, g_sz_hbPath);
  261. #ifdef __WITH_PKG_MAP__
  262. if (g_n_tickCnt % FLUSH_LOG_TICK == 0)
  263. can_flush_log();
  264. #endif
  265. }
  266. }
  267.  
  268. }//while
  269. }
  270. }//Load
  271. else
  272. doLog(h_cmd.m_sz_logFile, "Конфигурационный файл не доступен или содержит ошибки.");
  273. }
  274. }//parse
  275. doLog(h_cmd.m_sz_logFile, "Завершение программы.");
  276. return s32_res;
  277. }
  278.  
  279. /**
  280.  * @brief Функция вывода справки в стандартный вывод.
  281.  *
  282.  * @param sz_name -- название программы.
  283.  */
  284. void usage(const char* sz_name)
  285. {
  286. printf("usage: %s --config=/path/to/config [--log=/path/to/log] | --help \n", sz_name);
  287. printf(" --config -- the absolute or relative path to the configuration file\n");
  288. printf(" --log -- the absolute or relative path to the log-file.\n");
  289. printf(" --help -- show this message.\n\n");
  290. }
  291.  
  292. /**
  293.  * @brief Функция разбора параметров командной строки.
  294.  *
  295.  * @param s32_argc -- количество параметров командной строки;
  296.  * @param p_sz_argv -- указатель на массив параметров командной строки.
  297.  * @param h_cmd -- струкута с параметрами командной строки.
  298.  *
  299.  * @return
  300.  * @arg true -- параметры командной строки распознаны, ошибок нет.
  301.  * @arg false -- не заданы требуемые параметры.
  302.  */
  303. bool parseArgs(int32_t s32_argc,
  304. char* p_sz_argv[],
  305. DTCmdParams & h_cmd)
  306. {
  307. bool b_res = false;
  308.  
  309. if (s32_argc < 3)
  310. {
  311. std::list<std::pair<std::string, std::string> > v_cmd;
  312.  
  313. for (int i = 1; i < s32_argc; ++i)
  314. {
  315. std::string str(p_sz_argv[i]);
  316. std::list<std::string> v_str = strsub::split(str, "=");
  317. v_cmd.push_back(std::make_pair(v_str.front(), v_str.size() > 1 ? v_str.back() : std::string(
  318. "")));
  319. }
  320.  
  321. bool b_done = false;
  322. for (std::list<std::pair<std::string, std::string> >::iterator it = v_cmd.begin(); it
  323. != v_cmd.end() && !b_done; ++it)
  324. {
  325. if (it->first == "--help" && s32_argc == 2)
  326. {
  327. b_done = true;
  328. b_res = true;
  329. h_cmd.m_b_help = true;
  330. }
  331.  
  332. if (it->first == "--config" && !it->second.empty())
  333. {
  334. b_res = true;
  335. snprintf(&h_cmd.m_sz_cfgFile[0], sizeof(h_cmd.m_sz_cfgFile), "%s", it->second.c_str());
  336. }
  337.  
  338. if (it->first == "--log" && !it->second.empty())
  339. snprintf(&h_cmd.m_sz_logFile[0], sizeof(h_cmd.m_sz_logFile), "%s", it->second.c_str());
  340. }
  341. }
  342. return b_res;
  343. }
  344.  
  345. /**
  346.  * @brief Функция сохранения данных о номере версии ПО устройство разделяемой памяти.
  347.  *
  348.  * @param u32_version -- номер версии ПО.
  349.  */
  350. void saveVersion(uint32_t u32_version)
  351. {
  352. const char sz_path[] = "/tmp/sw_emka2_sil1_bur_can2udp_ver.txt";
  353. FILE* p_fd = fopen(sz_path, "w");
  354. if (p_fd)
  355. {
  356. fprintf(p_fd, "%d\n", u32_version);
  357. fclose(p_fd);
  358. }
  359. }
  360.  
  361. /**
  362.  * @brief Функция записи счетчика жизни в файл.
  363.  *
  364.  * @param u64_tickCnt -- счетчик циклов;
  365.  * @param sz_path -- полный или относительный путь к целефому файлу.
  366.  */
  367. void WriteHB(uint64_t u64_tickCnt,
  368. const char* sz_path)
  369. {
  370. if (sz_path)
  371. {
  372. FILE* fd = fopen(sz_path, "w+");
  373. if (fd)
  374. {
  375. fprintf(fd, "%d", (int32_t)(u64_tickCnt % MAX_HB));
  376. fclose(fd);
  377. }
  378. }
  379. }
  380.  
Success #stdin #stdout 0.02s 25384KB
stdin
Standard input is empty
stdout
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#include <unistd.h>
#include <pthread.h>

#ifdef __QNX__
#include <sys/neutrino.h>
#include <sys/netmgr.h>
#include <atomic.h>
#elif defined (__linux__)
#include <sys/timerfd.h>
#ifdef __cplusplus
#include <atomic>
 //#define _Atomic(X) std::atomic< X >
using namespace std;
#else
#ifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#endif
#endif
#endif

#include "utilites.h" //Лог, конфигурация, работа со строками
#include "../sw_emka2_sil2_bur_utilites/can2udp/cfilter.h"
#include "impl/defines.h"  //Типы данных
#include "impl/routines.h" //Прикладные функции программы
#include "../sw_emka2_sil1_bur_canlib/can_lib.h" //Библиотека CAN

#include "svnrevision.h"

 //
volatile bool b_doExit = false; //Признак завершения программы
#ifdef __QNX__
volatile unsigned g_n_tickCnt = 0; ///Количество тиков
#elif defined (__linux__)
volatile atomic_uint g_n_tickCnt(0); ///Количество тиков
#endif
volatile unsigned g_n_tickItvMs = 1; ///Интервал между тиками, миллисекунды.

char g_sz_hbPath[] = "/tmp/sw_emka2_sil1_bur_can2udp_hb.txt";

#define MY_PULSE_CODE_CONTROLBUO   _PULSE_CODE_MINAVAIL
#define MAX_HB  65536
#define FLUSH_LOG_ITV   100
#define FLUSH_LOG_TICK  (FLUSH_LOG_ITV < g_n_tickItvMs ? 1 : FLUSH_LOG_ITV / g_n_tickItvMs)

#ifdef __QNX__
typedef union
{

	struct _pulse pulse;

	/* your other message structures would go here too */

} my_message_t;
#endif

/**
 * @brief Структура, содержащая данные по параметрам командной строки
 */
typedef struct SCmdParams
{
	char m_sz_cfgFile[MAX_STRLEN];///Путь к файлу конфигурации.
	char m_sz_logFile[MAX_STRLEN];///Путь к файлу лога.
	bool m_b_help;///Запрос на вывод справки.
} DTCmdParams;

/**
 * @brief Функция вывода справки в стандартный вывод.
 *
 * @param sz_name -- название программы.
 */
void usage(const char* sz_name);

/**
 * @brief Функция разбора параметров командной строки.
 *
 * @param s32_argc -- количество параметров командной строки;
 * @param p_sz_argv -- указатель на массив параметров командной строки.
 * @param h_cmd -- струкута с параметрами командной строки.
 *
 * @return
 *   @arg true -- параметры командной строки распознаны, ошибок нет.
 *   @arg false -- не заданы требуемые параметры.
 */
bool parseArgs(int32_t s32_argc,
	char* p_sz_argv[],
	DTCmdParams& h_cmd);

/**
 * @brief Функция сохранения данных о номере версии ПО устройство разделяемой памяти.
 *
 * @param u32_version -- номер версии ПО.
 */
void saveVersion(uint32_t u32_version);

/**
 * @brief Функция записи счетчика жизни в файл.
 *
 * @param u64_tickCnt -- счетчик циклов;
 * @param sz_path -- полный или относительный путь к целефому файлу.
 */
void WriteHB(uint64_t u64_tickCnt,
	const char* sz_path);

/**
 * @brief Точка входа в программу.
 *
 * @param s32_argc -- количество параметров командной строки;
 * @param p_sz_argv -- указатель на массив параметров командной строки.
 *
 * @return
 *   @arg EXIT_FAILURE -- в случае ошибки.
 *   @arg EXIT_SUCCESS -- при отсутствии ошибок.
 */
int main(int32_t s32_argc,
	char* p_sz_argv[])
{
	int32_t s32_res = EXIT_SUCCESS;

	DTRoute v_route[MAX_ROUTES];
	DTCanInfo v_canInfo[MAX_CAN];
	DTGroupInfo v_grpInfo[MAX_GROUPS];
	int32_t v_canFds[MAX_CAN];
	int32_t v_grpFds[MAX_GROUPS];
	CFilter* v_filterCan[MAX_FILTERS];
	for (int i = 0; i < MAX_FILTERS; i++) {
		v_filterCan[i] = NewFilter();
	}

	DTCmdParams h_cmd;
	h_cmd.m_b_help = false;
	h_cmd.m_sz_cfgFile[0] = '\0';
	snprintf(&h_cmd.m_sz_logFile[0], sizeof(h_cmd.m_sz_logFile), "/var/log/%s.log", p_sz_argv[0]);

	saveVersion(u32_svn_revision);

	if (!parseArgs(s32_argc, p_sz_argv, h_cmd))
	{
		usage(p_sz_argv[0]);
		s32_res = EXIT_FAILURE;
	}
	else
	{
		doLog(h_cmd.m_sz_logFile, "Запуск программы.");

		if (h_cmd.m_b_help)
		{
			usage(p_sz_argv[0]);
		}
		else //Читаем конфигурационный файл
		{
			CConfig h_cfg;

			int32_t s32_errCode = 0;//Код ошибки
			int32_t n_canChannels = 0;//Количество каналов шины CAN
			int32_t n_udpChannels = 0;//Количество групп UDP-multicast
			int32_t n_filters = 0;//Количество фильтров в конфигурации

			if (0 == (s32_errCode = h_cfg.Load(h_cmd.m_sz_cfgFile)))
			{
				//Чтение фильтров
				n_filters = readIdFilter(&h_cfg, v_filterCan, MAX_ROUTES, h_cmd.m_sz_logFile);
				//Заполнение данных по линиям шины CAN
				n_canChannels = readCanInfo(&h_cfg, &v_canInfo[0], MAX_CAN);
				//Заполнение данных по группам Multicast
				n_udpChannels = readGroupInfo(&h_cfg, &v_grpInfo[0], MAX_GROUPS);
				//Запуск портов CAN (получение дескрипторов CAN-портов)
				int32_t s32_res = runCanChannels(&v_canInfo[0], MAX_CAN, &v_canFds[0], n_canChannels);
				//Присоединение к группам UDP-multicast(получение дескрипторов Multicast-групп)
				s32_res = runMulticastChannels(&v_grpInfo[0], MAX_GROUPS, &v_grpFds[0], n_udpChannels);
				//Составление маршрутов
				int32_t s32_nRoutes = MAX_ROUTES;
				s32_errCode = readAndBuildRoutes(&h_cfg, &v_canFds[0], n_canChannels, &v_grpFds[0],
					n_udpChannels, v_grpInfo, n_udpChannels, v_filterCan, n_filters, &v_route[0],
					&s32_nRoutes);

				if (-1 == s32_errCode)
				{
					doLog(h_cmd.m_sz_logFile, "Ошибка конфигурации: имеются некорректные маршруты.");
				}
				else
				{
					struct itimerspec       itime;
					itime.it_value.tv_sec = 0;
					itime.it_value.tv_nsec = 1000000 * g_n_tickItvMs;
					itime.it_interval.tv_sec = 0;
					itime.it_interval.tv_nsec = 1000000 * g_n_tickItvMs;

#ifdef __QNX__
					struct sigevent         event;
					timer_t                 timer_id;
					int                     chid;
					int                     rcvid;
					my_message_t            msg;

					chid = ChannelCreate(0);
					event.sigev_notify = SIGEV_PULSE;
					event.sigev_coid = ConnectAttach(ND_LOCAL_NODE, 0, chid, _NTO_SIDE_CHANNEL, 0);
					event.sigev_priority = getprio(0);
					event.sigev_code = MY_PULSE_CODE_CONTROLBUO;
					timer_create(CLOCK_REALTIME, &event, &timer_id);
					timer_settime(timer_id, 0, &itime, NULL);
#elif defined (__linux__)
					// int timerfd = timerfd_create(CLOCK_MONOTONIC, 0); // создаёт новый объект таймера и возвращает файловый дескриптор, который ссылается на таймер. CLOCK_MONOTONIC/CLOCK_REALTIME -
					// if (timerfd == -1)
					// {
						// perror("timerfd_create");
						// exit(EXIT_FAILURE);
					// }
					// if (timerfd_settime(timerfd, 0, &itime, NULL) == -1) // запускает таймер
					// {
						// close(timerfd);
						// perror("timerfd_settime");
						// exit(EXIT_FAILURE);
					// }
#endif

					//Маршрутизация
					while (!b_doExit)
					{

#ifdef __QNX__
						rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL);
						if (rcvid == 0)
						{
							if (msg.pulse.code == MY_PULSE_CODE_CONTROLBUO)
							{
								atomic_add(&g_n_tickCnt, 1U);
#elif defined (__linux__)
								// {
									// uint64_t expirationsNumber = 0; //
									// ssize_t s = read(timerfd, &expirationsNumber, sizeof(uint64_t)); // wait of timer
									// if (s != sizeof(uint64_t))
									// {
										// //perror("read");
										// continue; //
									// }
									// else
									// {
										// ++g_n_tickCnt;
#endif

										uint8_t u8_hiMask = 0;
										//Получение маски (1-й раз через 15-16 секун после запуска, далее -- каждые 5-6 секунд)
										parseProps(&h_cfg, &u8_hiMask);
										//Передача данных по всем маршрутам
										for (int i = 0; i < s32_nRoutes && !b_doExit; ++i)
										{
											if (!b_doExit)
												broadcastCAN(&v_route[i], u8_hiMask, &v_canFds[0], n_canChannels, &v_grpFds[0],
													n_udpChannels, &v_filterCan[0], n_filters);

											if (!b_doExit)
												broadcastUDP(&v_route[i], u8_hiMask, &v_canFds[0], n_canChannels, &v_grpFds[0],
													n_udpChannels, &v_filterCan[0], n_filters);
										}
										WriteHB(g_n_tickCnt, g_sz_hbPath);
#ifdef __WITH_PKG_MAP__
										if (g_n_tickCnt % FLUSH_LOG_TICK == 0)
											can_flush_log();
#endif
					}
				}

			}//while
		}
	}//Load
	else
	    doLog(h_cmd.m_sz_logFile, "Конфигурационный файл не доступен или содержит ошибки.");
}
  }//parse
	doLog(h_cmd.m_sz_logFile, "Завершение программы.");
	return s32_res;
}

/**
 * @brief Функция вывода справки в стандартный вывод.
 *
 * @param sz_name -- название программы.
 */
void usage(const char* sz_name)
{
	printf("usage: %s --config=/path/to/config [--log=/path/to/log] | --help \n", sz_name);
	printf("    --config -- the absolute or relative path to the configuration file\n");
	printf("    --log -- the absolute or relative path to the log-file.\n");
	printf("    --help -- show this message.\n\n");
}

/**
 * @brief Функция разбора параметров командной строки.
 *
 * @param s32_argc -- количество параметров командной строки;
 * @param p_sz_argv -- указатель на массив параметров командной строки.
 * @param h_cmd -- струкута с параметрами командной строки.
 *
 * @return
 *   @arg true -- параметры командной строки распознаны, ошибок нет.
 *   @arg false -- не заданы требуемые параметры.
 */
bool parseArgs(int32_t s32_argc,
	char* p_sz_argv[],
	DTCmdParams & h_cmd)
{
	bool b_res = false;

	if (s32_argc < 3)
	{
		std::list<std::pair<std::string, std::string> > v_cmd;

		for (int i = 1; i < s32_argc; ++i)
		{
			std::string str(p_sz_argv[i]);
			std::list<std::string> v_str = strsub::split(str, "=");
			v_cmd.push_back(std::make_pair(v_str.front(), v_str.size() > 1 ? v_str.back() : std::string(
				"")));
		}

		bool b_done = false;
		for (std::list<std::pair<std::string, std::string> >::iterator it = v_cmd.begin(); it
			!= v_cmd.end() && !b_done; ++it)
		{
			if (it->first == "--help" && s32_argc == 2)
			{
				b_done = true;
				b_res = true;
				h_cmd.m_b_help = true;
			}

			if (it->first == "--config" && !it->second.empty())
			{
				b_res = true;
				snprintf(&h_cmd.m_sz_cfgFile[0], sizeof(h_cmd.m_sz_cfgFile), "%s", it->second.c_str());
			}

			if (it->first == "--log" && !it->second.empty())
				snprintf(&h_cmd.m_sz_logFile[0], sizeof(h_cmd.m_sz_logFile), "%s", it->second.c_str());
		}
	}
	return b_res;
}

/**
 * @brief Функция сохранения данных о номере версии ПО устройство разделяемой памяти.
 *
 * @param u32_version -- номер версии ПО.
 */
void saveVersion(uint32_t u32_version)
{
	const char sz_path[] = "/tmp/sw_emka2_sil1_bur_can2udp_ver.txt";
	FILE* p_fd = fopen(sz_path, "w");
	if (p_fd)
	{
		fprintf(p_fd, "%d\n", u32_version);
		fclose(p_fd);
	}
}

/**
 * @brief Функция записи счетчика жизни в файл.
 *
 * @param u64_tickCnt -- счетчик циклов;
 * @param sz_path -- полный или относительный путь к целефому файлу.
 */
void WriteHB(uint64_t u64_tickCnt,
	const char* sz_path)
{
	if (sz_path)
	{
		FILE* fd = fopen(sz_path, "w+");
		if (fd)
		{
			fprintf(fd, "%d", (int32_t)(u64_tickCnt % MAX_HB));
			fclose(fd);
		}
	}
}