Цитата(rezident @ Nov 8 2009, 04:32)

Но в общем случае формирование и разбор пакетов не связаны напрямую с их приемом/отправкой и тем более с отслеживанием пауз. Прием/отправка чаще всего привязаны к прерываниям UART. Но в прерывании UART не желательно еще и паузы отслеживать (в крайнем случае можно лишь каждый байт сопровождать меткой времени, интерлив этих меток анализировать не его задача) и за сетевыми адресами следить и CRC считать.
Насчет приемной части пожалуй позволю себе с Вами не согласиться. При использовании последовательных интерфейсов, определением границ пакета удобнее всего заниматься там, где идет посимвольный поток. А где такой поток идет нативно? - Как раз в RX прерывании UARTa. Смену протокола, не меняя (не нарушая) структуру драйвера UART'a тоже элементарно сделать - предусмотрев подмену потоковой функции-обработчика. Крайне желательно чтобы эта функция-обработчик занималась определением сетевого адреса, отбрасывая мусор нам непредназначенный, тем самым экономя и время, и память.
Пусть есть сл. обработчик прерывания (упрощенно):
Код
__interrupt void uart_RxExtHandler(void)
{
U8 status = UART_STATUS_REG;
U8 ch = UART_DATA_REG;
if (status != OK )
{
DoHandleError();
return;
}
if (rx_cb) // Есть спец-функция обработки потока?
rx_cb( ch ); // пользуем ее
else // нет, тогда...
{
... положить в generic uart буфер или сделать что-то еще
}
}
Смена протокола сведется к смене обработчика потока:
rx_cb = MEK_RxCharHandler;
rx_cb = Modbus_RxCharHandler;
rx_cb = hc_RxCharHandler;
rx_cb = ppp_RxCharHandler;
rx_cb = slip_RxCharHandler;
...
и т.д. и т.п.
Пример возможного обработчика потока:
Код
/*****************************************
* ppp_RxCharHandler() *
* Attached when lower layer is UP *
* using byte staffing (flag sequence) *
* to extract packets *
* ---> val - current char from the link *
* <--- returns nothing *
*****************************************/
static void ppp_RxCharHandler(U8 val)
{
PPACKET_BUF pInPkt = linkContext.pInPkt;
#if (AUTO_ESCAPE)
static U8 prevch = 0;
U8 esc_val = (prevch == PPP_ESCAPE) ? val ^ 0x20 : val;
#else
#define esc_val val
#endif
if (!pInPkt) // return if no storage
return;
linkContext.pppRxOctetCnt += 1;
linkContext.pppRxTimeSinceLastOctet = 0;
if (val == PPP_FLAG) // new packet / end of packet
{
ppp_NewPacket( pInPkt );
}
else
{ // receiving packet
#if (AUTO_ESCAPE)
if (!ppp_IsEscaped( linkContext.inACCM, val))
{
pInPkt->payload[ pInPkt->Length++ ] = esc_val;
pInPkt->fcs = ppp_fcs16( pInPkt->fcs, &esc_val, 1);
if (pInPkt->fcs == PPPGOODFCS16)
ppp_NewPacket( pInPkt );
}
#else
pInPkt->payload[ pInPkt->Length++ ] = esc_val;
#endif
if (pInPkt->Length >= MAX_LINK_PACKET_SIZE)
{ // break receving (exceed max len)
linkContext.pppRxDiscardMaxLen += 1;
pInPkt->Length = 0;
}
}
#if (AUTO_ESCAPE)
prevch = val;
#endif
}
То что в этом обработчике делается весьма просто и без лишних затрат памяти - escaped characters, нативное определение границ пакета, - делать в аппликейшине накладнее. Кроме того например Microsoft не утруждает себя посылкой закрывающего флага 0x7E в конце пакета, MS считает что достаточно одного 0x7E флага в начале пакета. Поэтому, чтобы не терять время в ожидании таймаута <хрен знает какой длины> или следующего пакета с разделительным флагом - FCS (CRC) текущего пакета считается на лету, при совпадении пакет сразу же отцепляется.
Цитата
На приеме: если что-то пришло, без ошибок, фиксируемых аппаратурой UART, и есть место в буфере приема, то принимаем. Только такая организация физического уровня позволяет его использовать вне зависимости от вышестоящего протокола.
Ну мы говорим не про физ уровень, а про канальный уровень.
Приведенная выше организация решает обратную задачу, - как сделать протокол пригодным к использованию с любым каналом и экономить память занимаемую канальным уровнем.
Байт-обработчики можно использовать и для пакетных интерфесов, т.к. никто не мешает вызвать их n раз для n байт принятого пакета. Она не противоречит и Вашей организации. Можно из буфера приема (если есть память под этот отдельный буфер приема) читать символы побайтово, и скармливать байт-обработчику, только это будет двойная работа, и нет ясности как быть с таймаутами (не думаю что Вы всерьез предложили наградить каждый принятый байт довеском их одно-, двух-, трех-, четырех- байтой метки времени).