📄 ethernet.c
字号:
/******************************************************************************************
Ethernet.c (v1.0)
-------------------------------------------------------------------------------------
This code is from the book:
"Embedded Internet: TCP/IP Basics, Implementation and Applications" by Sergio Scaglia
[Pearson Education, 2006 - ISBN: 0-32-130638-4]
This code is copyright (c) 2006 by Sergio Scaglia, and it may only be used for educational
purposes. For commercial use, please contact me at sscaglia@intramarket.com.ar
For more information and updates, please visit www.embeddedinternet.org
******************************************************************************************/
#include "stack.h"
#include "Ethernet.h"
#include "arp.h"
#include <iolpc2129.h>
#include <string.h>
#include <stdio.h>
/* CS8900 PacketPage I/O Port Definitions */
#define pp_RxTxData 0x00 // Receive/Transmit data Port 0
#define pp_TxCmd 0x04 // Transmit Command
#define pp_TxLen 0x06 // Transmit Length
#define pp_Ptr 0x0A // PacketPage Pointer
#define pp_Data0 0x0C // PacketPage Data Port 0
/* CS8900 PacketPage Internal Registers */
#define pp_RxCFG 0x0102 // Receiver Configuration
#define pp_RxCTL 0x0104 // Receiver Control
#define pp_LineCTL 0x0112 // Line Control
#define pp_SelfCTL 0x0114 // Self Control
#define pp_TestCTL 0x0118 // Test Control
#define pp_RxEvent 0x0124 // Receiver Event
#define pp_SelfStatus 0x0136 // Self Status
#define pp_BusStatus 0x0138 // Bus Status
#define pp_IndividualA 0x0158 // Individual Address
char rx_buf[PACKET_BUF_SIZE];
char tx_buf[PACKET_BUF_SIZE];
char MyMAC[6] = MyMACAddress;
char MyIP[4] = MyIPAddress; // device IPv4 address
char Gateway[4] = GatewayAddress;
char SubNetMask[4] = SubNetMaskAddress;
/***************************************/
/* CS8900 Ethernet Private Functions */
/***************************************/
char CS8900_read_port(char port_address) {
char port_data;
IO0CLR = SAB; // Clear Address lines
IO0SET = (port_address<<4) & SAB; // Set Address lines
IO0CLR = IOR; // IOR=0 - Enable Read
port_data = ((IO0PIN & SDB)>>16); // Read Data from CS8900
IO0SET = IOR; // IOR=1 - Disable Read
return port_data; // Return Data
}
void CS8900_write_port(char port_address, char port_data) {
IO0DIR |= SDB; // SD7-SD0 as Outputs - Data lines
IO0CLR = SDB; // Clear Data lines
IO0SET = (port_data<<16); // Set Data lines
IO0CLR = SAB; // Clear Address lines
IO0SET = (port_address<<4) & SAB; // Set Address lines
IO0CLR = IOW; // IOW=0 - Enable Write
IO0SET = IOW; // IOW=1 - Disable Write
IO0DIR &= (~SDB); // SD7-SD0 as Inputs - Data lines
}
unsigned short CS8900_read_reg(unsigned short reg_address) {
CS8900_write_port(pp_Ptr, (reg_address & 0x0FF)); // Write Packet Page pointer - Lower byte
CS8900_write_port(pp_Ptr+1, ((reg_address>>8) & 0x0FF)); // Write Packet Page pointer - Higher byte
return ((CS8900_read_port(pp_Data0+1)<<8) + CS8900_read_port(pp_Data0)); // Read Data Port 0 and return
}
void CS8900_write_reg(unsigned short reg_address, unsigned short reg_data)
{
CS8900_write_port(pp_Ptr, (reg_address & 0x0FF)); // Write Packet Page pointer - Lower byte
CS8900_write_port(pp_Ptr+1, ((reg_address>>8) & 0x0FF)); // Write Packet Page pointer - Higher byte
CS8900_write_port(pp_Data0, (reg_data & 0x0FF)); // Write Packet Page Data Port 0 - Lower byte
CS8900_write_port(pp_Data0+1, ((reg_data>>8) & 0x0FF)); // Write Packet Page Data Port 0 - Higher byte
}
void frame_send(unsigned short len) {
unsigned short i, j=0xFFFF;
if (len > PACKET_BUF_SIZE) { //len exceeds maximum ethernet frame length
printf("Ethernet: maximum frame length exceeded\n");
return;
}
CS8900_write_port(pp_TxCmd, 0xC0);
CS8900_write_port(pp_TxCmd+1, 0x00);
CS8900_write_port(pp_TxLen, (len & 0xFF));
CS8900_write_port(pp_TxLen+1, ((len>>8) & 0xFF));
do {
j--;
} while(!((CS8900_read_reg(pp_BusStatus) & 0x0100)) && j>0);
if (j == 0) {
printf("Ethernet: CS8900 not ready to accept a frame!\n");
return;
}
for(i=0; i<len; i+=2) {
CS8900_write_port(pp_RxTxData, tx_buf[i]);
CS8900_write_port(pp_RxTxData+1, tx_buf[i+1]);
}
}
#if debug_ethernet
void frame_display(unsigned short len) {
unsigned short i, j;
printf("Frame Received - Length: %d bytes\r\n", len);
printf("Destination: %02x-%02x-%02x-%02x-%02x-%02x\r\n", FRAMEr->destination[0], FRAMEr->destination[1],
FRAMEr->destination[2], FRAMEr->destination[3],
FRAMEr->destination[4], FRAMEr->destination[5]);
printf("Source: %02x-%02x-%02x-%02x-%02x-%02x\r\n", FRAMEr->source[0], FRAMEr->source[1],
FRAMEr->source[2], FRAMEr->source[3],
FRAMEr->source[4], FRAMEr->source[5]);
printf("Type: %04x\r\n", HTONS(FRAMEr->protocol));
printf("Data:\r\n ");
j=0;
for(i=14; i<len; i++) {
printf("%02x ", rx_buf[i]);
j++;
if (j==16) {
j=0;
printf("\r\n ");
}
}
printf("\r\n----------------------------------------------------\r\n");
}
#endif //debug_ethernet
unsigned short frame_get(void) {
char header[4];
unsigned short RxLength;
unsigned short i;
header[0] = CS8900_read_port(pp_RxTxData + 1);
header[1] = CS8900_read_port(pp_RxTxData);
header[2] = CS8900_read_port(pp_RxTxData + 1);
header[3] = CS8900_read_port(pp_RxTxData);
RxLength = (header[2]<<8) + header[3];
if (RxLength > PACKET_BUF_SIZE) { // Skip Frame
CS8900_write_reg(pp_RxCFG, (CS8900_read_reg(pp_RxCFG) | 0x0040)); // Set Skip bit in RxCFG register
return 0;
}
for(i=0; i<RxLength; i+=2) {
rx_buf[i] = CS8900_read_port(pp_RxTxData);
rx_buf[i+1] = CS8900_read_port(pp_RxTxData + 1);
}
#if debug_ethernet
frame_display(RxLength);
#endif // debug_ethernet
return RxLength;
}
void frame_process(void) {
if (frame_get() == 0)
return;
switch (HTONS(FRAMEr->protocol)) {
case ARP_PROTOCOL:
arp_process();
break;
case IP_PROTOCOL:
// ip_process();
break;
}
}
/***************************************/
/* Ethernet Public Functions */
/***************************************/
void ethernet_init(void) {
unsigned short ret;
/* Define pin directions */
IO0DIR |= (SAB | IOR |IOW); // SA3-SA0, IOR, and IOW as Outputs
IO0DIR &= (~SDB); // SD7-SD0 as Inputs
IO0SET = IOW | IOR; // Set IOR=IOW=1
/* Reset the CS8900A */
CS8900_write_reg(pp_SelfCTL, 0x0040);
while(!(CS8900_read_reg(pp_SelfStatus) & 0x0080)); // wait for INITD=1 indicating CS8900 Reset Ok
/* Load parameters */
CS8900_write_reg(pp_LineCTL, 0x0000); // Clear all bits for 10Base-T
CS8900_write_reg(pp_TestCTL, 0x4000); // Set Full-Duplex bit
CS8900_write_reg(pp_RxCTL, 0x0D00); // Set RXOkA, IndividualA, BroadcastA bits
CS8900_write_reg(pp_RxCFG, 0x0000); // Clear BufferCRC bit
/* Load MAC Address */
CS8900_write_reg(pp_IndividualA, (MyMAC[1]<<8) + MyMAC[0]);
CS8900_write_reg(pp_IndividualA+2, (MyMAC[3]<<8) + MyMAC[2]);
CS8900_write_reg(pp_IndividualA+4, (MyMAC[5]<<8) + MyMAC[4]);
/* Enable Transmitter and Receiver */
ret = CS8900_read_reg(pp_LineCTL) | 0x00C0; // Set TxOn and RxOn bits
CS8900_write_reg(pp_LineCTL, ret); // in Line Control Register
}
void ethernet_poll(void) {
if ((CS8900_read_reg(pp_RxEvent) & 0x0100)) { // if RxOK bit set, there is a frame
frame_process();
}
}
void ethernet_send(unsigned short protocol, unsigned short len) {
char IPdest[4] = pcIP;
if (protocol == ARP_PROTOCOL) {
if (HTONS(ARPt->opcode) == 0x0001) {
memset(FRAMEt->destination,0xFF,6);
}else {
memcpy(FRAMEt->destination,ARPt->tarhwaddr,6);
}
}else {
if (arp_resolve(IPdest, FRAMEt->destination) == ARP_ENTRY_NOT_FOUND) {
return;
}
}
memcpy(FRAMEt->source, MyMAC, 6);
FRAMEt->protocol = HTONS(protocol);
frame_send(len + (sizeof(struct ethernet_hdr)));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -