from librpiplc import rpiplc
from lorawan import LoRaWAN, JoinError
from lora import LoRa, TimeoutError, ConfigurationError
import sys
import signal
import time

def signal_handler(sig, frame):
    print("\nExiting program.")
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

def main():
    rpiplc.init("RPIPLC_V6", "RPIPLC_21")
    rpiplc.pin_mode("I0.12", rpiplc.INPUT)
    rpiplc.pin_mode("EXP1_RST", rpiplc.OUTPUT)

    debug = True
    serial_port = "/dev/ttySC0"
    timeout = 30000
    appkey = "2018E498A67ECB2C1834D81397DC6E49"
    appeui = "0000000000000000"
    deveui = "70B3D57ED006A075"

    error_count = 0
    max_errors = 3

    # Perform hardware reset of the LoRa module once at the beginning
    rpiplc.digital_write("EXP1_RST", 1)
    if debug:
        print("Hardware reset of LoRa module.")
    time.sleep(2)  # Wait 2 seconds to ensure the module resets

    # Initialize LoRaWAN and join the network
    loraWAN = LoRaWAN(serial_port, timeout_serial=timeout, timeout_lora=timeout, debug=debug)
    try:
        loraWAN.config_otaa(appkey=appkey, appeui=appeui, deveui=deveui)
        loraWAN.join()
        if debug:
            print("Successfully joined LoRaWAN network.")
    except JoinError as e:
        print(f"Error joining LoRaWAN network: {e}")
        sys.exit(1)

    # Main loop
    while True:
        # Read local data
        read_value = rpiplc.analog_read("I0.12")
        read_value_string = str(read_value)
        print("The I0.12 is reading: {}".format(read_value_string))

        # --- Switch to radio mode to receive data ---
        try:
            loraWAN.mac_pause()
            time.sleep(1)
            loraWAN.radio_set_mode('lora')
            time.sleep(0.5)
            # Set 'radio' parameters after switching mode
            loraWAN._ser_write_read_verify("radio set freq 868100000", "ok")
            loraWAN._ser_write_read_verify("radio set sf sf12", "ok")
            loraWAN._ser_write_read_verify("radio set bw 125", "ok")
            loraWAN._ser_write_read_verify("radio set cr 4/5", "ok")
            loraWAN._ser_write_read_verify("radio set prlen 8", "ok")
            loraWAN._ser_write_read_verify("radio set crc on", "ok")
            loraWAN._ser_write_read_verify("radio set iqi off", "ok")
            time.sleep(0.5)
            loraWAN.radio_receive()

            if debug:
                print("LoRa:recv : Receiving...")
            incoming_data = loraWAN.recv_str()
            print("Received data from another RPIPLC: {}".format(incoming_data))
            combined_data = "Local: {}, Remote: {}".format(read_value_string, incoming_data)
        except TimeoutError:
            print("No incoming data received, using placeholder")
            combined_data = "Local: {}, Remote: No Data".format(read_value_string)
        except Exception as e:
            print(f"Error receiving data: {e}")
            combined_data = "Local: {}, Remote: Error".format(read_value_string)
        finally:
            # Always stop the radio receive operation
            loraWAN._ser_write_read_verify("radio rxstop", "ok")
            time.sleep(0.1)

        # --- Switch back to MAC mode and send via LoRaWAN ---
        try:
            loraWAN.mac_resume()
            if debug:
                print("LoRaWAN: Sending uplink...")
            hex_data = combined_data.encode('utf-8').hex()
            loraWAN.send_uplink(hex_data)
            print("Sent uplink with combined data: {}".format(combined_data))
            error_count = 0
        except Exception as e:
            print(f"Error sending uplink: {e}")
            error_count += 1
            if error_count >= max_errors:
                print("Maximum number of errors reached. Resetting LoRa module.")
                # Perform hardware reset
                rpiplc.digital_write("EXP1_RST", 0)
                time.sleep(0.1)
                rpiplc.digital_write("EXP1_RST", 1)
                time.sleep(2)  # Wait for the module to reset
                # Reinitialize the module configuration
                loraWAN.__init__(serial_port, timeout_serial=timeout, timeout_lora=timeout, debug=debug)
                loraWAN.config_otaa(appkey=appkey, appeui=appeui, deveui=deveui)
                loraWAN.join()
                # Reset the error counter
                error_count = 0

        # Wait before the next cycle
        time.sleep(30)  # Wait 30 seconds or adjust as needed

if __name__ == "__main__":
    main()
