<commit_before>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file HwInit.cxx
 * This file represents the hardware initialization for the TI Tiva MCU.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#include <cstdint>
#include <new>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "os/OS.hxx"
#include "TivaDev.hxx"

#include "dcc_control.hxx"
#include "hardware.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static TivaCdc cdc0("/dev/serUSB0", INT_RESOLVE(INT_USB0_, 0));

/** UART 0 serial driver instance */
static TivaUart uart2("/dev/ser0", UART2_BASE, INT_RESOLVE(INT_UART2_, 0));

/** CAN 0 CAN driver instance */
static TivaCan can0("/dev/can0", CAN0_BASE, INT_RESOLVE(INT_CAN0_, 0));

// Bit storing whether our dcc output is enabled or not.
static bool g_dcc_on = false;

extern "C" {
/** Blink LED */
uint32_t blinker_pattern = 0;
static uint32_t rest_pattern = 0;

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void setblink(uint32_t pattern)
{
    resetblink(pattern);
}

#define BLINKER_PORT GPIO_PORTN_BASE
#define BLINKER_PIN GPIO_PIN_1

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    MAP_GPIOPinWrite(BLINKER_PORT, BLINKER_PIN,
                     (rest_pattern & 1) ? BLINKER_PIN : 0);
    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern)
{
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

/** Configures a GPIO pin to directly drive a LED (with 8mA output drive). */
void set_gpio_led(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_8MA_SC, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_low(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_high(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a gpio pin for input with external pullup. */
void set_gpio_extinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
}

/** Configures a gpio pin for input with external pullup. */
void set_gpio_puinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
}

void enable_dcc() {
    g_dcc_on = true;
    MAP_GPIOPinWrite(LED_BLUE, 0xff);
    auto port = GPIO_PORTA_BASE;
    auto pin = GPIO_PIN_2 | GPIO_PIN_3;
    MAP_GPIOPinTypeTimer(port, pin);
    MAP_GPIOPinConfigure(GPIO_PA2_T1CCP0);
    MAP_GPIOPinConfigure(GPIO_PA3_T1CCP1);
    //MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
}

void disable_dcc() {
    // Take A2/A3 and set them to drive high. This will turn off the gate
    // driver.
    set_gpio_drive_high(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    g_dcc_on = false;
    MAP_GPIOPinWrite(LED_BLUE, 0);
}

bool query_dcc() {
  return g_dcc_on;
}

/** Initialize the processor hardware.
 */
void hw_preinit(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    /* First we take care of the important pins that control the power
     * transistors */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);

    // Q2/Q3 are wired together with A2-A3 on the timer output pins. Let's turn
    // them into high-impedance mode and turn off pullups.
    MAP_GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    // Disables any pullup/down.
    MAP_GPIOPadConfigSet(GPIO_PORTQ_BASE, GPIO_PIN_2 | GPIO_PIN_3,
                         GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    disable_dcc();

    // A4 controls the accessory bus, active high.
    set_gpio_drive_low(GPIO_PORTA_BASE, GPIO_PIN_4);

    /* Setup the system clock. */
    MAP_SysCtlClockFreqSet(SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL |
                           SYSCTL_OSC_MAIN | SYSCTL_CFG_VCO_480,
                           120000000);

    // USB pins initialization.
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);

    HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTD_BASE + GPIO_O_CR) = 0xff;
    MAP_GPIOPinConfigure(GPIO_PD6_USB0EPEN);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    MAP_GPIOPinTypeUSBDigital(GPIO_PORTD_BASE, GPIO_PIN_6);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6 | GPIO_PIN_7);
    MAP_GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_4);
    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority

    /* blinker LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1);
    MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, configCPU_CLOCK_HZ / 8);
    MAP_IntEnable(INT_TIMER5A);

    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* UART0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_GPIOPinConfigure(GPIO_PD4_U2RX);
    MAP_GPIOPinConfigure(GPIO_PD5_U2TX);
    MAP_GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /* CAN pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_GPIOPinConfigure(GPIO_PA0_CAN0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_CAN0TX);
    MAP_GPIOPinTypeCAN(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* USB0 pin initialization */
    //MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
    //MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6 | GPIO_PIN_7);
    /* USB interrupt priority */

    /* Boosterpack LEDs */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    set_gpio_led(LED_RED);  // red
    set_gpio_led(LED_YELLOW);  // yellow
    // hardware bug set_gpio_led(GPIO_PORTP_BASE, GPIO_PIN_4);  // green
    set_gpio_extinput(LED_GREEN);  // green
    set_gpio_led(LED_BLUE);  // blue

    set_gpio_led(LED_B1);  // onboard 1
    set_gpio_led(LED_B2);  // onboard 2
    set_gpio_led(LED_B3);  // onboard 3
    set_gpio_led(LED_B4);  // onboard 4

    /* Timer hardware for DCC signal generation */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    /* Temporary enable Irq for blinking. */
    asm("cpsie i\n");

    blinker_pattern = 0x80002;
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
    set_gpio_puinput(GPIO_PORTJ_BASE, GPIO_PIN_0);
    volatile uint8_t* mem = (uint8_t*)(GPIO_PORTJ_BASE + ((GPIO_PIN_0)<<2));
    uint32_t counter = configCPU_CLOCK_HZ / 3;
    while (*mem && --counter);

    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");
}

}  // extern C
<commit_msg>Switches the output of timerb of packet generation to the boosterpack 1.<commit_after>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file HwInit.cxx
 * This file represents the hardware initialization for the TI Tiva MCU.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#include <cstdint>
#include <new>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "os/OS.hxx"
#include "TivaDev.hxx"

#include "dcc_control.hxx"
#include "hardware.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static TivaCdc cdc0("/dev/serUSB0", INT_RESOLVE(INT_USB0_, 0));

/** UART 0 serial driver instance */
static TivaUart uart2("/dev/ser0", UART2_BASE, INT_RESOLVE(INT_UART2_, 0));

/** CAN 0 CAN driver instance */
static TivaCan can0("/dev/can0", CAN0_BASE, INT_RESOLVE(INT_CAN0_, 0));

// Bit storing whether our dcc output is enabled or not.
static bool g_dcc_on = false;

