Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Переинициализация в Protothreads по TimeOut.  (Прочитано 15008 раз)
0 Пользователей и 1 Гость смотрят эту тему.
pokk
Помогающий

ru
Offline Offline

« : 11-12-2015 10:04 » 

Добрый день недавно начал осваивать Protothreads от Adam Dunkels. Решил добавить переинициализацию потока при зависании опроса флага, но нечего путнего не нашёл как написать свой велосипед, в котором как всегда чего -то не хватает.

В общем задача следующая. По запросу  HTTP  надо выдать картинку которая находится в ПЗУ. И в момент считывания из ПЗУ (загрузочный сектор или данные картинки) происходит обрыв интерфейса ПЗУ. С дальнейшими действиями программы я ещё не могу определится но пока остановился на том что если обрыв произошёл до отдачи данных, То можно выдать что картинка не найдена, если же часть картинки была отправлена, то просто сбрасываю все соединения делаю переинициализацию интерфейса ПЗУ и запускаю поток с начала.

Так вот пока мне не понятно как узнать как завершился поток.
Т.е в функции A25L080_ReadData_thread  я могу засечь время опроса флага
Код:
while (!(SPI2->SR & SPI_I2S_FLAG_TXE)){PT_YIELD(pt);} 
И если превышен таймаут установить флаг, но как его передать в функцию Http  не понятно. 
Передавать через глобальные переменные пугает то что, это будет не достоверно что он пришел  из функции A25L080_ReadData_thread запущенной из потока Http,а не из левого потока работы с ПЗУ(хотя такое теоретически не может возникнуть).   
А через Return выдавать не получается из за конструкции макросов PT_THREAD.
Ещё думал как сделать выдачу через PtOpen(pt ), но хорошего варианта не придумал.
 
Код:

void Http(){

//Http Запрос
............
PT_WAIT_THREAD(OpenFile_thread(&PtOpen,&FileSystem,uri_name,id));
//Вот тут как-то надо определить как завершился поток OpenFile
..........

}

PT_THREAD(OpenFile_thread(struct pt *pt,MY_NTFS *fs,const char *name,unsigned char id)){
//----------------------------------------
PT_BEGIN(pt);
PT_INIT(&Point_Read_MFT_Thread);
while(1){
        PT_WAIT_THREAD(pt,Read_MFT_thread(&Point_Read_MFT_Thread,id));
//----------------------------------------
search_file(&fs,name);
//----------------------------------------
PT_END_YIELD(pt);
}
PT_END(pt);
}

//==============================================================================
/*
  * @Описание:    Считывает загрузочный сектор.
*/
PT_THREAD(Read_MFT_thread(struct pt *pt,unsigned char id)){
    unsigned char i=0;
PT_BEGIN(pt);
PT_INIT(&A25L080_ReadData);
while(1){
//-------------------------------------------------------------------------
PT_WAIT_THREAD(pt,A25L080_ReadData_thread(&A25L080_ReadData,Addr_MFT,(unsigned char*)MasterFileTable,list_len,id));
//-------------------------------------------------------------------------
MasterFileTable[0].FileStartAddr=SECTOR_1;
//--------Создаем имя для пустых файлов------------------------------------
for (i=0;i<END_LIST;i++){
MasterFileTable[i].FileName[19]=0;
}
//-------------------------------------------------------------------------
PT_END_YIELD(pt);
}
PT_END(pt);
}

