Обсуждаем контроллеры компании Atmel.
Ответить

Си. Передача массива констант в функцию, хранение и вызовы

Вт май 30, 2017 20:37:15

Всем доброго вечера!
Запнулся на проблеме. Нид хэлп, как говорится )
Задача.
Есть ядро программы в виде отдельного модуля. Назвал его Kernel
К проекту подключаются другие сишные модули. Они автоматически регистрируются в ядре.
У каждого модуля есть такая запись:
Код:
#define  _NoPSR  0

static const uint16_t* PSR_Addresses[]
{
   //InitPSR
   _NoPSR,
   //TurnOnPSR
   _NoPSR,
   //TurnOffPSR
   _NoPSR,
   //ReportPRS
   (uint16_t*) &ExceptionsReport,
   //ProcessPRS
   (uint16_t*) &Exceptions,
   
   //Input 1 - Очистка таблицы исключений
   (uint16_t*) &RemoveExceptions
};

Вначале идут стандартные функции, потом неопределенное количество Input'ов, которые зависят от конкретного модуля. Если функция не описана - там стоит _NoPSR, т.е. 0. Обработчик в ядре вызов не выполнит.

Далее, при инициализации каждого модуля, последний заносит в общую таблицу ядра некую информацию о себе, в том числе он должен передать указатель на эту таблицу. Вроде такого:
Код:
#define Sub (uint16_t*) &

void Exceptions_KernelInit(void)
{
   Kernel_RegisterProcess(Sub InsExceptions, PSR_Addresses, _DT_Exception);
}

В ядре эта информация сохраняется в структуре:
Код:
struct
{
   enum _dtList EDType;
   uint16_t (*pFunc);
   uint16_t PSRtable;   //тут пока глюки
} knAddr[ProcessesCount];

void Kernel_RegisterProcess(uint16_t (*ProcessVector), const uint16_t *PSRtable, enum _dtList EDType)
{
   knAddr[++knProperties.CurrentID].EDType = EDType;
   knAddr[knProperties.CurrentID].pFunc = &(*ProcessVector);
   knAddr[knProperties.CurrentID].PSRtable = (uint16_t) &(*PSRtable);  //глюки-глюки. сюда пока особо не смотреть. игрался, ничего не выходит пока
}

//И дальше должен идти сам вызов удаленной функции:
char Kernel_CallPSR(char DeviceID, char _kp_position)
{
   if ((uint16_t) knAddr[DeviceID].PSRtable[_kp_position] == _NoPSR)
      return 0;
   else
      return ((char(*)(void))  ...что-то тут... (knAddr[DeviceID].PSRtable)[_kp_position]();
}

Т.е. механизм такой. Ядро знает где у какого модуля искать таблицу PSR_Addresses[], в которой лежат адреса ее функций. И по номеру нужной функции (_kp_position) произвести вызов.
По-русски хоть написал? ))

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 20:42:41

ну а проблема-то в чем?

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 20:46:20

А вот не работает ) В генах, походу )) слабенький я еще в Си

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 20:49:52

что не работает-то? вы своего Гену там приструните, пусть толком говорит

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 20:51:25

Когда "не работает", самое эффективное - подключать инструменты отладки. Только Вы, как автор кода, сможете найти проблему в нём.

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 20:55:39

