FITkit
Fakulta informačních technologií

enc28j60_spi_tx.c

Zobrazit dokumentaci tohoto souboru.
00001 /*******************************************************************************
00002    enc28j60_spi_tx.c: Knihovna funkcí pro práci s odesílacím bufferem
00003    Copyright (C) 2010 Brno University of Technology,
00004                       Faculty of Information Technology
00005    Author(s): Martin Musil <xmusil34 AT fit.vutbr.cz>
00006 
00007    LICENSE TERMS
00008 
00009    Redistribution and use in source and binary forms, with or without
00010    modification, are permitted provided that the following conditions
00011    are met:
00012    1. Redistributions of source code must retain the above copyright
00013       notice, this list of conditions and the following disclaimer.
00014    2. Redistributions in binary form must reproduce the above copyright
00015       notice, this list of conditions and the following disclaimer in
00016       the documentation and/or other materials provided with the
00017       distribution.
00018    3. All advertising materials mentioning features or use of this software
00019       or firmware must display the following acknowledgement:
00020 
00021         This product includes software developed by the University of
00022         Technology, Faculty of Information Technology, Brno and its
00023         contributors.
00024 
00025    4. Neither the name of the Company nor the names of its contributors
00026       may be used to endorse or promote products derived from this
00027       software without specific prior written permission.
00028 
00029    This software or firmware is provided ``as is'', and any express or implied
00030    warranties, including, but not limited to, the implied warranties of
00031    merchantability and fitness for a particular purpose are disclaimed.
00032    In no event shall the company or contributors be liable for any
00033    direct, indirect, incidental, special, exemplary, or consequential
00034    damages (including, but not limited to, procurement of substitute
00035    goods or services; loss of use, data, or profits; or business
00036    interruption) however caused and on any theory of liability, whether
00037    in contract, strict liability, or tort (including negligence or
00038    otherwise) arising in any way out of the use of this software, even
00039    if advised of the possibility of such damage.
00040 
00041    $Id$
00042 
00043 *******************************************************************************/ 
00044 
00045 #include "enc28j60_spi_tx.h"
00046 #include "enc28j60_spi.h"
00047 #include "fspi.h"
00048 
00049 //hlavni ukazatele pro praci s buffery
00050 unsigned int tx_ptr;
00051 unsigned int tx_end_ptr;
00052 unsigned int TXST;
00053 unsigned int TXND;
00054 
00055 //promenna, znaci aktualni buffer
00056 unsigned char act_tx;
00057 
00058 //zamek bufferu
00059 #define LOCKED 1
00060 #define UNLOCKED 0
00061 char tx1_lock = UNLOCKED;
00062 char tx2_lock = UNLOCKED;
00063 char tx3_lock = UNLOCKED;
00064 
00065 //promenne pro ulozeni protokolu, ktery se pres ne odesila
00066 char tx1_protocol;
00067 char tx2_protocol;
00068 char tx3_protocol;
00069 
00070 //ukazatele pro jednotlive buffery, slouzi pro uchovavani hodnot behem prepinani
00071 unsigned int tx1_ptr;                   
00072 unsigned int tx2_ptr;
00073 unsigned int tx3_ptr;
00074 
00075 unsigned int tx1_end_ptr;
00076 unsigned int tx2_end_ptr;
00077 unsigned int tx3_end_ptr;
00078 
00079 //vnitrni pomocne funkce
00080 char tx_protocol(unsigned char protocol);
00081 
00082 
00083 //************************************************
00084 //odesilaci buffer
00085 //************************************************
00086 
00090 char tx_init(unsigned char protocol){
00091         
00092         int timer = TIMEOUT;                                    //timeout
00093                 
00094         //kontrola dokonceni odesilani predchoziho paketu
00095         while((read_reg8(ECON1,NO_DUMMY) & ECON1_TXRTS) && (timer-- > 0) );
00096                 
00097         if(timer == 0)                                          //timeout vyprsel
00098                 return -1;      
00099                         
00100         //buffer pro UDP pakety
00101         if(protocol == UDP_PROTO){
00102                 
00103                 if(tx1_lock == LOCKED){                                 //tx1 ma zamek,aby nedoslo k nahodnemu prepsani jeste
00104                         return -1;                                                      //neodeslaneho obsahu bufferu jinym. napr. pri odesilani  
00105                 }                                                                               //paketu z obsluhy preruseni    
00106 
00107                 tx1_lock = LOCKED;
00108                 tx_save(act_tx);
00109                 
00110                 TXST = TX1ST;                                                   //restart ukazatelu na zacatek a konec vyhrazene pameti
00111                 TXND = TX1ND;
00112                 act_tx = TX1;                                                   //bufferem je TX1
00113         
00114                 select_bank(0);
00115                 
00116                 write_reg16(ETXST,TXST);                                // zapsani ukazatele na zacatek bufferu do ENC28
00117                 write_reg16(ETXND,TXST);
00118                 
00119                 tx_ptr = TX1ST;                                                 //inicializace ukazatele do bufferu
00120                 tx1_ptr = TX1ST;                                                //nastaveni pomocnych ukazatelu (jsou pro 
00121                 tx1_end_ptr     = TX1ST;                                        // uchovani hodnot behem prepinani funkcemi tx_save a tx_load)
00122                 tx1_protocol = protocol;
00123                 
00124                 return tx_protocol(protocol);
00125         }
00126         
00127         //buffer pro TCP pakety
00128         else if(protocol == TCP_PROTO){
00129                 
00130                 if(tx3_lock == LOCKED){                                 //tx3 ma zamek, zde u TCP slouzi k tomu, aby nebylo mozne
00131                         return -1;                                                      //odesilat dalsi paket, dokud predchozi nebyl odeslan  
00132                 }                                                                               //   zamek odemyka stavovy automat TCP spojeni
00133                 tx3_lock = LOCKED;
00134                 
00135                 tx_save(act_tx);
00136                 
00137                 TXST = TX3ST;                                                   //restart ukazatelu na zacatek a konec vyhrazene pameti
00138                 TXND = TX3ND;
00139                 act_tx = TX3;                                                   //bufferem je TX3
00140         
00141                 select_bank(0);
00142                 
00143                 write_reg16(ETXST,TXST);                                // zapsani ukazatele na zacatek bufferu do ENC28
00144                 write_reg16(ETXND,TXST);
00145                 
00146                 tx_ptr = TX3ST;                                                 //inicializace ukazatele do bufferu
00147                 tx3_ptr = TX3ST;                                                //nastaveni pomocnych ukazatelu (jsou pro 
00148                 tx3_end_ptr     = TX3ST;                                        // uchovani hodnot behem prepinani funkcemi tx_save a tx_load)
00149                 tx3_protocol = protocol;
00150                 
00151                 return tx_protocol(protocol);
00152         }
00153                 
00154         //buffer pro automaticke odpovedi a ARP dotazy
00155         else if((protocol == ICMP_PROTO) | (protocol == TCP_PROTO_HEADER_ONLY)){
00156                 
00157                 if(tx2_lock == LOCKED){                                 //tx2 ma zamek,aby nedoslo k nahodnemu prepsani jeste
00158                         return -1;                                                      //neodeslaneho obsahu bufferu jinym. napr. pri odesilani  
00159                 }                                                                               //paketu z obsluhy preruseni    
00160 
00161                 tx2_lock = LOCKED;
00162                 tx_save(act_tx);                
00163                 
00164                 TXST = TX2ST;                                                   //restart ukazatelu na zacatek a konec vyhrazene pameti
00165                 TXND = TX2ND;
00166                 act_tx = TX2;                                                   //bufferem je TX2
00167         
00168                 select_bank(0);
00169                 
00170                 write_reg16(ETXST,TXST);                                // zapsani ukazatele na zacatek bufferu do ENC28
00171                 write_reg16(ETXND,TXST);                                // --||-- konec
00172                 
00173                 tx_ptr = TX2ST;                                                 //inicializace ukazatele do bufferu
00174                 tx2_ptr = TX2ST;                                                //nastaveni pomocnych ukazatelu (jsou pro 
00175                 tx2_end_ptr = TX2ST;                                    // uchovani hodnot behem prepinani funkcemi tx_save a tx_load)
00176                 tx2_protocol = protocol;
00177                 
00178                 return tx_protocol(protocol);
00179         }
00180         else if((protocol == ARP_PROTO)){
00181                 
00182                 tx_save(act_tx);                
00183                 
00184                 TXST = TX4ST;                                                   //restart ukazatelu na zacatek a konec vyhrazene pameti
00185                 TXND = TX4ND;
00186                 act_tx = TX4;                                                   //bufferem je TX4
00187         
00188                 select_bank(0);
00189                 
00190                 write_reg16(ETXST,TXST);                                // zapsani ukazatele na zacatek bufferu do ENC28
00191                 write_reg16(ETXND,TXST);                                // --||-- konec
00192                 
00193                 tx_ptr = TX4ST;                                                 //inicializace ukazatele do bufferu
00194                 
00195                 return tx_protocol(protocol);
00196         }
00197         
00198         
00199 return -1;
00200 }
00201 
00202 /*Fce pro preskoceni mista pro hlavicky podle pouziteho protokolu*/
00203 char tx_protocol(unsigned char protocol){
00204         
00205         switch(protocol){
00206                 case TCP_PROTO_HEADER_ONLY:
00207                 case TCP_PROTO:
00208                         tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN + TCP_HEADER_LEN;
00209                         break;  
00210                 case UDP_PROTO:
00211                         tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN;             
00212                         break;
00213                 case ICMP_PROTO:
00214                         tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN + ICMP_HEADER_LEN;            
00215                         break;          
00216                 case ARP_PROTO:
00217                         tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN;                      
00218                         break;          
00219                 default:
00220                         return -1;      
00221         }
00222         
00223         select_bank(0);
00224         write_reg16(EWRPT,tx_ptr);                                                      //posun na zacatek datove casti
00225                 
00226 return 0;
00227 }       
00228 
00233 void tx_rewind(){
00234         
00235         switch(act_tx){
00236                 case TX1:
00237                         tx_protocol(tx1_protocol);
00238                         break;
00239                 case TX2:
00240                         tx_protocol(tx2_protocol);
00241                         break;
00242                 case TX3:
00243                         tx_protocol(tx3_protocol);
00244                         break;  
00245         }
00246 }
00247 
00248 
00249 
00253 void tx_seek(unsigned char header){                     
00254         switch(header){
00255                 case CTRL:
00256                         tx_ptr = TXST;
00257                         break;
00258                 case ETH_HEADER:
00259                         tx_ptr = TXST + CTRL_LEN;
00260                         break;
00261                 case IP_HEADER:
00262                         tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN;
00263                         break;
00264                 case ICMP_HEADER:
00265                 case TCP_HEADER:
00266                 case UDP_HEADER:
00267                         tx_ptr = TXST + CTRL_LEN + ETH_HEADER_LEN + IP_HEADER_LEN;
00268                         break;
00269         }
00270         
00271         select_bank(0);
00272         write_reg16(EWRPT,tx_ptr);
00273 return;
00274 }       
00275 
00281 inline void tx_close(){ 
00282         select_bank(0);
00283         tx_end_ptr = tx_ptr;
00284         write_reg16(ETXND,tx_end_ptr-1);                //tx_end_ptr ukazatel ukazuje na misto, kde jeste neni nic zapsano, proto -1
00285 }                                                                                       //ETXND musi ukazovat na posledni bajt dat
00286 
00287 
00291 void tx_save(unsigned char buffer){
00292                 
00293                 //ulozeni stavu predchoziho bufferu
00294                 switch(buffer){
00295                         case TX1:
00296                                 tx1_ptr = tx_ptr;               //ulozeni stavu TX1
00297                                 tx1_end_ptr     = tx_end_ptr;
00298                                 break;
00299                                 
00300                         case TX2:
00301                                 tx2_ptr = tx_ptr;               //ulozeni stavu TX2
00302                                 tx2_end_ptr     = tx_end_ptr;
00303                                 break;
00304                                                                 
00305                         case TX3:
00306                                 tx3_ptr = tx_ptr;               //ulozeni stavu TX3
00307                                 tx3_end_ptr     = tx_end_ptr;
00308                                 break;
00309                 }
00310 return;
00311 }
00312 
00313 
00317 void tx_load(unsigned char buffer){
00318         
00319                 switch(buffer){
00320                         case TX1:       
00321                                 TXST = TX1ST;                   //obnoveni stavu pro TX1
00322                                 TXND = TX1ND;
00323                                 tx_ptr = tx1_ptr;
00324                                 tx_end_ptr = tx1_end_ptr;
00325                                 act_tx = TX1;
00326                                 break;
00327                         
00328                         case TX2:
00329                                 TXST = TX2ST;                   //obnoveni stavu pro TX2
00330                                 TXND = TX2ND;
00331                                 tx_ptr = tx2_ptr;
00332                                 tx_end_ptr = tx2_end_ptr;
00333                                 act_tx = TX2;
00334                                 break;
00335                                 
00336                         case TX3:
00337                                 TXST = TX3ST;                   //obnoveni stavu pro TX3
00338                                 TXND = TX3ND;
00339                                 tx_ptr = tx3_ptr;
00340                                 tx_end_ptr = tx3_end_ptr;
00341                                 act_tx = TX3;
00342                                 break;
00343                 }                       
00344         
00345         write_reg16(EWRPT,tx_ptr);              // nastaveni ukazatele pro zapis
00346         write_reg16(ETXST,TXST);                // zapsani ukazatele na zacatek bufferu do ENC28
00347         write_reg16(ETXND,tx_end_ptr-1);                //tx_end_ptr ukazatel ukazuje na misto, kde jeste neni nic zapsano, proto -1
00348                                                                                         //ETXND musi ukazovat na posledni bajt dat              
00349 
00350 return; 
00351 }
00352 
00356 unsigned char tx_act(){
00357         
00358         return act_tx;  
00359 }
00360 
00364 unsigned char tx_putc(char c){
00365         
00366         if(tx_ptr > TXND)
00367                 return 0;   
00368         else{
00369                 spi_putc(c);
00370                 tx_ptr++;
00371                 return 1;
00372         }
00373 }
00374 
00378 unsigned int tx_write(void* ptr, unsigned int length){
00379 
00380         int remaining = tx_left();
00381 
00382         if(tx_ptr > TXND)
00383                 return 0;
00384         else if(length >= remaining){
00385                 spi_write(ptr, remaining);
00386                 tx_ptr += remaining;    
00387                 return remaining;
00388         }
00389         else{
00390                 spi_write(ptr, length);
00391                 tx_ptr += length;
00392                 return length;
00393         }
00394 return 0;       
00395 }
00396 
00400 unsigned int tx_fill(unsigned char value, unsigned int length){
00401         
00402         int remaining = tx_left();
00403         
00404         if(tx_ptr > TXND)
00405                 return 0;
00406         else if(length >= remaining){
00407                 spi_fill(value, remaining);
00408                 tx_ptr += remaining;    
00409                 return remaining;
00410         }
00411         else{
00412                 spi_fill(value, length);
00413                 tx_ptr += length;
00414                 return length;
00415         }
00416 return 0;
00417 }
00418 
00423 unsigned int tx_skip(unsigned int length){
00424         
00425         int remaining = tx_left();
00426         
00427         if(tx_ptr > TXND)
00428                 return 0;
00429         else if(length >= remaining){
00430                 tx_ptr += remaining;
00431                 write_reg16(EWRPT,tx_ptr);      
00432                 return remaining;
00433         }
00434         else{
00435                 tx_ptr += length;
00436                 write_reg16(EWRPT,tx_ptr);
00437                 return length;
00438         }
00439 return 0;
00440 }
00441 
00445 char tx_send(){ 
00446 
00447         int timer = TIMEOUT;                                    //timeout
00448         
00449         while(( (read_reg8(ECON1,NO_DUMMY) & ECON1_TXRTS) > 0) & (timer-- > 0) );       //kontrola odeslani predchoziho paketu
00450 
00451         
00452         if(timer == 0){                                         //timeout vyprsel
00453                 if(act_tx == TX1){                              //odemknuti TX1 po nevydarenem odeslani
00454                         tx_unlock(TX1);
00455                 }
00456                 else if(act_tx == TX2){
00457                         tx_unlock(TX2); 
00458                 }
00459                 return -1;
00460         }
00461 
00462         // prepsani registru s nastavenim  paddingu,crc... sam od sebe se nejak "maze"
00463         //mozna hw zavada vybranyho kousku
00464         select_bank(2);
00465         write_reg8(MACON3,MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FULDPX);
00466 
00467         bf_set(ECON1,ECON1_TXRTS);                                      
00468 
00469         if(act_tx == TX1){                                      //odemknuti TX1
00470                 tx_unlock(TX1);
00471         }
00472         else if(act_tx == TX2){
00473                 tx_unlock(TX2); 
00474         }
00475 return 0;       
00476 }
00477 
00478 
00482 inline unsigned int tx_left(){
00483 
00484 return TXND - tx_ptr +1;        //kompenzace, TXND je posledni bajt zpravy, tx_ptr tam musi umoznit zapisovat
00485 }
00486 
00490 inline unsigned int tx_data_len(){
00491         
00492 return tx_end_ptr - tx_ptr; 
00493 }
00494 
00498 unsigned int tx_checksum(){
00499 
00500         //vyuziti vnitrniho DMA radice v ENC28J60 pro spocitani checksumu
00501         select_bank(0);
00502         write_reg16(EDMAST,tx_ptr);
00503         write_reg16(EDMAND,tx_end_ptr -1);
00504         bf_clear(EIR,EIR_DMAIF);
00505         
00506         bf_set(ECON1,ECON1_CSUMEN | ECON1_DMAST);
00507         
00508         while((read_reg8(EIR,NO_DUMMY) & EIR_DMAIF ) == 0);
00509                 
00510         return read_reg16(EDMACS,NO_DUMMY);
00511 
00512 }
00513 
00514 
00518 inline void tx_unlock(unsigned char buffer){
00519         
00520         if(buffer == TX1)
00521                 tx1_lock = UNLOCKED;
00522         else if(buffer == TX2)
00523                 tx2_lock = UNLOCKED;
00524         else if(buffer == TX3)
00525                 tx3_lock = UNLOCKED;
00526                 
00527 return;
00528 }