Commit e3070e4f authored by Martin Vítek's avatar Martin Vítek

This SNTP client should be working

parent 2bfa15c4
......@@ -54,6 +54,7 @@ void ARP_protocol::assembly_request(const IP& ip, ethernet_payload& payload)
{
arp_packet* arp = (arp_packet*)payload.data;
//TODO: Don't set length here, set it in NixieStack
payload.length = sizeof(arp_packet);
arp->hw_type = __htons(ETHERNET);
......@@ -103,12 +104,12 @@ void ARP_protocol::assembly_reply(const IP& requested_ip, const MAC& requested_m
bool ARP_protocol::decode(const ethernet_payload& rx_payload, ethernet_payload& tx_payload)
{
arp_packet* arp = (arp_packet*)rx_payload.data;
if (arp->hw_type != __htons(ETHERNET)) return false;
if (arp->protocol_type != __htons(IPV4)) return false;
if (arp->hw_size != 6) return false;
if (arp->protocol_size != 4) return false;
if (arp->operation_code == __htons(ARP_REQUEST))
{
IP requested_ip(arp->IP_target);
......@@ -125,6 +126,7 @@ bool ARP_protocol::decode(const ethernet_payload& rx_payload, ethernet_payload&
else
{
//TODO:
return false;
}
return false;
......
......@@ -209,11 +209,20 @@ void Debug::icmp_packet(const ICMP_packet* packet)
case ECHO_REQUEST: uart.send("Echo request");
break;
default: uart.send("Unkown");
default: uart.send("Unknown");
}
uart.send_new_line();
}
void Debug::sntp(const NTP_packet* packet)
{
uart.send("[SNTP] Get timestamp: ");
uart.send_dec(packet->transmit_timestamp.seconds);
uart.send('.');
uart.send_dec(packet->transmit_timestamp.seconds_fraction);
uart.send_new_line();
}
void Debug::tx_status(const ENC28J60_namespace::tx_status_vector& status, bool simple/*= true*/)
{
debug.info("TX status vector: ");
......
......@@ -6,6 +6,7 @@
#include "IP_protocol.h"
#include "ICMP_protocol.h"
#include "UDP_protocol.h"
#include "SNTP_client.h"
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
......@@ -50,6 +51,7 @@ class Debug
void frame_type(const ethernet_frame* frame);
void ip_packet(const IP_packet* packet);
void icmp_packet(const ICMP_packet* packet);
void sntp(const NTP_packet* packet);
void tx_status(const ENC28J60_namespace::tx_status_vector& status, bool simple=true);
void rx_status(const ENC28J60_namespace::rx_status_vector& status, bool simple=true);
void adc();
......
......@@ -92,6 +92,7 @@ namespace ENC28J60_namespace
bit_field_clear_in_PHY_register(PHCON1, PDPXMD_bm); //Force half-duplex
//write_PHY_register(PHLCON, (1<<13) | (1<<12) | LACFG2_bm | LBCFG2_bm | LBCFG1_bm | LBCFG0_bm | STRCH_bm); //LEDA (green) link status, LEDB (orange) rx & tx activity
write_PHY_register(PHLCON, (1<<13) | (1<<12) | LACFG2_bm | LACFG1_bm | LACFG0_bm | LBCFG2_bm | LBCFG1_bm | LBCFG0_bm | STRCH_bm); //Both LEDs indicates rx/tx activity
//write_PHY_register(PHLCON, (1<<13) | (1<<12) | LACFG3_bm | LACFG1_bm | LACFG0_bm | LBCFG3_bm | LBCFG1_bm | LBCFG0_bm); //Both LEDs slowly blinking
write_PHY_register(PHIE, PLNKIE_bm | PGEIE_bm); //Enable interrupt from PHY
//Enable interrupts - global enable, RX packet, link change, TX packet
......@@ -506,8 +507,8 @@ namespace ENC28J60_namespace
//Decrement frames count
bit_field_set_in_register(ECON2, PKTDEC_bm);
debug.error("Received frame - mishmash CRC (packet was dropped)");
debug.rx_status(status);
//debug.error("Received frame - mishmash CRC (packet was dropped)");
//debug.rx_status(status);
return false;
}
......@@ -518,8 +519,8 @@ namespace ENC28J60_namespace
//Decrement frame count
bit_field_set_in_register(ECON2, PKTDEC_bm);
debug.error("Received frame - length field doesn't correspond with rx bytes");
debug.rx_status(status);
//debug.error("Received frame - length field doesn't correspond with rx bytes");
//debug.rx_status(status);
return false;
}
......@@ -530,7 +531,7 @@ namespace ENC28J60_namespace
//Decrement frames count
bit_field_set_in_register(ECON2, PKTDEC_bm);
debug.error("Received frame isn't OK");
debug.error("Received frame isn't OK");
debug.rx_status(status);
return false;
......
......@@ -27,7 +27,7 @@ enum ICMPv4_informational_messages
TRACEROUTE = 30
};
#pragma pack(push, 1)
struct ICMP_packet
{
uint8_t type;
......@@ -42,6 +42,7 @@ struct ICMP_echo_packet
uint16_t sequence_number;
//Optional data (not specified)
};
#pragma pack(pop)
class ICMP_protocol
{
......
......@@ -8,11 +8,11 @@
#include "NetworkTypes.h"
#include "ICMP_protocol.h"
#include "UDP_protocol.h"
#include "SNTP_client.h"
#include "USART.h"
#include "Debug.h"
IP_protocol::IP_protocol(const IP& local_ip): icmp(),
udp(),
local_ip(local_ip)
{
}
......@@ -20,10 +20,9 @@ IP_protocol::IP_protocol(const IP& local_ip): icmp(),
bool IP_protocol::decode(const ethernet_payload& rx_payload, ethernet_payload& tx_payload)
{
IP_packet* rx_packet = (IP_packet*) rx_payload.data;
//debug.ip_packet(rx_packet);
IP_packet* tx_packet = (IP_packet*) tx_payload.data;
//debug.ip_packet(rx_packet);
//Trash not IPv4 packets
if (IP(rx_packet->version) != 4) return false;
......@@ -68,6 +67,28 @@ bool IP_protocol::decode(const ethernet_payload& rx_payload, ethernet_payload& t
return false;
}
void IP_protocol::assembly(ethernet_payload& payload, IP dst_ip, uint16_t& length, uint8_t protocol)
{
IP_packet* packet = (IP_packet*) payload.data;
packet->ihl = 5;
packet->version = 4;
packet->tos = 0;
packet->tl = __htons((4*packet->ihl) + length);
packet->identification = packet->identification;
packet->flags_fragment_offset = packet->flags_fragment_offset;
packet->ttl = 64;
packet->protocol = protocol;
packet->checksum = 0;
packet->src_address = local_ip.ip.value;
packet->dst_address = dst_ip.ip.value;
packet->checksum = checksum((uint8_t*)packet, __ntohs(packet->tl));
payload.length = __ntohs(packet->tl);
}
uint16_t IP_protocol::get_data_length(uint8_t ihl, uint16_t tl)
{
return __ntohs(tl) - (4*ihl);
......
......@@ -68,6 +68,7 @@ class IP_protocol
IP_protocol(const IP& local_ip);
bool decode(const ethernet_payload& rx_payload, ethernet_payload& tx_payload);
void assembly(ethernet_payload& payload, IP dst_ip, uint16_t& length, uint8_t protocol);
uint16_t get_data_length(uint8_t ihl, uint16_t tl);
uint16_t checksum(const uint8_t* vdata, uint16_t length);
......
......@@ -9,6 +9,8 @@
#include "NetworkTypes.h"
#include "ARP.h"
#include "IP_protocol.h"
#include "UDP_protocol.h"
#include "SNTP_client.h"
#include "ENC28J60.h"
#include "Debug.h"
#include "NixieClock.h"
......@@ -22,8 +24,14 @@ NixieStack::NixieStack(ENC28J60& eth): eth(eth),
broadcast_mac({0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
ip(0),
gateway(0),
mask({255, 255, 255, 0}),
link_is_up(false),
pending_sntp_request(false),
new_arp_in_cache(false),
pending_ip(0),
pending_sntp_server_ip(0),
arp(mac, ip),
sntp(),
ipv4(ip),
rx_buffer(),
tx_buffer()
......@@ -50,6 +58,11 @@ void NixieStack::set_gateway(const uint8_t (&ip)[4])
this->gateway.set(ip);
}
void NixieStack::set_mask(const uint8_t (&mask)[4])
{
this->mask.set(mask);
}
void NixieStack::check_link()
{
if (eth.flag_link_changed)
......@@ -75,7 +88,7 @@ void NixieStack::rx_handler()
//There is pending received packet
if (eth.flag_pending_packet && rx_buffer.free_space())
{
//If was RX successuful
//If was RX successful
if (eth.rx_frame(rx_buffer.write()))
{
debug.frame_type(rx_buffer.write());
......@@ -128,9 +141,10 @@ void NixieStack::packet_handler()
if (rx_buffer.check())
{
ethernet_frame* frame = rx_buffer.read();
//debug.frame(frame);
ethernet_frame* tx_frame = tx_buffer.write();
//debug.frame(frame);
switch (__htons(frame->type_length))
{
case IPV4:
......@@ -160,6 +174,11 @@ void NixieStack::packet_handler()
tx_buffer.write_advance();
}
else
{
new_arp_in_cache = true;
}
}
break;
......@@ -171,6 +190,108 @@ void NixieStack::packet_handler()
}
}
void NixieStack::send_arp_request(const IP& requested_ip)
{
ethernet_frame* frame = tx_buffer.write();
memcpy(frame->dest_address, broadcast_mac, 6);
memcpy(frame->src_address, mac, 6);
frame->type_length = __htons(ARP);
arp.assembly_request(requested_ip, frame->payload);
tx_buffer.write_advance();
}
void NixieStack::send_sntp_request(const IP ntp_server_ip)
{
MAC dst_mac;
IP ip_to_search;
//Is requested IP on local network?
if ((ntp_server_ip.ip.value & mask.ip.value) != (gateway.ip.value & mask.ip.value))
{
ip_to_search = gateway;
debug.message("Looking for gateway MAC");
}
else ip_to_search = ntp_server_ip;
//IP is in ARP cache
if (arp.search(ip_to_search, dst_mac))
{
//TODO: Method for sending UDP packets
ethernet_frame* frame = (ethernet_frame*) tx_buffer.write();
memcpy(frame->dest_address, dst_mac, 6);
memcpy(frame->src_address, mac, 6);
frame->type_length = __htons(IPV4);
UDP_packet* udp_packet = (UDP_packet*) frame->payload.data;
sntp.assembly_request(udp_packet->data, frame->payload.length);
frame->payload.length += UDP_HEADER_SIZE;
udp_packet->length = __htons(frame->payload.length);
udp_packet->dst_port = __htons(NTP_PORT);
udp_packet->src_port = __htons(NTP_PORT);
//TODO: UDP checksum
tx_buffer.write_advance();
}
//Ask for MAC otherwise
else
{
debug.message("Sending ARP request");
send_arp_request(ip_to_search);
pending_ip = ip_to_search;
pending_sntp_server_ip = ntp_server_ip;
pending_sntp_request = true;
}
}
void NixieStack::sntp_arp_handler()
{
if (pending_sntp_request && new_arp_in_cache)
{
MAC dst_mac;
if (arp.search(pending_ip, dst_mac))
{
ethernet_frame* frame = (ethernet_frame*) tx_buffer.write();
IP_packet* ip_packet = (IP_packet*) frame->payload.data;
UDP_packet* udp_packet = (UDP_packet*) ip_packet->data;
uint16_t length = 0;
memcpy(frame->dest_address, dst_mac, 6);
memcpy(frame->src_address, mac, 6);
frame->type_length = __htons(IPV4);
sntp.assembly_request(udp_packet->data, length);
length += UDP_HEADER_SIZE;
//TODO: udp.assembly()
udp_packet->length = __htons(length);
udp_packet->dst_port = __htons(NTP_PORT);
udp_packet->src_port = __htons(NTP_PORT);
//TODO: UDP checksum
ipv4.assembly(frame->payload, pending_sntp_server_ip, length, UDP);
tx_buffer.write_advance();
pending_sntp_request = false;
}
new_arp_in_cache = false;
}
}
void NixieStack::test_tx()
{
ethernet_frame* frame = tx_buffer.write();
......
......@@ -23,10 +23,16 @@ class NixieStack
MAC broadcast_mac;
IP ip;
IP gateway;
IP mask;
bool link_is_up;
bool pending_sntp_request;
bool new_arp_in_cache;
IP pending_ip;
IP pending_sntp_server_ip;
ARP_protocol arp;
SNTP_client sntp;
IP_protocol ipv4;
public:
......@@ -41,6 +47,7 @@ class NixieStack
void set_MAC(const uint8_t (&mac)[6]);
void set_IP(const uint8_t (&ip)[4]);
void set_gateway(const uint8_t (&ip)[4]);
void set_mask(const uint8_t (&mask)[4]);
void check_link();
......@@ -49,6 +56,11 @@ class NixieStack
void packet_handler();
void send_arp_request(const IP& requested_ip);
void send_sntp_request(const IP ntp_server_ip);
void sntp_arp_handler();
//For testing
void test_tx();
......
#include "SNTP_client.h"
#include <cstdint>
#include <cstring>
#include "Time.h"
#include "Debug.h"
SNTP_client::SNTP_client()
{
}
void SNTP_client::decode(uint8_t* data)
{
NTP_packet* packet = (NTP_packet*) data;
debug.sntp(packet);
seconds = packet->transmit_timestamp.seconds;
//TODO: Set milliseconds to match timestamp fraction part
}
void SNTP_client::assembly_request(uint8_t* data, uint16_t& length)
{
NTP_packet* packet = (NTP_packet*) data;
length = sizeof(NTP_packet);
memset(data, 0, length);
packet->version_number = VERSION_4;
packet->mode = CLIENT;
//TODO: Set transmit timestamp for more accuracy (to determine propagation delay)
}
#pragma once
#include <cstdint>
enum
{
NTP_PORT = 123
};
enum leap_indicators
{
NO_WARNING = 0,
LAST_MINUTE_HAS_61_SECONDS = 1,
LAST_MINUTE_HAS_59_SECONDS = 2,
ALARM_CONDITION = 3
};
enum versions
{
VERSION_3 = 3,
VERSION_4 = 4
};
enum modes
{
RESERVED = 0,
SYMMETRIC_ACTIVE = 1,
SYMMETRIC_PASSIVE = 2,
CLIENT = 3,
SERVER = 4,
BROADCAST = 5,
};
#pragma pack(push, 1)
struct NTP_timestamp
{
uint32_t seconds;
uint32_t seconds_fraction;
};
struct NTP_packet
{
uint8_t mode :3;
uint8_t version_number :3;
uint8_t leap_indicator :2;
uint8_t stratum;
uint8_t poll_interval;
uint8_t precision;
uint32_t root_delay;
uint32_t root_dispersion;
uint32_t reference_identifier;
NTP_timestamp reference_timestamp;
NTP_timestamp original_timestamp;
NTP_timestamp receive_timestamp;
NTP_timestamp transmit_timestamp;
//Optional authenticator
};
#pragma pack(pop)
class SNTP_client
{
public:
SNTP_client();
void decode(uint8_t* data);
void assembly_request(uint8_t* data, uint16_t& length);
};
......@@ -43,7 +43,7 @@ void System::init_clock()
//Set coarse step, fine step, multiplier
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) ;;
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(5) |
SYSCTRL_DFLLMUL_FSTEP(10) |
SYSCTRL_DFLLMUL_FSTEP(2) |
SYSCTRL_DFLLMUL_MUL(48000000/32768);
//Start closed-loop
......
#include "UDP_protocol.h"
#include "SNTP_client.h"
#include "USART.h"
#include "Debug.h"
UDP_protocol::UDP_protocol()
UDP_protocol::UDP_protocol(): sntp()
{
}
void UDP_protocol::decode(const uint8_t* data, const uint16_t length)
void UDP_protocol::decode(const uint8_t* udp_data, const uint16_t length)
{
for (uint16_t i=0; i<length; i++)
UDP_packet* packet = (UDP_packet*) udp_data;
switch (packet->src_port)
{
uart.send_hex8(data[i]);
uart.send(' ');
case NTP_PORT: sntp.decode(packet->data);
break;
default:
break;
}
uart.send_new_line();
}
void UDP_protocol::assembly(uint8_t* data, uint16_t length)
{
UDP_packet* packet = (UDP_packet*) data;
}
......@@ -2,6 +2,15 @@
#include <cstdint>
#include "SNTP_client.h"
enum
{
UDP_HEADER_SIZE = 8
};
#pragma pack(push, 1)
struct UDP_packet
{
uint16_t src_port;
......@@ -10,12 +19,16 @@ struct UDP_packet
uint16_t checksum;
uint8_t data[];
};
#pragma pack(pop)
class UDP_protocol
{
private:
SNTP_client sntp;
public:
UDP_protocol();
void decode(const uint8_t* data, const uint16_t length);
void decode(const uint8_t* udp_data, const uint16_t length);
void assembly(uint8_t* data, uint16_t length);
};
......@@ -95,6 +95,7 @@ class USART
{
DRE_enabled = true;
usart.INTENSET.reg = SERCOM_USART_INTENSET_DRE;
send_blocking(c);
}
......
......@@ -101,15 +101,21 @@ int main(void)
stack.set_MAC(eeprom_mac);
//Set-up IPv4 address
stack.set_IP({192, 168, 1, 2});
//stack.set_IP({10, 20, 70, 145});
//stack.set_IP({192, 168, 1, 2});
stack.set_IP({10, 20, 70, 145});
//Set-up gateway address
stack.set_gateway({192, 168, 1, 1});
//stack.set_gateway({192, 168, 1, 1});
stack.set_gateway({10, 20, 70, 1});
//Set-up network mask
stack.set_mask({255, 255, 255, 0});
//Init network stack and ENC28J60
stack.init();
//Send SNTP request on clock1.zcu.cz
stack.send_sntp_request(IP({147, 228, 57, 10 }));
time_t old = 0;
......@@ -123,6 +129,7 @@ int main(void)
stack.rx_handler();
stack.tx_handler();
stack.packet_handler();
stack.sntp_arp_handler();
if (adc.done)
{
......
......@@ -121,75 +121,75 @@
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<ArmGccCpp>
<armgcc.common.outputfiles.hex>True</armgcc.common.outputfiles.hex>
<armgcc.common.outputfiles.lss>True</armgcc.common.outputfiles.lss>
<armgcc.common.outputfiles.eep>True</armgcc.common.outputfiles.eep>
<armgcc.common.outputfiles.bin>True</armgcc.common.outputfiles.bin>
<armgcc.common.outputfiles.srec>True</armgcc.common.outputfiles.srec>
<armgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</armgcc.compiler.symbols.DefSymbols>
<armgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\SAMD20_DFP\1.1.84\samd20\include</Value>
<Value>%24(PackRepoDir)\arm\CMSIS\4.2.0\CMSIS\Include\</Value>
</ListValues>
</armgcc.compiler.directories.IncludePaths>
<armgcc.compiler.optimization.level>Optimize (-O1)</armgcc.compiler.optimization.level>
<armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>
<armgcc.compiler.optimization.PrepareDataForGarbageCollection>True</armgcc.compiler.optimization.PrepareDataForGarbageCollection>
<armgcc.compiler.optimization.DebugLevel>Maximum (-g3)</armgcc.compiler.optimization.DebugLevel>
<armgcc.compiler.warnings.AllWarnings>True</armgcc.compiler.warnings.AllWarnings>
<armgcc.compiler.warnings.ExtraWarnings>True</armgcc.compiler.warnings.ExtraWarnings>
<armgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</armgcccpp.compiler.symbols.DefSymbols>
<armgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\SAMD20_DFP\1.1.84\samd20\include</Value>
<Value>%24(PackRepoDir)\arm\CMSIS\4.2.0\CMSIS\Include\</Value>
</ListValues>
</armgcccpp.compiler.directories.IncludePaths>
<armgcccpp.compiler.optimization.level>Optimize (-O1)</armgcccpp.compiler.optimization.level>
<armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection>
<armgcccpp.compiler.optimization.PrepareDataForGarbageCollection>True</armgcccpp.compiler.optimization.PrepareDataForGarbageCollection>
<armgcccpp.compiler.optimization.DebugLevel>Maximum (-g3)</armgcccpp.compiler.optimization.DebugLevel>
<armgcccpp.compiler.warnings.AllWarnings>True</armgcccpp.compiler.warnings.AllWarnings>
<armgcccpp.compiler.warnings.ExtraWarnings>True</armgcccpp.compiler.warnings.ExtraWarnings>
<armgcccpp.compiler.miscellaneous.OtherFlags>-std=gnu++14</armgcccpp.compiler.miscellaneous.OtherFlags>
<armgcccpp.linker.general.AdditionalSpecs>Use syscall stubs (--specs=nosys.specs)</armgcccpp.linker.general.AdditionalSpecs>
<armgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</armgcccpp.linker.libraries.Libraries>
<armgcccpp.linker.libraries.LibrarySearchPaths>
<ListValues>
<Value>%24(ProjectDir)\Device_Startup</Value>
</ListValues>
</armgcccpp.linker.libraries.LibrarySearchPaths>
<armgcccpp.linker.optimization.GarbageCollectUnusedSections>True</armgcccpp.linker.optimization.GarbageCollectUnusedSections>
<armgcccpp.linker.memorysettings.ExternalRAM />
<armgcccpp.linker.miscellaneous.LinkerFlags>-Tsamd20g18_flash.ld</armgcccpp.linker.miscellaneous.LinkerFlags>
<armgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\SAMD20_DFP\1.1.84\samd20\include</Value>
<Value>%24(PackRepoDir)\arm\CMSIS\4.2.0\CMSIS\Include\</Value>
</ListValues>
</armgcccpp.assembler.general.IncludePaths>
<armgcccpp.assembler.debugging.DebugLevel>Default (-g)</armgcccpp.assembler.debugging.DebugLevel>
<armgcccpp.preprocessingassembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\SAMD20_DFP\1.1.84\samd20\include</Value>
<Value>%24(PackRepoDir)\arm\CMSIS\4.2.0\CMSIS\Include\</Value>
</ListValues>
</armgcccpp.preprocessingassembler.general.IncludePaths>
<armgcccpp.preprocessingassembler.debugging.DebugLevel>Default (-Wa,-g)</armgcccpp.preprocessingassembler.debugging.DebugLevel>
</ArmGccCpp>
<armgcc.common.outputfiles.hex>True</armgcc.common.outputfiles.hex>
<armgcc.common.outputfiles.lss>True</armgcc.common.outputfiles.lss>
<armgcc.common.outputfiles.eep>True</armgcc.common.outputfiles.eep>
<armgcc.common.outputfiles.bin>True</armgcc.common.outputfiles.bin>
<armgcc.common.outputfiles.srec>True</armgcc.common.outputfiles.srec>
<armgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</armgcc.compiler.symbols.DefSymbols>
<armgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\SAMD20_DFP\1.1.84\samd20\include</Value>
<Value>%24(PackRepoDir)\arm\CMSIS\4.2.0\CMSIS\Include\</Value>
</ListValues>
</armgcc.compiler.directories.IncludePaths>
<armgcc.compiler.optimization.level>Optimize for size (-Os)</armgcc.compiler.optimization.level>
<armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>
<armgcc.compiler.optimization.PrepareDataForGarbageCollection>True</armgcc.compiler.optimization.PrepareDataForGarbageCollection>
<armgcc.compiler.optimization.DebugLevel>Maximum (-g3)</armgcc.compiler.optimization.DebugLevel>
<armgcc.compiler.warnings.AllWarnings>True</armgcc.compiler.warnings.AllWarnings>
<armgcc.compiler.warnings.ExtraWarnings>True</armgcc.compiler.warnings.ExtraWarnings>
<armgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</armgcccpp.compiler.symbols.DefSymbols>
<armgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\SAMD20_DFP\1.1.84\samd20\include</Value>
<Value>%24(PackRepoDir)\arm\CMSIS\4.2.0\CMSIS\Include\</Value>
</ListValues>
</armgcccpp.compiler.directories.IncludePaths>
<armgcccpp.compiler.optimization.level>Optimize for size (-Os)</armgcccpp.compiler.optimization.level>
<armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection>
<armgcccpp.compiler.optimization.PrepareDataForGarbageCollection>True</armgcccpp.compiler.optimization.PrepareDataForGarbageCollection>
<armgcccpp.compiler.optimization.DebugLevel>Maximum (-g3)</armgcccpp.compiler.optimization.DebugLevel>
<armgcccpp.compiler.warnings.AllWarnings>True</armgcccpp.compiler.warnings.AllWarnings>
<armgcccpp.compiler.warnings.ExtraWarnings>True</armgcccpp.compiler.warnings.ExtraWarnings>