from multiprocessing.connection import Client
import pigpio # http://abyz.co.uk/rpi/pigpio/python.html
import os
import fnmatch
import time, random
import threading
import traceback
import struct
import sys
import binascii
import csv
import random
from datetime import datetime

from config import Config

class AT_Lora_Module():

	def __init__(self):
		self.pi = pigpio.pi()
		self.serialOpen = False
		if not self.pi.connected:
			print 'ERROR: pigpiod not running, start sudo pigpiod'
			exit()
		print 'PiGpiod running'
		
		self.txpin=23
		self.rxPin=24
		self.baudrate = 9600

		self.pi.set_mode(self.rxPin,pigpio.INPUT)
		self.pi.set_mode(self.txpin,pigpio.OUTPUT)
		pigpio.exceptions = False
		self.pi.bb_serial_read_close(self.rxPin)
		pigpio.exceptions = True


	def Sendline(self, value):
		self.pi.wave_clear()
		self.pi.wave_add_serial(self.txpin,self.baudrate,value,0,8,2)
		wid=self.pi.wave_create()
		self.pi.wave_send_once(wid)
		while self.pi.wave_tx_busy():
				pass
		self.pi.wave_delete(wid)

	def GetValue(self, command, value, delay, responsechar):
		#self.pi.bb_serial_read_open(self.rxPin,self.self.baudrate,8)
		try:
			wait_cnt = 0
			while(self.serialOpen):
				time.sleep(0.2)
				wait_cnt =+1
				if(wait_cnt>10):
					raise Exception("wait timeout")
			if (command == None):
				self.Sendline('\r') 
				#self.pi.bb_serial_read_close(self.rxPin)
				self.serialOpen  = False
				return
			else:
				self.serialOpen  = True  
				self.pi.bb_serial_read_open(self.rxPin,self.baudrate,8)
				self.Sendline(command+value +'\r') 
				self.serialOpen  = False
			response = bytearray()
			time.sleep(delay)
			while True:
					self.serialOpen  = True 
					(count, data) = self.pi.bb_serial_read(self.rxPin)
					#response.append(data)
					if count:
						#print 'rec: ', data
						response.extend(data)
						responselen = responsechar+1
						if(responsechar == 0):
							responselen = len(response)
						self.pi.bb_serial_read_close(self.rxPin)
						self.serialOpen  = False
						if('\r\n' in data):
							#print 'response\r\n', response
							if('OK' in response):
								return (True, response[0:responselen-1])
							elif('AT_ERROR' in response):
								return (False, response[0:responselen-1])
							else:
								print response
								return (False, response[0:responselen-1])
		except Exception as e:
			print "no serial read in progress"
			print e
			if(self.serialOpen):
				self.pi.bb_serial_read_close(self.rxPin)
			return (False, "Exception")

	def SendCommand(self, command, value, delay):
		#self.pi.bb_serial_read_open(self.rxPin,self.baudrate,8)
		try:
			wait_cnt = 0
			while(self.serialOpen):
				time.sleep(0.2)
				wait_cnt =+1
				if(wait_cnt>10):
					raise Exception("wait timeout")
			if (command == None):
				self.serialOpen  = True 
				self.Sendline('\r\n') 
				#self.pi.bb_serial_read_close(self.rxPin)
				self.serialOpen  = False
				return
			elif(value == None):
				self.serialOpen  = True 
				self.pi.bb_serial_read_open(self.rxPin,self.baudrate,8)
				self.Sendline(command +'\r')
				self.serialOpen  = False
			else:  
				self.serialOpen  = True 
				self.pi.bb_serial_read_open(self.rxPin,self.baudrate,8)
				self.Sendline(command+value +'\r')
				self.serialOpen  = False
			response = bytearray()
			time.sleep(delay)
			while True:
					self.serialOpen  = True 
					(count, data) = self.pi.bb_serial_read(self.rxPin)
					if count:
						response.extend(data)
						self.pi.bb_serial_read_close(self.rxPin)
						self.serialOpen  = False
						if('\r\n' in data):
							#print 'response\r\n', response
							if('OK' in response):
								#print 'true'
								return True
							elif('AT_PARAM_ERROR' in response):
								print 'param error'
								return False
							elif('AT_BUSY_ERROR' in response):
								print 'busy error'
								return False
							elif('AT_RX_ERRORR' in response):
								print 'rx error'
								return False
							elif('AT_NO_NETWORK_JOINED' in response):
								print 'no network error'
								return False
							elif('AT_ERROR' in response):
								#print 'false'
								return False
							else:
								print response + '\r\n'
								return False
		except Exception as e:
			print "no serial read in progress"
			print e
			if(self.serialOpen):
				self.pi.bb_serial_read_close(self.rxPin)
			return (False, "Exception")
			


	def ResetDevice(self):
		try:
			if(self.serialOpen):
				self.pi.bb_serial_read_close(self.rxPin)
				raise Exception("serial open")
			#try:
			#	self.pi.bb_serial_read_close(self.rxPin)
			#except Exception as e:
			#	print "no serial read in progress"
			#	print e
			self.serialOpen  = True 
			self.pi.bb_serial_read_open(self.rxPin,self.baudrate,8)
			self.Sendline('ATZ\r')
			response = bytearray()
			time.sleep(0.5)
			loopCount = 0
			while (True):
				loopCount += 1
				if(loopCount > 1000):
					self.pi.bb_serial_read_close(self.rxPin)
					self.serialOpen  = False
					return False
				self.serialOpen  = True 
				(count, data) = self.pi.bb_serial_read(self.rxPin)
				print count
				if count:
					response.extend(data)
					self.pi.bb_serial_read_close(self.rxPin)
					self.serialOpen  = False
					if(len(response)>170):
						print response
						return True
		except Exception as e:
			print "no serial read in progress "
			print e
			if(self.serialOpen):
				self.serialOpen = False
			return False
	
	def closeAT(self):
		self.pi.stop()
		


