shithub: heymac-node

ref: ad1df2d2a01bd064e643287ff305673dfede3ce3
dir: /src/bsp.c/

View raw version
/*============================================================================
* QP/C Real-Time Embedded Framework (RTEF)
* Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
*
* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
*
* This software is dual-licensed under the terms of the open source GNU
* General Public License version 3 (or any later version), or alternatively,
* under the terms of one of the closed source Quantum Leaps commercial
* licenses.
*
* The terms of the open source GNU General Public License version 3
* can be found at: <www.gnu.org/licenses/gpl-3.0>
*
* The terms of the closed source Quantum Leaps commercial licenses
* can be found at: <www.state-machine.com/licensing>
*
* Redistributions in source code must retain this top-level comment block.
* Plagiarizing this software to sidestep the license obligations is illegal.
*
* Contact information:
* <www.state-machine.com>
* <[email protected]>
============================================================================*/
/*!
* @date Last updated on: 2022-08-24
* @version Last updated for: Zephyr 3.1.99 and @ref qpc_7_1_0
*
* @file
* @brief BSP for Zephyr, DPP example
*/
#include "qpc.h"
#include "dpp.h"
#include "bsp.h"

#include <zephyr/device.h>
#include <zephyr/drivers/display.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/display/cfb.h>
#include <zephyr/sys/reboot.h>
#include <zephyr/drivers/lora.h>
#include <zephyr/logging/log.h>

/* other drivers, if necessary ... */

Q_DEFINE_THIS_FILE

LOG_MODULE_REGISTER(bsp);

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)

static const struct device *const display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
static const struct device *const lora_dev = DEVICE_DT_GET(DT_NODELABEL(lora0));

/* Local-scope objects -----------------------------------------------------*/
static struct gpio_dt_spec const l_led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static struct k_timer QF_tick_timer;
static uint32_t l_rnd; /* random seed */

#ifdef Q_SPY

    /* QSpy source IDs */
    static QSpyId const timerID = { 0U };

    enum AppRecords { /* application-specific trace records */
        PHILO_STAT = QS_USER,
        PAUSED_STAT,
        COMMAND_STAT,
        TEST_MSG
    };

#endif

int conf_radio(const struct device *dev, bool transmit)
{
        int ret;
        struct lora_modem_config config;

        config.frequency = 903080000;
        config.bandwidth = BW_125_KHZ;
        config.datarate = SF_10;
        config.preamble_len = 8;
        config.coding_rate = CR_4_5;
        config.tx_power = 4;
        config.iq_inverted = false;
        config.public_network = false;
        config.tx = transmit;

        return lora_config(dev, &config);
}

