Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вложенное определение типов
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
zheka
Точнее говоря, рекурсивно. Возможно ли такое? Дело в том что мне нужно создать некую структур для меню.

Вот код, из которого думаю будет ясна идея:

Код
typedef struct {
             char *title;
             int  type;
             TMenuItem submenu;
             } TMenuItem;

TMenuItem MainMenu[]=
             {
               {"Поиск",1, Search},
               {"Каналы",1, Channels},
               {"Настройки",1, Options},
               {"Выход",1, Exit}
                                            
             };


TMenuItem Channels[]=
             {
               {"Канал 0",1, xx},
               {"Канал 1",1, xx},
               {"Канал 2",1, xx},
               {"Канал 3",1, xx}
                                            
             };


TMenuItem Options[]=
             {
               {"Option 1",1, xx},
               {"Option 2",1, xx},
               {"Option 3",1, xx},
               {"Option 4",1, xx}
                                            
             };


Тип TMenuItem содержит в себе название пункта меню, далее зарезервированный параметр, далее подменю, вызываемое при выборе этого пункта. ОДнако такая фишка не работает.

Возможно ли вложение и если нет, то как лучше организовать меню?
beer_warrior
Все правильно, только нужен маленький финт:
typedef struct _TMenuItem{
char *title;
int type;
_TMenuItem *submenu;
} TMenuItem;
zheka
Хм... пока вы писали я сделал свой вариант (кстати, ваш не работает - declaration syntax error на строках _TMenuItem *submenu; и } TMenuItem; )

Мой же вариант таков:
struct TMenuItem{
char *title;
int type;
struct TMenuItem *submenu;
} ;

Компилятор не ругается.


Но при создании

TMenuItem MainMenu[]=
{
{"Поиск",1, Search},
{"Каналы",1, Channels},
{"Настройки",1, Options},
{"Выход",1, Exit}

} ;


Ругается на первую же строку: missing"("
beer_warrior
Да конечно, упустил struct.
char *title сделать как char title[16].
Указатель не несет в себе каких-то данных, если написано char * это просто забивка места под 1 адрес,
если нужен текст делаеться массив, чье имя и равно указателю, но указатель не равен массиву.
Займись серьезно указателями.
zheka
Насчет трех или 4 элементов - я знаю. Но ошибка то в другом месте генерировалась...
Или я не понял, что ты подразумевашеь под 4мя элементами:
Channels, Exit,Options и Search?

Или title,type,submenu - так их три...
beer_warrior
Звыняюсь недосмотрел.Одним глазом смотрю, другим в свой код smile.gif
zheka
Так... все получилось. Теперь я вылез за пределы памяти.
Global variable out of SRAM - совсем в другом месте программы..
Может стоит записать эти пункты во flash? Все- таки неизменяемые величины.
beer_warrior
В принципе все меню надо держать во флэше.
zheka
Записал во флеш - все работает.
Еще ламерский вопросик - как определить количество элементов в TMenuItem? count кажется в С++ был - не работает...
beer_warrior
sizeof(MainMenu[])/sizeof(TMenuItem)
zheka
sizeof (MainMenu)выдает число 80
sizeof (MainMenu[]) - invalid expression

Может я библиотеку какую не подключил?
#include "macros.h"
#include "mega8.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "NokiaLCD.h"


Цитата
Одним глазом смотрю, другим в свой код


Если не секрет, что конструируем?
defunct
Цитата(zheka @ Mar 18 2006, 19:55) *
Записал во флеш - все работает.
Еще ламерский вопросик - как определить количество элементов в TMenuItem? count кажется в С++ был - не работает...

Это вы точно подметили.
Как int или как unsigned char... или рекурсивно в программе, пока submenu != NULL

struct TMenuItem{
char *title;
int type;
int count;
struct TMenuItem *submenu;
} ;

Цитата
sizeof (MainMenu[]) - invalid expression

