From fbc275239b58bbb2d3110d91c8eea20d5069d14f Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Fri, 21 Dec 2018 15:28:37 +0000
Subject: [PATCH] Move stuff around to make this repository more organised.

---
 .gitignore => Gateway-Python/.gitignore       |    0
 decode_msg.py => Gateway-Python/decode_msg.py |    0
 .../lora_single_chan_gateway}/__init__.py     |    0
 .../lora_single_chan_gateway}/board_config.py |    0
 .../lora_single_chan_gateway}/gateway.py      |    0
 .../lora_single_chan_gateway}/package.py      |    0
 plot_db.py => Gateway-Python/plot_db.py       |    0
 print_db.py => Gateway-Python/print_db.py     |    0
 send_msg.py => Gateway-Python/send_msg.py     |    0
 README.md                                     |   12 +-
 Raw-RFM95-Python/rfmtest.py                   |  159 ++
 Raw-RFM95/Raw-RFM95.ino                       | 1313 +++++++++++++++++
 12 files changed, 1483 insertions(+), 1 deletion(-)
 rename .gitignore => Gateway-Python/.gitignore (100%)
 rename decode_msg.py => Gateway-Python/decode_msg.py (100%)
 rename {lora_single_chan_gateway => Gateway-Python/lora_single_chan_gateway}/__init__.py (100%)
 rename {lora_single_chan_gateway => Gateway-Python/lora_single_chan_gateway}/board_config.py (100%)
 rename {lora_single_chan_gateway => Gateway-Python/lora_single_chan_gateway}/gateway.py (100%)
 rename {lora_single_chan_gateway => Gateway-Python/lora_single_chan_gateway}/package.py (100%)
 rename plot_db.py => Gateway-Python/plot_db.py (100%)
 rename print_db.py => Gateway-Python/print_db.py (100%)
 rename send_msg.py => Gateway-Python/send_msg.py (100%)
 create mode 100644 Raw-RFM95-Python/rfmtest.py
 create mode 100644 Raw-RFM95/Raw-RFM95.ino

diff --git a/.gitignore b/Gateway-Python/.gitignore
similarity index 100%
rename from .gitignore
rename to Gateway-Python/.gitignore
diff --git a/decode_msg.py b/Gateway-Python/decode_msg.py
similarity index 100%
rename from decode_msg.py
rename to Gateway-Python/decode_msg.py
diff --git a/lora_single_chan_gateway/__init__.py b/Gateway-Python/lora_single_chan_gateway/__init__.py
similarity index 100%
rename from lora_single_chan_gateway/__init__.py
rename to Gateway-Python/lora_single_chan_gateway/__init__.py
diff --git a/lora_single_chan_gateway/board_config.py b/Gateway-Python/lora_single_chan_gateway/board_config.py
similarity index 100%
rename from lora_single_chan_gateway/board_config.py
rename to Gateway-Python/lora_single_chan_gateway/board_config.py
diff --git a/lora_single_chan_gateway/gateway.py b/Gateway-Python/lora_single_chan_gateway/gateway.py
similarity index 100%
rename from lora_single_chan_gateway/gateway.py
rename to Gateway-Python/lora_single_chan_gateway/gateway.py
diff --git a/lora_single_chan_gateway/package.py b/Gateway-Python/lora_single_chan_gateway/package.py
similarity index 100%
rename from lora_single_chan_gateway/package.py
rename to Gateway-Python/lora_single_chan_gateway/package.py
diff --git a/plot_db.py b/Gateway-Python/plot_db.py
similarity index 100%
rename from plot_db.py
rename to Gateway-Python/plot_db.py
diff --git a/print_db.py b/Gateway-Python/print_db.py
similarity index 100%
rename from print_db.py
rename to Gateway-Python/print_db.py
diff --git a/send_msg.py b/Gateway-Python/send_msg.py
similarity index 100%
rename from send_msg.py
rename to Gateway-Python/send_msg.py
diff --git a/README.md b/README.md
index ac6430c..7a48eb4 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,13 @@
-# lora_single_chan_gateway
+# LoRa Single Channel Gateway
+
+This repository contains my experiments into a bidirectional single-channel LoRa gateway.
+
+Key folders:
+
+ - `Gateway-Python` - Some code I found that interacts with an RFM95 in Python.
+ - `Raw-RFM95` - Arduino code that interacts with an RFM95's registers directly via SPI.
+ - `Raw-RFM95-Python` - Same as above, but in Python fort he Raspberry Pi. Tests the registeres to ensure they work correctly.
+
+
 
 Based on: https://github.com/tftelkamp/single_chan_pkt_fwd