extern "C" {
/** Blink LED */
uint32_t blinker_pattern = 0;
static uint32_t rest_pattern = 0;

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void setblink(uint32_t pattern)
{
    resetblink(pattern);
}

#define BLINKER_PORT GPIO_PORTN_BASE
#define BLINKER_PIN GPIO_PIN_1

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    MAP_GPIOPinWrite(BLINKER_PORT, BLINKER_PIN,
                     (rest_pattern & 1) ? BLINKER_PIN : 0);
    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern)
{
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

/** Configures a GPIO pin to directly drive a LED (with 8mA output drive). */
void set_gpio_led(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_8MA_SC, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_low(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_high(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a gpio pin for input with external pullup. */
void set_gpio_extinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
}

/** Configures a gpio pin for input with external pullup. */
void set_gpio_puinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
}

void enable_dcc() {
    g_dcc_on = true;
    MAP_GPIOPinWrite(LED_BLUE, 0xff);
    auto port = GPIO_PORTA_BASE;
    auto pin = GPIO_PIN_2 ; //| GPIO_PIN_3;
    MAP_GPIOPinTypeTimer(port, pin);
    MAP_GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_3);
    MAP_GPIOPinConfigure(GPIO_PA2_T1CCP0);
    MAP_GPIOPinConfigure(GPIO_PD3_T1CCP1);
    //MAP_GPIOPinConfigure(GPIO_PA3_T1CCP1);
    //MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
}

void disable_dcc() {
    // Take A2/A3 and set them to drive high. This will turn off the gate
    // driver.
    set_gpio_drive_high(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    set_gpio_drive_low(GPIO_PORTD_BASE, GPIO_PIN_3);
    g_dcc_on = false;
    MAP_GPIOPinWrite(LED_BLUE, 0);
}

bool query_dcc() {
  return g_dcc_on;
}

/** Initialize the processor hardware.
 */
void hw_preinit(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    /* First we take care of the important pins that control the power
     * transistors */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

    // Q2/Q3 are wired together with A2-A3 on the timer output pins. Let's turn
    // them into high-impedance mode and turn off pullups.
    MAP_GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    // Disables any pullup/down.
    MAP_GPIOPadConfigSet(GPIO_PORTQ_BASE, GPIO_PIN_2 | GPIO_PIN_3,
                         GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    disable_dcc();

    // A4 controls the accessory bus, active high.
    set_gpio_drive_low(GPIO_PORTA_BASE, GPIO_PIN_4);

    /* Setup the system clock. */
    MAP_SysCtlClockFreqSet(SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL |
                           SYSCTL_OSC_MAIN | SYSCTL_CFG_VCO_480,
                           120000000);

    // USB pins initialization.
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);

    HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTD_BASE + GPIO_O_CR) = 0xff;
    MAP_GPIOPinConfigure(GPIO_PD6_USB0EPEN);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    MAP_GPIOPinTypeUSBDigital(GPIO_PORTD_BASE, GPIO_PIN_6);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6 | GPIO_PIN_7);
    MAP_GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_4);
    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority

    /* blinker LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1);
    MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, configCPU_CLOCK_HZ / 8);
    MAP_IntEnable(INT_TIMER5A);

    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* UART0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_GPIOPinConfigure(GPIO_PD4_U2RX);
    MAP_GPIOPinConfigure(GPIO_PD5_U2TX);
    MAP_GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /* CAN pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_GPIOPinConfigure(GPIO_PA0_CAN0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_CAN0TX);
    MAP_GPIOPinTypeCAN(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* USB0 pin initialization */
    //MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
    //MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6 | GPIO_PIN_7);
    /* USB interrupt priority */

    /* Boosterpack LEDs */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    set_gpio_led(LED_RED);  // red
    set_gpio_led(LED_YELLOW);  // yellow
    // hardware bug set_gpio_led(GPIO_PORTP_BASE, GPIO_PIN_4);  // green
    set_gpio_extinput(LED_GREEN);  // green
    set_gpio_led(LED_BLUE);  // blue

    set_gpio_led(LED_B1);  // onboard 1
    set_gpio_led(LED_B2);  // onboard 2
    set_gpio_led(LED_B3);  // onboard 3
    set_gpio_led(LED_B4);  // onboard 4

    /* Timer hardware for DCC signal generation */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    /* Temporary enable Irq for blinking. */
    asm("cpsie i\n");

    blinker_pattern = 0x80002;
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
    set_gpio_puinput(GPIO_PORTJ_BASE, GPIO_PIN_0);
    volatile uint8_t* mem = (uint8_t*)(GPIO_PORTJ_BASE + ((GPIO_PIN_0)<<2));
    uint32_t counter = configCPU_CLOCK_HZ / 3;
    while (*mem && --counter);

    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");
}

}  // extern C
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	IP アドレス・クラス @n
			Copyright 2017 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "common/fixed_string.hpp"
