unsigned int enc28j60_receive_packet(unsigned int maxlen, unsigned char *buffer) { unsigned int rxstat; unsigned int len; //packet in buffer ? if ((enc28j60_read_address(ENC28J60_REG_EIR) & (1<<ENC28J60_BIT_PKTIF)) == 0){ //double check! //errata says that PKTIF does not work as it should //->check packetcount too: if (enc28j60_read_address(ENC28J60_REG_EPKTCNT) == 0) return 0; } //set read pointer to next packet; enc28j60_write_address(ENC28J60_REG_ERDPTL, (enc28j60_next_packet_ptr)); enc28j60_write_address(ENC28J60_REG_ERDPTH, (enc28j60_next_packet_ptr)>>8); //now read the transmit status vector //read next packet ptr enc28j60_next_packet_ptr = enc28j60_spi_read_byte(ENC28J60_OP_READ_BUF_MEM, 0); enc28j60_next_packet_ptr |= enc28j60_spi_read_byte(ENC28J60_OP_READ_BUF_MEM, 0)<<8; //read packet length len = enc28j60_spi_read_byte(ENC28J60_OP_READ_BUF_MEM, 0); len |= enc28j60_spi_read_byte(ENC28J60_OP_READ_BUF_MEM, 0)<<8; //read rx stat rxstat = enc28j60_spi_read_byte(ENC28J60_OP_READ_BUF_MEM, 0); rxstat |= enc28j60_spi_read_byte(ENC28J60_OP_READ_BUF_MEM, 0)<<8; //limit read bytecount if (len>maxlen) len = maxlen; //transfer packet from enc28j60 to our buffer enc28j60_read_buffer(buffer,len); //mark packet as processed (free mem) //ERRATA says we need to check packet pointer: if ((enc28j60_next_packet_ptr- 1 < ENC28J60_RX_BUFFER_START) || (enc28j60_next_packet_ptr- 1 > ENC28J60_RX_BUFFER_END)){ enc28j60_write_address(ENC28J60_REG_ERXRDPTL, LO8(ENC28J60_RX_BUFFER_END)); enc28j60_write_address(ENC28J60_REG_ERXRDPTH, HI8(ENC28J60_RX_BUFFER_END)); }else{ enc28j60_write_address(ENC28J60_REG_ERXRDPTL, LO8(enc28j60_next_packet_ptr- 1)); enc28j60_write_address(ENC28J60_REG_ERXRDPTH, HI8(enc28j60_next_packet_ptr- 1)); } //decrement packet counter: enc28j60_spi_write_word(ENC28J60_OP_BFS|ENC28J60_REG_ECON2, (1<<ENC28J60_BIT_PKTDEC)); return len; }
/** * Fetches a pending packet from the RAM buffer of the ENC28J60. * * The packet is written into the given buffer and the size of the packet * (ethernet header plus payload, exclusive the CRC) is returned. * * Zero is returned in the following cases: * - There is no packet pending. * - The packet is too large to completely fit into the buffer. * - Some error occured. * * \param[out] buffer The pointer to the buffer which receives the packet. * \param[in] buffer_len The length of the buffer. * \returns The packet size in bytes on success, \c 0 in the cases noted above. */ uint16_t enc28j60_receive_packet(uint8_t* buffer, uint16_t buffer_len) { if(!enc28j60_read(EPKTCNT)) return 0; /* set read pointer */ enc28j60_write(ERDPTL, packet_ptr & 0xff); enc28j60_write(ERDPTH, packet_ptr >> 8); /* read pointer to next packet */ packet_ptr = ((uint16_t) enc28j60_read_buffer_byte()) | ((uint16_t) enc28j60_read_buffer_byte()) << 8; /* read packet length */ uint16_t packet_len = ((uint16_t) enc28j60_read_buffer_byte()) | ((uint16_t) enc28j60_read_buffer_byte()) << 8; packet_len -= 4; /* ignore CRC */ /* read receive status */ enc28j60_read_buffer_byte(); enc28j60_read_buffer_byte(); /* read packet */ if(packet_len <= buffer_len) enc28j60_read_buffer(buffer, packet_len); /* free packet memory */ /* DS80349C.errata #14 */ uint16_t packet_ptr_errata = packet_ptr - 1; if(packet_ptr_errata < RX_START || packet_ptr_errata > RX_END) packet_ptr_errata = RX_END; enc28j60_write(ERXRDPTL, packet_ptr_errata & 0xff); enc28j60_write(ERXRDPTH, packet_ptr_errata >> 8); /* decrement packet counter */ enc28j60_set_bits(ECON2, (1 << ECON2_PKTDEC)); if(packet_len <= buffer_len) return packet_len; else return 0; }