PT_THREAD(A25L080_ReadData_thread(struct pt *pt,unsigned int addr,unsigned char *data,unsigned int len,unsigned char id)){
static unsigned int i=0;
static struct pt PointReadData;
static unsigned char StatusReadData;
PT_BEGIN(pt);
Init_Port_eeprom_A25L080_thread();
PT_INIT(&PointReadData);
while(1){

StatusReadData=WIP;
//-----ожидание завершения записи-------------
while(StatusReadData==WIP){
PT_WAIT_THREAD(pt,A25L080_ReadStatusReg_thread(&PointReadData,&StatusReadData,id));
StatusReadData=StatusReadData&WIP;
}
//while(flash_read_status_reg()&WIP==WIP);
//--------------------------------------------
FLASH_CS_LOW
//-----------command(Read Data Bytes)---------
while (!(SPI2->SR & SPI_I2S_FLAG_TXE)){PT_YIELD(pt);}
SPI2->DR = 0x03;
while (!(SPI2->SR & SPI_I2S_FLAG_RXNE)){PT_YIELD(pt);}
//------------------------addres--------------
while (!(SPI2->SR & SPI_I2S_FLAG_TXE)){PT_YIELD(pt);}
SPI2->DR = ((addr & 0x00FF0000) >> 16);
while (!(SPI2->SR & SPI_I2S_FLAG_RXNE)){PT_YIELD(pt);}

while (!(SPI2->SR & SPI_I2S_FLAG_TXE)){PT_YIELD(pt);}
SPI2->DR = ((addr & 0x0000FF00) >>  8);
while (!(SPI2->SR & SPI_I2S_FLAG_RXNE)){PT_YIELD(pt);}

while (!(SPI2->SR & SPI_I2S_FLAG_TXE)){PT_YIELD(pt);}
SPI2->DR = ((addr & 0x000000FF) >>  0);
while (!(SPI2->SR & SPI_I2S_FLAG_RXNE)){PT_YIELD(pt);}
while (!(SPI2->SR & SPI_I2S_FLAG_TXE)){PT_YIELD(pt);}
SPI2->DR;
//--------------data--------------------------
for(i=0;i<=len;i++){   //это типо  256
while (!(SPI2->SR & SPI_I2S_FLAG_TXE)){PT_YIELD(pt);}
SPI2->DR = 0x0FF;
while (!(SPI2->SR & SPI_I2S_FLAG_RXNE)){PT_YIELD(pt);}
data[i]=SPI2->DR;
}
//-------------------------------------------
FLASH_CS_HIGH
//-----ожидание завершения записи-------------
do{
PT_WAIT_THREAD(pt,A25L080_ReadStatusReg_thread(&PointReadData,&StatusReadData,id));
StatusReadData=StatusReadData&WIP;
}while(StatusReadData==WIP);
//------------------------------------------
PT_END_YIELD(pt);
//------------------------------------------
}
PT_END(pt);
}

Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 11-12-2015 12:13 » 

Флаг таймаута можно реализовать в модуле, который отвечает за работу с ПЗУ. Включить его в интерфейс модуля, и тогда в любой момент функция Http может получить его значение.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #2 : 11-12-2015 19:41 » 

Что-то нечего не понял.  "Включить его в интерфейс модуля"  это что ?
Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 11-12-2015 20:09 » 

Если у Вас есть модуль, в котором собраны все функции для работы с ПЗУ, то у него должен быть и файл интерфейса, где перечислены все сигнатуры этих функций (например, пусть это будет rom.h). Добавляем в этот интерфейс еще одно объявление:

Код: (C)
_Bool Rom_get_timeout_flag(void);

Соответственно в самом модуле обеспечиваем реализацию данной функции. Теперь любой клиент может узнать о том, что операция с ПЗУ вызвала таймаут, и в то же время никаких нежелательных глобальных переменных.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #4 : 12-12-2015 07:36 » 

В принципе я сделал что-то похожее(при наступления таймаута некоторая функция вызывается автоматически), только как дальше это использовать не понял.
" Теперь любой клиент может узнать о том, что операция с ПЗУ вызвала таймаут"  так это получается что  бы он узнал, то его каждый раз надо опрашивать? И так после каждого потока ?
Код:
void Http(){
//Http Запрос
............
PT_WAIT_THREAD(OpenFile_thread(&PtOpen,&FileSystem,uri_name,id));
if(Rom_get_timeout_flag()==FLAG_TIMEOUT){
//Переинициализация процесса.
}
..........
}

Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 12-12-2015 10:47 » 

Если работаете с событиями синхронно - опрос флага. Если асинхронно - например, используйте паттерн Observer.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #6 : 14-12-2015 03:51 » 

