Skip to content

Commit

Permalink
Working UDP example
Browse files Browse the repository at this point in the history
  • Loading branch information
Dr-Daily committed Oct 10, 2021
1 parent 673fd8c commit 845a040
Show file tree
Hide file tree
Showing 2 changed files with 328 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*/.vs/*
327 changes: 327 additions & 0 deletions CAN_to_UDP/CAN_to_UDP.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <FlexCAN_T4.h>
#include <TimeLib.h> // be able to keep realtime.
#include <TeensyID.h>

FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> Can0;
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can1;

#define CAN0_BAUD_RATE 250000
#define CAN1_BAUD_RATE 250000

#define DHCP_RENEW_THRESHOLD_MS 86400000 //86,400,000 milliseconds in a day
#define NTP_RENEW_INTERVAL_MS 300000 // 300,000 milliseconds in 5 minutes

EthernetUDP Udp;
#define WIZNET_CHIP_SELECT 10



uint32_t UDP_TX_Count;
uint32_t CAN0_RX_Count;
uint32_t CAN1_RX_Count;
uint32_t Total_CAN_RX_Count;

bool LED_state;

elapsedMillis DHCPLeaseRenewTimer;
elapsedMillis NTPRenewTimer;
elapsedMillis CANmessageTimer;

elapsedMicros microsecondsPerSecond;



// For a Maximum Transmission Unit (MTU) of 1500, 20 bytes are use for IP headers and 8 bytes are used for UDP headers
// This leaves 1472 bytes for the CAN data. However, if the last CAN frame spilled over the MTU boundary,
// Then the UDP packet will be fragmented and the header data will be sent twice to carry along the extra data.
// Therefore, we want to trigger a send command before the MTU is reached, so our threshold needs to be less than 1472
// by an amount equal to a can frame. There are 19 bytes per CAN frame.
// See https://wiki.networksecuritytoolkit.org/nstwiki/index.php/LAN_Ethernet_Maximum_Rates,_Generation,_Capturing_&_Monitoring
#define UDP_TX_PACKET_MAX_SIZE 1472 //increase UDP size
#define CAN_FRAME_SIZE 19
#define CAN_BUFFER_THRESHOLD UDP_TX_PACKET_MAX_SIZE-CAN_FRAME_SIZE
#define UDP_TX_PERIOD_MS 40

byte CANBuffer[UDP_TX_PACKET_MAX_SIZE];
byte packetBuffer[UDP_TX_PACKET_MAX_SIZE];
uint16_t CANBufferPosition = 0;

#define PACKED_CAN_FRAMES_NO_REAL_TIME 0x01

// We'll determine the MAC based on the TeensyID library.
// https://github.com/sstaub/TeensyID
uint8_t mac[6];

// Use this as a placeholder. We'll change it when we get the local IP.
IPAddress broadcast_address(192,168,1,255);
unsigned int localPort = 8899; // local port to listen for UDP packets

#define NTP_PACKET_SIZE 48 // NTP time stamp is in the first 48 bytes
const char timeServer[] = "time.nist.gov"; // time.nist.gov NTP serverof the message


void setup(void) {
pinMode(13, OUTPUT); digitalWrite(13, HIGH);
pinMode(14, OUTPUT); digitalWrite(14, LOW); /* optional tranceiver enable pin */
pinMode(35, OUTPUT); digitalWrite(35, LOW); /* optional tranceiver enable pin */
setSyncProvider(getTeensy3Time);
setSyncInterval(1);

// start Ethernet and UDP
Ethernet.init(WIZNET_CHIP_SELECT); // Based on the Schematic for the CAN-2 Ethernet board.
teensyMAC(mac); // Assign a unique MAC address. This uses the processors MAC (not the Wiznet)
while (true) {
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
} else if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
// no point in carrying on, so do nothing forevermore:
delay(1);
}
else { // Connection is good
Serial.print("The MAC address is: ");
Serial.println(teensyMAC());
Serial.print("The DNS server IP address is: ");
Serial.println(Ethernet.dnsServerIP());
Serial.print("The gateway IP address is: ");
Serial.println(Ethernet.gatewayIP());
// print your local IP address:
Serial.print("The Local IP address is: ");
Serial.println(Ethernet.localIP());
broadcast_address = Ethernet.localIP();
broadcast_address[3] = 255;
Serial.print("The Broadcast IP address is: ");
Serial.println(broadcast_address);
Serial.print("The subnet mask is: ");
Serial.println(Ethernet.subnetMask());

break;
}
}

Ethernet.setRetransmissionCount(3);

// Start the UDP client
if(Udp.begin(localPort)) Serial.println("UDP Started");

//Start the CAN channels
Can0.begin();
Serial.print("CAN0 Bitrate: ");
Serial.print(CAN0_BAUD_RATE);
Can0.setBaudRate(CAN0_BAUD_RATE);
Can0.setMaxMB(16);
Can0.enableFIFO();
Can0.enableFIFOInterrupt();
Can0.onReceive(canSniff0);
Serial.println("CAN0 mailbox Status:");
Can0.mailboxStatus(); //This prints out the status

Can1.begin();
Serial.print("CAN1 Bitrate: ");
Serial.print(CAN1_BAUD_RATE);
Can1.setBaudRate(CAN1_BAUD_RATE);
Can1.setMaxMB(16);
Can1.enableFIFO();
Can1.enableFIFOInterrupt();
Can1.onReceive(canSniff1);
Serial.println("CAN1 mailbox Status:");
Can1.mailboxStatus(); //This prints out the status