STANDARD = 0
FAVORITE = 1
REFERENCE = 2

MAX_MESSAGE_SIZE = 32
#MAX_MESSAGE_SIZE = 64
LORA_VERSION = 311
loraTime = datetime.now()

app_key = '2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C'
dev_eui = 'B1:B2:B3:B4:B5:B6:B7:B8'
app_eui = 'C1:C2:C3:C4:C5:C6:C7:C8'

class Lora():

	currentLoraDir = 'data/lora/'

	# Lora init function. All initializations should be made here
	def __init__(self, deviceId, mac):
		#Create file in server with format eg B2001.txt
		self.deviceId = deviceId
		self.mac_address = mac
		self.AT = AT_Lora_Module()

		if not os.path.exists(self.currentLoraDir):
			original_umask = os.umask(0)
			try:
				os.makedirs(self.currentLoraDir, 0777)
			finally:
				os.umask(original_umask)

		self.numberLogsLora = self.numberLogsInLora()
		print('lora version: ', LORA_VERSION )
		print('Logs in lora: ' + str(self.numberLogsLora))

		self.enable = False
		lora = Config().getLora()
		if lora is not None and lora['enable']:
			self.enable = True

		print('Lora Test configuration:', self.enable)

		self.comm_thread = LoraCommunicate(self.currentLoraDir, self.AT)

	def getAutoEnable(self):
		return self.enable

	def clearLogs(self):
		try:
			os.system('rm -rf %s/*' % self.currentLoraDir)
			self.numberLogsLora = self.numberLogsInLora()
		except Exception as e:
			print 'clear logs exception:' 
			print e
			pass

	#Number of tags to be sent
	def numberLogsInLora(self):
		if not os.path.exists(self.currentLoraDir):
			return 0

		n = len(fnmatch.filter(os.listdir(self.currentLoraDir),'*.csv'))
		return n

	# Write a file for Lora transmition
	def writeLineLora(self, tag, timeStr, id, tagType):
		try:
			#Create a file with the current time stamp
			fileName =  time.strftime("%Y%m%d%H%M%S")
			#Example to test multiple files
			#fileName =  "20161103010101"

			if os.path.exists(self.currentLoraDir + fileName + '.csv'):
				for x in range(0, 9999):
					fileNameNew = fileName + str(x).zfill(4)
					if not os.path.exists(self.currentLoraDir + fileNameNew + '.csv'):
						fileName = fileNameNew
						break

			fileName = self.currentLoraDir + fileName + '.temp_csv'

			# Info formatation
			# tag, id, type are strings
			# timeStr is in format %Y-%m-%d %H:%M:%S

			dateHex = format(int(time.mktime(time.strptime(timeStr, '%Y-%m-%d %H:%M:%S'))) - time.timezone, 'x').upper()
			idToWrite = id
			#use the id chars to store ref, if the tag is a reference
			if(tagType[0] == 'R' ):
				idToWrite = type.strip('Reference')
				
			row = (",".join([tag, dateHex, idToWrite, tagType[0]]))
			writeOK = False
			writeAttempts = 0
			while(not writeOK):
				self.tryWriteFile(fileName,row)
				writeAttempts+=1

				writeOK = self.checkFile(fileName, tag, dateHex, idToWrite, tagType[0])
				if(writeAttempts>4):
					raise IOError('write lora temp_csv error')
					break
			
			if(writeOK == True):
				pre, ext = os.path.splitext(fileName)
				os.rename(fileName, pre + ".csv")

		except Exception as e:
			print 'Lora write line Exception' 
			print e
			pass

	def tryWriteFile(self,fileToWrite, formattedRow):
		#remove file that may exist from previous 
		if os.path.isfile(fileToWrite):
			os.remove(fileToWrite)
		# Write info to file
		if(fileToWrite.endswith(".temp_csv")):
			with open(fileToWrite, 'w') as f:
				f.write(formattedRow + '\n')
				f.flush()
				os.fsync(f.fileno())
				f.close()
				return

	def checkFile(self,fileToCheck, tag, date, id, tagType):
		try:
			if not os.path.isfile(fileToCheck):
				return False	
			if not fileToCheck.endswith(".temp_csv"):
				return False
			if(os.path.getsize(fileToCheck) == 0):
				return False 
			
			with open(fileToCheck, 'r') as f:
				line = f.readline()
				f.close()
				
				if(self.checkLine(line, tag, date, id, tagType)):
					return True
				else:
					return False
		except Exception as e:
			print 'Lora checkFile Exception' 
			print e
			return False
	
	def checkLine(self,lineToCheck, tag, date, id, tagType):
			
			sline = lineToCheck.rstrip()
			value_list = sline.split(",")
			
			if(len(value_list) is not 4):
				return False
			#tag 
			if(value_list[0] != tag):
				return False
			#date
			if(value_list[1] != date):
				return False
			#tag type
			if(not value_list[3].isalpha()):
				return False

			return True

	def getLoraTimestamp(self):
		global loraTime
		return loraTime

	# Lora state machine that will run every loop
	def stateMachine(self):
		pass

	def setup(self):
		#global config_array
		global app_eui
		global dev_eui
		global app_key

		time.sleep(1)

		app_key = '2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C'
		dev_eui = self.mac_address.upper() + ':FF:FF'
		app_eui = 'AA:' + self.mac_address.upper() + ':AA'
		
		if (self.comm_thread.configureLora(dev_eui,app_eui,app_key)):
			print 'init configure lora'
			return True
		else:
			print 'init configure lora false'
			return False

	def runLoraThreads(self):
		if(self.comm_thread == None):
			self.comm_thread = LoraCommunicate(self.currentLoraDir, self.AT)
		self.comm_thread.start()
		print 'started Lora Threads'
		print '********************'
		return

	def stopLoraThreads(self):
		#self.comm_thread.stop()
		self.comm_thread.stop()
		print 'called Lora Thread stop()'
		self.comm_thread.join()
		print 'called Lora Thread join()'
		self.comm_thread = None
		print 'called Lora Thread release reference'
		self.comm_thread = LoraCommunicate(self.currentLoraDir, self.AT)
		print 'stopped Lora Threads'
		print '********************'
		return

	def reset(self):
		return self.comm_thread.reset()

	def getResetCount(self):
		try:
			count = self.comm_thread.getResetCount()
			if(count is not None):
				return count
			else: 
				return 0
		except Exception as e:
			print "get reset Exception:"
			print e
			return 0

	def isLoraPresent(self):
		return self.comm_thread.isLoraPresent()

	def isLoraConnected(self):
		return self.comm_thread.isLoraConnected()