Для начала я не могу передать в функцию указатель на массив констант неопределенной длины.
Где-то косяк. Или несколько.
Когда в последней строке
return ((char(*)(void)) ...что-то тут... (knAddr[DeviceID].PSRtable)[_kp_position]();
формируется адрес вызываемой функции, там всегда бред в итоге. Бросок в гущу кода.

Добавлено after 58 seconds:
Когда "не работает", самое эффективное - подключать инструменты отладки. Только Вы, как автор кода, сможете найти проблему в нём.


так-то оно так. только знаний пока маловато. и опыта. а спросить не у кого

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 21:01:56

рекомендую избавиться от явного приведения типов указателей - сразу делайте указатели нужного типа, иначе можно напортачить.
массивы "неопределенной длины" - это очень хороший способ выстрелить себе в ногу... источник всех проблем в ОС, напиманных на Си - зачем это вам?

и, если честно, я не очень понял, что вы затеяли... я подорбную систему "модулей" делал так:
1. определил структуру, описывающую интерфейс модуля
2. в каждом модуле структура эта помещена во flash и заполнена адресами соответствующих функций. если функция модулем не поддерживается, там пишу NULL
3. при "регистрации" модуля адрес этой структуры передаю "менеджеру" модулей, а он заносит этот адрес в массив.
4. когда надо обратиться к модулю, то по массиву беру нужную структуру, а из нее - адрес функции...
вот и все. у вас так или не так?

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 21:27:37

Так, только не определено количество этих функций. У каждого подключаемого модуля оно может быть разным. Ваша реализация это может поддержать?
Глобально идея выглядит так. Попробую вкратце.
Берется новая плата. На ней, к примеру, есть пять светодиодов, три кнопки и какой-то интерфейс связи (пусть будет уарт).
Текст программы main выглядит:
void main(void)
{
Kernel_AddDevice(_DT_Led);
Kernel_AddDevice(_DT_Led);
Kernel_AddDevice(_DT_Led);
Kernel_AddDevice(_DT_Led);
Kernel_AddDevice(_DT_Led);
Kernel_AddDevice(_DT_Button);
Kernel_AddDevice(_DT_Button);
Kernel_AddDevice(_DT_Button);
Kernel_AddDevice(_DT_UART);

while(1) Kernel;
}
Все само дальше крутится и отвечает на запросы по UART.
Когда приходит пакет по UART, модуль UART передает его ядру, которое ищет у себя нужный адресат и по коду команды вызывает нужную функцию у нужного модуля. Передавая остаток данных пакета тому самому обработчику.
Соответственно, у кнопок и светодиода разные задачи и разное количество команд управления (Input'ов у меня). В массив я не могу это засунуть, потому что структура неизвестна. Или я просто не знаю как это организовать правильно?

Добавлено after 12 minutes 35 seconds:
Re: Си. Передача массива констант в функцию, хранение и вызовы
Можете дать пример кода, где описывается ваша структура во флэш?

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 21:33:10

Код для AVR-GCC не хуже версии 4

Это от незавершенного проекта "цифровой цветомузыки" :)
Вложения
main_effect.h
Здесь определены все необходимые для работы с модулем структуры и т.п.
(3.73 KiB) Скачиваний: 305
template_effect.c
Это "шаблон" модуля - все функции в виде пустышек.
(2.1 KiB) Скачиваний: 609

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 21:41:24

спасибо! завтра поковыряюсь

Re: Си. Передача массива констант в функцию, хранение и вызо

Вт май 30, 2017 21:50:23

Что касается неизвестного количества функций у модуля, то могу предложить такой вариант
Код:
typedef int (*interface_func)(char *ptr); // определили тип для интерфейсной функции

// определяем тип для описания интерфейса модуля
typedef struct{
   uint8_t func_cnt; // количество функций в интерфейсе
   interface_func interface[]; // массив неопределенной длины
} module_interface_t;

// в менеджере модулей определяем массив, хранящий все модули
module_interface_t modules[MAX_MODULE_CNT];

// когда надо обратиться к конкретному модулю, надо делать так:
int run_module_func(uint8_t id, uint8_t func_id, char *data){
   if(id >= MAX_MODULE_CNT) return -1; // ошибка - модулей меньше, чем указано
   if(modules[id] == NULL) return -2; // ошибка - модуль с таким номером не зарегистрирован
   if(func_id >= modules[id].func_cnt) return -3; // ошибка - такая функция не может быть!
   if(modules[id].interface[func_id] == NULL) return -4; // ошибка - функция не реализована
   return modules[id].interface[func_id](data); // вызываем функцию и возвращаем ее результат работы
}


Добавлено after 6 minutes 57 seconds:
Re: Си. Передача массива констант в функцию, хранение и вызовы
да, чуть не забыл: инициализировать структуру интерфейса модуля можно так:
Код:
static module_interface_t module = {
   .func_cnt = 3,
   .interface[0] = func1,
   .interface[1] = func2,
   .interface[2] = func3
};

Re: Си. Передача массива констант в функцию, хранение и вызо

Ср май 31, 2017 11:43:49

День добрый!
Получается так.
Код:
typedef int (*interface_func);   //(char *ptr); // определили тип для интерфейсной функции

// определяем тип для описания интерфейса модуля
typedef struct{
   uint8_t func_cnt; // количество функций в интерфейсе
   interface_func tfunc;
   interface_func interface[]; // массив неопределенной длины
} module_interface_t;


в модуле
Код:
static module_interface_t Addresses = {
   .func_cnt = 3,
   .interface[0] = ExceptionsReport,     //<< Error: expected primary-expression before '.' token
        .interface[1] = Exceptions,     //<< Error: expected primary-expression before '.' token
   .interface[2] = RemoveExceptions,     //<< Error: expected primary-expression before '.' token
   .tfunc = RemoveExceptions
};


т.е. там где идет присвоение массиву - не хочет компилировать

Re: Си. Передача массива констант в функцию, хранение и вызо

Ср май 31, 2017 13:11:11

А почему у вас тип указателя на функцию без круглых скобок?

кроме того, обращаю ваше внимание, что приведенная мною форма инициализации поддерживается AVR-GCC c включенной поддержкой C99 и расширений GNU, другие компиляторы могу так сразу не прожевать...

Re: Си. Передача массива констант в функцию, хранение и вызо

Чт июн 01, 2017 09:19:47

вот этот и не жует. я в AtmelStudio7 пишу. проект под C++. Облом, значиццо. Буду думать

Re: Си. Передача массива констант в функцию, хранение и вызо

Чт июн 01, 2017 09:53:25

Должен жевать, добавьте опцию -std=gnu99

И всё-таки, почему указатель на функцию у вас без круглых скобок? вместо typedef int (*interface_func); должно быть typedef int (*interface_func)(void); или с нужными типами параметров...

Re: Си. Передача массива констант в функцию, хранение и вызо

Чт июн 01, 2017 12:46:11

А. этот недочет я исправил сразу. спасибо.
а параметр -std=gnu99 не хочет спасать ситуацию

Добавлено after 2 hours 16 minutes 37 seconds:
Re: Си. Передача массива констант в функцию, хранение и вызовы
Перенес процесс присвоения адресов в отдельную функцию и все заработало!
Спасибо за помощь!

Re: Си. Передача массива констант в функцию, хранение и вызо

Чт июн 01, 2017 12:50:27

RealHann писал(а):Перенес процесс присвоения адресов в отдельную функцию и все заработало!
это как?

Re: Си. Передача массива констант в функцию, хранение и вызо

Чт июн 01, 2017 18:16:43

Код:
#define Sub (uint16_t*) &

static module_interface_t DeviceInfo;

void Exceptions_KernelInit(void)
{
   DeviceInfo.interface[_kp_ProcessPSR] = Sub Exceptions;
   DeviceInfo.interface[_kp_ReportPSR] = Sub ExceptionsReport;
   DeviceInfo.interface[_kp_InputPSR + 0] = Sub RemoveExceptions;

   Kernel_RegisterProcess(Sub InsExceptions, &DeviceInfo, _DT_Exceptions);
}

ну, и сам вызов потом:
Код:
char Kernel_CallPSR(char DeviceID, char _kp_position)
{
   module_interface_t *DevInfo = knAddr[DeviceID].DeviceInfo;
   uint16_t* funcAddr = (uint16_t*) DevInfo->interface[_kp_position];

   if ((uint16_t) funcAddr == _NoPSR)
      return 0;
   else
      return ((char(*)(void)) funcAddr)();
}

Re: Си. Передача массива констант в функцию, хранение и вызо

Чт июн 01, 2017 18:35:17

меня интересовало, как у вас структура объявлена и как вы под нее память выделяете, не зная количества функций в массиве...

Re: Си. Передача массива констант в функцию, хранение и вызо

Чт июн 01, 2017 18:49:22

в .hpp
Код:
typedef uint16_t (*interface_func);   // определили тип для интерфейсной функции

// определяем тип для описания интерфейса модуля
struct module_interface_t
{
   char func_cnt; // количество функций в интерфейсе
   interface_func interface[]; // массив неопределенной длины
};


Добавлено after 1 minute 13 seconds:
Re: Си. Передача массива констант в функцию, хранение и вызовы
Ваши комментарии так и пойдут в мир )
Ответить