blob: ef81df71e3901a13fe4b5e570fd619ca273d4b35 [file] [log] [blame]
/* Copyright 2023 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <zephyr/kernel.h>
#include <zephyr/smf.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/shell/shell.h>
#include "controls.h"
#include "meas.h"
#include "view.h"
#include "model.h"
LOG_MODULE_REGISTER(main);
#define DEBUG 1
/* The devicetree node identifier for the led aliases. */
#define LED0_NODE DT_ALIAS(led0)
#define LED1_NODE DT_ALIAS(led1)
#define LED2_NODE DT_ALIAS(led2)
/* various flags for the current state of the snooper */
#define FLAGS_SNOOP0 0
#define FLAGS_SNOOP1 1
#define FLAGS_SNOOP2 2
#define FLAGS_SNOOP3 3
#define FLAGS_NO_CONNECTION 4
#define FLAGS_CC1_CONNECTION 5
#define FLAGS_CC2_CONNECTION 6
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
static const struct gpio_dt_spec led2 = GPIO_DT_SPEC_GET(LED2_NODE, gpios);
static const struct smf_state view_states[];
enum led_t {
LED_OFF,
LED_RED,
LED_GREEN,
LED_BLUE
};
enum view_state_t {
SNOOP0,
SNOOP1,
SNOOP2,
SNOOP3
};
struct view_obj_t {
struct smf_ctx ctx;
k_timeout_t timeout;
bool toggle;
atomic_t flags;
} view_obj;
snooper_mask_t get_view_snoop()
{
if (atomic_test_bit(&view_obj.flags, FLAGS_SNOOP0)) {
return 0;
}
if (atomic_test_bit(&view_obj.flags, FLAGS_SNOOP1)) {
return CC1_CHANNEL_BIT;
}
if (atomic_test_bit(&view_obj.flags, FLAGS_SNOOP2)) {
return CC2_CHANNEL_BIT;
}
if (atomic_test_bit(&view_obj.flags, FLAGS_SNOOP3)) {
return (CC1_CHANNEL_BIT | CC2_CHANNEL_BIT);
}
return 0;
}
int view_set_connection(snooper_mask_t vc)
{
switch (vc) {
case 0:
atomic_clear_bit(&view_obj.flags, FLAGS_CC1_CONNECTION);
atomic_clear_bit(&view_obj.flags, FLAGS_CC2_CONNECTION);
atomic_set_bit(&view_obj.flags, FLAGS_NO_CONNECTION);
break;
case CC1_CHANNEL_BIT:
atomic_clear_bit(&view_obj.flags, FLAGS_NO_CONNECTION);
atomic_clear_bit(&view_obj.flags, FLAGS_CC2_CONNECTION);
atomic_set_bit(&view_obj.flags, FLAGS_CC1_CONNECTION);
break;
case CC2_CHANNEL_BIT:
atomic_clear_bit(&view_obj.flags, FLAGS_NO_CONNECTION);
atomic_clear_bit(&view_obj.flags, FLAGS_CC1_CONNECTION);
atomic_set_bit(&view_obj.flags, FLAGS_CC2_CONNECTION);
break;
default:
return -EIO;
}
return 0;
}
int view_set_snoop(snooper_mask_t vs)
{
switch (vs) {
case 0:
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP1);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP2);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP3);
atomic_set_bit(&view_obj.flags, FLAGS_SNOOP0);
break;
case CC1_CHANNEL_BIT:
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP0);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP2);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP3);
atomic_set_bit(&view_obj.flags, FLAGS_SNOOP1);
break;
case CC2_CHANNEL_BIT:
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP0);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP1);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP3);
atomic_set_bit(&view_obj.flags, FLAGS_SNOOP2);
break;
case (CC1_CHANNEL_BIT | CC2_CHANNEL_BIT):
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP0);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP1);
atomic_clear_bit(&view_obj.flags, FLAGS_SNOOP2);
atomic_set_bit(&view_obj.flags, FLAGS_SNOOP3);
break;
default:
return -EIO;
}
view_set_connection(0);
return 0;
}
static void set_led(enum led_t led)
{
switch (led) {
case LED_OFF:
gpio_pin_set_dt(&led0, 0);
gpio_pin_set_dt(&led1, 0);
gpio_pin_set_dt(&led2, 0);
break;
case LED_RED:
gpio_pin_set_dt(&led0, 1);
gpio_pin_set_dt(&led1, 0);
gpio_pin_set_dt(&led2, 0);
break;
case LED_GREEN:
gpio_pin_set_dt(&led0, 0);
gpio_pin_set_dt(&led1, 1);
gpio_pin_set_dt(&led2, 0);
break;
case LED_BLUE:
gpio_pin_set_dt(&led0, 0);
gpio_pin_set_dt(&led1, 0);
gpio_pin_set_dt(&led2, 1);
break;
}
}
static void snoop0_entry(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
set_led(LED_OFF);
vo->timeout = K_MSEC(1000);
}
static void snoop0_run(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
if (atomic_test_bit(&vo->flags, FLAGS_SNOOP1)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP1]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP2)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP2]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP3)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP3]);
}
}
static void snoop0_exit(void *o)
{
}
static void snoop1_entry(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
vo->timeout = K_MSEC(1000);
}
static void snoop1_run(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
if (atomic_test_bit(&vo->flags, FLAGS_SNOOP0)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP0]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP2)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP2]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP3)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP3]);
} else if (atomic_test_bit(&vo->flags, FLAGS_NO_CONNECTION)) {
if (vo->toggle) {
set_led(LED_BLUE);
vo->toggle = false;
} else {
set_led(LED_OFF);
vo->toggle = true;
}
} else if (atomic_test_bit(&vo->flags, FLAGS_CC1_CONNECTION)) {
set_led(LED_GREEN);
} else if (atomic_test_bit(&vo->flags, FLAGS_CC2_CONNECTION)) {
set_led(LED_RED);
}
}
static void snoop1_exit(void *o)
{
set_led(LED_OFF);
}
static void snoop2_entry(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
vo->timeout = K_MSEC(500);
}
static void snoop2_run(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
if (atomic_test_bit(&vo->flags, FLAGS_SNOOP0)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP0]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP1)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP1]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP3)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP3]);
} else if (atomic_test_bit(&vo->flags, FLAGS_NO_CONNECTION)) {
if (vo->toggle) {
set_led(LED_BLUE);
vo->toggle = false;
} else {
set_led(LED_OFF);
vo->toggle = true;
}
} else if (atomic_test_bit(&vo->flags, FLAGS_CC1_CONNECTION)) {
set_led(LED_RED);
} else if (atomic_test_bit(&vo->flags, FLAGS_CC2_CONNECTION)) {
set_led(LED_GREEN);
}
}
static void snoop2_exit(void *o)
{
set_led(LED_OFF);
}
static void snoop3_entry(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
vo->timeout = K_MSEC(250);
}
static void snoop3_run(void *o)
{
struct view_obj_t *vo = (struct view_obj_t *)o;
if (atomic_test_bit(&vo->flags, FLAGS_SNOOP0)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP0]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP1)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP1]);
} else if (atomic_test_bit(&vo->flags, FLAGS_SNOOP2)) {
smf_set_state(SMF_CTX(vo), &view_states[SNOOP2]);
} else if (atomic_test_bit(&vo->flags, FLAGS_NO_CONNECTION)) {
if (vo->toggle) {
set_led(LED_BLUE);
vo->toggle = false;
} else {
set_led(LED_OFF);
vo->toggle = true;
}
} else if (atomic_test_bit(&vo->flags, FLAGS_CC1_CONNECTION)) {
set_led(LED_GREEN);
} else if (atomic_test_bit(&vo->flags, FLAGS_CC2_CONNECTION)) {
set_led(LED_GREEN);
}
}
static void snoop3_exit(void *o)
{
set_led(LED_OFF);
}
static const struct smf_state view_states[] = {
[SNOOP0] = SMF_CREATE_STATE(snoop0_entry, snoop0_run, snoop0_exit),
[SNOOP1] = SMF_CREATE_STATE(snoop1_entry, snoop1_run, snoop1_exit),
[SNOOP2] = SMF_CREATE_STATE(snoop2_entry, snoop2_run, snoop2_exit),
[SNOOP3] = SMF_CREATE_STATE(snoop3_entry, snoop3_run, snoop3_exit),
};
int view_init(void)
{
int ret;
if (!device_is_ready(led0.port)) {
return -EIO;
}
if (!device_is_ready(led1.port)) {
return -EIO;
}
if (!device_is_ready(led2.port)) {
return -EIO;
}
ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return ret;
}
ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return ret;
}
ret = gpio_pin_configure_dt(&led2, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return ret;
}
view_obj.flags = ATOMIC_INIT(0);
smf_set_initial(SMF_CTX(&view_obj), &view_states[SNOOP0]);
while (1) {
smf_run_state(SMF_CTX(&view_obj));
k_sleep(view_obj.timeout);
}
return 0;
}