Цитата(Make_Pic @ Sep 25 2015, 10:14)

А можно пример вашей машины с применением callback функций?
Да там собственно и показывать нечего.
Предположим у нас есть грубо говоря - драйвер, он чего-то делает по SPI, но это "что-то" состоит из команды, статуса и блока данных
У нас есть одна и та же функция, protothread - like для того, чтобы:
1. Выбрать CS ведомого, пнуть spi, послав команду - выполняется из основного потока
2. Забрать статус - выполняется уже из прерывания. Тут же настраивается DMA на блок данных
3. Коллбэк из прерывания TCIF DMA - вызывает абсолютно ту же функцию, которая выставляет флаги готовности и выключает CS ведомого.
Но если нужно - он может вызвать того, кто обработает результат. Это тоже несложно, если позаботиться о механизмах остановки и возобновления задач. То бишь активные задачи у нас в списке карусели, а неактивные - могут вызываться откуда угодно - либо на один шаг либо с восстановлением в списке активных.
В итоге получается, что текст пестрит "командами" типа yield, sleep, wake - но читается как линейный код.
CODE
void *thread(void *pc)
{
if(pc != NULL) goto *pc;
if(pending == NULL) return NULL;
// transaction start
slave_CS(0);
// put the 1 st byte (command)
slave_put(pending->command);
if(!pending->block)
{//non-blocking mode
spi_enable_rx_buffer_not_empty_interrupt(spi.port);
if(pending->size)
{//setup dma for data block
provide_dma();
return &&Get_Status;
}
else
{// transaction end
return &&Zero_Data;
}
}
else
{// blocking
my_wait(SPI_SR_RXNE);
}
Get_Status:
pending->status = slave_get();
if(pending->block)
{// block mode
char *ptr = pending->data;
while(pending->size)
{
pending->size -= 1;
slave_put(pending->read? 0xFF: *ptr++);
my_wait(SPI_SR_RXNE);
if(pending->read)
{
*ptr++ = slave_get();
}
}
goto Trans_END;
}
/*state mashine for non-block*/
spi_disable_rx_buffer_not_empty_interrupt(spi.port);
/*enable dma*/
if(pending->read) spi_enable_rx_dma(spi.port);
spi_enable_tx_dma(spi.port);
return &&Trans_END_Irq;
Trans_END_Irq:
if(pending->read) spi_disable_rx_dma(spi.port);
spi_disable_tx_dma(spi.port);
Trans_END:
slave_CS(1);//close
if(pending->chain_CB != NULL) pending->chain_CB();
pending = NULL; // trans. end
status_unread=1; // got status
return NULL;
Zero_Data:
pending->status = slave_get();
spi_disable_rx_buffer_not_empty_interrupt(spi.port);
goto Trans_END;
}
вот. а вызовы - разбросаны по всему тексту.
кроме того, там же есть и неблокирующий вариант - в зависимости от выставленного флага pending->block
единственно, усложнение - тогда, когда в жесткую стейт-машину возможны вклинивания "сторонних сил"

там нужно предусмотреть чтобы вызов шел с конкретным указателем.