#include <Arduino.h>
#line 1 "C:\\Users\\mc007\\Desktop\\osr\\lydia-printhead\\firmware\\tests\\rs485\\rs485.ino"
#include <Arduino_MachineControl.h>
using namespace machinecontrol;

#undef DISABLE_LOGGING
#include <ArduinoLog.h>

#include <osr-base.h>
#include <App.h>
#include <Addon.h>

#include <SPI.h>
#include <Ethernet.h>

#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
#define ARDUINO_MODBUS
#define MODBUS_BAUDRATE 19200

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
// The IP address will be dependent on your local network:
byte mac[] = {
    0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);

EthernetServer ethServer(502);
ModbusTCPServer modbusTCPServer;

#include "Mudbus.h"

class COM_TCP : public Component
{
public:
  Mudbus *mb;

  COM_TCP() : Component("COM_TCP", 10), mb(new Mudbus())
  {
    setFlag(OBJECT_RUN_FLAGS::E_OF_DEBUG);
  }

  short setup()
  {

    // Set the PMC Communication Protocols to default config
    comm_protocols.init();
    // RS485/RS232 default config is:
    // - RS485 mode
    // - Half Duplex
    // - No A/B and Y/Z 120 Ohm termination enabled

    // Enable the RS485/RS232 system
    comm_protocols.rs485Enable(true);

    Log.verboseln("Setup COM_TCP");

    // Ethernet.init(10);

    Ethernet.begin(mac, ip);

    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware)
    {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true)
      {
        delay(1); // do nothing, no point running without Ethernet hardware
      }
    }
    if (Ethernet.linkStatus() == LinkOFF)
    {
      Serial.println("Ethernet cable is not connected.");
    }

    // start the server
    ethServer.begin();

    // start the Modbus TCP server
    if (!modbusTCPServer.begin())
    {
      Serial.println("Failed to start Modbus TCP Server!");
      while (1)
        ;
    }

    // configure a single coil at address 0x00
    modbusTCPServer.configureCoils(0x00, 0);
    // configure a single coil at address 0x01
    modbusTCPServer.configureCoils(0x01, 0);

    for (uchar i = 0; i < 100; i++)
    {
      mb->R[i] = 0;
      mb->C[i] = 0;
    }

    return 0;
  }
  void updateLED()
  {
    // read the current value of the coil
    int coilValue = modbusTCPServer.coilRead(0x00);
    int coilValue1 = modbusTCPServer.coilRead(0x01);
    // Log.verboseln("coilValue - 0x00: %d", coilValue);
    // Log.verboseln("coilValue - 0x01: %d", coilValue1);
    if (coilValue)
    {
      // coil value set, turn LED on
      // analog_out.write(0, 10);
    }
    else
    {
      // analog_out.write(0, 0);
    }

  /*
    if (mb->C[0])
    {
      Log.verboseln("coilValue - 0x00: %d changed", 0);
      analog_out.write(0, 10);
      // mb->R[0] = 0;
    }
    else
    {
      analog_out.write(0, 0);
    }

    if (mb->C[1])
    {
      Log.verboseln("coilValue - 0x01: %d changed", 1);
      // mb->R[0] = 0;
    }
    */
  }

  short loop()
  {
    // Log.verboseln("Loop COM_TCP");

    // listen for incoming clients
    EthernetClient client = ethServer.available();

    if (client)
    {
      // a new client connected
      Log.verboseln("new client");

      // let the Modbus TCP accept the connection
      modbusTCPServer.accept(client);

      while (client.connected())
      {
        // poll for Modbus TCP requests, while client connected
        modbusTCPServer.poll();

        updateLED();
      }
      Log.verboseln("client disconnected");
    }
    // mb->Run();
    return 0;
  }

  short debug(Stream *stream)
  {
    // Log.verboseln("Debug COM_TCP");
    return 0;
  }

  short info(Stream *stream)
  {
    // Log.verboseln("Info COM_TCP");
    return 0;
  }
};

