Обсуждаем контроллеры компании 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) произвести вызов.
По-русски хоть написал? ))
Вт май 30, 2017 20:42:41
ну а проблема-то в чем?
Вт май 30, 2017 20:46:20
А вот не работает ) В генах, походу )) слабенький я еще в Си
Вт май 30, 2017 20:49:52
что не работает-то? вы своего Гену там приструните, пусть толком говорит
Вт май 30, 2017 20:51:25
Когда "не работает", самое эффективное - подключать инструменты отладки. Только Вы, как автор кода, сможете найти проблему в нём.
Вт май 30, 2017 20:55:39
Для начала я не могу передать в функцию указатель на массив констант неопределенной длины.
Где-то косяк. Или несколько.
Когда в последней строке
return ((char(*)(void)) ...что-то тут... (knAddr[DeviceID].PSRtable)[_kp_position]();
формируется адрес вызываемой функции, там всегда бред в итоге. Бросок в гущу кода.
Добавлено after 58 seconds:Когда "не работает", самое эффективное - подключать инструменты отладки. Только Вы, как автор кода, сможете найти проблему в нём.
так-то оно так. только знаний пока маловато. и опыта. а спросить не у кого
Вт май 30, 2017 21:01:56
рекомендую избавиться от явного приведения типов указателей - сразу делайте указатели нужного типа, иначе можно напортачить.
массивы "неопределенной длины" - это очень хороший способ выстрелить себе в ногу... источник всех проблем в ОС, напиманных на Си - зачем это вам?
и, если честно, я не очень понял, что вы затеяли... я подорбную систему "модулей" делал так:
1. определил структуру, описывающую интерфейс модуля
2. в каждом модуле структура эта помещена во flash и заполнена адресами соответствующих функций. если функция модулем не поддерживается, там пишу NULL
3. при "регистрации" модуля адрес этой структуры передаю "менеджеру" модулей, а он заносит этот адрес в массив.
4. когда надо обратиться к модулю, то по массиву беру нужную структуру, а из нее - адрес функции...
вот и все. у вас так или не так?
Вт май 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: Си. Передача массива констант в функцию, хранение и вызовы
Можете дать пример кода, где описывается ваша структура во флэш?
Вт май 30, 2017 21:33:10
Код для AVR-GCC не хуже версии 4
Это от незавершенного проекта "цифровой цветомузыки"
- Вложения
-
- main_effect.h
- Здесь определены все необходимые для работы с модулем структуры и т.п.
- (3.73 KiB) Скачиваний: 305
-
- template_effect.c
- Это "шаблон" модуля - все функции в виде пустышек.
- (2.1 KiB) Скачиваний: 609
Вт май 30, 2017 21:41:24
спасибо! завтра поковыряюсь
Вт май 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
};
Ср май 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
};
т.е. там где идет присвоение массиву - не хочет компилировать
Ср май 31, 2017 13:11:11
А почему у вас тип указателя на функцию без круглых скобок?
кроме того, обращаю ваше внимание, что приведенная мною форма инициализации поддерживается AVR-GCC c включенной поддержкой C99 и расширений GNU, другие компиляторы могу так сразу не прожевать...
Чт июн 01, 2017 09:19:47
вот этот и не жует. я в AtmelStudio7 пишу. проект под C++. Облом, значиццо. Буду думать
Чт июн 01, 2017 09:53:25
Должен жевать, добавьте опцию -std=gnu99
И всё-таки, почему указатель на функцию у вас без круглых скобок? вместо typedef int (*interface_func); должно быть typedef int (*interface_func)(void); или с нужными типами параметров...
Чт июн 01, 2017 12:46:11
А. этот недочет я исправил сразу. спасибо.
а параметр -std=gnu99 не хочет спасать ситуацию
Добавлено after 2 hours 16 minutes 37 seconds:
Re: Си. Передача массива констант в функцию, хранение и вызовы
Перенес процесс присвоения адресов в отдельную функцию и все заработало!
Спасибо за помощь!
Чт июн 01, 2017 12:50:27
RealHann писал(а):Перенес процесс присвоения адресов в отдельную функцию и все заработало!
это как?
Чт июн 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)();
}
Чт июн 01, 2017 18:35:17
меня интересовало, как у вас структура объявлена и как вы под нее память выделяете, не зная количества функций в массиве...
Чт июн 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: Си. Передача массива констант в функцию, хранение и вызовыВаши комментарии так и пойдут в мир )
Powered by phpBB © phpBB Group.
phpBB Mobile / SEO by Artodia.