понятно что invalid, какой же размер может быть у безразмерного массива?
sizeof(TMenuItem) - размер элемента в вашем случае.
WHALE
Странно,что у тебя компилятор не ругается,насколько я помню,структура не может содержать экземпля-
ры самой себя.И возможно,тебя ожидают еще одни грабли-ты определил структуру во флэш,и все эле-
менты структуры будут во флэши,т.е константными и переменные к структуре ты прикрутить не сможешь(правда,может оно тебе и не надо).Если не секрет,чем ты память забил,что в килобайт не влазишь.
defunct
Цитата(WHALE @ Mar 18 2006, 21:03) *
Странно,что у тебя компилятор не ругается,насколько я помню,структура не может содержать экземпля-
ры самой себя.И возможно,тебя ожидают еще одни грабли-ты определил структуру во флэш,и все эле-
менты структуры будут во флэши,т.е константными и переменные к структуре ты прикрутить не сможешь(правда,может оно тебе и не надо).Если не секрет,чем ты память забил,что в килобайт не влазишь.

У него структура не содержит саму себя, а сожержит только указатель фиксированного размера, который может быть "на что угодно". С технической стороны все Ок.
zheka
Цитата
struct TMenuItem{
char *title;
int type;
int count;
struct TMenuItem *submenu;
} ;


Я не вытерпел, так и сделал.


Цитата
Если не секрет,чем ты память забил,что в килобайт не влазишь.


Был бы секрет, не стал бы я эдак с неделю назад выкладывать полный код. FontLookup - шрифт. Не, можно и его конечно во флеш, но писал библиотеку не я.

Цитата
константными и переменные к структуре ты прикрутить не сможешь

Да это уже не грабли, натыкался ранее. А что касается данной структуры - я уверен - прикручивать ничего не надо будет.

А вообще все получилось. Уже лазию по менюшке, как в сотовом телефоне. ПРоблема пока только одна - как лезть по дереву обратно, т.е. как определять родителя. Можно конечно решить как и в случае с количеством элементов в массиве - вручную прописывать.


Цитата
У него структура не содержит саму себя, а сожержит только указатель фиксированного размера, который может быть "на что угодно".


Слышу иронию... Есть более рациональное решение?
defunct
Цитата(zheka @ Mar 18 2006, 21:49) *
А вообще все получилось. Уже лазию по менюшке, как в сотовом телефоне. ПРоблема пока только одна - как лезть по дереву обратно, т.е. как определять родителя. Можно конечно решить как и в случае с количеством элементов в массиве - вручную прописывать.

Сделать список двухсвязным. Т.е. чтобы submenu хранил также указатель на родиетеля(владельца).
struct TMenuItem{
char *title;
int type;
int count;
struct TMenuItem *submenu;
struct TMenuItem *parent;
} ;



Цитата
Слышу иронию... Есть более рациональное решение?

Когда кажется - креститься надо...
zheka
Код
typedef __flash struct _TMenuItem
    {
        char title[16];
        int type;                
        __flash struct _TMenuItem *parent;
        __flash struct _TMenuItem *submenu;
    } TMenuItem;


TMenuItem __flash Options[2]=
             {
               {"Option 1", 1, MainMenu , NULL},
               {"Option 2", 1, MainMenu , NULL}              
             };
          
TMenuItem __flash Channels[2]=
             {
               {"Channel 1", 1, MainMenu , NULL},
               {"Channel 2", 1, MainMenu , NULL}              
             };
            



TMenuItem __flash MainMenu[2]=
             {
               {"Options", 1, NULL , Options},
               {"Channels", 1, NULL ,Channels}              
             };



Бред получается. Как ни располагаю менюшки - всегда будет ошибка undefined symbol. Понятно что при указании идентификатора, он уже должен быть описан ранее.

Да и потом - по несколько раз повторять "MainMenu" как указатель на родителя внутри самого родителя - избыточно и нерационально. Но это не в упрек и не в качестве вопроса - я знаю как переделать структуру. ОДнако и в моем решении я также столкнулся с вышеописанной проблемой - undefined symbol.

Цитата
Когда кажется - креститься надо...