/*..........................................................................*/
static void QF_tick_function(struct k_timer *tid) {
    (void)tid; /* unused parameter */
    QTIMEEVT_TICK_X(0U, &timerID);
}
/*..........................................................................*/
void BSP_init(void) {
    int ret = gpio_pin_configure_dt(&l_led0, GPIO_OUTPUT_ACTIVE);
    Q_ASSERT(ret >= 0);

    k_timer_init(&QF_tick_timer, &QF_tick_function, NULL);

    //...
    BSP_randomSeed(1234U);

    if (QS_INIT((void *)0) == 0) { /* initialize the QS software tracing */
        Q_ERROR();
    }

    /* object dictionaries... */
    QS_OBJ_DICTIONARY(AO_Table);
    for (int n = 0; n < N_PHILO; ++n) {
        QS_OBJ_ARR_DICTIONARY(AO_Philo[n], n);
    }

    QS_OBJ_DICTIONARY(&timerID);
    QS_USR_DICTIONARY(PHILO_STAT);
    QS_USR_DICTIONARY(PAUSED_STAT);
    QS_USR_DICTIONARY(COMMAND_STAT);
    QS_USR_DICTIONARY(TEST_MSG);

    /* setup the QS filters... */
    QS_GLB_FILTER(QS_SM_RECORDS); /* state machine records */
    QS_GLB_FILTER(QS_AO_RECORDS); /* active object records */
    QS_GLB_FILTER(QS_UA_RECORDS); /* all user records */
    QS_GLB_FILTER(TEST_MSG);

    struct display_capabilities capabilities;

    if (display_dev == NULL) {
        Q_PRINTK("Display device not found.");
    } else {
        if (!device_is_ready(display_dev)) {
            Q_PRINTK("display not ready");
        }
    }
    display_get_capabilities(display_dev, &capabilities);

    ret = cfb_framebuffer_init(display_dev);
    if (ret != 0) {
        Q_PRINTK("Could not init fb");
    }

    ret = cfb_print(display_dev, "Hello world!", 0, 0);
    if (ret != 0) {
        Q_PRINTK("Could not print to fb");
    }

    ret = cfb_framebuffer_finalize(display_dev);
    if (ret != 0) {
        Q_PRINTK("Could not finalize to fb");
    }

    // LoRa:
    if (lora_dev != NULL) {
        Q_PRINTK("Found lora_dev: %s", lora_dev->name);
    }

/*
    if (!device_is_ready(lora_dev)) {
	Q_PRINTK("LoRa dev not ready.");
    } else {
	ret = conf_radio(lora_dev, true);
	if (ret != 0) {
		Q_PRINTK("Failed to conf_radio()");
	} else {
		Q_PRINTK("LoRa radio configured successfully.");
	}
    }
*/

} // end of BSP_init()

/*..........................................................................*/
void BSP_ledOn(void) {
    gpio_pin_set_dt(&l_led0, true);
}
/*..........................................................................*/
void BSP_ledOff(void) {
    gpio_pin_set_dt(&l_led0, false);
}
/*..........................................................................*/
void BSP_displayPhilStat(uint8_t n, char const *stat) {
    if (stat[0] == 'e') {
        BSP_ledOn();
    }
    else {
        BSP_ledOff();
    }
    Q_PRINTK("Philo[%d]->%s\n", n, stat);

    char buf[20];
    int ret = snprintf(buf, sizeof(buf), "Ph[%d]->%s", n, stat);
    //printk("Philo[%d]->%s\n", n, stat);
    printk(buf, n, stat);

    ret = cfb_print(display_dev, buf, 0, 0);
    if (ret != 0) {
        Q_PRINTK("Could not print to fb");
    }

    ret = cfb_framebuffer_finalize(display_dev);
    if (ret != 0) {
        Q_PRINTK("Could not finalize to fb");
    }

    QS_BEGIN_ID(PHILO_STAT, AO_Philo[n]->prio) /* app-specific record */
        QS_U8(1, n);  /* Philosopher number */
        QS_STR(stat); /* Philosopher status */
    QS_END()          /* application-specific record end */
}

/*..........................................................................*/
void BSP_displayPaused(uint8_t paused) {
    if (paused != 0U) {
        //BSP_LED_On(LED2);
    }
    else {
        //BSP_LED_Off(LED2);
    }
}
/*..........................................................................*/
uint32_t BSP_random(void) { /* a very cheap pseudo-random-number generator */
    uint32_t rnd;

    /* Some flating point code is to exercise the VFP... */
    float volatile x = 3.1415926F;
    x = x + 2.7182818F;

    /* "Super-Duper" Linear Congruential Generator (LCG)
    * LCG(2^32, 3*7*11*13*23, 0, seed)
    */
    rnd = l_rnd * (3U*7U*11U*13U*23U);
    l_rnd = rnd; /* set for the next time */

    return (rnd >> 8);
}
/*..........................................................................*/
void BSP_randomSeed(uint32_t seed) {
    l_rnd = seed;
}
/*..........................................................................*/
void BSP_terminate(int16_t result) {
    (void)result;
}