#include "common/format.hpp"
#include "common/input.hpp"

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  ip_adrs クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ip_adrs {

		union adrs_t {
			uint32_t	dw;
			uint8_t		bs[4];  // IPv4 address
			adrs_t(uint32_t v = 0) : dw(v) { }
			adrs_t(const uint8_t* src) {
				if(src == nullptr) {
					dw = 0;
					return;
				}
				bs[0] = src[0];
				bs[1] = src[1];
				bs[2] = src[2];
				bs[3] = src[3];
			}
			adrs_t(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3) {
				bs[0] = v0;
				bs[1] = v1;
				bs[2] = v2;
				bs[3] = v3;
			}
		};

		adrs_t	adrs_;

		static uint32_t ec_(uint32_t src)
		{
			return ((src >> 24) & 0x000000FF) | ((src >> 8 ) & 0x0000FF00)
				 | ((src << 8 ) & 0x00FF0000) | ((src << 24) & 0xFF000000);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
			@param[in]	dw	32bits IP
		*/
		//-----------------------------------------------------------------//
		ip_adrs(uint32_t dw = 0) : adrs_(dw) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
			@param[in]	adr	バイト列（nullptrの場合無効）
		*/
		//-----------------------------------------------------------------//
		ip_adrs(const uint8_t* adr) : adrs_(adr) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
			@param[in]	first	IP 1ST
			@param[in]	second	IP 2ND
			@param[in]	third	IP 3RD
			@param[in]	fourth	IP 4TH
		*/
		//-----------------------------------------------------------------//
		ip_adrs(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) :
			adrs_(first, second, third, fourth) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  設定
			@param[in]	first	IP 1ST
			@param[in]	second	IP 2ND
			@param[in]	third	IP 3RD
			@param[in]	fourth	IP 4TH
		*/
		//-----------------------------------------------------------------//
		void set(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
			adrs_.bs[0] = first;
			adrs_.bs[1] = second;
			adrs_.bs[2] = third;
			adrs_.bs[3] = fourth;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  配列から設定
			@param[in]	address	配列
		*/
		//-----------------------------------------------------------------//
		void set(const uint8_t* adrs) {
			if(adrs == nullptr) {
				adrs_.dw = 0;
				return;
			}
			adrs_.bs[0] = adrs[0];
			adrs_.bs[1] = adrs[1];
			adrs_.bs[2] = adrs[2];
			adrs_.bs[3] = adrs[3];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  バイト列取得
			@return バイト配列
		*/
		//-----------------------------------------------------------------//
		const uint8_t* get() const { return adrs_.bs; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ワード値取得
			@return ワード値
		*/
		//-----------------------------------------------------------------//
		uint32_t getw() const { return adrs_.dw; }

		//-----------------------------------------------------------------//
		/*!
			@brief  0.0.0.0 (Any)アドレスか検査
			@return Any なら「true」
		*/
		//-----------------------------------------------------------------//
		bool is_any() const { return adrs_.dw == 0; }

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列から設定
			@param[in]	address	配列
		*/
		//-----------------------------------------------------------------//
		bool from_string(const char *adrs) {
			if(adrs == nullptr) return false;
			int a, b, c, d;
			auto f = (utils::input("%d.%d.%d.%d", adrs) % a % b % c % d).status();
			if(f) {
				if(a >= 0 && a <= 255) adrs_.bs[0] = a;
				if(a >= 0 && b <= 255) adrs_.bs[1] = b;
				if(a >= 0 && c <= 255) adrs_.bs[2] = c;
				if(a >= 0 && d <= 255) adrs_.bs[3] = d;
			}
			return f;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  型変換キャスト演算子（uint32_t 型）
		*/
		//-----------------------------------------------------------------//
		operator uint32_t() const { return adrs_.dw; };

		//-----------------------------------------------------------------//
		/*!
			@brief  比較（自分と同じ型）
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator==(const ip_adrs& ipa) const {
			return adrs_.dw == ipa.adrs_.dw;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  比較（自分と同じ型）
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator == (const uint8_t* addr) const {
			if(addr == nullptr) return false;
			return (adrs_.bs[0] == addr[0]
				 && adrs_.bs[1] == addr[1]
				 && adrs_.bs[2] == addr[2]
				 && adrs_.bs[3] == addr[3]);
		}

		uint8_t operator [] (int index) const { return adrs_.bs[index]; };

		uint8_t& operator [] (int index) { return adrs_.bs[index]; };

		ip_adrs& operator = (const uint8_t* adrs) {
			adrs_.bs[0] = adrs[0];
			adrs_.bs[1] = adrs[1];
			adrs_.bs[2] = adrs[2];
			adrs_.bs[3] = adrs[3];
			return *this;
		}

		ip_adrs& operator = (uint32_t adrs) {
			adrs_.dw = adrs;
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列で取得
			@param[in]	spch	分離キャラクター（通常「.」）
			@return 文字列
		*/
		//-----------------------------------------------------------------//
		const char* c_str(char spch = '.') const {
			static char tmp[4*4+1];
			utils::sformat("%d%c%d%c%d%c%d", tmp, sizeof(tmp))
				% static_cast<int>(adrs_.bs[0]) % spch
				% static_cast<int>(adrs_.bs[1]) % spch
				% static_cast<int>(adrs_.bs[2]) % spch
				% static_cast<int>(adrs_.bs[3]);
			return tmp;
		}
	};
}

<commit_msg>remove a file<commit_after><|endoftext|>


<commit_before>#pragma once

#include <cstdint>
#include <functional>
#include <optional>
#include <unordered_map>

#include "utils/Concepts.hpp"

namespace utils::containers {

template <NumericIntegral TValue>
class DisjointSet {
public:
  using ValueType = TValue;

  [[nodiscard]] int64_t size() const noexcept {
    return static_cast<int64_t>(m_parents.size());
  }

  bool add(const ValueType value) {
    if (m_parents.contains(value)) {
      return false;
    }
    m_parents.emplace(value, value);
    return true;
  }

  std::optional<ValueType> find(const ValueType value) {
    if (auto it = m_parents.find(value); it != m_parents.end()) {
      return this->findParent(it)->first;
    }
    return std::nullopt;
  }

  bool merge(const ValueType lhs, const ValueType rhs) {
    auto lhsIts = m_parents.find(lhs);
    if (lhsIts == m_parents.end()) {
      return false;
    }
    auto rhsIts = m_parents.find(rhs);
    if (rhsIts == m_parents.end()) {
      return false;
    }
    if (lhsIts->second == rhsIts->second) {
      return false;
    }

    auto lhsParent = this->findParent(lhsIts);
    auto rhsParent = this->findParent(rhsIts);
    if (lhsParent == rhsParent) {
      return false;
    }

    if (lhsParent->first < rhsParent->first) {
      rhsParent->second = lhsParent->first;
    } else {
      lhsParent->second = rhsParent->first;
    }
    return true;
  }

private:
  using NodeIterator = typename std::unordered_map<ValueType, ValueType>::iterator;
  [[nodiscard]] NodeIterator findParent(NodeIterator it) {

    std::vector<NodeIterator> visitedNodesIts;

    while (it->first != it->second) {
      visitedNodesIts.push_back(it);
      it = m_parents.find(it->second);
    }

    for (auto &visitedNodeIt: visitedNodesIts) {
      visitedNodeIt->second = it->second;
    }
    return it;
  }
  std::unordered_map<ValueType, ValueType> m_parents;
};
} // namespace utils::containers
<commit_msg>Make hashmap easily replacable in DisjointSet<commit_after>#pragma once

#include <cstdint>
#include <functional>
#include <optional>
#include <unordered_map>

#include "utils/Concepts.hpp"

namespace utils::containers {

template <NumericIntegral TValue>
class DisjointSet {
public:
  using ValueType = TValue;

  [[nodiscard]] int64_t size() const noexcept {
    return static_cast<int64_t>(m_parents.size());
  }

  bool add(const ValueType value) {
    if (m_parents.contains(value)) {
      return false;
    }
    m_parents.emplace(value, value);
    return true;
  }

  std::optional<ValueType> find(const ValueType value) {
    if (auto it = m_parents.find(value); it != m_parents.end()) {
      return this->findParent(it)->first;
    }
    return std::nullopt;
  }

  bool merge(const ValueType lhs, const ValueType rhs) {
    auto lhsIts = m_parents.find(lhs);
    if (lhsIts == m_parents.end()) {
      return false;
    }
    auto rhsIts = m_parents.find(rhs);
    if (rhsIts == m_parents.end()) {
      return false;
    }
    if (lhsIts->second == rhsIts->second) {
      return false;
    }

    auto lhsParent = this->findParent(lhsIts);
    auto rhsParent = this->findParent(rhsIts);
    if (lhsParent == rhsParent) {
      return false;
    }

    if (lhsParent->first < rhsParent->first) {
      rhsParent->second = lhsParent->first;
    } else {
      lhsParent->second = rhsParent->first;
    }
    return true;
  }

private:
  using HashMap = std::unordered_map<ValueType, ValueType>;
  using NodeIterator = typename HashMap::iterator;
  [[nodiscard]] NodeIterator findParent(NodeIterator it) {

    std::vector<NodeIterator> visitedNodesIts;

    while (it->first != it->second) {
      visitedNodesIts.push_back(it);
      it = m_parents.find(it->second);
    }

    for (auto &visitedNodeIt: visitedNodesIts) {
      visitedNodeIt->second = it->second;
    }
    return it;
  }
  HashMap m_parents;
};
} // namespace utils::containers
<|endoftext|>


<commit_before>#include <string.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <time.h>

#include "SuMo.h"
#include "Timer.h"

/* specific to file */
const int NUM_ARGS = 4;
const char* filename = "logData";
const char* description = "log data from DAQ";
using namespace std;
/********************/

/* subtract pedestal values on-line */
static bool PED_SUBTRCT = false;

static int LIMIT_READOUT_RATE  = 6000;  //usecs limit between event polling
static int NUM_SEQ_TIMEOUTS    = 100;    // number of sequential timeouts before ending run
const  float  MAX_INT_TIMER    = 800.;    // max cpu timer before ending run (secs)
/* note: usb timeout defined in include/stdUSB.h */

bool overwriteExistingFile = false;

int main(int argc, char* argv[]){
    if(argc == 2 && std::string(argv[1]) == "-h"){
        cout << endl;
        cout << filename << " :: " << description << endl;
        cout << filename << " :: takes " << NUM_ARGS-1 << " arguments" << endl;
        return 1;
    }
    else if(argc > NUM_ARGS+1 || argc < NUM_ARGS){
        cout << "error: too many number of arguments" << endl;
        return -1;
    }
    else{
        int num_checks = 5;
        int num_events = 100;
        SuMo command;
        char log_data_filename[100];

        strcpy(log_data_filename, argv[1]);
        num_events = atoi(argv[2]);
        int trig_mode = atoi(argv[3]);

        if(command.check_active_boards(num_checks))
        return 1;

        vector<packet_t**> events = command.get_data(num_events, trig_mode, 0);
        command.log_data(log_data_filename, events, trig_mode);

        return 0;
    }
}

vector<packet_t**> SuMo::get_data(unsigned int NUM_READS, int trig_mode, int acq_rate){

    int check_event;
    int asic_baseline[psecSampleCells];
    int count = 0;
    int psec_cnt = 0;
    int last_k;
    float  _now_, t = 0.;
    char logDataFilename[300];
    Timer timer = Timer();
    time_t now;
    unsigned short sample;
    int* Meta;

    vector<packet_t**> event_data;

    // read all front end cards
    bool all[numFrontBoards];
    for(int i = 0; i < numFrontBoards; i++) all[i] = true;

    load_ped();

    int number_of_frontend_cards = 0;

    for( int board = 0; board < numFrontBoards; board++){
        if(DC_ACTIVE[board]) number_of_frontend_cards++;

    }

    cout << "--------------------------------------------------------------" << endl;
    cout << "number of front-end boards detected = " << number_of_frontend_cards
    << " of " << numFrontBoards << " address slots in system" << endl;
    cout << "Trying for " << NUM_READS << " events logged to disk, in a timeout window of "
    << MAX_INT_TIMER << " seconds" << endl;
    cout << "--------------------------------------------------------------" << endl << endl;

    usleep(100000);

    /* cpu time zero */
    timer.start();

    bool reset_event = true;

    // set read mode to NULL
    set_usb_read_mode(0);
    if(mode==USB2x) set_usb_read_mode_slaveDevice(0);
    system_card_trig_valid(false);
    if(mode==USB2x) system_slave_card_trig_valid(false);

    //check system trigger number
    read_CC(false, false, 100);
    int board_trigger= CC_EVENT_COUNT_FROMCC0;
    int last_board_trigger = board_trigger;

    for(int k=0; k<NUM_READS; k++){
        set_usb_read_mode(0);
        if(mode==USB2x) set_usb_read_mode_slaveDevice(0);

        time(&now);
        t = timer.stop();
        // interrupt if past specified logging time
        if(t > MAX_INT_TIMER) {
            cout << endl << "readout timed out at " << t << "on event " << k << endl;
            break;
        }

        // trig_mode = 1 is external source or PSEC4 self trigger
        // trig_mode = 0 is over software (USB), i.e. calibration logging
        if(trig_mode == 0){
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);

            // 'rate-only' mode, only pull data every second
            if(trig_mode == 2) usleep(3e6);

            prep_sync();
            if(mode == USB2x) software_trigger_slaveDevice((unsigned int)15);
            software_trigger((unsigned int) 15);
            make_sync();

            //acq rate limit
            usleep(LIMIT_READOUT_RATE); // somewhat arbitrary hard-coded rate limitation
            //system_card_trig_valid(false);
            //if(mode == USB2x) system_slave_card_trig_valid(false);
        }
        else{
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);
            usleep(100);
            for(int iii=0; iii<2; iii++){
                system_card_trig_valid(false);
                if(mode==USB2x) system_slave_card_trig_valid(false);
            }

            //send in trig 'valid' signal
            sys_wait(100);
            prep_sync();
            if(mode==USB2x) system_slave_card_trig_valid(true);
            system_card_trig_valid(true);
            make_sync();
            //}
            //acq rate limit
            usleep(acq_rate+LIMIT_READOUT_RATE);
        }
        int num_pulls = 0;
        int evts = 0;
        int digs = 0;
        while(board_trigger==last_board_trigger && t < MAX_INT_TIMER){

            read_CC(false, false, 100);
            board_trigger = CC_EVENT_COUNT_FROMCC0;
            cout << "waiting for trigger...     on system event: "
            << board_trigger << " & readout attempt " << k
            << " @time " << t << "                        \r";
            cout.flush();
            usleep(1000);
            t = timer.stop();
            num_pulls++;
            if(num_pulls > 100) break;
            //if(num_pulls > 10)  break;   //use this is board trigger does not iterate
        }

        last_board_trigger = board_trigger;
        if(mode == USB2x) system_slave_card_trig_valid(false);
        system_card_trig_valid(false);
        //set_usb_read_mode_slaveDevice(0), set_usb_read_mode(0);
        evts = read_CC(false, false, 0);
        for(int chkdig=0; chkdig<numFrontBoards; chkdig++)
        digs+=DIGITIZING_START_FLAG[chkdig];

        //if(evts == 0){
        //reset_event = true;
        //k = k-1;
        //continue;
        //}
        //condition for dumping event and trying again.
        //else if( DIGITIZING_START_FLAG[2] == 0 || evts < 6 || evts != digs){
        if( evts == 0 || evts != digs){
            print_to_terminal(k, NUM_READS,CC_EVENT_COUNT_FROMCC0, board_trigger, t);
            cout << "    --NULL--       " << endl;
            //cout.flush();
            reset_event = true;
            k = k-1;             //repeat event
            continue;
        }

        // show event number at terminal
        else{
            if((k+1) % 1 == 0 || k==0){
                print_to_terminal(k, NUM_READS, CC_EVENT_COUNT_FROMCC0, board_trigger, t);
                cout << "          \r";
                cout.flush();
            }
        }
        /**************************************/
        //Do bulk read on all front-end cards
        int numBoards = read_AC(1, all, false);
        /**************************************/
        sys_wait(10000);

        for(int jj=0; jj<2; jj++){
            //prep_sync();
            //turn off 'trig valid flag' until checking if data in buffer
            if(mode == USB2x) system_slave_card_trig_valid(false);
            system_card_trig_valid(false);
            if(mode == USB2x) set_usb_read_mode_slaveDevice(0);
            set_usb_read_mode(0);
        }
        reset_event = true; //have event, go ahead and reset for next event

        // form data for filesave
        for(int targetAC = 0; targetAC < numFrontBoards; targetAC++){
            if(BOARDS_READOUT[targetAC] && numBoards > 0){
                psec_cnt = 0;
                // assign meta data
                Meta=get_AC_info(false, targetAC, false,k, t, t, evts);

                check_event = 0;

                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = adcDat[targetAC]->AC_RAW_DATA[psec_cnt][i%6*256+j];
                        if(PED_SUBTRCT) sample -= PED_DATA[targetAC][i][j];

                        adcDat[targetAC]->Data[i][j] = (unsigned int) sample;
                    }
                }
                /* wraparound_correction, if desired: */
                int baseline[psecSampleCells];
                unwrap_baseline(baseline, 2);
                for (int j = 0; j < psecSampleCells; j++){
                    asic_baseline[j] = baseline[j];
                    adcDat[targetAC]->Data[AC_CHANNELS][j] = Meta[j];
                }
            }
            //if timeout on only some, but not all boards
            else if( numBoards > 0 && BOARDS_TIMEOUT[targetAC] && DC_ACTIVE[targetAC]){
                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = 0xFF;
                        adcDat[targetAC]->Data[i][j] = sample;
                    }
                }
                for(int j = 0; j < psecSampleCells; j++){
                    adcDat[targetAC]->Data[AC_CHANNELS][j] =0;
                }
            }
        }
        event_data.push_back(adcDat);

        last_k = k;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " << t << " sec" << endl;

    cleanup();

    dump_data();

    return event_data;
}