Я атеист, мне это не поможет :D
zheka
Что-то уже целый час тему просматривают и все молчат )))
beer_warrior
Делаешь вот так:
TMenuItem __flash Channels[2]=
{
{"Channel 1", 1, NULL, &MainMenu[1] },
{"Channel 2", 1, &MainMenu[0], NULL}
};
это позволяет крутиться по итемам одного уровня
далее делаешь массив указателей на менюитем, с размером на глубинe вложенности меню.
делаешь индекс для этого массива.
при активации пункта меню сохраняешь указатель в массиве и сдвигаешь индекс вперед, при возврате сдвигаешь индекс назад или сразу обнуляешь для возврата в главное меню.
Для отображения пользуешься ессно указателем лежащим по текущему индексу.
zheka
Господи, аж неудобно... заставил людей отвелчься от работы и писать программу.

Но и я тоже не сидел сложа руки. Пока я буду вникать в ваш код, выложу свой. Мне интересна ваша критика.

Код
typedef __flash struct _TMenuItem
    {
        char title[16];
        int type;                
        __flash struct _TMenuItem *parent;
        __flash struct _TMenuItem *submenu;
    } TMenuItem;

extern TMenuItem __flash MainMenu[];
extern TMenuItem __flash Search[];
extern TMenuItem __flash Options[];
extern TMenuItem __flash Channels[];

TMenuItem __flash Search[]=
             {
               {"Íà÷àòü",  1, MainMenu, NULL},
               {"Êîí÷èòü", 1, MainMenu, NULL},
               {"Âûéòè",   1, MainMenu, NULL}
             };

TMenuItem __flash Sub1[]=
             {
               {"Sub1 A", 1, Options, NULL},
               {"Sub1 B", 1, Options, NULL},
               {"Sub1 C", 1, Options, NULL}
             };

TMenuItem __flash Sub2[]=
             {
               {"Sub2 A", 1, Options, NULL},
               {"Sub2 B", 1, Options, NULL},
               {"Sub2 C", 1, Options, NULL}
             };

TMenuItem __flash Sub3[]=
             {
               {"Sub3 A", 1, Options, NULL},
               {"Sub3 B", 1, Options, NULL},
               {"Sub3 C", 1, Options, NULL}
             };

  
TMenuItem __flash Options[]=
             {
               {"Option 1", 1, MainMenu, Sub1},
               {"Option 2", 1, MainMenu, Sub2},
               {"Option 3", 1, MainMenu, Sub3}
             };

TMenuItem __flash Channels[]=
             {
               {"Channel 1", 1, MainMenu, NULL},
               {"Channel 2", 1, MainMenu, NULL},
               {"Channel 3", 1, MainMenu, NULL}
             };

            

TMenuItem __flash MainMenu[]=
             {
               {"Ïîèñê", 1,  NULL , Search},
               {"Êàíàëû", 1, NULL , Channels},
               {"Íàñòðîéêè", 1, NULL , Options}
             };

////////////////////////////////////////


void EnterMenuItem(TMenuItem __flash *point_to_menu)
{
int i;
char *s=r;
LcdClear();  
         for (i=0;i<3;i++)
          {
            LcdGotoXY(2,i+1);
            sprintf(s,"%p", point_to_menu[i].title);
            LcdStr(FONT_1X, s, NORMAL);  
           }
   LcdUpdate();
}



