Contiki-NG
Loading...
Searching...
No Matches
enc28j60.c
1/*
2 * Copyright (c) 2012-2013, Thingsquare, http://www.thingsquare.com/.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32#include "contiki.h"
33#include "dev/ethernet/enc28j60/enc28j60.h"
34#include <stdio.h>
35#include <string.h>
36
37#define DEBUG 0
38#if DEBUG
39#define PRINTF(...) printf(__VA_ARGS__)
40#else
41#define PRINTF(...)
42#endif
43
44#define EIE 0x1b
45#define EIR 0x1c
46#define ESTAT 0x1d
47#define ECON2 0x1e
48#define ECON1 0x1f
49
50#define ESTAT_CLKRDY 0x01
51#define ESTAT_TXABRT 0x02
52
53#define ECON1_RXEN 0x04
54#define ECON1_TXRTS 0x08
55
56#define ECON2_AUTOINC 0x80
57#define ECON2_PKTDEC 0x40
58
59#define EIR_TXIF 0x08
60
61#define ERXTX_BANK 0x00
62
63#define ERDPTL 0x00
64#define ERDPTH 0x01
65#define EWRPTL 0x02
66#define EWRPTH 0x03
67#define ETXSTL 0x04
68#define ETXSTH 0x05
69#define ETXNDL 0x06
70#define ETXNDH 0x07
71#define ERXSTL 0x08
72#define ERXSTH 0x09
73#define ERXNDL 0x0a
74#define ERXNDH 0x0b
75#define ERXRDPTL 0x0c
76#define ERXRDPTH 0x0d
77
78#define RX_BUF_START 0x0000
79#define RX_BUF_END 0x0fff
80
81#define TX_BUF_START 0x1200
82
83/* MACONx registers are in bank 2 */
84#define MACONX_BANK 0x02
85
86#define MACON1 0x00
87#define MACON3 0x02
88#define MACON4 0x03
89#define MABBIPG 0x04
90#define MAIPGL 0x06
91#define MAIPGH 0x07
92#define MAMXFLL 0x0a
93#define MAMXFLH 0x0b
94
95#define MACON1_TXPAUS 0x08
96#define MACON1_RXPAUS 0x04
97#define MACON1_MARXEN 0x01
98
99#define MACON3_PADCFG_FULL 0xe0
100#define MACON3_TXCRCEN 0x10
101#define MACON3_FRMLNEN 0x02
102#define MACON3_FULDPX 0x01
103
104#define MAX_MAC_LENGTH 1518
105
106#define MAADRX_BANK 0x03
107#define MAADR1 0x04 /* MAADR<47:40> */
108#define MAADR2 0x05 /* MAADR<39:32> */
109#define MAADR3 0x02 /* MAADR<31:24> */
110#define MAADR4 0x03 /* MAADR<23:16> */
111#define MAADR5 0x00 /* MAADR<15:8> */
112#define MAADR6 0x01 /* MAADR<7:0> */
113#define MISTAT 0x0a
114#define EREVID 0x12
115
116#define EPKTCNT_BANK 0x01
117#define ERXFCON 0x18
118#define EPKTCNT 0x19
119
120#define ERXFCON_UCEN 0x80
121#define ERXFCON_ANDOR 0x40
122#define ERXFCON_CRCEN 0x20
123#define ERXFCON_MCEN 0x02
124#define ERXFCON_BCEN 0x01
125
126
127PROCESS(enc_watchdog_process, "Enc28j60 watchdog");
128
129static uint8_t initialized = 0;
130static uint8_t bank = ERXTX_BANK;
131static uint8_t enc_mac_addr[6];
132static int received_packets = 0;
133static int sent_packets = 0;
134
135/*---------------------------------------------------------------------------*/
136static uint8_t
137is_mac_mii_reg(uint8_t reg)
138{
139 /* MAC or MII register (otherwise, ETH register)? */
140 switch(bank) {
141 case MACONX_BANK:
142 return reg < EIE;
143 case MAADRX_BANK:
144 return reg <= MAADR2 || reg == MISTAT;
145 case ERXTX_BANK:
146 case EPKTCNT_BANK:
147 default:
148 return 0;
149 }
150}
151/*---------------------------------------------------------------------------*/
152static uint8_t
153readreg(uint8_t reg)
154{
155 uint8_t r;
156 enc28j60_arch_spi_select();
157 enc28j60_arch_spi_write(0x00 | (reg & 0x1f));
158 if(is_mac_mii_reg(reg)) {
159 /* MAC and MII registers require that a dummy byte be read first. */
160 enc28j60_arch_spi_read();
161 }
162 r = enc28j60_arch_spi_read();
163 enc28j60_arch_spi_deselect();
164 return r;
165}
166/*---------------------------------------------------------------------------*/
167static void
168writereg(uint8_t reg, uint8_t data)
169{
170 enc28j60_arch_spi_select();
171 enc28j60_arch_spi_write(0x40 | (reg & 0x1f));
172 enc28j60_arch_spi_write(data);
173 enc28j60_arch_spi_deselect();
174}
175/*---------------------------------------------------------------------------*/
176static void
177setregbitfield(uint8_t reg, uint8_t mask)
178{
179 if(is_mac_mii_reg(reg)) {
180 writereg(reg, readreg(reg) | mask);
181 } else {
182 enc28j60_arch_spi_select();
183 enc28j60_arch_spi_write(0x80 | (reg & 0x1f));
184 enc28j60_arch_spi_write(mask);
185 enc28j60_arch_spi_deselect();
186 }
187}
188/*---------------------------------------------------------------------------*/
189static void
190clearregbitfield(uint8_t reg, uint8_t mask)
191{
192 if(is_mac_mii_reg(reg)) {
193 writereg(reg, readreg(reg) & ~mask);
194 } else {
195 enc28j60_arch_spi_select();
196 enc28j60_arch_spi_write(0xa0 | (reg & 0x1f));
197 enc28j60_arch_spi_write(mask);
198 enc28j60_arch_spi_deselect();
199 }
200}
201/*---------------------------------------------------------------------------*/
202static void
203setregbank(uint8_t new_bank)
204{
205 writereg(ECON1, (readreg(ECON1) & 0xfc) | (new_bank & 0x03));
206 bank = new_bank;
207}
208/*---------------------------------------------------------------------------*/
209static void
210writedata(const uint8_t *data, int datalen)
211{
212 int i;
213 enc28j60_arch_spi_select();
214 /* The Write Buffer Memory (WBM) command is 0 1 1 1 1 0 1 0 */
215 enc28j60_arch_spi_write(0x7a);
216 for(i = 0; i < datalen; i++) {
217 enc28j60_arch_spi_write(data[i]);
218 }
219 enc28j60_arch_spi_deselect();
220}
221/*---------------------------------------------------------------------------*/
222static void
223writedatabyte(uint8_t byte)
224{
225 writedata(&byte, 1);
226}
227/*---------------------------------------------------------------------------*/
228static int
229readdata(uint8_t *buf, int len)
230{
231 int i;
232 enc28j60_arch_spi_select();
233 /* THe Read Buffer Memory (RBM) command is 0 0 1 1 1 0 1 0 */
234 enc28j60_arch_spi_write(0x3a);
235 for(i = 0; i < len; i++) {
236 buf[i] = enc28j60_arch_spi_read();
237 }
238 enc28j60_arch_spi_deselect();
239 return i;
240}
241/*---------------------------------------------------------------------------*/
242static uint8_t
243readdatabyte(void)
244{
245 uint8_t r;
246 readdata(&r, 1);
247 return r;
248}
249/*---------------------------------------------------------------------------*/
250static void
251softreset(void)
252{
253 enc28j60_arch_spi_select();
254 /* The System Command (soft reset) is 1 1 1 1 1 1 1 1 */
255 enc28j60_arch_spi_write(0xff);
256 enc28j60_arch_spi_deselect();
257 bank = ERXTX_BANK;
258}
259/*---------------------------------------------------------------------------*/
260#if DEBUG
261static uint8_t
262readrev(void)
263{
264 uint8_t rev;
265 setregbank(MAADRX_BANK);
266 rev = readreg(EREVID);
267 switch(rev) {
268 case 2:
269 return 1;
270 case 6:
271 return 7;
272 default:
273 return rev;
274 }
275}
276#endif
277/*---------------------------------------------------------------------------*/
278static void
279reset(void)
280{
281 PRINTF("enc28j60: resetting chip\n");
282
283 enc28j60_arch_spi_init();
284
285 /*
286 6.0 INITIALIZATION
287
288 Before the ENC28J60 can be used to transmit and receive packets,
289 certain device settings must be initialized. Depending on the
290 application, some configuration options may need to be
291 changed. Normally, these tasks may be accomplished once after
292 Reset and do not need to be changed thereafter.
293
294 6.1 Receive Buffer
295
296 Before receiving any packets, the receive buffer must be
297 initialized by programming the ERXST and ERXND pointers. All
298 memory between and including the ERXST and ERXND addresses will be
299 dedicated to the receive hardware. It is recommended that the
300 ERXST pointer be programmed with an even address.
301
302 Applications expecting large amounts of data and frequent packet
303 delivery may wish to allocate most of the memory as the receive
304 buffer. Applications that may need to save older packets or have
305 several packets ready for transmission should allocate less
306 memory.
307
308 When programming the ERXST pointer, the ERXWRPT registers will
309 automatically be updated with the same values. The address in
310 ERXWRPT will be used as the starting location when the receive
311 hardware begins writing received data. For tracking purposes, the
312 ERXRDPT registers should additionally be programmed with the same
313 value. To program ERXRDPT, the host controller must write to
314 ERXRDPTL first, followed by ERXRDPTH. See Section 7.2.4 “Freeing
315 Receive Buffer Space for more information
316
317 6.2 Transmission Buffer
318
319 All memory which is not used by the receive buffer is considered
320 the transmission buffer. Data which is to be transmitted should be
321 written into any unused space. After a packet is transmitted,
322 however, the hardware will write a seven-byte status vector into
323 memory after the last byte in the packet. Therefore, the host
324 controller should leave at least seven bytes between each packet
325 and the beginning of the receive buffer. No explicit action is
326 required to initialize the transmission buffer.
327
328 6.3 Receive Filters
329
330 The appropriate receive filters should be enabled or disabled by
331 writing to the ERXFCON register. See Section 8.0 “Receive Filters
332 for information on how to configure it.
333
334 6.4 Waiting For OST
335
336 If the initialization procedure is being executed immediately
337 following a Power-on Reset, the ESTAT.CLKRDY bit should be polled
338 to make certain that enough time has elapsed before proceeding to
339 modify the MAC and PHY registers. For more information on the OST,
340 see Section 2.2 “Oscillator Start-up Timer.
341 */
342
343 softreset();
344
345 /* Workaround for erratum #2. */
346 clock_delay_usec(1000);
347
348 /* Wait for OST */
349 while((readreg(ESTAT) & ESTAT_CLKRDY) == 0);
350
351 setregbank(ERXTX_BANK);
352 /* Set up receive buffer */
353 writereg(ERXSTL, RX_BUF_START & 0xff);
354 writereg(ERXSTH, RX_BUF_START >> 8);
355 writereg(ERXNDL, RX_BUF_END & 0xff);
356 writereg(ERXNDH, RX_BUF_END >> 8);
357 writereg(ERDPTL, RX_BUF_START & 0xff);
358 writereg(ERDPTH, RX_BUF_START >> 8);
359 writereg(ERXRDPTL, RX_BUF_END & 0xff);
360 writereg(ERXRDPTH, RX_BUF_END >> 8);
361
362 /* Receive filters */
363 setregbank(EPKTCNT_BANK);
364 writereg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN);
365
366 /*
367 6.5 MAC Initialization Settings
368
369 Several of the MAC registers require configuration during
370 initialization. This only needs to be done once; the order of
371 programming is unimportant.
372
373 1. Set the MARXEN bit in MACON1 to enable the MAC to receive
374 frames. If using full duplex, most applications should also set
375 TXPAUS and RXPAUS to allow IEEE defined flow control to function.
376
377 2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3. Most
378 applications should enable automatic padding to at least 60 bytes
379 and always append a valid CRC. For convenience, many applications
380 may wish to set the FRMLNEN bit as well to enable frame length
381 status reporting. The FULDPX bit should be set if the application
382 will be connected to a full-duplex configured remote node;
383 otherwise, it should be left clear.
384
385 3. Configure the bits in MACON4. For conformance to the IEEE 802.3
386 standard, set the DEFER bit.
387
388 4. Program the MAMXFL registers with the maximum frame length to
389 be permitted to be received or transmitted. Normal network nodes
390 are designed to handle packets that are 1518 bytes or less.
391
392 5. Configure the Back-to-Back Inter-Packet Gap register,
393 MABBIPG. Most applications will program this register with 15h
394 when Full-Duplex mode is used and 12h when Half-Duplex mode is
395 used.
396
397 6. Configure the Non-Back-to-Back Inter-Packet Gap register low
398 byte, MAIPGL. Most applications will program this register with
399 12h.
400
401 7. If half duplex is used, the Non-Back-to-Back Inter-Packet Gap
402 register high byte, MAIPGH, should be programmed. Most
403 applications will program this register to 0Ch.
404
405 8. If Half-Duplex mode is used, program the Retransmission and
406 Collision Window registers, MACLCON1 and MACLCON2. Most
407 applications will not need to change the default Reset values. If
408 the network is spread over exceptionally long cables, the default
409 value of MACLCON2 may need to be increased.
410
411 9. Program the local MAC address into the MAADR1:MAADR6 registers.
412 */
413
414 setregbank(MACONX_BANK);
415
416 /* Turn on reception and IEEE-defined flow control */
417 setregbitfield(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
418
419 /* Set padding, crc, full duplex */
420 setregbitfield(MACON3, MACON3_PADCFG_FULL | MACON3_TXCRCEN | MACON3_FULDPX |
421 MACON3_FRMLNEN);
422
423 /* Don't modify MACON4 */
424
425 /* Set maximum frame length in MAMXFL */
426 writereg(MAMXFLL, MAX_MAC_LENGTH & 0xff);
427 writereg(MAMXFLH, MAX_MAC_LENGTH >> 8);
428
429 /* Set back-to-back inter packet gap */
430 writereg(MABBIPG, 0x15);
431
432 /* Set non-back-to-back packet gap */
433 writereg(MAIPGL, 0x12);
434
435 /* Set MAC address */
436 setregbank(MAADRX_BANK);
437 writereg(MAADR6, enc_mac_addr[5]);
438 writereg(MAADR5, enc_mac_addr[4]);
439 writereg(MAADR4, enc_mac_addr[3]);
440 writereg(MAADR3, enc_mac_addr[2]);
441 writereg(MAADR2, enc_mac_addr[1]);
442 writereg(MAADR1, enc_mac_addr[0]);
443
444 /*
445 6.6 PHY Initialization Settings
446
447 Depending on the application, bits in three of the PHY module’s
448 registers may also require configuration. The PHCON1.PDPXMD bit
449 partially controls the device’s half/full-duplex
450 configuration. Normally, this bit is initialized correctly by the
451 external circuitry (see Section 2.6 “LED Configuration). If the
452 external circuitry is not present or incorrect, however, the host
453 controller must program the bit properly. Alternatively, for an
454 externally configurable system, the PDPXMD bit may be read and the
455 FULDPX bit be programmed to match.
456
457 For proper duplex operation, the PHCON1.PDPXMD bit must also match
458 the value of the MACON3.FULDPX bit.
459
460 If using half duplex, the host controller may wish to set the
461 PHCON2.HDLDIS bit to prevent automatic loopback of the data which
462 is transmitted. The PHY register, PHLCON, controls the outputs of
463 LEDA and LEDB. If an application requires a LED configuration
464 other than the default, PHLCON must be altered to match the new
465 requirements. The settings for LED operation are discussed in
466 Section 2.6 “LED Configuration. The PHLCON register is shown in
467 Register 2-2 (page 9).
468 */
469
470 /* Don't worry about PHY configuration for now */
471
472 /* Turn on autoincrement for buffer access */
473 setregbitfield(ECON2, ECON2_AUTOINC);
474
475 /* Turn on reception */
476 writereg(ECON1, ECON1_RXEN);
477}
478/*---------------------------------------------------------------------------*/
479void
480enc28j60_init(const uint8_t *mac_addr)
481{
482 if(initialized) {
483 return;
484 }
485
486 memcpy(enc_mac_addr, mac_addr, 6);
487
488 /* Start watchdog process */
489 process_start(&enc_watchdog_process, NULL);
490
491 reset();
492
493 PRINTF("ENC28J60 rev. B%d\n", readrev());
494
495 initialized = 1;
496}
497/*---------------------------------------------------------------------------*/
498int
499enc28j60_send(const uint8_t *data, uint16_t datalen)
500{
501 uint16_t dataend;
502
503 if(!initialized) {
504 return -1;
505 }
506
507 /*
508 1. Appropriately program the ETXST pointer to point to an unused
509 location in memory. It will point to the per packet control
510 byte. In the example, it would be programmed to 0120h. It is
511 recommended that an even address be used for ETXST.
512
513 2. Use the WBM SPI command to write the per packet control byte,
514 the destination address, the source MAC address, the
515 type/length and the data payload.
516
517 3. Appropriately program the ETXND pointer. It should point to the
518 last byte in the data payload. In the example, it would be
519 programmed to 0156h.
520
521 4. Clear EIR.TXIF, set EIE.TXIE and set EIE.INTIE to enable an
522 interrupt when done (if desired).
523
524 5. Start the transmission process by setting
525 ECON1.TXRTS.
526 */
527
528 setregbank(ERXTX_BANK);
529 /* Set up the transmit buffer pointer */
530 writereg(ETXSTL, TX_BUF_START & 0xff);
531 writereg(ETXSTH, TX_BUF_START >> 8);
532 writereg(EWRPTL, TX_BUF_START & 0xff);
533 writereg(EWRPTH, TX_BUF_START >> 8);
534
535 /* Write the transmission control register as the first byte of the
536 output packet. We write 0x00 to indicate that the default
537 configuration (the values in MACON3) will be used. */
538 writedatabyte(0x00); /* MACON3 */
539
540 writedata(data, datalen);
541
542 /* Write a pointer to the last data byte. */
543 dataend = TX_BUF_START + datalen;
544 writereg(ETXNDL, dataend & 0xff);
545 writereg(ETXNDH, dataend >> 8);
546
547 /* Clear EIR.TXIF */
548 clearregbitfield(EIR, EIR_TXIF);
549
550 /* Don't care about interrupts for now */
551
552 /* Send the packet */
553 setregbitfield(ECON1, ECON1_TXRTS);
554 while((readreg(ECON1) & ECON1_TXRTS) > 0);
555
556#if DEBUG
557 if((readreg(ESTAT) & ESTAT_TXABRT) != 0) {
558 uint16_t erdpt;
559 uint8_t tsv[7];
560 erdpt = (readreg(ERDPTH) << 8) | readreg(ERDPTL);
561 writereg(ERDPTL, (dataend + 1) & 0xff);
562 writereg(ERDPTH, (dataend + 1) >> 8);
563 readdata(tsv, sizeof(tsv));
564 writereg(ERDPTL, erdpt & 0xff);
565 writereg(ERDPTH, erdpt >> 8);
566 PRINTF("enc28j60: tx err: %d: %02x:%02x:%02x:%02x:%02x:%02x\n"
567 " tsv: %02x%02x%02x%02x%02x%02x%02x\n", datalen,
568 0xff & data[0], 0xff & data[1], 0xff & data[2],
569 0xff & data[3], 0xff & data[4], 0xff & data[5],
570 tsv[6], tsv[5], tsv[4], tsv[3], tsv[2], tsv[1], tsv[0]);
571 } else {
572 PRINTF("enc28j60: tx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", datalen,
573 0xff & data[0], 0xff & data[1], 0xff & data[2],
574 0xff & data[3], 0xff & data[4], 0xff & data[5]);
575 }
576#endif
577
578 sent_packets++;
579 PRINTF("enc28j60: sent_packets %d\n", sent_packets);
580 return datalen;
581}
582/*---------------------------------------------------------------------------*/
583int
584enc28j60_read(uint8_t *buffer, uint16_t bufsize)
585{
586 int n, len, next, err;
587
588 uint8_t nxtpkt[2];
589 uint8_t status[2];
590 uint8_t length[2];
591
592 if(!initialized) {
593 return -1;
594 }
595
596 err = 0;
597
598 setregbank(EPKTCNT_BANK);
599 n = readreg(EPKTCNT);
600
601 if(n == 0) {
602 return 0;
603 }
604
605 PRINTF("enc28j60: EPKTCNT 0x%02x\n", n);
606
607 setregbank(ERXTX_BANK);
608 /* Read the next packet pointer */
609 nxtpkt[0] = readdatabyte();
610 nxtpkt[1] = readdatabyte();
611
612 PRINTF("enc28j60: nxtpkt 0x%02x%02x\n", nxtpkt[1], nxtpkt[0]);
613
614 length[0] = readdatabyte();
615 length[1] = readdatabyte();
616
617 PRINTF("enc28j60: length 0x%02x%02x\n", length[1], length[0]);
618
619 status[0] = readdatabyte();
620 status[1] = readdatabyte();
621
622 /* This statement is just to avoid a compiler warning: */
623 status[0] = status[0];
624 PRINTF("enc28j60: status 0x%02x%02x\n", status[1], status[0]);
625
626 len = (length[1] << 8) + length[0];
627 if(bufsize >= len) {
628 readdata(buffer, len);
629 } else {
630 uint16_t i;
631
632 err = 1;
633
634 /* flush rx fifo */
635 for(i = 0; i < len; i++) {
636 readdatabyte();
637 }
638 }
639
640 /* Read an additional byte at odd lengths, to avoid FIFO corruption */
641 if((len % 2) != 0) {
642 readdatabyte();
643 }
644
645 /* Errata #14 */
646 next = (nxtpkt[1] << 8) + nxtpkt[0];
647 if(next == RX_BUF_START) {
648 next = RX_BUF_END;
649 } else {
650 next = next - 1;
651 }
652 writereg(ERXRDPTL, next & 0xff);
653 writereg(ERXRDPTH, next >> 8);
654
655 setregbitfield(ECON2, ECON2_PKTDEC);
656
657 if(err) {
658 PRINTF("enc28j60: rx err: flushed %d\n", len);
659 return 0;
660 }
661 PRINTF("enc28j60: rx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", len,
662 0xff & buffer[0], 0xff & buffer[1], 0xff & buffer[2],
663 0xff & buffer[3], 0xff & buffer[4], 0xff & buffer[5]);
664
665 received_packets++;
666 PRINTF("enc28j60: received_packets %d\n", received_packets);
667 return len;
668}
669/*---------------------------------------------------------------------------*/
670PROCESS_THREAD(enc_watchdog_process, ev, data)
671{
672 static struct etimer et;
673
675
676 while(1) {
677#define RESET_PERIOD (30 * CLOCK_SECOND)
678 etimer_set(&et, RESET_PERIOD);
680
681 PRINTF("enc28j60: test received_packet %d > sent_packets %d\n", received_packets, sent_packets);
682 if(received_packets <= sent_packets) {
683 PRINTF("enc28j60: resetting chip\n");
684 reset();
685 }
686 received_packets = 0;
687 sent_packets = 0;
688 }
689
690 PROCESS_END();
691}
692/*---------------------------------------------------------------------------*/
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition clock.c:150
static bool etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition etimer.h:201
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition etimer.c:177
#define PROCESS(name, strname)
Declare a process.
Definition process.h:307
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:120
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition process.h:157
#define PROCESS_END()
Define the end of a process.
Definition process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:107
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:273
A timer.
Definition etimer.h:79