├── .github
└── workflows
│ └── Continuous-Integration.yml
├── AUTHORS
├── README
├── README.md
├── examples
├── AdvancedChatServer
│ └── AdvancedChatServer.ino
├── BarometricPressureWebServer
│ └── BarometricPressureWebServer.ino
├── ChatServer
│ └── ChatServer.ino
├── DhcpAddressPrinter
│ └── DhcpAddressPrinter.ino
├── DhcpChatServer
│ └── DhcpChatServer.ino
├── TelnetClient
│ └── TelnetClient.ino
├── UDPSendReceiveString
│ └── UDPSendReceiveString.ino
├── UdpNtpClient
│ └── UdpNtpClient.ino
├── WebClient
│ └── WebClient.ino
├── WebClientFreeRTOS
│ └── WebClientFreeRTOS.ino
├── WebClientRepeating
│ └── WebClientRepeating.ino
├── WebServer
│ └── WebServer.ino
└── WebServerFreeRTOS
│ └── WebServerFreeRTOS.ino
├── keywords.txt
├── library.json
├── library.properties
└── src
├── Dhcp.cpp
├── Dhcp.h
├── Dns.cpp
├── Dns.h
├── EthernetClient.cpp
├── EthernetClient.h
├── EthernetServer.cpp
├── EthernetServer.h
├── EthernetUdp.cpp
├── EthernetUdp.h
├── STM32Ethernet.cpp
├── STM32Ethernet.h
├── lwipopts.h
├── lwipopts_default.h
└── utility
├── ethernetif.cpp
├── ethernetif.h
├── stm32_eth.cpp
└── stm32_eth.h
/.github/workflows/Continuous-Integration.yml:
--------------------------------------------------------------------------------
1 | name: STM32Ethernet Continuous Integration
2 | on:
3 | push:
4 | branches:
5 | - main
6 | paths-ignore:
7 | - '*'
8 | - '**.md'
9 | - '**.txt'
10 | pull_request:
11 | paths-ignore:
12 | - '*'
13 | - '**.md'
14 | - '**.txt'
15 | jobs:
16 | astyle_check:
17 | runs-on: ubuntu-latest
18 | name: AStyle check
19 | steps:
20 | # First of all, clone the repo using the checkout action.
21 | - name: Checkout
22 | uses: actions/checkout@main
23 |
24 | - name: Astyle check
25 | id: Astyle
26 | uses: stm32duino/actions/astyle-check@main
27 |
28 | # Use the output from the `Astyle` step
29 | - name: Astyle Errors
30 | if: failure()
31 | run: |
32 | cat ${{ steps.Astyle.outputs.astyle-result }}
33 | exit 1
34 | codespell:
35 | name: Check for spelling errors
36 | runs-on: ubuntu-latest
37 | steps:
38 | - name: Checkout
39 | uses: actions/checkout@main
40 |
41 | # See: https://github.com/codespell-project/actions-codespell/blob/master/README.md
42 | - name: Spell check
43 | uses: codespell-project/actions-codespell@master
44 | with:
45 | check_filenames: true
46 | check_hidden: true
47 | # In the event of a false positive, add the word in all lower case to this file:
48 | # ignore_words_file: ./extras/codespell-ignore-words-list.txt
49 | lib_build:
50 | runs-on: ubuntu-latest
51 | name: Library compilation
52 | steps:
53 | # First of all, clone the repo using the checkout action.
54 | - name: Checkout
55 | uses: actions/checkout@main
56 |
57 | - name: Compilation
58 | id: Compile
59 | uses: stm32duino/actions/compile-examples@main
60 | with:
61 | board-pattern: "DISCO_F746NG|NUCLEO_F429ZI|NUCLEO_F767ZI"
62 | libraries: "STM32duino LwIP, STM32duino FreeRTOS"
63 |
64 | # Use the output from the `Compile` step
65 | - name: Compilation Errors
66 | if: failure()
67 | run: |
68 | cat ${{ steps.Compile.outputs.compile-result }}
69 | exit 1
70 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 |
2 | Alberto Panu https://github.com/bigjohnson
3 | Alasdair Allan https://github.com/aallan
4 | Alice Pintus https://github.com/00alis
5 | Adrian McEwen https://github.com/amcewen
6 | Arduino LLC http://arduino.cc/
7 | Arnie97 https://github.com/Arnie97
8 | Arturo Guadalupi https://github.com/agdl
9 | Bjoern Hartmann https://people.eecs.berkeley.edu/~bjoern/
10 | chaveiro https://github.com/chaveiro
11 | Cristian Maglie https://github.com/cmaglie
12 | David A. Mellis https://github.com/damellis
13 | Dino Tinitigan https://github.com/bigdinotech
14 | Eddy https://github.com/eddyst
15 | Federico Vanzati https://github.com/Fede85
16 | Federico Fissore https://github.com/ffissore
17 | Jack Christensen https://github.com/JChristensen
18 | Johann Richard https://github.com/johannrichard
19 | Jordan Terrell https://github.com/iSynaptic
20 | Justin Paulin https://github.com/interwho
21 | lathoub https://github.com/lathoub
22 | Martino Facchin https://github.com/facchinm
23 | Matthias Hertel https://github.com/mathertel
24 | Matthijs Kooijman https://github.com/matthijskooijman
25 | Matt Robinson https://github.com/ribbons
26 | MCQN Ltd. http://mcqn.com/
27 | Michael Amie https://github.com/michaelamie
28 | Michael Margolis https://github.com/michaelmargolis
29 | Norbert Truchsess https://github.com/ntruchsess
30 | Paul Stoffregen https://github.com/PaulStoffregen
31 | per1234 https://github.com/per1234
32 | Richard Sim
33 | Scott Fitzgerald https://github.com/shfitz
34 | Stefan Staub https://github.com/sstaub
35 | STMicroelectronics https://github.com/stm32duino
36 | Thibaut Viard https://github.com/aethaniel
37 | Tom Igoe https://github.com/tigoe
38 | Wi6Labs http://www.wi6labs.com/
39 | WizNet http://www.wiznet.co.kr
40 | Zach Eveland https://github.com/zeveland
41 |
42 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | == License ==
2 |
3 | Copyright (c) 2010 Arduino LLC. All right reserved.
4 |
5 | This library is free software; you can redistribute it and/or
6 | modify it under the terms of the GNU Lesser General Public
7 | License as published by the Free Software Foundation; either
8 | version 2.1 of the License, or (at your option) any later version.
9 |
10 | This library is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | Lesser General Public License for more details.
14 |
15 | You should have received a copy of the GNU Lesser General Public
16 | License along with this library; if not, write to the Free Software
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # STM32 Ethernet Library for Arduino
2 |
3 | With an STM32 board with Ethernet compatibility, this library allows a STM32
4 | board (NUCLEO, DISCOVERY, ...) to connect to the internet.
5 |
6 | This library follows the Ethernet API from Arduino.
7 | For more information about it please visit: http://www.arduino.cc/en/Reference/Ethernet
8 |
9 | ## Dependency
10 |
11 | This library is based on LwIP, a Lightweight TCP/IP stack, available here:
12 |
13 | http://git.savannah.gnu.org/cgit/lwip.git
14 |
15 | The LwIP has been ported as Arduino library and is available thanks Arduino Library Manager.
16 |
17 | Source: https://github.com/stm32duino/LwIP
18 |
19 | ## Configuration
20 |
21 | The LwIP has several user defined options, which is specified from within the `lwipopts.h` file.
22 |
23 | This library provides a default user defined options file named `lwipopts_default.h`.
24 |
25 | User can provide his own defined options at sketch level by adding his configuration in a file named `STM32lwipopts.h` or
26 | extend the default one by adding some extra configuration in a file named `lwipopts_extra.h`.
27 |
28 |
29 |
30 | ## New alternative init procedure **!!!**
31 |
32 | There are alternative inits of the Ethernet interface with following orders:
33 |
34 | Ethernet.begin();
35 | Ethernet.begin(ip);
36 | Ethernet.begin(ip, subnet);
37 | Ethernet.begin(ip, subnet, gateway);
38 | Ethernet.begin(ip, subnet, gateway, dns);
39 |
40 | This is more logical. A MAC address is no more needed and will retrieved internally by the mbed MAC address!
41 |
42 | You can get the MAC address with following function, this must be done after Ethernet.Begin()
43 |
44 | uint8_t *mac;
45 | Ethernet.begin();
46 | Ethernet.MACAddress(mac);
47 |
48 | You can also set a new user based MAC address, this must be done before Ethernet.begin()
49 |
50 | uint8_t newMAC[] = {0x00, 0x80, 0xE1, 0x01, 0x01, 0x01};
51 | Ethernet.setMACAddress(newMAC);
52 | Ethernet.begin();
53 |
54 | ## Note
55 |
56 | `EthernetClass::maintain()` in no more required to renew IP address from DHCP.
57 | It is done automatically by the LwIP stack in a background task.
58 |
59 | An Idle task is required by the LwIP stack to handle timer and data reception.
60 | This idle task is called inside a timer callback each 1 ms by the
61 | function `stm32_eth_scheduler()`.
62 | A `DEFAULT_ETHERNET_TIMER` is set in the library to `TIM14`.
63 | `DEFAULT_ETHERNET_TIMER` can be redefined in the core variant.
64 | Be careful to not lock the system in a function which disabling IRQ.
65 | Call `Ethernet::schedule()` performs an update of the LwIP stack.
66 |
67 | ## Wiki
68 |
69 | You can find information at https://github.com/stm32duino/Arduino_Core_STM32/wiki/STM32Ethernet
70 |
--------------------------------------------------------------------------------
/examples/AdvancedChatServer/AdvancedChatServer.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Advanced Chat Server
3 |
4 | A more advanced server that distributes any incoming messages
5 | to all connected clients but the client the message comes from.
6 | To use, telnet to your device's IP address and type.
7 | You can see the client's input in the serial monitor as well.
8 |
9 | Circuit:
10 | * STM32 board with Ethernet support
11 |
12 | created 18 Dec 2009
13 | by David A. Mellis
14 | modified 9 Apr 2012
15 | by Tom Igoe
16 | redesigned to make use of operator== 25 Nov 2013
17 | by Norbert Truchsess
18 | modified 23 Jun 2017
19 | by Wi6Labs
20 | modified 1 Jun 2018
21 | by sstaub
22 |
23 | */
24 |
25 | #include
26 | #include
27 |
28 | // Enter an IP address for your controller below.
29 | // The IP address will be dependent on your local network.
30 | // gateway and subnet are optional:
31 |
32 | IPAddress ip(192, 168, 1, 177);
33 | IPAddress myDns(192, 168, 1, 1);
34 | IPAddress gateway(192, 168, 1, 1);
35 | IPAddress subnet(255, 255, 0, 0);
36 |
37 |
38 | // telnet defaults to port 23
39 | EthernetServer server(23);
40 |
41 | EthernetClient clients[4];
42 |
43 | void setup() {
44 | // initialize the Ethernet device
45 | Ethernet.begin(ip, subnet, gateway, myDns);
46 | // start listening for clients
47 | server.begin();
48 | // Open serial communications and wait for port to open:
49 | Serial.begin(9600);
50 | while (!Serial) {
51 | ; // wait for serial port to connect. Needed for native USB port only
52 | }
53 |
54 |
55 | Serial.print("Chat server address:");
56 | Serial.println(Ethernet.localIP());
57 | }
58 |
59 | void loop() {
60 | // wait for a new client:
61 | EthernetClient client = server.available();
62 |
63 | // when the client sends the first byte, say hello:
64 | if (client) {
65 |
66 | bool newClient = true;
67 | for (byte i = 0; i < 4; i++) {
68 | //check whether this client refers to the same socket as one of the existing instances:
69 | if (clients[i] == client) {
70 | newClient = false;
71 | break;
72 | }
73 | }
74 |
75 | if (newClient) {
76 | //check which of the existing clients can be overridden:
77 | for (byte i = 0; i < 4; i++) {
78 | if (!clients[i] && clients[i] != client) {
79 | clients[i] = client;
80 | // clear out the input buffer:
81 | client.flush();
82 | Serial.println("We have a new client");
83 | client.print("Hello, client number: ");
84 | client.print(i);
85 | client.println();
86 | break;
87 | }
88 | }
89 | }
90 |
91 | if (client.available() > 0) {
92 | // read the bytes incoming from the client:
93 | char thisChar = client.read();
94 | // echo the bytes back to all other connected clients:
95 | for (byte i = 0; i < 4; i++) {
96 | if (clients[i] && (clients[i] != client)) {
97 | clients[i].write(thisChar);
98 | }
99 | }
100 | // echo the bytes to the server as well:
101 | Serial.write(thisChar);
102 | }
103 | }
104 | for (byte i = 0; i < 4; i++) {
105 | if (!(clients[i].connected())) {
106 | // client.stop() invalidates the internal socket-descriptor, so next use of == will always return false;
107 | clients[i].stop();
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino:
--------------------------------------------------------------------------------
1 | /*
2 | SCP1000 Barometric Pressure Sensor Display
3 |
4 | Serves the output of a Barometric Pressure Sensor as a web page.
5 | Uses the SPI library. For details on the sensor, see:
6 | http://www.sparkfun.com/commerce/product_info.php?products_id=8161
7 |
8 | This sketch adapted from Nathan Seidle's SCP1000 example for PIC:
9 | http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip
10 |
11 | Circuit:
12 | SCP1000 sensor attached to pins 6,7, and 11 - 13:
13 | DRDY: pin 6
14 | CSB: pin 7
15 | MOSI: pin 11
16 | MISO: pin 12
17 | SCK: pin 13
18 |
19 | created 31 July 2010
20 | by Tom Igoe
21 | modified 23 Jun 2017
22 | by Wi6Labs
23 | modified 1 Jun 2018
24 | by sstaub
25 | */
26 |
27 | #include
28 | #include
29 | // the sensor communicates using SPI, so include the library:
30 | #include
31 |
32 |
33 | // assign an IP address for the controller:
34 | IPAddress ip(192, 168, 1, 20);
35 |
36 |
37 | // Initialize the Ethernet server library
38 | // with the IP address and port you want to use
39 | // (port 80 is default for HTTP):
40 | EthernetServer server(80);
41 |
42 |
43 | //Sensor's memory register addresses:
44 | const int PRESSURE = 0x1F; //3 most significant bits of pressure
45 | const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure
46 | const int TEMPERATURE = 0x21; //16 bit temperature reading
47 |
48 | // pins used for the connection with the sensor
49 | // the others you need are controlled by the SPI library):
50 | const int dataReadyPin = 6;
51 | const int chipSelectPin = 7;
52 |
53 | float temperature = 0.0;
54 | long pressure = 0;
55 | long lastReadingTime = 0;
56 |
57 | void setup() {
58 | // start the SPI library:
59 | SPI.begin();
60 |
61 | // start the Ethernet connection and the server:
62 | Ethernet.begin(ip);
63 | server.begin();
64 |
65 | // initialize the data ready and chip select pins:
66 | pinMode(dataReadyPin, INPUT);
67 | pinMode(chipSelectPin, OUTPUT);
68 |
69 | Serial.begin(9600);
70 |
71 | //Configure SCP1000 for low noise configuration:
72 | writeRegister(0x02, 0x2D);
73 | writeRegister(0x01, 0x03);
74 | writeRegister(0x03, 0x02);
75 |
76 | // give the sensor and Ethernet shield time to set up:
77 | delay(1000);
78 |
79 | //Set the sensor to high resolution mode tp start readings:
80 | writeRegister(0x03, 0x0A);
81 |
82 | }
83 |
84 | void loop() {
85 | // check for a reading no more than once a second.
86 | if (millis() - lastReadingTime > 1000) {
87 | // if there's a reading ready, read it:
88 | // don't do anything until the data ready pin is high:
89 | if (digitalRead(dataReadyPin) == HIGH) {
90 | getData();
91 | // timestamp the last time you got a reading:
92 | lastReadingTime = millis();
93 | }
94 | }
95 |
96 | // listen for incoming Ethernet connections:
97 | listenForEthernetClients();
98 | }
99 |
100 |
101 | void getData() {
102 | Serial.println("Getting reading");
103 | //Read the temperature data
104 | int tempData = readRegister(0x21, 2);
105 |
106 | // convert the temperature to celsius and display it:
107 | temperature = (float)tempData / 20.0;
108 |
109 | //Read the pressure data highest 3 bits:
110 | byte pressureDataHigh = readRegister(0x1F, 1);
111 | pressureDataHigh &= 0b00000111; //you only needs bits 2 to 0
112 |
113 | //Read the pressure data lower 16 bits:
114 | unsigned int pressureDataLow = readRegister(0x20, 2);
115 | //combine the two parts into one 19-bit number:
116 | pressure = ((pressureDataHigh << 16) | pressureDataLow) / 4;
117 |
118 | Serial.print("Temperature: ");
119 | Serial.print(temperature);
120 | Serial.println(" degrees C");
121 | Serial.print("Pressure: " + String(pressure));
122 | Serial.println(" Pa");
123 | }
124 |
125 | void listenForEthernetClients() {
126 | // listen for incoming clients
127 | EthernetClient client = server.available();
128 | if (client) {
129 | Serial.println("Got a client");
130 | // an http request ends with a blank line
131 | bool currentLineIsBlank = true;
132 | while (client.connected()) {
133 | if (client.available()) {
134 | char c = client.read();
135 | // if you've gotten to the end of the line (received a newline
136 | // character) and the line is blank, the http request has ended,
137 | // so you can send a reply
138 | if (c == '\n' && currentLineIsBlank) {
139 | // send a standard http response header
140 | client.println("HTTP/1.1 200 OK");
141 | client.println("Content-Type: text/html");
142 | client.println();
143 | // print the current readings, in HTML format:
144 | client.print("Temperature: ");
145 | client.print(temperature);
146 | client.print(" degrees C");
147 | client.println("
");
148 | client.print("Pressure: " + String(pressure));
149 | client.print(" Pa");
150 | client.println("
");
151 | break;
152 | }
153 | if (c == '\n') {
154 | // you're starting a new line
155 | currentLineIsBlank = true;
156 | } else if (c != '\r') {
157 | // you've gotten a character on the current line
158 | currentLineIsBlank = false;
159 | }
160 | }
161 | }
162 | // give the web browser time to receive the data
163 | delay(1);
164 | // close the connection:
165 | client.stop();
166 | }
167 | }
168 |
169 |
170 | //Send a write command to SCP1000
171 | void writeRegister(byte registerName, byte registerValue) {
172 | // SCP1000 expects the register name in the upper 6 bits
173 | // of the byte:
174 | registerName <<= 2;
175 | // command (read or write) goes in the lower two bits:
176 | registerName |= 0b00000010; //Write command
177 |
178 | // take the chip select low to select the device:
179 | digitalWrite(chipSelectPin, LOW);
180 |
181 | SPI.transfer(registerName); //Send register location
182 | SPI.transfer(registerValue); //Send value to record into register
183 |
184 | // take the chip select high to de-select:
185 | digitalWrite(chipSelectPin, HIGH);
186 | }
187 |
188 |
189 | //Read register from the SCP1000:
190 | unsigned int readRegister(byte registerName, int numBytes) {
191 | byte inByte = 0; // incoming from the SPI read
192 | unsigned int result = 0; // result to return
193 |
194 | // SCP1000 expects the register name in the upper 6 bits
195 | // of the byte:
196 | registerName <<= 2;
197 | // command (read or write) goes in the lower two bits:
198 | registerName &= 0b11111100; //Read command
199 |
200 | // take the chip select low to select the device:
201 | digitalWrite(chipSelectPin, LOW);
202 | // send the device the register you want to read:
203 | int command = SPI.transfer(registerName);
204 | // send a value of 0 to read the first byte returned:
205 | inByte = SPI.transfer(0x00);
206 |
207 | result = inByte;
208 | // if there's more than one byte returned,
209 | // shift the first byte then get the second byte:
210 | if (numBytes > 1) {
211 | result = inByte << 8;
212 | inByte = SPI.transfer(0x00);
213 | result = result | inByte;
214 | }
215 | // take the chip select high to de-select:
216 | digitalWrite(chipSelectPin, HIGH);
217 | // return the result:
218 | return (result);
219 | }
220 |
--------------------------------------------------------------------------------
/examples/ChatServer/ChatServer.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Chat Server
3 |
4 | A simple server that distributes any incoming messages to all
5 | connected clients. To use, telnet to your device's IP address and type.
6 | You can see the client's input in the serial monitor as well.
7 |
8 | Circuit:
9 | * STM32 board with Ethernet support
10 |
11 | created 18 Dec 2009
12 | by David A. Mellis
13 | modified 9 Apr 2012
14 | by Tom Igoe
15 | modified 23 Jun 2017
16 | by Wi6Labs
17 | modified 1 Jun 2018
18 | by sstaub
19 | */
20 |
21 | #include
22 | #include
23 |
24 | // Enter an IP address for your controller below.
25 | // The IP address will be dependent on your local network.
26 | // gateway and subnet are optional:
27 |
28 | IPAddress ip(192, 168, 1, 177);
29 | IPAddress myDns(192,168,1, 1);
30 | IPAddress gateway(192, 168, 1, 1);
31 | IPAddress subnet(255, 255, 0, 0);
32 |
33 |
34 | // telnet defaults to port 23
35 | EthernetServer server(23);
36 | bool alreadyConnected = false; // whether or not the client was connected previously
37 |
38 | void setup() {
39 | // initialize the ethernet device
40 | Ethernet.begin(ip, subnet, gateway, myDns);
41 | // start listening for clients
42 | server.begin();
43 | // Open serial communications and wait for port to open:
44 | Serial.begin(9600);
45 | while (!Serial) {
46 | ; // wait for serial port to connect. Needed for native USB port only
47 | }
48 |
49 |
50 | Serial.print("Chat server address:");
51 | Serial.println(Ethernet.localIP());
52 | }
53 |
54 | void loop() {
55 | // wait for a new client:
56 | EthernetClient client = server.available();
57 |
58 | // when the client sends the first byte, say hello:
59 | if (client) {
60 | if (!alreadyConnected) {
61 | // clear out the input buffer:
62 | client.flush();
63 | Serial.println("We have a new client");
64 | client.println("Hello, client!");
65 | alreadyConnected = true;
66 | }
67 |
68 | if (client.available() > 0) {
69 | // read the bytes incoming from the client:
70 | char thisChar = client.read();
71 | // echo the bytes back to the client:
72 | server.write(thisChar);
73 | // echo the bytes to the server as well:
74 | Serial.write(thisChar);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino:
--------------------------------------------------------------------------------
1 | /*
2 | DHCP-based IP printer
3 |
4 | This sketch uses the DHCP extensions to the Ethernet library
5 | to get an IP address via DHCP and print the address obtained.
6 |
7 | Circuit:
8 | STM32 board with Ethernet support
9 |
10 | created 12 April 2011
11 | modified 9 Apr 2012
12 | by Tom Igoe
13 | modified 02 Sept 2015
14 | by Arturo Guadalupi
15 | modified 23 Jun 2017
16 | by Wi6Labs
17 | modified 1 Jun 2018
18 | by sstaub
19 | */
20 |
21 | #include
22 | #include
23 |
24 |
25 | // Initialize the Ethernet client library
26 | // with the IP address and port of the server
27 | // that you want to connect to (port 80 is default for HTTP):
28 | EthernetClient client;
29 |
30 | void setup() {
31 | // Open serial communications and wait for port to open:
32 | Serial.begin(9600);
33 | // this check is only needed on the Leonardo:
34 | while (!Serial) {
35 | ; // wait for serial port to connect. Needed for native USB port only
36 | }
37 |
38 | // start the Ethernet connection:
39 | if (Ethernet.begin() == 0) {
40 | Serial.println("Failed to configure Ethernet using DHCP");
41 | // no point in carrying on, so do nothing forevermore:
42 | for (;;)
43 | ;
44 | }
45 | // print your local IP address:
46 | printIPAddress();
47 | }
48 |
49 | void loop() {
50 |
51 | switch (Ethernet.maintain())
52 | {
53 | case 1:
54 | //renewed fail
55 | Serial.println("Error: renewed fail");
56 | break;
57 |
58 | case 2:
59 | //renewed success
60 | Serial.println("Renewed success");
61 |
62 | //print your local IP address:
63 | printIPAddress();
64 | break;
65 |
66 | case 3:
67 | //rebind fail
68 | Serial.println("Error: rebind fail");
69 | break;
70 |
71 | case 4:
72 | //rebind success
73 | Serial.println("Rebind success");
74 |
75 | //print your local IP address:
76 | printIPAddress();
77 | break;
78 |
79 | default:
80 | //nothing happened
81 | break;
82 |
83 | }
84 | }
85 |
86 | void printIPAddress()
87 | {
88 | Serial.print("My IP address: ");
89 | for (byte thisByte = 0; thisByte < 4; thisByte++) {
90 | // print the value of each byte of the IP address:
91 | Serial.print(Ethernet.localIP()[thisByte], DEC);
92 | Serial.print(".");
93 | }
94 |
95 | Serial.println();
96 | }
97 |
--------------------------------------------------------------------------------
/examples/DhcpChatServer/DhcpChatServer.ino:
--------------------------------------------------------------------------------
1 | /*
2 | DHCP Chat Server
3 |
4 | A simple server that distributes any incoming messages to all
5 | connected clients. To use, telnet to your device's IP address and type.
6 | You can see the client's input in the serial monitor as well.
7 |
8 | THis version attempts to get an IP address using DHCP
9 |
10 | Circuit:
11 | * STM32 board with Ethernet support
12 |
13 | created 21 May 2011
14 | modified 9 Apr 2012
15 | by Tom Igoe
16 | modified 02 Sept 2015
17 | by Arturo Guadalupi
18 | Based on ChatServer example by David A. Mellis
19 | modified 23 Jun 2017
20 | by Wi6Labs
21 | modified 1 Jun 2018
22 | by sstaub
23 | */
24 |
25 | #include
26 | #include
27 |
28 | // Enter an IP address for your controller below.
29 | // The IP address will be dependent on your local network.
30 | // gateway and subnet are optional:
31 | IPAddress ip(192, 168, 1, 177);
32 | IPAddress myDns(192,168,1, 1);
33 | IPAddress gateway(192, 168, 1, 1);
34 | IPAddress subnet(255, 255, 0, 0);
35 |
36 | // telnet defaults to port 23
37 | EthernetServer server(23);
38 | bool gotAMessage = false; // whether or not you got a message from the client yet
39 |
40 | void setup() {
41 | // Open serial communications and wait for port to open:
42 | Serial.begin(9600);
43 | // this check is only needed on the Leonardo:
44 | while (!Serial) {
45 | ; // wait for serial port to connect. Needed for native USB port only
46 | }
47 |
48 |
49 | // start the Ethernet connection:
50 | Serial.println("Trying to get an IP address using DHCP");
51 | if (Ethernet.begin() == 0) {
52 | Serial.println("Failed to configure Ethernet using DHCP");
53 | // initialize the Ethernet device not using DHCP:
54 | Ethernet.begin(ip, subnet, gateway, myDns);
55 | }
56 | // print your local IP address:
57 | Serial.print("My IP address: ");
58 | ip = Ethernet.localIP();
59 | for (byte thisByte = 0; thisByte < 4; thisByte++) {
60 | // print the value of each byte of the IP address:
61 | Serial.print(ip[thisByte], DEC);
62 | Serial.print(".");
63 | }
64 | Serial.println();
65 | // start listening for clients
66 | server.begin();
67 |
68 | }
69 |
70 | void loop() {
71 | // wait for a new client:
72 | EthernetClient client = server.available();
73 |
74 | // when the client sends the first byte, say hello:
75 | if (client) {
76 | if (!gotAMessage) {
77 | Serial.println("We have a new client");
78 | client.println("Hello, client!");
79 | gotAMessage = true;
80 | }
81 |
82 | // read the bytes incoming from the client:
83 | char thisChar = client.read();
84 | // echo the bytes back to the client:
85 | server.write(thisChar);
86 | // echo the bytes to the server as well:
87 | Serial.print(thisChar);
88 | Ethernet.maintain();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/examples/TelnetClient/TelnetClient.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Telnet client
3 |
4 | This sketch connects to a a telnet server (http://www.google.com)
5 | using an Arduino Wiznet Ethernet shield. You'll need a telnet server
6 | to test this with.
7 | Processing's ChatServer example (part of the network library) works well,
8 | running on port 10002. It can be found as part of the examples
9 | in the Processing application, available at
10 | http://processing.org/
11 |
12 | Circuit:
13 | * STM32 board with Ethernet support
14 |
15 | created 14 Sep 2010
16 | modified 9 Apr 2012
17 | by Tom Igoe
18 | modified 23 Jun 2017
19 | by Wi6Labs
20 | modified 1 Jun 2018
21 | by sstaub
22 | */
23 |
24 | #include
25 | #include
26 |
27 | // Enter an IP address for your controller below.
28 | // The IP address will be dependent on your local network:
29 | IPAddress ip(192, 168, 1, 177);
30 |
31 | // Enter the IP address of the server you're connecting to:
32 | IPAddress server(1, 1, 1, 1);
33 |
34 | // Initialize the Ethernet client library
35 | // with the IP address and port of the server
36 | // that you want to connect to (port 23 is default for telnet;
37 | // if you're using Processing's ChatServer, use port 10002):
38 | EthernetClient client;
39 |
40 | void setup() {
41 | // start the Ethernet connection:
42 | Ethernet.begin(ip);
43 | // Open serial communications and wait for port to open:
44 | Serial.begin(9600);
45 | while (!Serial) {
46 | ; // wait for serial port to connect. Needed for native USB port only
47 | }
48 |
49 |
50 | // give the Ethernet shield a second to initialize:
51 | delay(1000);
52 | Serial.println("connecting...");
53 |
54 | // if you get a connection, report back via serial:
55 | if (client.connect(server, 10002)) {
56 | Serial.println("connected");
57 | } else {
58 | // if you didn't get a connection to the server:
59 | Serial.println("connection failed");
60 | }
61 | }
62 |
63 | void loop() {
64 | // if there are incoming bytes available
65 | // from the server, read them and print them:
66 | if (client.available()) {
67 | char c = client.read();
68 | Serial.print(c);
69 | }
70 |
71 | // as long as there are bytes in the serial queue,
72 | // read them and send them out the socket if it's open:
73 | while (Serial.available() > 0) {
74 | char inChar = Serial.read();
75 | if (client.connected()) {
76 | client.print(inChar);
77 | }
78 | }
79 |
80 | // if the server's disconnected, stop the client:
81 | if (!client.connected()) {
82 | Serial.println();
83 | Serial.println("disconnecting.");
84 | client.stop();
85 | // do nothing:
86 | while (true);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/examples/UDPSendReceiveString/UDPSendReceiveString.ino:
--------------------------------------------------------------------------------
1 | /*
2 | UDPSendReceiveString:
3 | This sketch receives UDP message strings, prints them to the serial port
4 | and sends an "acknowledge" string back to the sender
5 |
6 | A Processing sketch is included at the end of file that can be used to send
7 | and received messages for testing with a computer.
8 |
9 | created 21 Aug 2010
10 | by Michael Margolis
11 | modified 23 Jun 2017
12 | by Wi6Labs
13 | modified 1 Jun 2018
14 | by sstaub
15 | This code is in the public domain.
16 | */
17 |
18 | #include
19 | #include
20 | #include // UDP library from: bjoern@cs.stanford.edu 12/30/2008
21 |
22 |
23 | // Enter an IP address for your controller below.
24 | // The IP address will be dependent on your local network:
25 | IPAddress ip(192, 168, 1, 177);
26 |
27 | unsigned int localPort = 8888; // local port to listen on
28 |
29 | // buffers for receiving and sending data
30 | char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
31 | char ReplyBuffer[] = "acknowledged"; // a string to send back
32 |
33 | // An EthernetUDP instance to let us send and receive packets over UDP
34 | EthernetUDP Udp;
35 |
36 | void setup() {
37 | // start the Ethernet and UDP:
38 | Ethernet.begin(ip);
39 | Udp.begin(localPort);
40 |
41 | Serial.begin(9600);
42 | }
43 |
44 | void loop() {
45 | // if there's data available, read a packet
46 | int packetSize = Udp.parsePacket();
47 | if (packetSize) {
48 | Serial.print("Received packet of size ");
49 | Serial.println(packetSize);
50 | Serial.print("From ");
51 | IPAddress remote = Udp.remoteIP();
52 | for (int i = 0; i < 4; i++) {
53 | Serial.print(remote[i], DEC);
54 | if (i < 3) {
55 | Serial.print(".");
56 | }
57 | }
58 | Serial.print(", port ");
59 | Serial.println(Udp.remotePort());
60 |
61 | // read the packet into packetBufffer
62 | Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
63 | Serial.println("Contents:");
64 | Serial.println(packetBuffer);
65 |
66 | // send a reply to the IP address and port that sent us the packet we received
67 | Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
68 | Udp.write(ReplyBuffer);
69 | Udp.endPacket();
70 | }
71 | delay(10);
72 | }
73 |
74 |
75 | /*
76 | Processing sketch to run with this example
77 | =====================================================
78 |
79 | // Processing UDP example to send and receive string data from Arduino
80 | // press any key to send the "Hello Arduino" message
81 |
82 |
83 | import hypermedia.net.*;
84 |
85 | UDP udp; // define the UDP object
86 |
87 |
88 | void setup() {
89 | udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000
90 | //udp.log( true ); // <-- printout the connection activity
91 | udp.listen( true ); // and wait for incoming message
92 | }
93 |
94 | void draw()
95 | {
96 | }
97 |
98 | void keyPressed() {
99 | String ip = "192.168.1.177"; // the remote IP address
100 | int port = 8888; // the destination port
101 |
102 | udp.send("Hello World", ip, port ); // the message to send
103 |
104 | }
105 |
106 | void receive( byte[] data ) { // <-- default handler
107 | //void receive( byte[] data, String ip, int port ) { // <-- extended handler
108 |
109 | for(int i=0; i < data.length; i++)
110 | print(char(data[i]));
111 | println();
112 | }
113 | */
114 |
--------------------------------------------------------------------------------
/examples/UdpNtpClient/UdpNtpClient.ino:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Udp NTP Client
4 |
5 | Get the time from a Network Time Protocol (NTP) time server
6 | Demonstrates use of UDP sendPacket and ReceivePacket
7 | For more on NTP time servers and the messages needed to communicate with them,
8 | see http://en.wikipedia.org/wiki/Network_Time_Protocol
9 |
10 | created 4 Sep 2010
11 | by Michael Margolis
12 | modified 9 Apr 2012
13 | by Tom Igoe
14 | modified 02 Sept 2015
15 | by Arturo Guadalupi
16 | modified 23 Jun 2017
17 | by Wi6Labs
18 | modified 1 Jun 2018
19 | by sstaub
20 | This code is in the public domain.
21 |
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | unsigned int localPort = 8888; // local port to listen for UDP packets
29 |
30 | char timeServer[] = "time.nist.gov"; // time.nist.gov NTP server
31 |
32 | const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
33 |
34 | byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
35 |
36 | // A UDP instance to let us send and receive packets over UDP
37 | EthernetUDP Udp;
38 |
39 | void setup() {
40 | // Open serial communications and wait for port to open:
41 | Serial.begin(9600);
42 | while (!Serial) {
43 | ; // wait for serial port to connect. Needed for native USB port only
44 | }
45 |
46 |
47 | // start Ethernet and UDP
48 | if (Ethernet.begin() == 0) {
49 | Serial.println("Failed to configure Ethernet using DHCP");
50 | // no point in carrying on, so do nothing forevermore:
51 | for (;;)
52 | ;
53 | }
54 | Udp.begin(localPort);
55 | }
56 |
57 | void loop() {
58 | sendNTPpacket(timeServer); // send an NTP packet to a time server
59 |
60 | // wait to see if a reply is available
61 | delay(1000);
62 | if (Udp.parsePacket()) {
63 | // We've received a packet, read the data from it
64 | Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
65 |
66 | // the timestamp starts at byte 40 of the received packet and is four bytes,
67 | // or two words, long. First, extract the two words:
68 |
69 | unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
70 | unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
71 | // combine the four bytes (two words) into a long integer
72 | // this is NTP time (seconds since Jan 1 1900):
73 | unsigned long secsSince1900 = highWord << 16 | lowWord;
74 | Serial.print("Seconds since Jan 1 1900 = ");
75 | Serial.println(secsSince1900);
76 |
77 | // now convert NTP time into everyday time:
78 | Serial.print("Unix time = ");
79 | // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
80 | const unsigned long seventyYears = 2208988800UL;
81 | // subtract seventy years:
82 | unsigned long epoch = secsSince1900 - seventyYears;
83 | // print Unix time:
84 | Serial.println(epoch);
85 |
86 |
87 | // print the hour, minute and second:
88 | Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
89 | Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
90 | Serial.print(':');
91 | if (((epoch % 3600) / 60) < 10) {
92 | // In the first 10 minutes of each hour, we'll want a leading '0'
93 | Serial.print('0');
94 | }
95 | Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
96 | Serial.print(':');
97 | if ((epoch % 60) < 10) {
98 | // In the first 10 seconds of each minute, we'll want a leading '0'
99 | Serial.print('0');
100 | }
101 | Serial.println(epoch % 60); // print the second
102 | }
103 | // wait ten seconds before asking for the time again
104 | delay(10000);
105 | Ethernet.maintain();
106 | }
107 |
108 | // send an NTP request to the time server at the given address
109 | void sendNTPpacket(char* address) {
110 | // set all bytes in the buffer to 0
111 | memset(packetBuffer, 0, NTP_PACKET_SIZE);
112 | // Initialize values needed to form NTP request
113 | // (see URL above for details on the packets)
114 | packetBuffer[0] = 0b11100011; // LI, Version, Mode
115 | packetBuffer[1] = 0; // Stratum, or type of clock
116 | packetBuffer[2] = 6; // Polling Interval
117 | packetBuffer[3] = 0xEC; // Peer Clock Precision
118 | // 8 bytes of zero for Root Delay & Root Dispersion
119 | packetBuffer[12] = 49;
120 | packetBuffer[13] = 0x4E;
121 | packetBuffer[14] = 49;
122 | packetBuffer[15] = 52;
123 |
124 | // all NTP fields have been given values, now
125 | // you can send a packet requesting a timestamp:
126 | Udp.beginPacket(address, 123); //NTP requests are to port 123
127 | Udp.write(packetBuffer, NTP_PACKET_SIZE);
128 | Udp.endPacket();
129 | }
130 |
--------------------------------------------------------------------------------
/examples/WebClient/WebClient.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Web client
3 |
4 | This sketch connects to a website (http://www.google.com)
5 |
6 | Circuit:
7 | * STM32 board with Ethernet support
8 |
9 | created 18 Dec 2009
10 | by David A. Mellis
11 | modified 9 Apr 2012
12 | by Tom Igoe, based on work by Adrian McEwen
13 | modified 23 Jun 2017
14 | by Wi6Labs
15 | modified 1 Jun 2018
16 | by sstaub
17 | */
18 |
19 | #include
20 | #include
21 |
22 | // if you don't want to use DNS (and reduce your sketch size)
23 | // use the numeric IP instead of the name for the server:
24 | //IPAddress server(74,125,232,128); // numeric IP for Google (no DNS)
25 | char server[] = "www.google.com"; // name address for Google (using DNS)
26 |
27 | // Set the static IP address to use if the DHCP fails to assign
28 | IPAddress ip(192, 168, 0, 177);
29 |
30 | // Initialize the Ethernet client library
31 | // with the IP address and port of the server
32 | // that you want to connect to (port 80 is default for HTTP):
33 | EthernetClient client;
34 |
35 | void setup() {
36 | // Open serial communications and wait for port to open:
37 | Serial.begin(9600);
38 | while (!Serial) {
39 | ; // wait for serial port to connect. Needed for native USB port only
40 | }
41 |
42 | // start the Ethernet connection:
43 | if (Ethernet.begin() == 0) {
44 | Serial.println("Failed to configure Ethernet using DHCP");
45 | // try to configure using IP address instead of DHCP:
46 | Ethernet.begin(ip);
47 | }
48 | // give the Ethernet shield a second to initialize:
49 | delay(1000);
50 | Serial.println("connecting...");
51 |
52 | // if you get a connection, report back via serial:
53 | if (client.connect(server, 80)) {
54 | Serial.println("connected");
55 | // Make a HTTP request:
56 | client.println("GET /search?q=arduino HTTP/1.1");
57 | client.println("Host: www.google.com");
58 | client.println("Connection: close");
59 | client.println();
60 | } else {
61 | // if you didn't get a connection to the server:
62 | Serial.println("connection failed");
63 | }
64 | }
65 |
66 | void loop() {
67 | // if there are incoming bytes available
68 | // from the server, read them and print them:
69 | if (client.available()) {
70 | char c = client.read();
71 | Serial.print(c);
72 | }
73 |
74 | // if the server's disconnected, stop the client:
75 | if (!client.connected()) {
76 | Serial.println();
77 | Serial.println("disconnecting.");
78 | client.stop();
79 |
80 | // do nothing forevermore:
81 | while (true);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/examples/WebClientFreeRTOS/WebClientFreeRTOS.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Port of WebClient on FreeRTOS
3 |
4 | This sketch connects to a website (http://www.google.com)
5 |
6 | Circuit:
7 | * STM32 board with Ethernet support
8 |
9 | created 18 Dec 2009
10 | by David A. Mellis
11 | modified 9 Apr 2012
12 | by Tom Igoe, based on work by Adrian McEwen
13 | modified 23 Jun 2017
14 | by Wi6Labs
15 | modified 1 Jun 2018
16 | by sstaub
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | // if you don't want to use DNS (and reduce your sketch size)
24 | // use the numeric IP instead of the name for the server:
25 | //IPAddress server(74,125,232,128); // numeric IP for Google (no DNS)
26 | char server[] = "www.google.com"; // name address for Google (using DNS)
27 |
28 | // Set the static IP address to use if the DHCP fails to assign
29 | IPAddress ip(192, 168, 0, 177);
30 |
31 | // Initialize the Ethernet client library
32 | // with the IP address and port of the server
33 | // that you want to connect to (port 80 is default for HTTP):
34 | EthernetClient client;
35 |
36 |
37 | // task code
38 | void taskETH(void* arg) {
39 | UNUSED(arg);
40 | // start the Ethernet connection:
41 | if (Ethernet.begin() == 0) {
42 | Serial.println("Failed to configure Ethernet using DHCP");
43 | // try to configure using IP address instead of DHCP:
44 | Ethernet.begin(ip);
45 | }
46 | // give the Ethernet shield a second to initialize:
47 | delay(1000);
48 | Serial.println("connecting...");
49 |
50 | // if you get a connection, report back via serial:
51 | if (client.connect(server, 80)) {
52 | Serial.println("connected");
53 | // Make a HTTP request:
54 | client.println("GET /search?q=arduino HTTP/1.1");
55 | client.println("Host: www.google.com");
56 | client.println("Connection: close");
57 | client.println();
58 | } else {
59 | // if you didn't get a connection to the server:
60 | Serial.println("connection failed");
61 | }
62 |
63 | while(1){
64 | // if there are incoming bytes available
65 | // from the server, read them and print them:
66 | if (client.available()) {
67 | char c = client.read();
68 | Serial.print(c);
69 | }
70 |
71 | // if the server's disconnected, stop the client:
72 | if (!client.connected()) {
73 | Serial.println();
74 | Serial.println("disconnecting.");
75 | client.stop();
76 |
77 | // do nothing forevermore:
78 | while (true);
79 | }
80 | }
81 | }
82 |
83 |
84 | void setup() {
85 | // Open serial communications and wait for port to open:
86 | Serial.begin(9600);
87 | while (!Serial) {
88 | ; // wait for serial port to connect. Needed for native USB port only
89 | }
90 |
91 | portBASE_TYPE s = xTaskCreate(taskETH, NULL, 200, NULL, 1, NULL);
92 | if (s != pdPASS) {
93 | printf("Ethernet task creation failed\n");
94 | while (1);
95 | }
96 |
97 | vTaskStartScheduler();
98 | Serial.println("Scheduler failed");
99 | while (1);
100 | }
101 |
102 | void loop() {
103 | // Not used.
104 | }
105 |
--------------------------------------------------------------------------------
/examples/WebClientRepeating/WebClientRepeating.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Repeating Web client
3 |
4 | This sketch connects to a a web server and makes a request.
5 |
6 | This example uses DNS, by assigning the Ethernet client with a MAC address,
7 | IP address, and DNS address.
8 |
9 | Circuit:
10 | * STM32 board with Ethernet support
11 |
12 | created 19 Apr 2012
13 | by Tom Igoe
14 | modified 21 Jan 2014
15 | by Federico Vanzati
16 | modified 23 Jun 2017
17 | by Wi6Labs
18 | modified 1 Jun 2018
19 | by sstaub
20 | http://www.arduino.cc/en/Tutorial/WebClientRepeating
21 | This code is in the public domain.
22 |
23 | */
24 |
25 | #include
26 | #include
27 |
28 | // fill in an available IP address on your network here,
29 | // for manual configuration:
30 | IPAddress ip(192, 168, 1, 177);
31 | IPAddress gateway(192, 168, 1, 1);
32 | IPAddress subnet(255, 255, 0, 0);
33 | // fill in your Domain Name Server address here:
34 | IPAddress myDns(1, 1, 1, 1);
35 |
36 | // initialize the library instance:
37 | EthernetClient client;
38 |
39 | char server[] = "www.arduino.cc";
40 | //IPAddress server(64,131,82,241);
41 |
42 | unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
43 | const unsigned long postingInterval = 10L * 1000L; // delay between updates, in milliseconds
44 | // the "L" is needed to use long type numbers
45 |
46 | void setup() {
47 | // start serial port:
48 | Serial.begin(9600);
49 | while (!Serial) {
50 | ; // wait for serial port to connect. Needed for native USB port only
51 | }
52 |
53 | // give the ethernet module time to boot up:
54 | delay(1000);
55 | // start the Ethernet connection using a fixed IP address and DNS server:
56 | Ethernet.begin(ip, subnet, gateway, myDns);
57 | // print the Ethernet board/shield's IP address:
58 | Serial.print("My IP address: ");
59 | Serial.println(Ethernet.localIP());
60 | }
61 |
62 | void loop() {
63 | // if there's incoming data from the net connection.
64 | // send it out the serial port. This is for debugging
65 | // purposes only:
66 | if (client.available()) {
67 | char c = client.read();
68 | Serial.write(c);
69 | }
70 |
71 | // if ten seconds have passed since your last connection,
72 | // then connect again and send data:
73 | if (millis() - lastConnectionTime > postingInterval) {
74 | httpRequest();
75 | }
76 |
77 | }
78 |
79 | // this method makes a HTTP connection to the server:
80 | void httpRequest() {
81 | // close any connection before send a new request.
82 | // This will free the socket on the WiFi shield
83 | client.stop();
84 |
85 | // if there's a successful connection:
86 | if (client.connect(server, 80)) {
87 | Serial.println("connecting...");
88 | // send the HTTP GET request:
89 | client.println("GET /latest.txt HTTP/1.1");
90 | client.println("Host: www.arduino.cc");
91 | client.println("User-Agent: arduino-ethernet");
92 | client.println("Connection: close");
93 | client.println();
94 |
95 | // note the time that the connection was made:
96 | lastConnectionTime = millis();
97 | } else {
98 | // if you couldn't make a connection:
99 | Serial.println("connection failed");
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/examples/WebServer/WebServer.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Web Server
3 |
4 | A simple web server that shows the value of the analog input pins.
5 |
6 | Circuit:
7 | * STM32 board with Ethernet support
8 | * Analog inputs attached to pins A0 through A5 (optional)
9 |
10 | created 18 Dec 2009
11 | by David A. Mellis
12 | modified 9 Apr 2012
13 | by Tom Igoe
14 | modified 02 Sept 2015
15 | by Arturo Guadalupi
16 | modified 23 Jun 2017
17 | by Wi6Labs
18 | modified 1 Jun 2018
19 | by sstaub
20 | */
21 |
22 | #include
23 | #include
24 |
25 | // Enter an IP address for your controller below.
26 | // The IP address will be dependent on your local network:
27 | IPAddress ip(192, 168, 1, 177);
28 |
29 | // Initialize the Ethernet server library
30 | // with the IP address and port you want to use
31 | // (port 80 is default for HTTP):
32 | EthernetServer server(80);
33 |
34 | void setup() {
35 | // Open serial communications and wait for port to open:
36 | Serial.begin(9600);
37 | while (!Serial) {
38 | ; // wait for serial port to connect. Needed for native USB port only
39 | }
40 |
41 |
42 | // start the Ethernet connection and the server:
43 | Ethernet.begin(ip);
44 | server.begin();
45 | Serial.print("server is at ");
46 | Serial.println(Ethernet.localIP());
47 | }
48 |
49 |
50 | void loop() {
51 | // listen for incoming clients
52 | EthernetClient client = server.available();
53 | if (client) {
54 | Serial.println("new client");
55 | // an http request ends with a blank line
56 | bool currentLineIsBlank = true;
57 | while (client.connected()) {
58 | if (client.available()) {
59 | char c = client.read();
60 | Serial.write(c);
61 | // if you've gotten to the end of the line (received a newline
62 | // character) and the line is blank, the http request has ended,
63 | // so you can send a reply
64 | if (c == '\n' && currentLineIsBlank) {
65 | // send a standard http response header
66 | client.println("HTTP/1.1 200 OK");
67 | client.println("Content-Type: text/html");
68 | client.println("Connection: close"); // the connection will be closed after completion of the response
69 | client.println("Refresh: 5"); // refresh the page automatically every 5 sec
70 | client.println();
71 | client.println("");
72 | client.println("");
73 | // output the value of each analog input pin
74 | for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
75 | int sensorReading = analogRead(analogChannel);
76 | client.print("analog input ");
77 | client.print(analogChannel);
78 | client.print(" is ");
79 | client.print(sensorReading);
80 | client.println("
");
81 | }
82 | client.println("");
83 | break;
84 | }
85 | if (c == '\n') {
86 | // you're starting a new line
87 | currentLineIsBlank = true;
88 | } else if (c != '\r') {
89 | // you've gotten a character on the current line
90 | currentLineIsBlank = false;
91 | }
92 | }
93 | }
94 | // give the web browser time to receive the data
95 | delay(1);
96 | // close the connection:
97 | client.stop();
98 | Serial.println("client disconnected");
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/examples/WebServerFreeRTOS/WebServerFreeRTOS.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Port of WebServer on FreeRTOS
3 |
4 | A simple web server that shows the value of the analog input pins.
5 | 2 task are created:
6 | Ethernet: to manage the server
7 | Analog to read input values
8 |
9 | Circuit:
10 | STM32 board with Ethernet support
11 | Analog inputs attached to pins A0 through A5 (optional)
12 |
13 | created 18 Dec 2009
14 | by David A. Mellis
15 | modified 9 Apr 2012
16 | by Tom Igoe
17 | modified 02 Sept 2015
18 | by Arturo Guadalupi
19 | modified 23 Jun 2017
20 | by Wi6Labs
21 | modified 1 Jun 2018
22 | by sstaub
23 | */
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | // Enter an IP address for your controller below.
30 | // The IP address will be dependent on your local network:
31 | IPAddress ip(192, 168, 0, 177);
32 |
33 | // Initialize the Ethernet server library
34 | // with the IP address and port you want to use
35 | // (port 80 is default for HTTP):
36 | EthernetServer server(80);
37 |
38 | #define ANALOG_CHANEL_NUMBER 6
39 | int sensorReading[ANALOG_CHANEL_NUMBER];
40 |
41 | void taskAnalog(void* arg) {
42 | UNUSED(arg);
43 | while (1) {
44 | for (int analogChannel = 0; analogChannel < ANALOG_CHANEL_NUMBER; analogChannel++) {
45 | sensorReading[analogChannel] = analogRead(analogChannel);
46 | }
47 | vTaskDelay(1000); // read Analog every seconds
48 | }
49 | }
50 |
51 | // task code
52 | void taskETH(void* arg) {
53 | UNUSED(arg);
54 | // start the Ethernet connection and the server:
55 | Ethernet.begin(ip);
56 | server.begin();
57 | Serial.print("server is at ");
58 | Serial.println(Ethernet.localIP());
59 |
60 | while (1) {
61 | // listen for incoming clients
62 | EthernetClient client = server.available();
63 | if (client) {
64 | Serial.println("new client");
65 | // an http request ends with a blank line
66 | bool currentLineIsBlank = true;
67 | while (client.connected()) {
68 | if (client.available()) {
69 | char c = client.read();
70 | Serial.write(c);
71 | // if you've gotten to the end of the line (received a newline
72 | // character) and the line is blank, the http request has ended,
73 | // so you can send a reply
74 | if (c == '\n' && currentLineIsBlank) {
75 | // send a standard http response header
76 | client.println("HTTP/1.1 200 OK");
77 | client.println("Content-Type: text/html");
78 | client.println("Connection: close"); // the connection will be closed after completion of the response
79 | client.println("Refresh: 5"); // refresh the page automatically every 5 sec
80 | client.println();
81 | client.println("");
82 | client.println("");
83 | // output the value of each analog input pin
84 | for (int analogChannel = 0; analogChannel < ANALOG_CHANEL_NUMBER; analogChannel++) {
85 | client.print("analog input ");
86 | client.print(analogChannel);
87 | client.print(" is ");
88 | client.print(sensorReading[analogChannel]);
89 | client.println("
");
90 | }
91 | client.println("");
92 | break;
93 | }
94 | if (c == '\n') {
95 | // you're starting a new line
96 | currentLineIsBlank = true;
97 | } else if (c != '\r') {
98 | // you've gotten a character on the current line
99 | currentLineIsBlank = false;
100 | }
101 | }
102 | }
103 | // give the web browser time to receive the data
104 | delay(1);
105 | // close the connection:
106 | client.stop();
107 | Serial.println("client disconnected");
108 | }
109 | }
110 | }
111 |
112 | void setup() {
113 | // Open serial communications and wait for port to open:
114 | Serial.begin(9600);
115 | while (!Serial) {
116 | ; // wait for serial port to connect. Needed for native USB port only
117 | }
118 |
119 | portBASE_TYPE s = xTaskCreate(taskETH, NULL, 200, NULL, 1, NULL);
120 | if (s != pdPASS) {
121 | printf("Ethernet task creation failed\n");
122 | while (1);
123 | }
124 |
125 | s = xTaskCreate(taskAnalog, NULL, 200, NULL, 2, NULL);
126 | if (s != pdPASS) {
127 | printf("Analog task creation failed\n");
128 | while (1);
129 | }
130 |
131 | vTaskStartScheduler();
132 | Serial.println("Scheduler failed");
133 | while (1);
134 | }
135 |
136 |
137 | void loop() {
138 | // Not used.
139 | }
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 | #######################################
2 | # Syntax Coloring Map For Ethernet
3 | #######################################
4 |
5 | #######################################
6 | # Datatypes (KEYWORD1)
7 | #######################################
8 |
9 | Ethernet KEYWORD1 Ethernet
10 | EthernetClient KEYWORD1 EthernetClient
11 | EthernetServer KEYWORD1 EthernetServer
12 | IPAddress KEYWORD1 EthernetIPAddress
13 |
14 | #######################################
15 | # Methods and Functions (KEYWORD2)
16 | #######################################
17 |
18 | status KEYWORD2
19 | connect KEYWORD2
20 | write KEYWORD2
21 | available KEYWORD2
22 | read KEYWORD2
23 | peek KEYWORD2
24 | flush KEYWORD2
25 | stop KEYWORD2
26 | connected KEYWORD2
27 | accept KEYWORD2
28 | begin KEYWORD2
29 | beginMulticast KEYWORD2
30 | beginPacket KEYWORD2
31 | endPacket KEYWORD2
32 | parsePacket KEYWORD2
33 | remoteIP KEYWORD2
34 | remotePort KEYWORD2
35 | getSocketNumber KEYWORD2
36 | localIP KEYWORD2
37 | localPort KEYWORD2
38 | maintain KEYWORD2
39 | linkStatus KEYWORD2
40 | MACAddress KEYWORD2
41 | setMACAddress KEYWORD2
42 | subnetMask KEYWORD2
43 | gatewayIP KEYWORD2
44 | dnsServerIP KEYWORD2
45 | setDnsServerIP KEYWORD2
46 | setConnectionTimeout KEYWORD2
47 |
48 | #######################################
49 | # Constants (LITERAL1)
50 | #######################################
51 | LinkON LITERAL1
52 | LinkOFF LITERAL1
53 |
--------------------------------------------------------------------------------
/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "STM32Ethernet",
3 | "keywords": "Ethernet",
4 | "description": "Arduino library to support Ethernet for STM32 based board.",
5 | "repository":
6 | {
7 | "type": "git",
8 | "url": "https://github.com/stm32duino/STM32Ethernet"
9 | },
10 | "version": "1.4.0",
11 | "frameworks": "arduino",
12 | "platforms": "ststm32",
13 | "build": {
14 | "libArchive": false
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=STM32duino STM32Ethernet
2 | version=1.4.0
3 | author=Various
4 | maintainer=STMicroelectronics
5 | sentence=Enables network connection (local and Internet) using the STM32 Board.
6 | paragraph=With this library you can use the STM32 board to connect to Internet. The library provides both Client and server functionalities. The library permits you to connect to a local network also with DHCP and to resolve DNS. This library depends on the LwIP library.
7 | category=Communication
8 | url=https://github.com/stm32duino/STM32Ethernet
9 | architectures=stm32
10 | depends=STM32duino LwIP
11 |
--------------------------------------------------------------------------------
/src/Dhcp.cpp:
--------------------------------------------------------------------------------
1 | // DHCP Library v0.3 - April 25, 2009
2 | // Author: Jordan Terrell - blog.jordanterrell.com
3 |
4 | #include
5 | #include
6 | #include "Dhcp.h"
7 | #include "Arduino.h"
8 | #include "utility/stm32_eth.h"
9 |
10 | int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
11 | {
12 | UNUSED(responseTimeout);
13 | _timeout = timeout;
14 | _dhcp_lease_state = DHCP_CHECK_NONE;
15 |
16 | // zero out _dhcpMacAddr
17 | memset(_dhcpMacAddr, 0, 6);
18 | reset_DHCP_lease();
19 | if (mac == NULL) {
20 | // use mac from Ethernet chip
21 | stm32_eth_get_macaddr(_dhcpMacAddr);
22 | } else {
23 | memcpy((void *)_dhcpMacAddr, (void *)mac, 6);
24 | }
25 | _dhcp_state = STATE_DHCP_START;
26 | stm32_set_DHCP_state(_dhcp_state);
27 | return request_DHCP_lease();
28 | }
29 |
30 | void DhcpClass::reset_DHCP_lease()
31 | {
32 | _dhcp_state = STATE_DHCP_RELEASE;
33 | stm32_set_DHCP_state(_dhcp_state);
34 | stm32_eth_scheduler();
35 | _dhcp_state = stm32_get_DHCP_state();
36 | }
37 |
38 | //return:0 on error, 1 if request is sent and response is received
39 | int DhcpClass::request_DHCP_lease()
40 | {
41 |
42 | int result = 0;
43 | unsigned long startTime = millis();
44 |
45 | while (_dhcp_state != STATE_DHCP_LEASED) {
46 | stm32_eth_scheduler();
47 | _dhcp_state = stm32_get_DHCP_state();
48 |
49 | if (result != 1 && ((millis() - startTime) > _timeout)) {
50 | reset_DHCP_lease();
51 | break;
52 | }
53 | }
54 |
55 | if (_dhcp_state == STATE_DHCP_LEASED) {
56 | result = 1;
57 | }
58 |
59 | return result;
60 | }
61 |
62 | /*
63 | returns:
64 | 0/DHCP_CHECK_NONE: nothing happened
65 | 1/DHCP_CHECK_RENEW_FAIL: renew failed
66 | 2/DHCP_CHECK_RENEW_OK: renew success
67 | 3/DHCP_CHECK_REBIND_FAIL: rebind fail
68 | 4/DHCP_CHECK_REBIND_OK: rebind success
69 | */
70 | int DhcpClass::checkLease()
71 | {
72 | int rc = DHCP_CHECK_NONE;
73 |
74 | stm32_eth_scheduler();
75 | rc = stm32_get_DHCP_lease_state();
76 |
77 | if (rc != _dhcp_lease_state) {
78 | switch (_dhcp_lease_state) {
79 | case DHCP_CHECK_NONE:
80 | _dhcp_lease_state = rc;
81 | rc = DHCP_CHECK_NONE;
82 | break;
83 |
84 | case DHCP_CHECK_RENEW_OK:
85 | _dhcp_lease_state = rc;
86 | if (rc == DHCP_CHECK_NONE) {
87 | rc = DHCP_CHECK_RENEW_OK;
88 | } else {
89 | rc = DHCP_CHECK_RENEW_FAIL;
90 | }
91 | break;
92 |
93 | case DHCP_CHECK_REBIND_OK:
94 | _dhcp_lease_state = rc;
95 | if (rc == DHCP_CHECK_NONE) {
96 | rc = DHCP_CHECK_REBIND_OK;
97 | } else {
98 | rc = DHCP_CHECK_REBIND_FAIL;
99 | }
100 | break;
101 |
102 | default:
103 | _dhcp_lease_state = DHCP_CHECK_NONE;
104 | break;
105 | }
106 | }
107 |
108 | return rc;
109 | }
110 |
111 | IPAddress DhcpClass::getLocalIp()
112 | {
113 | return IPAddress(stm32_eth_get_ipaddr());
114 | }
115 |
116 | IPAddress DhcpClass::getSubnetMask()
117 | {
118 | return IPAddress(stm32_eth_get_netmaskaddr());
119 | }
120 |
121 | IPAddress DhcpClass::getGatewayIp()
122 | {
123 | return IPAddress(stm32_eth_get_gwaddr());
124 | }
125 |
126 | IPAddress DhcpClass::getDhcpServerIp()
127 | {
128 | return IPAddress(stm32_eth_get_dhcpaddr());
129 | }
130 |
131 | IPAddress DhcpClass::getDnsServerIp()
132 | {
133 | return IPAddress(stm32_eth_get_dnsaddr());
134 | }
135 |
--------------------------------------------------------------------------------
/src/Dhcp.h:
--------------------------------------------------------------------------------
1 | // DHCP Library v0.3 - April 25, 2009
2 | // Author: Jordan Terrell - blog.jordanterrell.com
3 |
4 | #ifndef Dhcp_h
5 | #define Dhcp_h
6 |
7 | #include "EthernetUdp.h"
8 |
9 | /* DHCP state machine. */
10 | #define STATE_DHCP_STOP DHCP_OFF
11 | #define STATE_DHCP_START DHCP_START
12 | #define STATE_DHCP_DISCOVER DHCP_WAIT_ADDRESS
13 | #define STATE_DHCP_REQUEST 0
14 | #define STATE_DHCP_LEASED DHCP_ADDRESS_ASSIGNED
15 | #define STATE_DHCP_REREQUEST 0
16 | #define STATE_DHCP_RELEASE DHCP_ASK_RELEASE
17 |
18 | #define DHCP_CHECK_NONE (0)
19 | #define DHCP_CHECK_RENEW_FAIL (1)
20 | #define DHCP_CHECK_RENEW_OK (2)
21 | #define DHCP_CHECK_REBIND_FAIL (3)
22 | #define DHCP_CHECK_REBIND_OK (4)
23 |
24 | class DhcpClass {
25 | private:
26 | uint8_t _dhcpMacAddr[6];
27 | unsigned long _timeout;
28 | uint8_t _dhcp_lease_state;
29 | uint8_t _dhcp_state;
30 |
31 | int request_DHCP_lease();
32 | void reset_DHCP_lease();
33 |
34 | public:
35 | IPAddress getLocalIp();
36 | IPAddress getSubnetMask();
37 | IPAddress getGatewayIp();
38 | IPAddress getDhcpServerIp();
39 | IPAddress getDnsServerIp();
40 |
41 | int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
42 | int checkLease();
43 | };
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/src/Dns.cpp:
--------------------------------------------------------------------------------
1 | // Arduino DNS client for WizNet5100-based Ethernet shield
2 | // (c) Copyright 2009-2010 MCQN Ltd.
3 | // Released under Apache License, version 2.0
4 |
5 | #include "EthernetUdp.h"
6 | #include "utility/stm32_eth.h"
7 |
8 | #include "Dns.h"
9 | #include
10 | #include "Arduino.h"
11 |
12 | // Possible return codes from ProcessResponse
13 | #define SUCCESS 1
14 | #define TIMED_OUT -1
15 | #define INVALID_SERVER -2
16 | #define TRUNCATED -3
17 | #define INVALID_RESPONSE -4
18 |
19 | void DNSClient::begin(const IPAddress &aDNSServer)
20 | {
21 | iDNSServer = aDNSServer;
22 | stm32_dns_init(iDNSServer.raw_address());
23 | }
24 |
25 |
26 | int DNSClient::inet_aton(const char *address, IPAddress &result)
27 | {
28 | uint16_t acc = 0; // Accumulator
29 | uint8_t dots = 0;
30 |
31 | if (address == NULL) {
32 | return 0;
33 | }
34 |
35 | while (*address) {
36 | char c = *address++;
37 | if (c >= '0' && c <= '9') {
38 | acc = acc * 10 + (c - '0');
39 | if (acc > 255) {
40 | // Value out of [0..255] range
41 | return 0;
42 | }
43 | } else if (c == '.') {
44 | if (dots == 3) {
45 | // Too much dots (there must be 3 dots)
46 | return 0;
47 | }
48 | result[dots++] = acc;
49 | acc = 0;
50 | } else {
51 | // Invalid char
52 | return 0;
53 | }
54 | }
55 |
56 | if (dots != 3) {
57 | // Too few dots (there must be 3 dots)
58 | return 0;
59 | }
60 | result[3] = acc;
61 | return 1;
62 | }
63 |
64 | int DNSClient::getHostByName(const char *aHostname, IPAddress &aResult)
65 | {
66 | int ret = 0;
67 | uint32_t ipResult = 0;
68 |
69 | // See if it's a numeric IP address
70 | if (inet_aton(aHostname, aResult)) {
71 | // It is, our work here is done
72 | return SUCCESS;
73 | }
74 |
75 | // Check we've got a valid DNS server to use
76 | if (iDNSServer == INADDR_NONE) {
77 | return INVALID_SERVER;
78 | }
79 |
80 | ret = stm32_dns_gethostbyname(aHostname, &ipResult);
81 | aResult = IPAddress(ipResult);
82 |
83 | return ret;
84 | }
85 |
86 | /* Deprecated function. Do not use anymore. */
87 | uint16_t DNSClient::BuildRequest(const char *aName)
88 | {
89 | UNUSED(aName);
90 | return 0;
91 | }
92 |
93 | /* Deprecated function. Do not use anymore. */
94 | uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress &aAddress)
95 | {
96 | UNUSED(aTimeout);
97 | UNUSED(aAddress);
98 | // If we get here then we haven't found an answer
99 | return -10;//INVALID_RESPONSE;
100 | }
101 |
--------------------------------------------------------------------------------
/src/Dns.h:
--------------------------------------------------------------------------------
1 | // Arduino DNS client for WizNet5100-based Ethernet shield
2 | // (c) Copyright 2009-2010 MCQN Ltd.
3 | // Released under Apache License, version 2.0
4 |
5 | #ifndef DNSClient_h
6 | #define DNSClient_h
7 |
8 | #include
9 |
10 | class DNSClient {
11 | public:
12 | // ctor
13 | void begin(const IPAddress &aDNSServer);
14 |
15 | /** Convert a numeric IP address string into a four-byte IP address.
16 | @param aIPAddrString IP address to convert
17 | @param aResult IPAddress structure to store the returned IP address
18 | @result 1 if aIPAddrString was successfully converted to an IP address,
19 | else error code
20 | */
21 | int inet_aton(const char *aIPAddrString, IPAddress &aResult);
22 |
23 | /** Resolve the given hostname to an IP address.
24 | @param aHostname Name to be resolved
25 | @param aResult IPAddress structure to store the returned IP address
26 | @result 1 if aIPAddrString was successfully converted to an IP address,
27 | else error code
28 | */
29 | int getHostByName(const char *aHostname, IPAddress &aResult);
30 |
31 | protected:
32 | uint16_t BuildRequest(const char *aName);
33 | uint16_t ProcessResponse(uint16_t aTimeout, IPAddress &aAddress);
34 |
35 | IPAddress iDNSServer;
36 | };
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/src/EthernetClient.cpp:
--------------------------------------------------------------------------------
1 | extern "C" {
2 | #include "string.h"
3 | }
4 |
5 | #include "Arduino.h"
6 |
7 | #include "STM32Ethernet.h"
8 | #include "EthernetClient.h"
9 | #include "EthernetServer.h"
10 | #include "Dns.h"
11 |
12 | EthernetClient::EthernetClient()
13 | : _tcp_client(NULL)
14 | {
15 | }
16 |
17 | /* Deprecated constructor. Keeps compatibility with W5100 architecture
18 | sketches but sock is ignored. */
19 | EthernetClient::EthernetClient(uint8_t sock)
20 | : _tcp_client(NULL)
21 | {
22 | UNUSED(sock);
23 | }
24 |
25 | EthernetClient::EthernetClient(struct tcp_struct *tcpClient)
26 | {
27 | _tcp_client = tcpClient;
28 | }
29 |
30 | int EthernetClient::connect(const char *host, uint16_t port)
31 | {
32 | // Look up the host first
33 | int ret = 0;
34 | DNSClient dns;
35 | IPAddress remote_addr;
36 |
37 | dns.begin(Ethernet.dnsServerIP());
38 | ret = dns.getHostByName(host, remote_addr);
39 | if (ret == 1) {
40 | return connect(remote_addr, port);
41 | } else {
42 | return 0;
43 | }
44 | }
45 |
46 | int EthernetClient::connect(IPAddress ip, uint16_t port)
47 | {
48 | if (_tcp_client == NULL) {
49 | /* Allocates memory for client */
50 | _tcp_client = (struct tcp_struct *)mem_malloc(sizeof(struct tcp_struct));
51 |
52 | if (_tcp_client == NULL) {
53 | return 0;
54 | }
55 | }
56 |
57 | /* Creates a new TCP protocol control block */
58 | _tcp_client->pcb = tcp_new();
59 |
60 | if (_tcp_client->pcb == NULL) {
61 | return 0;
62 | }
63 |
64 | _tcp_client->data.p = NULL;
65 | _tcp_client->data.available = 0;
66 | _tcp_client->state = TCP_NONE;
67 |
68 | uint32_t startTime = millis();
69 | ip_addr_t ipaddr;
70 | tcp_arg(_tcp_client->pcb, _tcp_client);
71 | if (ERR_OK != tcp_connect(_tcp_client->pcb, u8_to_ip_addr(rawIPAddress(ip), &ipaddr), port, &tcp_connected_callback)) {
72 | stop();
73 | return 0;
74 | }
75 |
76 | startTime = millis();
77 | while (_tcp_client->state == TCP_NONE) {
78 | stm32_eth_scheduler();
79 | if ((_tcp_client->state == TCP_CLOSING) || ((millis() - startTime) >= _connectionTimeout)) {
80 | stop();
81 | return 0;
82 | }
83 | }
84 |
85 | return 1;
86 | }
87 |
88 | size_t EthernetClient::write(uint8_t b)
89 | {
90 | return write(&b, 1);
91 | }
92 |
93 | size_t EthernetClient::write(const uint8_t *buf, size_t size)
94 | {
95 | if ((_tcp_client == NULL) || (_tcp_client->pcb == NULL) ||
96 | (buf == NULL) || (size == 0)) {
97 | return 0;
98 | }
99 |
100 | /* If client not connected or accepted, it can't write because connection is
101 | not ready */
102 | if ((_tcp_client->state != TCP_ACCEPTED) &&
103 | (_tcp_client->state != TCP_CONNECTED)) {
104 | return 0;
105 | }
106 |
107 | size_t max_send_size, bytes_to_send;
108 | size_t bytes_sent = 0;
109 | size_t bytes_left = size;
110 | err_t res;
111 |
112 | do {
113 | max_send_size = tcp_sndbuf(_tcp_client->pcb);
114 | bytes_to_send = bytes_left > max_send_size ? max_send_size : bytes_left;
115 |
116 | if (bytes_to_send > 0) {
117 | res = tcp_write(_tcp_client->pcb, &buf[bytes_sent], bytes_to_send, TCP_WRITE_FLAG_COPY);
118 |
119 | if (res == ERR_OK) {
120 | bytes_sent += bytes_to_send;
121 | bytes_left = size - bytes_sent;
122 | } else if (res != ERR_MEM) {
123 | // other error, cannot continue
124 | return 0;
125 | }
126 | }
127 |
128 | //Force to send data right now!
129 | if (ERR_OK != tcp_output(_tcp_client->pcb)) {
130 | return 0;
131 | }
132 | stm32_eth_scheduler();
133 |
134 | } while (bytes_sent != size);
135 |
136 | return size;
137 | }
138 |
139 | int EthernetClient::available()
140 | {
141 | stm32_eth_scheduler();
142 | if (_tcp_client != NULL) {
143 | return _tcp_client->data.available;
144 | }
145 | return 0;
146 | }
147 |
148 | int EthernetClient::read()
149 | {
150 | uint8_t b;
151 | if ((_tcp_client != NULL) && (_tcp_client->data.p != NULL)) {
152 | stm32_get_data(&(_tcp_client->data), &b, 1);
153 | return b;
154 | }
155 | // No data available
156 | return -1;
157 | }
158 |
159 | int EthernetClient::read(uint8_t *buf, size_t size)
160 | {
161 | if ((_tcp_client != NULL) && (_tcp_client->data.p != NULL)) {
162 | return stm32_get_data(&(_tcp_client->data), buf, size);
163 | }
164 | return -1;
165 | }
166 |
167 | int EthernetClient::peek()
168 | {
169 | uint8_t b;
170 | // Unlike recv, peek doesn't check to see if there's any data available, so we must
171 | if (!available()) {
172 | return -1;
173 | }
174 | b = pbuf_get_at(_tcp_client->data.p, _tcp_client->data.p->tot_len - _tcp_client->data.available);
175 | return b;
176 | }
177 |
178 | void EthernetClient::flush()
179 | {
180 | if ((_tcp_client == NULL) || (_tcp_client->pcb == NULL)) {
181 | return;
182 | }
183 | tcp_output(_tcp_client->pcb);
184 | stm32_eth_scheduler();
185 | }
186 |
187 | void EthernetClient::stop()
188 | {
189 | if (_tcp_client == NULL) {
190 | return;
191 | }
192 |
193 | // close tcp connection if not closed yet
194 | if (status() != TCP_CLOSING) {
195 | tcp_connection_close(_tcp_client->pcb, _tcp_client);
196 | }
197 | mem_free(_tcp_client);
198 | _tcp_client = NULL;
199 | }
200 |
201 | uint8_t EthernetClient::connected()
202 | {
203 | uint8_t s = status();
204 | return ((available() && (s == TCP_CLOSING)) ||
205 | (s == TCP_CONNECTED) || (s == TCP_ACCEPTED));
206 | }
207 |
208 | uint8_t EthernetClient::status()
209 | {
210 | if (_tcp_client == NULL) {
211 | return TCP_NONE;
212 | }
213 | return _tcp_client->state;
214 | }
215 |
216 | // the next function allows us to use the client returned by
217 | // EthernetServer::available() as the condition in an if-statement.
218 |
219 | EthernetClient::operator bool()
220 | {
221 | return (_tcp_client && (_tcp_client->state != TCP_CLOSING));
222 | }
223 |
224 | bool EthernetClient::operator==(const EthernetClient &rhs)
225 | {
226 | return _tcp_client == rhs._tcp_client && _tcp_client->pcb == rhs._tcp_client->pcb;
227 | }
228 |
229 | /* This function is not a function defined by Arduino. This is a function
230 | specific to the W5100 architecture. To keep the compatibility we leave it and
231 | returns always 0. */
232 | uint8_t EthernetClient::getSocketNumber()
233 | {
234 | return 0;
235 | }
236 |
--------------------------------------------------------------------------------
/src/EthernetClient.h:
--------------------------------------------------------------------------------
1 | #ifndef ethernetclient_h
2 | #define ethernetclient_h
3 | #include "Arduino.h"
4 | #include "Print.h"
5 | #include "Client.h"
6 | #include "IPAddress.h"
7 | #include "utility/stm32_eth.h"
8 |
9 | class EthernetClient : public Client {
10 |
11 | public:
12 | EthernetClient();
13 | EthernetClient(uint8_t sock);
14 | EthernetClient(struct tcp_struct *tcpClient);
15 |
16 | uint8_t status();
17 | virtual int connect(IPAddress ip, uint16_t port);
18 | virtual int connect(const char *host, uint16_t port);
19 | virtual size_t write(uint8_t);
20 | virtual size_t write(const uint8_t *buf, size_t size);
21 | virtual int available();
22 | virtual int read();
23 | virtual int read(uint8_t *buf, size_t size);
24 | virtual int peek();
25 | virtual void flush();
26 | virtual void stop();
27 | virtual uint8_t connected();
28 | virtual operator bool();
29 | virtual bool operator==(const bool value)
30 | {
31 | return bool() == value;
32 | }
33 | virtual bool operator!=(const bool value)
34 | {
35 | return bool() != value;
36 | }
37 | virtual bool operator==(const EthernetClient &);
38 | virtual bool operator!=(const EthernetClient &rhs)
39 | {
40 | return !this->operator==(rhs);
41 | };
42 | uint8_t getSocketNumber();
43 | virtual uint16_t localPort()
44 | {
45 | return (_tcp_client->pcb->local_port);
46 | };
47 | virtual IPAddress remoteIP()
48 | {
49 | return (IPAddress(_tcp_client->pcb->remote_ip.addr));
50 | };
51 | virtual uint16_t remotePort()
52 | {
53 | return (_tcp_client->pcb->remote_port);
54 | };
55 | void setConnectionTimeout(uint16_t timeout)
56 | {
57 | _connectionTimeout = timeout;
58 | }
59 |
60 | friend class EthernetServer;
61 |
62 | using Print::write;
63 |
64 | private:
65 | struct tcp_struct *_tcp_client;
66 | uint16_t _connectionTimeout = 10000;
67 | };
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/src/EthernetServer.cpp:
--------------------------------------------------------------------------------
1 | extern "C" {
2 | #include "string.h"
3 | }
4 |
5 | #include "STM32Ethernet.h"
6 | #include "EthernetClient.h"
7 | #include "EthernetServer.h"
8 |
9 | EthernetServer::EthernetServer(uint16_t port)
10 | {
11 | _port = port;
12 | for (int i = 0; i < MAX_CLIENT; i++) {
13 | _tcp_client[i] = {};
14 | }
15 | _tcp_server = {};
16 | }
17 |
18 | void EthernetServer::begin()
19 | {
20 | if (_tcp_server.pcb != NULL) {
21 | return;
22 | }
23 |
24 | _tcp_server.pcb = tcp_new();
25 |
26 | if (_tcp_server.pcb == NULL) {
27 | return;
28 | }
29 |
30 | tcp_arg(_tcp_server.pcb, &_tcp_client);
31 | _tcp_server.state = TCP_NONE;
32 |
33 | if (ERR_OK != tcp_bind(_tcp_server.pcb, IP_ADDR_ANY, _port)) {
34 | memp_free(MEMP_TCP_PCB, _tcp_server.pcb);
35 | _tcp_server.pcb = NULL;
36 | return;
37 | }
38 |
39 | _tcp_server.pcb = tcp_listen(_tcp_server.pcb);
40 | tcp_accept(_tcp_server.pcb, tcp_accept_callback);
41 | }
42 |
43 | void EthernetServer::begin(uint16_t port)
44 | {
45 | _port = port;
46 | begin();
47 | }
48 |
49 | void EthernetServer::end(void)
50 | {
51 | /* Free client */
52 | for (int n = 0; n < MAX_CLIENT; n++) {
53 | if (_tcp_client[n] != NULL) {
54 | EthernetClient client(_tcp_client[n]);
55 | client.stop();
56 | _tcp_client[n] = NULL;
57 | }
58 | }
59 | if (_tcp_server.pcb != NULL) {
60 | tcp_close(_tcp_server.pcb);
61 | _tcp_server.pcb = NULL;
62 | }
63 | }
64 |
65 | void EthernetServer::accept()
66 | {
67 | /* Free client if disconnected */
68 | for (int n = 0; n < MAX_CLIENT; n++) {
69 | if (_tcp_client[n] != NULL) {
70 | EthernetClient client(_tcp_client[n]);
71 | if (client.status() == TCP_CLOSING) {
72 | mem_free(_tcp_client[n]);
73 | _tcp_client[n] = NULL;
74 | }
75 | }
76 | }
77 | }
78 |
79 | EthernetClient EthernetServer::available()
80 | {
81 | accept();
82 |
83 | for (int n = 0; n < MAX_CLIENT; n++) {
84 | if (_tcp_client[n] != NULL) {
85 | if (_tcp_client[n]->pcb != NULL) {
86 | EthernetClient client(_tcp_client[n]);
87 | uint8_t s = client.status();
88 | if (s == TCP_ACCEPTED) {
89 | if (client.available()) {
90 | return client;
91 | }
92 | }
93 | }
94 | }
95 | }
96 |
97 | struct tcp_struct *default_client = NULL;
98 | return EthernetClient(default_client);
99 | }
100 |
101 | size_t EthernetServer::write(uint8_t b)
102 | {
103 | return write(&b, 1);
104 | }
105 |
106 | size_t EthernetServer::write(const uint8_t *buffer, size_t size)
107 | {
108 | size_t n = 0;
109 |
110 | accept();
111 |
112 | for (int i = 0; i < MAX_CLIENT; i++) {
113 | if (_tcp_client[i] != NULL) {
114 | if (_tcp_client[i]->pcb != NULL) {
115 | EthernetClient client(_tcp_client[i]);
116 | uint8_t s = client.status();
117 | if (s == TCP_ACCEPTED) {
118 | n += client.write(buffer, size);
119 | }
120 | }
121 | }
122 | }
123 |
124 | return n;
125 | }
126 |
127 | EthernetServer::operator bool()
128 | {
129 | // server is listening for incoming clients
130 | return ((_tcp_server.pcb != NULL) && (_tcp_server.pcb->state == LISTEN));
131 | }
132 |
--------------------------------------------------------------------------------
/src/EthernetServer.h:
--------------------------------------------------------------------------------
1 | #ifndef ethernetserver_h
2 | #define ethernetserver_h
3 |
4 | #include "Server.h"
5 |
6 | class EthernetClient;
7 |
8 | class EthernetServer :
9 | public Server {
10 | private:
11 | uint16_t _port;
12 | struct tcp_struct _tcp_server;
13 | struct tcp_struct *_tcp_client[MAX_CLIENT];
14 |
15 | void accept(void);
16 | public:
17 | EthernetServer(uint16_t port = 80);
18 | EthernetClient available();
19 | virtual void begin();
20 | virtual void begin(uint16_t port);
21 | void end(void);
22 | virtual size_t write(uint8_t);
23 | virtual size_t write(const uint8_t *buf, size_t size);
24 | virtual operator bool();
25 | using Print::write;
26 | };
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/src/EthernetUdp.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
3 | * This version only offers minimal wrapping of socket.c/socket.h
4 | * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/
5 | *
6 | * MIT License:
7 | * Copyright (c) 2008 Bjoern Hartmann
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | * THE SOFTWARE.
25 | *
26 | * bjoern@cs.stanford.edu 12/30/2008
27 | */
28 | #include "STM32Ethernet.h"
29 | #include "Udp.h"
30 | #include "Dns.h"
31 |
32 | #include "lwip/igmp.h"
33 | #include "lwip/ip_addr.h"
34 |
35 | /* Constructor */
36 | EthernetUDP::EthernetUDP() {}
37 |
38 | /* Start EthernetUDP socket, listening at local port PORT */
39 | uint8_t EthernetUDP::begin(uint16_t port)
40 | {
41 | return begin(Ethernet.localIP(), port);
42 | }
43 |
44 | /* Start EthernetUDP socket, listening at local IP ip and port PORT */
45 | uint8_t EthernetUDP::begin(IPAddress ip, uint16_t port, bool multicast)
46 | {
47 | // Can create a single udp connection per socket
48 | if (_udp.pcb != NULL) {
49 | return 0;
50 | }
51 |
52 | _udp.pcb = udp_new();
53 |
54 | if (_udp.pcb == NULL) {
55 | return 0;
56 | }
57 |
58 | ip_addr_t ipaddr;
59 | err_t err;
60 | u8_to_ip_addr(rawIPAddress(ip), &ipaddr);
61 | if (multicast) {
62 | err = udp_bind(_udp.pcb, IP_ADDR_ANY, port);
63 | } else {
64 | err = udp_bind(_udp.pcb, &ipaddr, port);
65 | }
66 |
67 | if (ERR_OK != err) {
68 | stop();
69 | return 0;
70 | }
71 |
72 | #if LWIP_IGMP
73 | if ((multicast) && (ERR_OK != igmp_joingroup(IP_ADDR_ANY, &ipaddr))) {
74 | return 0;
75 | }
76 | #endif
77 | udp_recv(_udp.pcb, &udp_receive_callback, &_udp);
78 |
79 | _port = port;
80 | _remaining = 0;
81 |
82 | stm32_eth_scheduler();
83 |
84 | return 1;
85 | }
86 |
87 | /* return number of bytes available in the current packet,
88 | will return zero if parsePacket hasn't been called yet */
89 | int EthernetUDP::available()
90 | {
91 | return _remaining;
92 | }
93 |
94 | /* Release any resources being used by this EthernetUDP instance */
95 | void EthernetUDP::stop()
96 | {
97 | if (_udp.pcb != NULL) {
98 | udp_disconnect(_udp.pcb);
99 | udp_remove(_udp.pcb);
100 | _udp.pcb = NULL;
101 | }
102 |
103 | stm32_eth_scheduler();
104 | }
105 |
106 | int EthernetUDP::beginPacket(const char *host, uint16_t port)
107 | {
108 | // Look up the host first
109 | int ret = 0;
110 | DNSClient dns;
111 | IPAddress remote_addr;
112 |
113 | dns.begin(Ethernet.dnsServerIP());
114 | ret = dns.getHostByName(host, remote_addr);
115 | if (ret == 1) {
116 | return beginPacket(remote_addr, port);
117 | } else {
118 | return ret;
119 | }
120 | }
121 |
122 | int EthernetUDP::beginPacket(IPAddress ip, uint16_t port)
123 | {
124 | if (_udp.pcb == NULL) {
125 | return 0;
126 | }
127 |
128 | _sendtoIP = ip;
129 | _sendtoPort = port;
130 |
131 | udp_recv(_udp.pcb, &udp_receive_callback, &_udp);
132 | stm32_eth_scheduler();
133 |
134 | return 1;
135 | }
136 |
137 | int EthernetUDP::endPacket()
138 | {
139 | if ((_udp.pcb == NULL) || (_data == NULL)) {
140 | return 0;
141 | }
142 |
143 | ip_addr_t ipaddr;
144 | if (ERR_OK != udp_sendto(_udp.pcb, _data, u8_to_ip_addr(rawIPAddress(_sendtoIP), &ipaddr), _sendtoPort)) {
145 | _data = stm32_free_data(_data);
146 | return 0;
147 | }
148 |
149 | _data = stm32_free_data(_data);
150 | stm32_eth_scheduler();
151 |
152 | return 1;
153 | }
154 |
155 | size_t EthernetUDP::write(uint8_t byte)
156 | {
157 | return write(&byte, 1);
158 | }
159 |
160 | size_t EthernetUDP::write(const uint8_t *buffer, size_t size)
161 | {
162 | _data = stm32_new_data(_data, buffer, size);
163 | if (_data == NULL) {
164 | return 0;
165 | }
166 |
167 | return size;
168 | }
169 |
170 | int EthernetUDP::parsePacket()
171 | {
172 | // discard any remaining bytes in the last packet
173 | // while (_remaining) {
174 | // // could this fail (loop endlessly) if _remaining > 0 and recv in read fails?
175 | // // should only occur if recv fails after telling us the data is there, lets
176 | // // hope the w5100 always behaves :)
177 | // read();
178 | // }
179 |
180 | stm32_eth_scheduler();
181 |
182 | if (_udp.data.available > 0) {
183 | _remoteIP = IPAddress(ip_addr_to_u32(&(_udp.ip)));
184 | _remotePort = _udp.port;
185 | _remaining = _udp.data.available;
186 |
187 | return _remaining;
188 | }
189 | // There aren't any packets available
190 | return 0;
191 | }
192 |
193 | int EthernetUDP::read()
194 | {
195 | uint8_t byte;
196 |
197 | if (_udp.data.p == NULL) {
198 | return -1;
199 | }
200 |
201 | if (_remaining > 0) {
202 | if (read(&byte, 1) > 0) {
203 | return byte;
204 | }
205 | }
206 |
207 | // If we get here, there's no data available
208 | return -1;
209 | }
210 |
211 | int EthernetUDP::read(unsigned char *buffer, size_t len)
212 | {
213 | if (_udp.data.p == NULL) {
214 | return -1;
215 | }
216 |
217 | if (_remaining > 0) {
218 | int got;
219 |
220 | if (_remaining <= len) {
221 | // data should fit in the buffer
222 | got = (int)stm32_get_data(&(_udp.data), (uint8_t *)buffer, _remaining);
223 | } else {
224 | // too much data for the buffer,
225 | // grab as much as will fit
226 | got = (int)stm32_get_data(&(_udp.data), (uint8_t *)buffer, len);
227 | }
228 |
229 | if (got > 0) {
230 | _remaining -= got;
231 | return got;
232 | }
233 |
234 | }
235 |
236 | // If we get here, there's no data available or recv failed
237 | return -1;
238 |
239 | }
240 |
241 | int EthernetUDP::peek()
242 | {
243 | uint8_t b;
244 | // Unlike recv, peek doesn't check to see if there's any data available, so we must.
245 | // If the user hasn't called parsePacket yet then return nothing otherwise they
246 | // may get the UDP header
247 | if (!_remaining) {
248 | return -1;
249 | }
250 | b = pbuf_get_at(_udp.data.p, _udp.data.p->tot_len - _udp.data.available);
251 | return b;
252 | }
253 |
254 | void EthernetUDP::flush()
255 | {
256 | // TODO: we should wait for TX buffer to be emptied
257 | }
258 |
259 | /* Start EthernetUDP socket, listening at local port PORT */
260 | uint8_t EthernetUDP::beginMulticast(IPAddress ip, uint16_t port)
261 | {
262 | return begin(ip, port, true);
263 | }
264 |
265 | #if LWIP_UDP
266 | void EthernetUDP::onDataArrival(std::function onDataArrival_fn)
267 | {
268 | _udp.onDataArrival = onDataArrival_fn;
269 | }
270 | #endif
271 |
--------------------------------------------------------------------------------
/src/EthernetUdp.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
3 | * This version only offers minimal wrapping of socket.c/socket.h
4 | * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/
5 | *
6 | * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
7 | * 1) UDP does not guarantee the order in which assembled UDP packets are received. This
8 | * might not happen often in practice, but in larger network topologies, a UDP
9 | * packet can be received out of sequence.
10 | * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
11 | * aware of it. Again, this may not be a concern in practice on small local networks.
12 | * For more information, see http://www.cafeaulait.org/course/week12/35.html
13 | *
14 | * MIT License:
15 | * Copyright (c) 2008 Bjoern Hartmann
16 | * Permission is hereby granted, free of charge, to any person obtaining a copy
17 | * of this software and associated documentation files (the "Software"), to deal
18 | * in the Software without restriction, including without limitation the rights
19 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20 | * copies of the Software, and to permit persons to whom the Software is
21 | * furnished to do so, subject to the following conditions:
22 | *
23 | * The above copyright notice and this permission notice shall be included in
24 | * all copies or substantial portions of the Software.
25 | *
26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 | * THE SOFTWARE.
33 | *
34 | * bjoern@cs.stanford.edu 12/30/2008
35 | */
36 |
37 | #ifndef ethernetudp_h
38 | #define ethernetudp_h
39 |
40 | #include
41 | #include
42 |
43 | #include "utility/stm32_eth.h"
44 |
45 | #define UDP_TX_PACKET_MAX_SIZE 24
46 |
47 | class EthernetUDP : public UDP {
48 | private:
49 | uint16_t _port; // local port to listen on
50 | IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed
51 | uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed
52 | IPAddress _sendtoIP; // the remote IP address set by beginPacket
53 | uint16_t _sendtoPort; // the remote port set by beginPacket
54 |
55 | struct pbuf *_data; //pbuf for data to send
56 | struct udp_struct _udp; //udp settings
57 |
58 | protected:
59 | uint16_t _remaining; // remaining bytes of incoming packet yet to be processed
60 |
61 | public:
62 | EthernetUDP(); // Constructor
63 | virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
64 | virtual uint8_t begin(IPAddress, uint16_t, bool multicast = false); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
65 | virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
66 | virtual void stop(); // Finish with the UDP socket
67 |
68 | // Sending UDP packets
69 |
70 | // Start building up a packet to send to the remote host specific in ip and port
71 | // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
72 | virtual int beginPacket(IPAddress ip, uint16_t port);
73 | // Start building up a packet to send to the remote host specific in host and port
74 | // Returns 1 if successful, 0 if there was a problem resolving the hostname or port
75 | virtual int beginPacket(const char *host, uint16_t port);
76 | // Finish off this packet and send it
77 | // Returns 1 if the packet was sent successfully, 0 if there was an error
78 | virtual int endPacket();
79 | // Write a single byte into the packet
80 | virtual size_t write(uint8_t);
81 | // Write size bytes from buffer into the packet
82 | virtual size_t write(const uint8_t *buffer, size_t size);
83 |
84 | using Print::write;
85 |
86 | // Start processing the next available incoming packet
87 | // Returns the size of the packet in bytes, or 0 if no packets are available
88 | virtual int parsePacket();
89 | // Number of bytes remaining in the current packet
90 | virtual int available();
91 | // Read a single byte from the current packet
92 | virtual int read();
93 | // Read up to len bytes from the current packet and place them into buffer
94 | // Returns the number of bytes read, or 0 if none are available
95 | virtual int read(unsigned char *buffer, size_t len);
96 | // Read up to len characters from the current packet and place them into buffer
97 | // Returns the number of characters read, or 0 if none are available
98 | virtual int read(char *buffer, size_t len)
99 | {
100 | return read((unsigned char *)buffer, len);
101 | };
102 | // Return the next byte from the current packet without moving on to the next byte
103 | virtual int peek();
104 | virtual void flush(); // Finish reading the current packet
105 |
106 | // Return the IP address of the host who sent the current incoming packet
107 | virtual IPAddress remoteIP()
108 | {
109 | return _remoteIP;
110 | };
111 | // Return the port of the host who sent the current incoming packet
112 | virtual uint16_t remotePort()
113 | {
114 | return _remotePort;
115 | };
116 | virtual void onDataArrival(std::function onDataArrival_fn);
117 | };
118 |
119 | #endif
120 |
--------------------------------------------------------------------------------
/src/STM32Ethernet.cpp:
--------------------------------------------------------------------------------
1 | #include "STM32Ethernet.h"
2 | #include "Dhcp.h"
3 |
4 | int EthernetClass::begin(unsigned long timeout, unsigned long responseTimeout)
5 | {
6 | static DhcpClass s_dhcp;
7 | _dhcp = &s_dhcp;
8 | stm32_eth_init(NULL, NULL, NULL, NULL);
9 |
10 | // Now try to get our config info from a DHCP server
11 | int ret = _dhcp->beginWithDHCP(NULL, timeout, responseTimeout);
12 | if (ret == 1) {
13 | _dnsServerAddress = _dhcp->getDnsServerIp();
14 | }
15 |
16 | return ret;
17 | }
18 |
19 | void EthernetClass::begin(IPAddress local_ip)
20 | {
21 | IPAddress subnet(255, 255, 255, 0);
22 | begin(local_ip, subnet);
23 | }
24 |
25 | void EthernetClass::begin(IPAddress local_ip, IPAddress subnet)
26 | {
27 | // Assume the gateway will be the machine on the same network as the local IP
28 | // but with last octet being '1'
29 | IPAddress gateway = local_ip;
30 | gateway[3] = 1;
31 | begin(local_ip, subnet, gateway);
32 | }
33 |
34 | void EthernetClass::begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway)
35 | {
36 | // Assume the DNS server will be the same machine than gateway
37 | begin(local_ip, subnet, gateway, gateway);
38 | }
39 |
40 | void EthernetClass::begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway, IPAddress dns_server)
41 | {
42 | stm32_eth_init(NULL, local_ip.raw_address(), gateway.raw_address(), subnet.raw_address());
43 | /* If there is a local DHCP informs it of our manual IP configuration to
44 | prevent IP conflict */
45 | stm32_DHCP_manual_config();
46 | _dnsServerAddress = dns_server;
47 | }
48 |
49 | int EthernetClass::begin(uint8_t *mac_address, unsigned long timeout, unsigned long responseTimeout)
50 | {
51 | static DhcpClass s_dhcp;
52 | _dhcp = &s_dhcp;
53 |
54 | stm32_eth_init(mac_address, NULL, NULL, NULL);
55 |
56 | // Now try to get our config info from a DHCP server
57 | int ret = _dhcp->beginWithDHCP(mac_address, timeout, responseTimeout);
58 | if (ret == 1) {
59 | _dnsServerAddress = _dhcp->getDnsServerIp();
60 | }
61 | return ret;
62 | }
63 |
64 | void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip)
65 | {
66 | // Assume the DNS server will be the machine on the same network as the local IP
67 | // but with last octet being '1'
68 | IPAddress dns_server = local_ip;
69 | dns_server[3] = 1;
70 | begin(mac_address, local_ip, dns_server);
71 | }
72 |
73 | void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server)
74 | {
75 | // Assume the gateway will be the machine on the same network as the local IP
76 | // but with last octet being '1'
77 | IPAddress gateway = local_ip;
78 | gateway[3] = 1;
79 | begin(mac_address, local_ip, dns_server, gateway);
80 | }
81 |
82 | void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway)
83 | {
84 | IPAddress subnet(255, 255, 255, 0);
85 | begin(mac_address, local_ip, dns_server, gateway, subnet);
86 | }
87 |
88 | void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet)
89 | {
90 | stm32_eth_init(mac_address, local_ip.raw_address(), gateway.raw_address(), subnet.raw_address());
91 | /* If there is a local DHCP informs it of our manual IP configuration to
92 | prevent IP conflict */
93 | stm32_DHCP_manual_config();
94 | _dnsServerAddress = dns_server;
95 | }
96 |
97 | EthernetLinkStatus EthernetClass::linkStatus()
98 | {
99 | return (!stm32_eth_is_init()) ? Unknown : (stm32_eth_link_up() ? LinkON : LinkOFF);
100 | }
101 |
102 | int EthernetClass::maintain()
103 | {
104 | int rc = DHCP_CHECK_NONE;
105 |
106 | if (_dhcp != NULL) {
107 | //we have a pointer to dhcp, use it
108 | rc = _dhcp->checkLease();
109 | switch (rc) {
110 | case DHCP_CHECK_NONE:
111 | //nothing done
112 | break;
113 | case DHCP_CHECK_RENEW_OK:
114 | case DHCP_CHECK_REBIND_OK:
115 | _dnsServerAddress = _dhcp->getDnsServerIp();
116 | break;
117 | default:
118 | //this is actually a error, it will retry though
119 | break;
120 | }
121 | }
122 | return rc;
123 | }
124 |
125 | /*
126 | * This function updates the LwIP stack and can be called to be sure to update
127 | * the stack (e.g. in case of a long loop).
128 | */
129 | void EthernetClass::schedule(void)
130 | {
131 | stm32_eth_scheduler();
132 | }
133 |
134 | void EthernetClass::setMACAddress(const uint8_t *mac_address)
135 | {
136 | stm32_eth_set_macaddr(mac_address);
137 | }
138 |
139 | void EthernetClass::MACAddress(uint8_t *mac_address)
140 | {
141 | stm32_eth_get_macaddr(mac_address);
142 | }
143 |
144 | IPAddress EthernetClass::localIP()
145 | {
146 | return IPAddress(stm32_eth_get_ipaddr());
147 | }
148 |
149 | IPAddress EthernetClass::subnetMask()
150 | {
151 | return IPAddress(stm32_eth_get_netmaskaddr());
152 | }
153 |
154 | IPAddress EthernetClass::gatewayIP()
155 | {
156 | return IPAddress(stm32_eth_get_gwaddr());
157 | }
158 |
159 | IPAddress EthernetClass::dnsServerIP()
160 | {
161 | return _dnsServerAddress;
162 | }
163 |
164 | void EthernetClass::setDnsServerIP(const IPAddress dns_server)
165 | {
166 | _dnsServerAddress = dns_server;
167 | }
168 |
169 | EthernetClass Ethernet;
170 |
--------------------------------------------------------------------------------
/src/STM32Ethernet.h:
--------------------------------------------------------------------------------
1 | #ifndef ethernet_h
2 | #define ethernet_h
3 |
4 | #include
5 | #include "IPAddress.h"
6 | #include "EthernetClient.h"
7 | #include "EthernetServer.h"
8 | #include "Dhcp.h"
9 |
10 | enum EthernetLinkStatus {
11 | Unknown,
12 | LinkON,
13 | LinkOFF
14 | };
15 |
16 | class EthernetClass {
17 | private:
18 | IPAddress _dnsServerAddress;
19 | DhcpClass *_dhcp;
20 |
21 | public:
22 | // Initialise the Ethernet with the internal provided MAC address and gain the rest of the
23 | // configuration through DHCP.
24 | // Returns 0 if the DHCP configuration failed, and 1 if it succeeded
25 | int begin(unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
26 | EthernetLinkStatus linkStatus();
27 | void begin(IPAddress local_ip);
28 | void begin(IPAddress local_ip, IPAddress subnet);
29 | void begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway);
30 | void begin(IPAddress local_ip, IPAddress subnet, IPAddress gateway, IPAddress dns_server);
31 | // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the
32 | // configuration through DHCP.
33 | // Returns 0 if the DHCP configuration failed, and 1 if it succeeded
34 | int begin(uint8_t *mac_address, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
35 | void begin(uint8_t *mac_address, IPAddress local_ip);
36 | void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server);
37 | void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway);
38 | void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet);
39 |
40 |
41 | int maintain();
42 | void schedule(void);
43 |
44 | void MACAddress(uint8_t *mac_address);
45 | IPAddress localIP();
46 | IPAddress subnetMask();
47 | IPAddress gatewayIP();
48 | IPAddress dnsServerIP();
49 |
50 | void setMACAddress(const uint8_t *mac_address);
51 | void setDnsServerIP(const IPAddress dns_server);
52 |
53 | friend class EthernetClient;
54 | friend class EthernetServer;
55 | };
56 |
57 | extern EthernetClass Ethernet;
58 |
59 | #endif
60 |
--------------------------------------------------------------------------------
/src/lwipopts.h:
--------------------------------------------------------------------------------
1 | /*
2 | * @file lwipopts.h
3 | * @author Frederic Pillon for STMicroelectronics.
4 | * @brief Include header file to match Arduino library format
5 | */
6 |
7 | #ifndef _ARDUINO_LWIPOPTS_H
8 | #define _ARDUINO_LWIPOPTS_H
9 |
10 | /* LwIP specific configuration options. */
11 | #if __has_include("STM32lwipopts.h")
12 | #include "STM32lwipopts.h"
13 | #else
14 | #if __has_include("lwipopts_extra.h")
15 | #include "lwipopts_extra.h"
16 | #endif
17 | #include "lwipopts_default.h"
18 | #endif
19 |
20 | #endif /* _ARDUINO_LWIPOPTS_H */
21 |
22 |
--------------------------------------------------------------------------------
/src/lwipopts_default.h:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file lwipopts_default.h
4 | * @author MCD Application Team
5 | * @brief lwIP Options Configuration.
6 | ******************************************************************************
7 | * @attention
8 | *
9 | * © Copyright (c) 2017 STMicroelectronics International N.V.
10 | * All rights reserved.
11 | *
12 | * This software component is licensed by ST under Ultimate Liberty license
13 | * SLA0044, the "License"; You may not use this file except in compliance with
14 | * the License. You may obtain a copy of the License at:
15 | * www.st.com/SLA0044
16 | *
17 | ******************************************************************************
18 | */
19 | #ifndef __LWIPOPTS_H__
20 | #define __LWIPOPTS_H__
21 |
22 | /**
23 | * NO_SYS==1: Provides VERY minimal functionality. Otherwise,
24 | * use lwIP facilities.
25 | */
26 | #define NO_SYS 1
27 |
28 | /**
29 | * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
30 | * critical regions during buffer allocation, deallocation and memory
31 | * allocation and deallocation.
32 | */
33 | #define SYS_LIGHTWEIGHT_PROT 0
34 |
35 | #define LWIP_NOASSERT
36 |
37 | /* ---------- Memory options ---------- */
38 | /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
39 | lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
40 | byte alignment -> define MEM_ALIGNMENT to 2. */
41 | #define MEM_ALIGNMENT 4
42 |
43 | /* MEM_SIZE: the size of the heap memory. If the application will send
44 | a lot of data that needs to be copied, this should be set high. */
45 | #define MEM_SIZE (10*1024)
46 |
47 | /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
48 | sends a lot of data out of ROM (or other static memory), this
49 | should be set high. */
50 | #define MEMP_NUM_PBUF 10
51 | /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
52 | per active UDP "connection". */
53 | #define MEMP_NUM_UDP_PCB 6
54 | /* MEMP_NUM_TCP_PCB: the number of simultaneously active TCP
55 | connections. */
56 | #define MEMP_NUM_TCP_PCB 10
57 | /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
58 | connections. */
59 | #define MEMP_NUM_TCP_PCB_LISTEN 6
60 | /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
61 | segments. */
62 | #define MEMP_NUM_TCP_SEG 8
63 | /* MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active
64 | timeouts. */
65 | #define MEMP_NUM_SYS_TIMEOUT 10
66 |
67 |
68 | /* ---------- Pbuf options ---------- */
69 | /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
70 | #define PBUF_POOL_SIZE 8
71 |
72 | /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
73 | #define PBUF_POOL_BUFSIZE 1524
74 |
75 |
76 | /* ---------- TCP options ---------- */
77 | #define LWIP_TCP 1
78 | #define TCP_TTL 255
79 | #define LWIP_SO_RCVTIMEO 1
80 | #define LWIP_SO_RCVRCVTIMEO_NONSTANDARD 1 /* Pass an integer number of ms instead of a timeval struct. */
81 | #define LWIP_SO_SNDTIMEO 1
82 | #define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 1 /* Pass an integer number of ms instead of a timeval struct. */
83 |
84 | /* Controls if TCP should queue segments that arrive out of
85 | order. Define to 0 if your device is low on memory and you are not scared by TCP congestion and latencies. */
86 | #define TCP_QUEUE_OOSEQ 0
87 |
88 | /* TCP Maximum segment size. */
89 | #define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */
90 |
91 | /* TCP sender buffer space (bytes). */
92 | #define TCP_SND_BUF (4*TCP_MSS)
93 |
94 | /* TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
95 | as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */
96 |
97 | #define TCP_SND_QUEUELEN (2* TCP_SND_BUF/TCP_MSS)
98 |
99 | /* TCP receive window. */
100 | #define TCP_WND (3*TCP_MSS)
101 |
102 | #define LWIP_TCP_KEEPALIVE 1 /* Keep the TCP link active. Important for MQTT/TLS */
103 | #define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 1 /* Prevent the same port to be used after reset.
104 | Otherwise, the remote host may be confused if the port was not explicitly closed before the reset. */
105 |
106 |
107 | /* ---------- ICMP options ---------- */
108 | #define LWIP_ICMP 1
109 | #define LWIP_RAW 1 /* PING changed to 1 */
110 | #define DEFAULT_RAW_RECVMBOX_SIZE 3 /* for ICMP PING */
111 |
112 |
113 | /* ---------- DHCP options ---------- */
114 | /* Define LWIP_DHCP to 1 if you want DHCP configuration of
115 | interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
116 | turning this on does currently not work. */
117 | #define LWIP_DHCP 1
118 |
119 |
120 | /* ---------- UDP options ---------- */
121 | #define LWIP_UDP 1
122 | #define UDP_TTL 255
123 |
124 |
125 | /* ---------- Statistics options ---------- */
126 | #define LWIP_STATS 0
127 | #define LWIP_PROVIDE_ERRNO
128 |
129 | /* ---------- link callback options ---------- */
130 | /* LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface
131 | * whenever the link changes (i.e., link down)
132 | */
133 | // need for building net_ip.c
134 | #define LWIP_NETIF_HOSTNAME 1
135 | #define LWIP_NETIF_STATUS_CALLBACK 1
136 | #define LWIP_NETIF_LINK_CALLBACK 1
137 | #define LWIP_DHCP_CHECK_LINK_UP 1
138 |
139 | /*
140 | --------------------------------------
141 | ---------- Checksum options ----------
142 | --------------------------------------
143 | */
144 |
145 | /*
146 | The STM32F4x7 allows computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
147 | - To use this feature let the following define uncommented.
148 | - To disable it and process by CPU comment the the checksum.
149 | */
150 | #define CHECKSUM_BY_HARDWARE
151 |
152 |
153 | #ifdef CHECKSUM_BY_HARDWARE
154 | /* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
155 | #define CHECKSUM_GEN_IP 0
156 | /* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
157 | #define CHECKSUM_GEN_UDP 0
158 | /* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
159 | #define CHECKSUM_GEN_TCP 0
160 | /* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
161 | #define CHECKSUM_CHECK_IP 0
162 | /* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
163 | #define CHECKSUM_CHECK_UDP 0
164 | /* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
165 | #define CHECKSUM_CHECK_TCP 0
166 | /* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/
167 | #define CHECKSUM_GEN_ICMP 0
168 | #else
169 | /* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
170 | #define CHECKSUM_GEN_IP 1
171 | /* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
172 | #define CHECKSUM_GEN_UDP 1
173 | /* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
174 | #define CHECKSUM_GEN_TCP 1
175 | /* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
176 | #define CHECKSUM_CHECK_IP 1
177 | /* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
178 | #define CHECKSUM_CHECK_UDP 1
179 | /* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
180 | #define CHECKSUM_CHECK_TCP 1
181 | /* CHECKSUM_CHECK_ICMP==1: Check checksums by hardware for incoming ICMP packets.*/
182 | #define CHECKSUM_GEN_ICMP 1
183 | #endif
184 |
185 |
186 | /*
187 | ----------------------------------------------
188 | ---------- Sequential layer options ----------
189 | ----------------------------------------------
190 | */
191 | /**
192 | * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
193 | */
194 | #define LWIP_NETCONN 0
195 |
196 | /*
197 | ------------------------------------
198 | ---------- Socket options ----------
199 | ------------------------------------
200 | */
201 | /**
202 | * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
203 | */
204 | #define LWIP_SOCKET 0
205 | #define LWIP_DNS 1
206 |
207 | /*
208 | ------------------------------------
209 | ---------- httpd options ----------
210 | ------------------------------------
211 | */
212 |
213 | /** Set this to 1 to support CGI */
214 | #define LWIP_HTTPD_CGI 1
215 |
216 | /** Set this to 1 to support SSI (Server-Side-Includes) */
217 | #define LWIP_HTTPD_SSI 1
218 |
219 | /** Set this to 1 to include "fsdata_custom.c" instead of "fsdata.c" for the
220 | * file system (to prevent changing the file included in CVS) */
221 | #define HTTPD_USE_CUSTOM_FSDATA 1
222 |
223 | /*
224 | ------------------------------------
225 | ---------- Custom options ----------
226 | ------------------------------------
227 | */
228 |
229 | /** Enables the Ethernet peripheral in RMII mode. If not defined, MII mode will
230 | be enabled. Pin mapping must be configured for the selected mode
231 | (see PinMap_Ethernet in PeripheralPins.c). */
232 | #define ETHERNET_RMII_MODE_CONFIGURATION 1
233 |
234 | /** Uncomment this line to use the ethernet input in interrupt mode.
235 | * NOTE: LwIP stack documentation recommends to use the polling mode without
236 | * an operating system. */
237 | //#define ETH_INPUT_USE_IT 1
238 |
239 | #endif /* __LWIPOPTS_H__ */
240 |
241 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
242 |
--------------------------------------------------------------------------------
/src/utility/ethernetif.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file ethernetif.c
4 | * @author MCD Application Team & Wi6Labs
5 | * @version V1.5.0
6 | * @date 20-june-2017
7 | * @brief This file implements Ethernet network interface drivers for lwIP
8 | ******************************************************************************
9 | * @attention
10 | *
11 | * © Copyright (c) 2017 STMicroelectronics International N.V.
12 | * All rights reserved.
13 | *
14 | * Redistribution and use in source and binary forms, with or without
15 | * modification, are permitted, provided that the following conditions are met:
16 | *
17 | * 1. Redistribution of source code must retain the above copyright notice,
18 | * this list of conditions and the following disclaimer.
19 | * 2. Redistributions in binary form must reproduce the above copyright notice,
20 | * this list of conditions and the following disclaimer in the documentation
21 | * and/or other materials provided with the distribution.
22 | * 3. Neither the name of STMicroelectronics nor the names of other
23 | * contributors to this software may be used to endorse or promote products
24 | * derived from this software without specific written permission.
25 | * 4. This software, including modifications and/or derivative works of this
26 | * software, must execute solely and exclusively on microcontroller or
27 | * microprocessor devices manufactured by or for STMicroelectronics.
28 | * 5. Redistribution and use of this software other than as permitted under
29 | * this license is void and will automatically terminate your rights under
30 | * this license.
31 | *
32 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
33 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
35 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
36 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
37 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
40 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
41 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
43 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 | *
45 | ******************************************************************************
46 | */
47 | /* Includes ------------------------------------------------------------------*/
48 | #include "stm32_def.h"
49 | #include "lwip/timeouts.h"
50 | #include "netif/etharp.h"
51 | #include "ethernetif.h"
52 | #include
53 | #include "PeripheralPins.h"
54 | #include "lwip/igmp.h"
55 | #include "stm32_eth.h"
56 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01050000)
57 | #include "variant.h"
58 | #endif
59 |
60 | #ifdef __cplusplus
61 | extern "C" {
62 | #endif
63 |
64 | /* Private typedef -----------------------------------------------------------*/
65 | /* Private define ------------------------------------------------------------*/
66 | /* Network interface name */
67 | #define IFNAME0 's'
68 | #define IFNAME1 't'
69 |
70 | /* Definition of PHY SPECIAL CONTROL/STATUS REGISTER bitfield Auto-negotiation done indication */
71 | /* Placed in STM32Ethernet library instead of HAL conf to avoid compatibility dependence with Arduino_Core_STM32 */
72 | /* Could be moved from this file once Generic PHY is implemented */
73 | #define PHY_SR_AUTODONE ((uint16_t)0x1000)
74 |
75 | /* Private macro -------------------------------------------------------------*/
76 | /* Private variables ---------------------------------------------------------*/
77 | #if defined ( __ICCARM__ ) /*!< IAR Compiler */
78 | #pragma data_alignment=4
79 | #endif
80 | __ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END;/* Ethernet Rx MA Descriptor */
81 |
82 | #if defined ( __ICCARM__ ) /*!< IAR Compiler */
83 | #pragma data_alignment=4
84 | #endif
85 | __ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END;/* Ethernet Tx DMA Descriptor */
86 |
87 | #if defined ( __ICCARM__ ) /*!< IAR Compiler */
88 | #pragma data_alignment=4
89 | #endif
90 | __ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */
91 |
92 | #if defined ( __ICCARM__ ) /*!< IAR Compiler */
93 | #pragma data_alignment=4
94 | #endif
95 | __ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */
96 |
97 | static ETH_HandleTypeDef EthHandle;
98 |
99 | /* If default MAC fields is not defined use default values based on UID */
100 | #if !defined(MAC_ADDR0)
101 | #define MAC_ADDR0 0x00
102 | #endif
103 | #if !defined(MAC_ADDR1)
104 | #define MAC_ADDR1 0x80
105 | #endif
106 | #if !defined(MAC_ADDR2)
107 | #define MAC_ADDR2 0xE1
108 | #endif
109 | #if !defined(MAC_ADDR3)
110 | #define MAC_ADDR3 ((uint8_t)(((*(uint32_t *)UID_BASE) & 0x00FF0000) >> 16))
111 | #endif
112 | #if !defined(MAC_ADDR4)
113 | #define MAC_ADDR4 ((uint8_t)(((*(uint32_t *)UID_BASE) & 0x0000FF00) >> 8))
114 | #endif
115 | #if !defined(MAC_ADDR5)
116 | #define MAC_ADDR5 ((uint8_t)((*(uint32_t *)UID_BASE) & 0x000000FF))
117 | #endif
118 | static uint8_t macaddress[6] = { MAC_ADDR0, MAC_ADDR1, MAC_ADDR2, MAC_ADDR3, MAC_ADDR4, MAC_ADDR5 };
119 |
120 | #if LWIP_IGMP
121 | uint32_t ETH_HashTableHigh = 0x0;
122 | uint32_t ETH_HashTableLow = 0x0;
123 | #endif
124 |
125 | /* Private function prototypes -----------------------------------------------*/
126 | /* Private functions ---------------------------------------------------------*/
127 | /*******************************************************************************
128 | Ethernet MSP Routines
129 | *******************************************************************************/
130 | /**
131 | * @brief Initializes the ETH MSP.
132 | * @param heth: ETH handle
133 | * @retval None
134 | */
135 | void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
136 | {
137 | GPIO_InitTypeDef GPIO_InitStructure;
138 | const PinMap *map = PinMap_Ethernet;
139 | PinName pin = pin_pinName(map);
140 | GPIO_TypeDef *port;
141 |
142 | UNUSED(heth);
143 |
144 | /* Ethernet pins configuration ************************************************/
145 |
146 | if (map != NULL) {
147 | while (pin != NC) {
148 | /* Set port clock */
149 | port = set_GPIO_Port_Clock(STM_PORT(pin));
150 |
151 | /* pin configuration */
152 | GPIO_InitStructure.Pin = STM_GPIO_PIN(pin);
153 | GPIO_InitStructure.Mode = STM_PIN_MODE(pinmap_function(pin, PinMap_Ethernet));
154 | GPIO_InitStructure.Pull = STM_PIN_PUPD(pinmap_function(pin, PinMap_Ethernet));
155 | GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
156 | GPIO_InitStructure.Alternate = STM_PIN_AFNUM(pinmap_function(pin, PinMap_Ethernet));
157 | HAL_GPIO_Init(port, &GPIO_InitStructure);
158 |
159 | pin = pin_pinName(++map);
160 | }
161 | }
162 |
163 | #ifdef ETH_INPUT_USE_IT
164 | /* Enable the Ethernet global Interrupt */
165 | HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0);
166 | HAL_NVIC_EnableIRQ(ETH_IRQn);
167 | #endif /* ETH_INPUT_USE_IT */
168 |
169 | /* Enable ETHERNET clock */
170 | __HAL_RCC_ETH_CLK_ENABLE();
171 | }
172 |
173 | /*******************************************************************************
174 | LL Driver Interface ( LwIP stack --> ETH)
175 | *******************************************************************************/
176 | /**
177 | * @brief In this function, the hardware should be initialized.
178 | * Called from ethernetif_init().
179 | *
180 | * @param netif the already initialized lwip network interface structure
181 | * for this ethernetif
182 | */
183 | static void low_level_init(struct netif *netif)
184 | {
185 | uint32_t regvalue;
186 |
187 | EthHandle.Instance = ETH;
188 | EthHandle.Init.MACAddr = macaddress;
189 | EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
190 | EthHandle.Init.Speed = ETH_SPEED_100M;
191 | EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
192 | #ifdef ETHERNET_RMII_MODE_CONFIGURATION
193 | EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
194 | #else
195 | EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
196 | #endif /* ETHERNET_RMII_MODE_CONFIGURATION */
197 | #ifdef ETH_INPUT_USE_IT
198 | EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE;
199 | #else
200 | EthHandle.Init.RxMode = ETH_RXPOLLING_MODE;
201 | #endif /* ETH_INPUT_USE_IT */
202 | EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
203 | EthHandle.Init.PhyAddress = LAN8742A_PHY_ADDRESS;
204 |
205 | /* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
206 | if (HAL_ETH_Init(&EthHandle) == HAL_OK) {
207 | /* Set netif link flag */
208 | netif->flags |= NETIF_FLAG_LINK_UP;
209 | }
210 |
211 | /* Initialize Tx Descriptors list: Chain Mode */
212 | HAL_ETH_DMATxDescListInit(&EthHandle, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
213 |
214 | /* Initialize Rx Descriptors list: Chain Mode */
215 | HAL_ETH_DMARxDescListInit(&EthHandle, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
216 |
217 | /* set MAC hardware address length */
218 | netif->hwaddr_len = ETH_HWADDR_LEN;
219 |
220 | /* set MAC hardware address */
221 | netif->hwaddr[0] = macaddress[0];
222 | netif->hwaddr[1] = macaddress[1];
223 | netif->hwaddr[2] = macaddress[2];
224 | netif->hwaddr[3] = macaddress[3];
225 | netif->hwaddr[4] = macaddress[4];
226 | netif->hwaddr[5] = macaddress[5];
227 |
228 | /* maximum transfer unit */
229 | netif->mtu = 1500;
230 |
231 | /* device capabilities */
232 | /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
233 | netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
234 |
235 | /* Enable MAC and DMA transmission and reception */
236 | HAL_ETH_Start(&EthHandle);
237 | #if LWIP_IGMP
238 | netif_set_igmp_mac_filter(netif, igmp_mac_filter);
239 | #endif
240 | /**** Configure PHY to generate an interrupt when Eth Link state changes ****/
241 | /* Read Register Configuration */
242 | HAL_ETH_ReadPHYRegister(&EthHandle, PHY_IMR, ®value);
243 |
244 | regvalue |= PHY_ISFR_INT4;
245 |
246 | /* Enable Interrupt on change of link status */
247 | HAL_ETH_WritePHYRegister(&EthHandle, PHY_IMR, regvalue);
248 | #if LWIP_IGMP
249 | ETH_HashTableHigh = EthHandle.Instance->MACHTHR;
250 | ETH_HashTableLow = EthHandle.Instance->MACHTLR;
251 | #endif
252 | }
253 |
254 | /**
255 | * @brief This function should do the actual transmission of the packet. The packet is
256 | * contained in the pbuf that is passed to the function. This pbuf
257 | * might be chained.
258 | *
259 | * @param netif the lwip network interface structure for this ethernetif
260 | * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
261 | * @return ERR_OK if the packet could be sent
262 | * an err_t value if the packet couldn't be sent
263 | *
264 | * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
265 | * strange results. You might consider waiting for space in the DMA queue
266 | * to become available since the stack doesn't retry to send a packet
267 | * dropped because of memory failure (except for the TCP timers).
268 | */
269 | static err_t low_level_output(struct netif *netif, struct pbuf *p)
270 | {
271 | err_t errval;
272 | struct pbuf *q;
273 | uint8_t *buffer = (uint8_t *)(EthHandle.TxDesc->Buffer1Addr);
274 | __IO ETH_DMADescTypeDef *DmaTxDesc;
275 | uint32_t framelength = 0;
276 | uint32_t bufferoffset = 0;
277 | uint32_t byteslefttocopy = 0;
278 | uint32_t payloadoffset = 0;
279 |
280 | UNUSED(netif);
281 |
282 | DmaTxDesc = EthHandle.TxDesc;
283 | bufferoffset = 0;
284 |
285 | /* copy frame from pbufs to driver buffers */
286 | for (q = p; q != NULL; q = q->next) {
287 | /* Is this buffer available? If not, goto error */
288 | if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
289 | errval = ERR_USE;
290 | goto error;
291 | }
292 |
293 | /* Get bytes in current lwIP buffer */
294 | byteslefttocopy = q->len;
295 | payloadoffset = 0;
296 |
297 | /* Check if the length of data to copy is bigger than Tx buffer size*/
298 | while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE) {
299 | /* Copy data to Tx buffer*/
300 | memcpy((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset));
301 |
302 | /* Point to next descriptor */
303 | DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
304 |
305 | /* Check if the buffer is available */
306 | if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) {
307 | errval = ERR_USE;
308 | goto error;
309 | }
310 |
311 | buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
312 |
313 | byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
314 | payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
315 | framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
316 | bufferoffset = 0;
317 | }
318 |
319 | /* Copy the remaining bytes */
320 | memcpy((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), byteslefttocopy);
321 | bufferoffset = bufferoffset + byteslefttocopy;
322 | framelength = framelength + byteslefttocopy;
323 | }
324 |
325 | /* Prepare transmit descriptors to give to DMA */
326 | HAL_ETH_TransmitFrame(&EthHandle, framelength);
327 |
328 | errval = ERR_OK;
329 |
330 | error:
331 |
332 | /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
333 | if ((EthHandle.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET) {
334 | /* Clear TUS ETHERNET DMA flag */
335 | EthHandle.Instance->DMASR = ETH_DMASR_TUS;
336 |
337 | /* Resume DMA transmission*/
338 | EthHandle.Instance->DMATPDR = 0;
339 | }
340 | return errval;
341 | }
342 |
343 | /**
344 | * @brief Should allocate a pbuf and transfer the bytes of the incoming
345 | * packet from the interface into the pbuf.
346 | *
347 | * @param netif the lwip network interface structure for this ethernetif
348 | * @return a pbuf filled with the received packet (including MAC header)
349 | * NULL on memory error
350 | */
351 | static struct pbuf *low_level_input(struct netif *netif)
352 | {
353 | struct pbuf *p = NULL;
354 | struct pbuf *q;
355 | uint16_t len;
356 | uint8_t *buffer;
357 | __IO ETH_DMADescTypeDef *dmarxdesc;
358 | uint32_t bufferoffset = 0;
359 | uint32_t payloadoffset = 0;
360 | uint32_t byteslefttocopy = 0;
361 | uint32_t i = 0;
362 |
363 | UNUSED(netif);
364 |
365 | if (HAL_ETH_GetReceivedFrame_IT(&EthHandle) != HAL_OK) {
366 | return NULL;
367 | }
368 |
369 | /* Obtain the size of the packet and put it into the "len" variable. */
370 | len = EthHandle.RxFrameInfos.length;
371 | buffer = (uint8_t *)EthHandle.RxFrameInfos.buffer;
372 |
373 | if (len > 0) {
374 | /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
375 | p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
376 | }
377 |
378 | if (p != NULL) {
379 | dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;
380 | bufferoffset = 0;
381 |
382 | for (q = p; q != NULL; q = q->next) {
383 | byteslefttocopy = q->len;
384 | payloadoffset = 0;
385 |
386 | /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size */
387 | while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE) {
388 | /* Copy data to pbuf */
389 | memcpy((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
390 |
391 | /* Point to next descriptor */
392 | dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
393 | buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);
394 |
395 | byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
396 | payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
397 | bufferoffset = 0;
398 | }
399 |
400 | /* Copy remaining data in pbuf */
401 | memcpy((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), byteslefttocopy);
402 | bufferoffset = bufferoffset + byteslefttocopy;
403 | }
404 | }
405 |
406 | /* Release descriptors to DMA */
407 | /* Point to first descriptor */
408 | dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;
409 | /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
410 | for (i = 0; i < EthHandle.RxFrameInfos.SegCount; i++) {
411 | dmarxdesc->Status |= ETH_DMARXDESC_OWN;
412 | dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
413 | }
414 |
415 | /* Clear Segment_Count */
416 | EthHandle.RxFrameInfos.SegCount = 0;
417 |
418 | /* When Rx Buffer unavailable flag is set: clear it and resume reception */
419 | if ((EthHandle.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
420 | /* Clear RBUS ETHERNET DMA flag */
421 | EthHandle.Instance->DMASR = ETH_DMASR_RBUS;
422 | /* Resume DMA reception */
423 | EthHandle.Instance->DMARPDR = 0;
424 | }
425 | return p;
426 | }
427 |
428 | /**
429 | * @brief This function should be called when a packet is ready to be read
430 | * from the interface. It uses the function low_level_input() that
431 | * should handle the actual reception of bytes from the network
432 | * interface. Then the type of the received packet is determined and
433 | * the appropriate input function is called.
434 | *
435 | * @param netif the lwip network interface structure for this ethernetif
436 | */
437 | void ethernetif_input(struct netif *netif)
438 | {
439 | err_t err;
440 | struct pbuf *p;
441 |
442 | /* move received packet into a new pbuf */
443 | p = low_level_input(netif);
444 |
445 | /* no packet could be read, silently ignore this */
446 | if (p == NULL) {
447 | return;
448 | }
449 |
450 | /* entry point to the LwIP stack */
451 | err = netif->input(p, netif);
452 |
453 | if (err != ERR_OK) {
454 | LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
455 | pbuf_free(p);
456 | p = NULL;
457 | }
458 | }
459 |
460 | /**
461 | * @brief Returns the current state
462 | *
463 | * @param None
464 | * @return 0 not initialized else 1
465 | */
466 | uint8_t ethernetif_is_init(void)
467 | {
468 | return (EthHandle.State != HAL_ETH_STATE_RESET);
469 | }
470 |
471 | /**
472 | * @brief Should be called at the beginning of the program to set up the
473 | * network interface. It calls the function low_level_init() to do the
474 | * actual setup of the hardware.
475 | *
476 | * This function should be passed as a parameter to netif_add().
477 | *
478 | * @param netif the lwip network interface structure for this ethernetif
479 | * @return ERR_OK if the loopif is initialized
480 | * ERR_MEM if private data couldn't be allocated
481 | * any other err_t on error
482 | */
483 | err_t ethernetif_init(struct netif *netif)
484 | {
485 | LWIP_ASSERT("netif != NULL", (netif != NULL));
486 |
487 | #if LWIP_NETIF_HOSTNAME
488 | /* Initialize interface hostname */
489 | netif->hostname = "lwip";
490 | #endif /* LWIP_NETIF_HOSTNAME */
491 |
492 | netif->name[0] = IFNAME0;
493 | netif->name[1] = IFNAME1;
494 | /* We directly use etharp_output() here to save a function call.
495 | * You can instead declare your own function an call etharp_output()
496 | * from it if you have to do some checks before sending (e.g. if link
497 | * is available...) */
498 | netif->output = etharp_output;
499 | netif->linkoutput = low_level_output;
500 |
501 | /* initialize the hardware */
502 | low_level_init(netif);
503 |
504 | return ERR_OK;
505 | }
506 |
507 | /**
508 | * @brief Returns the current time in milliseconds
509 | * when LWIP_TIMERS == 1 and NO_SYS == 1
510 | * @param None
511 | * @retval Current Time value
512 | */
513 | u32_t sys_now(void)
514 | {
515 | return HAL_GetTick();
516 | }
517 |
518 | /**
519 | * @brief This function sets the netif link status.
520 | * @param netif: the network interface
521 | * @retval None
522 | */
523 | void ethernetif_set_link(struct netif *netif)
524 | {
525 | uint32_t regvalue = 0;
526 |
527 | /* Read PHY_MISR*/
528 | HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ISFR, ®value);
529 |
530 | /* Check whether the link interrupt has occurred or not */
531 | if ((regvalue & PHY_ISFR_INT4) != (uint16_t)RESET) {
532 | netif_set_link_down(netif);
533 | }
534 |
535 | HAL_ETH_ReadPHYRegister(&EthHandle, PHY_BSR, ®value);
536 |
537 | if ((regvalue & PHY_LINKED_STATUS) != (uint16_t)RESET) {
538 | #if LWIP_IGMP
539 | if (!(netif->flags & NETIF_FLAG_IGMP)) {
540 | netif->flags |= NETIF_FLAG_IGMP;
541 | igmp_init();
542 | igmp_start(netif);
543 | }
544 | #endif
545 | netif_set_link_up(netif);
546 | }
547 | }
548 |
549 | /**
550 | * @brief Link callback function, this function is called on change of link status
551 | * to update low level driver configuration.
552 | * @param netif: The network interface
553 | * @retval None
554 | */
555 | void ethernetif_update_config(struct netif *netif)
556 | {
557 | uint32_t regvalue = 0;
558 |
559 | if (netif_is_link_up(netif)) {
560 | /* Restart the auto-negotiation */
561 | if (EthHandle.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE) {
562 |
563 | /* Check Auto negotiation */
564 | HAL_ETH_ReadPHYRegister(&EthHandle, PHY_SR, ®value);
565 | if ((regvalue & PHY_SR_AUTODONE) != PHY_SR_AUTODONE) {
566 | goto error;
567 | }
568 |
569 | /* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */
570 | if ((regvalue & PHY_DUPLEX_STATUS) != (uint32_t)RESET) {
571 | /* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
572 | EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
573 | } else {
574 | /* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
575 | EthHandle.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
576 | }
577 | /* Configure the MAC with the speed fixed by the auto-negotiation process */
578 | if (regvalue & PHY_SPEED_STATUS) {
579 | /* Set Ethernet speed to 10M following the auto-negotiation */
580 | EthHandle.Init.Speed = ETH_SPEED_10M;
581 | } else {
582 | /* Set Ethernet speed to 100M following the auto-negotiation */
583 | EthHandle.Init.Speed = ETH_SPEED_100M;
584 | }
585 | } else { /* AutoNegotiation Disable */
586 | error :
587 | /* Check parameters */
588 | assert_param(IS_ETH_SPEED(EthHandle.Init.Speed));
589 | assert_param(IS_ETH_DUPLEX_MODE(EthHandle.Init.DuplexMode));
590 |
591 | /* Set MAC Speed and Duplex Mode to PHY */
592 | HAL_ETH_WritePHYRegister(&EthHandle, PHY_BCR, ((uint16_t)(EthHandle.Init.DuplexMode >> 3) |
593 | (uint16_t)(EthHandle.Init.Speed >> 1)));
594 | }
595 |
596 | /* ETHERNET MAC Re-Configuration */
597 | HAL_ETH_ConfigMAC(&EthHandle, (ETH_MACInitTypeDef *) NULL);
598 |
599 | /* Restart MAC interface */
600 | HAL_ETH_Start(&EthHandle);
601 | } else {
602 | /* Stop MAC interface */
603 | HAL_ETH_Stop(&EthHandle);
604 | }
605 |
606 | ethernetif_notify_conn_changed(netif);
607 | }
608 |
609 | /**
610 | * @brief This function notify user about link status changement.
611 | * @param netif: the network interface
612 | * @retval None
613 | */
614 | __weak void ethernetif_notify_conn_changed(struct netif *netif)
615 | {
616 | /* NOTE : This is function clould be implemented in user file
617 | when the callback is needed,
618 | */
619 | UNUSED(netif);
620 | }
621 |
622 | /**
623 | * @brief This function set a custom MAC address. This function must be called
624 | * before ethernetif_init().
625 | * @param mac: mac address
626 | * @retval None
627 | */
628 | void ethernetif_set_mac_addr(const uint8_t *mac)
629 | {
630 | if ((mac != NULL) && !(ethernetif_is_init())) {
631 | memcpy(macaddress, mac, 6);
632 | }
633 | }
634 |
635 | /**
636 | * @brief This function get the current MAC address.
637 | * @param mac: mac address
638 | * @retval None
639 | */
640 | void ethernetif_get_mac_addr(uint8_t *mac)
641 | {
642 | if (mac != NULL) {
643 | memcpy(mac, macaddress, 6);
644 | }
645 | }
646 |
647 | #if LWIP_IGMP
648 | err_t igmp_mac_filter(struct netif *netif, const ip4_addr_t *ip4_addr, netif_mac_filter_action action)
649 | {
650 | uint8_t mac[6];
651 | const uint8_t *p = (const uint8_t *)ip4_addr;
652 |
653 | mac[0] = 0x01;
654 | mac[1] = 0x00;
655 | mac[2] = 0x5E;
656 | mac[3] = *(p + 1) & 0x7F;
657 | mac[4] = *(p + 2);
658 | mac[5] = *(p + 3);
659 |
660 | register_multicast_address(mac);
661 |
662 | return 0;
663 | }
664 |
665 | #ifndef HASH_BITS
666 | #define HASH_BITS 6 /* #bits in hash */
667 | #endif
668 |
669 | uint32_t ethcrc(const uint8_t *data, size_t length)
670 | {
671 | uint32_t crc = 0xffffffff;
672 | size_t i;
673 | int j;
674 |
675 | for (i = 0; i < length; i++) {
676 | for (j = 0; j < 8; j++) {
677 | if (((crc >> 31) ^ (data[i] >> j)) & 0x01) {
678 | /* x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 */
679 | crc = (crc << 1) ^ 0x04C11DB7;
680 | } else {
681 | crc = crc << 1;
682 | }
683 | }
684 | }
685 | return ~crc;
686 | }
687 |
688 | void register_multicast_address(const uint8_t *mac)
689 | {
690 | uint32_t crc;
691 | uint8_t hash;
692 |
693 | /* Calculate crc32 value of mac address */
694 | crc = ethcrc(mac, HASH_BITS);
695 |
696 | /*
697 | * Only upper HASH_BITS are used
698 | * which point to specific bit in the hash registers
699 | */
700 | hash = (crc >> 26) & 0x3F;
701 |
702 | if (hash > 31) {
703 | ETH_HashTableHigh |= 1 << (hash - 32);
704 | EthHandle.Instance->MACHTHR = ETH_HashTableHigh;
705 | } else {
706 | ETH_HashTableLow |= 1 << hash;
707 | EthHandle.Instance->MACHTLR = ETH_HashTableLow;
708 | }
709 | }
710 | #endif /* LWIP_IGMP */
711 |
712 |
713 | #ifdef ETH_INPUT_USE_IT
714 | /**
715 | * @brief Ethernet Rx Transfer completed callback
716 | * @param heth: ETH handle
717 | * @retval None
718 | */
719 | void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
720 | {
721 | ethernetif_input(&gnetif);
722 | }
723 |
724 | /**
725 | * @brief This function handles Ethernet interrupt request.
726 | * @param None
727 | * @retval None
728 | */
729 | void ETH_IRQHandler(void)
730 | {
731 | HAL_ETH_IRQHandler(&EthHandle);
732 | }
733 | #endif /* ETH_INPUT_USE_IT */
734 |
735 | #ifdef __cplusplus
736 | }
737 | #endif
738 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
739 |
--------------------------------------------------------------------------------
/src/utility/ethernetif.h:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file ethernetif.h
4 | * @author MCD Application Team & Wi6Labs
5 | * @version V1.5.0
6 | * @date 20-June-2017
7 | * @brief Ethernet interface header file.
8 | ******************************************************************************
9 | * @attention
10 | *
11 | * © Copyright (c) 2017 STMicroelectronics International N.V.
12 | * All rights reserved.
13 | *
14 | * Redistribution and use in source and binary forms, with or without
15 | * modification, are permitted, provided that the following conditions are met:
16 | *
17 | * 1. Redistribution of source code must retain the above copyright notice,
18 | * this list of conditions and the following disclaimer.
19 | * 2. Redistributions in binary form must reproduce the above copyright notice,
20 | * this list of conditions and the following disclaimer in the documentation
21 | * and/or other materials provided with the distribution.
22 | * 3. Neither the name of STMicroelectronics nor the names of other
23 | * contributors to this software may be used to endorse or promote products
24 | * derived from this software without specific written permission.
25 | * 4. This software, including modifications and/or derivative works of this
26 | * software, must execute solely and exclusively on microcontroller or
27 | * microprocessor devices manufactured by or for STMicroelectronics.
28 | * 5. Redistribution and use of this software other than as permitted under
29 | * this license is void and will automatically terminate your rights under
30 | * this license.
31 | *
32 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
33 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
35 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
36 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
37 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
40 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
41 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
43 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 | *
45 | ******************************************************************************
46 | */
47 |
48 | #ifndef __ETHERNETIF_H__
49 | #define __ETHERNETIF_H__
50 | #ifdef __cplusplus
51 | extern "C" {
52 | #endif
53 | #include "lwip/err.h"
54 | #include "lwip/netif.h"
55 | /* Exported types ------------------------------------------------------------*/
56 | uint8_t ethernetif_is_init(void);
57 | err_t ethernetif_init(struct netif *netif);
58 | void ethernetif_input(struct netif *netif);
59 | void ethernetif_set_link(struct netif *netif);
60 | void ethernetif_update_config(struct netif *netif);
61 | void ethernetif_notify_conn_changed(struct netif *netif);
62 |
63 | void ethernetif_set_mac_addr(const uint8_t *mac);
64 | void ethernetif_get_mac_addr(uint8_t *mac);
65 |
66 | #if LWIP_IGMP
67 | err_t igmp_mac_filter(struct netif *netif, const ip4_addr_t *ip4_addr, netif_mac_filter_action action);
68 | void register_multicast_address(const uint8_t *mac);
69 | #endif
70 |
71 | #ifdef __cplusplus
72 | }
73 | #endif
74 |
75 | #endif
76 |
--------------------------------------------------------------------------------
/src/utility/stm32_eth.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file stm32_eth.cpp
4 | * @author WI6LABS
5 | * @version V1.0.0
6 | * @date 24-May-2017
7 | * @brief This file implements Ethernet network interface drivers for
8 | * Arduino STM32Ethernet library.
9 | ******************************************************************************
10 | * @attention
11 | *
12 | * © COPYRIGHT(c) 2016 STMicroelectronics
13 | *
14 | * Redistribution and use in source and binary forms, with or without modification,
15 | * are permitted provided that the following conditions are met:
16 | * 1. Redistributions of source code must retain the above copyright notice,
17 | * this list of conditions and the following disclaimer.
18 | * 2. Redistributions in binary form must reproduce the above copyright notice,
19 | * this list of conditions and the following disclaimer in the documentation
20 | * and/or other materials provided with the distribution.
21 | * 3. Neither the name of STMicroelectronics nor the names of its contributors
22 | * may be used to endorse or promote products derived from this software
23 | * without specific prior written permission.
24 | *
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 | *
36 | ******************************************************************************
37 | */
38 |
39 | #include "Arduino.h"
40 | #include "stm32_eth.h"
41 | #include "lwip/init.h"
42 | #include "lwip/netif.h"
43 | #include "lwip/timeouts.h"
44 | #include "netif/ethernet.h"
45 | #include "ethernetif.h"
46 | #include "lwip/dhcp.h"
47 | #include "lwip/prot/dhcp.h"
48 | #include "lwip/dns.h"
49 |
50 | /* Check ethernet link status every seconds */
51 | #define TIME_CHECK_ETH_LINK_STATE 500U
52 |
53 | /* Timeout for DNS request */
54 | #define TIMEOUT_DNS_REQUEST 10000U
55 |
56 | /* Maximum number of retries for DHCP request */
57 | #define MAX_DHCP_TRIES 4
58 |
59 | /*
60 | * Defined a default timer used to call ethernet scheduler at regular interval
61 | * Could be redefined in the variant
62 | * Note: This is planned to extend Timer API's of the Arduino STM32 core
63 | * They could be used for this library when available
64 | */
65 | #ifndef DEFAULT_ETHERNET_TIMER
66 | #define DEFAULT_ETHERNET_TIMER TIM14
67 | #warning "Default timer used to call ethernet scheduler at regular interval: TIM14"
68 | #endif
69 |
70 | /* Interrupt priority */
71 | #ifndef ETH_TIM_IRQ_PRIO
72 | #define ETH_TIM_IRQ_PRIO 15 // Warning: it should be lower prio (higher value) than Systick
73 | #endif
74 | #ifndef ETH_TIM_IRQ_SUBPRIO
75 | #define ETH_TIM_IRQ_SUBPRIO 0
76 | #endif
77 | /* Ethernet configuration: user parameters */
78 | struct stm32_eth_config {
79 | ip_addr_t ipaddr;
80 | ip_addr_t netmask;
81 | ip_addr_t gw;
82 | };
83 |
84 | /* Use to give user parameters to netif configuration */
85 | static struct stm32_eth_config gconfig;
86 |
87 | /* Netif global configuration structure */
88 | struct netif gnetif;
89 |
90 | /* DHCP periodic timer */
91 | static uint32_t DHCPfineTimer = 0;
92 |
93 | /* DHCP current state */
94 | __IO uint8_t DHCP_state = DHCP_OFF;
95 |
96 | /* Set to 1 if user use DHCP to obtain network addresses */
97 | static uint8_t DHCP_Started_by_user = 0;
98 |
99 | /* Ethernet link status periodic timer */
100 | static uint32_t gEhtLinkTickStart = 0;
101 |
102 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01060100)
103 | /* Handler for stimer */
104 | static stimer_t TimHandle;
105 | #else
106 | HardwareTimer *EthTim = NULL;
107 | #endif
108 |
109 | /*************************** Function prototype *******************************/
110 | static void Netif_Config(void);
111 | static err_t tcp_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
112 | static err_t tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len);
113 | static void tcp_err_callback(void *arg, err_t err);
114 | static void TIM_scheduler_Config(void);
115 | #if defined(STM32_CORE_VERSION) && (STM32_CORE_VERSION > 0x01060100)
116 | void _stm32_eth_scheduler(void);
117 | #endif
118 |
119 | /**
120 | * @brief Configure the network interface
121 | * @param None
122 | * @retval None
123 | */
124 | static void Netif_Config(void)
125 | {
126 | netif_remove(&gnetif);
127 | /* Add the network interface */
128 | netif_add(&gnetif, &(gconfig.ipaddr), &(gconfig.netmask), &(gconfig.gw), NULL, ðernetif_init, ðernet_input);
129 |
130 | /* Registers the default network interface */
131 | netif_set_default(&gnetif);
132 |
133 | if (netif_is_link_up(&gnetif)) {
134 | /* When the netif is fully configured this function must be called */
135 | netif_set_up(&gnetif);
136 | } else {
137 | /* When the netif link is down this function must be called */
138 | netif_set_down(&gnetif);
139 | }
140 |
141 | #if LWIP_NETIF_LINK_CALLBACK
142 | /* Set the link callback function, this function is called on change of link status */
143 | netif_set_link_callback(&gnetif, ethernetif_update_config);
144 | #endif /* LWIP_NETIF_LINK_CALLBACK */
145 | }
146 |
147 | /**
148 | * @brief Scheduler callback. Call by a timer interrupt.
149 | * @param htim: pointer to stimer_t or Hardware Timer
150 | * @retval None
151 | */
152 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01060100)
153 | static void scheduler_callback(stimer_t *htim)
154 | #elif (STM32_CORE_VERSION <= 0x01080000)
155 | static void scheduler_callback(HardwareTimer *htim)
156 | #else
157 | static void scheduler_callback(void)
158 | #endif
159 | {
160 | #if (STM32_CORE_VERSION <= 0x01080000)
161 | UNUSED(htim);
162 | #endif
163 | _stm32_eth_scheduler();
164 | }
165 |
166 | #if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01060100)
167 | /**
168 | * @brief Enable the timer used to call ethernet scheduler function at regular
169 | * interval.
170 | * @param None
171 | * @retval None
172 | */
173 | static void TIM_scheduler_Config(void)
174 | {
175 | /* Set TIMx instance. */
176 | TimHandle.timer = DEFAULT_ETHERNET_TIMER;
177 | /* Timer set to 1ms */
178 | TimerHandleInit(&TimHandle, (uint16_t)(1000 - 1), ((uint32_t)(getTimerClkFreq(DEFAULT_ETHERNET_TIMER) / (1000000)) - 1));
179 | attachIntHandle(&TimHandle, scheduler_callback);
180 | }
181 | #else
182 | /**
183 | * @brief Enable the timer used to call ethernet scheduler function at regular
184 | * interval.
185 | * @param None
186 | * @retval None
187 | */
188 | static void TIM_scheduler_Config(void)
189 | {
190 | /* Configure HardwareTimer */
191 | EthTim = new HardwareTimer(DEFAULT_ETHERNET_TIMER);
192 | EthTim->setInterruptPriority(ETH_TIM_IRQ_PRIO, ETH_TIM_IRQ_SUBPRIO);
193 | EthTim->setMode(1, TIMER_OUTPUT_COMPARE);
194 |
195 | /* Timer set to 1ms */
196 | EthTim->setOverflow(1000, MICROSEC_FORMAT);
197 | EthTim->attachInterrupt(scheduler_callback);
198 | EthTim->resume();
199 | }
200 | #endif
201 |
202 | void stm32_eth_init(const uint8_t *mac, const uint8_t *ip, const uint8_t *gw, const uint8_t *netmask)
203 | {
204 | static uint8_t initDone = 0;
205 |
206 | if (!initDone) {
207 | /* Initialize the LwIP stack */
208 | lwip_init();
209 | }
210 |
211 | if (mac != NULL) {
212 | ethernetif_set_mac_addr(mac);
213 | } // else default value is used: MAC_ADDR0 ... MAC_ADDR5
214 |
215 | if (ip != NULL) {
216 | IP_ADDR4(&(gconfig.ipaddr), ip[0], ip[1], ip[2], ip[3]);
217 | } else {
218 | #if LWIP_DHCP
219 | ip_addr_set_zero_ip4(&(gconfig.ipaddr));
220 | #else
221 | IP_ADDR4(&(gconfig.ipaddr), IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
222 | #endif /* LWIP_DHCP */
223 | }
224 |
225 | if (gw != NULL) {
226 | IP_ADDR4(&(gconfig.gw), gw[0], gw[1], gw[2], gw[3]);
227 | } else {
228 | #if LWIP_DHCP
229 | ip_addr_set_zero_ip4(&(gconfig.gw));
230 | #else
231 | IP_ADDR4(&(gconfig.gw), GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
232 | #endif /* LWIP_DHCP */
233 | }
234 |
235 | if (netmask != NULL) {
236 | IP_ADDR4(&(gconfig.netmask), netmask[0], netmask[1], netmask[2], netmask[3]);
237 | } else {
238 | #if LWIP_DHCP
239 | ip_addr_set_zero_ip4(&(gconfig.netmask));
240 | #else
241 | IP_ADDR4(&(gconfig.netmask), NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
242 | #endif /* LWIP_DHCP */
243 | }
244 |
245 | /* Configure the Network interface */
246 | Netif_Config();
247 |
248 | if (!initDone) {
249 | // stm32_eth_scheduler() will be called every 1ms.
250 | TIM_scheduler_Config();
251 | initDone = 1;
252 | }
253 |
254 | /* Reset DHCP if used */
255 | User_notification(&gnetif);
256 |
257 | /* Update LwIP stack */
258 | stm32_eth_scheduler();
259 | }
260 |
261 | /**
262 | * @brief Return Ethernet init status
263 | * @param None
264 | * @retval 1 for initialized, 0 for not initialized
265 | */
266 | uint8_t stm32_eth_is_init(void)
267 | {
268 | return ethernetif_is_init();
269 | }
270 |
271 | /**
272 | * @brief Set Ethernet MAC address
273 | * @param mac: mac address
274 | * @retval None
275 | */
276 | void stm32_eth_set_macaddr(const uint8_t *mac)
277 | {
278 | ethernetif_set_mac_addr(mac);
279 | }
280 | /**
281 | * @brief Return Ethernet MAC address
282 | * @param mac: mac address
283 | * @retval None
284 | */
285 | void stm32_eth_get_macaddr(uint8_t *mac)
286 | {
287 | return ethernetif_get_mac_addr(mac);
288 | }
289 |
290 | /**
291 | * @brief Return Ethernet link status
292 | * @param None
293 | * @retval 1 for link up, 0 for link down
294 | */
295 | uint8_t stm32_eth_link_up(void)
296 | {
297 | return netif_is_link_up(&gnetif);
298 | }
299 |
300 | #if defined(STM32_CORE_VERSION) && (STM32_CORE_VERSION > 0x01060100)
301 | /**
302 | * @brief This function generates Timer Update event to force call to _stm32_eth_scheduler().
303 | * @param None
304 | * @retval None
305 | */
306 | void stm32_eth_scheduler(void)
307 | {
308 | if (EthTim != NULL) {
309 | EthTim->refresh();
310 | }
311 | }
312 |
313 | /**
314 | * @brief This function is called solely by Timer callback to avoid race condition.
315 | * @param None
316 | * @retval None
317 | */
318 | void _stm32_eth_scheduler(void)
319 | #else
320 | /**
321 | * @brief This function is called solely by Timer callback to avoid race condition.
322 | * @param None
323 | * @retval None
324 | */
325 | void stm32_eth_scheduler(void)
326 | #endif
327 | {
328 | /* Read a received packet from the Ethernet buffers and send it
329 | to the lwIP for handling */
330 | #ifndef ETH_INPUT_USE_IT
331 | ethernetif_input(&gnetif);
332 | #endif /* ETH_INPUT_USE_IT */
333 |
334 | /* Check ethernet link status */
335 | if ((HAL_GetTick() - gEhtLinkTickStart) >= TIME_CHECK_ETH_LINK_STATE) {
336 | ethernetif_set_link(&gnetif);
337 | gEhtLinkTickStart = HAL_GetTick();
338 | }
339 |
340 | /* Handle LwIP timeouts */
341 | sys_check_timeouts();
342 |
343 | #if LWIP_DHCP
344 | stm32_DHCP_Periodic_Handle(&gnetif);
345 | #endif /* LWIP_DHCP */
346 | }
347 |
348 | #if LWIP_DHCP
349 |
350 | /**
351 | * @brief Returns DHCP activation state
352 | * @param None
353 | * @retval true if DHCP enabled or false if not used
354 | */
355 | uint8_t stm32_dhcp_started(void)
356 | {
357 | return DHCP_Started_by_user;
358 | }
359 |
360 | /**
361 | * @brief DHCP_Process_Handle
362 | * @param netif pointer to generic data structure used for all lwIP network interfaces
363 | * @retval None
364 | */
365 | void stm32_DHCP_process(struct netif *netif)
366 | {
367 | struct dhcp *dhcp;
368 |
369 | if (netif_is_link_up(netif)) {
370 | switch (DHCP_state) {
371 | case DHCP_START: {
372 | ip_addr_set_zero_ip4(&netif->ip_addr);
373 | ip_addr_set_zero_ip4(&netif->netmask);
374 | ip_addr_set_zero_ip4(&netif->gw);
375 | DHCP_state = DHCP_WAIT_ADDRESS;
376 | dhcp_start(netif);
377 | DHCP_Started_by_user = 1;
378 | }
379 | break;
380 |
381 | case DHCP_WAIT_ADDRESS: {
382 | if (dhcp_supplied_address(netif)) {
383 | DHCP_state = DHCP_ADDRESS_ASSIGNED;
384 | } else {
385 | dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
386 |
387 | /* DHCP timeout */
388 | if (dhcp->tries > MAX_DHCP_TRIES) {
389 | DHCP_state = DHCP_TIMEOUT;
390 |
391 | // If DHCP address not bind, keep DHCP stopped
392 | DHCP_Started_by_user = 0;
393 |
394 | /* Stop DHCP */
395 | dhcp_stop(netif);
396 | }
397 | }
398 | }
399 | break;
400 | case DHCP_ASK_RELEASE: {
401 | /* Force release */
402 | dhcp_release(netif);
403 | dhcp_stop(netif);
404 | DHCP_state = DHCP_OFF;
405 | }
406 | break;
407 | case DHCP_LINK_DOWN: {
408 | /* Stop DHCP */
409 | dhcp_stop(netif);
410 | DHCP_state = DHCP_OFF;
411 | }
412 | break;
413 | default: break;
414 | }
415 | } else {
416 | DHCP_state = DHCP_OFF;
417 | }
418 | }
419 |
420 | /**
421 | * @brief DHCP periodic check
422 | * @param netif pointer to generic data structure used for all lwIP network interfaces
423 | * @retval None
424 | */
425 | void stm32_DHCP_Periodic_Handle(struct netif *netif)
426 | {
427 | /* Fine DHCP periodic process every 500ms */
428 | if (HAL_GetTick() - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS) {
429 | DHCPfineTimer = HAL_GetTick();
430 | /* process DHCP state machine */
431 | stm32_DHCP_process(netif);
432 | }
433 | }
434 |
435 | /**
436 | * @brief Inform the local DHCP of our manual IP configuration
437 | * @param None
438 | * @retval None
439 | */
440 | void stm32_DHCP_manual_config(void)
441 | {
442 | dhcp_inform(&gnetif);
443 | }
444 |
445 | /**
446 | * @brief Return status of the DHCP when renew or rebind
447 | * @param None
448 | * @retval Renew or rebind. Adapted from Arduino Ethernet library.
449 | */
450 | uint8_t stm32_get_DHCP_lease_state(void)
451 | {
452 | uint8_t res = 0;
453 | struct dhcp *dhcp = (struct dhcp *)netif_get_client_data(&gnetif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
454 |
455 | if (dhcp->state == DHCP_STATE_RENEWING) {
456 | res = 2;
457 | } else if (dhcp->state == DHCP_STATE_REBINDING) {
458 | res = 4;
459 | }
460 |
461 | return res;
462 | }
463 |
464 | /**
465 | * @brief Set DHCP state
466 | * @param state: DHCP_START, DHCP_ASK_RELEASE or DHCP_STOP. Others should not be used.
467 | * @retval None
468 | */
469 | void stm32_set_DHCP_state(uint8_t state)
470 | {
471 | DHCP_state = state;
472 | }
473 |
474 | /**
475 | * @brief Return DHCP state
476 | * @param None
477 | * @retval One of the following state:
478 | DHCP_OFF
479 | DHCP_START
480 | DHCP_WAIT_ADDRESS
481 | DHCP_ADDRESS_ASSIGNED
482 | DHCP_TIMEOUT
483 | DHCP_LINK_DOWN
484 | DHCP_ASK_RELEASE
485 | */
486 | uint8_t stm32_get_DHCP_state(void)
487 | {
488 | return DHCP_state;
489 | }
490 |
491 | #endif /* LWIP_DHCP */
492 |
493 | /**
494 | * @brief Converts IP address in readable format for user.
495 | * @param None
496 | * @retval address in uint32_t format
497 | */
498 | uint32_t stm32_eth_get_ipaddr(void)
499 | {
500 | return ip4_addr_get_u32(&(gnetif.ip_addr));
501 | }
502 |
503 | /**
504 | * @brief Converts gateway address in readable format for user.
505 | * @param None
506 | * @retval address in uint32_t format
507 | */
508 | uint32_t stm32_eth_get_gwaddr(void)
509 | {
510 | return ip4_addr_get_u32(&(gnetif.gw));
511 | }
512 |
513 | /**
514 | * @brief Converts network mask address in readable format for user.
515 | * @param None
516 | * @retval address in uint32_t format
517 | */
518 | uint32_t stm32_eth_get_netmaskaddr(void)
519 | {
520 | return ip4_addr_get_u32(&(gnetif.netmask));
521 | }
522 |
523 | /**
524 | * @brief Converts DNS address in readable format for user.
525 | * @param None
526 | * @retval address in uint32_t format
527 | */
528 | uint32_t stm32_eth_get_dnsaddr(void)
529 | {
530 | const ip_addr_t *tmp = dns_getserver(0);
531 | return ip4_addr_get_u32(tmp);
532 | }
533 |
534 | /**
535 | * @brief Converts DHCP address in readable format for user.
536 | * @param None
537 | * @retval address in uint32_t format
538 | */
539 | uint32_t stm32_eth_get_dhcpaddr(void)
540 | {
541 | struct dhcp *dhcp = (struct dhcp *)netif_get_client_data(&gnetif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
542 | return ip4_addr_get_u32(&(dhcp->server_ip_addr));
543 | }
544 |
545 | #if LWIP_NETIF_LINK_CALLBACK
546 |
547 | /**
548 | * @brief This function notify user about link status changement.
549 | * @param netif: the network interface
550 | * @retval None
551 | */
552 | void ethernetif_notify_conn_changed(struct netif *netif)
553 | {
554 | if (netif_is_link_up(netif)) {
555 | /* Update DHCP state machine if DHCP used */
556 | if (DHCP_Started_by_user == 1) {
557 | DHCP_state = DHCP_START;
558 | }
559 |
560 | /* When the netif is fully configured this function must be called.*/
561 | netif_set_up(netif);
562 | } else {
563 | /* Update DHCP state machine if DHCP used */
564 | if (DHCP_Started_by_user == 1) {
565 | DHCP_state = DHCP_LINK_DOWN;
566 | }
567 |
568 | /* When the netif link is down this function must be called.*/
569 | netif_set_down(netif);
570 | }
571 | }
572 |
573 | #endif /* LWIP_NETIF_LINK_CALLBACK */
574 |
575 | /**
576 | * @brief Notify the User about the network interface config status
577 | * @param netif: the network interface
578 | * @retval None
579 | */
580 | void User_notification(struct netif *netif)
581 | {
582 | if (netif_is_up(netif)) {
583 | //Link up
584 | } else {
585 | /* Update DHCP state machine */
586 | if (DHCP_Started_by_user == 1) {
587 | DHCP_state = DHCP_LINK_DOWN;
588 | }
589 | }
590 | }
591 |
592 | #if LWIP_DNS
593 |
594 | /**
595 | * @brief Initializes DNS
596 | * @param dnsaddr: DNS address
597 | * @retval None
598 | */
599 | void stm32_dns_init(const uint8_t *dnsaddr)
600 | {
601 | ip_addr_t ip;
602 |
603 | /* DNS initialized by DHCP when call dhcp_start() */
604 | if (!stm32_dhcp_started()) {
605 | dns_init();
606 | IP_ADDR4(&ip, dnsaddr[0], dnsaddr[1], dnsaddr[2], dnsaddr[3]);
607 | dns_setserver(0, &ip);
608 | }
609 | }
610 |
611 | /** Callback which is invoked when a hostname is found.
612 | * A function of this type must be implemented by the application using the DNS resolver.
613 | * @param name pointer to the name that was looked up.
614 | * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
615 | * or NULL if the name could not be found (or on any other error).
616 | * @param callback_arg a user-specified callback argument passed to dns_gethostbyname
617 | */
618 | void dns_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
619 | {
620 | UNUSED(name);
621 |
622 | if (ipaddr != NULL) {
623 | *((uint32_t *)callback_arg) = ip4_addr_get_u32(ipaddr);
624 | } else {
625 | *((uint32_t *)callback_arg) = 0;
626 | }
627 | }
628 |
629 | /**
630 | * Resolve a hostname (string) into an IP address.
631 | *
632 | * @param hostname the hostname that is to be queried
633 | * @param addr pointer to a uint8_t where to store the address
634 | * @return an error code compatible with Arduino Ethernet library
635 | */
636 | int8_t stm32_dns_gethostbyname(const char *hostname, uint32_t *ipaddr)
637 | {
638 | ip_addr_t iphost;
639 | err_t err;
640 | uint32_t tickstart = 0;
641 | int8_t ret = 0;
642 |
643 | *ipaddr = 0;
644 | err = dns_gethostbyname(hostname, &iphost, &dns_callback, ipaddr);
645 |
646 | switch (err) {
647 | case ERR_OK:
648 | *ipaddr = ip4_addr_get_u32(&iphost);
649 | ret = 1;
650 | break;
651 |
652 | case ERR_INPROGRESS:
653 | tickstart = HAL_GetTick();
654 | while (*ipaddr == 0) {
655 | stm32_eth_scheduler();
656 | if ((HAL_GetTick() - tickstart) >= TIMEOUT_DNS_REQUEST) {
657 | ret = -1;
658 | break;
659 | }
660 | }
661 |
662 | if (ret == 0) {
663 | if (*ipaddr == 0) {
664 | ret = -2;
665 | } else {
666 | ret = 1;
667 | }
668 | }
669 | break;
670 |
671 | case ERR_ARG:
672 | ret = -4;
673 | break;
674 |
675 | default:
676 | ret = -4;
677 | break;
678 | }
679 |
680 | return ret;
681 | }
682 |
683 | #endif /* LWIP_DNS */
684 |
685 | /**
686 | * @brief Converts a uint8_t IP address to a ip_addr_t address
687 | * @param ipu8: pointer to an address to convert
688 | * @param ipaddr: pointer where store the address converted
689 | * @retval pointer to an address in ip_addr_t format
690 | */
691 | ip_addr_t *u8_to_ip_addr(uint8_t *ipu8, ip_addr_t *ipaddr)
692 | {
693 | IP_ADDR4(ipaddr, ipu8[0], ipu8[1], ipu8[2], ipu8[3]);
694 | return ipaddr;
695 | }
696 |
697 | /**
698 | * @brief Converts a ip_addr_t IP address to a uint32_t address
699 | * @param ipaddr: pointer to an address to convert
700 | * @retval pointer to the address converted
701 | */
702 | uint32_t ip_addr_to_u32(ip_addr_t *ipaddr)
703 | {
704 | return ip4_addr_get_u32(ipaddr);
705 | }
706 |
707 | /**
708 | * @brief Allocate a pbuf with data pass in parameter
709 | * @param p: pointer to pbuf
710 | * @param buffer: pointer to data to store
711 | * @param size: number of data to store
712 | * @retval pointer to the pbuf allocated
713 | */
714 | struct pbuf *stm32_new_data(struct pbuf *p, const uint8_t *buffer, size_t size)
715 | {
716 | // Allocate memory if pbuf doesn't exit yet.
717 | if (p == NULL) {
718 | p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
719 |
720 | if (p != NULL) {
721 | // Copy data inside pbuf
722 | if (ERR_OK == pbuf_take(p, (uint8_t *)buffer, size)) {
723 | return p;
724 | } else {
725 | pbuf_free(p);
726 | }
727 | }
728 | }
729 | // If pbuf allocated, grow the size of pbuf and add new data
730 | // NOTE: pbuf_realloc can't be used to grow the size of pbuf
731 | else {
732 | struct pbuf *q = pbuf_alloc(PBUF_TRANSPORT, size + p->tot_len, PBUF_RAM);
733 |
734 | if (q != NULL) {
735 | if (ERR_OK == pbuf_copy(q, p)) {
736 | if (ERR_OK == pbuf_take_at(q, (uint8_t *)buffer, size, p->tot_len)) {
737 | pbuf_free(p);
738 | p = q;
739 | return p;
740 | }
741 | }
742 |
743 | pbuf_free(q);
744 | }
745 | }
746 |
747 | return 0;
748 | }
749 |
750 | /**
751 | * @brief Free pbuf
752 | * @param p: pointer to pbuf
753 | * @retval return always NULL
754 | */
755 | struct pbuf *stm32_free_data(struct pbuf *p)
756 | {
757 | uint16_t n;
758 |
759 | if (p != NULL) {
760 | do {
761 | n = pbuf_free(p);
762 | } while (n == 0);
763 | }
764 |
765 | return NULL;
766 | }
767 |
768 | /**
769 | * @brief This function passes pbuf data to uin8_t buffer. It takes account if
770 | * pbuf is chained.
771 | * @param data pointer to data structure
772 | * @param buffer the buffer where write the data read
773 | * @param size the number of data to read
774 | * @retval number of data read
775 | */
776 | uint16_t stm32_get_data(struct pbuf_data *data, uint8_t *buffer, size_t size)
777 | {
778 | uint16_t i;
779 | uint16_t offset;
780 | uint16_t nb;
781 | struct pbuf *ptr;
782 |
783 | if ((data->p == NULL) || (buffer == NULL) || (size == 0) ||
784 | (data->available == 0) || (data->available > data->p->tot_len)) {
785 | return 0;
786 | }
787 |
788 | nb = 0;
789 |
790 | while ((nb < size) && (data->p != NULL) && (data->available > 0)) {
791 | ptr = data->p;
792 | offset = ptr->tot_len - data->available;
793 |
794 | /* Get data from p */
795 | for (i = 0; (nb < size) && ((offset + i) < ptr->len) && (data->available > 0); i++) {
796 | buffer[nb] = pbuf_get_at(ptr, offset + i);
797 | nb++;
798 | data->available--;
799 | }
800 |
801 | if (nb < size) {
802 | /* continue with next pbuf in chain (if any) */
803 | data->p = ptr->next;
804 |
805 | if (data->p != NULL) {
806 | /* increment reference count for p */
807 | pbuf_ref(data->p);
808 | }
809 |
810 | /* chop first pbuf from chain */
811 | ptr = stm32_free_data(ptr);
812 | }
813 | }
814 |
815 | if (data->available == 0) {
816 | data->p = stm32_free_data(data->p);
817 | }
818 |
819 | return nb;
820 | }
821 |
822 | #if LWIP_UDP
823 |
824 | /**
825 | * @brief This function is called when an UDP datagram has been received on
826 | * the port UDP_PORT.
827 | * @param arg user supplied argument
828 | * @param pcb the udp_pcb which received data
829 | * @param p the packet buffer that was received
830 | * @param addr the remote IP address from which the packet was received
831 | * @param port the remote port from which the packet was received
832 | * @retval None
833 | */
834 | void udp_receive_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p,
835 | const ip_addr_t *addr, u16_t port)
836 | {
837 | struct udp_struct *udp_arg = (struct udp_struct *)arg;
838 |
839 | /* Send data to the application layer */
840 | if ((udp_arg != NULL) && (udp_arg->pcb == pcb)) {
841 | // Free the old p buffer if not read
842 | if (udp_arg->data.p != NULL) {
843 | pbuf_free(udp_arg->data.p);
844 | }
845 |
846 | udp_arg->data.p = p;
847 | udp_arg->data.available = p->len;
848 |
849 | ip_addr_copy(udp_arg->ip, *addr);
850 | udp_arg->port = port;
851 |
852 | if (udp_arg->onDataArrival != NULL) {
853 | udp_arg->onDataArrival();
854 | }
855 | } else {
856 | pbuf_free(p);
857 | }
858 | }
859 |
860 | #endif /* LWIP_UDP */
861 |
862 | #if LWIP_TCP
863 |
864 | /**
865 | * @brief Function called when TCP connection established
866 | * @param arg: user supplied argument
867 | * @param tpcb: pointer on the connection control block
868 | * @param err: when connection correctly established err should be ERR_OK
869 | * @retval err_t: returned error
870 | */
871 | err_t tcp_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
872 | {
873 | struct tcp_struct *tcp_arg = (struct tcp_struct *)arg;
874 |
875 | if (err == ERR_OK) {
876 | if ((tcp_arg != NULL) && (tcp_arg->pcb == tpcb)) {
877 | tcp_arg->state = TCP_CONNECTED;
878 |
879 | /* initialize LwIP tcp_recv callback function */
880 | tcp_recv(tpcb, tcp_recv_callback);
881 |
882 | /* initialize LwIP tcp_sent callback function */
883 | tcp_sent(tpcb, tcp_sent_callback);
884 |
885 | /* initialize LwIP tcp_err callback function */
886 | tcp_err(tpcb, tcp_err_callback);
887 |
888 | return ERR_OK;
889 | } else {
890 | /* close connection */
891 | tcp_connection_close(tpcb, tcp_arg);
892 |
893 | return ERR_ARG;
894 | }
895 | } else {
896 | /* close connection */
897 | tcp_connection_close(tpcb, tcp_arg);
898 | }
899 | return err;
900 | }
901 |
902 | /**
903 | * @brief This function is the implementation of tcp_accept LwIP callback
904 | * @param arg user supplied argument
905 | * @param newpcb: pointer on tcp_pcb struct for the newly created tcp connection
906 | * @param err: when connection correctly established err should be ERR_OK
907 | * @retval err_t: error status
908 | */
909 | err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
910 | {
911 | err_t ret_err;
912 | uint8_t accepted;
913 | struct tcp_struct **tcpClient = (struct tcp_struct **)arg;
914 |
915 | /* set priority for the newly accepted tcp connection newpcb */
916 | tcp_setprio(newpcb, TCP_PRIO_MIN);
917 |
918 | if ((tcpClient != NULL) && (ERR_OK == err)) {
919 | struct tcp_struct *client = (struct tcp_struct *)mem_malloc(sizeof(struct tcp_struct));
920 |
921 | if (client != NULL) {
922 | client->state = TCP_ACCEPTED;
923 | client->pcb = newpcb;
924 | client->data.p = NULL;
925 | client->data.available = 0;
926 |
927 | /* Looking for an empty socket */
928 | for (uint16_t i = 0; i < MAX_CLIENT; i++) {
929 | if (tcpClient[i] == NULL) {
930 | tcpClient[i] = client;
931 | accepted = 1;
932 | break;
933 | }
934 | }
935 |
936 | if (accepted) {
937 | /* pass newly allocated client structure as argument to newpcb */
938 | tcp_arg(newpcb, client);
939 |
940 | /* initialize lwip tcp_recv callback function for newpcb */
941 | tcp_recv(newpcb, tcp_recv_callback);
942 |
943 | /* initialize lwip tcp_err callback function for newpcb */
944 | tcp_err(newpcb, tcp_err_callback);
945 |
946 | /* initialize LwIP tcp_sent callback function */
947 | tcp_sent(newpcb, tcp_sent_callback);
948 |
949 | ret_err = ERR_OK;
950 | } else {
951 | /* close tcp connection */
952 | tcp_connection_close(newpcb, client);
953 | mem_free(client);
954 |
955 | /* return memory error */
956 | ret_err = ERR_MEM;
957 | }
958 | } else {
959 | /* close tcp connection */
960 | tcp_connection_close(newpcb, client);
961 | mem_free(client);
962 |
963 | /* return memory error */
964 | ret_err = ERR_MEM;
965 | }
966 | } else {
967 | tcp_close(newpcb);
968 | ret_err = ERR_ARG;
969 | }
970 | return ret_err;
971 | }
972 |
973 | /**
974 | * @brief tcp_receiv callback
975 | * @param arg: argument to be passed to receive callback
976 | * @param tpcb: tcp connection control block
977 | * @param err: receive error code
978 | * @retval err_t: returned error
979 | */
980 | static err_t tcp_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
981 | {
982 | struct tcp_struct *tcp_arg = (struct tcp_struct *)arg;
983 | err_t ret_err;
984 |
985 | /* if we receive an empty tcp frame from server => close connection */
986 | if (p == NULL) {
987 | /* we're done sending, close connection */
988 | tcp_connection_close(tpcb, tcp_arg);
989 | ret_err = ERR_OK;
990 | }
991 | /* else : a non empty frame was received from echo server but for some reason err != ERR_OK */
992 | else if (err != ERR_OK) {
993 | /* free received pbuf*/
994 | if (p != NULL) {
995 | pbuf_free(p);
996 | }
997 | ret_err = err;
998 | } else if ((tcp_arg->state == TCP_CONNECTED) || (tcp_arg->state == TCP_ACCEPTED)) {
999 | /* Acknowledge data reception */
1000 | tcp_recved(tpcb, p->tot_len);
1001 |
1002 | if (tcp_arg->data.p == NULL) {
1003 | tcp_arg->data.p = p;
1004 | } else {
1005 | pbuf_chain(tcp_arg->data.p, p);
1006 | }
1007 |
1008 | tcp_arg->data.available += p->len;
1009 | ret_err = ERR_OK;
1010 | }
1011 | /* data received when connection already closed */
1012 | else {
1013 | /* Acknowledge data reception */
1014 | tcp_recved(tpcb, p->tot_len);
1015 |
1016 | /* free pbuf and do nothing */
1017 | pbuf_free(p);
1018 | ret_err = ERR_OK;
1019 | }
1020 | return ret_err;
1021 | }
1022 |
1023 | /**
1024 | * @brief This function implements the tcp_sent LwIP callback (called when ACK
1025 | * is received from remote host for sent data)
1026 | * @param arg: pointer on argument passed to callback
1027 | * @param tcp_pcb: tcp connection control block
1028 | * @param len: length of data sent
1029 | * @retval err_t: returned error code
1030 | */
1031 | static err_t tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len)
1032 | {
1033 | struct tcp_struct *tcp_arg = (struct tcp_struct *)arg;
1034 |
1035 | LWIP_UNUSED_ARG(len);
1036 |
1037 | if ((tcp_arg != NULL) && (tcp_arg->pcb == tpcb)) {
1038 | return ERR_OK;
1039 | }
1040 |
1041 | return ERR_ARG;
1042 | }
1043 |
1044 | /** Function prototype for tcp error callback functions. Called when the pcb
1045 | * receives a RST or is unexpectedly closed for any other reason.
1046 | *
1047 | * @note The corresponding pcb is already freed when this callback is called!
1048 | *
1049 | * @param arg Additional argument to pass to the callback function (@see tcp_arg())
1050 | * @param err Error code to indicate why the pcb has been closed
1051 | * ERR_ABRT: aborted through tcp_abort or by a TCP timer
1052 | * ERR_RST: the connection was reset by the remote host
1053 | */
1054 | static void tcp_err_callback(void *arg, err_t err)
1055 | {
1056 | struct tcp_struct *tcp_arg = (struct tcp_struct *)arg;
1057 |
1058 | if (tcp_arg != NULL) {
1059 | if (ERR_OK != err) {
1060 | tcp_arg->pcb = NULL;
1061 | tcp_arg->state = TCP_CLOSING;
1062 | }
1063 | }
1064 | }
1065 |
1066 | /**
1067 | * @brief This function is used to close the tcp connection with server
1068 | * @param tpcb: tcp connection control block
1069 | * @param es: pointer on echoclient structure
1070 | * @retval None
1071 | */
1072 | void tcp_connection_close(struct tcp_pcb *tpcb, struct tcp_struct *tcp)
1073 | {
1074 | /* remove callbacks */
1075 | tcp_recv(tpcb, NULL);
1076 | tcp_sent(tpcb, NULL);
1077 | tcp_poll(tpcb, NULL, 0);
1078 | tcp_err(tpcb, NULL);
1079 | tcp_accept(tpcb, NULL);
1080 |
1081 | /* close tcp connection */
1082 | tcp_close(tpcb);
1083 |
1084 | tcp->pcb = NULL;
1085 | tcp->state = TCP_CLOSING;
1086 | }
1087 |
1088 | #endif /* LWIP_TCP */
1089 |
--------------------------------------------------------------------------------
/src/utility/stm32_eth.h:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file stm32_eth.h
4 | * @author WI6LABS
5 | * @version V1.0.0
6 | * @date 24-May-2017
7 | * @brief Include stm32_eth source files
8 | ******************************************************************************
9 | * @attention
10 | *
11 | * © COPYRIGHT(c) 2016 STMicroelectronics
12 | *
13 | * Redistribution and use in source and binary forms, with or without modification,
14 | * are permitted provided that the following conditions are met:
15 | * 1. Redistributions of source code must retain the above copyright notice,
16 | * this list of conditions and the following disclaimer.
17 | * 2. Redistributions in binary form must reproduce the above copyright notice,
18 | * this list of conditions and the following disclaimer in the documentation
19 | * and/or other materials provided with the distribution.
20 | * 3. Neither the name of STMicroelectronics nor the names of its contributors
21 | * may be used to endorse or promote products derived from this software
22 | * without specific prior written permission.
23 | *
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | *
35 | ******************************************************************************
36 | */
37 |
38 | #ifndef __STM32_ETH_H__
39 | #define __STM32_ETH_H__
40 |
41 | /* Includes ------------------------------------------------------------------*/
42 | #include "stm32_def.h"
43 | #include "lwip/ip_addr.h"
44 | #include "lwip/dhcp.h"
45 | #include "lwip/udp.h"
46 | #include "lwip/tcp.h"
47 | #include "lwip/opt.h"
48 | #include
49 |
50 | /* Exported types ------------------------------------------------------------*/
51 | /* TCP connection state */
52 | typedef enum {
53 | TCP_NONE = 0,
54 | TCP_CONNECTED,
55 | TCP_RECEIVED,
56 | TCP_SENT,
57 | TCP_ACCEPTED,
58 | TCP_CLOSING,
59 | } tcp_client_states;
60 |
61 | /* Struct to store received data */
62 | struct pbuf_data {
63 | struct pbuf *p; // the packet buffer that was received
64 | uint16_t available; // number of data
65 | };
66 |
67 | /* UDP structure */
68 | struct udp_struct {
69 | struct udp_pcb *pcb; /* pointer on the current udp_pcb */
70 | struct pbuf_data data;
71 | ip_addr_t ip; // the remote IP address from which the packet was received
72 | u16_t port; // the remote port from which the packet was received
73 | std::function onDataArrival;
74 | };
75 |
76 | /* TCP structure */
77 | struct tcp_struct {
78 | struct tcp_pcb *pcb; /* pointer on the current tcp_pcb */
79 | struct pbuf_data data;
80 | tcp_client_states state; /* current connection state */
81 | };
82 |
83 | /* Exported constants --------------------------------------------------------*/
84 | /*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
85 | #define IP_ADDR0 (uint8_t) 192
86 | #define IP_ADDR1 (uint8_t) 168
87 | #define IP_ADDR2 (uint8_t) 0
88 | #define IP_ADDR3 (uint8_t) 10
89 |
90 | /*NETMASK*/
91 | #define NETMASK_ADDR0 (uint8_t) 255
92 | #define NETMASK_ADDR1 (uint8_t) 255
93 | #define NETMASK_ADDR2 (uint8_t) 255
94 | #define NETMASK_ADDR3 (uint8_t) 0
95 |
96 | /*Gateway Address*/
97 | #define GW_ADDR0 (uint8_t) 192
98 | #define GW_ADDR1 (uint8_t) 168
99 | #define GW_ADDR2 (uint8_t) 0
100 | #define GW_ADDR3 (uint8_t) 1
101 |
102 | /* DHCP process states */
103 | #define DHCP_OFF (uint8_t) 0
104 | #define DHCP_START (uint8_t) 1
105 | #define DHCP_WAIT_ADDRESS (uint8_t) 2
106 | #define DHCP_ADDRESS_ASSIGNED (uint8_t) 3
107 | #define DHCP_TIMEOUT (uint8_t) 4
108 | #define DHCP_LINK_DOWN (uint8_t) 5
109 | #define DHCP_ASK_RELEASE (uint8_t) 6
110 |
111 | /* Maximum number of client per server */
112 | #define MAX_CLIENT 32
113 |
114 | #ifdef ETH_INPUT_USE_IT
115 | extern struct netif gnetif;
116 | #endif
117 |
118 |
119 | /* Exported functions ------------------------------------------------------- */
120 | void stm32_eth_init(const uint8_t *mac, const uint8_t *ip, const uint8_t *gw, const uint8_t *netmask);
121 | uint8_t stm32_eth_is_init(void);
122 | void stm32_eth_get_macaddr(uint8_t *mac);
123 | void stm32_eth_set_macaddr(const uint8_t *mac);
124 | uint8_t stm32_eth_link_up(void);
125 | void stm32_eth_scheduler(void);
126 |
127 | void User_notification(struct netif *netif);
128 |
129 | #if LWIP_DHCP
130 | void stm32_DHCP_Process(struct netif *netif);
131 | void stm32_DHCP_Periodic_Handle(struct netif *netif);
132 | void stm32_DHCP_manual_config(void);
133 | uint8_t stm32_get_DHCP_lease_state(void);
134 | void stm32_set_DHCP_state(uint8_t state);
135 | uint8_t stm32_get_DHCP_state(void);
136 | uint8_t stm32_dhcp_started(void);
137 | #else
138 | #error "LWIP_DHCP must be enabled in lwipopts.h"
139 | #endif
140 |
141 | #if LWIP_DNS
142 | void stm32_dns_init(const uint8_t *dnsaddr);
143 | int8_t stm32_dns_gethostbyname(const char *hostname, uint32_t *ipaddr);
144 | #else
145 | #error "LWIP_DNS must be enabled in lwipopts.h"
146 | #endif
147 |
148 | #if LWIP_UDP
149 | void udp_receive_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p,
150 | const ip_addr_t *addr, u16_t port);
151 | #else
152 | #error "LWIP_UDP must be enabled in lwipopts.h"
153 | #endif
154 |
155 | uint32_t stm32_eth_get_ipaddr(void);
156 | uint32_t stm32_eth_get_gwaddr(void);
157 | uint32_t stm32_eth_get_netmaskaddr(void);
158 | uint32_t stm32_eth_get_dnsaddr(void);
159 | uint32_t stm32_eth_get_dhcpaddr(void);
160 |
161 | struct pbuf *stm32_new_data(struct pbuf *p, const uint8_t *buffer, size_t size);
162 | struct pbuf *stm32_free_data(struct pbuf *p);
163 | uint16_t stm32_get_data(struct pbuf_data *data, uint8_t *buffer, size_t size);
164 |
165 | ip_addr_t *u8_to_ip_addr(uint8_t *ipu8, ip_addr_t *ipaddr);
166 | uint32_t ip_addr_to_u32(ip_addr_t *ipaddr);
167 |
168 | #if LWIP_TCP
169 | err_t tcp_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err);
170 | err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err);
171 | void tcp_connection_close(struct tcp_pcb *tpcb, struct tcp_struct *tcp);
172 | #else
173 | #error "LWIP_TCP must be enabled in lwipopts.h"
174 | #endif
175 |
176 | #endif /* __STM32_ETH_H__ */
177 |
--------------------------------------------------------------------------------