/** \file
 *
 *  Contains the LPC3Reg class implementation.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sched.h>

#include "LPC3Reg.h"
#include "utils/Timestamp.h"

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define BATT_POWER_STATE  (0x400000)    // GPI_22  - bit 22
#define DROP_WEIGHT_STATE (0x100)       // GPI_08  - bit 8
#define DROP_WEIGHT_SENSE_PWR (0x8000)  // GPO_15  - bit 15
#define EMERG_MODE_OFF (0x2000)         // GPO_13  - bit 13
#define CF_CARD_PRESENT (0x10000000)    // GPI_28  - bit 28
#define CPU_BURNWIRE_FIRE (0x400000)    // GPO_22  - bit 22
#define CPU_BURNWIRE_OFF (0x20000000)   // GPIO_04 - bit 29
#define CPU_LOAD_CONT_ON (0x1) 		    // P0.0    - bit 0
#define BATT_MUX_ACTIVATE (0x10)        // P0.4    - bit 4
#define GFSHTDN (0x80000)               // GPO_19  - bit 19
#define GF_TEST (0x800)                 // GPO_11  - bit 11
#define LC_FAULT (0x200)                // GPI_09  - bit 9
#define LPC3250_HEARTBEAT (0x20)        // GPO_05  - bit 5
#define RADIO_BACKUP_PWR (0x4000)       // GPO_14  - bit 14
#define SHORE_POWER_STATE (0x1)         // GPI_00  - bit 0
#define SW_RESIN (0x2000000)   			// GPIO_00 - bit 25
#define WATER_SENSOR_STATE (0x4)        // GPI_02  - bit 2

Mutex LPC3Reg::Mutex_;

// Constructor
LPC3Reg::LPC3Reg( unsigned long targetAddress, int bytesMapped )
    : targetAddress_( targetAddress ), bytesMapped_( bytesMapped )
{
#ifdef __arm__
    unsigned long *map_base;

    if( ( devFD_ = open( "/dev/mem", O_RDWR | O_SYNC ) ) == -1 )
    {
        FATAL;
    }

    map_base = static_cast<unsigned long*>( mmap( 0, bytesMapped_, PROT_READ | PROT_WRITE, MAP_SHARED, devFD_, targetAddress_ & ~MAP_MASK ) );
    if( map_base == ( void * ) 0xFFFFFFFF )
    {
        FATAL;
    }

    map_ = ( int* )( ( unsigned long )map_base + ( targetAddress_ & MAP_MASK ) );
    //printf("Target address 0x%x mapped at address %p.\n", targetAddress_, map_base); // **DEBUG**

#else
    map_ = ( int* )( new char[bytesMapped_] );
    memset( ( void* )map_, 0, bytesMapped_ );
#endif // #ifdef __arm__
}


LPC3Reg::~LPC3Reg()
{
#ifdef __arm__
    unsigned long *map_base;
    map_base = ( unsigned long* )( ( unsigned long )map_ - ( targetAddress_ & MAP_MASK ) );
    //printf("Unmapping virtual address %p for target address 0x%x.\n", map_base, targetAddress_); // **DEBUG**
    if( munmap( map_base, bytesMapped_ ) == -1 ) FATAL;
    close( devFD_ );
#else
    delete[]( char* )( map_ );
#endif // #ifdef __arm__
}

// Flags
bool LPC3Reg::BurnwireActive_( false );

// Clock Control - 0x40004000 base
LPC3Reg LPC3Reg::SysCtrlPhys_ = LPC3Reg( 0x40004000, 0xFF );
volatile int& LPC3Reg::AdcClkCtrl1_     = *( SysCtrlPhys_.map_ + 0x60 / sizeof( int ) );
volatile int& LPC3Reg::AdcClkCtrl_      = *( SysCtrlPhys_.map_ + 0xB4 / sizeof( int ) );
volatile int& LPC3Reg::TimClkCtrl_      = *( SysCtrlPhys_.map_ + 0xBC / sizeof( int ) );
volatile int& LPC3Reg::U3ClkPhys_       = *( SysCtrlPhys_.map_ + 0xD0 / sizeof( int ) );
volatile int& LPC3Reg::U4ClkPhys_       = *( SysCtrlPhys_.map_ + 0xD4 / sizeof( int ) );
volatile int& LPC3Reg::U6ClkPhys_       = *( SysCtrlPhys_.map_ + 0xDC / sizeof( int ) );
volatile int& LPC3Reg::UartClkCtrl_     = *( SysCtrlPhys_.map_ + 0xE4 / sizeof( int ) );

// Main Interrupt Controller - 0x40008000 base

// Sub Interrupt Controller 1 - 0x4000C000 base
LPC3Reg LPC3Reg::Sic1_ = LPC3Reg( 0x4000C000, 0x18 );
volatile int& LPC3Reg::Sic1Er_          = *( Sic1_.map_ + 0x0 / sizeof( int ) );
volatile int& LPC3Reg::Sic1Rsr_         = *( Sic1_.map_ + 0x4 / sizeof( int ) );
volatile int& LPC3Reg::Sic1Sr_          = *( Sic1_.map_ + 0x8 / sizeof( int ) );
volatile int& LPC3Reg::Sic1Apr_         = *( Sic1_.map_ + 0xC / sizeof( int ) );
volatile int& LPC3Reg::Sic1Atr_         = *( Sic1_.map_ + 0x10 / sizeof( int ) );
volatile int& LPC3Reg::Sic1Itr_         = *( Sic1_.map_ + 0x14 / sizeof( int ) );

// Sub Interrupt Controller 2 - 0x40010000 base

// High Speed Uart 1 - 40014000 base
LPC3Reg LPC3Reg::Hsu1RxPhys_ = LPC3Reg( 0x40014000, 0x10 );
volatile int& LPC3Reg::Hsu1RX_          = *( Hsu1RxPhys_.map_ + 0x00 / sizeof( int ) );
volatile int& LPC3Reg::Hsu1Ctrl_        = *( Hsu1RxPhys_.map_ + 0x0C / sizeof( int ) );

// High Speed Uart 2 - 0x40018000 base
LPC3Reg LPC3Reg::Hsu2RxPhys_ = LPC3Reg( 0x40018000, 0x10 );
volatile int& LPC3Reg::Hsu2RX_          = *( Hsu2RxPhys_.map_ + 0x00 / sizeof( int ) );
volatile int& LPC3Reg::Hsu2Level_       = *( Hsu2RxPhys_.map_ + 0x04 / sizeof( int ) );

// High Speed Uart 2 - 0x4001C000 base
LPC3Reg LPC3Reg::Hsu7RxPhys_ = LPC3Reg( 0x4001C000, 0x10 );
volatile int& LPC3Reg::Hsu7RX_          = *( Hsu7RxPhys_.map_ + 0x00 / sizeof( int ) );


// GPIO Registers - 0x40028000 base
LPC3Reg LPC3Reg::PioPhys_ = LPC3Reg( 0x40028000, 0x200 );
volatile int& LPC3Reg::P3InpStatePhys_  = *( PioPhys_.map_ + 0x0 / sizeof( int ) );
volatile int& LPC3Reg::PioOutpSetPhys_  = *( PioPhys_.map_ + 0x04 / sizeof( int ) );
volatile int& LPC3Reg::PioOutpClrPhys_  = *( PioPhys_.map_ + 0x08 / sizeof( int ) );
volatile int& LPC3Reg::PioMuxSetPhys_   = *( PioPhys_.map_ + 0x28 / sizeof( int ) );
volatile int& LPC3Reg::PioMuxClrPhys_   = *( PioPhys_.map_ + 0x104 / sizeof( int ) );
volatile int& LPC3Reg::PioMuxStatePhys_ = *( PioPhys_.map_ + 0x108 / sizeof( int ) );
volatile int& LPC3Reg::P0InpStatePhys_  = *( PioPhys_.map_ + 0x40 / sizeof( int ) );
volatile int& LPC3Reg::P0OutpSetPhys_   = *( PioPhys_.map_ + 0x44 / sizeof( int ) );
volatile int& LPC3Reg::P0OutpClrPhys_   = *( PioPhys_.map_ + 0x48 / sizeof( int ) );
volatile int& LPC3Reg::P0OutpStatePhys_ = *( PioPhys_.map_ + 0x4C / sizeof( int ) );
volatile int& LPC3Reg::P0DirSetPhys_    = *( PioPhys_.map_ + 0x50 / sizeof( int ) );
volatile int& LPC3Reg::P0MuxSetPhys_    = *( PioPhys_.map_ + 0x120 / sizeof( int ) );
volatile int& LPC3Reg::P0MuxClrPhys_    = *( PioPhys_.map_ + 0x124 / sizeof( int ) );
volatile int& LPC3Reg::P3MuxSetPhys_    = *( PioPhys_.map_ + 0x110 / sizeof( int ) );
volatile int& LPC3Reg::P3MuxClrPhys_    = *( PioPhys_.map_ + 0x114 / sizeof( int ) );
volatile int& LPC3Reg::P3MuxStatePhys_  = *( PioPhys_.map_ + 0x118 / sizeof( int ) );


// ADC Control - 0x40048000 base
LPC3Reg LPC3Reg::Adc_ = LPC3Reg( 0x40048000, 0x50 );
volatile int& LPC3Reg::AdcSelect_       = *( Adc_.map_ + 0x04 / sizeof( int ) );
volatile int& LPC3Reg::AdcCtrl_         = *( Adc_.map_ + 0x08 / sizeof( int ) );
volatile int& LPC3Reg::AdcValue_        = *( Adc_.map_ + 0x48 / sizeof( int ) );

// UART Control - 0x40054000 base
LPC3Reg LPC3Reg::UartGenCtrlPhys_ = LPC3Reg( 0x40054000, 0x10 );
volatile int& LPC3Reg::UartCtrlPhys_    = *( UartGenCtrlPhys_.map_ + 0x00 / sizeof( int ) );
volatile int& LPC3Reg::UartClkModePhys_ = *( UartGenCtrlPhys_.map_ + 0x04 / sizeof( int ) );
volatile int& LPC3Reg::UartLoopPhys_    = *( UartGenCtrlPhys_.map_ + 0x08 / sizeof( int ) );


// Regular Uart 3 - 0x40080000 base
LPC3Reg LPC3Reg::Uart3Phys_ = LPC3Reg( 0x40080000, 0xFF );
volatile int& LPC3Reg::U3DllPhys_       = *( Uart3Phys_.map_ + 0x00 / sizeof( int ) );
volatile int& LPC3Reg::U3LsrPhys_       = *( Uart3Phys_.map_ + 0x14 / sizeof( int ) );

// Regular Uart 4 - 0x40088000 base
LPC3Reg LPC3Reg::Uart4Phys_ = LPC3Reg( 0x40088000, 0xFF );
volatile int& LPC3Reg::U4DllPhys_       = *( Uart4Phys_.map_ + 0x00 / sizeof( int ) );
volatile int& LPC3Reg::U4LsrPhys_       = *( Uart4Phys_.map_ + 0x14 / sizeof( int ) );

// Regular Uart 5 - 0x40090000 base
LPC3Reg LPC3Reg::Uart5Phys_ = LPC3Reg( 0x40090000, 0xFF );
volatile int& LPC3Reg::U5LsrPhys_       = *( Uart5Phys_.map_ + 0x14 / sizeof( int ) );

// Regular Uart 6 - 0x40098000 base
LPC3Reg LPC3Reg::Uart6Phys_ = LPC3Reg( 0x40098000, 0xFF );
volatile int& LPC3Reg::U6DllPhys_       = *( Uart6Phys_.map_ + 0x00 / sizeof( int ) );
volatile int& LPC3Reg::U6IERPhys_       = *( Uart6Phys_.map_ + 0x04 / sizeof( int ) );
volatile int& LPC3Reg::U6LsrPhys_       = *( Uart6Phys_.map_ + 0x14 / sizeof( int ) );

// Watchdog Timer - 0x4003C000 base
LPC3Reg LPC3Reg::WDTPhys_ = LPC3Reg( 0x4003C000, 0xFF );
volatile int& LPC3Reg::WDTimCtrl_       = *( WDTPhys_.map_ + 0x04 / sizeof( int ) );
volatile int& LPC3Reg::WDTimCounter_    = *( WDTPhys_.map_ + 0x08 / sizeof( int ) );
volatile int& LPC3Reg::WDTimMCtrl_      = *( WDTPhys_.map_ + 0x0C / sizeof( int ) );
volatile int& LPC3Reg::WDTimMatch0_     = *( WDTPhys_.map_ + 0x10 / sizeof( int ) );
volatile int& LPC3Reg::WDTimEMR_        = *( WDTPhys_.map_ + 0x14 / sizeof( int ) );
volatile int& LPC3Reg::WDTimPulse_      = *( WDTPhys_.map_ + 0x18 / sizeof( int ) );
volatile int& LPC3Reg::WDTimRes_        = *( WDTPhys_.map_ + 0x1C / sizeof( int ) );


// Fire up the watchdog timer
// Initialize the watchdog timer
// Set up to be driven by PERIPH_CLK @ 13 Mhz.
// Full 32 bit register cycle will be 4294967295 * (1/13,000,000) ~ 5.506 minutes
bool LPC3Reg::InitializeWDT( void )
{
    bool retVal = false;

#ifndef __arm__
    LPC3Reg::WDTimCounter_ = 1;
#endif // #ifndef __arm__

    // First enable all WDT register and clock
    LPC3Reg::TimClkCtrl_ |= 0x1;

    Timespan::Milliseconds( 10 ).sleepFor();

    // Enable the timer counter
    LPC3Reg::WDTimCtrl_ = 0x1; // COUNT_ENAB
    // Enable the WDOG_RESET2 signal and interrupt status generation (MR0_INT) on match0
    LPC3Reg::WDTimMCtrl_ = 0x11;
    // Set match output high on match (MATCH_CTRL) and clear any existing match
    LPC3Reg::WDTimEMR_ = 0x20;
    // Set the pulse width to 261 PERIPH_CLKs (0xFF + 6)
    LPC3Reg::WDTimPulse_ = 0xFF;

    Timespan::Milliseconds( 10 ).sleepFor();

    if( ( LPC3Reg::WDTimCounter_ > 0 ) && ( LPC3Reg::WDTimCtrl_ == 0x1 ) && ( LPC3Reg::WDTimEMR_ == 0x20 ) && ( LPC3Reg::WDTimPulse_ == 0xFF ) )
    {
        retVal = true;
    }
    return retVal;
}

bool LPC3Reg::HeartbeatHi_( false );

/// Get ready to heartbeat
void LPC3Reg::InitializeHBC( void )
{
#ifdef __arm__

    // CPLD in emerg circuit needs two rising edges
    LPC3Reg::PioOutpSetPhys_ = LPC3250_HEARTBEAT;
    Timespan::Milliseconds( 32 ).sleepFor();
    LPC3Reg::PioOutpClrPhys_ = LPC3250_HEARTBEAT;
    Timespan::Milliseconds( 32 ).sleepFor();
    LPC3Reg::PioOutpSetPhys_ = LPC3250_HEARTBEAT;
    HeartbeatHi_ = true;

#endif // __arm__
}


/// Kick the dog
void LPC3Reg::StrobeWDT( void )
{
#ifdef __arm__
    unsigned int count = LPC3Reg::WDTimCounter_;

    // Add 60 seconds to the counter
    count += 0x2E7DDB00;

    // And write to the match register
    LPC3Reg::WDTimMatch0_ = count;

#endif // __arm__
}


// Strobe the heartbeat counter
void LPC3Reg::StrobeHBC()
{
    if( HeartbeatHi_ )
    {
        LPC3Reg::PioOutpClrPhys_ = LPC3250_HEARTBEAT;
        HeartbeatHi_ = false;
    }
    else
    {
        LPC3Reg::PioOutpSetPhys_ = LPC3250_HEARTBEAT;
        HeartbeatHi_ = true;
    }
}


void LPC3Reg::ActivateBurnwire( void )
{
    // First de-assert the burnwire off discrete
    LPC3Reg::PioOutpClrPhys_ = CPU_BURNWIRE_OFF;

    // Edge sensitive. Clear first (just to be safe), then assert.
    LPC3Reg::PioOutpClrPhys_ = CPU_BURNWIRE_FIRE;
    Timespan::Milliseconds( 10 ).sleepFor();
    LPC3Reg::PioOutpSetPhys_ = CPU_BURNWIRE_FIRE;

    BurnwireActive_ = true;
}


void LPC3Reg::ActivateBackupRadioPwr( void )
{
    // First clear the signal
    LPC3Reg::PioOutpClrPhys_ = RADIO_BACKUP_PWR;
    Timespan::Milliseconds( 25 ).sleepFor();
    // Then assert
    LPC3Reg::PioOutpSetPhys_ = RADIO_BACKUP_PWR;
}


void LPC3Reg::ActivateDropweightSense( void )
{
    LPC3Reg::PioOutpSetPhys_ = DROP_WEIGHT_SENSE_PWR;
}



void LPC3Reg::ActivateGFPwr( void )
{
    LPC3Reg::PioOutpClrPhys_ = GFSHTDN;
}


void LPC3Reg::DeactivateBurnwire( void )
{
    // First de-assert the burnwire fire discrete
    LPC3Reg::PioOutpClrPhys_ = CPU_BURNWIRE_FIRE;

    // Edge sensitive. Clear first (just to be safe), then assert.
    LPC3Reg::PioOutpClrPhys_ = CPU_BURNWIRE_OFF;
    Timespan::Milliseconds( 10 ).sleepFor();
    LPC3Reg::PioOutpSetPhys_ = CPU_BURNWIRE_OFF;

    BurnwireActive_ = false;
}


void LPC3Reg::DeactivateDropweightSense( void )
{
    LPC3Reg::PioOutpClrPhys_ = DROP_WEIGHT_SENSE_PWR;
}


void LPC3Reg::DeactivateEmergMode( void )
{
    // Init the mux for EMERG_MODE_OFF
    LPC3Reg::P3MuxClrPhys_ = EMERG_MODE_OFF;

    // Set the EMERG_MODE_OFF signal
    LPC3Reg::PioOutpSetPhys_ = EMERG_MODE_OFF;

    // Deactivate the burnwire
    DeactivateBurnwire();

    // Shut off backup radio power
    DeactivateBackupRadioPwr();
}


void LPC3Reg::DeactivateGFPwr( void )
{
    LPC3Reg::PioOutpSetPhys_ = GFSHTDN;
}


void LPC3Reg::DeactivateBackupRadioPwr( void )
{
    // Edge sensitive. First set, then clear
    LPC3Reg::PioOutpSetPhys_ = RADIO_BACKUP_PWR;
    Timespan::Milliseconds( 25 ).sleepFor();
    LPC3Reg::PioOutpClrPhys_ = RADIO_BACKUP_PWR;
}


bool LPC3Reg::InitializeMuxPins( void )
{
    bool retVal = false;
    // Init the mux for EMERG_MODE_OFF
    LPC3Reg::P3MuxClrPhys_ = EMERG_MODE_OFF;

    // UART Loopback mode off
    LPC3Reg::UartLoopPhys_ = 0x00;

    Timespan::Milliseconds( 10 ).sleepFor();

    // Confirm mux
    if( !( LPC3Reg::P3MuxStatePhys_ & EMERG_MODE_OFF ) )
    {
        retVal = true;
    }
    return retVal;
}


void LPC3Reg::SWReset( void )
{
    // Set the SW_RESIN signal (active low)
    LPC3Reg::PioOutpClrPhys_ = SW_RESIN;
    // Shouldn't really get beyond here, but just in case...
    Timespan::Milliseconds( 10 ).sleepFor();
    LPC3Reg::PioOutpSetPhys_ = SW_RESIN;
}


void LPC3Reg::PowerOffBatteryMux( void )
{
    LPC3Reg::P0OutpClrPhys_ = BATT_MUX_ACTIVATE;
}


void LPC3Reg::PowerOnBatteryMux( void )
{
    LPC3Reg::P0OutpSetPhys_ = BATT_MUX_ACTIVATE;
}


// Returns true when load is powered off.
bool LPC3Reg::PowerOffLoads( void )
{
    LPC3Reg::P0OutpClrPhys_ = CPU_LOAD_CONT_ON;
    Timespan::Milliseconds( 10 ).sleepFor();

    // If backplane is still on, that's a problem
    if( QueryBackplanePower() )
    {
        return false;
    }
    else // Otherwise we're good. Could short circuit the if but though this was more simple to understand
    {
        return true;
    }
}


// Activates power to the load control backplane.
// Returns true when load is powered on.
bool LPC3Reg::PowerOnLoads( void )
{
    // Edge sensitive. De-assert first, then assert
    LPC3Reg::P0OutpClrPhys_ = CPU_LOAD_CONT_ON;
    Timespan::Milliseconds( 10 ).sleepFor();
    LPC3Reg::P0OutpSetPhys_ = CPU_LOAD_CONT_ON;
    Timespan::Milliseconds( 10 ).sleepFor();

    return QueryBackplanePower();
}


// Returns true if the drop weight is present, false if not
bool LPC3Reg::IsDropweightOK( void )
{
    bool retVal = false;
    if( ( LPC3Reg::P3InpStatePhys_ & DROP_WEIGHT_STATE ) )
    {
        retVal = true;
    }
    return retVal;
}


// Returns true if shore power is on, false if not.
// High is operating from batteries, low is shore power.
bool LPC3Reg::QueryShorepower( void )
{
    bool retVal = false;
#ifdef __arm__
    if( !( LPC3Reg::P3InpStatePhys_ & SHORE_POWER_STATE ) )
#endif
    {
        retVal = true;
    }
    return retVal;
}

// Returns true when operating on main battery power. Returns false when on backup battery.
bool LPC3Reg::QueryBattPower( void )
{
    bool retVal = true;
    if( ( LPC3Reg::P3InpStatePhys_ & BATT_POWER_STATE ) )
    {
        retVal = false;
    }
    return retVal;
}

// Returns true if battery power is being distributed to the backplane
bool LPC3Reg::QueryBackplanePower( void )
{
    MutexLocker lock( Mutex_ );
    // Check to see if power has been applied
    // Note: discussion with Ed M. 01/12/2015 ended with LC_FAULT being a general signal to
    // denote battery power applied to the LC backplane. Not a signal simply for overcurrent.
    // This does not indicate health/status of individual power cards plugged into the backplane.

    // Note: follow up discussion on 11/16/2018 revealed that per Ed M. later e-mail, the LC_FAULT signal
    // is in fact just for overcurrent as it appears on the schematic and HW manual for the part.
    // Thus this function now simply returns the state of the load cont on signal as it was set
    // in the P0 register. Describing this takes 8 lines of code, doing it takes 1. See below.
    if( LPC3Reg::P0OutpStatePhys_ & CPU_LOAD_CONT_ON )
    {
        return true;
    }
    else
    {
        return false;
    }
}

// Returns true if an overcurrent state is detected on the backplane
bool LPC3Reg::QueryBackplaneOvercurrent( void )
{
    if( LPC3Reg::P3InpStatePhys_ & LC_FAULT )
    {
        return true;
    }
    else
    {
        return false;
    }
}


// Returns true if water is detected in the pressure hull
bool LPC3Reg::WaterDetected( void )
{
    bool retVal = false;
    if( !( LPC3Reg::P3InpStatePhys_ & WATER_SENSOR_STATE ) )
    {
        retVal = true;
    }
    return retVal;
}


bool LPC3Reg::CFMissing( void )
{
    bool retVal = false;
    if( ( LPC3Reg::P3InpStatePhys_ & CF_CARD_PRESENT ) )
    {
        retVal = true;
    }
    return retVal;
}


/// Uninit function
void LPC3Reg::UninitializeWDT( void )
{
    // Enable all WDT register and clock
    LPC3Reg::TimClkCtrl_ |= 0x1;
    Timespan::Milliseconds( 10 ).sleepFor();

    //Disable WDT. See Initialize for descriptions
    LPC3Reg::WDTimCtrl_ = 0;
    LPC3Reg::WDTimMCtrl_ = 0;
    LPC3Reg::WDTimEMR_ = 0;
    LPC3Reg::WDTimPulse_ = 0x0;

    // Zero out count and match registers
    LPC3Reg::WDTimMatch0_ = 0;
    LPC3Reg::WDTimCounter_ = 0;

    // Disable WDT registers and clock
    LPC3Reg::TimClkCtrl_ &= 0xFFFFFFFE;
}


/// Ground fault circuit handling
void LPC3Reg::ActivateGF( GFChan channel )
{
    LPC3Reg::PioOutpSetPhys_ = channel;
}


//void LPC3Reg::DeactivateGF( GFChan channel )
void LPC3Reg::DeactivateGF( void )
{
    LPC3Reg::PioOutpClrPhys_ = ( CHAN_A0 | CHAN_A1 | CHAN_A2 | CHAN_A3 | CHAN_B0 | CHAN_B1 | CHAN_B2 | CHAN_B3 | GF_TEST );
}


