Main Page | Data Structures | File List | Data Fields | Globals | Related Pages

link.c

Go to the documentation of this file.
00001 /***
00002  * This file is part of OpenHome, an open source home automation system.
00003  * Copyright (C) 2003 Jan Klötzke
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00059 #include <avr/io.h>
00060 #include <avr/signal.h>
00061 #include <avr/interrupt.h>
00062 #include <avr/pgmspace.h>
00063 #include <inttypes.h>
00064 #include <stdlib.h>
00065 #include <string.h>
00066 #include "net/link.h"
00067 #include "net/buffers.h"
00068 #include "net.h"
00069 
00070 // external interrupt functions
00071 #ifdef EIMSK
00072 #       define ext_init()       sbi(EICR, LNK_EXT_ISCx1)
00073 #       define ext_enable()     {EIFR = _BV(LNK_EXT_INT); sbi(EIMSK, LNK_EXT_INT);}
00074 #       define ext_disable()    cbi(EIMSK, LNK_EXT_INT)
00075 #else
00076 #       define ext_init()       sbi(MCUCR, LNK_EXT_ISCx1)
00077 #       define ext_enable()     {GIFR = _BV(LNK_EXT_INT); sbi(GIMSK, LNK_EXT_INT);}
00078 #       define ext_disable()    cbi(GIMSK, LNK_EXT_INT)
00079 #endif
00080 
00081 // solve uart register and interrupt naming problems
00082 #ifndef UDR
00083 #       define UDR      UDR0
00084 #       define USR      UCSR0A
00085 #       define UCR      UCSR0B
00086 #       define UBRR     UBRR0
00087 #       define RENAME_ISR
00088 #endif
00089 
00091 enum recv_stat_e {
00092         RECV_STAT_FREE,         
00093         RECV_STAT_RECEIVING,    
00094         RECV_STAT_EXAMINE       
00095 };
00096 
00098 enum send_stat_e {
00099         SEND_STAT_IDLE,         
00100         SEND_STAT_WAIT,         
00101         SEND_STAT_SEND_DATA,    
00102         SEND_STAT_INFORM        
00103 };
00104 
00106 struct receive_info_t {
00107         enum recv_stat_e status;        
00108         uint16_t slots;                 
00109         uint16_t crc16;                 
00110         uint8_t pos;                    
00111         uint8_t buf[LNK_BUFFER_SIZE];   
00112 };
00113 
00115 struct send_info_t {
00116         enum send_stat_e status;
00117         uint16_t slot;          
00118         uint8_t backlog;        
00119         uint8_t backlog_add;    
00120         net_buf_t data;         
00121 };
00122 
00123 // global vars
00124 static struct send_info_t send;         //< transmit variables
00125 static struct receive_info_t receive;   //< receive variables
00126 static struct lnk_err_t err;            //< error statistics
00127 
00129 #define POLY_CRC16      0x1021
00130 
00137 #ifdef RENAME_ISR
00138 SIGNAL(SIG_UART0_RECV)
00139 #else
00140 SIGNAL(SIG_UART_RECV)
00141 #endif
00142 {
00143         uint8_t i, value;
00144         
00145         // handle bus timing, (re)start counting slots
00146         TCNT0 = LNK_ALPHA_TIME;
00147         receive.slots = 0;
00148         
00149         // get byte
00150         if ((USR & _BV(FE)) != 0) err.rx_fe++;
00151         value = UDR;
00152         if ((USR & _BV(DOR)) != 0) err.rx_ovr++;
00153                 
00154         // expecting to receive sth? if not, simply ignore byte
00155         // This could happen if we could not process a packet fast enough so
00156         // the next has already started. This leads to missing bytes in the
00157         // buffer but should be handled by crc and length comparison. Beta2
00158         // should be increased to prevent this.
00159         if (receive.status > RECV_STAT_RECEIVING) {
00160                 err.rx_ovr++;
00161                 return;
00162         }
00163         receive.status = RECV_STAT_RECEIVING;
00164         
00165         // critical section handled
00166         sei();
00167         
00168         
00169         // store in buffer
00170         if (receive.pos < LNK_BUFFER_SIZE) receive.buf[receive.pos++] = value;
00171         
00172         // calculate checksum (add only header+data, not checksum itself)
00173         if ((uint8_t)(receive.buf[0]+2) >= receive.pos) {
00174                 receive.crc16 ^= ((uint16_t)value << 8);
00175                 for (i=0; i<8; i++) {
00176                         if (receive.crc16 & 0x8000)
00177                                 receive.crc16 = (receive.crc16 << 1) ^ POLY_CRC16;
00178                         else
00179                                 receive.crc16 <<= 1;
00180                 }
00181         }
00182 }
00183 
00190 SIGNAL(SIG_OVERFLOW0)
00191 {
00192         TCNT0 += LNK_ALPHA_TIME;
00193         receive.slots++;
00194         
00195         // receive: detect end of packet and switch to examine mode
00196         // this will also be executed if we sent a packet!
00197         if (receive.slots == LNK_BETA_1) {
00198                 if (receive.status == RECV_STAT_RECEIVING) {
00199                         receive.status = RECV_STAT_EXAMINE;     // signal that data arrived
00200                         ext_enable();                           // start detection of new data
00201                 }
00202         }
00203         
00204         // send: start sending if right slot reached
00205         if (receive.slots >= send.slot) {
00206                 cbi(TIMSK, TOIE0);                      // disable slot timer
00207                 ext_disable();                          // disable detection of new data
00208                 cbi(UCR, RXEN);                         // disable receiver
00209                 sbi(UCR, TXEN);                         // enable transmitter
00210                 cbi(LNK_SEND_PORT, LNK_SEND_PIN);       // enable driver
00211                 
00212                 UDR = *send.data.data++;                // send first byte
00213                 send.data.len--;
00214                 send.status = SEND_STAT_SEND_DATA;
00215                 send.slot = 0xffff;
00216                 sbi(UCR, UDRIE);                        // enable UDRIE
00217         }
00218 }
00219 
00226 SIGNAL(LNK_EXT_SIG)
00227 {
00228         ext_disable();          // disable detection
00229         TCNT0 = LNK_ALPHA_TIME; // restart...
00230         receive.slots = 0;      // ...slot counting
00231         send.slot = 0xffff;     // under no circumstances can we send data
00232 }
00233 
00241 #ifdef RENAME_ISR
00242 SIGNAL(SIG_UART0_DATA)
00243 #else
00244 SIGNA(SIG_UART_DATA)
00245 #endif
00246 {
00247         if (send.data.len > 0) {
00248                 UDR = *send.data.data++;
00249                 send.data.len--;
00250         } else {
00251                 cbi(UCR, UDRIE);
00252         }
00253 }
00254 
00261 #ifdef RENAME_ISR
00262 SIGNAL(SIG_UART0_TRANS)
00263 #else
00264 SIGNAL(SIG_UART_TRANS)
00265 #endif
00266 {
00267         sbi(LNK_SEND_PORT, LNK_SEND_PIN);       // disable driver
00268         cbi(UCR, TXEN);                         // disable transmitter
00269         sbi(UCR, RXEN);                         // enable receiver
00270         TCNT0 = LNK_ALPHA_TIME;                 // setup...
00271         receive.slots = 0;                      // clear...
00272         sbi(TIMSK, TOIE0);                      // and enable slot timer
00273         ext_enable();                           // start detection of new data
00274         send.status = SEND_STAT_INFORM;         // done
00275 }
00276 
00277 /********************************************************************************
00278  * Public functions
00279  */
00280 
00281 extern uint8_t lnk_ind(uint8_t *buf, uint8_t len);
00282 extern void lnk_con(void);
00283 
00289 void lnk_init(void)
00290 {
00291         UBRR = LNK_F_CLK/(LNK_BAUD_RATE*16l) - 1;               // set baud rate
00292         sbi(LNK_SEND_PORT, LNK_SEND_PIN);                       // configure send pin
00293         sbi(LNK_SEND_DDR, LNK_SEND_PIN);
00294         UCR = _BV(RXCIE)|_BV(TXCIE)|_BV(RXEN);                  // enable receiver+interrupts
00295         
00296         send.slot = 0xffff;             // don't want to send
00297         receive.crc16 = 0;
00298         
00299         receive.slots = 0x8000;         // set up slot timer
00300         TCCR0 = LNK_ALPHA_PRESC;
00301         sbi(TIMSK, TOIE0);
00302         
00303         ext_init();
00304         ext_enable();                   // start detection of new data
00305 }
00306 
00317 void lnk_process(void)
00318 {
00319         // be sure that slot timer doesn't wrap
00320         cli();
00321         if (receive.slots > 0xa000) receive.slots = 0x3000;
00322         sei();
00323 
00324         // assign slot number if data is waiting
00325         cli();
00326         if ((send.status == SEND_STAT_WAIT) && (send.slot == 0xffff)) {
00327                 // range: LNK_BETA_2+[0..16*(send.backlog+1)-1]
00328                 send.slot = LNK_BETA_2 + ((uint16_t)random() % (16*((uint16_t)send.backlog+1)));
00329         }
00330         sei();
00331         
00332         // call lnk_con if transmitted all data
00333         if (send.status == SEND_STAT_INFORM) {
00334                 // add backlog
00335                 if (send.backlog >= (uint8_t)(0xff-send.backlog_add))
00336                         send.backlog = 0xff;
00337                 else
00338                         send.backlog += send.backlog_add;
00339                 // call network layer
00340                 lnk_con();
00341                 send.status = SEND_STAT_IDLE;
00342         }
00343         
00344         // any received packet ready for processing?
00345         if (receive.status == RECV_STAT_EXAMINE) {
00346                 if (send.backlog > 0) send.backlog--;
00347                 // call network layer only if valid packet (length && crc right)
00348                 if ((receive.pos == receive.buf[0]+4) &&
00349                     (receive.crc16 == *((uint16_t*)(receive.buf+receive.pos-2)))) {
00350                         // add backlog delta
00351                         if (send.backlog >= (uint8_t)(0xff-receive.buf[1]))
00352                                 send.backlog = 0xff;
00353                         else
00354                                 send.backlog += receive.buf[1];
00355                         // call network layer
00356                         lnk_ind(receive.buf+2, receive.buf[0]);
00357                 } else {
00358                         if (receive.pos != receive.buf[0]+4)
00359                                 err.rx_len++;
00360                         else
00361                                 err.rx_crc++;
00362                 }
00363                 // return to normal operation
00364                 receive.pos = 0;
00365                 receive.crc16 = 0;
00366                 receive.status = RECV_STAT_FREE;
00367         }
00368 }
00369 
00383 int8_t lnk_requ(net_buf_t *buf, uint8_t backlog)
00384 {
00385         uint8_t len, *data, i;
00386         uint16_t crc;
00387         
00388         // already sending?
00389         if (send.status != SEND_STAT_IDLE) return 0;
00390         
00391         // prepend link layer header
00392         len = buf_len(buf);
00393         buf_prep_char(buf, backlog);
00394         buf_prep_char(buf, len);
00395         
00396         // calculate and append checksum
00397         len += 2;
00398         data = buf->data;
00399         crc = 0;
00400         while (len > 0) {
00401                 len--;
00402                 crc ^= ((uint16_t)(*data++) << 8);
00403                 for (i=0; i<8; i++) {
00404                         if (crc & 0x8000)
00405                                 crc = (crc << 1) ^ POLY_CRC16;
00406                         else
00407                                 crc <<= 1;
00408                 }               
00409         }
00410         buf_app_int(buf, crc);
00411         
00412         // prepare for sending
00413         send.data = *buf;
00414         send.backlog_add = backlog;
00415         send.slot = 0xffff;
00416         send.status = SEND_STAT_WAIT;
00417         return 1;
00418 }
00419 
00426 uint8_t lnk_clear_to_send(void)
00427 {
00428         return send.status == SEND_STAT_IDLE;
00429 }
00430 
00436 void lnk_get_error_stats(struct lnk_err_t *buf)
00437 {
00438         memcpy(buf, &err, sizeof(err));
00439 }

Generated on Fri Oct 17 16:45:54 2003 for OpenHome by doxygen 1.3.3