int SuMo::log_data(const char* log_filename, vector<packet_t**> event_data, int trig_mode){
    int asic_baseline[psecSampleCells];
    float  _now_, t = 0.;
    Timer timer = Timer();
    time_t now;
    int last_k;
    char logDataFilename[300];
    // 'scalar' mode
    ofstream rate_fs;
    if(trig_mode == 2){
        char logRateFilename[300];
        sprintf(logRateFilename, "%s.acdc.rate", log_filename);
        rate_fs.open(logRateFilename, ios::trunc);
    }

    // full waveform, standard mode
    time(&now);
    char timestring[100];
    strftime(timestring, 80, "%Y-%m-%d-%H-%M", localtime(&now));
    // sprintf(logDataFilename, "%s-%s.acdc.dat", timestring, log_filename);
    sprintf(logDataFilename, "%s.acdc.dat", log_filename);

    // check if file exists, inquire whether to overwrite
    // shouldn't be an issue now since file timestamped in filename ^^
    string temp;
    while(fileExists(logDataFilename)){
        cout << "file already exists, try new filename: (or enter to overwrite / ctrl-C to quit): ";
        getline(cin, temp);
        if(temp.empty()) break;
        sprintf(logDataFilename, "%s.acdc.dat", temp.c_str());
    }

    ofstream ofs;
    ofs.open(logDataFilename, ios::trunc);

    // save pedestal data to file header for reference, easy access
    // zero pad to match data format

    /* wraparound_correction, if desired: */
    int baseline[psecSampleCells];
    unwrap_baseline(baseline, 2);
    for (int j = 0; j < psecSampleCells; j++){
        asic_baseline[j] = baseline[j];
    }

    /* Create header */
    char delim = ' ';
    ofs << "Event" << delim << "Board" << delim << "Sample";
    for(int c=1; c <= AC_CHANNELS; c++){
        ofs << delim << "Ch" << c;
    }

    /* Record events */
    // For each event
    for(int k = 0; k < event_data.size(); k++){
        packet_t** events = event_data[k];

        for(int i=0; i < psecSampleCells; i++){
            for(int board=0; board<numFrontBoards; board++){
                // Get the event vector for the given board
                for(int channel=0; channel < AC_CHANNELS; channel++){
                    if (DC_ACTIVE[board]){
                            ofs << k << delim << board << delim << i;
                            int ped_subtracted =  events[board]->Data[channel][i] - PED_DATA[board][channel][i];
                            // DEBUG
                            std::cout << ped_subtracted;
                            ofs << delim << std::dec << ped_subtracted;

                    }
                }
            }
            ofs <<endl;
        }

        if(trig_mode == 2){
            for(int board=0; board<numFrontBoards; board++){
                // Get the event vector for the given board
                if (DC_ACTIVE[board]){
                    if(BOARDS_READOUT[board]){

                        rate_fs << k << "\t" << board << "\t" << t << "\t";

                        for(int channel=0; channel < AC_CHANNELS; channel++)  rate_fs <<  events[board]->self_trig_scalar[channel] << "\t";

                        rate_fs << endl;
                    }
                }
            }
        }
        last_k = k;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " <<t<< " sec" << endl;

    cleanup();

    ofs.close();

    if(trig_mode == 2) rate_fs.close();

    cout << "Data saved in file: " << logDataFilename << endl << "*****" << endl;

    return 0;
}

void SuMo::print_to_terminal(int k, int NUM_READS, int cc_event, int board_trig, double t){
    cout << "Readout:  " << k+1 << " of " << NUM_READS;
    cout <<" :: system|sw evt-" << cc_event << "|" << board_trig;
    cout <<" :: evtflags-";
    for(int evt_flag =0; evt_flag< numFrontBoards; evt_flag++) cout << EVENT_FLAG[evt_flag];
    cout << " :: digflags-";
    for(int dig_flag =0; dig_flag< numFrontBoards; dig_flag++) cout << DIGITIZING_START_FLAG[dig_flag];
    cout <<" :: @time "<< t << " sec ";
    //cout.flush();
}
<commit_msg>added missing endl<commit_after>#include <string.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <time.h>

#include "SuMo.h"
#include "Timer.h"

/* specific to file */
const int NUM_ARGS = 4;
const char* filename = "logData";
const char* description = "log data from DAQ";
using namespace std;
/********************/

/* subtract pedestal values on-line */
static bool PED_SUBTRCT = false;

static int LIMIT_READOUT_RATE  = 6000;  //usecs limit between event polling
static int NUM_SEQ_TIMEOUTS    = 100;    // number of sequential timeouts before ending run
const  float  MAX_INT_TIMER    = 800.;    // max cpu timer before ending run (secs)
/* note: usb timeout defined in include/stdUSB.h */

bool overwriteExistingFile = false;

int main(int argc, char* argv[]){
    if(argc == 2 && std::string(argv[1]) == "-h"){
        cout << endl;
        cout << filename << " :: " << description << endl;
        cout << filename << " :: takes " << NUM_ARGS-1 << " arguments" << endl;
        return 1;
    }
    else if(argc > NUM_ARGS+1 || argc < NUM_ARGS){
        cout << "error: too many number of arguments" << endl;
        return -1;
    }
    else{
        int num_checks = 5;
        int num_events = 100;
        SuMo command;
        char log_data_filename[100];

        strcpy(log_data_filename, argv[1]);
        num_events = atoi(argv[2]);
        int trig_mode = atoi(argv[3]);

        if(command.check_active_boards(num_checks))
        return 1;

        vector<packet_t**> events = command.get_data(num_events, trig_mode, 0);
        command.log_data(log_data_filename, events, trig_mode);

        return 0;
    }
}

vector<packet_t**> SuMo::get_data(unsigned int NUM_READS, int trig_mode, int acq_rate){

    int check_event;
    int asic_baseline[psecSampleCells];
    int count = 0;
    int psec_cnt = 0;
    int last_k;
    float  _now_, t = 0.;
    char logDataFilename[300];
    Timer timer = Timer();
    time_t now;
    unsigned short sample;
    int* Meta;

    vector<packet_t**> event_data;

    // read all front end cards
    bool all[numFrontBoards];
    for(int i = 0; i < numFrontBoards; i++) all[i] = true;

    load_ped();

    int number_of_frontend_cards = 0;

    for( int board = 0; board < numFrontBoards; board++){
        if(DC_ACTIVE[board]) number_of_frontend_cards++;

    }

    cout << "--------------------------------------------------------------" << endl;
    cout << "number of front-end boards detected = " << number_of_frontend_cards
    << " of " << numFrontBoards << " address slots in system" << endl;
    cout << "Trying for " << NUM_READS << " events logged to disk, in a timeout window of "
    << MAX_INT_TIMER << " seconds" << endl;
    cout << "--------------------------------------------------------------" << endl << endl;

    usleep(100000);

    /* cpu time zero */
    timer.start();

    bool reset_event = true;

    // set read mode to NULL
    set_usb_read_mode(0);
    if(mode==USB2x) set_usb_read_mode_slaveDevice(0);
    system_card_trig_valid(false);
    if(mode==USB2x) system_slave_card_trig_valid(false);

    //check system trigger number
    read_CC(false, false, 100);
    int board_trigger= CC_EVENT_COUNT_FROMCC0;
    int last_board_trigger = board_trigger;

    for(int k=0; k<NUM_READS; k++){
        set_usb_read_mode(0);
        if(mode==USB2x) set_usb_read_mode_slaveDevice(0);

        time(&now);
        t = timer.stop();
        // interrupt if past specified logging time
        if(t > MAX_INT_TIMER) {
            cout << endl << "readout timed out at " << t << "on event " << k << endl;
            break;
        }

        // trig_mode = 1 is external source or PSEC4 self trigger
        // trig_mode = 0 is over software (USB), i.e. calibration logging
        if(trig_mode == 0){
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);

            // 'rate-only' mode, only pull data every second
            if(trig_mode == 2) usleep(3e6);

            prep_sync();
            if(mode == USB2x) software_trigger_slaveDevice((unsigned int)15);
            software_trigger((unsigned int) 15);
            make_sync();

            //acq rate limit
            usleep(LIMIT_READOUT_RATE); // somewhat arbitrary hard-coded rate limitation
            //system_card_trig_valid(false);
            //if(mode == USB2x) system_slave_card_trig_valid(false);
        }
        else{
            manage_cc_fifo(1);
            if(mode==USB2x) manage_cc_fifo_slaveDevice(1);
            usleep(100);
            for(int iii=0; iii<2; iii++){
                system_card_trig_valid(false);
                if(mode==USB2x) system_slave_card_trig_valid(false);
            }

            //send in trig 'valid' signal
            sys_wait(100);
            prep_sync();
            if(mode==USB2x) system_slave_card_trig_valid(true);
            system_card_trig_valid(true);
            make_sync();
            //}
            //acq rate limit
            usleep(acq_rate+LIMIT_READOUT_RATE);
        }
        int num_pulls = 0;
        int evts = 0;
        int digs = 0;
        while(board_trigger==last_board_trigger && t < MAX_INT_TIMER){

            read_CC(false, false, 100);
            board_trigger = CC_EVENT_COUNT_FROMCC0;
            cout << "waiting for trigger...     on system event: "
            << board_trigger << " & readout attempt " << k
            << " @time " << t << "                        \r";
            cout.flush();
            usleep(1000);
            t = timer.stop();
            num_pulls++;
            if(num_pulls > 100) break;
            //if(num_pulls > 10)  break;   //use this is board trigger does not iterate
        }

        last_board_trigger = board_trigger;
        if(mode == USB2x) system_slave_card_trig_valid(false);
        system_card_trig_valid(false);
        //set_usb_read_mode_slaveDevice(0), set_usb_read_mode(0);
        evts = read_CC(false, false, 0);
        for(int chkdig=0; chkdig<numFrontBoards; chkdig++)
        digs+=DIGITIZING_START_FLAG[chkdig];

        //if(evts == 0){
        //reset_event = true;
        //k = k-1;
        //continue;
        //}
        //condition for dumping event and trying again.
        //else if( DIGITIZING_START_FLAG[2] == 0 || evts < 6 || evts != digs){
        if( evts == 0 || evts != digs){
            print_to_terminal(k, NUM_READS,CC_EVENT_COUNT_FROMCC0, board_trigger, t);
            cout << "    --NULL--       " << endl;
            //cout.flush();
            reset_event = true;
            k = k-1;             //repeat event
            continue;
        }

        // show event number at terminal
        else{
            if((k+1) % 1 == 0 || k==0){
                print_to_terminal(k, NUM_READS, CC_EVENT_COUNT_FROMCC0, board_trigger, t);
                cout << "          \r";
                cout.flush();
            }
        }
        /**************************************/
        //Do bulk read on all front-end cards
        int numBoards = read_AC(1, all, false);
        /**************************************/
        sys_wait(10000);

        for(int jj=0; jj<2; jj++){
            //prep_sync();
            //turn off 'trig valid flag' until checking if data in buffer
            if(mode == USB2x) system_slave_card_trig_valid(false);
            system_card_trig_valid(false);
            if(mode == USB2x) set_usb_read_mode_slaveDevice(0);
            set_usb_read_mode(0);
        }
        reset_event = true; //have event, go ahead and reset for next event

        // form data for filesave
        for(int targetAC = 0; targetAC < numFrontBoards; targetAC++){
            if(BOARDS_READOUT[targetAC] && numBoards > 0){
                psec_cnt = 0;
                // assign meta data
                Meta=get_AC_info(false, targetAC, false,k, t, t, evts);

                check_event = 0;

                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = adcDat[targetAC]->AC_RAW_DATA[psec_cnt][i%6*256+j];
                        if(PED_SUBTRCT) sample -= PED_DATA[targetAC][i][j];

                        adcDat[targetAC]->Data[i][j] = (unsigned int) sample;
                    }
                }
                /* wraparound_correction, if desired: */
                int baseline[psecSampleCells];
                unwrap_baseline(baseline, 2);
                for (int j = 0; j < psecSampleCells; j++){
                    asic_baseline[j] = baseline[j];
                    adcDat[targetAC]->Data[AC_CHANNELS][j] = Meta[j];
                }
            }
            //if timeout on only some, but not all boards
            else if( numBoards > 0 && BOARDS_TIMEOUT[targetAC] && DC_ACTIVE[targetAC]){
                for(int i = 0; i < AC_CHANNELS; i++){
                    if(i>0 && i % 6 == 0) psec_cnt ++;

                    for(int j = 0; j < psecSampleCells; j++){
                        sample = 0xFF;
                        adcDat[targetAC]->Data[i][j] = sample;
                    }
                }
                for(int j = 0; j < psecSampleCells; j++){
                    adcDat[targetAC]->Data[AC_CHANNELS][j] =0;
                }
            }
        }
        event_data.push_back(adcDat);

        last_k = k;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " << t << " sec" << endl;

    cleanup();

    dump_data();

    return event_data;
}