void main ()
{
int i,j, selection_pos, submenu_n;
char *s=r;
TMenuItem __flash *current_point;
DDRD=0x00;
PORTD=0xFF;
LcdInit();
Delay();  

current_point=MainMenu;
EnterMenuItem(current_point);
selection_pos=0;
LcdSelect(selection_pos);
LcdUpdate();    

for(;;)
{

   if (!PIND.0)  
     {
      LcdSelect(selection_pos);
      selection_pos++;        
      LcdSelect(selection_pos);      
     }
  
   if (!PIND.1)  
     {
      LcdSelect(selection_pos);
      selection_pos--;        
      LcdSelect(selection_pos);      
    }

   if (!PIND.2)  
     {
        if (current_point[selection_pos].submenu==NULL) continue;
           current_point=current_point[selection_pos].submenu;
           EnterMenuItem(current_point);
           selection_pos=0;      
           LcdSelect(selection_pos);        

    }

   if (!PIND.3)  
     {
        if (current_point[selection_pos].parent==NULL) continue;
          current_point=current_point[selection_pos].parent;
          EnterMenuItem(current_point);
          selection_pos=0;      
          LcdSelect(selection_pos);        
    }

   LcdUpdate();

}


Цитата
при активации пункта меню сохраняешь указатель в массиве и сдвигаешь индекс вперед, при возврате сдвигаешь индекс назад или сразу обнуляешь для возврата в главное меню.



Нравится твоя идея, но! Вспомним windows-проводник. В нем есть две кнопки - "Вверх" и "Назад". Так вот твой вариант это как раз кнопка "Назад". Вариант "Вверх" логичней и в принципе, то что я сделал, работает.

Ладно, пойду искать следующие грабли.
defunct
ЗЫ, я свой выложу чуть позже еще раз после того как проверю полностью. Пока что удалил.

Вот обещанный пример (проверенный):

Код
#define uchar unsigned char
#define schar signed char

typedef __flash struct
{
   char title[16];
   schar Layer;
} TListItem;

TListItem __flash BunchOfStrings[]=
{
  {"Options", 0},
  {"Option 1",1},
  {"SubOption1 1", 2},
  {"Option 2", 1},
  {"SubOption2 1", 2},
  {"SubOption2 2", 2},
  {"SubOption2 3", 2},
  {"Channels", 0},
  {"Channel 1", 1},
  {"Channel 2", 1}
//  ,{"", -1} // Dummy item для отладки.
};
#define MAX_LAYER 3  // Последний уровень субменю

#define mdMoveUp -1    // Движение по меню "вверх"
#define mdMoveDown 1   // Движение по меню "вниз"
#define mdMoveLeft -2 // Движение по меню в рамках одного слоя влево (пред. пункт)
#define mdMoveRight 2 // Движение по меню в рамках одного слоя вправо (следующий пункт)
#define ItemCount sizeof(BunchOfStrings)/sizeof(TListItem)

TListItem __flash *GetNextMenuItem(schar MoveDirection)
{
  static uchar CurrentPos = 0;   // Текущая позиция в слое
  schar CurrentLayer;         // Текущий слой
  uchar TempPos;

  uchar searchleft(uchar pos, schar layer);
  uchar searchright(uchar pos, schar layer);

  CurrentLayer = BunchOfStrings[CurrentPos].Layer;
  switch (MoveDirection)
  {
    case mdMoveUp:
    {
         if ((CurrentLayer > 0)&&(CurrentPos > 0)) {
           CurrentLayer--;
           while (!CurrentPos--){
             if (BunchOfStrings[CurrentPos].Layer == CurrentLayer)
               break;
           }
         }
         else{
            CurrentPos = 0;
         }
       break;
    };
    case mdMoveDown:
    {
       if ((CurrentLayer < MAX_LAYER)&&(CurrentPos < ItemCount-1)){
         if (BunchOfStrings[CurrentPos +1].Layer > CurrentLayer)
          {
            CurrentLayer++;
            CurrentPos++;
          }
       }
       break;
    };
    case mdMoveLeft:
    {
       TempPos = searchright(CurrentPos, CurrentLayer);
       if (BunchOfStrings[TempPos].Layer != CurrentLayer)
         TempPos = searchleft(CurrentPos, CurrentLayer);
       if (BunchOfStrings[TempPos].Layer == CurrentLayer)
         CurrentPos = TempPos;
       break;
    }
    case mdMoveRight:
    {
       TempPos = searchleft(CurrentPos, CurrentLayer);
       if (BunchOfStrings[TempPos].Layer != CurrentLayer)
         TempPos = searchright(CurrentPos, CurrentLayer);
       if (BunchOfStrings[TempPos].Layer == CurrentLayer)
         CurrentPos = TempPos;
       break;
    }
    default: CurrentPos = 0;
  }
  return &BunchOfStrings[CurrentPos];

}

uchar searchleft(uchar pos, schar layer)
{
    uchar i;
    i = ++pos;
    while ((i > 0) && (BunchOfStrings[i].Layer > layer)) i++;
    return i;
}

uchar searchright(uchar pos, schar layer)
{
    uchar i;
    i = --pos;
    while ((i < ItemCount) && (BunchOfStrings[i].Layer > layer)) i--;
    return i;
}



Пример применения:

Код
int main( void )
{
  char __flash *c;
  TListItem __flash *ListItem;
// Изначально находимся в меню Options..
  ListItem = GetNextMenuItem( mdMoveDown );  // Здесь навелись на Option 1
  ListItem = GetNextMenuItem( mdMoveRight ); // Здесь навелись на Option 2
  ListItem = GetNextMenuItem( mdMoveDown );  // Здесь навелись на SubOption2_1
  ListItem = GetNextMenuItem( mdMoveRight ); // Здесь навелись на SubOption2_2
  ListItem = GetNextMenuItem( mdMoveRight ); // Здесь навелись на SubOption2_3
  ListItem = GetNextMenuItem( mdMoveRight ); // Здесь навелись на SubOption2_1

  ListItem = GetNextMenuItem( mdMoveUp );
  ListItem = GetNextMenuItem( mdMoveUp );
  ListItem = GetNextMenuItem( mdMoveUp );

  ListItem = GetNextMenuItem( mdMoveRight );
  ListItem = GetNextMenuItem( mdMoveDown );
  ListItem = GetNextMenuItem( mdMoveLeft );
  c = ListItem -> title; // Здесь в "c" находится "Channel 2"
....
zheka
Да, кстати - по поводу предыдущей проблемы - с sizeof - ну задал я размерность массива - и толку :

sprintf(s,"%d", sizeof(MainMenu));
LcdStr(FONT_1X, s, NORMAL);

- показывает большие числа - 22 в частности при размере 3,


sprintf(s,"%d", sizeof(MainMenu[])) - компилятор обзывает инвалидом детства...
zheka
Господа!
Еще вам загадка:

Вот из Codevision Example по EEPROM:

Код
// EEPROM access example

// CodeVisionAVR C Compiler
// (C) 2000-2002 HP InfoTech S.R.L.
// www.hpinfotech.ro

// Chip: AT90S2313
// Memory Model: TINY
// Data Stack Size: 64 bytes

flash char f[]="This is a test";
#pragma warn-
eeprom char e[16];
#pragma warn+
char r[16];

void main (void)
{
char flash *ptr_to_flash;
char eeprom *ptr_to_eeprom;
char *ptr_to_ram;

// copy the string f from FLASH to
// the string e in EEPROM
ptr_to_flash=f;
ptr_to_eeprom=e;
while (*ptr_to_flash)
      *ptr_to_eeprom++=*ptr_to_flash++;

// copy the string e from EEPROM to
// the string r in RAM
ptr_to_eeprom=e;
ptr_to_ram=r;
while (*ptr_to_eeprom)
      *ptr_to_ram++=*ptr_to_eeprom++;

// stop here
while (1);
}



В общем не выводит ничего... В моей программе часть кода
Код
while (*ptr_to_flash)
      *ptr_to_eeprom++=*ptr_to_flash++;


была заменена на

Код
i=0;
while (*ptr_to_flash)
{
      *ptr_to_eeprom++=*ptr_to_flash++;
      LcdLine(0,i*5,80,i*5);
      i++;
      
}


Ну и чтение из EEPROM соответственно модифицировано. Линии там - типа таблицы, оказались очень полезны для отладки. При записи в EEPROM их было столько, сколько символов в записываемой строке.

При чтении - рисование таблицы длилось долго-долго, после чего то ли у Меги, то ли у индикатора съезжала крыша...

Найдите ошибку... ПОчему ptrt_to_eeprom указывает на что-то очень длинное..
defunct
Цитата
Еще вам загадка:

Е-мае.. кончайте нас загадками "парить"! Загадки в отдельной ветке задавайте.. И прочитайте плз. тот документ, который я в прошлой ветке дал.. "как правильно задавать технические вопросы"..
WHALE
zheka ты продолжаешь хамить,правда уже в косвенной форме.
Человек практически написал за тебя код решения вопроса,заданного в посте.С проверкой это не 5 минут времени,а значительно больше angry.gif .Ты не словом не поблагодарив,как будто не заметив,ми-
ло разворачиваешь обсуждение на 180 градусов и задаеш вопрос совсем из другой оперы blink.gif
Ты черезмерно используешь мягкость людей,здесь собравшихся.Еще раз повторю,в большинстве других форумов ты уже или получил бы бан в лоб,или тема была бы на помойке.Которой здесь,кстати,
нет,что говорит о безумной либеральности форума к радости таких как ты.
Тут дело уже не в С-учись банальной вежливости и правилам общения интеллигентных людей
zheka
Уважаемый WHALE!!!

Цитата
Человек практически написал за тебя код решения вопроса,заданного в посте


Смотрим время редактирования этого поста. То есть время, когда код там появился.


Цитата
Ты не словом не поблагодарив,как будто не заметив,ми-
ло разворачиваешь обсуждение на 180 градусов и задаеш вопрос совсем из другой оперы


Смотрим время оставления поста №22, на который вы намекаете.

Делаем выводы, об обоснованности данной претензии.

Я безумно благодарен этим людям. К сожалению не могу отвечать спасибо на каждый пост, пока задача еще не решена.

Цитата
Тут дело уже не в С-учись банальной вежливости и правилам общения интеллигентных людей


Некоторые из которых пойманы на невнимательности, влекущей за собой необоснованные претензии в мой адрес. Нет, я не отрицаю, что я нетерпелив, иногда лень разобраться прежде чем задавать вопросы другим.

Но факты есть факты - искаженное цитирование моих сообщений, последнее ваше обвинение в хамстве.

Defunct, Whale все-таки прав, хотя бы один раз я должен Вас поблагодарить за трату Вашего времени на меня. Да и я, кажется уже восхищался этим ранее.
WHALE
zheka тьфу,начал писать,получил от тебя РМ.Ладно,я тут вообще не причем,defunct делал
за тебя работу в хорошем стиле.Во всяком случае я рад,что ты не безнадежен smile.gif Но извини,тебе несколько разных людей делали одинаковые замечания по стиою твоему общения,да и программинга
тоже.Ты поблагодарил человека?
И так не делается,в одной ветке задавать вопросы,абсолютно не связанные с темой.К тому-же извини,
твой последний вопрос уж совсем никакой cranky.gif В приведенном тобой маленьком кусочке вроде все правильно.И опять те-же вопросы:ты правильно инициировал указатели?И в который раз,насколько я
понимаю,свежеоткомпилированный код ты сразу заливаешь в камень и ждешь,сработает ли.Ответь,по-
жалуйста,ради бога,ну почему ты не пользуешься отладчиком?!
zheka
Ну... спасибо огромное, всем кто помогал, у меня наконец-то все заработало. Извините, если с кем был некорректен.
WHALE
Я лично рад a14.gif Больше выдержки и удачных новых проектов. smile.gif
IEC
попытайся в структуру включить ссылку на адрес родителя.

Пардон! Не досмотрел страницу и с ответом запаздал!
ut1wpr
Цитата(zheka @ Mar 22 2006, 18:33) *
Ну... спасибо огромное, всем кто помогал, у меня наконец-то все заработало. Извините, если с кем был некорректен.

Похожее решал, трудно сейчас тексты найти, но была еще плюс заморочка.
Одним из пунктов меню было выбор языка меню. Всего четыре набора строк.
Помню, что красиво было... smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.