diff --git a/BaS_gcc/Makefile b/BaS_gcc/Makefile index 7af89ac..a4ae3ed 100644 --- a/BaS_gcc/Makefile +++ b/BaS_gcc/Makefile @@ -93,10 +93,13 @@ CSRCS= \ \ nbuf.c \ queue.c \ + net_timer.c \ nif.c \ fecbd.c \ fec.c \ + ip.c \ udp.c \ + arp.c \ \ basflash.c \ basflash_start.c diff --git a/BaS_gcc/bas.lk.in b/BaS_gcc/bas.lk.in index 6300048..5ac9f68 100644 --- a/BaS_gcc/bas.lk.in +++ b/BaS_gcc/bas.lk.in @@ -51,11 +51,14 @@ SECTIONS OBJDIR/wait.o(.text) OBJDIR/nbuf.o(.text) + OBJDIR/net_timer.o(.text) OBJDIR/queue.o(.text) OBJDIR/nif.o(.text) OBJDIR/fecbd.o(.text) OBJDIR/fec.o(.text) + OBJDIR/ip.o(.text) OBJDIR/udp.o(text) + OBJDIR/arp.o(text) OBJDIR/unicode.o(.text) OBJDIR/mmc.o(.text) diff --git a/BaS_gcc/include/interrupts.h b/BaS_gcc/include/interrupts.h index 188562d..39ab72c 100644 --- a/BaS_gcc/include/interrupts.h +++ b/BaS_gcc/include/interrupts.h @@ -97,4 +97,11 @@ extern int register_interrupt_handler(uint8_t source, uint8_t level, uint8_t priority, uint8_t intr, void (*handler)(void)); +#define ISR_DBUG_ISR 0x01 +#define ISR_USER_ISR 0x02 + +extern void isr_init(void); +extern int isr_register_handler(int type, int vector, int (*handler)(void *, void *), void *hdev, void *harg); +extern void isr_remove_handler(int type ,int (*handler)(void *, void *)); +extern bool isr_execute_handler(int vector); #endif /* _INTERRUPTS_H_ */ diff --git a/BaS_gcc/include/net_timer.h b/BaS_gcc/include/net_timer.h new file mode 100644 index 0000000..056d803 --- /dev/null +++ b/BaS_gcc/include/net_timer.h @@ -0,0 +1,33 @@ +/* + * File: net_timer.h + * Purpose: Provide a timer use by the dBUG network as a timeout + * indicator + * + * Notes: + */ + +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include +#include +#include + +typedef struct +{ + uint8_t ch; /* which channel is this structure for? */ + uint8_t lvl; /* Interrupt level for this channel */ + uint8_t pri; /* Interrupt priority for this channel */ + uint8_t reference; /* timeout indicator */ + uint32_t gms; /* mode select register value */ + uint16_t pre; /* prescale value */ + uint16_t cnt; /* prescaled clocks for timeout */ +} NET_TIMER; + + +extern bool timer_init(uint8_t, uint8_t, uint8_t); + +/* Vector numbers for all the timer channels */ +#define TIMER_VECTOR(x) (126-x) + +#endif /* _TIMER_H_ */ diff --git a/BaS_gcc/net/arp.c b/BaS_gcc/net/arp.c new file mode 100644 index 0000000..93acd4f --- /dev/null +++ b/BaS_gcc/net/arp.c @@ -0,0 +1,462 @@ +/* + * File: arp.c + * Purpose: Address Resolution Protocol routines. + * + * Notes: + */ + +#include "net.h" +#include +#include + +#define TIMER_NETWORK 0 + +static uint8_t *arp_find_pair(ARP_INFO *arptab, uint16_t protocol, uint8_t *hwa, uint8_t *pa) +{ + /* + * This function searches through the ARP table for the + * specified or address pair. + * If it is found, then a a pointer to the non-specified + * address is returned. Otherwise NULL is returned. + * If you pass in then you get out. + * If you pass in then you get out. + */ + int slot, i, match = false; + uint8_t *rvalue; + + if (((hwa == 0) && (pa == 0)) || (arptab == 0)) + return NULL; + + rvalue = NULL; + + /* + * Check each protocol address for a match + */ + for (slot = 0; slot < arptab->tab_size; slot++) + { + if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) && + (arptab->table[slot].protocol == protocol)) + { + match = true; + if (hwa != 0) + { + /* + * Check the Hardware Address field + */ + rvalue = &arptab->table[slot].pa[0]; + for (i = 0; i < arptab->table[slot].hwa_size; i++) + { + if (arptab->table[slot].hwa[i] != hwa[i]) + { + match = false; + break; + } + } + } + else + { + /* + * Check the Protocol Address field + */ + rvalue = &arptab->table[slot].hwa[0]; + for (i = 0; i < arptab->table[slot].pa_size; i++) + { + if (arptab->table[slot].pa[i] != pa[i]) + { + match = false; + break; + } + } + } + if (match) + { + break; + } + } + } + + if (match) + return rvalue; + else + return NULL; +} + +void arp_merge(ARP_INFO *arptab, uint16_t protocol, int hwa_size, uint8_t *hwa, + int pa_size, uint8_t *pa, int longevity) +{ + /* + * This function merges an entry into the ARP table. If + * either piece is NULL, the function exits, otherwise + * the entry is merged or added, provided there is space. + */ + int i, slot; + uint8_t *ta; + + if ((hwa == NULL) || (pa == NULL) || (arptab == NULL) || + ((longevity != ARP_ENTRY_TEMP) && + (longevity != ARP_ENTRY_PERM))) + { + return; + } + + /* First search ARP table for existing entry */ + if ((ta = arp_find_pair(arptab,protocol,NULL,pa)) != 0) + { + /* Update hardware address */ + for (i = 0; i < hwa_size; i++) + ta[i] = hwa[i]; + return; + } + + /* Next try to find an empty slot */ + slot = -1; + for (i = 0; i < MAX_ARP_ENTRY; i++) + { + if (arptab->table[i].longevity == ARP_ENTRY_EMPTY) + { + slot = i; + break; + } + } + + /* if no empty slot was found, pick a temp slot */ + if (slot == -1) + { + for (i = 0; i < MAX_ARP_ENTRY; i++) + { + if (arptab->table[i].longevity == ARP_ENTRY_TEMP) + { + slot = i; + break; + } + } + } + + /* if after all this, still no slot found, add in last slot */ + if (slot == -1) + slot = (MAX_ARP_ENTRY -1); + + /* add the entry into the slot */ + arptab->table[slot].protocol = protocol; + + arptab->table[slot].hwa_size = (uint8_t) hwa_size; + for (i = 0; i < hwa_size; i++) + arptab->table[slot].hwa[i] = hwa[i]; + + arptab->table[slot].pa_size = (uint8_t) pa_size; + for (i = 0; i < pa_size; i++) + arptab->table[slot].pa[i] = pa[i]; + + arptab->table[slot].longevity = longevity; +} + + +void arp_remove(ARP_INFO *arptab, uint16_t protocol, uint8_t *hwa, uint8_t *pa) +{ + /* + * This function removes an entry from the ARP table. The + * ARP table is searched according to the non-NULL address + * that is provided. + */ + int slot, i, match; + + if (((hwa == 0) && (pa == 0)) || (arptab == 0)) + return; + + /* check each hardware adress for a match */ + for (slot = 0; slot < arptab->tab_size; slot++) + { + if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) && + (arptab->table[slot].protocol == protocol)) + { + match = true; + if (hwa != 0) + { + /* Check Hardware Address field */ + for (i = 0; i < arptab->table[slot].hwa_size; i++) + { + if (arptab->table[slot].hwa[i] != hwa[i]) + { + match = false; + break; + } + } + } + else + { + /* Check Protocol Address field */ + for (i = 0; i < arptab->table[slot].pa_size; i++) + { + if (arptab->table[slot].pa[i] != pa[i]) + { + match = false; + break; + } + } + } + if (match) + { + for (i = 0; i < arptab->table[slot].hwa_size; i++) + arptab->table[slot].hwa[i] = 0; + for (i = 0; i < arptab->table[slot].pa_size; i++) + arptab->table[slot].pa[i] = 0; + arptab->table[slot].longevity = ARP_ENTRY_EMPTY; + break; + } + } + } +} + +void arp_request(NIF *nif, uint8_t *pa) +{ + /* + * This function broadcasts an ARP request for the protocol + * address "pa" + */ + uint8_t *addr; + NBUF *pNbuf; + arp_frame_hdr *arpframe; + int i, result; + + pNbuf = nbuf_alloc(); + if (pNbuf == NULL) + { + #if defined(DEBUG_PRINT) + printf("ARP: arp_request couldn't allocate Tx buffer\n"); + #endif + return; + } + + arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET]; + + /* Build the ARP request packet */ + arpframe->ar_hrd = ETHERNET; + arpframe->ar_pro = ETH_FRM_IP; + arpframe->ar_hln = 6; + arpframe->ar_pln = 4; + arpframe->opcode = ARP_REQUEST; + + addr = &nif->hwa[0]; + for (i = 0; i < 6; i++) + arpframe->ar_sha[i] = addr[i]; + + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + for (i = 0; i < 4; i++) + arpframe->ar_spa[i] = addr[i]; + + for (i = 0; i < 6; i++) + arpframe->ar_tha[i] = 0x00; + + for (i = 0; i < 4; i++) + arpframe->ar_tpa[i] = pa[i]; + + pNbuf->length = ARP_HDR_LEN; + + /* Send the ARP request */ + result = nif->send(nif, nif->broadcast, nif->hwa, ETH_FRM_ARP, pNbuf); + + if (result == 0) + nbuf_free(pNbuf); +} + +static int arp_resolve_pa(NIF *nif, uint16_t protocol, uint8_t *pa, uint8_t **ha) +{ + /* + * This function accepts a pointer to a protocol address and + * searches the ARP table for a hardware address match. If no + * no match found, false is returned. + */ + ARP_INFO *arptab; + + if ((pa == NULL) || (nif == NULL) || (protocol == 0)) + return 0; + + arptab = nif_get_protocol_info (nif,ETH_FRM_ARP); + *ha = arp_find_pair(arptab,protocol,0,pa); + + if (*ha == NULL) + return 0; + else + return 1; +} + +uint8_t *arp_resolve(NIF *nif, uint16_t protocol, uint8_t *pa) +{ + int i; + uint8_t *hwa; + + /* + * Check to see if the necessary MAC-to-IP translation information + * is in table already + */ + if (arp_resolve_pa (nif, protocol, pa, &hwa)) + return hwa; + + /* + * Ok, it's not, so we need to try to obtain it by broadcasting + * an ARP request. Hopefully the desired host is listening and + * will respond with it's MAC address + */ + for (i = 0; i < 3; i++) + { + arp_request (nif, pa); + + timer_set_secs(TIMER_NETWORK, ARP_TIMEOUT); + while (timer_get_reference(TIMER_NETWORK)) + { + if (arp_resolve_pa (nif, protocol, pa, &hwa)) + return hwa; + } + } + + return NULL; +} + +void arp_init(ARP_INFO *arptab) +{ + int slot, i; + + arptab->tab_size = MAX_ARP_ENTRY; + for (slot = 0; slot < arptab->tab_size; slot++) + { + for (i = 0; i < MAX_HWA_SIZE; i++) + arptab->table[slot].hwa[i] = 0; + for (i = 0; i < MAX_PA_SIZE; i++) + arptab->table[slot].pa[i] = 0; + arptab->table[slot].longevity = ARP_ENTRY_EMPTY; + arptab->table[slot].hwa_size = 0; + arptab->table[slot].pa_size = 0; + } +} + +void arp_handler(NIF *nif, NBUF *pNbuf) +{ + /* + * ARP protocol handler + */ + uint8_t *addr; + ARP_INFO *arptab; + int longevity; + arp_frame_hdr *rx_arpframe, *tx_arpframe; + + arptab = nif_get_protocol_info(nif, ETH_FRM_ARP); + rx_arpframe = (arp_frame_hdr *) &pNbuf->data[pNbuf->offset]; + + /* + * Check for an appropriate ARP packet + */ + if ((pNbuf->length < ARP_HDR_LEN) || + (rx_arpframe->ar_hrd != ETHERNET) || + (rx_arpframe->ar_hln != 6) || + (rx_arpframe->ar_pro != ETH_FRM_IP) || + (rx_arpframe->ar_pln != 4)) + { + nbuf_free(pNbuf); + return; + } + + /* + * Check to see if it was addressed to me - if it was, keep this + * ARP entry in the table permanently; if not, mark it so that it + * can be displaced later if necessary + */ + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + if ((rx_arpframe->ar_tpa[0] == addr[0]) && + (rx_arpframe->ar_tpa[1] == addr[1]) && + (rx_arpframe->ar_tpa[2] == addr[2]) && + (rx_arpframe->ar_tpa[3] == addr[3]) ) + { + longevity = ARP_ENTRY_PERM; + } + else + longevity = ARP_ENTRY_TEMP; + + /* + * Add ARP info into the table + */ + arp_merge(arptab, + rx_arpframe->ar_pro, + rx_arpframe->ar_hln, + &rx_arpframe->ar_sha[0], + rx_arpframe->ar_pln, + &rx_arpframe->ar_spa[0], + longevity + ); + + switch (rx_arpframe->opcode) + { + case ARP_REQUEST: + /* + * Check to see if request is directed to me + */ + if ((rx_arpframe->ar_tpa[0] == addr[0]) && + (rx_arpframe->ar_tpa[1] == addr[1]) && + (rx_arpframe->ar_tpa[2] == addr[2]) && + (rx_arpframe->ar_tpa[3] == addr[3]) ) + { + /* + * Reuse the current network buffer to assemble an ARP reply + */ + tx_arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET]; + + /* + * Build new ARP frame from the received data + */ + tx_arpframe->ar_hrd = ETHERNET; + tx_arpframe->ar_pro = ETH_FRM_IP; + tx_arpframe->ar_hln = 6; + tx_arpframe->ar_pln = 4; + tx_arpframe->opcode = ARP_REPLY; + tx_arpframe->ar_tha[0] = rx_arpframe->ar_sha[0]; + tx_arpframe->ar_tha[1] = rx_arpframe->ar_sha[1]; + tx_arpframe->ar_tha[2] = rx_arpframe->ar_sha[2]; + tx_arpframe->ar_tha[3] = rx_arpframe->ar_sha[3]; + tx_arpframe->ar_tha[4] = rx_arpframe->ar_sha[4]; + tx_arpframe->ar_tha[5] = rx_arpframe->ar_sha[5]; + tx_arpframe->ar_tpa[0] = rx_arpframe->ar_spa[0]; + tx_arpframe->ar_tpa[1] = rx_arpframe->ar_spa[1]; + tx_arpframe->ar_tpa[2] = rx_arpframe->ar_spa[2]; + tx_arpframe->ar_tpa[3] = rx_arpframe->ar_spa[3]; + + /* + * Now copy in the new information + */ + addr = &nif->hwa[0]; + tx_arpframe->ar_sha[0] = addr[0]; + tx_arpframe->ar_sha[1] = addr[1]; + tx_arpframe->ar_sha[2] = addr[2]; + tx_arpframe->ar_sha[3] = addr[3]; + tx_arpframe->ar_sha[4] = addr[4]; + tx_arpframe->ar_sha[5] = addr[5]; + + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + tx_arpframe->ar_spa[0] = addr[0]; + tx_arpframe->ar_spa[1] = addr[1]; + tx_arpframe->ar_spa[2] = addr[2]; + tx_arpframe->ar_spa[3] = addr[3]; + + /* + * Save the length of my packet in the buffer structure + */ + pNbuf->length = ARP_HDR_LEN; + + nif->send(nif, + &tx_arpframe->ar_tha[0], + &tx_arpframe->ar_sha[0], + ETH_FRM_ARP, + pNbuf); + } + else + nbuf_free(pNbuf); + break; + case ARP_REPLY: + /* + * The ARP Reply case is already taken care of + */ + default: + nbuf_free(pNbuf); + break; + } + + return; +} diff --git a/BaS_gcc/net/ip.c b/BaS_gcc/net/ip.c new file mode 100644 index 0000000..7af7e44 --- /dev/null +++ b/BaS_gcc/net/ip.c @@ -0,0 +1,293 @@ +/* + * File: ip.c + * Purpose: Internet Protcol device driver + * + * Notes: + * + * Modifications: + */ +#include "net.h" +#include +#include + + +void ip_init(IP_INFO *info, IP_ADDR_P myip, IP_ADDR_P gateway, IP_ADDR_P netmask) +{ + int index; + + for (index = 0; index < sizeof(IP_ADDR); index++) + { + info->myip[index] = myip[index]; + info->gateway[index] = gateway[index]; + info->netmask[index] = netmask[index]; + info->broadcast[index] = 0xFF; + } + + info->rx = 0; + info->rx_unsup = 0; + info->tx = 0; + info->err = 0; +} + +uint8_t *ip_get_myip(IP_INFO *info) +{ + if (info != 0) + { + return (uint8_t *) &info->myip[0]; + } + return 0; +} + +int ip_addr_compare(IP_ADDR_P addr1, IP_ADDR_P addr2) +{ + int i; + + for (i = 0; i < sizeof(IP_ADDR); i++) + { + if (addr1[i] != addr2[i]) + return 0; + } + return 1; +} + +uint8_t *ip_resolve_route(NIF *nif, IP_ADDR_P destip) +{ + /* + * This function determines whether or not an outgoing IP + * packet needs to be transmitted on the local net or sent + * to the router for transmission. + */ + IP_INFO *info; + IP_ADDR mask,result; + int i; + + info = nif_get_protocol_info(nif,ETH_FRM_IP); + + /* create mask for local IP */ + for (i = 0; i < sizeof(IP_ADDR); i++) + { + mask[i] = info->myip[i] & info->netmask[i]; + } + + /* apply mask to the destination IP */ + for (i = 0; i < sizeof(IP_ADDR); i++) + { + result[i] = mask[i] & destip[i]; + } + + /* See if destination IP is local or not */ + if (ip_addr_compare(mask,result)) + { + /* The destination IP is on the local net */ + return arp_resolve(nif,ETH_FRM_IP,destip); + } + else + { + /* The destination IP is not on the local net */ + return arp_resolve(nif,ETH_FRM_IP,info->gateway); + } +} + +int ip_send(NIF *nif, uint8_t *dest, uint8_t *src, uint8_t protocol, NBUF *pNbuf) +{ + /* + * This function assembles an IP datagram and passes it + * onto the hardware to be sent over the network. + */ + uint8_t *route; + ip_frame_hdr *ipframe; + + /* + * Construct the IP header + */ + ipframe = (ip_frame_hdr*) &pNbuf->data[IP_HDR_OFFSET]; + + /* IP version 4, Internet Header Length of 5 32-bit words */ + ipframe->version_ihl = 0x45; + + /* Type of Service == 0, normal and routine */ + ipframe->service_type = 0x00; + + /* Total length of data */ + ipframe->total_length = (uint16_t) (pNbuf->length + IP_HDR_SIZE); + + /* User defined identification */ + ipframe->identification = 0x0000; + + /* Fragment Flags and Offset -- Don't fragment, last frag */ + ipframe->flags_frag_offset = 0x0000; + + /* Time To Live */ + ipframe->ttl = 0xFF; + + /* Protocol */ + ipframe->protocol = protocol; + + /* Checksum, computed later, zeroed for computation */ + ipframe->checksum = 0x0000; + + /* source IP address */ + ipframe->source_addr[0] = src[0]; + ipframe->source_addr[1] = src[1]; + ipframe->source_addr[2] = src[2]; + ipframe->source_addr[3] = src[3]; + + /* dest IP address */ + ipframe->dest_addr[0] = dest[0]; + ipframe->dest_addr[1] = dest[1]; + ipframe->dest_addr[2] = dest[2]; + ipframe->dest_addr[3] = dest[3]; + + /* Compute checksum */ + ipframe->checksum = ip_chksum((uint16_t *) ipframe, IP_HDR_SIZE); + + /* Increment the packet length by the size of the IP header */ + pNbuf->length += IP_HDR_SIZE; + + /* + * Determine the hardware address of the recipient + */ + route = ip_resolve_route(nif, dest); + if (route == NULL) + { + xprintf("Unable to locate %d.%d.%d.%d\n", + dest[0],dest[1],dest[2],dest[3]); + return 0; + } + + return nif->send(nif, + route, + &nif->hwa[0], + ETH_FRM_IP, + pNbuf + ); +} + +#if defined(DEBUG_PRINT) +void +dump_ip_frame (ip_frame_hdr *ipframe) +{ + printf("Version: %02X\n", ((ipframe->version_ihl & 0x00f0) >> 4)); + printf("IHL: %02X\n", ipframe->version_ihl & 0x000f); + printf("Service: %02X\n", ipframe->service_type); + printf("Length: %04X\n", ipframe->total_length); + printf("Ident: %04X\n", ipframe->identification); + printf("Flags: %02X\n", ((ipframe->flags_frag_offset & 0xC000) >> 14)); + printf("Frag: %04X\n", ipframe->flags_frag_offset & 0x3FFF); + printf("TTL: %02X\n", ipframe->ttl); + printf("Protocol: %02X\n", ipframe->protocol); + printf("Chksum: %04X\n", ipframe->checksum); + printf("Source : %d.%d.%d.%d\n", + ipframe->source_addr[0], + ipframe->source_addr[1], + ipframe->source_addr[2], + ipframe->source_addr[3]); + printf("Dest : %d.%d.%d.%d\n", + ipframe->dest_addr[0], + ipframe->dest_addr[1], + ipframe->dest_addr[2], + ipframe->dest_addr[3]); + printf("Options: %08X\n", ipframe->options); +} +#endif + + +uint16_t ip_chksum(uint16_t *data, int num) +{ + int chksum, ichksum; + uint16_t temp; + + chksum = 0; + num = num >> 1; /* from bytes to words */ + for (; num; num--, data++) + { + temp = *data; + ichksum = chksum + temp; + ichksum = ichksum & 0x0000FFFF; + if ((ichksum < temp) || (ichksum < chksum)) + { + ichksum += 1; + ichksum = ichksum & 0x0000FFFF; + } + chksum = ichksum; + } + return (uint16_t) ~chksum; +} + +static int validate_ip_hdr(NIF *nif, ip_frame_hdr *ipframe) +{ + int index, chksum; + IP_INFO *info; + + /* + * Check the IP Version + */ + if (IP_VERSION(ipframe) != 4) + return 0; + + /* + * Check Internet Header Length + */ + if (IP_IHL(ipframe) < 5) + return 0; + + /* + * Check the destination IP address + */ + info = nif_get_protocol_info(nif,ETH_FRM_IP); + for (index = 0; index < sizeof(IP_ADDR); index++) + if (info->myip[index] != ipframe->dest_addr[index]) + return 0; + + /* + * Check the checksum + */ + chksum = (int)((uint16_t) IP_CHKSUM(ipframe)); + IP_CHKSUM(ipframe) = 0; + + if (ip_chksum((uint16_t *) ipframe,IP_IHL(ipframe)*4) != chksum) + return 0; + + IP_CHKSUM(ipframe) = (uint16_t) chksum; + + return 1; +} + +void ip_handler(NIF *nif, NBUF *pNbuf) +{ + /* + * IP packet handler + */ + ip_frame_hdr *ipframe; + + ipframe = (ip_frame_hdr *)&pNbuf->data[pNbuf->offset]; + + /* + * Verify valid IP header and destination IP + */ + if (!validate_ip_hdr(nif,ipframe)) + { + nbuf_free(pNbuf); + return; + } + + pNbuf->offset += (IP_IHL(ipframe) * 4); + pNbuf->length = (uint16_t)(IP_LENGTH(ipframe) - (IP_IHL(ipframe) * 4)); + + /* + * Call the appriopriate handler + */ + switch (IP_PROTOCOL(ipframe)) + { + case IP_PROTO_ICMP: + // FIXME: icmp_handler(nif,pNbuf); + break; + case IP_PROTO_UDP: + udp_handler(nif,pNbuf); + break; + default: + nbuf_free(pNbuf); + break; + } + return; +} diff --git a/BaS_gcc/net/net_timer.c b/BaS_gcc/net/net_timer.c new file mode 100644 index 0000000..491b14a --- /dev/null +++ b/BaS_gcc/net/net_timer.c @@ -0,0 +1,176 @@ +/* + * File: net_timer.c + * Purpose: Provide a timer use by the dBUG network as a timeout + * indicator + * + * Notes: + */ +#include "net_timer.h" +#include +#include +#include "MCF5475.h" +#include "interrupts.h" + +#if defined(MACHINE_FIREBEE) +#include "firebee.h" +#elif defined(MACHINE_M5484LITE) +#include "m5484l.h" +#else +#error unknown machine! +#endif + +static NET_TIMER net_timer[4] = {{0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}}; + + +int timer_default_isr(void *not_used, NET_TIMER *t) +{ + (void) not_used; + + /* + * Clear the pending event + */ + MCF_GPT_GMS(t->ch) = 0; + + /* + * Clear the reference - the desired seconds have expired + */ + t->reference = 0; + + return 1; +} + +void timer_irq_enable(uint8_t ch) +{ + /* + * Setup the appropriate ICR + */ + MCF_INTC_ICR(TIMER_VECTOR(ch) - 64) = + (uint8_t)(0 + | MCF_INTC_ICR_IP(net_timer[ch].pri) + | MCF_INTC_ICR_IL(net_timer[ch].lvl)); + + /* + * Unmask the FEC interrupt in the interrupt controller + */ + if (ch == 3) + MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK59; + else if (ch == 2) + MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK60; + else if (ch == 1) + MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK61; + else + MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK62; +} + +bool timer_set_secs(uint8_t ch, uint32_t secs) +{ + uint16_t timeout; + + /* + * Reset the timer + */ + MCF_GPT_GMS(ch) = 0; + + /* + * Get the timeout in seconds + */ + timeout = (uint16_t)(secs * net_timer[ch].cnt); + + /* + * Set the reference indicating that we have not yet reached the + * desired timeout + */ + net_timer[ch].reference = 1; + + /* + * Enable timer interrupt to the processor + */ + timer_irq_enable(ch); + + /* + * Enable the timer using the pre-calculated values + */ + MCF_GPT_GCIR(ch) = (0 + | MCF_GPT_GCIR_CNT(timeout) + | MCF_GPT_GCIR_PRE(net_timer[ch].pre) + ); + MCF_GPT_GMS(ch) = net_timer[ch].gms; + + return true; +} + +uint32_t timer_get_reference(uint8_t ch) +{ + return (uint32_t) net_timer[ch].reference; +} + +bool timer_init(uint8_t ch, uint8_t lvl, uint8_t pri) +{ + /* + * Initialize the timer to expire after one second + * + * This routine should only be called by the project (board) specific + * initialization code. + */ + if (!((ch <= 3) && (lvl <= 7) && (lvl >= 1) && (pri <= 7))) + return false; + + /* + * Reset the timer + */ + MCF_GPT_GMS(ch) = 0; + + /* + * Save off the channel, and interrupt lvl/pri information + */ + net_timer[ch].ch = ch; + net_timer[ch].lvl = lvl; + net_timer[ch].pri = pri; + + /* + * Register the timer interrupt handler + */ + if (!isr_register_handler(ISR_DBUG_ISR, + TIMER_VECTOR(ch), + (int (*)(void *,void *)) timer_default_isr, + NULL, + (void *) &net_timer[ch]) + ) + { + return false; + } + + /* + * Calculate the require CNT value to get a 1 second timeout + * + * 1 sec = CNT * Clk Period * PRE + * CNT = 1 sec / (Clk Period * PRE) + * CNT = Clk Freq / PRE + * + * The system clock frequency is defined as SYSTEM_CLOCK and + * is given in MHz. We need to multiple it by 1000000 to get the + * true value. If we assume PRE to be the maximum of 0xFFFF, + * then the CNT value needed to achieve a 1 second timeout is + * given by: + * + * CNT = SYSTEM_CLOCK * (1000000/0xFFFF) + */ + net_timer[ch].pre = 0xFFFF; + net_timer[ch].cnt = (uint16_t) (SYSCLK * (1000000 / 0xFFFF)); + + /* + * Save off the appropriate mode select register value + */ + net_timer[ch].gms = (0 + | MCF_GPT_GMS_TMS_GPIO + | MCF_GPT_GMS_IEN + | MCF_GPT_GMS_SC + | MCF_GPT_GMS_CE + ); + + return true; +} + diff --git a/BaS_gcc/net/udp.c b/BaS_gcc/net/udp.c index 6cca10e..4d2fbbd 100644 --- a/BaS_gcc/net/udp.c +++ b/BaS_gcc/net/udp.c @@ -9,30 +9,22 @@ */ #include "bas_types.h" #include "net.h" +#include -#ifdef DBUG_NETWORK - -/********************************************************************/ typedef struct { uint16_t port; void (*handler)(NIF *, NBUF *); } UDP_BOUND_PORT; -/********************************************************************/ - #define UDP_MAX_PORTS (5) /* plenty for this implementation */ -static UDP_BOUND_PORT -udp_port_table[UDP_MAX_PORTS]; +static UDP_BOUND_PORT udp_port_table[UDP_MAX_PORTS]; -static uint16 -udp_port; +static uint16_t udp_port; -/********************************************************************/ -void -udp_init (void) +void udp_init(void) { int index; @@ -43,15 +35,13 @@ udp_init (void) udp_port = DEFAULT_UDP_PORT; /* next free port */ } -/********************************************************************/ -void -udp_prime_port (uint16 init_port) + +void udp_prime_port(uint16_t init_port) { udp_port = init_port; } -/********************************************************************/ -void -udp_bind_port (uint16 port, void (*handler)(NIF *, NBUF *)) + +void udp_bind_port(uint16_t port, void (*handler)(NIF *, NBUF *)) { int index; @@ -65,9 +55,8 @@ udp_bind_port (uint16 port, void (*handler)(NIF *, NBUF *)) } } } -/********************************************************************/ -void -udp_free_port (uint16 port) + +void udp_free_port(uint16_t port) { int index; @@ -80,9 +69,8 @@ udp_free_port (uint16 port) } } } -/********************************************************************/ -static void * -udp_port_handler (uint16 port) + +static void *udp_port_handler(uint16_t port) { int index; @@ -95,11 +83,10 @@ udp_port_handler (uint16 port) } return NULL; } -/********************************************************************/ -uint16 -udp_obtain_free_port (void) + +uint16_t udp_obtain_free_port(void) { - uint16 port; + uint16_t port; port = udp_port; if (--udp_port <= 255) @@ -107,50 +94,47 @@ udp_obtain_free_port (void) return port; } -/********************************************************************/ -int -udp_send ( NIF *nif, uint8 *dest, int sport, int dport, NBUF *pNbuf) + +int udp_send(NIF *nif, uint8_t *dest, int sport, int dport, NBUF *pNbuf) { /* * This function takes data and creates a UDP frame and * passes it onto the IP layer */ - udp_frame_hdr *udpframe; + udp_frame_hdr *udpframe; - udpframe = (udp_frame_hdr *)&pNbuf->data[UDP_HDR_OFFSET]; + udpframe = (udp_frame_hdr *) &pNbuf->data[UDP_HDR_OFFSET]; /* Set UDP source port */ - udpframe->src_port = (uint16)sport; + udpframe->src_port = (uint16_t) sport; /* Set UDP destination port */ - udpframe->dest_port = (uint16)dport; + udpframe->dest_port = (uint16_t) dport; /* Set length */ - udpframe->length = (uint16)(pNbuf->length + UDP_HDR_SIZE); + udpframe->length = (uint16_t) (pNbuf->length + UDP_HDR_SIZE); /* No checksum calcualation needed */ - udpframe->chksum = (uint16)0; + udpframe->chksum = (uint16_t) 0; /* Add the length of the UDP packet to the total length of the packet */ pNbuf->length += 8; - return (ip_send(nif, - dest, - ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)), + return (ip_send(nif, dest, + ip_get_myip(nif_get_protocol_info(nif, ETH_FRM_IP)), IP_PROTO_UDP, pNbuf)); } -/********************************************************************/ -void -udp_handler (NIF *nif, NBUF *pNbuf) + +void udp_handler(NIF *nif, NBUF *pNbuf) { /* * This function handles incoming UDP packets */ - udp_frame_hdr *udpframe; + udp_frame_hdr *udpframe; void (*handler)(NIF *, NBUF *); - udpframe = (udp_frame_hdr *)&pNbuf->data[pNbuf->offset]; + udpframe = (udp_frame_hdr *) &pNbuf->data[pNbuf->offset]; /* * Adjust the length and valid data offset of the packet we are @@ -163,18 +147,13 @@ udp_handler (NIF *nif, NBUF *pNbuf) * Traverse the list of bound ports to see if there is a higher * level protocol to pass the packet on to */ - if ((handler = (void(*)(NIF*,NBUF*))udp_port_handler(UDP_DEST(udpframe))) != NULL) + if ((handler = (void(*)(NIF*, NBUF*)) udp_port_handler(UDP_DEST(udpframe))) != NULL) handler(nif, pNbuf); else { - #ifdef DBUG_PRINT - printf("Received UDP packet for non-supported port\n"); - #endif + xprintf("Received UDP packet for non-supported port\n"); nbuf_free(pNbuf); } return; } -/********************************************************************/ - -#endif /* #ifdef DBUG_NETWORK */ diff --git a/BaS_gcc/sys/interrupts.c b/BaS_gcc/sys/interrupts.c index e092c1f..4ac9a1f 100644 --- a/BaS_gcc/sys/interrupts.c +++ b/BaS_gcc/sys/interrupts.c @@ -23,6 +23,7 @@ */ #include +#include #include "MCF5475.h" #include "bas_utils.h" #include "bas_printf.h" @@ -79,3 +80,146 @@ int register_interrupt_handler(uint8_t source, uint8_t level, uint8_t priority, return 0; } + +#ifndef UIF_MAX_ISR_ENTRY +#define UIF_MAX_ISR_ENTRY (20) +#endif + + +typedef struct +{ + int vector; + int type; + int (*handler)(void *, void *); + void *hdev; + void *harg; +} ISRENTRY; + +ISRENTRY isrtab[UIF_MAX_ISR_ENTRY]; + + +void isr_init(void) +{ + int index; + + for (index = 0; index < UIF_MAX_ISR_ENTRY; index++) + { + isrtab[index].vector = 0; + isrtab[index].type = 0; + isrtab[index].handler = 0; + isrtab[index].hdev = 0; + isrtab[index].harg = 0; + } +} + + +int isr_register_handler ( + int type, int vector, + int (*handler)(void *, void *), void *hdev, void *harg) +{ + /* + * This function places an interrupt handler in the ISR table, + * thereby registering it so that the low-level handler may call it. + * + * The two parameters are intended for the first arg to be a + * pointer to the device itself, and the second a pointer to a data + * structure used by the device driver for that particular device. + */ + int index; + + if ((vector == 0) || + ((type != ISR_DBUG_ISR) && (type != ISR_USER_ISR)) || + (handler == NULL)) + { + return true; + } + + for (index = 0; index < UIF_MAX_ISR_ENTRY; index++) + { + if ((isrtab[index].vector == vector) && + (isrtab[index].type == type)) + { + /* only one entry of each type per vector */ + return 0; + } + + if (isrtab[index].vector == 0) + { + isrtab[index].vector = vector; + isrtab[index].type = type; + isrtab[index].handler = handler; + isrtab[index].hdev = hdev; + isrtab[index].harg = harg; + return 1; + } + } + return false; /* no available slots */ +} + +void isr_remove_handler(int type, int (*handler)(void *, void *)) +{ + /* + * This routine removes from the ISR table all + * entries that matches 'type' and 'handler'. + */ + int index; + + for (index = 0; index < UIF_MAX_ISR_ENTRY; index++) + { + if ((isrtab[index].handler == handler) && + (isrtab[index].type == type)) + { + isrtab[index].vector = 0; + isrtab[index].type = 0; + isrtab[index].handler = 0; + isrtab[index].hdev = 0; + isrtab[index].harg = 0; + } + } +} + + +bool isr_execute_handler(int vector) +{ + /* + * This routine searches the ISR table for an entry that matches + * 'vector'. If one is found, then 'handler' is executed. + */ + int index; + bool retval = false; + + /* + * First locate a dBUG Interrupt Service Routine handler. + */ + for (index = 0; index < UIF_MAX_ISR_ENTRY; index++) + { + if ((isrtab[index].vector == vector) && + (isrtab[index].type == ISR_DBUG_ISR)) + { + if (isrtab[index].handler(isrtab[index].hdev,isrtab[index].harg)) + { + retval = true; + break; + } + } + } + + /* + * Try to locate a user-registered Interrupt Service Routine handler. + */ + for (index = 0; index < UIF_MAX_ISR_ENTRY; index++) + { + if ((isrtab[index].vector == vector) && + (isrtab[index].type == ISR_USER_ISR)) + { + if (isrtab[index].handler(isrtab[index].hdev,isrtab[index].harg)) + { + retval = true; + break; + } + } + } + + return retval; +} +