###################################################################################
# NAME		: LoraMonitorLog
# DESCRIPTION : checks for new log entries, converts and populates the message queue
# INPUT	   : NONE
###################################################################################
class LoraMonitorLog():
	def __init__(self, monitor_dir):
		self.monitor_dir = os.path.abspath(monitor_dir)

	def file_is_empty(self, file_path):
		return os.stat(file_path).st_size == 0

	def deleteFile(self, file_path = None):
		if os.path.exists(file_path):
			os.remove(file_path)
			# print('deleted: ', file_path)
			return

		print('The file does not exist: ', file_path)
		return

	def processFile(self, file_path):
		tag_str = None
		path = file_path

		try:
			# Check if file exist
			if not os.path.exists(path):
				return None
			if self.file_is_empty(path):
				print "file is empty,getting next"
				pre, ext = os.path.splitext(path)
				os.rename(path, pre + ".bad_csv")
				path = self.nextFile()
				if(path == None):
					return None


			log_file = open(path, 'r')
			# print('opening and reading: ', file_path)

			line = log_file.readline()
			line = line.strip('\n')

			log_file.close()

			if line is not None and line != '':
				tag_str = self.convertToByteArray(line)

		except (IOError, Exception) as e:
			# Delete all files that are not correctly formated
			print('Process File', e)
			try:
				self.deleteFile(path)
			except:
				pass
			pass

		return tag_str

	#typedef struct BeamerPacket{
	#	uint8_t packetSize;
	#	//uint8_t packetType;
	#	//int32_t unixEpoch;
	#	//uint8_t id_a;
	#	//uint8_t id_b;
	#	//uint8_t id_c;
	#	uint8_t cType;
	# uint8_t ref;
	#	uint8_t data[MAX_TAG_SIZE];
	#} BeamerPacket;
	##################################################################
	def convertToByteArray(self,line):
		lines = line.rstrip()
		value_list = lines.split(",")
		#format tag
		tag = binascii.a2b_hex(value_list[0])
		
		#format epoch
		#epoch_int = int(value_list[1],16)
		#epoch = struct.pack("<I", epoch_int)
		
		#format ID chars
		#id_a_char,id_b_char,id_c_char = value_list[2]
		#id_a = struct.pack('<B', ord(id_a_char))
		#id_b = struct.pack('<B', ord(id_b_char))
		#id_c = struct.pack('<B', ord(id_c_char))
		
		#packet type byte
		#packet_type_hex = 0x55
		#packet_type = struct.pack('<B',packet_type_hex)
		#card type
		ctype_int = 0
		if value_list[3] == 'S':
			ctype_int = STANDARD
		elif value_list[3] == 'F':
			ctype_int = FAVORITE
		elif value_list[3] == 'R':
			ctype_int = REFERENCE
		ctype = struct.pack('<B',ctype_int)
		ref_byte = value_list[2]
		ref = struct.pack('<B', int(ref_byte))

		#includes size of itself
		#length_int = 1 + len(packet_type) + len(epoch) + len(id_a) + len(id_b) + len(id_c) + len(ctype) + len(tag)
		#length = struct.pack('<B', length_int)
		#byte_str = length + packet_type + epoch + id_a + id_b + id_c + ctype + tag

		length_int = 1 + len(ctype)+ len(ref) + len(tag)
		length = struct.pack('<B', length_int)
		byte_str = length + ctype + ref + tag

		print('byte_str:',binascii.hexlify(byte_str))
		#byte_list = bytearray(byte_str)

		return binascii.hexlify(byte_str)

	def nextFile(self):

		file_path = None
		try:
			l = os.listdir(self.monitor_dir)
			for file in l:
				if(file.endswith(".csv")):
					file_path = os.path.join(self.monitor_dir, file)
					if os.path.isfile(file_path):
						break

		except (IOError):
			print 'IOError'
			pass

		return file_path