int SuMo::log_data(const char* log_filename, vector<packet_t**> event_data, int trig_mode){
    int asic_baseline[psecSampleCells];
    float  _now_, t = 0.;
    Timer timer = Timer();
    time_t now;
    int last_k;
    char logDataFilename[300];
    // 'scalar' mode
    ofstream rate_fs;
    if(trig_mode == 2){
        char logRateFilename[300];
        sprintf(logRateFilename, "%s.acdc.rate", log_filename);
        rate_fs.open(logRateFilename, ios::trunc);
    }

    // full waveform, standard mode
    time(&now);
    char timestring[100];
    strftime(timestring, 80, "%Y-%m-%d-%H-%M", localtime(&now));
    // sprintf(logDataFilename, "%s-%s.acdc.dat", timestring, log_filename);
    sprintf(logDataFilename, "%s.acdc.dat", log_filename);

    // check if file exists, inquire whether to overwrite
    // shouldn't be an issue now since file timestamped in filename ^^
    string temp;
    while(fileExists(logDataFilename)){
        cout << "file already exists, try new filename: (or enter to overwrite / ctrl-C to quit): ";
        getline(cin, temp);
        if(temp.empty()) break;
        sprintf(logDataFilename, "%s.acdc.dat", temp.c_str());
    }

    ofstream ofs;
    ofs.open(logDataFilename, ios::trunc);

    // save pedestal data to file header for reference, easy access
    // zero pad to match data format

    /* wraparound_correction, if desired: */
    int baseline[psecSampleCells];
    unwrap_baseline(baseline, 2);
    for (int j = 0; j < psecSampleCells; j++){
        asic_baseline[j] = baseline[j];
    }

    /* Create header */
    char delim = ' ';
    ofs << "Event" << delim << "Board" << delim << "Sample";
    for(int c=1; c <= AC_CHANNELS; c++){
        ofs << delim << "Ch" << c;
    }
    ofs << delim << endl;

    /* Record events */
    // For each event
    for(int k = 0; k < event_data.size(); k++){
        packet_t** events = event_data[k];

        for(int i=0; i < psecSampleCells; i++){
            for(int board=0; board<numFrontBoards; board++){
                // Get the event vector for the given board
                ofs << k << delim << board << delim << i;
                for(int channel=0; channel < AC_CHANNELS; channel++){
                    if (DC_ACTIVE[board]){
                            int ped_subtracted =  events[board]->Data[channel][i] - PED_DATA[board][channel][i];
                            ofs << delim << std::dec << ped_subtracted;

                    }
                }
            }
            ofs <<endl;
        }

        if(trig_mode == 2){
            for(int board=0; board<numFrontBoards; board++){
                // Get the event vector for the given board
                if (DC_ACTIVE[board]){
                    if(BOARDS_READOUT[board]){

                        rate_fs << k << "\t" << board << "\t" << t << "\t";

                        for(int channel=0; channel < AC_CHANNELS; channel++)  rate_fs <<  events[board]->self_trig_scalar[channel] << "\t";

                        rate_fs << endl;
                    }
                }
            }
        }
        last_k = k;
    }

    cout << endl;
    cout << "Done on readout:  " << last_k+1 << " :: @time " <<t<< " sec" << endl;

    cleanup();

    ofs.close();

    if(trig_mode == 2) rate_fs.close();

    cout << "Data saved in file: " << logDataFilename << endl << "*****" << endl;

    return 0;
}