diff --git a/Raw-RFM95-Python/rfmtest.py b/Raw-RFM95-Python/rfmtest.py
new file mode 100644
index 0000000..66720f5
--- /dev/null
+++ b/Raw-RFM95-Python/rfmtest.py
@@ -0,0 +1,159 @@
+# rfmtest.py - performs SPI comms on raspberry pi to RFM95 IC.	Paul Richarsd pi@sosgez.co.uk
+#
+# NB this is python2 code. SPI data transfer does not use external driver.
+#
+import RPi.GPIO as GPIO
+from time import sleep
+#define GPIO board pin assignments for comms
+
+def swait():	# just a short delay.
+	sleep(0.001)
+	
+def initports():
+	global gclk,gout,gin,ginit,gen
+	ginit=15 # was 3 # chip reset
+	gclk=23	#	CLOCK
+	gout=19	# MOSI
+	gin=21	# MISO
+	gen=24	# chip enable (active low)
+	GPIO.setmode(GPIO.BOARD)
+	GPIO.setup(ginit,GPIO.OUT)
+	GPIO.setup(gclk,GPIO.OUT)
+	GPIO.setup(gout,GPIO.OUT)
+	GPIO.setup(gen,GPIO.OUT)
+	GPIO.setup(gin,GPIO.IN,pull_up_down = GPIO.PUD_UP)
+	swait()
+	# set default state
+	GPIO.output(ginit,0)
+	GPIO.output(gclk,0)
+	GPIO.output(gout,0)
+	GPIO.output(gen,1)
+	GPIO.output(ginit,1)
+# READY FOR 1 TRANSFER	
+			
+def xfr1(iswrite,address,data1):		# SPI data transfer main routine. Single byte is	transferred out and in
+	global gen,gout,gin,gclk
+	GPIO.output(gen,0)
+	swait()
+	swait()
+	d1 = address & 127
+	if iswrite>0:
+		d1 = d1 | 128
+	swait()
+	m=128 # send MSB first
+	for bit in xrange(8):
+	if((d1 & m) >0):
+		GPIO.output(gout,1)
+	else:
+		GPIO.output(gout,0)
+	swait()
+	GPIO.output(gclk,1)
+	swait()
+	GPIO.output(gclk,0)
+	swait()
+	m = (m >> 1) & 127
+	m = 128
+	d2 = data1
+	res = 0
+	for bit in xrange(8):
+	if((d2 & m)>0):
+		GPIO.output(gout,1)
+	else:
+		GPIO.output(gout,0)
+	swait()
+	res = res << 1
+	GPIO.output(gclk,1)
+	if(GPIO.input(gin)>0):
+		res = res | 1		
+	swait()
+	GPIO.output(gclk,0)
+	swait()
+	m = m >> 1
+	GPIO.output(gen,1)
+	swait()
+	return res
+ 
+
+def writeReg(where,data):
+	xfr1(1,where,data)
+
+def readReg(where):
+	return xfr1(0,where,0)
+
+def ex1():	# just exercising a pin so I can see it on scope
+	global gclk,gout,gin,gen,ginit
+	dt = 0.01
+	port = gen
+	for x in xrange(100):
+		print 1
+		GPIO.output(port,1)
+		sleep(dt)
+		print 0
+		GPIO.output(port,0)
+		sleep(dt)
+
+def readregs():
+	print "Reg Value"
+	for x in xrange(0x44):		
+		res = -1
+		v = xfr1(0,x,0)
+		print '@',format(x,'02X'),
+		print '	','	$',format(v,'02X')			
+			
+			
+def GetOpMode():
+	x = xfr1(0,1,0)	# register 1 controls the RFM IC mode. eg FSK/LORA/SLEEP/STANDBY/TX/RX
+	return x
+				
+def GetRegBitRate():
+	h = xfr1(0,2,0)
+	l = xfr1(0,3,0)
+	return h*256 + l
+
+def GetCarrierFreq():
+	h = readReg(6)	# MSB
+	m = readReg(7)
+	l = readReg(8)	# LSB
+	return ((h*256.0+m)*256.0 + l)*61.035 # in Hz
+
+def SetFreq(mhz):
+	f = int(mhz*1e6/61.035)
+	h = int(f/65536.0)
+	r = f-h*65536
+	m = int(r/256)
+	l = r-256*m
+	writeReg(6,h)	# MSB
+	writeReg(7,m)
+	writeReg(8,l)	# LSB
+	return	
+
+def GetAGC():
+	return xfr1(0,0x61,0) # or use readReg(0x61) etc
+
+def GetAGC1():
+	return xfr1(0,0x62,0)
+	
+def GetAGC2():
+	return xfr1(0,0x63,0)
+	
+def GetAGC3():
+	return xfr1(0,0x64,0)
+				
+def ShowRegs():
+	print' Some regsiter examples'
+	print 'Op Mode ',GetOpMode()
+	print 'Bit Rate ', GetRegBitRate()				
+	print 'Default carrier freq ',GetCarrierFreq()/1e6, ' MHz'
+	print 'AGC regs 61-64 : ',format(GetAGC(),'02X'),format(GetAGC1(),'02X'),format(GetAGC2(),'02X'),format(GetAGC3(),'02X')
+
+def main():
+	print ('Simple GPIO SPI without drivers')
+	sleep(0.5) # secs
+	initports()
+	readregs()	# shows massive list, before any changes are made
+	ShowRegs()	# shows a few interesting registers
+	SetFreq(868.1)	# now write to registers 6,7,8
+	print 'New carrier freq ',GetCarrierFreq()/1e6, ' MHz'
+	print ("*** Finished")
+	GPIO.cleanup()
+main()
diff --git a/Raw-RFM95/Raw-RFM95.ino b/Raw-RFM95/Raw-RFM95.ino
new file mode 100644
index 0000000..3173fd5
--- /dev/null
+++ b/Raw-RFM95/Raw-RFM95.ino
@@ -0,0 +1,1313 @@
+// LORA_ARM_TX made from from AEStest and SPITEST
+//
+#define JOB_TX      1
+#define JOB_MAILBOX 2
+#define JOB_TEMP    3
+#define JOB_TEST1   4
+
+#define JOB JOB_TEST1
+
+// from SPITest par 23jul18 rfm95 comms
+// reset=PA3=8, NSS=PA4=7, MOSI=PA7=4, CLK=PB0=3, MISO=PA6=5, DIO0=PB12=31
+#define RESET 8
+#define NSS 7
+#define MOSI 4
+#define CLK 3
+#define MISO 5
+#define DIO0PIN 31
+
+// RGB led pins acive high
+#define RLED 17
+#define GLED 18
+#define BLED 19
+
+#define ASENSE 12
+#define BSENSE 13
+#define CSENSE 15
+#define NSENSE 14
+
+#define ADRIVE 10
+#define BDRIVE 9
+#define CDRIVE 11
+
+#define MAPLELED  33
+#define DHT22 26
+
+
+// pins used for mode selction options
+
+// opt0 = enable serial comms for debug
+// opt1 = enable fast transmit rate
+
+#define OPTION1 30
+#define OPTION2 29
+#define OPTION3 28
+#define OPTION4 27
+
+#define IRDRIVE 9
+
+// REGISTERS in RFM95
+#define REG_FIFO          0x00
+#define REG_MODE          0x01
+#define REG_FREQ_H        0x06
+#define REG_FREQ_M        0x07
+#define REG_FREQ_L        0x08
+#define REG_PACONFIG      0x09
+#define REG_FIFOADDRPTR   0x0D
+#define REG_FIFOTXBASEADDR  0X0E
+#define REG_FIFORXBASEADDR  0x0F
+#define REG_MODEMCONFIG   0x1D
+#define REG_MODEMCONFIG2  0x1E
+#define REG_SYMBTIMEOUT   0x1F
+#define REG_PREAMBLE_MSB  0x20
+#define REG_PREAMBLE_LSB  0x21
+#define REG_PAYLOADLENGTH 0x22
+#define REG_MODEMCONFIG3  0x26
+#define REG_NODEADR       0x33
+#define REG_SYNC          0x39
+#define REG_IMAGECAL      0x3B
+#define REG_DIOMAPPING1   0x40
+
+// Mode constants
+#define MODE_SLEEP        0x00
+#define MODE_STANDBY      0x01
+#define MODE_LORA_SLEEP   0x80
+#define MODE_LORA_STANDBY 0x81
+#define MODE_LORA_TX      0x83
+
+
+int fb1,fb2,fb3;
+
+// LOCATION WHERE FRAME COUNTER IS STORED in EEPROM
+#define count_addr 0
+unsigned int MyFrameCounter = 0;
+#include <EEPROM.h>
+
+int optSerial=0,optFast=0,optIR=0,optResetCounter=0;
+
+void readFrameCounter()
+{
+  int l = EEPROM.read(count_addr) & 255;
+  int h = EEPROM.read(count_addr+1) & 255;
+  MyFrameCounter = l | h<<8;
+}
+
+void writeFrameCounter()
+{
+  unsigned char l = MyFrameCounter & 255;
+  unsigned char h = (MyFrameCounter >> 8) & 255;
+  EEPROM.write(count_addr,l);
+  EEPROM.write(count_addr+1,h);
+}
+
+void swait()  // tiny delays
+{
+  int y=10; // was 100
+  while(y--);
+}
+
+int xfr(unsigned char iswrite,unsigned char addr,unsigned char data)
+{
+  int d1;
+  digitalWrite(NSS,0);
+  swait();
+  swait();
+  d1 = addr & 127;
+  if(iswrite!=0) d1 |= 128;
+  swait();
+  int m=128;
+  for(int bit=0;bit<8;bit++)
+  {
+    if( d1 & m)  digitalWrite(MOSI,1);
+    else        digitalWrite(MOSI,0);
+    swait();
+    digitalWrite(CLK,1);
+    swait();
+    digitalWrite(CLK,0);
+    swait();
+    m = (m >> 1) & 127;    
+  }
+  m = 128;
+  int d2=data,res=0;
+  for(int bit=0;bit<8;bit++)
+  {
+    if((d2 & m)>0) digitalWrite(MOSI,1);
+    else        digitalWrite(MOSI,0);
+    swait();
+    res = res << 1;
+    digitalWrite(CLK,1);
+    if(digitalRead(MISO)>0) 
+      res |= 1;
+    swait();
+    digitalWrite(CLK,0);
+    m >>= 1;
+  }
+  digitalWrite(NSS,1);
+  swait();
+  return res;
+}
+
+void writer(unsigned char addr, unsigned char data)
+{
+  xfr(1,addr,data);
+}
+
+unsigned char reader(unsigned char addr)
+{
+  return xfr(0,addr,0);
+}
+
+void spiInit() { // using my own SPI code
+  pinMode(RESET,OUTPUT);
+  pinMode(NSS,OUTPUT);
+  pinMode(CLK,OUTPUT);
+  pinMode(MOSI,OUTPUT);
+  pinMode(MISO,INPUT);
+  pinMode(DIO0PIN,INPUT);
+  digitalWrite(CLK,0);
+  digitalWrite(NSS,1);
+  digitalWrite(MOSI,0);
+  digitalWrite(RESET,0);
+  delay(1000);
+  digitalWrite(RESET,1);
+}
+
+void optionInit() // one-time decision about operating mode required, set on links
+{
+  pinMode(OPTION1,INPUT_PULLUP);
+  pinMode(OPTION2,INPUT_PULLUP);
+  pinMode(OPTION3,INPUT_PULLUP);
+  pinMode(OPTION4,INPUT_PULLUP);
+  delay(10);
+  optSerial = digitalRead(OPTION1)==0;
+  optFast = digitalRead(OPTION2)==0;
+  optIR = digitalRead(OPTION3)==0;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+/*
+ * AES TEST EXAMPLE
+ Copied from "CLE's" ATtiny85 + RFM95 Temperature Sensor
+*/
+
+unsigned char NwkSkey[16] = { 0xBB, 0x80, 0x64, 0x68, 0xF1, 0xE2, 0x3D, 0x06, 0xC0, 0xAF, 0x11, 0x9C, 0xAF, 0x4B, 0x07, 0xE5 };
+unsigned char AppSkey[16] = { 0xE9, 0x74, 0x8A, 0xA3, 0xAA, 0x2F, 0x28, 0x4D, 0xD9, 0xFB, 0x2A, 0xEE, 0xDA, 0xD2, 0x9D, 0x7C };
+unsigned char DevAddr[4] = { 0x26, 0x00, 0x13, 0x8D };
+//unsigned int Frame_Counter_Tx = 0x0000;
+
+// after char  PROGMEM
+static const unsigned char PROGMEM S_Table[16][16] = {
+  {0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76},
+  {0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0},
+  {0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15},
+  {0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75},
+  {0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84},
+  {0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF},
+  {0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8},
+  {0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2},
+  {0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73},
+  {0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB},
+  {0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79},
+  {0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08},
+  {0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A},
+  {0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E},
+  {0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF},
+  {0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16}
+};
+
+
+// definitions becvause soiurce i n reverse def order
+void Encrypt_Payload(unsigned char *Data, unsigned char Data_Length, unsigned int Frame_Counter, unsigned char Direction);
+void Calculate_MIC(unsigned char *Data, unsigned char *Final_MIC, unsigned char Data_Length, unsigned int Frame_Counter, unsigned char Direction);
+void RFM_Send_Package(unsigned char *RFM_Tx_Package, unsigned char Package_Length);
+void AES_Encrypt(unsigned char *Data, unsigned char *Key);
+void Generate_Keys(unsigned char *K1, unsigned char *K2);
+void XOR(unsigned char *New_Data,unsigned char *Old_Data);
+void Shift_Left(unsigned char *Data);
+void AES_Add_Round_Key(unsigned char *Round_Key, unsigned char (*State)[4]);
+unsigned char AES_Sub_Byte(unsigned char Byte);
+void AES_Shift_Rows(unsigned char (*State)[4]);
+void AES_Mix_Collums(unsigned char (*State)[4]);
+void AES_Calculate_Round_Key(unsigned char Round, unsigned char *Round_Key);
+
+int DIO0()
+{
+    return digitalRead(DIO0PIN); 
+}
+
+void memcpy(char *dest,char *src,int len)
+{
+    while(len--)
+    {
+        *dest++ = *src++;
+    }
+}
+
+/*
+*****************************************************************************************
+* Description : Function contstructs a LoRaWAN package and sends it
+*
+* Arguments   : *Data pointer to the array of data that will be transmitted
+*               Data_Length nuber of bytes to be transmitted
+*               Frame_Counter_Up  Frame counter of upstream frames
+*****************************************************************************************
+*/
+void LORA_Send_Data(unsigned char *Data, unsigned char Data_Length, unsigned int Frame_Counter_Tx)
+{
+  //Define variables
+  unsigned char i;
+
+  //Direction of frame is up
+  unsigned char Direction = 0x00;
+
+  unsigned char RFM_Data[64];
+  unsigned char RFM_Package_Length;
+
+  unsigned char MIC[4];
+
+  //Unconfirmed data up
+  unsigned char Mac_Header = 0x40;
+
+  unsigned char Frame_Control = 0x00;
+  unsigned char Frame_Port = 0x01;
+
+  //Encrypt the data
+  Encrypt_Payload(Data, Data_Length, Frame_Counter_Tx, Direction);
+  
+  //Build the Radio Package
+  RFM_Data[0] = Mac_Header;
+
+  RFM_Data[1] = DevAddr[3];
+  RFM_Data[2] = DevAddr[2];
+  RFM_Data[3] = DevAddr[1];
+  RFM_Data[4] = DevAddr[0];
+
+  RFM_Data[5] = Frame_Control;
+
+  RFM_Data[6] = (Frame_Counter_Tx & 0x00FF);
+  RFM_Data[7] = ((Frame_Counter_Tx >> 8) & 0x00FF);
+
+  RFM_Data[8] = Frame_Port;
+
+  //Set Current package length
+  RFM_Package_Length = 9;
+
+  //Load Data
+  for(i = 0; i < Data_Length; i++)
+  {
+    RFM_Data[RFM_Package_Length + i] = Data[i];
+  }
+
+  //Add data Lenth to package length
+  RFM_Package_Length = RFM_Package_Length + Data_Length;
+  
+  //Calculate MIC
+  Calculate_MIC(RFM_Data, MIC, RFM_Package_Length, Frame_Counter_Tx, Direction);
+
+  //Load MIC in package
+  for(i = 0; i < 4; i++)
+  {
+    RFM_Data[i + RFM_Package_Length] = MIC[i];
+  }
+
+  //Add MIC length to RFM package length
+  RFM_Package_Length = RFM_Package_Length + 4;
+ 
+  //Send Package
+  RFM_Send_Package(RFM_Data, RFM_Package_Length);
+}
+
+void RFM_Write(char w,char d)
+{
+    writer(w,d); // calls my SPI code
+}
+
+
+void SetMode(unsigned char d)
+{
+  writer(REG_MODE,d);
+}
+
+unsigned char GetMode()
+{
+  return reader(REG_MODE);
+}
+
+void WriteFIFO(unsigned char d)
+{
+  writer(REG_FIFO,d);
+}
+
+void msg(char *m)
+{
+  if(optSerial){
+    if(Serial) Serial.print(m);
+  }
+}
+
+void RFM_Init()
+{
+  digitalWrite(RESET,0);
+  delay(1000);
+  digitalWrite(RESET,1);
+  delay(100);
+  //Switch RFM to sleep
+  SetMode(MODE_SLEEP);
+  delay(10);
+  //Set RFM in LoRa mode
+  SetMode(MODE_LORA_SLEEP);  // WAS LORA SLEEP
+  delay(100);
+  //Set RFM in Standby mode wait on mode ready
+  SetMode(MODE_LORA_STANDBY);
+  delay(100);
+  char wk[100];
+  sprintf(wk,"Expect lstby, Mode now %02X\n",GetMode());
+  msg(wk);
+  /*
+  while (digitalRead(DIO5) == LOW)
+  {
+  }
+  */
+  delay(10);
+  //Set carrier frequency
+  // 868.100 MHz / 61.035 Hz = 14222987 = 0xD9068B
+  RFM_Write(REG_FREQ_H,0xD9);
+  RFM_Write(REG_FREQ_M,0x06);
+  RFM_Write(REG_FREQ_L,0x8B);
+
+  RFM_Write(REG_PACONFIG,0xff); // ff is max   //PA pin (maximal power)
+  RFM_Write(REG_MODEMCONFIG,0x72);  //BW = 125 kHz, Coding rate 4/5, Explicit header mode
+  RFM_Write(REG_MODEMCONFIG2,0xB4);  //Spreading factor 7, PayloadCRC On
+  RFM_Write(REG_SYMBTIMEOUT,0x25);  //Rx Timeout set to 37 symbols
+  RFM_Write(REG_PREAMBLE_MSB,0x00);
+  RFM_Write(REG_PREAMBLE_LSB,0x08);  //Preamble length set to 8 symbols 0x0008 + 4 = 12
+  RFM_Write(REG_MODEMCONFIG3,0x0C);  //Low datarate optimization off AGC auto on
+
+  
+  RFM_Write(0x39,0x34); //Set LoRa sync word
+    
+  //Set IQ to normal values
+  RFM_Write(0x33,0x27);
+  RFM_Write(0x3B,0x1D);
+
+  //Set FIFO pointers
+  RFM_Write(REG_FIFOTXBASEADDR,0x80);
+  RFM_Write(REG_FIFORXBASEADDR,0x00);
+  SetMode(MODE_LORA_SLEEP);
+}
+
+
+void setFreq(double freq)
+{
+  double d = freq*1.0e6/61.035;
+  int l = (int)d;
+  fb1 = l >> 16 & 255;
+  fb2 = l >> 8 & 255;
+  fb3 = l & 255; 
+}
+
+/*
+*****************************************************************************************
+* Description : Function for sending a package with the RFM
+*
+* Arguments   : *RFM_Tx_Package Pointer to arry with data to be send
+*               Package_Length  Length of the package to send
+*****************************************************************************************
+*/
+
+void RFM_Send_Package(unsigned char *RFM_Tx_Package, unsigned char Package_Length)
+{
+  unsigned char i;
+  unsigned char RFM_Tx_Location = 0x00;
+  //Set RFM in Standby mode wait on mode ready
+  SetMode(MODE_SLEEP);
+  SetMode(MODE_LORA_SLEEP);
+  SetMode(MODE_LORA_STANDBY);
+  /*
+  while (digitalRead(DIO5) == LOW)  {  }
+  */
+  delay(100);
+  //Switch DIO0 to TxDone
+  //RFM_Write(0x40,0x40);
+  //Set carrier frequency 868.100 MHz / 61.035 Hz = 14222987 = 0xD9068B
+  //RFM_Write(REG_FREQ_H,0xD9);
+  //RFM_Write(REG_FREQ_M,0x06);
+  //RFM_Write(REG_FREQ_L,0x8B);
+
+  RFM_Write(REG_FREQ_H,fb1);
+  RFM_Write(REG_FREQ_M,fb2);
+  RFM_Write(REG_FREQ_L,fb3);
+
+  // RE ORDR NEXT 2 LINES
+  RFM_Write(REG_MODEMCONFIG,0x72); //125 kHz 4/5 coding rate explicit header mode
+  //RFM_Write(REG_MODEMCONFIG2, 0x74); //SF7 CRC On (LOOKS OK)
+  RFM_Write(REG_MODEMCONFIG2,0x70); //SF7 CRC On (LOOKS OK)
+  //RFM_Write(REG_MODEMCONFIG3,0x04); //Low datarate optimization off AGC auto on
+  RFM_Write(REG_MODEMCONFIG3,0x00); //Low datarate optimization off AGC auto on
+  RFM_Write(REG_PACONFIG,0xff); // ff is maxc POWER LEVEL
+  //Set IQ to normal values
+  // RFM_Write(0x33,0x27); // TAKE OUT 2 LINES
+  //RFM_Write(0x3B,0x1D);
+  RFM_Write(REG_PREAMBLE_MSB,0x00);
+  RFM_Write(REG_PREAMBLE_LSB,13);  //Preamble length set to 12 +4
+
+  RFM_Write(REG_SYNC,0x34); // newer
+  RFM_Write(REG_PAYLOADLENGTH,Package_Length);
+  RFM_Tx_Location = reader(REG_FIFOTXBASEADDR);  //Get location of Tx part of FiFo
+  RFM_Write(REG_FIFOADDRPTR,RFM_Tx_Location);  //Set SPI pointer to start of Tx part in FiFo
+  RFM_Write(REG_FIFOADDRPTR,0x80); /// new
+  RFM_Write(REG_FIFOTXBASEADDR,0x80); /// new
+
+  //Write Payload to FiFo
+  for (i = 0;i < Package_Length; i++)
+      WriteFIFO(*RFM_Tx_Package++);
+  char wk[100];
+  int wt = 0,m=0;
+  //sprintf(wk,"Before tx starts, DIO0 is %d, mode is %02X, pkglen %d\n",DIO0(),GetMode(),Package_Length);
+  //msg(wk);
+  //Wait for TxDone
+  //Switch RFM to Tx
+  SetMode(MODE_LORA_TX);
+  m = GetMode();
+  while(GetMode()==MODE_LORA_TX) // was DIO0()==0
+  {  wt++; 
+  };
+  sprintf(wk,"count %d mode %02X  ",wt,m);
+  msg(wk);
+  //Switch RFM to sleep
+  SetMode(MODE_LORA_SLEEP);
+}
+
+void Encrypt_Payload(unsigned char *Data, unsigned char Data_Length, unsigned int Frame_Counter, unsigned char Direction)
+{
+  unsigned char i = 0x00;
+  unsigned char j;
+  unsigned char Number_of_Blocks = 0x00;
+  unsigned char Incomplete_Block_Size = 0x00;
+
+  unsigned char Block_A[16];
+
+  //Calculate number of blocks
+  Number_of_Blocks = Data_Length / 16;
+  Incomplete_Block_Size = Data_Length % 16;
+  if(Incomplete_Block_Size != 0)
+  {
+    Number_of_Blocks++;
+  }
+
+  for(i = 1; i <= Number_of_Blocks; i++)
+  {
+    Block_A[0] = 0x01;
+    Block_A[1] = 0x00;
+    Block_A[2] = 0x00;
+    Block_A[3] = 0x00;
+    Block_A[4] = 0x00;
+
+    Block_A[5] = Direction;
+
+    Block_A[6] = DevAddr[3];
+    Block_A[7] = DevAddr[2];
+    Block_A[8] = DevAddr[1];
+    Block_A[9] = DevAddr[0];
+
+    Block_A[10] = (Frame_Counter & 0x00FF);
+    Block_A[11] = ((Frame_Counter >> 8) & 0x00FF);
+
+    Block_A[12] = 0x00; //Frame counter upper Bytes
+    Block_A[13] = 0x00;
+
+    Block_A[14] = 0x00;
+
+    Block_A[15] = i;
+
+    //Calculate S
+    AES_Encrypt(Block_A,AppSkey); //original
+    
+
+    //Check for last block
+    if(i != Number_of_Blocks)
+    {
+      for(j = 0; j < 16; j++)
+      {
+        *Data = *Data ^ Block_A[j];
+        Data++;
+      }
+    }
+    else
+    {
+      if(Incomplete_Block_Size == 0)
+      {
+        Incomplete_Block_Size = 16;
+      }
+      for(j = 0; j < Incomplete_Block_Size; j++)
+      {
+        *Data = *Data ^ Block_A[j];
+        Data++;
+      }
+    }
+  }
+}
+
+void Calculate_MIC(unsigned char *Data, unsigned char *Final_MIC, unsigned char Data_Length, unsigned int Frame_Counter, unsigned char Direction)
+{
+  unsigned char i;
+  unsigned char Block_B[16];
+  
+  unsigned char Key_K1[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  unsigned char Key_K2[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+
+  //unsigned char Data_Copy[16];
+
+  unsigned char Old_Data[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  unsigned char New_Data[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  
+  
+  unsigned char Number_of_Blocks = 0x00;
+  unsigned char Incomplete_Block_Size = 0x00;
+  unsigned char Block_Counter = 0x01;
+
+  //Create Block_B
+  Block_B[0] = 0x49;
+  Block_B[1] = 0x00;
+  Block_B[2] = 0x00;
+  Block_B[3] = 0x00;
+  Block_B[4] = 0x00;
+
+  Block_B[5] = Direction;
+
+  Block_B[6] = DevAddr[3];
+  Block_B[7] = DevAddr[2];
+  Block_B[8] = DevAddr[1];
+  Block_B[9] = DevAddr[0];
+
+  Block_B[10] = (Frame_Counter & 0x00FF);
+  Block_B[11] = ((Frame_Counter >> 8) & 0x00FF);
+
+  Block_B[12] = 0x00; //Frame counter upper bytes
+  Block_B[13] = 0x00;
+
+  Block_B[14] = 0x00;
+  Block_B[15] = Data_Length;
+
+  //Calculate number of Blocks and blocksize of last block
+  Number_of_Blocks = Data_Length / 16;
+  Incomplete_Block_Size = Data_Length % 16;
+
+  if(Incomplete_Block_Size != 0)
+  {
+    Number_of_Blocks++;
+  }
+
+  Generate_Keys(Key_K1, Key_K2);
+
+  //Preform Calculation on Block B0
+
+  //Preform AES encryption
+  AES_Encrypt(Block_B,NwkSkey);
+
+  //Copy Block_B to Old_Data
+  for(i = 0; i < 16; i++)
+  {
+    Old_Data[i] = Block_B[i];
+  }
+
+  //Preform full calculating until n-1 messsage blocks
+  while(Block_Counter < Number_of_Blocks)
+  {
+    //Copy data into array
+    for(i = 0; i < 16; i++)
+    {
+      New_Data[i] = *Data;
+      Data++;
+    }
+
+    //Preform XOR with old data
+    XOR(New_Data,Old_Data);
+
+    //Preform AES encryption
+    AES_Encrypt(New_Data,NwkSkey);
+
+    //Copy New_Data to Old_Data
+    for(i = 0; i < 16; i++)
+    {
+      Old_Data[i] = New_Data[i];
+    }
+
+    //Raise Block counter
+    Block_Counter++;
+  }
+
+  //Perform calculation on last block
+  //Check if Datalength is a multiple of 16
+  if(Incomplete_Block_Size == 0)
+  {
+    //Copy last data into array
+    for(i = 0; i < 16; i++)
+    {
+      New_Data[i] = *Data;
+      Data++;
+    }
+
+    //Preform XOR with Key 1
+    XOR(New_Data,Key_K1);
+
+    //Preform XOR with old data
+    XOR(New_Data,Old_Data);
+    
+    //Preform last AES routine
+    // read NwkSkey from PROGMEM
+    AES_Encrypt(New_Data,NwkSkey);
+  }
+  else
+  {
+    //Copy the remaining data and fill the rest
+    for(i =  0; i < 16; i++)
+    {
+      if(i < Incomplete_Block_Size)
+      {
+        New_Data[i] = *Data;
+        Data++;
+      }
+      if(i == Incomplete_Block_Size)
+      {
+        New_Data[i] = 0x80;
+      }
+      if(i > Incomplete_Block_Size)
+      {
+        New_Data[i] = 0x00;
+      }
+    }
+
+    //Preform XOR with Key 2
+    XOR(New_Data,Key_K2);
+
+    //Preform XOR with Old data
+    XOR(New_Data,Old_Data);
+
+    //Preform last AES routine
+    AES_Encrypt(New_Data,NwkSkey);
+  }
+
+  Final_MIC[0] = New_Data[0];
+  Final_MIC[1] = New_Data[1];
+  Final_MIC[2] = New_Data[2];
+  Final_MIC[3] = New_Data[3];
+}
+
+void Generate_Keys(unsigned char *K1, unsigned char *K2)
+{
+  unsigned char i;
+  unsigned char MSB_Key;
+
+  //Encrypt the zeros in K1 with the NwkSkey
+  AES_Encrypt(K1,NwkSkey);
+
+  //Create K1
+  //Check if MSB is 1
+  if((K1[0] & 0x80) == 0x80)
+  {
+    MSB_Key = 1;
+  }
+  else
+  {
+    MSB_Key = 0;
+  }
+
+  //Shift K1 one bit left
+  Shift_Left(K1);
+
+  //if MSB was 1
+  if(MSB_Key == 1)
+  {
+    K1[15] = K1[15] ^ 0x87;
+  }
+
+  //Copy K1 to K2
+  for( i = 0; i < 16; i++)
+  {
+    K2[i] = K1[i];
+  }
+
+  //Check if MSB is 1
+  if((K2[0] & 0x80) == 0x80)
+  {
+    MSB_Key = 1;
+  }
+  else
+  {
+    MSB_Key = 0;
+  }
+
+  //Shift K2 one bit left
+  Shift_Left(K2);
+
+  //Check if MSB was 1
+  if(MSB_Key == 1)
+  {
+    K2[15] = K2[15] ^ 0x87;
+  }
+}
+
+void Shift_Left(unsigned char *Data)
+{
+  unsigned char i;
+  unsigned char Overflow = 0;
+  //unsigned char High_Byte, Low_Byte;
+
+  for(i = 0; i < 16; i++)
+  {
+    //Check for overflow on next byte except for the last byte
+    if(i < 15)
+    {
+      //Check if upper bit is one
+      if((Data[i+1] & 0x80) == 0x80)
+      {
+        Overflow = 1;
+      }
+      else
+      {
+        Overflow = 0;
+      }
+    }
+    else
+    {
+      Overflow = 0;
+    }
+
+    //Shift one left
+    Data[i] = (Data[i] << 1) + Overflow;
+  }
+}
+
+void XOR(unsigned char *New_Data,unsigned char *Old_Data)
+{
+  unsigned char i;
+
+  for(i = 0; i < 16; i++)
+  {
+    New_Data[i] = New_Data[i] ^ Old_Data[i];
+  }
+}
+
+/*
+*****************************************************************************************
+* Title         : AES_Encrypt
+* Description  : 
+*****************************************************************************************
+*/
+void AES_Encrypt(unsigned char *Data, unsigned char *Key)
+{
+  unsigned char Row, Column, Round = 0;
+  unsigned char Round_Key[16];
+    unsigned char State[4][4];
+
+  //  Copy input to State arry
+  for( Column = 0; Column < 4; Column++ )
+  {
+    for( Row = 0; Row < 4; Row++ )
+    {
+      State[Row][Column] = Data[Row + (Column << 2)];
+    }
+  }
+
+  //  Copy key to round key
+  memcpy( &Round_Key[0], &Key[0], 16 );
+
+  //  Add round key
+  AES_Add_Round_Key( Round_Key, State );
+
+  //  Preform 9 full rounds with mixed collums
+  for( Round = 1 ; Round < 10 ; Round++ )
+  {
+    //  Perform Byte substitution with S table
+    for( Column = 0 ; Column < 4 ; Column++ )
+    {
+      for( Row = 0 ; Row < 4 ; Row++ )
+      {
+        State[Row][Column] = AES_Sub_Byte( State[Row][Column] );
+      }
+    }
+
+    //  Perform Row Shift
+    AES_Shift_Rows(State);
+
+    //  Mix Collums
+    AES_Mix_Collums(State);
+
+    //  Calculate new round key
+    AES_Calculate_Round_Key(Round, Round_Key);
+
+        //  Add the round key to the Round_key
+    AES_Add_Round_Key(Round_Key, State);
+  }
+
+  //  Perform Byte substitution with S table whitout mix collums
+  for( Column = 0 ; Column < 4 ; Column++ )
+  {
+    for( Row = 0; Row < 4; Row++ )
+    {
+      State[Row][Column] = AES_Sub_Byte(State[Row][Column]);
+    }
+  }
+    
+  //  Shift rows
+  AES_Shift_Rows(State);
+
+  //  Calculate new round key
+  AES_Calculate_Round_Key( Round, Round_Key );
+
+    //  Add round key
+  AES_Add_Round_Key( Round_Key, State );
+
+  //  Copy the State into the data array
+  for( Column = 0; Column < 4; Column++ )
+  {
+    for( Row = 0; Row < 4; Row++ )
+    {
+      Data[Row + (Column << 2)] = State[Row][Column];
+    }
+  }
+} // AES_Encrypt
+
+
+/*
+*****************************************************************************************
+* Title         : AES_Add_Round_Key
+* Description : 
+*****************************************************************************************
+*/
+void AES_Add_Round_Key(unsigned char *Round_Key, unsigned char (*State)[4])
+{
+  unsigned char Row, Collum;
+
+  for(Collum = 0; Collum < 4; Collum++)
+  {
+    for(Row = 0; Row < 4; Row++)
+    {
+      State[Row][Collum] ^= Round_Key[Row + (Collum << 2)];
+    }
+  }
+} // AES_Add_Round_Key
+
+
+/*
+*****************************************************************************************
+* Title         : AES_Sub_Byte
+* Description : 
+*****************************************************************************************
+*/
+unsigned char AES_Sub_Byte(unsigned char Byte)
+{
+//  unsigned char S_Row,S_Collum;
+//  unsigned char S_Byte;
+//
+//  S_Row    = ((Byte >> 4) & 0x0F);
+//  S_Collum = ((Byte >> 0) & 0x0F);
+//  S_Byte   = S_Table [S_Row][S_Collum];
+
+  //return S_Table [ ((Byte >> 4) & 0x0F) ] [ ((Byte >> 0) & 0x0F) ]; // original
+  return S_Table [((Byte >> 4) & 0x0F)] [((Byte >> 0) & 0x0F)];
+} //    AES_Sub_Byte
+
+
+
+/*
+*****************************************************************************************
+* Title         : AES_Shift_Rows
+* Description : 
+*****************************************************************************************
+*/
+void AES_Shift_Rows(unsigned char (*State)[4])
+{
+  unsigned char Buffer;
+
+  //Store firt byte in buffer
+  Buffer      = State[1][0];
+  //Shift all bytes
+  State[1][0] = State[1][1];
+  State[1][1] = State[1][2];
+  State[1][2] = State[1][3];
+  State[1][3] = Buffer;
+
+  Buffer      = State[2][0];
+  State[2][0] = State[2][2];
+  State[2][2] = Buffer;
+  Buffer      = State[2][1];
+  State[2][1] = State[2][3];
+  State[2][3] = Buffer;
+
+  Buffer      = State[3][3];
+  State[3][3] = State[3][2];
+  State[3][2] = State[3][1];
+  State[3][1] = State[3][0];
+  State[3][0] = Buffer;
+}   //  AES_Shift_Rows
+
+
+/*
+*****************************************************************************************
+* Title         : AES_Mix_Collums
+* Description : 
+*****************************************************************************************
+*/
+void AES_Mix_Collums(unsigned char (*State)[4])
+{
+  unsigned char Row,Collum;
+  unsigned char a[4], b[4];
+    
+    
+  for(Collum = 0; Collum < 4; Collum++)
+  {
+    for(Row = 0; Row < 4; Row++)
+    {
+      a[Row] =  State[Row][Collum];
+      b[Row] = (State[Row][Collum] << 1);
+
+      if((State[Row][Collum] & 0x80) == 0x80)
+      {
+        b[Row] ^= 0x1B;
+      }
+    }
+        
+    State[0][Collum] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3];
+    State[1][Collum] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3];
+    State[2][Collum] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3];
+    State[3][Collum] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3];
+  }
+}   //  AES_Mix_Collums
+
+
+
+/*
+*****************************************************************************************
+* Title         : AES_Calculate_Round_Key
+* Description : 
+*****************************************************************************************
+*/
+void AES_Calculate_Round_Key(unsigned char Round, unsigned char *Round_Key)
+{
+  unsigned char i, j, b, Rcon;
+  unsigned char Temp[4];
+ 
+  //Calculate Rcon
+  Rcon = 0x01;
+  while(Round != 1)
+  {
+    b = Rcon & 0x80;
+    Rcon = Rcon << 1;
+        
+    if(b == 0x80)
+    {
+      Rcon ^= 0x1b;
+    }
+    Round--;
+  }
+    
+  //  Calculate first Temp
+  //  Copy laste byte from previous key and subsitute the byte, but shift the array contents around by 1.
+    Temp[0] = AES_Sub_Byte( Round_Key[12 + 1] );
+    Temp[1] = AES_Sub_Byte( Round_Key[12 + 2] );
+    Temp[2] = AES_Sub_Byte( Round_Key[12 + 3] );
+    Temp[3] = AES_Sub_Byte( Round_Key[12 + 0] );
+
+  //  XOR with Rcon
+  Temp[0] ^= Rcon;
+
+  //  Calculate new key
+  for(i = 0; i < 4; i++)
+  {
+    for(j = 0; j < 4; j++)
+    {
+      Round_Key[j + (i << 2)]  ^= Temp[j];
+      Temp[j]                   = Round_Key[j + (i << 2)];
+    }
+  }
+}   //  AES_Calculate_Round_Key
+
+float readThermistor() {
+  return 25.0f;
+}
+
+void DoMessage() {
+    uint16_t temp;
+    uint8_t Data[32];
+    uint8_t Data_Length;
+    //temp = (int)(readThermistor() * 100);
+    //Data[0] = (temp >> 8) & 0xff;
+    //Data[1] = temp & 0xff;
+    Data_Length = 5;
+    memcpy(Data,"windy!",Data_Length);    
+    LORA_Send_Data(Data, Data_Length, MyFrameCounter);
+    MyFrameCounter++;
+    writeFrameCounter(); // save counter to EEPROM
+}
+
+void DoMessage_Temp(int temperature) {
+    uint16_t temp;
+    uint8_t Data[32];
+    uint8_t Data_Length;
+    temp = temperature;
+    Data[0] = (temp >> 8) & 0xff; // high byte first
+    Data[1] = temp & 0xff;
+    Data_Length = 2;
+    LORA_Send_Data(Data, Data_Length, MyFrameCounter);
+    MyFrameCounter++;
+    writeFrameCounter(); // save counter to EEPROM
+}
+
+
+double readerd(unsigned int addr)
+{
+    int n = (int)reader(addr);
+    return (double)n;
+}
+
+double getFreqMHz()
+{
+  return  61.035e-6*(readerd(8)+readerd(7)*256.0+readerd(6)*256.0*256.0);
+}
+
+// IR section
+#define AIN1  6
+int diff,previousdiff = 0;
+
+void irTest()
+{
+  char buf[80];
+  int n0A,n0B,n0C,n1A,n1B,n1C;
+  digitalWrite(NSENSE,0); // sensors all on
+  digitalWrite(ADRIVE,1);
+  digitalWrite(BDRIVE,1); // off
+  digitalWrite(CDRIVE,1);
+  digitalWrite(GLED,1);
+  delay(10);
+  n0A = analogRead(ASENSE);
+  n0B = analogRead(BSENSE);
+  n0C = analogRead(CSENSE);
+  sprintf(buf,"LED off : %5d %5d %5d\n",n0A,n0B,n0C);
+  msg(buf);
+  digitalWrite(ADRIVE,0);
+  digitalWrite(BDRIVE,0); // on
+  digitalWrite(CDRIVE,0);
+  delay(10);
+  n1A = analogRead(ASENSE);
+  n1B = analogRead(BSENSE);
+  n1C = analogRead(CSENSE);
+  
+  diff = abs(n1B-n0B);
+  digitalWrite(ADRIVE,1);
+  digitalWrite(BDRIVE,1); // off
+  digitalWrite(CDRIVE,1);
+  sprintf(buf,"LED ON : %5d %5d %5d \n",n1A,n1B,n1C);
+  msg(buf);
+  if(abs(diff-previousdiff)>30)
+    {
+      sprintf(buf,"******* BIG CHANGE \n");
+      msg(buf);     
+    }
+  previousdiff = diff;
+}
+
+void MapleLED(int n)
+{
+  digitalWrite(MAPLELED,n);
+}
+
+void otest()
+{
+  char buf[80];
+  int o1,o2,o3,o4;
+  while(1)
+  {
+  o1 = digitalRead(OPTION1);
+  o2 = digitalRead(OPTION2);
+  o3 = digitalRead(OPTION3);
+  o4 = digitalRead(OPTION4);
+  sprintf(buf," %d %d %d %d\n",o1,o2,o3,o4);
+  msg(buf);
+  }
+}
+
+void t_test()
+{
+  char mess[80];
+  int temp = 143;
+  sprintf(mess,"Faked Temperature %5.1f decimal %d\n",(float)temp/10.0,temp);
+  msg(mess);
+  DoMessage_Temp(temp);  // read DHT22 temperature and send it
+}
+
+void t_test2()
+{
+  char mess[80];
+  int i,dat[40],lo,hi,d,n,w0,w1,mask,by[5],b,ptr,bit,thr;
+  
+  sprintf(mess,"Reading DHT22\n");
+  msg(mess);
+  pinMode(DHT22,OUTPUT);
+  digitalWrite(DHT22,0);
+  delay(18);
+  digitalWrite(DHT22,1);
+  pinMode(DHT22,INPUT);
+  lo = hi = 0;
+  while(digitalRead(DHT22)==1);
+  // expect low for 50us, then high for 50us
+  // then 40 lots of 50us low, 26/70us high
+  while(digitalRead(DHT22)==0) lo++;
+  while(digitalRead(DHT22)==1) hi++;
+
+  for(d=0;d<40;d++)
+    {
+      n = 0;
+      while(digitalRead(DHT22)==0) n++;
+      n = 0;
+      while(digitalRead(DHT22)==1) n++;
+      dat[d]=n;
+    }
+  delay(100);
+  pinMode(DHT22,OUTPUT);
+  thr = lo/2;
+  ptr = 0; // array walk
+  for(b=0;b<5;b++){
+      mask = 0x80;
+      by[b]=0;  
+      for(bit=0;bit<8;bit++)
+          {
+          if(dat[ptr]>thr) 
+            by[b] |= mask;
+          mask = mask >> 1;
+          ptr ++;
+          }
+    }
+  //sprintf(mess,"bytes %d %d %d %d    %d, sum%d \n",by[0],by[1],by[2],by[3],by[4],(by[0]+by[1]+by[2]+by[3]) % 256);
+  //msg(mess);
+  sprintf(mess,"RH %d%% Temp %dC\n",by[0],by[2]);
+  msg(mess);
+}
+
+void test1()
+{
+  char mess[80];
+  int i,v;
+#define NN 1000000
+  sprintf(mess,"START %d  ",NN);
+  msg(mess);
+  for(i=0;i<NN;i++)
+    v = analogRead(ASENSE);
+  msg("DONE\n");  
+  
+}
+
+
+
+void setup() {
+  optionInit(); // header pins determine function
+  if(optSerial){
+    Serial.begin(9600);
+    while(!Serial);
+  }
+//  otest();
+  if(optResetCounter) {
+    MyFrameCounter = 0;
+    writeFrameCounter();  
+  }
+  spiInit();  
+  pinMode(MAPLELED,OUTPUT);
+  digitalWrite(MAPLELED,0);
+  pinMode(IRDRIVE,OUTPUT);  
+  digitalWrite(IRDRIVE,0);
+  pinMode(RLED,OUTPUT);
+  pinMode(GLED,OUTPUT);
+  pinMode(BLED,OUTPUT);
+  pinMode(NSENSE,OUTPUT);
+  pinMode(ASENSE,INPUT);
+  pinMode(BSENSE,INPUT);
+  pinMode(CSENSE,INPUT);
+  pinMode(ADRIVE,OUTPUT);
+  pinMode(BDRIVE,OUTPUT);
+  pinMode(CDRIVE,OUTPUT);
+  pinMode(DHT22,OUTPUT);
+  digitalWrite(RLED,0);
+  digitalWrite(GLED,0);
+  digitalWrite(BLED,0);
+  digitalWrite(ADRIVE,1);
+  digitalWrite(BDRIVE,1);
+  digitalWrite(CDRIVE,1);
+  digitalWrite(NSENSE,1);
+  digitalWrite(DHT22,0); 
+  msg("LORA_ARM_TX Various mode version - Starting up...\n"); 
+  RFM_Init();
+  readFrameCounter();
+  setFreq(868.1);
+}
+
+
+void loop() {
+  char buf[80];
+  switch(JOB){
+    case JOB_TX:
+        {
+        sprintf(buf,"TX Freq %6.1f MHz Counter %d\n",getFreqMHz(),MyFrameCounter);        
+        msg(buf);
+        delay(1000);   
+        MapleLED(1);
+        DoMessage();
+        MapleLED(0);
+        msg("Time to next tx : ");
+        int cyc=30;
+        for(int i=cyc;i>0;i--)
+          {
+          if(i % 5 == 0 || i<5 )
+            {
+            sprintf(buf,"%d ",i);    
+            msg(buf);
+            }
+          delay(1000);
+          }
+        msg("\n");
+        }
+        break;
+      
+    case JOB_MAILBOX:
+        {
+        msg("IR Sensor B only\n");       
+        delay(1000);
+        irTest();
+        }
+        break;
+
+    case JOB_TEMP:
+        {
+        msg("Temperature/Humidity\n");
+        delay(1000);
+        t_test2();
+        delay(3000);
+        //delay(60000);
+        }
+        break;
+
+    case JOB_TEST1:
+        {
+        msg("TEST1 - see how fast it samples\n");
+        test1();
+        }
+    break;
+    default:     
+        break;
+  }
+ 
+}
+// end
