diff --git a/CSCE838-Lab4-Node/CSCE838-Lab4-Node.ino b/CSCE838-Lab4-Node/CSCE838-Lab4-Node.ino
new file mode 100644
index 0000000000000000000000000000000000000000..7735c85dd6778b689486cb8c3e39e26938738f1f
--- /dev/null
+++ b/CSCE838-Lab4-Node/CSCE838-Lab4-Node.ino
@@ -0,0 +1,170 @@
+/*******************************************************************************
+  Copyright (c) 2015 Matthijs Kooijman
+  Copyright (c) 2018 Terry Moore, MCCI Corporation
+
+  Permission is hereby granted, free of charge, to anyone
+  obtaining a copy of this document and accompanying files,
+  to do whatever they want with them without any restriction,
+  including, but not limited to, copying, modification and redistribution.
+  NO WARRANTY OF ANY KIND IS PROVIDED.
+
+  This example transmits data on hardcoded channel and receives data
+  when not transmitting. Running this sketch on two nodes should allow
+  them to communicate.
+*******************************************************************************/
+#include <lmic.h>
+#include <hal/hal.h>
+#include <SPI.h>
+
+// we formerly would check this configuration; but now there is a flag,
+// in the LMIC, LMIC.noRXIQinversion;
+// if we set that during init, we get the same effect. If
+// DISABLE_INVERT_IQ_ON_RX is defined, it means that LMIC.noRXIQinversion is
+// treated as always set.
+//
+// #if !defined(DISABLE_INVERT_IQ_ON_RX)
+// #error This example requires DISABLE_INVERT_IQ_ON_RX to be set. Update \
+// lmic_project_config.h in arduino-lmic/project_config to set it.
+// #endif
+// How often to send a packet. Note that this sketch bypasses the normal
+// LMIC duty cycle limiting, so when you change anything in this sketch
+// (payload length, frequency, spreading factor), be sure to check if
+// this interval should not also be increased.
+// See this spreadsheet for an easy airtime and duty cycle calculator:
+// https://docs.google.com/spreadsheets/d/1voGAtQAjC1qBmaVuP1ApNKs1ekgUjavHuVQIXyYSvNc
+#define TX_INTERVAL 60000 //Delay between each message in millisecond.
+
+// Pin mapping for SAMD21
+const lmic_pinmap lmic_pins = {
+  .nss = 12,//RFM Chip Select
+  .rxtx = LMIC_UNUSED_PIN,
+  .rst = 7,//RFM Reset
+  .dio = {6, 10, 11}, //RFM Interrupt, RFM LoRa pin, RFM LoRa pin
+};
+
+// These callbacks are only used in over-the-air activation, so they are
+// left empty here (we cannot leave them out completely unless
+// DISABLE_JOIN is set in arduino-lmoc/project_config/lmic_project_config.h,
+// otherwise the linker will complain).
+void os_getArtEui (u1_t* buf) { }
+void os_getDevEui (u1_t* buf) { }
+void os_getDevKey (u1_t* buf) { }
+
+void onEvent (ev_t ev)
+{
+  
+}
+
+osjob_t txjob;
+osjob_t timeoutjob;
+static void tx_func (osjob_t* job);
+
+// Transmit the given string and call the given function afterwards
+void tx(const char *str, osjobcb_t func)
+{
+  os_radio(RADIO_RST); // Stop RX first
+  delay(1); // Wait a bit, without this os_radio below asserts, apparently because the state hasn't changed yet
+  LMIC.dataLen = 0;
+  while (*str)
+  LMIC.frame[LMIC.dataLen++] = *str++;
+  LMIC.osjob.func = func;
+  os_radio(RADIO_TX);
+  SerialUSB.println("TX");
+}
+
+// Enable rx mode and call func when a packet is received
+void rx(osjobcb_t func)
+{
+  LMIC.osjob.func = func;
+  LMIC.rxtime = os_getTime(); // RX _now_
+  // Enable "continuous" RX (e.g. without a timeout, still stops after
+  // receiving a packet)
+  os_radio(RADIO_RXON);
+  SerialUSB.println("RX");
+}
+
+static void rxtimeout_func(osjob_t *job)
+{
+  digitalWrite(LED_BUILTIN, LOW); // off
+}
+
+static void rx_func (osjob_t* job)
+{
+  // Blink once to confirm reception and then keep the led on
+  digitalWrite(LED_BUILTIN, LOW); // off
+  delay(10);
+  digitalWrite(LED_BUILTIN, HIGH); // on
+  // Timeout RX (i.e. update led status) after 3 periods without RX
+  os_setTimedCallback(&timeoutjob, os_getTime() + ms2osticks(3*TX_INTERVAL), rxtimeout_func);
+  // Reschedule TX so that it should not collide with the other side's
+  // next TX
+  os_setTimedCallback(&txjob, os_getTime() + ms2osticks(TX_INTERVAL / 2), tx_func);
+  SerialUSB.print("Got ");
+  SerialUSB.print(LMIC.dataLen);
+  SerialUSB.println(" bytes");
+  SerialUSB.write(LMIC.frame, LMIC.dataLen);
+  SerialUSB.println();
+  // Restart RX
+  rx(rx_func);
+}
+
+static void txdone_func (osjob_t* job)
+{
+  //rx(rx_func);
+}
+
+// log text to USART and toggle LED
+static void tx_func (osjob_t* job)
+{
+  // say hello
+  tx("Hello, world!", txdone_func);
+  // reschedule job every TX_INTERVAL (plus a bit of random to prevent systematic collisions), unless packets are received, then rx_func will reschedule at half this time.
+  os_setTimedCallback(job, os_getTime() + ms2osticks(TX_INTERVAL + random(500)), tx_func);
+}
+
+// application entry point
+void setup()
+{
+  SerialUSB.begin(115200);
+  while (!SerialUSB); // wait for Serial Monitor to be attached to SparkFun Pro RF board
+  SerialUSB.println("Starting");
+  
+  pinMode(LED_BUILTIN, OUTPUT);
+  // initialize runtime env
+  os_init();
+  
+  // this is automatically set to the proper bandwidth in kHz, based on the selected channel
+  uint32_t uBandwidth;
+  LMIC.freq = 915000000; // originally was 903900000 in the example
+  uBandwidth = 125;
+  LMIC.datarate = US915_DR_SF10; // DR4, originally was US915_DR_SF7 in the example
+  LMIC.txpow = 20;  // originally was 21 in the example
+  
+  // disable RX IQ inversion
+  LMIC.noRXIQinversion = true;
+  
+  // This sets CR 4/5, BW125 (except for EU/AS923 DR_SF7B, which uses BW250)
+  LMIC.rps = updr2rps(LMIC.datarate);
+  SerialUSB.print("Frequency: "); SerialUSB.print(LMIC.freq / 1000000);
+  SerialUSB.print("."); SerialUSB.print((LMIC.freq / 100000) % 10);
+  SerialUSB.print("MHz");
+  SerialUSB.print(" LMIC.datarate: "); SerialUSB.print(LMIC.datarate);
+  SerialUSB.print(" LMIC.txpow: "); SerialUSB.println(LMIC.txpow);
+  
+  // This sets CR 4/5, BW125 (except for DR_SF7B, which uses BW250)
+  LMIC.rps = updr2rps(LMIC.datarate);
+  
+  // disable RX IQ inversion
+  LMIC.noRXIQinversion = true;
+  SerialUSB.println("Started");
+  SerialUSB.flush();
+  
+  // setup initial job
+  os_setCallback(&txjob, tx_func);
+}
+
+void loop()
+{
+  // execute scheduled jobs and events
+  os_runloop_once();
+}