Походу с опросом флага. Можно ли в этом случае сделать более универсальный подход. Т.е если я сейчас после каждого потока в каждом модуле наставлю опрос флага Таймаута, а после решу модифицировать работу таймаута, типа при первом срабатывании только сбросить состояние при повторном зависании сделать Выкл/Вкл периферией, то мне придется во всех модулях где ставил флаг править его, хотя логика работы для всех модулей одинакова. Можно ли это вынести в отдельный модуль?   
Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 14-12-2015 06:05 » 

А кто вправе запретить вынос повторяющегося кода в отдельный модуль?

Самое подходящее место для такого флага - драйвер ПЗУ.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #8 : 14-12-2015 06:33 » 

"А кто вправе запретить вынос повторяющегося кода в отдельный модуль?"
Каша в голове не даёт=))

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

ru
Offline Offline

« Ответ #9 : 17-12-2015 01:48 » 

С передачей флага более менее разобрался.
Теперь как можно по феншую сделать таймаут на поллинг флага ?
Код:
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){PT_YIELD(pt);};
Тут я сделал так:
Код:
StartTimeOut(error,id); //
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){
   MainTimeOut(id); //В случае истечения таймаута вызывает обработчик по id.
   PT_YIELD(pt);
};
И завернул всё в макрос
Код:
#define WHILE_TIMEOUT(content,error,id) StartTimeOut(error,id); \
while (content){ MainTimeOut(id);PT_YIELD(pt);}
Получилось
Код:
WHILE_TIMEOUT((SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET),SPI,id);
Честно говоря идея завернуть всё в макрос мне не очень нравится, но другого варианта не нашёл =(.
Думал этим макросом обойдусь, но оказалось что нет. Есть ещё такой вариант. Тут кроме как по всему коду наставить StartTimeOut и MainTimeOut выхода не вижу.
Код:
               StartTimeOut(error,id);
do{
PT_WAIT_THREAD(pt,A25L080_ReadStatusReg_thread(&A25L080_ReadStatusReg,&StatusReg,id));
                        StatusReg=StatusReg&0x01;
if(MainTimeOut(id)==TIMEOUT){return PT_ERROR;};
}while(StatusReg!=0x00);

Есть какие либо другие варианты решения моей задачи? В идеале хотелось бы вообще не трогать код всякими StartTimeOut и MainTimeOut, а просто в отдельном модуле задать время TimeOut для каждой периферии.
 


Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 17-12-2015 06:34 » 

Теперь как можно по феншую сделать таймаут на поллинг флага ?

Сделать условие выхода из цикла ожидания составным:

Код: (C)
while (Флаг_не_установлен() && Таймаут_не_истек())
{
  Ждать();
}

if (Флаг_установлен())
  ...;  // событие, которого ждали, таки произошло
else
  ...;  // истек таймаут

Есть какие либо другие варианты решения моей задачи?

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

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #11 : 17-12-2015 07:00 » 

Код:
while (Флаг_не_установлен() && Таймаут_не_истек())
{
  Ждать();
}

А как тут определяется что  Таймаут_не_истек() именно для этого цикла ?

Т.е как быть в таком случае когда много циклов следует друг за другом.

Код:
SPI_I2S_SendData (SPI2,((AddrSel & 0x00FF0000) >> 16));
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){PT_YIELD(pt);};

temp[0]=SPI_I2S_ReceiveData(SPI2);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){PT_YIELD(pt);};
SPI_I2S_SendData (SPI2,((AddrSel & 0x0000FF00) >>  8));
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){PT_YIELD(pt);};
temp[1]=SPI_I2S_ReceiveData(SPI2);

while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){PT_YIELD(pt);};
SPI_I2S_SendData (SPI2,((AddrSel & 0x000000FF) >>  0));
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){PT_YIELD(pt);};
temp[2]=SPI_I2S_ReceiveData(SPI2);
//---------------read----------------------------------------------------
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){PT_YIELD(pt);};
SPI_I2S_SendData (SPI2,0xFF);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){PT_YIELD(pt);};
temp[3]=SPI_I2S_ReceiveData(SPI2);

 
Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 17-12-2015 07:08 » new

А как тут определяется что  Таймаут_не_истек() именно для этого цикла ?

Каждая операция ввода/вывода перезапускает таймер. Таймаут замеряется для текущей операции.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines