Skip to content

Commit

Permalink
NTP server code
Browse files Browse the repository at this point in the history
  • Loading branch information
ddrown committed Jun 5, 2020
1 parent bfc5824 commit ce3a050
Show file tree
Hide file tree
Showing 20 changed files with 222 additions and 671 deletions.
52 changes: 52 additions & 0 deletions Inc/NTPServer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#define NTP_LEAP_NONE 0
#define NTP_LEAP_61S 1
#define NTP_LEAP_59S 2
#define NTP_LEAP_UNSYNC 3
#define NTP_VERS_4 4
#define NTP_VERS_3 3
#define NTP_MODE_RSVD 0
#define NTP_MODE_SYMACT 1
#define NTP_MODE_SYMPAS 2
#define NTP_MODE_CLIENT 3
#define NTP_MODE_SERVER 4
#define NTP_MODE_BROADC 5
#define NTP_MODE_CTRL 6
#define NTP_MODE_PRIV 7

extern "C" {
struct ntp_packet {
uint8_t mode : 3;
uint8_t version : 3;
uint8_t leap : 2;
uint8_t stratum;
uint8_t poll;
int8_t precision;
uint16_t root_delay;
uint16_t root_delay_fb;
uint16_t dispersion;
uint16_t dispersion_fb;
uint32_t ident;
uint32_t ref_time;
uint32_t ref_time_fb;
uint32_t org_time;
uint32_t org_time_fb;
uint32_t recv_time;
uint32_t recv_time_fb;
uint32_t trans_time;
uint32_t trans_time_fb;
};
};

class NTPServer {
public:
NTPServer();
void recv(struct pbuf *request_buf, struct pbuf *response_buf, const struct ip_addr *addr, u16_t port);
void setup();

private:
struct udp_pcb *ntp_pcb;
};

extern NTPServer server;
13 changes: 0 additions & 13 deletions Inc/adc.h

This file was deleted.

8 changes: 2 additions & 6 deletions Inc/ntp.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
#ifndef NTP_H
#define NTP_H
#pragma once

void TXTimestampCallback(uint32_t TimeStampLow, uint32_t TimeStampHigh);
void ntp_init();
void ntp_poll(uint8_t dest);
void ntp_poll_set(uint8_t active);

#endif // NTP_H
8 changes: 3 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ Src/lwip.c \
Src/ethernetif.c \
Src/ping.c \
Src/ptp.c \
Src/ntp.c \
Src/int64.c \
Src/adc.c \
Src/timer.c \
Src/jobs.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_eth.c \
Expand Down Expand Up @@ -115,8 +113,6 @@ Middlewares/Third_Party/LwIP/src/core/ipv6/mld6.c \
Middlewares/Third_Party/LwIP/src/core/ipv6/nd6.c \
Middlewares/Third_Party/LwIP/src/apps/mqtt/mqtt.c \
Middlewares/Third_Party/LwIP/src/apps/sntp/sntp.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c \
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c

Expand All @@ -126,7 +122,9 @@ Src/DateTime.cpp \
Src/GPS.cpp \
Src/GPSDateTime.cpp \
Src/timesync.cpp \
Src/ClockPID.cpp
Src/ClockPID.cpp \
Src/ntp.cpp \
Src/NTPServer.cpp

# ASM sources
ASM_SOURCES = \
Expand Down
9 changes: 7 additions & 2 deletions Middlewares/Third_Party/LwIP/src/include/lwip/pbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,14 @@ struct pbuf {
u16_t ref;

// RX timestamp
u32_t timestamp_seconds;
u32_t timestamp_subseconds;
union {
u32_t parts[2];
uint64_t whole;
} ts;
};
// arm is little endian
#define TS_POS_S 1
#define TS_POS_SUBS 0