void SuMo::print_to_terminal(int k, int NUM_READS, int cc_event, int board_trig, double t){
    cout << "Readout:  " << k+1 << " of " << NUM_READS;
    cout <<" :: system|sw evt-" << cc_event << "|" << board_trig;
    cout <<" :: evtflags-";
    for(int evt_flag =0; evt_flag< numFrontBoards; evt_flag++) cout << EVENT_FLAG[evt_flag];
    cout << " :: digflags-";
    for(int dig_flag =0; dig_flag< numFrontBoards; dig_flag++) cout << DIGITIZING_START_FLAG[dig_flag];
    cout <<" :: @time "<< t << " sec ";
    //cout.flush();
}
<|endoftext|>


<commit_before>// Copyright © 2016-2017, Prosoft Engineering, Inc. (A.K.A "Prosoft")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Prosoft nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PROSOFT ENGINEERING, INC. BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef PS_CORE_FILESYSTEM_ITERATOR_HPP
#define PS_CORE_FILESYSTEM_ITERATOR_HPP

#include <iterator>
#include <memory>
#include <type_traits>

namespace prosoft {
namespace filesystem {
inline namespace v1 {

class file_status;

class directory_entry {
    // C++ states that a name within a scope must have a unique meaning.
    // Therefore path() conflicts with the use of the 'path' type from our namespace and is ambigous.
    // GCC warns about this, clang does not.
    using path_type = prosoft::filesystem::path;
    path_type m_path;

public:
    directory_entry() noexcept(std::is_nothrow_constructible<path_type>::value) : m_path() {}
    ~directory_entry() = default;
    PS_DEFAULT_COPY(directory_entry);
    PS_DEFAULT_MOVE(directory_entry);
    explicit directory_entry(const path_type& p)
        : m_path(p) {}
    // Extensions //
    explicit directory_entry(path_type&& p) noexcept(std::is_nothrow_move_constructible<path_type>::value)
        : m_path(std::move(p)) {}

    void assign(path_type&& p) {
        m_path = std::move(p);
    }
    // Extensions //

    void assign(const path_type& p) {
        m_path = p;
    }

    void replace_filename(const path_type& p) {
        m_path.replace_filename(p);
    }

    operator const path_type&() const noexcept {
        return this->path();
    }

    const path_type& path() const & noexcept {
        return m_path;
    }

    path_type path() && noexcept(std::is_nothrow_move_constructible<path_type>::value) {
        return path_type{std::move(m_path)};
    }

    file_status status() const;
    file_status status(error_code&) const noexcept;

    file_status symlink_status() const;
    file_status symlink_status(error_code&) const noexcept;
};

enum class directory_options : unsigned {
    none,
    follow_directory_symlink,
    skip_permission_denied,

    // Extensions
    include_created_events = 1U<<16, // change_iterator
    include_modified_events = 1U<<17, // change_iterator

    skip_subdirectory_descendants = 1U<<20,
    skip_hidden_descendants = 1U<<21,
    skip_package_descendants = 1U<<22, // macOS
    follow_mountpoints = 1U<<23,
    include_postorder_directories = 1U<<24,
    // By default, we mimic the behavior of NSDirectoryEnumerator and skip "._" files.
    // However, unlike NSDE, we only skip "._" files that have a sibling of the same name. Orphan "._" files are always returned.
    // If for some reason you want paired "._" files too, set this. Normally it should not be set as the system automatically handles pairs.
    include_apple_double_files = 1U<<25, // macOS

    // Internal state
    reserved_state_skip_descendants = 1U<<30,
    reserved_state_postorder = 1U<<31,
    reserved_state_mask = 0xf0000000,
};
PS_ENUM_BITMASK_OPS(directory_options);

constexpr directory_options make_public(directory_options opts) {
    return opts & ~directory_options::reserved_state_mask;
}

using iterator_depth_type = int;

namespace ifilesystem {
class iterator_state {
    path m_root;
    directory_entry m_current;
    directory_options m_opts;

protected:
    virtual path next(error_code&) = 0;

    void set(directory_options opts) noexcept {
        m_opts |= opts & directory_options::reserved_state_mask;
    }

    void clear(directory_options opts) noexcept {
        m_opts &= ~(opts & directory_options::reserved_state_mask);
    }

    bool is_current_empty() const {
        return m_current.path().empty();
    }

public:
    iterator_state() = default;
    iterator_state(const path& p, directory_options opts, error_code&)
        : m_root(p)
        , m_current()
        , m_opts(opts) {}
    virtual ~iterator_state() = default;

    const path& root() const noexcept {
        return m_root;
    }

    const directory_entry& current() const noexcept {
        return m_current;
    }

    directory_options options() const noexcept {
        return m_opts;
    }

    void increment(error_code& ec) {
        m_current = directory_entry{next(ec)};
    }

    virtual bool equal_to(const iterator_state*) const;

    virtual void pop() {}

    virtual iterator_depth_type depth() const noexcept {
        return 0;
    }

    virtual void skip_descendants() {}

    virtual bool at_end() const {
        return is_current_empty();
    }
};

using iterator_state_ptr = std::shared_ptr<ifilesystem::iterator_state>;

struct null_iterator_config {};

struct iterator_traits {
    static constexpr directory_options required = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options not_supported = directory_options::none;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_config;
};

struct recursive_iterator_traits {
    static constexpr directory_options required = directory_options::none;
    static constexpr directory_options not_supported = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_config;
};

template <class Traits>
struct is_recursive {
    static constexpr bool value = is_set(Traits::not_supported & directory_options::skip_subdirectory_descendants);
};

static_assert(!is_recursive<iterator_traits>::value, "WTF?");
static_assert(is_recursive<recursive_iterator_traits>::value, "WTF?");

iterator_state_ptr make_iterator_state(const path&, directory_options, iterator_traits::configuration_type, error_code&, iterator_traits);

inline iterator_state_ptr
make_iterator_state(const path& p, directory_options opts, recursive_iterator_traits::configuration_type, error_code& ec, recursive_iterator_traits) {
    return make_iterator_state(p, opts, iterator_traits::configuration_type{}, ec, iterator_traits{});
}

const error_code& permission_denied_error();

template <class Traits>
inline const error_code& permission_denied_error(Traits) {
    return permission_denied_error();
}

template <class Traits>
constexpr directory_options make_options(directory_options opts) {
    return (make_public(opts) | Traits::required) & ~Traits::not_supported;
}
} // ifilesystem

template <class Traits>
class basic_iterator {
    ifilesystem::iterator_state_ptr m_i;

    const directory_entry& empty_entry() const {
        static const directory_entry empty;
        return empty;
    }

    const path& root_or_empty() const {
        return m_i ? m_i->root() : empty_entry().path();
    }

    void clear_if_denied(error_code& ec) const;

    template <typename Recurse>
    struct resurse_only : public std::enable_if<ifilesystem::is_recursive<Traits>::value, Recurse> {};

    template <typename Recurse>
    using recurse_only_t = typename resurse_only<Recurse>::type;

    friend Traits;
public:
    using traits_type = Traits;
    using configuration_type = typename traits_type::configuration_type;
    using value_type = directory_entry;
    using difference_type = ptrdiff_t;
    using pointer = const value_type*;
    using reference = const value_type&;
    using iterator_category = std::input_iterator_tag;

    basic_iterator() noexcept(std::is_nothrow_constructible<decltype(m_i)>::value) = default;
    explicit basic_iterator(const path&);
    basic_iterator(const path&, error_code&);
    basic_iterator(const path&, directory_options);
    basic_iterator(const path&, directory_options, error_code&);
    basic_iterator(const path&, directory_options, configuration_type&&);
    basic_iterator(const path&, directory_options, configuration_type&&, error_code&);
    basic_iterator(const basic_iterator&) = default;
    basic_iterator(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    ~basic_iterator() = default;

    directory_options options() const;
    const directory_entry& operator*() const;
    const directory_entry* operator->() const;

    basic_iterator& operator=(const basic_iterator&) = default;
    basic_iterator& operator=(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    basic_iterator& operator++();
    basic_iterator& increment(error_code&);

    bool operator==(const basic_iterator&) const;

    // Recursive only
    template <typename Recurse = void>
    iterator_depth_type depth(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? m_i->depth() : iterator_depth_type{};
    }

    template <typename Recurse = void>
    bool recursion_pending(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? !is_set(m_i->options() & directory_options::reserved_state_skip_descendants) : false;
    }

    template <typename Recurse = void>
    void pop(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->pop();
        }
    }

    template <typename Recurse = void>
    void disable_recursion_pending(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->skip_descendants();
        }
    }

    // Extensions
    basic_iterator& operator++(int);

    static constexpr directory_options default_options() {
        return Traits::defaults;
    }
};

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p)
    : basic_iterator<Traits>::basic_iterator(p, default_options()) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, default_options(), ec) {
}

template <class Traits>
basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}, ec) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, configuration_type&& t, error_code& ec)
    : m_i(ifilesystem::make_iterator_state(p, ifilesystem::make_options<Traits>(opts), std::move(t), ec, traits_type{})) {
    increment(ec);
    clear_if_denied(ec);
}