/* QF callbacks ============================================================*/
void QF_onStartup(void) {
    k_timer_start(&QF_tick_timer, K_MSEC(1), K_MSEC(1));
    Q_PRINTK("QF_onStartup\n");
}
/*..........................................................................*/
void QF_onCleanup(void) {
    Q_PRINTK("QF_onCleanup\n");
}

/*..........................................................................*/
Q_NORETURN Q_onAssert(char const * const module, int_t const loc) {
    /*
    * NOTE: add here your application-specific error handling
    */
    printk("\nASSERTION in %s:%d\n", module, loc);
    QS_ASSERTION(module, loc, 10000U); /* report assertion to QS */
#ifndef NDEBUG
    k_panic(); /* debug build: halt the system for error search... */
#else
    sys_reboot(SYS_REBOOT_COLD); /* release build: reboot the system */
#endif
}

/* QS callbacks ============================================================*/
#ifdef Q_SPY

#include <zephyr/drivers/uart.h>

/* select the Zephyr shell UART
* NOTE: you can change this to other UART peripheral if desired
*/
static struct device const *uart_dev =
     DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));

/*..........................................................................*/
static void uart_cb(const struct device *dev, void *user_data) {
    if (!uart_irq_update(uart_dev)) {
        return;
    }

    if (uart_irq_rx_ready(uart_dev)) {
        uint8_t buf[32];
        int n = uart_fifo_read(uart_dev, buf, sizeof(buf));
        for (uint8_t const *p = buf; n > 0; --n, ++p) {
            QS_RX_PUT(*p);
        }
    }
}
/*..........................................................................*/
uint8_t QS_onStartup(void const *arg) {
    static uint8_t qsTxBuf[1024]; /* buffer for QS-TX channel */
    static uint8_t qsRxBuf[256];  /* buffer for QS-RX channel */

    Q_REQUIRE(uart_dev != (struct device *)0);

    QS_initBuf  (qsTxBuf, sizeof(qsTxBuf));
    QS_rxInitBuf(qsRxBuf, sizeof(qsRxBuf));

    // configure interrupt and callback to receive data
    uart_irq_callback_user_data_set(uart_dev, &uart_cb, (void *)0);
    uart_irq_rx_enable(uart_dev);

    return 1U; /* return success */
}
/*..........................................................................*/
void QS_onCleanup(void) {
}
/*..........................................................................*/
QSTimeCtr QS_onGetTime(void) {  /* NOTE: invoked with interrupts DISABLED */
    return k_cycle_get_32();
}
/*..........................................................................*/
void QS_onFlush(void) {
    uint16_t len = 0xFFFFU; /* to get as many bytes as available */
    uint8_t const *buf;
    while ((buf = QS_getBlock(&len)) != (uint8_t*)0) {
        for (; len != 0U; --len, ++buf) {
            uart_poll_out(uart_dev, *buf);
        }
        len = 0xFFFFU; /* to get as many bytes as available */
    }
}
/*..........................................................................*/
void QS_doOutput(void) {
    uint16_t len = 0xFFFFU; /* big number to get all available bytes */

    QS_CRIT_STAT_
    QS_CRIT_E_();
    uint8_t const *buf = QS_getBlock(&len);
    QS_CRIT_X_();

    /* transmit the bytes via the UART... */
    for (; len != 0U; --len, ++buf) {
        uart_poll_out(uart_dev, *buf);
    }
}
/*..........................................................................*/
/*! callback function to reset the target (to be implemented in the BSP) */
void QS_onReset(void) {
    sys_reboot(SYS_REBOOT_COLD);
}
/*..........................................................................*/
/*! callback function to execute a user command (to be implemented in BSP) */
void QS_onCommand(uint8_t cmdId,
                  uint32_t param1, uint32_t param2, uint32_t param3)
{
    (void)cmdId;
    (void)param1;
    (void)param2;
    (void)param3;
}

#endif /* Q_SPY */