/** Helper struct for const-correctness only.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ Hardware: Seeed's Arch Max with STM32F407 + 100M ethernet

Software: built on STM32CubeMX + LwIP

It will poll the NTP servers listed in Src/ntp.c:dests every second and output to the debug serial port (USB J8)
There's a simple command line interface on the debug serial port (USB J8)

There's a simple command line interface
It expects a GPS to be connected to PD6 (uart RX) and PA3 (GPS PPS)

Build system is make + arm-none-eabi-gcc

Expand Down
104 changes: 104 additions & 0 deletions Src/NTPServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
extern "C" {
#include "main.h"
#include "lwip/udp.h"
#include "ptp.h"
#include "uart.h"
};

#include "NTPServer.h"

NTPServer server;

// the values below are in 2^32 fractional second units
// 12821ns, measured
#define TX_DELAY 55065
/*
* from DP83848J datasheet, T2.25.5
* RXD[1:0] latency from symbol on receive pair = 38 bits
* (default elasticisty of 4 bits)
*/
#define RX_PHY 1632
#define TX_PHY 730
// adjusting from preamble timestamp to trailer timestamp: 752 bits at 100M
#define RX_TRAILER 32298

void NTPServer::recv(struct pbuf *request_buf, struct pbuf *response_buf, const struct ip_addr *addr, u16_t port) {
union {
uint32_t parts[2];
uint64_t whole;
} start_tx;

// drop too small packets
if(request_buf->len < sizeof(struct ntp_packet)) {
return;
}

struct ntp_packet *request = (struct ntp_packet *)request_buf->payload;
struct ntp_packet *response = (struct ntp_packet *)response_buf->payload;

if(request->version < 2 || request->version > 4) {
return; // unknown version
}

if(request->mode != NTP_MODE_CLIENT) {
return; // not a client request
}

response->mode = NTP_MODE_SERVER;
response->version = NTP_VERS_4;
response->leap = NTP_LEAP_NONE; // TODO: no leap second support
response->stratum = 1;
if(response->poll < 6) {
response->poll = 6;
}
if(response->poll > 12) {
response->poll = 12;
}
response->precision = -27; // 168MHz
response->root_delay = 0; // TODO
response->root_delay_fb = 0; // TODO
response->dispersion = 0; // TODO
response->dispersion_fb = 0; // TODO
response->ident = htonl(0x50505300); // "PPS"
response->ref_time = htonl(request_buf->ts.parts[TS_POS_S]); // TODO
response->ref_time_fb = 0;
response->org_time = request->trans_time;
response->org_time_fb = request->trans_time_fb;

request_buf->ts.parts[TS_POS_SUBS] *= 2; // PTP clock runs at 2^31
request_buf->ts.whole += RX_TRAILER - RX_PHY;
response->recv_time = htonl(request_buf->ts.parts[TS_POS_S]);
response->recv_time_fb = htonl(request_buf->ts.parts[TS_POS_SUBS]);

start_tx.whole = ptp_now();
start_tx.whole += TX_DELAY + TX_PHY;
response->trans_time = htonl(start_tx.parts[TS_POS_S]);
response->trans_time_fb = htonl(start_tx.parts[TS_POS_SUBS]);

udp_sendto(ntp_pcb, response_buf, addr, port);
}

extern "C" {
static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const struct ip_addr *addr, u16_t port) {
UNUSED(arg);
UNUSED(pcb);
struct pbuf *response = pbuf_alloc(PBUF_IP, sizeof(struct ntp_packet), PBUF_RAM);
if(!response) {
pbuf_free(p);
return;
}
server.recv(p, response, addr, port);
pbuf_free(p);
pbuf_free(response);
}
};

NTPServer::NTPServer() {
ntp_pcb = NULL;
}

void NTPServer::setup() {
ntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
udp_recv(ntp_pcb, ntp_recv, NULL);
udp_bind(ntp_pcb, IP_ANY_TYPE, 123);
}
Loading

0 comments on commit ce3a050

Please sign in to comment.