class COM_RS485 : public Component
{
public:
  COM_RS485() : Component("COM_RS485", 10)
  {
    setFlag(OBJECT_RUN_FLAGS::E_OF_DEBUG);
  }

  short setup()
  {
    Log.verboseln("Setup RS485");

#ifdef PORTENTA_RS485
    // Set the PMC Communication Protocols to default config
    comm_protocols.init();
    // RS485/RS232 default config is:
    // - RS485 mode
    // - Half Duplex
    // - No A/B and Y/Z 120 Ohm termination enabled

    // Enable the RS485/RS232 system
    comm_protocols.rs485Enable(true);

    // Enable Full Duplex mode
    // This will also enable A/B and Y/Z 120 Ohm termination resistors
    comm_protocols.rs485FullDuplex(true);

    // Specify baudrate, and preamble and postamble times for RS485 communication
    comm_protocols.rs485.begin(115200, 0, 500);

    // Start in receive mode
    comm_protocols.rs485.receive();
#endif

#ifdef ARDUINO_MODBUS

    // Set the PMC Communication Protocols to default config
    comm_protocols.init();
    // RS485/RS232 default config is:
    // - RS485 mode
    // - Half Duplex
    // - No A/B and Y/Z 120 Ohm termination enabled

    // Enable the RS485/RS232 system
    comm_protocols.rs485Enable(true);

    // Enable Full Duplex mode
    // This will also enable A/B and Y/Z 120 Ohm termination resistors
    comm_protocols.rs485FullDuplex(true);

    // Specify baudrate, and preamble and postamble times for RS485 communication
    comm_protocols.rs485.begin(115200, 0, 500);

    // start the Modbus RTU server, with (slave) id 1
    if (!ModbusRTUServer.begin(1, MODBUS_BAUDRATE))
    {
      Serial.println("Failed to start Modbus RTU Server!");
      while (1)
        ;
    }

    // configure a single coil at address 0x00
    ModbusRTUServer.configureCoils(0x00, 1);

#endif
    return 0;
  }

  short loop()
  {
    Log.verboseln("Loop RS485");
    // poll for Modbus RTU requests
    int packetReceived = ModbusRTUServer.poll();

    if (packetReceived)
    {
      Log.verboseln("Loop RS485: Got packet");
      // read the current value of the coil
      int coilValue = ModbusRTUServer.coilRead(0x00);
      if (coilValue)
      {
        // coil value set, turn LED on
        analog_out.write(0, 10);
      }
      else
      {
        analog_out.write(0, 0);
      }
    }
    return 0;
  }

  short debug(Stream *stream)
  {
    Log.verboseln("Debug RS485");
    return 0;
  }

  short info(Stream *stream)
  {
    Log.verboseln("Info RS485");
    return 0;
  }
};

class RS485_Test : public App
{
public:
  COM_RS485 *rs485;
  COM_TCP *tcp;

  RS485_Test() : App(),
                 rs485(new COM_RS485()),
                 tcp(new COM_TCP()) {}

  short setup()
  {
    Serial.begin(19200);
    while (!Serial && !Serial.available())
    {
    }
    Log.begin(LOG_LEVEL_VERBOSE, &Serial);
    Log.verbose(F(CR "* App:setup   *" CR));
    components.push_back((Component *)rs485);
    components.push_back((Component *)tcp);
    App::setup();
    return E_OK;
  }
};

RS485_Test testApp;

#line 308 "C:\\Users\\mc007\\Desktop\\osr\\lydia-printhead\\firmware\\tests\\rs485\\rs485.ino"
void setup();
#line 315 "C:\\Users\\mc007\\Desktop\\osr\\lydia-printhead\\firmware\\tests\\rs485\\rs485.ino"
void loop();
#line 308 "C:\\Users\\mc007\\Desktop\\osr\\lydia-printhead\\firmware\\tests\\rs485\\rs485.ino"
void setup()
{
  // init_osr_base();
  Log.verboseln("Setup");
  testApp.setup();
}

void loop()
{
  testApp.loop();
  // Log.verbose(F("* main hb *" CR));
  delay(100);
}