template <class Traits>
const directory_entry& basic_iterator<Traits>::operator*() const {
    return m_i ? m_i->current() : empty_entry();
}

template <class Traits>
inline const directory_entry* basic_iterator<Traits>::operator->() const {
    return &operator*();
}

template <class Traits>
directory_options basic_iterator<Traits>::options() const {
    return m_i ? make_public(m_i->options()) : directory_options::none;
}

template <class Traits>
basic_iterator<Traits>& basic_iterator<Traits>::increment(error_code& ec) {
    if (m_i) {
        m_i->increment(ec);
        if (m_i->at_end()) {
            m_i.reset(); // become end
        }
    }
    return *this;
}

template <class Traits>
bool basic_iterator<Traits>::operator==(const basic_iterator<Traits>& other) const {
    auto ti = m_i.get();
    auto oi = other.m_i.get();
    return ti == oi || (ti && oi && ti->equal_to(oi));
}

template <class Traits>
inline bool operator!=(const basic_iterator<Traits>& lhs, const basic_iterator<Traits>& rhs) {
    return !lhs.operator==(rhs);
}

template <class Traits>
inline basic_iterator<Traits> begin(basic_iterator<Traits> i) {
    return i;
}

template <class Traits>
inline basic_iterator<Traits> end(const basic_iterator<Traits>&) {
    return basic_iterator<Traits>{};
}

template <class Traits>
void basic_iterator<Traits>::clear_if_denied(error_code& ec) const {
    if (is_set(options() & directory_options::skip_permission_denied) && ec == ifilesystem::permission_denied_error(Traits{})) {
        ec.clear();
    }
}

// Extensions
template <class Traits>
inline basic_iterator<Traits>& basic_iterator<Traits>::operator++(int) {
    return operator++(); // // XXX: Input iter one-pass semantics.
}

} // v1
} // filesystem
} // prosoft

#endif // PS_CORE_FILESYSTEM_ITERATOR_HPP
<commit_msg>Add directory_entry.empty()<commit_after>// Copyright © 2016-2017, Prosoft Engineering, Inc. (A.K.A "Prosoft")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Prosoft nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PROSOFT ENGINEERING, INC. BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef PS_CORE_FILESYSTEM_ITERATOR_HPP
#define PS_CORE_FILESYSTEM_ITERATOR_HPP

#include <iterator>
#include <memory>
#include <type_traits>

