======
Basics
======

Core concepts and fundamental usage of RevPiModIO.

.. contents:: Contents
   :local:
   :depth: 2

Programming Paradigms
=====================

RevPiModIO supports two complementary programming approaches:

**Cyclic Programming** - Execute a function at regular intervals, similar to PLC programming.

* Best for deterministic timing, state machines, and time-critical control
* Runs your function every cycle (typically 20-50ms)
* See :doc:`cyclic_programming` for details

**Event-Driven Programming** - Register callbacks triggered by hardware state changes.

* Best for user interactions, sporadic events, and system integration
* Consumes CPU only when events occur
* See :doc:`event_programming` for details

Both approaches can be combined in a single application. See :doc:`advanced` for examples.

Getting Started
===============

Basic Instantiation
-------------------

Create a RevPiModIO instance to access your hardware:

.. code-block:: python

    import revpimodio2

    rpi = revpimodio2.RevPiModIO(autorefresh=True)

    # Your code here

    rpi.exit()

Configuration Parameters
------------------------

.. code-block:: python

    rpi = revpimodio2.RevPiModIO(
        autorefresh=True,    # Auto-sync process image (recommended)
        monitoring=False,    # Read-only mode
        syncoutputs=True,    # Load output values on init
        debug=False          # Enable debug messages
    )

**autorefresh** - Automatically reads inputs and writes outputs. Set to ``True`` for most applications.

**monitoring** - Read-only mode. Use when monitoring without controlling hardware.

**syncoutputs** - Load current output values on startup. Prevents outputs from resetting.

**debug** - Enable debug logging for troubleshooting.

Cycle Timing
------------

Default update rates depend on your hardware:

* **Core 1**: 40ms (25Hz)
* **Core3/Connect**: 20ms (50Hz)
* **NetIO**: 50ms (20Hz)

Adjust cycle time to match your needs:

.. code-block:: python

    rpi = revpimodio2.RevPiModIO()
    rpi.cycletime = 100  # Set to 100ms
    rpi.autorefresh_all()

**Important:** Faster cycle times consume more CPU. Choose the slowest cycle time that meets your requirements. Default values will fit most needs.

Error Handling
--------------

Configure I/O error threshold:

.. code-block:: python

    maxioerrors = 10  # Raise exception after 10 errors

    # Check error count
    if rpi.core.ioerrorcount > maxioerrors:
        print("Warning: I/O errors detected")

Core Objects
============

rpi.io - Input/Output Access
-----------------------------

Access all configured IOs from piCtory:

.. code-block:: python

    # Direct attribute access
    value = rpi.io.button.value
    rpi.io.led.value = True

    # String-based access
    rpi.io["button"].value

    # Check existence
    if "sensor" in rpi.io:
        print(rpi.io.sensor.value)

    # Iterate all IOs
    for io in rpi.io:
        print(f"{io.name}: {io.value}")

IO Properties
~~~~~~~~~~~~~

Each IO object has these properties:

* ``.name`` - IO name from piCtory
* ``.value`` - Current value (read/write)
* ``.address`` - Byte address in process image
* ``.type`` - IO type (INPUT=300, OUTPUT=301, MEMORY=302)
* ``.defaultvalue`` - Default value from piCtory

rpi.core - System Control
--------------------------

Access Revolution Pi system features:

LED Control
~~~~~~~~~~~

.. code-block:: python

    # Using constants
    rpi.core.A1 = revpimodio2.GREEN
    rpi.core.A2 = revpimodio2.RED
    rpi.core.A3 = revpimodio2.OFF

    # Individual colors
    rpi.core.a1green.value = True
    rpi.core.a1red.value = False

System Status
~~~~~~~~~~~~~

.. code-block:: python

    # CPU information
    temp = rpi.core.temperature.value
    freq = rpi.core.frequency.value

    # piBridge status
    cycle_time = rpi.core.iocycle.value
    errors = rpi.core.ioerrorcount.value

Watchdog
~~~~~~~~

.. code-block:: python

    # Toggle watchdog
    rpi.core.wd_toggle()

    # Watchdog IO object
    rpi.core.wd.value = True

See :doc:`advanced` for complete watchdog management examples.

rpi.device - Device Access
---------------------------

Access specific hardware devices:

.. code-block:: python

    # By name
    dio = rpi.device.DIO_Module_1

    # By position
    first = rpi.device[0]

    # Iterate
    for device in rpi.device:
        print(device.name)

Signal Handling
===============

Graceful Shutdown
-----------------

Handle SIGINT and SIGTERM for clean program termination:

.. code-block:: python

    rpi = revpimodio2.RevPiModIO(autorefresh=True)

    # Enable signal handling
    rpi.handlesignalend()

    # Run main loop
    rpi.mainloop()

Custom Signal Handler
---------------------

Implement custom cleanup logic:

.. code-block:: python

    def cleanup(signum, frame):
        print("Shutting down...")
        rpi.setdefaultvalues()
        rpi.exit()

    rpi.handlesignalend(cleanup)
    rpi.mainloop()

Simple Examples
===============

Read Input, Control Output
---------------------------

.. code-block:: python

    import revpimodio2

    rpi = revpimodio2.RevPiModIO(autorefresh=True)

    # Read input and control output
    if rpi.io.button.value:
        rpi.io.led.value = True
    else:
        rpi.io.led.value = False

    rpi.exit()

LED Control
-----------

.. code-block:: python

    import revpimodio2

    rpi = revpimodio2.RevPiModIO(autorefresh=True)

    # Control status LEDs
    rpi.core.A1 = revpimodio2.GREEN
    rpi.core.A2 = revpimodio2.RED

    rpi.exit()

Iterate All IOs
---------------

.. code-block:: python

    import revpimodio2

    rpi = revpimodio2.RevPiModIO(autorefresh=True)

    # Print all IOs and their values
    for io in rpi.io:
        print(f"{io.name}: {io.value}")

    rpi.exit()

Best Practices
==============

Use Descriptive IO Names
-------------------------

Configure descriptive names in piCtory:

.. code-block:: python

    # Good - Clear intent
    if rpi.io.emergency_stop.value:
        rpi.io.motor.value = False

    # Poor - Generic names
    if rpi.io.I_15.value:
        rpi.io.O_3.value = False

Always Clean Up
---------------

Always call ``rpi.exit()`` to clean up resources:

.. code-block:: python

    rpi = revpimodio2.RevPiModIO(autorefresh=True)

    try:
        # Your code here
        pass
    finally:
        rpi.exit()

Check IO Existence
------------------

Verify IOs exist before accessing:

.. code-block:: python

    if "optional_sensor" in rpi.io:
        value = rpi.io.optional_sensor.value
    else:
        print("Sensor not configured")

See Also
========

* :doc:`cyclic_programming` - Cyclic programming patterns
* :doc:`event_programming` - Event-driven programming patterns
* :doc:`advanced` - Advanced topics and best practices
* :doc:`api/index` - API reference
