Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function to transmit based on GPIO trigger #8

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions node/companion-app/riot-apps/chirpotle-companion/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ LORA_GPIO_DIO3 ?= "GPIO_UNDEF"
LORA_GPIO_SNIFFER ?= "GPIO_UNDEF"
LORA_GPIO_JAMMER ?= "GPIO_UNDEF"

# This GPIO is used to trigger a synchronized transmission via an external line,
# configured using the transmit_on_gpio_trigger()
LORA_GPIO_TRIGGER_TX ?= "GPIO_UNDEF"

# If the board supports GPIOs and/or GPIO interrupts, we want to have them.
# Except for native, where IRQs aren't stable yet.
ifneq ($(BOARD),native)
Expand Down Expand Up @@ -135,6 +139,7 @@ CFLAGS += -DLORA_GPIO_DIO4=$(LORA_GPIO_DIO4)
CFLAGS += -DLORA_GPIO_DIO5=$(LORA_GPIO_DIO5)
CFLAGS += -DLORA_GPIO_SNIFFER=$(LORA_GPIO_SNIFFER)
CFLAGS += -DLORA_GPIO_JAMMER=$(LORA_GPIO_JAMMER)
CFLAGS += -DLORA_GPIO_TRIGGER_TX=$(LORA_GPIO_TRIGGER_TX)
CFLAGS += -DLORA_UART_DAEMON_DEVICE=$(LORA_UART_DAEMON_DEVICE)
CFLAGS += -DLORA_UART_DAEMON_BAUDRATE=$(LORA_UART_DAEMON_BAUDRATE)
CFLAGS += -DLORA_TCP_DAEMON_PORT=$(LORA_TCP_DAEMON_PORT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ ifeq ($(PRECONF),lopy4-uart)
LORA_GPIO_DIO3 ?= GPIO23

LORA_GPIO_SNIFFER ?= GPIO4
LORA_GPIO_TRIGGER_TX ?= GPIO15

# We use the TCP interface over WiFi
INTERFACE ?= uart
Expand Down Expand Up @@ -263,7 +264,8 @@ ifeq ($(PRECONF),t-beam-uart)
LORA_GPIO_DIO0 ?= GPIO26

# Jam on button press
LORA_GPIO_JAMMER ?= GPIO38
LORA_GPIO_JAMMER ?= GPIO_UNDEF
LORA_GPIO_TRIGGER_TX ?= GPIO38

# We use the TCP interface over WiFi
INTERFACE ?= uart
Expand Down
6 changes: 6 additions & 0 deletions node/companion-app/riot-apps/chirpotle-companion/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ const char if_name[] = "STDIO";
#ifndef LORA_GPIO_JAMMER
#define LORA_GPIO_JAMMER GPIO_UNDEF
#endif
#ifndef LORA_GPIO_TRIGGER_TX
#define LORA_GPIO_TRIGGER_TX GPIO_UNDEF
#endif
#endif

/** Structure for the modem */
Expand Down Expand Up @@ -111,6 +114,9 @@ int main(void)
modem.gpio_dio3 = LORA_GPIO_DIO3;
modem.gpio_sniffer = LORA_GPIO_SNIFFER;
modem.gpio_jammer = LORA_GPIO_JAMMER;
#endif
#ifdef MODULE_PERIPH_GPIO_IRQ
modem.gpio_trigger_tx = LORA_GPIO_TRIGGER_TX;
#endif
printf("Initializing modem... ");
int modem_init_res = lora_modem_init(&modem);
Expand Down
72 changes: 49 additions & 23 deletions node/companion-app/riot-modules/include/lora_modem.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ typedef struct lora_tx_queue_entry {
typedef struct lora_modem_active_tasks {
volatile bool rx;
volatile bool tx;
#ifdef MODULE_PERIPH_GPIO_IRQ
volatile bool prepared_tx;
#endif
volatile bool sniffer;
volatile bool jammer;
} lora_modem_active_tasks_t;
Expand Down Expand Up @@ -282,6 +285,26 @@ typedef struct lora_modem {
gpio_t gpio_jammer;
#endif

#ifdef MODULE_PERIPH_GPIO_IRQ
/** GPIO input used to trigger transmission */
gpio_t gpio_trigger_tx;
/**
* Length of the payload configured for GPIO-triggered transmission.
* (0 = no transmission should happen)
*/
volatile uint8_t gpio_tx_len;
/** Payload of the GPIO-triggered transmission*/
uint8_t gpio_tx_payload[LORA_PAYLOAD_MAX_LENGTH];
/** Delay after which the payload should be sent */
uint64_t gpio_tx_delay;
/** Is the transmission prepared? */
bool gpio_tx_prepared;
/** Message that is used to trigger the transmission */
msg_t gpio_tx_trigmsg;
/** Timer for the delay */
xtimer_t gpio_tx_trigtimer;
#endif

/** Value of the DIO_MAPPING1 register (used to determine which interrupt has fired) */
volatile uint8_t dio_mapping1;
/** Value of the DIO_MAPPING2 register (used to determine which interrupt has fired) */
Expand Down Expand Up @@ -375,9 +398,6 @@ typedef struct lora_modem {
/** True while the jammer is active to debounce the trigger */
volatile bool jammer_active;

/** True, if a tx is prepared in the modem's FIFO */
bool tx_prepared;

#ifdef MODULE_LORA_MODEM_JAMMER_UDP
/** IPv6 to send the triggers to (from the sniffer) */
uint8_t sniffer_addr[16];
Expand Down Expand Up @@ -427,6 +447,9 @@ int lora_modem_configure_gain(lora_modem_t *modem,
/**
* Enables the externally triggered jammer and configures the trigger type.
*
* If the node was configured to transmit a frame on GPIO input, this will be disabled
* in favor of the jammer.
*
* @param[in] modem Modem descriptor
* @param[in] trigger Trigger type
* @return 0 Success
Expand All @@ -437,6 +460,9 @@ int lora_modem_enable_rc_jammer(lora_modem_t *modem, lora_jammer_trigger_t trigg
/**
* Enables the sniffer and configures optional actions when a frame arrives.
*
* If the node was configured to transmit a frame on GPIO input, this will be disabled
* in favor of the sniffing mode.
*
* @param[in] modem Modem descriptor
* @param[in] pattern The pattern that must match in the frame
* @param[in] mask The mask that is applied to the pattern (only high bits will be compared)
Expand Down Expand Up @@ -520,19 +546,6 @@ int lora_modem_get_syncword(lora_modem_t *modem);

int lora_modem_get_txcrc(lora_modem_t *modem);

/**
* Prepares the transmission of a message so that it can be sent immediately
* without any further preparation time.
*
* Cancels any other task on the modem, like calling lora_modem_standby().
*
* @param[in] modem Modem descriptor
* @param[in] frame Payload
* @return 0 success
* @return !=0 failure
*/
int lora_modem_prepare_tx(lora_modem_t *modem, lora_frame_t *frame);

int lora_modem_receive(lora_modem_t *modem);

int lora_modem_set_bandwidth(lora_modem_t *modem, lora_bandwidth_t bw);
Expand Down Expand Up @@ -567,6 +580,15 @@ int lora_modem_set_invertiqrx(lora_modem_t *modem, bool invertiq);
*/
int lora_modem_set_invertiqtx(lora_modem_t *modem, bool invertiq);

/**
* Configures the payload length for jamming payload.
*
* Prepared frame transmission via lora_modem_transmit_on_gpio will be disabled
* when this function is called, as it interacts directly with the payload length
* register, which needs to be locked for preparing transmissions
*
* @param[in] length The length of the payload
*/
void lora_modem_set_jammer_plength(lora_modem_t *modem, uint8_t length);

int lora_modem_set_modulation(lora_modem_t *modem, lora_modulation_t mod);
Expand Down Expand Up @@ -595,17 +617,21 @@ int lora_modem_standby(lora_modem_t *modem);
int lora_modem_transmit(lora_modem_t *modem, lora_frame_t *frame,
uint64_t time, bool blocking);

#ifdef MODULE_PERIPH_GPIO_IRQ
/**
* Transmits a previously prepared frame
*
* The modem must not be used for other actions between the calls to
* lora_modem_prepare_tx and lora_modem_transmit_prepared.
* Configure a frame to be sent when the trigger GPIO is pulled high
*
* The prepared frame will be sent on GPIO high until either the modem is set to standby
* or the function is called again with an empty payload.
*
* If a jammer or sniffer is configured, it will be disabled.
*
* @param[in] modem The modem descriptor
* @param[in] await The function will sleep until txdone
* @return 0 on success
* @param[in] frame The frame to transmit on trigger
* @param[in] delay Optional delay between receiving trigger and transmitting
*/
int lora_modem_transmit_prepared(lora_modem_t *modem, bool await);
void lora_modem_transmit_on_gpio(lora_modem_t *modem, lora_frame_t *frame, uint64_t delay);
#endif

/** Dumps the content of the FIFO to stdout */
void lora_modem_dump_fifo(lora_modem_t *modem);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ typedef enum {

/** Command to transmit a frame */
LORA_DAEMON_REQ_TRANSMIT_FRAME,

/** Command to prepare a GPIO-triggered transmission */
LORA_DAEMON_REQ_TRANSMIT_ON_GPIO_TRIGGER,
} lora_daemon_reqtype_t;

/** Type of the response object */
Expand Down Expand Up @@ -240,7 +243,7 @@ typedef struct lora_daemon_req_standby {
uint8_t filler;
} lora_daemon_req_standby_t;

/** Request getting the current channel config */
/** Request to transmit a frame */
typedef struct lora_daemon_req_transmit_frame {
/** The payload to transmit */
uint8_t payload[LORA_PAYLOAD_MAX_LENGTH];
Expand All @@ -254,6 +257,16 @@ typedef struct lora_daemon_req_transmit_frame {
bool blocking;
} lora_daemon_req_transmit_frame_t;

/** Request to transmit based on a GPIO Trigger */
typedef struct lora_daemon_req_transmit_on_gpio_trigger {
/** The payload to transmit */
uint8_t payload[LORA_PAYLOAD_MAX_LENGTH];
/** Size of the payload */
size_t length;
/** The time to wait after getting the trigger before transmitting */
uint64_t delay;
} lora_daemon_req_transmit_on_gpio_trigger_t;

/** Generic error object if the request failedc */
typedef struct lora_daemon_res_error {
char message[LORA_DAEMON_RES_MSG_MAX_LENGTH];
Expand Down Expand Up @@ -334,6 +347,7 @@ typedef struct lora_daemon_req {
lora_daemon_req_set_txcrc_t set_txcrc;
lora_daemon_req_standby_t standby;
lora_daemon_req_transmit_frame_t transmit_frame;
lora_daemon_req_transmit_on_gpio_trigger_t transmit_on_gpio_trigger;
} params;

} lora_daemon_req_t;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ static void _cmd_transmit_frame(
lora_daemon_res_t *res
);

/** Handler function for the transmit_on_gpio_trigger command */
static void _cmd_transmit_on_gpio_trigger(
lora_modem_t *modem,
lora_daemon_req_transmit_on_gpio_trigger_t *req,
lora_daemon_res_t *res
);

/** Writes an error response object to the response */
static void _raise_error(const char* msg, lora_daemon_res_t *res);

Expand Down Expand Up @@ -153,6 +160,10 @@ void lora_daemon_run_cmd(lora_daemon_t *daemon, lora_daemon_req_t *req, lora_dae
DEBUG("%s: Running command transmit_frame\n", daemon->name);
_cmd_transmit_frame(modem, &(req->params.transmit_frame), res);
break;
case LORA_DAEMON_REQ_TRANSMIT_ON_GPIO_TRIGGER:
DEBUG("%s: Running command transmit_on_gpio_trigger\n", daemon->name);
_cmd_transmit_on_gpio_trigger(modem, &(req->params.transmit_on_gpio_trigger), res);
break;
default:
DEBUG("%s: Unknown command, cannot run.\n", daemon->name);
_raise_error("Unknown command", res);
Expand Down Expand Up @@ -508,6 +519,27 @@ static void _cmd_transmit_frame(
}
}

static void _cmd_transmit_on_gpio_trigger(
lora_modem_t *modem,
lora_daemon_req_transmit_on_gpio_trigger_t *req,
lora_daemon_res_t *res)
{
// In case the application is compiled without GPIO IRQ support,
// we cannot trigger a transmission based on that, so we return
// an error directly.
#ifdef MODULE_PERIPH_GPIO_IRQ
lora_frame_t frame;
frame.length = req->length;
frame.payload = req->payload;
lora_modem_transmit_on_gpio(modem, &frame, req->delay);
_return_status("Triggered transmission configured", 0, res);
#else
(void)modem;
(void)req;
_raise_error("GPIO IRQ support unavailable", res);
#endif
}

static void _raise_error(const char* msg, lora_daemon_res_t *res)
{
DEBUG("lora_daemon: Raising error: %s\n", msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ void _set_param_transmit_frame(
const ubjson_type_t type,
const ssize_t content);

void _set_param_transmit_on_gpio_trigger(
ubjson_cookie_t *__restrict cookie,
lora_daemon_req_transmit_on_gpio_trigger_t *req,
const char * param_name,
const ubjson_type_t type,
const ssize_t content);

/**
* Tries to read the command name from the parameter and to set the type in req
* accordingly. Returns 0 if a valid command name was used
Expand Down Expand Up @@ -251,6 +258,9 @@ void _set_parameter(
case LORA_DAEMON_REQ_TRANSMIT_FRAME:
_set_param_transmit_frame(cookie, &(req->params.transmit_frame), param_name, type, content);
break;
case LORA_DAEMON_REQ_TRANSMIT_ON_GPIO_TRIGGER:
_set_param_transmit_on_gpio_trigger(cookie, &(req->params.transmit_on_gpio_trigger), param_name, type, content);
break;
case LORA_DAEMON_REQ_FETCH_FRAME:
case LORA_DAEMON_REQ_GET_LORA_CHANNEL:
case LORA_DAEMON_REQ_GET_PREAMBLE_LENGTH:
Expand Down Expand Up @@ -534,6 +544,37 @@ void _set_param_transmit_frame(
}
}

void _set_param_transmit_on_gpio_trigger(
ubjson_cookie_t *__restrict cookie,
lora_daemon_req_transmit_on_gpio_trigger_t *req,
const char * param_name,
const ubjson_type_t type,
const ssize_t content)
{
if(strcmp("payload", param_name) == 0 && type == UBJSON_ENTER_ARRAY) {
req->length = 0;
_ubjson_parse_array(cookie, req->payload, &(req->length), LORA_PAYLOAD_MAX_LENGTH);
}
else if(strcmp("delay", param_name) == 0) {
if (type == UBJSON_TYPE_INT32) {
int32_t val = 0;
ubjson_get_i32(cookie, content, &val);
req->delay = (uint64_t)val;
}
else if (type == UBJSON_TYPE_INT64) {
int64_t val = 0;
ubjson_get_i64(cookie, content, &val);
req->delay = (uint64_t)val;
}
else {
_ubjson_skip_entity(cookie, type, content);
}
}
else {
_ubjson_skip_entity(cookie, type, content);
}
}

int _set_reqtype(lora_daemon_req_t *req, char *command_name)
{
if (strcmp("configure_gain", command_name) == 0) {
Expand Down Expand Up @@ -593,6 +634,11 @@ int _set_reqtype(lora_daemon_req_t *req, char *command_name)
req->params.transmit_frame.length = 0;
req->params.transmit_frame.time_set = false;
}
else if (strcmp("transmit_on_gpio_trigger", command_name) == 0) {
req->type = LORA_DAEMON_REQ_TRANSMIT_ON_GPIO_TRIGGER;
req->params.transmit_on_gpio_trigger.length = 0;
req->params.transmit_on_gpio_trigger.delay = 0;
}
else {
return 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ enum {
* Restore the modem state after a transmission
*/
LORAMODEM_MTYPE_TX_RESTORE,
/**
* Transmit a prepared message based on a GPIO trigger
*/
LORAMODEM_MTYPE_TRIGGER_MESSAGE,
};

/**
Expand Down
Loading