NTPRenewTimer = NTP_RENEW_INTERVAL_MS + 1;
}

// send an NTP request to the time server at the given address
void sendpacket(const char * address) {
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); // NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}

void canSniff0(const CAN_message_t &msg) {
CAN0_RX_Count++;
uint8_t channel = 0;
canSniff(msg,channel,CAN0_RX_Count);
}

void canSniff1(const CAN_message_t &msg) {
CAN1_RX_Count++;
uint8_t channel = 1;
canSniff(msg,channel,CAN1_RX_Count);
}

void canSniff(const CAN_message_t &msg, uint8_t channel, uint32_t CAN_RX_Count) {
// Format defined by Subhohjeet in the RFC proposal!!!
Total_CAN_RX_Count++;

// Format 1
uint32_t micro_t = microsecondsPerSecond;
memcpy(&CANBuffer[CANBufferPosition],&channel,1);
CANBufferPosition += 1;
memcpy(&CANBuffer[CANBufferPosition],&micro_t,3);
CANBufferPosition += 3;
memcpy(&CANBuffer[CANBufferPosition],&msg.timestamp,2);
CANBufferPosition += 2;
memcpy(&CANBuffer[CANBufferPosition],&msg.id,4);
CANBufferPosition += 4;
memcpy(&CANBuffer[CANBufferPosition],&msg.len,1);
CANBufferPosition += 1;
memcpy(&CANBuffer[CANBufferPosition],&msg.buf,8);
CANBufferPosition += 8;
}

/*
* Reset the microsecond counter and return the realtime clock
* This function requires the sync interval to be exactly 1 second.
*/
time_t getTeensy3Time(){
microsecondsPerSecond = 0;
return Teensy3Clock.get();
}
void loop() {
Can0.events();
//Periodically Renew the DHCP Lease
//This may be blocking an affect the logging. Uncomment if needed
// if (DHCPLeaseRenewTimer > DHCP_RENEW_THRESHOLD_MS){
// DHCPLeaseRenewTimer = 0;
// Serial.print("DHCP Lease Renewal Returned : ");
// Serial.println(Ethernet.maintain()); // Renew DHCP Lease
// }

// Send a request to get NTP time.
if (NTPRenewTimer >= NTP_RENEW_INTERVAL_MS){
NTPRenewTimer = 0;
sendpacket(timeServer);
}

if (CANBufferPosition > CAN_BUFFER_THRESHOLD || CANmessageTimer > UDP_TX_PERIOD_MS){
CANmessageTimer = 0;
Udp.beginPacket(broadcast_address, 9101);
Udp.write(CANBuffer, CANBufferPosition);
Udp.endPacket();
Serial.print("Sent UDP Message: ");
for (int i=0; i < CANBufferPosition; i++){
Serial.printf("%02X ",CANBuffer[i]);
}
Serial.println();
memset(CANBuffer,0,sizeof(CANBuffer));
CANBuffer[0] = PACKED_CAN_FRAMES_NO_REAL_TIME;
CANBufferPosition = 1;

UDP_TX_Count++;
memcpy(&CANBuffer[CANBufferPosition], &UDP_TX_Count, 4);
CANBufferPosition += 4;


memcpy(&CANBuffer[CANBufferPosition], &Total_CAN_RX_Count, 4);
CANBufferPosition += 4;

time_t timeStamp = now();
memcpy(&CANBuffer[CANBufferPosition], &timeStamp, 4);
CANBufferPosition += 4;
}

int packetSize = Udp.parsePacket();
if(Udp.available()){
Serial.print("Received packet of size ");
Serial.println(packetSize);
Serial.print("From ");
IPAddress remote = Udp.remoteIP();
for (int i =0; i < 4; i++)
{
Serial.print(remote[i], DEC);
if (i < 3)
{
Serial.print(".");
}
}
Serial.print(", port ");
Serial.println(Udp.remotePort());

// read the packet into packetBufffer
Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
Serial.print("Contents: ");
for (int i=0; i< packetSize; i++){
Serial.printf("%02X ",packetBuffer[i]);
}
Serial.println();

if (Udp.remotePort() == 123){
// Now, read the data from the UDP packet

// the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, extract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
Serial.print("Seconds since Jan 1 1900 = ");
Serial.println(secsSince1900);

// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
Serial.println(epoch);


// print the hour, minute and second:
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
Serial.print(':');
if (((epoch % 3600) / 60) < 10) {
// In the first 10 minutes of each hour, we'll want a leading '0'
Serial.print('0');
}
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
Serial.print(':');
if ((epoch % 60) < 10) {
// In the first 10 seconds of each minute, we'll want a leading '0'
Serial.print('0');
}
Serial.println(epoch % 60); // print the second

Teensy3Clock.set(epoch); // set the RTC
setTime(epoch);
}
}

static uint32_t timeout = millis();
if ( millis() - timeout > 500 ) {
CAN_message_t msg;
msg.id = 0x7DD;
for ( uint8_t i = 0; i < 8; i++ ) msg.buf[i] = i + 1;
Can0.write(msg);
timeout = millis();
LED_state = !LED_state;
digitalWrite(13, LED_state);
}

}

0 comments on commit 845a040

Please sign in to comment.