diff --git a/part15-tcpip-webserver/.DS_Store b/part15-tcpip-webserver/.DS_Store
new file mode 100644
index 0000000..22c5e21
Binary files /dev/null and b/part15-tcpip-webserver/.DS_Store differ
diff --git a/part15-tcpip/Makefile b/part15-tcpip-webserver/Makefile
similarity index 100%
rename from part15-tcpip/Makefile
rename to part15-tcpip-webserver/Makefile
diff --git a/part15-tcpip/Makefile.gcc b/part15-tcpip-webserver/Makefile.gcc
similarity index 100%
rename from part15-tcpip/Makefile.gcc
rename to part15-tcpip-webserver/Makefile.gcc
diff --git a/part15-tcpip-webserver/README.md b/part15-tcpip-webserver/README.md
new file mode 100644
index 0000000..88135e6
--- /dev/null
+++ b/part15-tcpip-webserver/README.md
@@ -0,0 +1,94 @@
+Writing a "bare metal" operating system for Raspberry Pi 4 (Part 15)
+====================================================================
+
+Adding a TCP/IP stack
+---------------------
+Having achieved "proof of life" from our Ethernet module in _part14-spi-ethernet_, you're doubtless wondering how to go from there to serving web pages, posting tweets on Twitter or perhaps even just simply responding to a ping!
+
+This is where you'll need a fully-fledged TCP/IP stack that goes way beyond handcrafted ARPs, implementing many more protocols to achieve efficient bi-directional communication.
+
+In this part we make use of some code from Guido Socher of [tuxgraphics.org](http://tuxgraphics.org/), designed to be a lightweight TCP/IP stack for embedded devices. I chose this because it was super simple to get working (or "port"), but you might want to look at [LwIP](https://en.wikipedia.org/wiki/LwIP) if you need something more advanced.
+
+The code
+--------
+Most of the new code is in the _tcpip/_ subdirectory. I actually came across it in [this tarball](http://tuxgraphics.org/common/src2/article09051/eth_tcp_client_server-dhcp-5.10.tar.gz) and, again, made only a very few cosmetic changes (`diff` is your friend!).
+
+It did require me to expose the `strlen()` function we implemented in _lib/fb.c_, so that's added to _include/fb.h_. Similarly, we expose the `memcpy()` function we implemented in _kernel/kernel.c_, so that's added to _kernel/kernel.h_.
+
+I also needed a single function that tells the ENC to send a packet. Nothing new here, just different packaging:
+
+```c
+void enc28j60PacketSend(unsigned short buflen, void *buffer) {
+ if (ENC_RestoreTXBuffer(&handle, buflen) == 0) {
+ ENC_WriteBuffer((unsigned char *) buffer, buflen);
+ handle.transmitLength = buflen;
+ ENC_Transmit(&handle);
+ }
+}
+```
+
+This was also added to _kernel/kernel.h_.
+
+What happened to _arp.c_?
+-------------------------
+You'll notice that I've merged _arp.c_ and _kernel.c_. We still initialise the network card in exactly the same way but, when we're done, we call this function in Guido's code:
+
+```c
+init_udp_or_www_server(myMAC, deviceIP);
+```
+
+This tells the TCP/IP library who we are, so we're all on the same page!
+
+Finally, and aside from a little cleanup (eg. moving the HAL timer functions to _io.c_ with the commensurate changes to _io.h_), the major change is the new `serve()` function:
+
+```c
+void serve(void)
+{
+ while (1) {
+ while (!ENC_GetReceivedFrame(&handle));
+
+ uint8_t *buf = (uint8_t *)handle.RxFrameInfos.buffer;
+ uint16_t len = handle.RxFrameInfos.length;
+ uint16_t dat_p = packetloop_arp_icmp_tcp(buf, len);
+
+ if (dat_p != 0) {
+ debugstr("Incoming web request... ");
+
+ if (strncmp("GET ", (char *)&(buf[dat_p]), 4) != 0) {
+ debugstr("not GET");
+ dat_p = fill_tcp_data(buf, 0, "HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\n
ERROR
");
+ } else {
+ if (strncmp("/ ", (char *)&(buf[dat_p+4]), 2) == 0) {
+ // just one web page in the "root directory" of the web server
+ debugstr("GET root");
+ dat_p = fill_tcp_data(buf, 0, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\nHello world!
");
+ } else {
+ // just one web page not in the "root directory" of the web server
+ debugstr("GET not root");
+ dat_p = fill_tcp_data(buf, 0, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\nGoodbye cruel world.
");
+ }
+ }
+
+ www_server_reply(buf, dat_p); // send web page data
+ debugcrlf();
+ }
+ }
+}
+```
+
+This is an infinite loop which waits for an incoming packet and then firstly passes it to Guido's `packetloop_arp_icmp_tcp()` function. This function implements some useful things, like responding to pings. I modified the routine to print a message to the screen when it sends a "pong" (look from line 1371 of _tcpip/ip_arp_udp_tcp.c_), so we can see when it's in action!
+
+Examining the return value of `packetloop_arp_icmp_tcp()` then allows us to check whether there is an incoming web request, since we've configured the TCP/IP library to be a web server in _tcpip/ip_config.h_ with `#define WWW_server`.
+
+We then serve responses based on three possible cases:
+
+ * The incoming request is not a GET request (eg. maybe it's a HEAD request) - you can simulate this using the `curl` tool: `curl -I 192.168.0.66`
+ * The incoming request is a GET request for the root web page `/` - `curl 192.168.0.66/`
+ * The incoming request is a GET request for any non-root web page - eg. `curl 192.168.0.66/isometimes/monkey`
+
+I recommend reading [this page](http://tuxgraphics.org/electronics/200905/embedded-tcp-ip-stack.shtml) for a full explanation. The code I have ported is very similar to what you see there.
+
+_Imagine my excitement when I built, ran and could ping my RPi4 at 192.168.0.66 and get a web response to my browser on both my laptop and my iPhone!_
+
+![Pinging from my iPhone](images/15-tcpip-webserver-pinging.jpg)
+![Browsing from my laptop](images/15-tcpip-webserver-browser.png)
diff --git a/part15-tcpip/boot/boot.S b/part15-tcpip-webserver/boot/boot.S
similarity index 100%
rename from part15-tcpip/boot/boot.S
rename to part15-tcpip-webserver/boot/boot.S
diff --git a/part15-tcpip/boot/link.ld b/part15-tcpip-webserver/boot/link.ld
similarity index 100%
rename from part15-tcpip/boot/link.ld
rename to part15-tcpip-webserver/boot/link.ld
diff --git a/part15-tcpip/boot/sysregs.h b/part15-tcpip-webserver/boot/sysregs.h
similarity index 100%
rename from part15-tcpip/boot/sysregs.h
rename to part15-tcpip-webserver/boot/sysregs.h
diff --git a/part15-tcpip-webserver/images/15-tcpip-webserver-browser.png b/part15-tcpip-webserver/images/15-tcpip-webserver-browser.png
new file mode 100644
index 0000000..14cfdc0
Binary files /dev/null and b/part15-tcpip-webserver/images/15-tcpip-webserver-browser.png differ
diff --git a/part15-tcpip/images/15-tcpip-pinging.jpg b/part15-tcpip-webserver/images/15-tcpip-webserver-pinging.jpg
similarity index 100%
rename from part15-tcpip/images/15-tcpip-pinging.jpg
rename to part15-tcpip-webserver/images/15-tcpip-webserver-pinging.jpg
diff --git a/part15-tcpip/include/fb.h b/part15-tcpip-webserver/include/fb.h
similarity index 100%
rename from part15-tcpip/include/fb.h
rename to part15-tcpip-webserver/include/fb.h
diff --git a/part15-tcpip/include/io.h b/part15-tcpip-webserver/include/io.h
similarity index 91%
rename from part15-tcpip/include/io.h
rename to part15-tcpip-webserver/include/io.h
index 0c79113..707ae63 100644
--- a/part15-tcpip/include/io.h
+++ b/part15-tcpip-webserver/include/io.h
@@ -17,3 +17,5 @@ void gpio_setPinOutputBool(unsigned int pin_number, unsigned int onOrOff);
void gpio_initOutputPinWithPullNone(unsigned int pin_number);
void uart_hex(unsigned int d);
void uart_byte(unsigned char b);
+unsigned long HAL_GetTick(void);
+void HAL_Delay(unsigned int ms);
diff --git a/part15-tcpip/include/mb.h b/part15-tcpip-webserver/include/mb.h
similarity index 100%
rename from part15-tcpip/include/mb.h
rename to part15-tcpip-webserver/include/mb.h
diff --git a/part15-tcpip/include/multicore.h b/part15-tcpip-webserver/include/multicore.h
similarity index 100%
rename from part15-tcpip/include/multicore.h
rename to part15-tcpip-webserver/include/multicore.h
diff --git a/part15-tcpip/include/spi.h b/part15-tcpip-webserver/include/spi.h
similarity index 100%
rename from part15-tcpip/include/spi.h
rename to part15-tcpip-webserver/include/spi.h
diff --git a/part15-tcpip/include/terminal.h b/part15-tcpip-webserver/include/terminal.h
similarity index 100%
rename from part15-tcpip/include/terminal.h
rename to part15-tcpip-webserver/include/terminal.h
diff --git a/part15-tcpip/kernel/arp.c b/part15-tcpip-webserver/kernel/kernel.c
similarity index 56%
rename from part15-tcpip/kernel/arp.c
rename to part15-tcpip-webserver/kernel/kernel.c
index 98c084f..420afa1 100644
--- a/part15-tcpip/kernel/arp.c
+++ b/part15-tcpip-webserver/kernel/kernel.c
@@ -1,17 +1,8 @@
-#include "../net/enc28j60.h"
#include "../include/fb.h"
+#include "../include/spi.h"
+#include "../net/enc28j60.h"
#include "../tcpip/ip_arp_udp_tcp.h"
-ENC_HandleTypeDef handle;
-
-// MAC address to be assigned to the ENC28J60
-
-unsigned char myMAC[6] = { 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee };
-
-// IP address to be assigned to the ENC28J60
-
-unsigned char deviceIP[4] = { 192, 168, 0, 66 };
-
// HELPER FUNCTIONS
void *memset(void *dest, unsigned char val, unsigned short len)
@@ -45,27 +36,31 @@ uint8_t memcmp(void *str1, void *str2, unsigned count)
return 0;
}
-void enc28j60PacketSend(unsigned short buflen, void *buffer) {
- if (ENC_RestoreTXBuffer(&handle, buflen) == 0) {
- ENC_WriteBuffer((unsigned char *) buffer, buflen);
- handle.transmitLength = buflen;
- ENC_Transmit(&handle);
- }
-}
-
-// MAIN FUNCTIONS
-
-void net_test(void)
+int strncmp(const char *s1, const char *s2, unsigned short n)
{
- while (1) {
- while (!ENC_GetReceivedFrame(&handle));
-
- uint16_t len = handle.RxFrameInfos.length;
- uint8_t *buffer = (uint8_t *)handle.RxFrameInfos.buffer;
- packetloop_arp_icmp_tcp(buffer, len);
- }
+ unsigned char u1, u2;
+
+ while (n-- > 0)
+ {
+ u1 = (unsigned char) *s1++;
+ u2 = (unsigned char) *s2++;
+ if (u1 != u2) return u1 - u2;
+ if (u1 == '\0') return 0;
+ }
+
+ return 0;
}
+// NETWORKING GLOBALS AND FUNCTIONS
+
+ENC_HandleTypeDef handle;
+
+// MAC address to be assigned to the ENC28J60
+unsigned char myMAC[6] = { 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee };
+
+// IP address to be assigned to the ENC28J60
+unsigned char deviceIP[4] = { 192, 168, 0, 66 };
+
void init_network(void)
{
handle.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
@@ -100,3 +95,61 @@ void init_network(void)
debugstr("done.");
debugcrlf();
}
+
+void enc28j60PacketSend(unsigned short buflen, void *buffer) {
+ if (ENC_RestoreTXBuffer(&handle, buflen) == 0) {
+ ENC_WriteBuffer((unsigned char *) buffer, buflen);
+ handle.transmitLength = buflen;
+ ENC_Transmit(&handle);
+ }
+}
+
+void serve(void)
+{
+ while (1) {
+ while (!ENC_GetReceivedFrame(&handle));
+
+ uint8_t *buf = (uint8_t *)handle.RxFrameInfos.buffer;
+ uint16_t len = handle.RxFrameInfos.length;
+ uint16_t dat_p = packetloop_arp_icmp_tcp(buf, len);
+
+ if (dat_p != 0) {
+ debugstr("Incoming web request... ");
+
+ if (strncmp("GET ", (char *)&(buf[dat_p]), 4) != 0) {
+ debugstr("not GET");
+ dat_p = fill_tcp_data(buf, 0, "HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\nERROR
");
+ } else {
+ if (strncmp("/ ", (char *)&(buf[dat_p+4]), 2) == 0) {
+ // just one web page in the "root directory" of the web server
+ debugstr("GET root");
+ dat_p = fill_tcp_data(buf, 0, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\nHello world!
");
+ } else {
+ // just one web page not in the "root directory" of the web server
+ debugstr("GET not root");
+ dat_p = fill_tcp_data(buf, 0, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\nGoodbye cruel world.
");
+ }
+ }
+
+ www_server_reply(buf, dat_p); // send web page data
+ debugcrlf();
+ }
+ }
+}
+
+// MAIN FUNCTION
+
+void main(void)
+{
+ fb_init();
+
+ // Init network and serve web pages
+
+ spi_init();
+ init_network();
+ serve();
+
+ // Catch us if we fall
+
+ while(1);
+}
diff --git a/part15-tcpip-webserver/kernel/kernel.h b/part15-tcpip-webserver/kernel/kernel.h
new file mode 100644
index 0000000..38ebe29
--- /dev/null
+++ b/part15-tcpip-webserver/kernel/kernel.h
@@ -0,0 +1,2 @@
+void enc28j60PacketSend(unsigned short buflen, void *buffer);
+void *memcpy(void *dest, const void *src, unsigned short len);
diff --git a/part15-tcpip/lib/fb.c b/part15-tcpip-webserver/lib/fb.c
similarity index 100%
rename from part15-tcpip/lib/fb.c
rename to part15-tcpip-webserver/lib/fb.c
diff --git a/part15-tcpip/lib/io.c b/part15-tcpip-webserver/lib/io.c
similarity index 88%
rename from part15-tcpip/lib/io.c
rename to part15-tcpip-webserver/lib/io.c
index 34a02aa..6a7b221 100644
--- a/part15-tcpip/lib/io.c
+++ b/part15-tcpip-webserver/lib/io.c
@@ -197,3 +197,33 @@ void uart_byte(unsigned char b) {
}
uart_writeByteBlockingActual(' ');
}
+
+// TIMER
+
+struct timer_regs {
+ volatile unsigned int control_status;
+ volatile unsigned int counter_lo;
+ volatile unsigned int counter_hi;
+ volatile unsigned int compare[4];
+};
+
+#define REGS_TIMER ((struct timer_regs *)(PERIPHERAL_BASE + 0x00003000))
+
+unsigned long HAL_GetTick(void) {
+ unsigned int hi = REGS_TIMER->counter_hi;
+ unsigned int lo = REGS_TIMER->counter_lo;
+
+ //double check hi value didn't change after setting it...
+ if (hi != REGS_TIMER->counter_hi) {
+ hi = REGS_TIMER->counter_hi;
+ lo = REGS_TIMER->counter_lo;
+ }
+
+ return ((unsigned long)hi << 32) | lo;
+}
+
+void HAL_Delay(unsigned int ms) {
+ unsigned long start = HAL_GetTick();
+
+ while(HAL_GetTick() < start + (ms * 1000));
+}
diff --git a/part15-tcpip/lib/mb.c b/part15-tcpip-webserver/lib/mb.c
similarity index 100%
rename from part15-tcpip/lib/mb.c
rename to part15-tcpip-webserver/lib/mb.c
diff --git a/part15-tcpip/lib/multicore.c b/part15-tcpip-webserver/lib/multicore.c
similarity index 100%
rename from part15-tcpip/lib/multicore.c
rename to part15-tcpip-webserver/lib/multicore.c
diff --git a/part15-tcpip/lib/spi.c b/part15-tcpip-webserver/lib/spi.c
similarity index 100%
rename from part15-tcpip/lib/spi.c
rename to part15-tcpip-webserver/lib/spi.c
diff --git a/part15-tcpip/net/enc28j60.c b/part15-tcpip-webserver/net/enc28j60.c
similarity index 96%
rename from part15-tcpip/net/enc28j60.c
rename to part15-tcpip-webserver/net/enc28j60.c
index 9547184..eab8a76 100644
--- a/part15-tcpip/net/enc28j60.c
+++ b/part15-tcpip-webserver/net/enc28j60.c
@@ -81,6 +81,7 @@ Errata 18 is implemented in lwip stack
/* Includes ------------------------------------------------------------------*/
#include "enc28j60.h"
#include "../include/fb.h"
+#include "../include/io.h"
/** @addtogroup BSP
* @{
@@ -1171,6 +1172,8 @@ void ENC_Transmit(ENC_HandleTypeDef *handle)
enc_waitwhilegreg(ENC_EIR, EIR_TXIF | EIR_TXERIF, 0);
#endif
+ HAL_Delay(20); // Added by AGB - fixes weird timing bug
+
/* Stop transmission */
enc_bfcgreg(ENC_ECON1, ECON1_TXRTS);
diff --git a/part15-tcpip/net/enc28j60.h b/part15-tcpip-webserver/net/enc28j60.h
similarity index 97%
rename from part15-tcpip/net/enc28j60.h
rename to part15-tcpip-webserver/net/enc28j60.h
index dc77865..e2c3504 100644
--- a/part15-tcpip/net/enc28j60.h
+++ b/part15-tcpip-webserver/net/enc28j60.h
@@ -61,11 +61,6 @@
#define MIN_FRAMELEN 64
#define MAX_FRAMELEN 1518
-
-/* External functions --------------------------------------------------------*/
-void HAL_Delay(volatile uint32_t Delay);
-uint32_t HAL_GetTick(void);
-
/* Callback functions *********************************************************/
/**
diff --git a/part15-tcpip/net/encspi.c b/part15-tcpip-webserver/net/encspi.c
similarity index 100%
rename from part15-tcpip/net/encspi.c
rename to part15-tcpip-webserver/net/encspi.c
diff --git a/part15-tcpip/tcpip/ip_arp_udp_tcp.c b/part15-tcpip-webserver/tcpip/ip_arp_udp_tcp.c
similarity index 91%
rename from part15-tcpip/tcpip/ip_arp_udp_tcp.c
rename to part15-tcpip-webserver/tcpip/ip_arp_udp_tcp.c
index bce8f00..b0af8be 100644
--- a/part15-tcpip/tcpip/ip_arp_udp_tcp.c
+++ b/part15-tcpip-webserver/tcpip/ip_arp_udp_tcp.c
@@ -2,7 +2,7 @@
* vim:sw=8:ts=8:si:et
* To use the above modeline in vim you must have "set modeline" in your .vimrc
*
- * Author: Guido Socher
+ * Author: Guido Socher
* Copyright:LGPL V2
* See http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html
*
@@ -16,27 +16,29 @@
* large pages.
*
*********************************************/
-
+#include "net.h"
+#include "../net/enc28j60.h"
+#include "../kernel/kernel.h"
+#include "../include/fb.h"
#include "ip_config.h"
-#include "ip_arp_udp_tcp.h"
// I use them to debug stuff:
#define LEDOFF PORTB|=(1<>8;
buf[IP_TOTLEN_L_P]=j& 0xff;
@@ -597,10 +587,10 @@ void make_tcp_synack_from_syn(uint8_t *buf)
// put an inital seq number
buf[TCP_SEQ_H_P+0]= 0;
buf[TCP_SEQ_H_P+1]= 0;
- // we step only the second byte, this allows us to send packts
+ // we step only the second byte, this allows us to send packts
// with 255 bytes, 512 or 765 (step by 3) without generating
// overlapping numbers.
- buf[TCP_SEQ_H_P+2]= seqnum;
+ buf[TCP_SEQ_H_P+2]= seqnum;
buf[TCP_SEQ_H_P+3]= 0;
// step the inititial seq num by something we will not use
// during this tcp session:
@@ -629,7 +619,7 @@ void make_tcp_synack_from_syn(uint8_t *buf)
// you must have initialized info_data_len at some time before calling this function
//
-// This info_data_len initialisation is done automatically if you call
+// This info_data_len initialisation is done automatically if you call
// packetloop_icmp_tcp(buf,enc28j60PacketReceive(BUFFER_SIZE, buf));
// and test the return value for non zero.
//
@@ -644,28 +634,27 @@ void www_server_reply(uint8_t *buf,uint16_t dlen)
// This code requires that we send only one data packet
// because we keep no state information. We must therefore set
// the fin here:
- buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V;//|TCP_FLAGS_FIN_V;
+ buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V;
make_tcp_ack_with_data_noflags(buf,dlen); // send data
}
#endif // WWW_server
-#if defined (ALL_clients)
+#if defined (ALL_clients) || defined (GRATARP) || defined (WOL_client)
// fill buffer with a prog-mem string
-void fill_buf_p(uint8_t *buf,uint16_t len, const char *progmem_s)
+void fill_buf_p(uint8_t *buf,uint16_t len, const char *progmem_str_p)
{
- uint8_t i=0;
-
while (len){
- *buf= progmem_s[i];
+ *buf= pgm_read_byte(progmem_str_p);
buf++;
- len--; i++;
+ progmem_str_p++;
+ len--;
}
}
-#endif
+#endif
#ifdef PING_client
-// icmp echo, matchpat is a pattern that has to be sent back by the
+// icmp echo, matchpat is a pattern that has to be sent back by the
// host answering the ping.
// The ping is sent to destip and mac dstmac
void client_icmp_request(uint8_t *buf,uint8_t *destip,uint8_t *dstmac)
@@ -697,14 +686,14 @@ void client_icmp_request(uint8_t *buf,uint8_t *destip,uint8_t *dstmac)
buf[ICMP_CHECKSUM_H_P]=0;
buf[ICMP_CHECKSUM_L_P]=0;
// a possibly unique id of this host:
- buf[ICMP_IDENT_H_P]=5; // some number
+ buf[ICMP_IDENT_H_P]=5; // some number
buf[ICMP_IDENT_L_P]=ipaddr[3]; // last byte of my IP
//
buf[ICMP_IDENT_L_P+1]=0; // seq number, high byte
buf[ICMP_IDENT_L_P+2]=1; // seq number, low byte, we send only 1 ping at a time
// copy the data:
i=0;
- while(i<56){
+ while(i<56){
buf[ICMP_DATA_P+i]=PINGPATTERN;
i++;
}
@@ -725,6 +714,7 @@ void client_ntp_request(uint8_t *buf,uint8_t *ntpip,uint8_t srcport,uint8_t *dst
{
uint8_t i=0;
uint16_t ck;
+ if (!enc28j60linkup())return;
//
while(i<6){
buf[ETH_DST_MAC +i]=dstmac[i]; // gw mac in local lan or host mac
@@ -756,7 +746,7 @@ void client_ntp_request(uint8_t *buf,uint8_t *ntpip,uint8_t srcport,uint8_t *dst
// copy the data:
i=0;
// most fields are zero, here we zero everything and fill later
- while(i<48){
+ while(i<48){
buf[UDP_DATA_P+i]=0;
i++;
}
@@ -772,7 +762,7 @@ void client_ntp_request(uint8_t *buf,uint8_t *ntpip,uint8_t srcport,uint8_t *dst
// return 1 on sucessful processing of answer
uint8_t client_ntp_process_answer(uint8_t *buf,uint32_t *time,uint8_t dstport_l){
if (dstport_l){
- if (buf[UDP_DST_PORT_L_P]!=dstport_l){
+ if (buf[UDP_DST_PORT_L_P]!=dstport_l){
return(0);
}
}
@@ -787,9 +777,9 @@ uint8_t client_ntp_process_answer(uint8_t *buf,uint32_t *time,uint8_t dstport_l)
#endif
#ifdef UDP_client
-// -------------------- send a spontanious UDP packet to a server
+// -------------------- send a spontanious UDP packet to a server
// There are two ways of using this:
-// 1) you call send_udp_prepare, you fill the data yourself into buf starting at buf[UDP_DATA_P],
+// 1) you call send_udp_prepare, you fill the data yourself into buf starting at buf[UDP_DATA_P],
// you send the packet by calling send_udp_transmit
//
// 2) You just allocate a large enough buffer for you data and you call send_udp and nothing else
@@ -820,9 +810,9 @@ void send_udp_prepare(uint8_t *buf,uint16_t sport, const uint8_t *dip, uint16_t
}
// done in transmit: fill_ip_hdr_checksum(buf);
buf[UDP_DST_PORT_H_P]=(dport>>8);
- buf[UDP_DST_PORT_L_P]=0xff&dport;
+ buf[UDP_DST_PORT_L_P]=0xff&dport;
buf[UDP_SRC_PORT_H_P]=(sport>>8);
- buf[UDP_SRC_PORT_L_P]=sport&0xff;
+ buf[UDP_SRC_PORT_L_P]=sport&0xff;
buf[UDP_LEN_H_P]=0;
// done in transmit: buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen;
// zero the checksum
@@ -912,7 +902,7 @@ void send_wol(uint8_t *buf,uint8_t *wolmac)
buf[UDP_CHECKSUM_L_P]=0;
// copy the data (102 bytes):
i=0;
- while(i<6){
+ while(i<6){
buf[UDP_DATA_P+i]=0xff;
i++;
}
@@ -920,7 +910,7 @@ void send_wol(uint8_t *buf,uint8_t *wolmac)
pos=UDP_DATA_P+6;
while (m<16){
i=0;
- while(i<6){
+ while(i<6){
buf[pos]=wolmac[i];
i++;
pos++;
@@ -960,7 +950,7 @@ uint8_t gratutious_arp(uint8_t *buf)
buf[ETH_TYPE_L_P] = ETHTYPE_ARP_L_V;
// arp request and reply are the same execept for
// the opcode:
- fill_buf_p(&buf[ETH_ARP_P],8,arpreqhdr);
+ fill_buf_p(&buf[ETH_ARP_P],8,arpreqhdr);
//buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V; // reply
i=0;
while(i<6){
@@ -982,8 +972,8 @@ uint8_t gratutious_arp(uint8_t *buf)
#if ARP_MAC_resolver_client
// make a arp request
-// Note: you must have initialized the stack with
-// init_udp_or_www_server or client_ifconfig
+// Note: you must have initialized the stack with
+// init_udp_or_www_server or client_ifconfig
// before you can use this function
void client_arp_whohas(uint8_t *buf,uint8_t *ip_we_search)
{
@@ -1025,8 +1015,8 @@ uint8_t get_mac_with_arp_wait(void)
// reference_number is something that is just returned in the callback
// to make matching and waiting for a given ip/mac address pair easier
-// Note: you must have initialized the stack with
-// init_udp_or_www_server or client_ifconfig
+// Note: you must have initialized the stack with
+// init_udp_or_www_server or client_ifconfig
// before you can use this function
void get_mac_with_arp(uint8_t *ip, uint8_t reference_number,void (*arp_result_callback)(uint8_t *ip,uint8_t reference_number,uint8_t *mac))
{
@@ -1039,7 +1029,7 @@ void get_mac_with_arp(uint8_t *ip, uint8_t reference_number,void (*arp_result_ca
i++;
}
}
-#endif
+#endif
#if defined (TCP_client)
// Make a tcp syn packet
@@ -1076,12 +1066,12 @@ void tcp_client_syn(uint8_t *buf,uint8_t srcport,uint16_t dstport)
buf[TCP_SEQ_H_P+i]=0;
i++;
}
- // -- header ready
+ // -- header ready
// put inital seq number
- // we step only the second byte, this allows us to send packts
+ // we step only the second byte, this allows us to send packts
// with 255 bytes 512 (if we step the initial seqnum by 2)
// or 765 (step by 3)
- buf[TCP_SEQ_H_P+2]= seqnum;
+ buf[TCP_SEQ_H_P+2]= seqnum;
// step the inititial seq num by something we will not use
// during this tcp session:
seqnum+=3;
@@ -1110,7 +1100,7 @@ void tcp_client_syn(uint8_t *buf,uint8_t srcport,uint16_t dstport)
}
#endif // TCP_client
-#if defined (TCP_client)
+#if defined (TCP_client)
// This is how to use the tcp client:
//
// Declare a callback function to get the result (tcp data from the server):
@@ -1126,16 +1116,16 @@ void tcp_client_syn(uint8_t *buf,uint8_t srcport,uint16_t dstport)
// output such that this will be the only packet.
//
// close_tcp_session=1 means close the session now. close_tcp_session=0
-// read all data and leave it to the other side to close it.
+// read all data and leave it to the other side to close it.
// If you connect to a web server then you want close_tcp_session=0.
// If you connect to a modbus/tcp equipment then you want close_tcp_session=1
//
-// Declare a callback function to be called in order to fill in the
+// Declare a callback function to be called in order to fill in the
//
// request (tcp data sent to the server):
// uint16_t your_client_tcp_datafill_callback(uint8_t fd){...your code;return(len_of_data_filled_in);}
//
-// Now call:
+// Now call:
// fd=client_tcp_req(&your_client_tcp_result_callback,&your_client_tcp_datafill_callback,portnumber);
//
// fd is a file descriptor like number that you get back in the fill and result
@@ -1171,7 +1161,7 @@ uint8_t client_tcp_req(uint8_t (*result_callback)(uint8_t fd,uint8_t statuscode,
}
#endif // TCP_client
-#if defined (WWW_client)
+#if defined (WWW_client)
uint16_t www_client_internal_datafill_callback(uint8_t fd){
char strbuf[5];
uint16_t len=0;
@@ -1179,27 +1169,27 @@ uint16_t www_client_internal_datafill_callback(uint8_t fd){
if (browsertype==0){
// GET
len=fill_tcp_data_p(bufptr,0,PSTR("GET "));
- len=fill_tcp_data_p(bufptr,len,client_urlbuf);
+ len=fill_tcp_data_p(bufptr,len,client_urlbuf_p);
len=fill_tcp_data(bufptr,len,client_urlbuf_var);
// I would prefer http/1.0 but there is a funny
// bug in some apache webservers which causes
// them to send two packets (fragmented PDU)
// if we don't use HTTP/1.1 + Connection: close
len=fill_tcp_data_p(bufptr,len,PSTR(" HTTP/1.1\r\nHost: "));
- len=fill_tcp_data(bufptr,len,client_hoststr);
- len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.1\r\nAccept: text/html\r\nConnection: close\r\n\r\n"));
+ len=fill_tcp_data_p(bufptr,len,client_hoststr);
+ len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.1\r\nAccept: text/html\r\n\r\n"));
}else{
// POST
len=fill_tcp_data_p(bufptr,0,PSTR("POST "));
- len=fill_tcp_data_p(bufptr,len,client_urlbuf);
+ len=fill_tcp_data_p(bufptr,len,client_urlbuf_p);
len=fill_tcp_data(bufptr,len,client_urlbuf_var);
len=fill_tcp_data_p(bufptr,len,PSTR(" HTTP/1.1\r\nHost: "));
- len=fill_tcp_data(bufptr,len,client_hoststr);
- if (client_additionalheaderline){
+ len=fill_tcp_data_p(bufptr,len,client_hoststr);
+ if (client_additionalheaderline_p){
len=fill_tcp_data_p(bufptr,len,PSTR("\r\n"));
- len=fill_tcp_data_p(bufptr,len,client_additionalheaderline);
+ len=fill_tcp_data_p(bufptr,len,client_additionalheaderline_p);
}
- len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.1\r\nAccept: */*\r\nConnection: close\r\n"));
+ len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.1\r\nAccept: */*\r\n"));
len=fill_tcp_data_p(bufptr,len,PSTR("Content-Length: "));
itoa(strlen(client_postval),strbuf,10);
len=fill_tcp_data(bufptr,len,strbuf);
@@ -1213,7 +1203,7 @@ uint16_t www_client_internal_datafill_callback(uint8_t fd){
uint8_t www_client_internal_result_callback(uint8_t fd, uint8_t statuscode, uint16_t datapos, uint16_t len_of_data){
uint16_t web_statuscode=0; // tcp status is OK but we need to check http layer too
- uint8_t i=0;
+ uint8_t i=0;
if (fd!=www_fd){
(*client_browser_callback)(500,0,0);
return(0);
@@ -1222,7 +1212,7 @@ uint8_t www_client_internal_result_callback(uint8_t fd, uint8_t statuscode, uint
// we might have a http status code
// http status codes are 3digit numbers as ascii text. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
// The buffer would look like this: HTTP/1.1 200 OK\r\n
- // web_statuscode=0 means we got a corrupted answer
+ // web_statuscode=0 means we got a corrupted answer
if (client_browser_callback){
if (isblank(bufptr[datapos+8]) && isdigit(bufptr[datapos+9])&& isdigit(bufptr[datapos+11])){ // e.g 200 OK, a status code has 3 digits from datapos+9 to datapos+11, copy over the web/http status code to web_statuscode:
while(i<2){
@@ -1260,10 +1250,10 @@ uint8_t www_client_internal_result_callback(uint8_t fd, uint8_t statuscode, uint
// The string buffers to which urlbuf_varpart and hoststr are pointing
// must not be changed until the callback is executed.
//
-void client_browse_url(const prog_char *urlbuf,const char *urlbuf_varpart,const char *hoststr,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac)
+void client_browse_url(const char *urlbuf_p,char *urlbuf_varpart,const char *hoststr,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac)
{
if (!enc28j60linkup())return;
- client_urlbuf=urlbuf;
+ client_urlbuf_p=urlbuf_p;
client_urlbuf_var=urlbuf_varpart;
client_hoststr=hoststr;
browsertype=0;
@@ -1272,19 +1262,19 @@ void client_browse_url(const prog_char *urlbuf,const char *urlbuf_varpart,const
}
// client web browser using http POST operation:
-// additionalheaderline must be set to NULL if not used.
+// additionalheaderline_p must be set to NULL if not used.
// The string buffers to which urlbuf_varpart and hoststr are pointing
// must not be changed until the callback is executed.
-// postval is a string buffer which can only be de-allocated by the caller
+// postval is a string buffer which can only be de-allocated by the caller
// when the post operation was really done (e.g when callback was executed).
// postval must be urlencoded.
-void client_http_post(const prog_char *urlbuf, const char *urlbuf_varpart,const char *hoststr, const prog_char *additionalheaderline,char *postval,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac)
+void client_http_post(const char *urlbuf_p, char *urlbuf_varpart,const char *hoststr, const char *additionalheaderline_p,char *postval,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac)
{
if (!enc28j60linkup())return;
- client_urlbuf=urlbuf;
+ client_urlbuf_p=urlbuf_p;
client_hoststr=hoststr;
client_urlbuf_var=urlbuf_varpart;
- client_additionalheaderline=additionalheaderline;
+ client_additionalheaderline_p=additionalheaderline_p;
client_postval=postval;
browsertype=1;
client_browser_callback=callback;
@@ -1314,18 +1304,18 @@ uint8_t packetloop_icmp_checkreply(uint8_t *buf,uint8_t *ip_monitoredhost)
#endif // PING_client
-// return 0 to just continue in the packet loop and return the position
+// return 0 to just continue in the packet loop and return the position
// of the tcp data if there is tcp data part
uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
{
-// uint16_t len;
+ uint16_t len;
#if defined (TCP_client)
uint8_t send_fin=0;
uint16_t tcpstart;
uint16_t save_len;
#endif
#ifdef ARP_MAC_resolver_client
- //plen will be unequal to zero if there is a valid
+ //plen will be unequal to zero if there is a valid
// packet (without crc error):
if(plen==0){
if (arpip_state == (WGW_ACCEPT_ARP_REPLY|WGW_INITIAL_ARP) && arp_delaycnt==0 ){
@@ -1352,17 +1342,17 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
}
#endif // ARP_MAC_resolver_client
// arp is broadcast if unknown but a host may also
- // verify the mac address by sending it to
+ // verify the mac address by sending it to
// a unicast address.
if(eth_type_is_arp_and_my_ip(buf,plen)){
if (buf[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REQ_L_V){
- // is it an arp request
+ // is it an arp request
make_arp_answer_from_request(buf);
}
#ifdef ARP_MAC_resolver_client
if ((arpip_state & WGW_ACCEPT_ARP_REPLY) && (buf[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REPLY_L_V)){
- // is it an arp reply
- if (memcmp(&buf[ETH_ARP_SRC_IP_P],arpip,4)!=0) return(0); // not an arp reply for the IP we were searching
+ // is it an arp reply
+ if (memcmp(&buf[ETH_ARP_SRC_IP_P],arpip,4)!=0) return(0); // not an arp reply for the IP we were searching
(*client_arp_result_callback)(arpip,arp_reference_number,buf+ETH_ARP_SRC_MAC_P);
arpip_state=WGW_HAVE_MAC;
}
@@ -1379,13 +1369,13 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
(*icmp_callback)(&(buf[IP_SRC_P]));
}
// a ping packet, let's send pong
- debugstr("Sending ping reply...");
- debugcrlf();
+ debugstr("Replying to ping..."); debugcrlf();
make_echo_reply_from_request(buf,plen);
return(0);
}
- if (plen<54 && buf[IP_PROTO_P]!=IP_PROTO_TCP_V ){
- // smaller than the smallest TCP packet and not tcp port
+ // this is an important check to avoid working on the wrong packets:
+ if (plen<54 || buf[IP_PROTO_P]!=IP_PROTO_TCP_V ){
+ // smaller than the smallest TCP packet (TCP packet with no options section) or not tcp port
return(0);
}
#if defined (TCP_client)
@@ -1393,7 +1383,7 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
if ( buf[TCP_DST_PORT_H_P]==TCPCLIENT_SRC_PORT_H){
#if defined (WWW_client)
// workaround to pass pointer to www_client_internal..
- bufptr=buf;
+ bufptr=buf;
#endif // WWW_client
if (check_ip_message_is_from(buf,tcp_otherside_ip)==0){
return(0);
@@ -1404,7 +1394,7 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
// parameters in client_tcp_result_callback: fd, status, buf_start, len
(*client_tcp_result_callback)((buf[TCP_DST_PORT_L_P]>>5)&0x7,3,0,0);
}
- tcp_client_state=5;
+ tcp_client_state=6;
return(0);
}
len=get_tcp_data_len(buf);
@@ -1418,7 +1408,7 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
// still have a valid tcp-ack in the buffer. In other words
// you have just called make_tcp_ack_from_any(buf,0).
if (client_tcp_datafill_callback){
- // in this case it is src port because the above
+ // in this case it is src port because the above
// make_tcp_ack_from_any swaps the dst and src port:
len=(*client_tcp_datafill_callback)((buf[TCP_SRC_PORT_L_P]>>5)&0x7);
}else{
@@ -1447,7 +1437,7 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
}
// in tcp_client_state==3 we will normally first get an empty
// ack-packet and then a ack-packet with data.
- if (tcp_client_state==3 && len>0){
+ if (tcp_client_state==3 && len>0){
// our first real data packet
tcp_client_state=4;
// return the data we received
@@ -1470,11 +1460,25 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
}
}
if(tcp_client_state==5){
- // no more ack
+ // we get one more final ack to our fin-ack:
+ if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
+ tcp_client_state=6; // in state 6 communication should be finished
+ }
+ return(0);
+ }
+ if(tcp_client_state==6){
+ // something wrong, can't deal with this, reset the connection
+ len++;
+ if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V) len=0; // if packet was an ack then do not step the ack number
+ make_tcp_ack_from_any(buf,len,TCP_FLAGS_RST_V);
+ // just a single reset, do not repeat if more messages:
+ tcp_client_state=7;
return(0);
}
if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
- make_tcp_ack_from_any(buf,len+1,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
+ // this normally a fin ack message but it could be
+ // any message with fin we answer with fin-ack:
+ make_tcp_ack_from_any(buf,len+1,TCP_FLAGS_FIN_V);
tcp_client_state=5; // connection terminated
return(0);
}
@@ -1490,7 +1494,7 @@ uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
//
#ifdef WWW_server
// tcp port web server start
- if (buf[IP_PROTO_P]==IP_PROTO_TCP_V && buf[TCP_DST_PORT_H_P]==wwwport_h && buf[TCP_DST_PORT_L_P]==wwwport_l){
+ if (buf[TCP_DST_PORT_H_P]==wwwport_h && buf[TCP_DST_PORT_L_P]==wwwport_l){
if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V){
make_tcp_synack_from_syn(buf);
// make_tcp_synack_from_syn does already send the syn,ack
diff --git a/part15-tcpip/tcpip/ip_arp_udp_tcp.h b/part15-tcpip-webserver/tcpip/ip_arp_udp_tcp.h
similarity index 99%
rename from part15-tcpip/tcpip/ip_arp_udp_tcp.h
rename to part15-tcpip-webserver/tcpip/ip_arp_udp_tcp.h
index 7c20b4f..e4b2e57 100644
--- a/part15-tcpip/tcpip/ip_arp_udp_tcp.h
+++ b/part15-tcpip-webserver/tcpip/ip_arp_udp_tcp.h
@@ -12,10 +12,6 @@
#ifndef IP_ARP_UDP_TCP_H
#define IP_ARP_UDP_TCP_H 1
-#include "net.h"
-#include "../net/enc28j60.h"
-#include "../kernel/kernel.h"
-#include "../include/fb.h"
#include "ip_config.h"
// set my own mac address:
diff --git a/part15-tcpip/tcpip/ip_config.h b/part15-tcpip-webserver/tcpip/ip_config.h
similarity index 98%
rename from part15-tcpip/tcpip/ip_config.h
rename to part15-tcpip-webserver/tcpip/ip_config.h
index 22c108b..b043ee9 100644
--- a/part15-tcpip/tcpip/ip_config.h
+++ b/part15-tcpip-webserver/tcpip/ip_config.h
@@ -22,7 +22,7 @@
// a server answering to UDP messages
#define UDP_server
// a web server
-#undef WWW_server
+#define WWW_server
// to send out a ping:
#undef PING_client
diff --git a/part15-tcpip/tcpip/net.h b/part15-tcpip-webserver/tcpip/net.h
similarity index 100%
rename from part15-tcpip/tcpip/net.h
rename to part15-tcpip-webserver/tcpip/net.h
diff --git a/part15-tcpip/README.md b/part15-tcpip/README.md
deleted file mode 100644
index f6065ff..0000000
--- a/part15-tcpip/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-Writing a "bare metal" operating system for Raspberry Pi 4 (Part 15)
-====================================================================
-
-Adding a TCP/IP stack
----------------------
-Having achieved "proof of life" from our Ethernet module in _part14-spi-ethernet_, you're doubtless wondering how to go from there to serving web pages, posting tweets on Twitter or perhaps even just simply responding to a ping!
-
-This is where you'll need a fully-fledged TCP/IP stack that goes way beyond handcrafted ARPs, implementing many more protocols to achieve efficient bi-directional communication.
-
-In this part we make use of some code from Guido Socher of [tuxgraphics.org](http://tuxgraphics.org/), designed to be a lightweight TCP/IP stack for embedded devices. I chose this because it was super simple to get working (or "port"), but you might want to look at [LwIP](https://en.wikipedia.org/wiki/LwIP) if you need something more advanced.
-
-The code
---------
-Most of the new code is in the _tcpip/_ subdirectory. I actually came across it in [this Github repository](https://github.com/ussserrr/maglev-ti-rtos) and, again, made only a very few cosmetic changes (`diff` is your friend!).
-
-It did require me to expose the `strlen()` function we implemented in _lib/fb.c_, so that's added to _include/fb.h_. Similarly, we expose the `memcpy()` function we implemented in _kernel/kernel.c_, so that's added to _kernel/kernel.h_.
-
-I also needed a single function that tells the ENC to send a packet. Nothing new here, just different packaging:
-
-```c
-void enc28j60PacketSend(unsigned short buflen, void *buffer) {
- if (ENC_RestoreTXBuffer(&handle, buflen) == 0) {
- ENC_WriteBuffer((unsigned char *) buffer, buflen);
- handle.transmitLength = buflen;
- ENC_Transmit(&handle);
- }
-}
-```
-
-This was also added to _kernel/kernel.h_. Finally, _kernel/kernel.c_ now calls a function called `net_test()` instead of our original `arp_test()`.
-
-The changes to _arp.c_
-----------------------
-We initialise the network card in exactly the same way but, when we're done, we call this function in Guido's code:
-
-```c
-init_udp_or_www_server(myMAC, deviceIP);
-```
-
-This tells the TCP/IP library who we are, so we're all on the same page!
-
-Finally, and aside from a little cleanup, the major change is the new `net_test()` function:
-
-```c
-void net_test(void)
-{
- while (1) {
- while (!ENC_GetReceivedFrame(&handle));
-
- uint16_t len = handle.RxFrameInfos.length;
- uint8_t *buffer = (uint8_t *)handle.RxFrameInfos.buffer;
- packetloop_arp_icmp_tcp(buffer, len);
- }
-}
-```
-
-This is an infinite loop which waits for an incoming packet and then simply passes it to Guido's `packetloop_arp_icmp_tcp()` function. This function implements some useful things, like responding to pings. I modified the routine to print a message to the screen when it sends a "pong" (look from line 1381 of _tcpip/ip_arp_udp_tcp.c_), so we can see when it's in action!
-
-_Imagine my excitement when I built, ran and could ping my RPi4 at 192.168.0.66 and get a response to both my laptop and my iPhone!_
-
-I recommend reading [this page](http://tuxgraphics.org/electronics/200905/embedded-tcp-ip-stack.shtml) to give you some ideas about what else you might achieve with Guido's library...
-
-![Pinging from my iPhone](images/15-tcpip-pinging.jpg)
diff --git a/part15-tcpip/kernel/irq.c b/part15-tcpip/kernel/irq.c
deleted file mode 100644
index 3ab82d1..0000000
--- a/part15-tcpip/kernel/irq.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "kernel.h"
-
-void enable_interrupt_controller() {
- REGS_IRQ->irq0_enable_0 = SYS_TIMER_IRQ_1 | SYS_TIMER_IRQ_3;
-}
-
-void disable_interrupt_controller() {
- REGS_IRQ->irq0_enable_0 = 0;
-}
-
-void handle_irq() {
- unsigned int irq = REGS_IRQ->irq0_pending_0;
-
- while(irq) {
- if (irq & SYS_TIMER_IRQ_1) {
- irq &= ~SYS_TIMER_IRQ_1;
-
- handle_timer_1();
- }
-
- if (irq & SYS_TIMER_IRQ_3) {
- irq &= ~SYS_TIMER_IRQ_3;
-
- handle_timer_3();
- }
- }
-}
diff --git a/part15-tcpip/kernel/irqentry.S b/part15-tcpip/kernel/irqentry.S
deleted file mode 100644
index d24ae00..0000000
--- a/part15-tcpip/kernel/irqentry.S
+++ /dev/null
@@ -1,160 +0,0 @@
-#define SYNC_INVALID_EL1t 0
-#define IRQ_INVALID_EL1t 1
-#define FIQ_INVALID_EL1t 2
-#define ERROR_INVALID_EL1t 3
-
-#define SYNC_INVALID_EL1h 4
-#define IRQ_INVALID_EL1h 5
-#define FIQ_INVALID_EL1h 6
-#define ERROR_INVALID_EL1h 7
-
-#define SYNC_INVALID_EL0_64 8
-#define IRQ_INVALID_EL0_64 9
-#define FIQ_INVALID_EL0_64 10
-#define ERROR_INVALID_EL0_64 11
-
-#define SYNC_INVALID_EL0_32 12
-#define IRQ_INVALID_EL0_32 13
-#define FIQ_INVALID_EL0_32 14
-#define ERROR_INVALID_EL0_32 15
-
-//stack frame size
-#define S_FRAME_SIZE 256
-
-.macro kernel_entry
- sub sp, sp, #S_FRAME_SIZE
- stp x0, x1, [sp, #16 * 0]
- stp x2, x3, [sp, #16 * 1]
- stp x4, x5, [sp, #16 * 2]
- stp x6, x7, [sp, #16 * 3]
- stp x8, x9, [sp, #16 * 4]
- stp x10, x11, [sp, #16 * 5]
- stp x12, x13, [sp, #16 * 6]
- stp x14, x15, [sp, #16 * 7]
- stp x16, x17, [sp, #16 * 8]
- stp x18, x19, [sp, #16 * 9]
- stp x20, x21, [sp, #16 * 10]
- stp x22, x23, [sp, #16 * 11]
- stp x24, x25, [sp, #16 * 12]
- stp x26, x27, [sp, #16 * 13]
- stp x28, x29, [sp, #16 * 14]
- str x30, [sp, #16 * 15]
-.endm
-
-.macro kernel_exit
- ldp x0, x1, [sp, #16 * 0]
- ldp x2, x3, [sp, #16 * 1]
- ldp x4, x5, [sp, #16 * 2]
- ldp x6, x7, [sp, #16 * 3]
- ldp x8, x9, [sp, #16 * 4]
- ldp x10, x11, [sp, #16 * 5]
- ldp x12, x13, [sp, #16 * 6]
- ldp x14, x15, [sp, #16 * 7]
- ldp x16, x17, [sp, #16 * 8]
- ldp x18, x19, [sp, #16 * 9]
- ldp x20, x21, [sp, #16 * 10]
- ldp x22, x23, [sp, #16 * 11]
- ldp x24, x25, [sp, #16 * 12]
- ldp x26, x27, [sp, #16 * 13]
- ldp x28, x29, [sp, #16 * 14]
- ldr x30, [sp, #16 * 15]
- add sp, sp, #S_FRAME_SIZE
- eret
-.endm
-
-.macro handle_invalid_entry type
- kernel_entry
- mov x0, #\type
- mrs x1, esr_el1
- mrs x2, elr_el1
-
- // We could pass this to a function to print an error here
- // e.g. bl show_invalid_entry_message
- //
- // For now we'll just hang
-
- b err_hang
-.endm
-
-.macro ventry label
-.align 7
- b \label
-.endm
-
-//Exception vectors table
-.align 11
-.globl vectors
-vectors:
- ventry sync_invalid_el1t // Synchronous EL1t
- ventry irq_invalid_el1t // IRQ EL1t
- ventry fiq_invalid_el1t // FIQ EL1t
- ventry error_invalid_el1t // Error EL1t
-
- ventry sync_invalid_el1h // Synchronous EL1h
- ventry handle_el1_irq // IRQ EL1h
- ventry fiq_invalid_el1h // FIQ EL1h
- ventry error_invalid_el1h // Error EL1h
-
- ventry sync_invalid_el0_64 // Synchronous 64-bit EL0
- ventry irq_invalid_el0_64 // IRQ 64-bit EL0
- ventry fiq_invalid_el0_64 // FIQ 64-bit EL0
- ventry error_invalid_el0_64 // Error 64-bit EL0
-
- ventry sync_invalid_el0_32 // Synchronous 32-bit EL0
- ventry irq_invalid_el0_32 // IRQ 32-bit EL0
- ventry fiq_invalid_el0_32 // FIQ 32-bit EL0
- ventry error_invalid_el0_32 // Error 32-bit EL0
-
-
-sync_invalid_el1t:
- handle_invalid_entry SYNC_INVALID_EL1t
-
-irq_invalid_el1t:
- handle_invalid_entry IRQ_INVALID_EL1t
-
-fiq_invalid_el1t:
- handle_invalid_entry FIQ_INVALID_EL1t
-
-error_invalid_el1t:
- handle_invalid_entry ERROR_INVALID_EL1t
-
-sync_invalid_el1h:
- handle_invalid_entry SYNC_INVALID_EL1h
-
-fiq_invalid_el1h:
- handle_invalid_entry FIQ_INVALID_EL1h
-
-error_invalid_el1h:
- handle_invalid_entry ERROR_INVALID_EL1h
-
-sync_invalid_el0_64:
- handle_invalid_entry SYNC_INVALID_EL0_64
-
-irq_invalid_el0_64:
- handle_invalid_entry IRQ_INVALID_EL0_64
-
-fiq_invalid_el0_64:
- handle_invalid_entry FIQ_INVALID_EL0_64
-
-error_invalid_el0_64:
- handle_invalid_entry ERROR_INVALID_EL0_64
-
-sync_invalid_el0_32:
- handle_invalid_entry SYNC_INVALID_EL0_32
-
-irq_invalid_el0_32:
- handle_invalid_entry IRQ_INVALID_EL0_32
-
-fiq_invalid_el0_32:
- handle_invalid_entry FIQ_INVALID_EL0_32
-
-error_invalid_el0_32:
- handle_invalid_entry ERROR_INVALID_EL0_32
-
-handle_el1_irq:
- kernel_entry
- bl handle_irq
- kernel_exit
-
-.globl err_hang
-err_hang: b err_hang
diff --git a/part15-tcpip/kernel/kernel.c b/part15-tcpip/kernel/kernel.c
deleted file mode 100644
index 24e4ce9..0000000
--- a/part15-tcpip/kernel/kernel.c
+++ /dev/null
@@ -1,167 +0,0 @@
-#include "../include/fb.h"
-#include "../include/io.h"
-#include "../include/spi.h"
-#include "../include/multicore.h"
-#include "kernel.h"
-
-void initProgress(void)
-{
- drawRect(0, 0, 301, 50, 0x0f, 0);
- drawString(309, 21, "Core 0", 0x0f, 1);
-
- drawRect(0, 60, 301, 110, 0x0f, 0);
- drawString(309, 81, "Core 1", 0x0f, 1);
-
- drawRect(0, 120, 301, 170, 0x0f, 0);
- drawString(309, 141, "Timer 1", 0x0f, 1);
-
- drawRect(0, 180, 301, 230, 0x0f, 0);
- drawString(309, 201, "Timer 3", 0x0f, 1);
-}
-
-void drawProgress(unsigned int core, unsigned int val) {
- unsigned char col = (core + 1) + ((core + 1) << 4);
-
- // val should be 0-100
- if (val == 0) drawRect(1, (60 * core) + 1, 300, (60 * core) + 49, 0x00, 1);
- if (val > 0) drawRect(1, (60 * core) + 1, (val * 3), (60 * core) + 49, col, 1);
-}
-
-void core3_main(void) {
- clear_core3(); // Only run once
-
- // Test the network card
-
- spi_init();
- init_network();
- net_test();
-
- while(1);
-}
-
-void core0_main(void)
-{
- unsigned int core0_val = 0;
-
- while (core0_val <= 100) {
- wait_msec(0x100000);
- drawProgress(0, core0_val);
- core0_val++;
- }
-
- debugstr("Core 0 done.");
- debugcrlf();
-}
-
-void core1_main(void)
-{
- unsigned int core1_val = 0;
-
- clear_core1(); // Only run once
-
- while (core1_val <= 100) {
- wait_msec(0x3FFFF);
- drawProgress(1, core1_val);
- core1_val++;
- }
-
- debugstr("Core 1 done.");
- debugcrlf();
-
- while(1);
-}
-
-// TIMER FUNCTIONS
-
-const unsigned int timer1_int = CLOCKHZ;
-const unsigned int timer3_int = CLOCKHZ / 4;
-unsigned int timer1_val = 0;
-unsigned int timer3_val = 0;
-
-void timer_init() {
- timer1_val = REGS_TIMER->counter_lo;
- timer1_val += timer1_int;
- REGS_TIMER->compare[1] = timer1_val;
-
- timer3_val = REGS_TIMER->counter_lo;
- timer3_val += timer3_int;
- REGS_TIMER->compare[3] = timer3_val;
-}
-
-void handle_timer_1() {
- timer1_val += timer1_int;
- REGS_TIMER->compare[1] = timer1_val;
- REGS_TIMER->control_status |= SYS_TIMER_IRQ_1;
-
- unsigned int progval = timer1_val / timer1_int;
- if (progval <= 100) {
- drawProgress(2, progval);
- } else {
- debugstr("Timer 1 done.");
- debugcrlf();
- }
-}
-
-void handle_timer_3() {
- timer3_val += timer3_int;
- REGS_TIMER->compare[3] = timer3_val;
- REGS_TIMER->control_status |= SYS_TIMER_IRQ_3;
-
- unsigned int progval = timer3_val / timer3_int;
- if (progval <= 100) drawProgress(3, progval);
-}
-
-unsigned long HAL_GetTick(void) {
- unsigned int hi = REGS_TIMER->counter_hi;
- unsigned int lo = REGS_TIMER->counter_lo;
-
- //double check hi value didn't change after setting it...
- if (hi != REGS_TIMER->counter_hi) {
- hi = REGS_TIMER->counter_hi;
- lo = REGS_TIMER->counter_lo;
- }
-
- return ((unsigned long)hi << 32) | lo;
-}
-
-void HAL_Delay(unsigned int ms) {
- unsigned long start = HAL_GetTick();
-
- while(HAL_GetTick() < start + (ms * 1000));
-}
-
-void main(void)
-{
- fb_init();
-
- unsigned int i=0;
- while (i++<30) debugcrlf();
-
- initProgress();
-
- // Kick it off on core 1
-
- start_core1(core1_main);
-
- // Kick off the timers
-
- irq_init_vectors();
- enable_interrupt_controller();
- irq_enable();
- timer_init();
-
- // Kick it off on core 3
-
- start_core3(core3_main);
-
- // Kick it off on core 0
-
- core0_main();
-
- // Disable IRQs and loop endlessly
-
- irq_disable();
- disable_interrupt_controller();
-
- while(1);
-}
diff --git a/part15-tcpip/kernel/kernel.h b/part15-tcpip/kernel/kernel.h
deleted file mode 100644
index b2dcb44..0000000
--- a/part15-tcpip/kernel/kernel.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#define PERIPHERAL_BASE 0xFE000000
-#define CLOCKHZ 1000000
-
-struct timer_regs {
- volatile unsigned int control_status;
- volatile unsigned int counter_lo;
- volatile unsigned int counter_hi;
- volatile unsigned int compare[4];
-};
-
-#define REGS_TIMER ((struct timer_regs *)(PERIPHERAL_BASE + 0x00003000))
-
-struct arm_irq_regs_2711 {
- volatile unsigned int irq0_pending_0;
- volatile unsigned int irq0_pending_1;
- volatile unsigned int irq0_pending_2;
- volatile unsigned int res0;
- volatile unsigned int irq0_enable_0;
- volatile unsigned int irq0_enable_1;
- volatile unsigned int irq0_enable_2;
- volatile unsigned int res1;
- volatile unsigned int irq0_disable_0;
- volatile unsigned int irq0_disable_1;
- volatile unsigned int irq0_disable_2;
-};
-
-typedef struct arm_irq_regs_2711 arm_irq_regs;
-
-#define REGS_IRQ ((arm_irq_regs *)(PERIPHERAL_BASE + 0x0000B200))
-
-enum vc_irqs {
- SYS_TIMER_IRQ_0 = 1,
- SYS_TIMER_IRQ_1 = 2,
- SYS_TIMER_IRQ_2 = 4,
- SYS_TIMER_IRQ_3 = 8,
- AUX_IRQ = (1 << 29)
-};
-
-void irq_init_vectors();
-void irq_enable();
-void irq_disable();
-void enable_interrupt_controller();
-void disable_interrupt_controller();
-
-void handle_timer_1();
-void handle_timer_3();
-
-void init_network(void);
-void net_test(void);
-void enc28j60PacketSend(unsigned short buflen, void *buffer);
-void *memcpy(void *dest, const void *src, unsigned short len);
diff --git a/part15-tcpip/kernel/utils.S b/part15-tcpip/kernel/utils.S
deleted file mode 100644
index 6027c0d..0000000
--- a/part15-tcpip/kernel/utils.S
+++ /dev/null
@@ -1,15 +0,0 @@
-.globl irq_init_vectors
-irq_init_vectors:
- adr x0, vectors
- msr vbar_el1, x0
- ret
-
-.globl irq_enable
-irq_enable:
- msr daifclr, #2
- ret
-
-.globl irq_disable
-irq_disable:
- msr daifset, #2
- ret