-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
328 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*/.vs/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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],µ_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); | ||
} | ||
|
||
} |