Руководство системного программиста / Описание форматов файлов структур и протоколов программного обеспечения прибора |
Файл конфигурации загрузки представляет собой текстовый файл в формате ASCII с разделителями строк символами с кодами 0D или 0D0A. Данный файл сообщает диспетчеру РМ информацию о том, какие именно расчётные модули необходимо загрузить, под какими именами алгоритмов и с каким интервалом их необходимо вызывать в процессе работы прибора.
Файл представляет собой таблицу, где на каждой строке описывается способ вызова расчётного модуля. Строки имеют следующий формат:
<имя исполняемого файла расчётного модуля> <имя алгоритма> <интервал вызова в мсек> <к-во вызовов (повторов) за один интервал вызова данного расчётного модуля>
….. и так на остальных строках. Разделитель слов в строке – пробел.
Пример текста в файле:
сalc algo1 60 1 сalc algo2 120 2
Процессы в данной версии исполняемой среды выполняются последовательно, в соответствии с тем как они описаны в файле конфигурации загрузки. При этом если у процессов установлен разный такт выполнения, то общий такт будет равен минимальному из заданных, но алгоритм у которого период выполнения задан больше будет выполняться не на каждом шаге. Т.е например для приведённого примера algo1 будет выполняться на каждом шаге, а algo2 – через шаг. Время, выводимое для отладчика (см. описание сетевого протокола GdbServer) равно: (минимальный из заданных шагов)*(к-во циклов диспетчера). При вызовах run-функции в расчётном модуле время равно 0, поскольку в явном виде нигде там не используется.
Такты выполнения расчётных модулей являются задаваемой и постоянной величиной. Для более подробной информации – см. исходный код DispExemod\main.c, функция takt_work. Ниже приведён фрагмент данной функции с кодом расчёта условного модельного времени:
void takt_work(void) { int count = 0; int k = 0; uint64_t cycle1 = 0; uint64_t cycle2 = 0; uint64_t ncycles = 0; uint64_t cps = 0; struct timespec req = { 0 }; double delta_scan = 0.0; double time_sleep = 0.0; char cmd[1] = {0}; char rep[1] = {0}; /*Цикл посылки сообщений для тестирования*/ while (1) { /*Количество циклов процессора до начала обработки бд*/ cycle1 = ClockCycles( ); /*Будем запускать на выполнение расчетные модули время * которых пришло */ for (count = 0; count < ptr_header->number_exemod; count++) { /*Текущий счетчик в 0 значит время пришло*/ if (ptr_exemod[count].tek_time == 0) { /*Отправим на выполнение расчетный модуль стоько * сколько он должен выполняться за один такт */ for (k = 0; k < ptr_exemod[count].num_work; k++) { cmd[0] = 0x01; MsgSend(ptr_exemod[count].coid, cmd, sizeof(cmd), rep, sizeof(rep)); } /*for (k = 0; k < ptr_exemod[count].num_work; k++)*/ /*Восстановим текущее время*/ ptr_exemod[count].tek_time = ptr_exemod[count].takt_mod; } /*if (ptr_exemod[count].tek_time == 0)*/ } /*for (count = 0; count < ptr_header->number_exemod; count++)*/ /*Количество циклов процессора после обработки бд*/ cycle2 = ClockCycles( ); /*Количество циклов ушедшее на обработку бд*/ ncycles = cycle2 - cycle1; /*Сколько циклов в секунде*/ cps = SYSPAGE_ENTRY(qtime)->cycles_per_sec; /*Время затраченное на обработку бд*/ delta_scan = (1000.0 * ((double) ncycles / cps)); /*Время сна, с компенсацией времени на предыдущем шаге*/ time_sleep = (double) ptr_header->takt - delta_scan; /*Спим оставшееся время до начала следующего такта*/ nsec2timespec(&req, (uint64_t) ( time_sleep * 1000000L)); /*Спим до начала следующего такта*/ if (nanosleep(&req, NULL) == -1) { perror("nanosleep"); } /*nanosleep.....*/ /*Еще один такт прошел уменьшим время ожидания запуска * расчетных модулей */ sheduler_takt(); //Это счётчик своих тактов синхронизатора, по нему считаем время ptr_header – это главная общая область памяти диспетчера /header ptr_header->takt_counter = ptr_header->takt_counter + 1; } /*while (1)*/ }
Далее при выводе времени на клиент (то есть в графическую оболочку) используется следующий код (GdbServer.c функция packet_send):
int packet_send(void) { header_packet header = {0}; signal_addr var_signal_addr; struct queue_ *pkt = NULL; int sum = 0; int nbytes = 0; double f = 0; unsigned char *ptr_buf_packet = buf_packet + sizeof(header); //Это код подготовки значения модельного времени прибора //для вывода его на схеме в графической оболочке в режиме отладки /*Шаг интегрирования - в секундах !!!*/ header.fStep = ptr_header->takt*0.001; //Это собственно время, выводимое в оболочке header.time_connect = ptr_header->takt_counter*header.fStep; . . . . . . . . . . . . . .