Checksum
The checksum is a method to control the packet integrity, or rather permits to establish if this contains errors (and so is unusable).
the word checksum doesn't identify a particular algorithm, but that used for IP and others protocols is the complement to 1 of the complements sum to 1 of the words at 16bit of the dates where it is made the calculation;
or rather, they sum all the words at 16bit, summing also the eventual overflow and at last follow the complement at 1.
Fisrt it was illustrated how the checksum, in the sending phase, is calculated and then wrote in the packet; what wasn't still illustrated is the checksum control at the packet arrive. To verify that the packet is integral, must save temporally the packet checksum field and put at zero, then follow the calculation and then confront the result with that one saved; if are the same, the packet is correct.
Actually ,for how is made the algorithm, the verifying in very simple: it's enough to calculate the checksum in the packet without modify it; if the result is zero, so the packet in OK, or else is for reject.
The ENC28J60 integral, in the DMA module, a function quite fast for the checksum calculation, and we'll use it.
Unfortunatelly,
in the chip B5 review, this function gives big problems to the packets reception, so in this case the calculation will follow the software.
First of all, let's see the function prototype DMAChecksum:
u16 DMAChecksum(u16 start, u16 len, BOOL rx)
the first parameter indicates the address from where begin the dates, len the length in byte of these dates, at last rx is useful to indicate
if the address "talks" about the RX or TX .
(The address is an offset relative, compared with the MAC packet dates field beginning )
As I told first, this method has two different implementations for the review B1-B4 e B5, let's see the first one:
u16 DMAChecksum(u16 start, u16 len, BOOL rx){
// calculates the checksum using the chip function
u16 tmp;
u8 L,H;
if (rx) {
tmp = TX_BUF_START + 1 + sizeof(MAC_Header) + start;
} else {
tmp = packetStart + 6 + sizeof(MAC_Header) + start;
if (tmp > RX_BUF_END)
tmp = tmp - RX_BUF_END + RX_BUF_START - 1;
}
setBank(0);
writeReg(EDMASTL, LOW(tmp));
writeReg(EDMASTH, HIGH(tmp));
tmp = tmp+len-1; // end packet
if (!rx && tmp > RX_BUF_END)
tmp = tmp - RX_BUF_END + RX_BUF_START - 1;
writeReg(EDMANDL, LOW(tmp));
writeReg(EDMANDH, HIGH(tmp));
BFSReg(ECON1, 0b00110000); //start calculation
while(readETH(ECON1) & 0b00100000); // wait end calculation
tmp = (u16)readETH(EDMACSL) << 8;
tmp = tmp | readETH(EDMACSH);
return tmp; // return the checksum calculated
}Fist of all, are calculated and wrote in the registers the absolute start and end addresses of the dates on we make the operation. Then is passed the calculation and we are waiting for the end.
In the second case, is followed the calculation on the software, which makes the operation very slow:
u16 DMAChecksum(u16 start, u16 len, BOOL rx){
// calculate the checksum via software
u16 tmp;
u16 reg[2];
u32 sum;
u16 len2;
int i;
if (rx) {
tmp = TX_BUF_START + 1 + sizeof(MAC_Header) + start;
} else {
tmp = packetStart + 6 + sizeof(MAC_Header) + start;
if (tmp > RX_BUF_END)
tmp = tmp - RX_BUF_END + RX_BUF_START - 1;
}
// salva ERDPT
setBank(0);
reg[0] = readETH(ERDPTL);
reg[1] = readETH(ERDPTH);
writeReg(ERDPTL,LOW(tmp));
writeReg(ERDPTH,HIGH(tmp));
sum = 0;
len2 = len & 0xFE;
CS = 0;
spiWrite(RBM);
for (i=0; i<len2; i=i+2){
tmp = ((u16)spiRead()) << 8 | spiRead();
sum = sum + (u32) tmp;
}
if (len2!=len) sum += ((u32)spiRead()) << 8; // if the packet has odd length
CS = 1;
while (sum >> 16)
sum = (sum & 0xFFFF) + (sum >> 16);
tmp = ~sum;
// return ERDPT;
setBank(0);
writeReg(ERDPTL,reg[0]);
writeReg(ERDPTH,reg[1]);
return htons(tmp); // return the checksum calculated
}Before effecting the operation, is saved the ERDPT register (restored at the end ), that's why are read
all the byte necessary to the calculation.
Let's see also the method putChecksum used in precedence:
void putChecksum(u16 offset, u16 sum){
// write the checksum "sum" to the address "offset" to the writing buffer internal
u16 tmp;
u16 addr[2];
setBank(0);
addr[0] = readETH(EWRPTL); // save temporally the punter
addr[1] = readETH(EWRPTH); // of the writing
tmp = 1+sizeof(MAC_Header)+offset; // new address
writeReg(EWRPTL,LOW(TX_BUF_START+tmp));
writeReg(EWRPTH,HIGH(TX_BUF_START+tmp)); // charge the punter
encPut(LOW(sum));
encPut(HIGH(sum)); // write the checksum
writeReg(EWRPTL,addr[0]);
writeReg(EWRPTH,addr[1]); // restore the old pinter}
|