###################################################################################
# NAME		: LoraCommunicate
# DESCRIPTION : Consumes the message queue from monitor thread, transmits via i2c
# INPUT	   : NONE
###################################################################################
class LoraCommunicate(threading.Thread):
	def __init__(self, lora_dir, AT_Module):
		threading.Thread.__init__(self)
		self._stop_event = threading.Event()

		self.daemon = True
		self.setDaemon(True)

		self.AT = AT_Module

		self.monitor = LoraMonitorLog(lora_dir)
		self.isConnected = False
		self.keepAliveTime = 0
		self.resetCounter = 0
	
	def stop(self):
		#self.AT.closeAT()
		#self.AT = None
		self._stop_event.set()

	def stopped(self):
		return self._stop_event.is_set()

	def get_thread_id(self): 
		# returns id of the respective thread 
		if hasattr(self, '_thread_id'): 
				return self._thread_id 
		for cur_thread_id, thread in threading._active.items(): 
				if thread is self: 
						return cur_thread_id

	def raise_exception(self): 
		thread_id = self.get_id() 
		res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit)) 
		if res > 1: 
			ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0) 
			print('Exception raise failure') 

	def setLoraTimestamp(self):
		global loraTime
		loraTime = datetime.now()

	def configureLora(self, dev_eui, app_eui, app_key):
		self.AT.SendCommand( 'AT+DEUI=', dev_eui,1) 
		time.sleep(1)
		(success, result) = self.AT.GetValue('AT+DEUI=', '?',1, 23)
		print result
		if(not success):
			return False
		if(result.upper() != dev_eui):
			return False
	
		self.AT.SendCommand( 'AT+APPEUI=', app_eui,1) 
		time.sleep(1)
		(success, result) = self.AT.GetValue('AT+APPEUI=', '?',1, 23)
		print result
		if(not success):
			return False
		if(result.upper() != app_eui):
			return False
		print 'lora configured'
		
		return True

	def joinStatus(self):
			joined = False
			print 'checking join status'
			(success, join) = self.AT.GetValue('AT+NJS=', '?',1, 1)
			if(success and join == '1'):
				joined = True
				self.isConnected = True
				return joined

	def joinLora(self):
		count = 0

		while(True):
			if (self.joinStatus() == True):
				self.isConnected = True
				return True
			
			#print 'joining'
			cmd_stat = self.AT.SendCommand('AT+JOIN',None,1)
			if(cmd_stat):
				time.sleep(10)
			
			count+=1
			#print 'not joined:', join
			#print 'success:', success
			if (count>4):
				print 'cannot join'
				return False

	def setDataRate(self):
		cmd_stat = self.AT.SendCommand('AT+DR=','7',1)
		time.sleep(1)
		(success, result) = self.AT.GetValue('AT+DR=', '?',1, 1)

		if(success):
			if(result.upper() == '7'):
				print 'set Data rate 7'
				return True
		return False

	def setMessageConfirm(self):
		cmd_stat = self.AT.SendCommand('AT+CFM=','1',1)
		time.sleep(1)
		(success, result) = self.AT.GetValue('AT+CFM=', '?',1, 1)

		if(success):
			if(result.upper() == '1'):
				print 'Confirm messages'
				return True
		return False

	def disableMessageConfirm(self):
		cmd_stat = self.AT.SendCommand('AT+CFM=','0',1)
		time.sleep(1)
		(success, result) = self.AT.GetValue('AT+CFM=', '?',1, 1)

		if(success):
			if(result.upper() == '0'):
				print 'Disable Confirm messages'
				return True
		return False

	def setDutyCycleEnable(self, enabled):
		duty = '0'
		if enabled:
			duty = '1'

		cmd_stat = self.AT.SendCommand('AT+DCS=',duty,1)
		time.sleep(1)
		(success, result) = self.AT.GetValue('AT+DCS=', '?',1, 1)

		if(success):
			if(result.upper() == duty):
				print 'duty cycle set: ', result
				return True
		return False

	def reset(self):
		print('[loraReset] Reset')
		self.isConnected = False
		while(not self.AT.ResetDevice()):
			self.delay(1,0)
			self.resetCounter +=1
			print("."), 
		print"."
		self.resetCounter = 0
		print('[loraReset] Reset Done')
		return True

	def getResetCount(self):
		return self.resetCounter

	def isLoraPresent(self):
		return True

	def isLoraConnected(self):
		return self.isConnected

	def getLoraRSSI(self):
		RSSI = 0
		print 'getting RSSI'
		(success, RSSI) = self.AT.GetValue('AT+RSSI=', '?',1, 0)
		print 'RSSI:', RSSI
		if(success):
			txtRSSI=RSSI[0:-3].decode()
			print 'txrssi: ', txtRSSI
		return RSSI

	def getLoraSNR(self):
		SNR = 0
		print 'getting SNR'
		(success, SNR) = self.AT.GetValue('AT+SNR=', '?',1, 0)
		print 'SNR:', SNR
		return SNR
	
	def getModemVer(self):
		version = 0
		print 'getting modem Version'
		(success, version) = self.AT.GetValue('AT+SNR=', '?',1, 0)
		print 'version:', version
		return version

	def keepAliveByteArray(self, SNR,RSSI):
		byteSNR= struct.pack('<B',SNR)
		byteRSSI= struct.pack('<B',RSSI)
		alive_byte_str = byteSNR + byteRSSI
		print('keepalive byte_str:',binascii.hexlify(alive_byte_str))
		return binascii.hexlify(alive_byte_str)

	def sendKeepAliveLora(self):
		self.disableMessageConfirm()
		time.sleep(1)
		msgAlive = self.keepAliveByteArray(10,40)
		cmd_stat = self.AT.SendCommand('AT+SENDB=','20:'+ msgAlive,1)
		if(cmd_stat):
			print 'keep alive sent'
		else:
			print 'keep alive tx not ready'
		time.sleep(1)
		self.setMessageConfirm()
		
		return cmd_stat

	def sendMsgLora(self,msgToSend = []):
		#must be of 4 elements
		msgLength = len(msgToSend)
		#print 'msgLength: ', msgLength
		if (msgLength < 6) or (msgLength > MAX_MESSAGE_SIZE):
			print 'incorrect list size in sendMsgLora'
			return False

		print 'sending message'
		cmd_stat = self.AT.SendCommand('AT+SENDB=','50:'+ msgToSend,1)
		return cmd_stat

	def LocalDeleteLoraLogFile(self,file_path = None):
		if os.path.exists(file_path):
			os.remove(file_path)
			print 'deleted: ', file_path
			return
		else:
			#print 'The file does not exist: ', file_path
			return

	def delay(self, t, r = None):
		if r is None:
			r = 5

		d = random.uniform(0, r)
		time.sleep(t + d)
		return

	def getConfirmation(self):
		#print 'checking confirmation'
		(success, result) = self.AT.GetValue('AT+CFS=', '?',1, 1)
		if(success):
			#print result
			if(result.upper() == '1'):
				return True
		
		return False

	def loraWaitConnect(self):
		connection_attempts = 0
		self.isConnected = False
		while True:
			self.setLoraTimestamp()

			if self.stopped():
				print '[loraWaitConnect] stopped event'
				return False
	
			print'[loraWaitConnect] Connection attemps', connection_attempts
			if (connection_attempts > 6):
				connection_attempts = 0
				self.reset()
				self.delay(1,0)
	
			print('[loraWaitConnect] Configuring Lora')
			if not self.configureLora(dev_eui, app_eui, app_key):
				connection_attempts+=1
				self.delay(5,0)
				continue
			print '[loraWaitConnect] Configured Successfully'
			self.delay(1,0)
			
			print '[loraWaitConnect] checking join status, attempts: ', connection_attempts
			if not self.joinLora():
				connection_attempts+=1
				self.delay(8,2)
				continue
			print '[loraWaitConnect] JOINED'
			connection_attempts = 0
			self.delay(1,0)
			self.sendKeepAliveLora()
			self.isConnected = True
			return True

	def run(self):
		if self.stopped():
			print '[Lora Run 1     ] stopped event'
			return
		self.setLoraTimestamp()

		time.sleep(1)
		count=0
		tx_retry_count = 0
		tx_waiting_count = 0
		local_lora_packet = None
		

		while True:
			self.setLoraTimestamp()
		
			if self.stopped():
				print '[Lora Run 1.5   ] stopped event'
				return
			self.reset()
			self.setDutyCycleEnable(True)
			self.setDataRate()
			self.loraWaitConnect()
			#normal operation begins here

			file = None
			tx_retry_count = 0
			tx_waiting_count = 0
		
			self.setMessageConfirm()
			self.delay(5,1)
			print '[Lora Run 2     ] lora steady state'
			
			while True:
				self.setLoraTimestamp()

				if self.stopped():
					print '[Lora Run 2     ] stopped event'
					return
				
				msgSent = False
				
				#too many retries, break the loop
				if tx_retry_count > 3:
					tx_retry_count = 0
					print '[Lora Run 2     ] hit max retry count, resetting'
					self.delay(1)
					break

				#if lora modem will not send a message during this time, reset (go to outer loop)
				if tx_waiting_count > 22:
					tx_waiting_count = 0
					print '[Lora Run 2     ] hit max TX NOT READY, resetting'
					self.delay(1)
					break

 				file=self.monitor.nextFile()
				if local_lora_packet is not None:
					self.keepAliveTime = 0
					print '[Lora Run 2     ] resending local_lora_tuple'

				elif file is not None:
					self.keepAliveTime = 0
					lora_packet = self.monitor.processFile(file)

					if lora_packet is not None:
						local_lora_packet = lora_packet
						tx_retry_count = 0
				
				#more than 5 minutes passed
				elif self.keepAliveTime > 300:
					self.keepAliveTime = 0
					print '[Lora Run 2     ] Send KeepAlive'
					if(not self.sendKeepAliveLora()):
						tx_waiting_count +=1
						self.keepAliveTime = 150
					else:
						self.keepAliveTime = 0
					time.sleep(5)
					continue

				else:
					self.delay(3, 0)
					#print '[Lora Run 2     ] Idle'
					self.keepAliveTime +=3
					continue

				if local_lora_packet is not None:
					msgSent = self.sendMsgLora(local_lora_packet)
					print '[Lora Run 2     ] end msg status: ', msgSent
					tx_timeout = 4
					
					
					if(not msgSent):
						tx_waiting_count +=1
						print '[Lora Run 3     ] TX not ready, waiting count:', tx_waiting_count
						time.sleep(5)
						
					else:
						while(True):
							if self.stopped():
								print '[Lora Run 3     ] stopped event'
								return
							tx_waiting_count = 0
							time.sleep(.5)
							print '[Lora Run 3     ] packet sent to lora module,waiting for TX to complete'
							if(self.getConfirmation()):
								self.isConnected = True
								count+=1
								print '[Lora Run 3     ] TX complete, sent packet number: ', count
								self.monitor.deleteFile(file)
								file = None
								local_lora_packet = None
								self.delay(6,4)
								self.keepAliveTime = 0
								break
							else:
								self.delay(3,1)
								tx_timeout-=1

								if(tx_timeout == 0):
									tx_retry_count+=1
									print '[Lora Run 3     ] TX timed  or failed out, retrying'
									break	


