Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp@5:837b2680bebb, 2021-04-24 (annotated)
- Committer:
- timo_k2
- Date:
- Sat Apr 24 15:28:36 2021 +0000
- Revision:
- 5:837b2680bebb
- Parent:
- 4:4118d38b68e1
Sends a series of four UDP messages with different number of bytes. For each one prints the round trip delay. The number of bytes has no effect on the round trip delay, the latency.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| timo_k2 | 0:2a5da7b2278c | 1 | /* |
| timo_k2 | 0:2a5da7b2278c | 2 | * Copyright (c) 2006-2020 Arm Limited and affiliates. |
| timo_k2 | 0:2a5da7b2278c | 3 | * SPDX-License-Identifier: Apache-2.0 |
| timo_k2 | 0:2a5da7b2278c | 4 | *********************************** |
| timo_k2 | 4:4118d38b68e1 | 5 | * Round trip delay meter. |
| timo_k2 | 4:4118d38b68e1 | 6 | * Mbed OS Timer with microsecond precision used for a stopwatch. |
| timo_k2 | 0:2a5da7b2278c | 7 | * A microcontroller board with an Ethernet interface. |
| timo_k2 | 4:4118d38b68e1 | 8 | * For measuring documentation the date and time is taken from a NTP server. |
| timo_k2 | 3:fb39c8c13b34 | 9 | * An other microcontroller with "Round trip echo" will be needed. |
| timo_k2 | 0:2a5da7b2278c | 10 | * NXP FRDM-K64F used for testing. |
| timo_k2 | 0:2a5da7b2278c | 11 | * |
| timo_k2 | 5:837b2680bebb | 12 | * Timo Karppinen 24.4.2021 |
| timo_k2 | 0:2a5da7b2278c | 13 | ***********************************/ |
| timo_k2 | 0:2a5da7b2278c | 14 | #include "mbed.h" |
| timo_k2 | 0:2a5da7b2278c | 15 | #include "EthernetInterface.h" |
| timo_k2 | 0:2a5da7b2278c | 16 | #include "ntp-client/NTPClient.h" |
| timo_k2 | 0:2a5da7b2278c | 17 | |
| timo_k2 | 0:2a5da7b2278c | 18 | #define REMOTE_PORT 5000 |
| timo_k2 | 0:2a5da7b2278c | 19 | #define LOCAL_PORT 5001 |
| timo_k2 | 5:837b2680bebb | 20 | #define BUFF_SIZE 512 // test with 32, 128, 512 |
| timo_k2 | 0:2a5da7b2278c | 21 | |
| timo_k2 | 0:2a5da7b2278c | 22 | //Network interface |
| timo_k2 | 0:2a5da7b2278c | 23 | EthernetInterface net; |
| timo_k2 | 0:2a5da7b2278c | 24 | |
| timo_k2 | 0:2a5da7b2278c | 25 | //Threads |
| timo_k2 | 0:2a5da7b2278c | 26 | Thread recv_thread; |
| timo_k2 | 4:4118d38b68e1 | 27 | |
| timo_k2 | 0:2a5da7b2278c | 28 | // UDP |
| timo_k2 | 5:837b2680bebb | 29 | SocketAddress clientUDP; // Client on remote device. IP address from incoming message. |
| timo_k2 | 0:2a5da7b2278c | 30 | UDPSocket serverUDP; // UDP server in this device |
| timo_k2 | 0:2a5da7b2278c | 31 | |
| timo_k2 | 0:2a5da7b2278c | 32 | //NTP server is a time server used for delivering timing information for networks. |
| timo_k2 | 4:4118d38b68e1 | 33 | //Returns 32 bits for seconds and 32 bits for fraction of seconds. |
| timo_k2 | 0:2a5da7b2278c | 34 | //#define ntpAddress "2.pool.ntp.org" |
| timo_k2 | 0:2a5da7b2278c | 35 | #define ntpAddress "time.mikes.fi" // The VTT Mikes in Helsinki |
| timo_k2 | 0:2a5da7b2278c | 36 | #define ntpPort 123 |
| timo_k2 | 4:4118d38b68e1 | 37 | // The address and port number can be replaced with the ones for the local |
| timo_k2 | 4:4118d38b68e1 | 38 | // network NTP server. |
| timo_k2 | 0:2a5da7b2278c | 39 | |
| timo_k2 | 0:2a5da7b2278c | 40 | // Functions |
| timo_k2 | 4:4118d38b68e1 | 41 | //time_t getNTP(); |
| timo_k2 | 0:2a5da7b2278c | 42 | void udpReceive( void ); |
| timo_k2 | 5:837b2680bebb | 43 | void udpSend( int ii ); |
| timo_k2 | 0:2a5da7b2278c | 44 | |
| timo_k2 | 3:fb39c8c13b34 | 45 | DigitalIn sw2(SW2); // sw2 on K64F, button pressed = FALSE |
| timo_k2 | 4:4118d38b68e1 | 46 | DigitalOut led2(LED2); // RGB LED on K64F, FALSE = Green |
| timo_k2 | 0:2a5da7b2278c | 47 | int sw2state = 0; |
| timo_k2 | 0:2a5da7b2278c | 48 | int sw2old = 1; |
| timo_k2 | 0:2a5da7b2278c | 49 | |
| timo_k2 | 5:837b2680bebb | 50 | char in_data[BUFF_SIZE]; // 512 taken as max message size |
| timo_k2 | 0:2a5da7b2278c | 51 | int newDatagram = 0; |
| timo_k2 | 2:150dadff3c6b | 52 | int newDatagramOld = 0; |
| timo_k2 | 4:4118d38b68e1 | 53 | //time_t timeNTP = 0; |
| timo_k2 | 0:2a5da7b2278c | 54 | |
| timo_k2 | 4:4118d38b68e1 | 55 | Timer stopwatch; // Timer is an operating system class since OS 6.0 |
| timo_k2 | 2:150dadff3c6b | 56 | Timer armedFor; |
| timo_k2 | 0:2a5da7b2278c | 57 | |
| timo_k2 | 0:2a5da7b2278c | 58 | int main() { |
| timo_k2 | 3:fb39c8c13b34 | 59 | printf("\nRound trip delay in UDP messaging (using Ethernet)\n"); |
| timo_k2 | 0:2a5da7b2278c | 60 | |
| timo_k2 | 0:2a5da7b2278c | 61 | //Bring up the network interface |
| timo_k2 | 5:837b2680bebb | 62 | //eth.set_network(IP_Adress,MASK, GATEWAY); // leave out if using DHCP |
| timo_k2 | 5:837b2680bebb | 63 | net.set_network("192.168.1.10","255.255.252.0","192.168.1.1"); |
| timo_k2 | 0:2a5da7b2278c | 64 | net.connect(); |
| timo_k2 | 0:2a5da7b2278c | 65 | |
| timo_k2 | 0:2a5da7b2278c | 66 | // Show network address |
| timo_k2 | 0:2a5da7b2278c | 67 | SocketAddress netAddress; |
| timo_k2 | 0:2a5da7b2278c | 68 | net.get_ip_address(&netAddress); |
| timo_k2 | 0:2a5da7b2278c | 69 | printf("\n\n NTPClient - UDPServer IP Address: %s\n", netAddress.get_ip_address() ? netAddress.get_ip_address():"None"); |
| timo_k2 | 0:2a5da7b2278c | 70 | |
| timo_k2 | 4:4118d38b68e1 | 71 | |
| timo_k2 | 4:4118d38b68e1 | 72 | // NTP client |
| timo_k2 | 4:4118d38b68e1 | 73 | |
| timo_k2 | 4:4118d38b68e1 | 74 | //printf("Message to NTP time server...\n"); |
| timo_k2 | 4:4118d38b68e1 | 75 | //timeNTP = getNTP(); |
| timo_k2 | 4:4118d38b68e1 | 76 | //printf("Current time in day month hour.min.sec year is %s\r\n", ctime(&timeNTP)); |
| timo_k2 | 0:2a5da7b2278c | 77 | |
| timo_k2 | 0:2a5da7b2278c | 78 | // UDP server |
| timo_k2 | 0:2a5da7b2278c | 79 | |
| timo_k2 | 0:2a5da7b2278c | 80 | serverUDP.open(&net); |
| timo_k2 | 0:2a5da7b2278c | 81 | int err = serverUDP.bind(LOCAL_PORT); |
| timo_k2 | 0:2a5da7b2278c | 82 | printf("Port status is: %d\n",err); |
| timo_k2 | 0:2a5da7b2278c | 83 | |
| timo_k2 | 0:2a5da7b2278c | 84 | recv_thread.start(udpReceive); |
| timo_k2 | 0:2a5da7b2278c | 85 | printf("Listening has been started at port number %d\n", LOCAL_PORT); |
| timo_k2 | 4:4118d38b68e1 | 86 | printf("The operator for the \"Echo board\" should send a message!\n "); |
| timo_k2 | 0:2a5da7b2278c | 87 | printf("The IP will be taken from the incoming message\n"); |
| timo_k2 | 4:4118d38b68e1 | 88 | printf("Press the blue switch after receiving \"Echo server listening\"\n"); |
| timo_k2 | 0:2a5da7b2278c | 89 | |
| timo_k2 | 0:2a5da7b2278c | 90 | while(1) { |
| timo_k2 | 0:2a5da7b2278c | 91 | sw2state = sw2.read(); |
| timo_k2 | 5:837b2680bebb | 92 | printf( "\nsw2 %d - Push for sending Echo Request\n", sw2state); |
| timo_k2 | 0:2a5da7b2278c | 93 | |
| timo_k2 | 4:4118d38b68e1 | 94 | if((sw2state == 0)&&(sw2state != sw2old)) { // Note! Checking for FALSE sw |
| timo_k2 | 5:837b2680bebb | 95 | led2.write(1); |
| timo_k2 | 5:837b2680bebb | 96 | for ( int i=0; i < 5; ++i){ |
| timo_k2 | 2:150dadff3c6b | 97 | armedFor.reset(); // reset timer to zero |
| timo_k2 | 0:2a5da7b2278c | 98 | stopwatch.reset(); // reset stopwatch timer to zero |
| timo_k2 | 4:4118d38b68e1 | 99 | //timeNTP = getNTP(); |
| timo_k2 | 5:837b2680bebb | 100 | ThisThread::sleep_for(10ms); //time for resetting |
| timo_k2 | 2:150dadff3c6b | 101 | armedFor.start(); |
| timo_k2 | 4:4118d38b68e1 | 102 | //stopwatch.start(); // moved to udpSend subroutine |
| timo_k2 | 5:837b2680bebb | 103 | udpSend(i); |
| timo_k2 | 0:2a5da7b2278c | 104 | |
| timo_k2 | 0:2a5da7b2278c | 105 | |
| timo_k2 | 4:4118d38b68e1 | 106 | // Start polling for the incoming "Echo" UDP datagram |
| timo_k2 | 5:837b2680bebb | 107 | while ( armedFor.elapsed_time().count() <2000000 ){ |
| timo_k2 | 2:150dadff3c6b | 108 | if((newDatagram == 1)&&(newDatagram != newDatagramOld)){ |
| timo_k2 | 4:4118d38b68e1 | 109 | stopwatch.stop(); |
| timo_k2 | 2:150dadff3c6b | 110 | char firstChar; |
| timo_k2 | 2:150dadff3c6b | 111 | firstChar = in_data[0]; |
| timo_k2 | 5:837b2680bebb | 112 | printf( "\nfirstChar: %s\n", &firstChar); |
| timo_k2 | 5:837b2680bebb | 113 | ThisThread::sleep_for(120ms); // waiting for print buffer, 100 ms was just too short |
| timo_k2 | 2:150dadff3c6b | 114 | for (int k =0; k < BUFF_SIZE; k++){ |
| timo_k2 | 2:150dadff3c6b | 115 | in_data[k] = 0; |
| timo_k2 | 4:4118d38b68e1 | 116 | } |
| timo_k2 | 5:837b2680bebb | 117 | // printing for testing. Replace with writing once to a SD memory card. |
| timo_k2 | 5:837b2680bebb | 118 | //printf("Measured at ( day month hour.min.sec year ) %s\r\n", ctime(&timeNTP)); |
| timo_k2 | 5:837b2680bebb | 119 | printf("The time taken was %llu microseconds\n", stopwatch.elapsed_time().count()); |
| timo_k2 | 5:837b2680bebb | 120 | } // if new datagram |
| timo_k2 | 4:4118d38b68e1 | 121 | newDatagramOld = newDatagram; //Reading the stopwatch once only |
| timo_k2 | 5:837b2680bebb | 122 | newDatagram = 0; |
| timo_k2 | 5:837b2680bebb | 123 | } // while armed |
| timo_k2 | 5:837b2680bebb | 124 | ThisThread::sleep_for(70ms); // Delay of 10ms + 120ms + 70ms = 200ms |
| timo_k2 | 5:837b2680bebb | 125 | } //for i loop |
| timo_k2 | 2:150dadff3c6b | 126 | |
| timo_k2 | 2:150dadff3c6b | 127 | // printing for testing. Replace with writing once to a SD memory card. |
| timo_k2 | 4:4118d38b68e1 | 128 | //printf("Measured at ( day month hour.min.sec year ) %s\r\n", ctime(&timeNTP)); |
| timo_k2 | 5:837b2680bebb | 129 | //printf("The time taken was %llu microseconds\n", stopwatch.elapsed_time().count()); |
| timo_k2 | 5:837b2680bebb | 130 | } // if sw2 |
| timo_k2 | 0:2a5da7b2278c | 131 | sw2old = sw2state; // Once only with pushing the button as long as you like. |
| timo_k2 | 4:4118d38b68e1 | 132 | led2.write(0); |
| timo_k2 | 2:150dadff3c6b | 133 | armedFor.stop(); |
| timo_k2 | 0:2a5da7b2278c | 134 | stopwatch.stop(); // Stop the stopwatch if we did not receive the echo. |
| timo_k2 | 0:2a5da7b2278c | 135 | |
| timo_k2 | 4:4118d38b68e1 | 136 | ThisThread::sleep_for(1000ms); |
| timo_k2 | 5:837b2680bebb | 137 | } // while loop |
| timo_k2 | 5:837b2680bebb | 138 | } // main |
| timo_k2 | 0:2a5da7b2278c | 139 | |
| timo_k2 | 0:2a5da7b2278c | 140 | // The functions |
| timo_k2 | 0:2a5da7b2278c | 141 | |
| timo_k2 | 0:2a5da7b2278c | 142 | time_t getNTP() { |
| timo_k2 | 0:2a5da7b2278c | 143 | NTPClient ntp(&net); |
| timo_k2 | 0:2a5da7b2278c | 144 | ntp.set_server(ntpAddress, ntpPort); |
| timo_k2 | 0:2a5da7b2278c | 145 | time_t timestamp = ntp.get_timestamp(); |
| timo_k2 | 0:2a5da7b2278c | 146 | if (timestamp < 0) { |
| timo_k2 | 0:2a5da7b2278c | 147 | printf("An error occurred when getting the time. Code: %u\r\n", timestamp); |
| timo_k2 | 0:2a5da7b2278c | 148 | } |
| timo_k2 | 0:2a5da7b2278c | 149 | else { // the printings for testing only! |
| timo_k2 | 4:4118d38b68e1 | 150 | printf("The timestamp seconds from the NTP server in\r\n 32 bit hexadecimal number is %X\r\n", timestamp); |
| timo_k2 | 4:4118d38b68e1 | 151 | printf(" decimal number is %u\r\n", timestamp); |
| timo_k2 | 0:2a5da7b2278c | 152 | timestamp += (60*60*2); // GMT +2 for Finland for the winter time. |
| timo_k2 | 4:4118d38b68e1 | 153 | printf("Current time is %s\r\n", ctime(×tamp)); |
| timo_k2 | 0:2a5da7b2278c | 154 | } |
| timo_k2 | 0:2a5da7b2278c | 155 | return timestamp; |
| timo_k2 | 0:2a5da7b2278c | 156 | } |
| timo_k2 | 0:2a5da7b2278c | 157 | |
| timo_k2 | 0:2a5da7b2278c | 158 | void udpReceive() |
| timo_k2 | 0:2a5da7b2278c | 159 | { |
| timo_k2 | 0:2a5da7b2278c | 160 | int bytes; |
| timo_k2 | 0:2a5da7b2278c | 161 | while(1) { |
| timo_k2 | 5:837b2680bebb | 162 | bytes = serverUDP.recvfrom(&clientUDP, &in_data, 512); // 512 as largest possible |
| timo_k2 | 3:fb39c8c13b34 | 163 | newDatagram = 1; // set this before using time for printing |
| timo_k2 | 5:837b2680bebb | 164 | ThisThread::sleep_for(50ms); // waiting for the print buffer |
| timo_k2 | 0:2a5da7b2278c | 165 | printf("bytes received: %d\n",bytes); |
| timo_k2 | 0:2a5da7b2278c | 166 | printf("string: %s\n",in_data); |
| timo_k2 | 0:2a5da7b2278c | 167 | printf("client address: %s\n", clientUDP.get_ip_address()); |
| timo_k2 | 0:2a5da7b2278c | 168 | } |
| timo_k2 | 0:2a5da7b2278c | 169 | } |
| timo_k2 | 0:2a5da7b2278c | 170 | |
| timo_k2 | 5:837b2680bebb | 171 | void udpSend(int ii) |
| timo_k2 | 0:2a5da7b2278c | 172 | { |
| timo_k2 | 5:837b2680bebb | 173 | int BUFF_SIZE_NOW; |
| timo_k2 | 5:837b2680bebb | 174 | switch(ii){ |
| timo_k2 | 5:837b2680bebb | 175 | case 0: |
| timo_k2 | 5:837b2680bebb | 176 | BUFF_SIZE_NOW = BUFF_SIZE/16; |
| timo_k2 | 5:837b2680bebb | 177 | break; |
| timo_k2 | 5:837b2680bebb | 178 | case 1: |
| timo_k2 | 5:837b2680bebb | 179 | BUFF_SIZE_NOW = BUFF_SIZE/8; |
| timo_k2 | 5:837b2680bebb | 180 | break; |
| timo_k2 | 5:837b2680bebb | 181 | case 2: |
| timo_k2 | 5:837b2680bebb | 182 | BUFF_SIZE_NOW = BUFF_SIZE/4; |
| timo_k2 | 5:837b2680bebb | 183 | break; |
| timo_k2 | 5:837b2680bebb | 184 | case 3: |
| timo_k2 | 5:837b2680bebb | 185 | BUFF_SIZE_NOW = BUFF_SIZE/2; |
| timo_k2 | 5:837b2680bebb | 186 | break; |
| timo_k2 | 5:837b2680bebb | 187 | case 4: |
| timo_k2 | 5:837b2680bebb | 188 | BUFF_SIZE_NOW = BUFF_SIZE; |
| timo_k2 | 5:837b2680bebb | 189 | break; |
| timo_k2 | 5:837b2680bebb | 190 | } |
| timo_k2 | 5:837b2680bebb | 191 | char out_data[BUFF_SIZE_NOW]; |
| timo_k2 | 5:837b2680bebb | 192 | snprintf(out_data, BUFF_SIZE_NOW, "UDP message for getting the Echo" ); |
| timo_k2 | 5:837b2680bebb | 193 | printf("\nSending out: %s\n", out_data); |
| timo_k2 | 0:2a5da7b2278c | 194 | printf("with %d" , sizeof(out_data)); |
| timo_k2 | 0:2a5da7b2278c | 195 | printf(" data bytes in UDP datagram\n"); |
| timo_k2 | 4:4118d38b68e1 | 196 | clientUDP.set_port(REMOTE_PORT); |
| timo_k2 | 4:4118d38b68e1 | 197 | stopwatch.start(); // starting the stopwatch after preparations are done |
| timo_k2 | 4:4118d38b68e1 | 198 | serverUDP.sendto(clientUDP, out_data, sizeof(out_data)); |
| timo_k2 | 4:4118d38b68e1 | 199 | } |