Привет, я работаю над встроенной системой, которая управляет лифтом через последовательную шину.
Каждый раз, когда я отправляю сообщение (пакет содержит адрес, длину данных, данные, crc), мне нужно ждать ответа лифта, который представлен пакетом подтверждения.
ACK устанавливается каждый раз, когда я получаю пакет от лифта.
Получение сообщений осуществляется через прерывание.
Пакет ACK выглядит так:
0xA0,0x00,0x00,0x00,0x00
и когда он приходит, я устанавливаю ACK true
Вот моя функция отправки:
bool TransferService::send(char recAddr,char dataLength, char *data){
pc.putc(startByte);
pc.putc(recAddr);
pc.putc(controllerAddress);
pc.putc(dataLength);
for (int i = 0; i < dataLength; i++) {
pc.putc(data[i]);
}
pc.putc(getCrc(recAddr,controllerAddress,data, dataLength));
_messageReceived = false;
timer.reset();
timer.start();
ACK = false;
do {
if (ACK) {
break;
}
} while(timer.read_ms()<=15);
timer.stop();
if (!ACK) {
send(recAddr,dataLength,data);
}
}
Это только попытка, это не работа.
bool TransferService::send(char recAddr,char dataLength, char *data){
PT_BEGIN();
timer.reset();
timer.start();
do {
pc.putc(startByte);
pc.putc(recAddr);
pc.putc(controllerAddress);
pc.putc(dataLength);
for (int i = 0; i < dataLength; i++) {
pc.putc(data[i]);
}
pc.putc(getCrc(recAddr,controllerAddress,data, dataLength));
_messageReceived = false;
PT_WAIT_UNTIL(!timer.read_ms() <=10 || ACK);
} while(timer.read_ms() <=10);
PT_END();
}
Мой вопрос заключается в том, как сделать так, чтобы первая функция работала корректно, используя protothreads.
Структура функции потока в Реализация Адама Данкела Прототипов вполне ясно, и ваша функция явно не следует за ним.
Функция потока Protothread должна возвращать int
а также обычно имеет подпись:
int threadfunction( struct pt* pt ) ;
и должен быть определен с использованием PT_THREAD
макрос таким образом:
PT_THREAD( threadfunction( struct pt* pt ) )
{
PT_BEGIN(pt) ;
// thread body here
PT_END(pt) ;
}
От Protothread документация…
Функция protothread всегда должна возвращать целое число, но никогда не должна
явный возврат — возврат выполняется внутри протопотока
заявления.
Глядя на определение PT_THREAD
Я не вижу ничего, что могло бы помешать его использованию с функцией-членом C ++ или использованием дополнительных аргументов, кроме pt
, в этом случае следующее ближе к правильному:
PT_THREAD( TransferService::send( struct pt* pt, char recAddr, char dataLength, char *data )
{
PT_BEGIN( pt );
timer.reset();
timer.start();
pc.putc( startByte );
pc.putc( recAddr );
pc.putc( controllerAddress );
pc.putc( dataLength );
for( int i = 0; i < dataLength; i++ )
{
pc.putc( data[i] );
}
pc.putc( getCrc( recAddr, controllerAddress, data, dataLength ) );
_messageReceived = false;
PT_WAIT_UNTIL( pt, timer.read_ms() > 10 || ACK );
PT_END();
}
В вашей попытке у вас был и цикл do-while, и PT_WAIT_UNTIL
, но ПОДОЖДИТЕ делает цикл ненужным. На самом деле нет необходимости передавать pt
аргумент, необходимый struct pt
может быть членом класса или даже глобальным (хотя это было бы опрометчиво).
Обратите внимание, что вышеизложенное следует шаблону, очевидному в вопросе, но это будет необычный шаблон дизайна; чаще всего поток выполняется бесконечно, а не для одной транзакции. Не зная всего вашего приложения, я бы предположил, что нить должен работать на более высоком уровне, чем единичная транзакцияsend()
функция, такая, что у вас есть поток «отправителя», который может многократно выполнять операции отправки, не выходя, как показано ниже контур (т.е. не полный или «реальный» код и с большим количеством предположений):
// Constructor...
TransferService::TransferService()
{
PT_INIT( &m_pt ) ; // Where thread state m_pt
// is a member variable of
// type struct pt (or just pt
// since this is C++)
...
}
// Thread function
PT_THREAD(TransferService::senderThread() )
{
PT_BEGIN(&m_pt);
for(;;)
{
PT_WAIT_UNTIL( &m_pt, ready_to_send ) ;
timer.reset();
timer.start();
send( recAddr, dataLength, data ) ;
PT_WAIT_UNTIL( &m_pt, timer.read_ms() > 10 || ACK );
}
PT_END(pt);
}
// Single send transaction function
bool TransferService::send( char recAddr, char dataLength, char *data )
{
pc.putc( startByte );
pc.putc( recAddr );
pc.putc( controllerAddress );
pc.putc( dataLength );
for( int i = 0; i < dataLength; i++ )
{
pc.putc( data[i] );
}
pc.putc( getCrc( recAddr, controllerAddress, data, dataLength ) );
_messageReceived = false;
}
Обратите внимание, что из-за способа, которым PT_...
API работает, PT_WAIT_UNTIL
должен быть в той же функции, что и PT_BEGIN
а также PT_END
, следовательно, перемещение таймера ожидания в коде выше.
Других решений пока нет …