namespace prosoft {
namespace filesystem {
inline namespace v1 {

class file_status;

class directory_entry {
    // C++ states that a name within a scope must have a unique meaning.
    // Therefore path() conflicts with the use of the 'path' type from our namespace and is ambigous.
    // GCC warns about this, clang does not.
    using path_type = prosoft::filesystem::path;
    path_type m_path;

public:
    directory_entry() noexcept(std::is_nothrow_constructible<path_type>::value) : m_path() {}
    ~directory_entry() = default;
    PS_DEFAULT_COPY(directory_entry);
    PS_DEFAULT_MOVE(directory_entry);
    explicit directory_entry(const path_type& p)
        : m_path(p) {}
    // Extensions //
    explicit directory_entry(path_type&& p) noexcept(std::is_nothrow_move_constructible<path_type>::value)
        : m_path(std::move(p)) {}

    void assign(path_type&& p) {
        m_path = std::move(p);
    }

    bool empty() const noexcept(noexcept(std::declval<path_type>().empty())) {
        return m_path.empty();
    }
    // Extensions //

    void assign(const path_type& p) {
        m_path = p;
    }

    void replace_filename(const path_type& p) {
        m_path.replace_filename(p);
    }

    operator const path_type&() const noexcept {
        return this->path();
    }

    const path_type& path() const & noexcept {
        return m_path;
    }

    path_type path() && noexcept(std::is_nothrow_move_constructible<path_type>::value) {
        return path_type{std::move(m_path)};
    }

    file_status status() const;
    file_status status(error_code&) const noexcept;

    file_status symlink_status() const;
    file_status symlink_status(error_code&) const noexcept;
};

enum class directory_options : unsigned {
    none,
    follow_directory_symlink,
    skip_permission_denied,

    // Extensions
    include_created_events = 1U<<16, // change_iterator
    include_modified_events = 1U<<17, // change_iterator

    skip_subdirectory_descendants = 1U<<20,
    skip_hidden_descendants = 1U<<21,
    skip_package_descendants = 1U<<22, // macOS
    follow_mountpoints = 1U<<23,
    include_postorder_directories = 1U<<24,
    // By default, we mimic the behavior of NSDirectoryEnumerator and skip "._" files.
    // However, unlike NSDE, we only skip "._" files that have a sibling of the same name. Orphan "._" files are always returned.
    // If for some reason you want paired "._" files too, set this. Normally it should not be set as the system automatically handles pairs.
    include_apple_double_files = 1U<<25, // macOS

    // Internal state
    reserved_state_skip_descendants = 1U<<30,
    reserved_state_postorder = 1U<<31,
    reserved_state_mask = 0xf0000000,
};
PS_ENUM_BITMASK_OPS(directory_options);

constexpr directory_options make_public(directory_options opts) {
    return opts & ~directory_options::reserved_state_mask;
}

using iterator_depth_type = int;

namespace ifilesystem {
class iterator_state {
    path m_root;
    directory_entry m_current;
    directory_options m_opts;

protected:
    virtual path next(error_code&) = 0;

    void set(directory_options opts) noexcept {
        m_opts |= opts & directory_options::reserved_state_mask;
    }

    void clear(directory_options opts) noexcept {
        m_opts &= ~(opts & directory_options::reserved_state_mask);
    }

    bool is_current_empty() const {
        return m_current.path().empty();
    }

public:
    iterator_state() = default;
    iterator_state(const path& p, directory_options opts, error_code&)
        : m_root(p)
        , m_current()
        , m_opts(opts) {}
    virtual ~iterator_state() = default;

    const path& root() const noexcept {
        return m_root;
    }

    const directory_entry& current() const noexcept {
        return m_current;
    }

    directory_options options() const noexcept {
        return m_opts;
    }

    void increment(error_code& ec) {
        m_current = directory_entry{next(ec)};
    }

    virtual bool equal_to(const iterator_state*) const;

    virtual void pop() {}

    virtual iterator_depth_type depth() const noexcept {
        return 0;
    }

    virtual void skip_descendants() {}

    virtual bool at_end() const {
        return is_current_empty();
    }
};

using iterator_state_ptr = std::shared_ptr<ifilesystem::iterator_state>;

struct null_iterator_config {};

struct iterator_traits {
    static constexpr directory_options required = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options not_supported = directory_options::none;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_config;
};

struct recursive_iterator_traits {
    static constexpr directory_options required = directory_options::none;
    static constexpr directory_options not_supported = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_config;
};

template <class Traits>
struct is_recursive {
    static constexpr bool value = is_set(Traits::not_supported & directory_options::skip_subdirectory_descendants);
};

static_assert(!is_recursive<iterator_traits>::value, "WTF?");
static_assert(is_recursive<recursive_iterator_traits>::value, "WTF?");

iterator_state_ptr make_iterator_state(const path&, directory_options, iterator_traits::configuration_type, error_code&, iterator_traits);

inline iterator_state_ptr
make_iterator_state(const path& p, directory_options opts, recursive_iterator_traits::configuration_type, error_code& ec, recursive_iterator_traits) {
    return make_iterator_state(p, opts, iterator_traits::configuration_type{}, ec, iterator_traits{});
}

const error_code& permission_denied_error();

template <class Traits>
inline const error_code& permission_denied_error(Traits) {
    return permission_denied_error();
}

template <class Traits>
constexpr directory_options make_options(directory_options opts) {
    return (make_public(opts) | Traits::required) & ~Traits::not_supported;
}
} // ifilesystem

template <class Traits>
class basic_iterator {
    ifilesystem::iterator_state_ptr m_i;

    const directory_entry& empty_entry() const {
        static const directory_entry empty;
        return empty;
    }

    const path& root_or_empty() const {
        return m_i ? m_i->root() : empty_entry().path();
    }

    void clear_if_denied(error_code& ec) const;

    template <typename Recurse>
    struct resurse_only : public std::enable_if<ifilesystem::is_recursive<Traits>::value, Recurse> {};

    template <typename Recurse>
    using recurse_only_t = typename resurse_only<Recurse>::type;

    friend Traits;
public:
    using traits_type = Traits;
    using configuration_type = typename traits_type::configuration_type;
    using value_type = directory_entry;
    using difference_type = ptrdiff_t;
    using pointer = const value_type*;
    using reference = const value_type&;
    using iterator_category = std::input_iterator_tag;

    basic_iterator() noexcept(std::is_nothrow_constructible<decltype(m_i)>::value) = default;
    explicit basic_iterator(const path&);
    basic_iterator(const path&, error_code&);
    basic_iterator(const path&, directory_options);
    basic_iterator(const path&, directory_options, error_code&);
    basic_iterator(const path&, directory_options, configuration_type&&);
    basic_iterator(const path&, directory_options, configuration_type&&, error_code&);
    basic_iterator(const basic_iterator&) = default;
    basic_iterator(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    ~basic_iterator() = default;

    directory_options options() const;
    const directory_entry& operator*() const;
    const directory_entry* operator->() const;

    basic_iterator& operator=(const basic_iterator&) = default;
    basic_iterator& operator=(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    basic_iterator& operator++();
    basic_iterator& increment(error_code&);

    bool operator==(const basic_iterator&) const;

    // Recursive only
    template <typename Recurse = void>
    iterator_depth_type depth(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? m_i->depth() : iterator_depth_type{};
    }

    template <typename Recurse = void>
    bool recursion_pending(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? !is_set(m_i->options() & directory_options::reserved_state_skip_descendants) : false;
    }

    template <typename Recurse = void>
    void pop(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->pop();
        }
    }

    template <typename Recurse = void>
    void disable_recursion_pending(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->skip_descendants();
        }
    }

    // Extensions
    basic_iterator& operator++(int);

    static constexpr directory_options default_options() {
        return Traits::defaults;
    }
};

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p)
    : basic_iterator<Traits>::basic_iterator(p, default_options()) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, default_options(), ec) {
}

template <class Traits>
basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}, ec) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, configuration_type&& t, error_code& ec)
    : m_i(ifilesystem::make_iterator_state(p, ifilesystem::make_options<Traits>(opts), std::move(t), ec, traits_type{})) {
    increment(ec);
    clear_if_denied(ec);
}

template <class Traits>
const directory_entry& basic_iterator<Traits>::operator*() const {
    return m_i ? m_i->current() : empty_entry();
}

template <class Traits>
inline const directory_entry* basic_iterator<Traits>::operator->() const {
    return &operator*();
}

template <class Traits>
directory_options basic_iterator<Traits>::options() const {
    return m_i ? make_public(m_i->options()) : directory_options::none;
}

template <class Traits>
basic_iterator<Traits>& basic_iterator<Traits>::increment(error_code& ec) {
    if (m_i) {
        m_i->increment(ec);
        if (m_i->at_end()) {
            m_i.reset(); // become end
        }
    }
    return *this;
}

template <class Traits>
bool basic_iterator<Traits>::operator==(const basic_iterator<Traits>& other) const {
    auto ti = m_i.get();
    auto oi = other.m_i.get();
    return ti == oi || (ti && oi && ti->equal_to(oi));
}

template <class Traits>
inline bool operator!=(const basic_iterator<Traits>& lhs, const basic_iterator<Traits>& rhs) {
    return !lhs.operator==(rhs);
}

template <class Traits>
inline basic_iterator<Traits> begin(basic_iterator<Traits> i) {
    return i;
}

template <class Traits>
inline basic_iterator<Traits> end(const basic_iterator<Traits>&) {
    return basic_iterator<Traits>{};
}

template <class Traits>
void basic_iterator<Traits>::clear_if_denied(error_code& ec) const {
    if (is_set(options() & directory_options::skip_permission_denied) && ec == ifilesystem::permission_denied_error(Traits{})) {
        ec.clear();
    }
}

// Extensions
template <class Traits>
inline basic_iterator<Traits>& basic_iterator<Traits>::operator++(int) {
    return operator++(); // // XXX: Input iter one-pass semantics.
}

} // v1
} // filesystem
} // prosoft

#endif // PS_CORE_FILESYSTEM_ITERATOR_HPP
<|endoftext|>