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

Issue #384: (U)ESEND with printf_P-similar syntax #395

Merged
merged 2 commits into from
Aug 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion control6/lang.d/00_header.m4
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ divert(0)dnl
#ifdef NAMED_PIN_SUPPORT
#include "core/portio/user_config.h"
#endif
#include "protocols/ecmd/sender/ecmd_sender_net.h"
#include "protocols/uip/uip_router.h"
#include "protocols/ecmd/sender/ecmd_sender_net.h"

#include "protocols/uip/uip.h"
#include "control6.h"
Expand Down
40 changes: 39 additions & 1 deletion control6/lang.d/50_ecmd_sender.m4
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,43 @@ define(`IPADDR', `ifelse(regexp($1, `:'), `-1', `ip4addr_expand(translit(`$1', `
define(`ip4addr_expand', `uip_ipaddr_t ip; uip_ipaddr(&ip, $1, $2, $3, $4)')
define(`ip6addr_expand', `uip_ipaddr_t ip; uip_ip6addr(&ip, $1, $2, $3, $4, $5, $6, $7, $8)')

define(`ESEND', `do {IPADDR($1); ecmd_sender_send_command(&ip, PSTR($2), NULL); } while(0)')
define(`ESEND', `ECMD_SENDER_USED()dnl
{IPADDR($1);
ifelse(`$#', 2, `ecmd_sender_send_command_P(&ip, NULL, PSTR($2))',
`ecmd_sender_send_command_P(&ip, NULL, PSTR($2), shift(shift($@)))');}')

define(`ESENDGET', `INTHREAD(`', `DIE(`Can use ESENDGET only in a THREAD')')ECMD_SENDER_USED()dnl
ifelse(`$#', 2,dnl
{IPADDR($1);
`ecmd_callback_blocking'action_thread_ident` = 1;
ecmd_sender_send_command_P(&ip, ecmd_callback'action_thread_ident`, PSTR($2));
PT_WAIT_WHILE(pt, ecmd_callback_blocking'action_thread_ident` == 1);' },
{IPADDR($1);
`ecmd_callback_blocking'action_thread_ident` = 1;
ecmd_sender_send_command_P(&ip, ecmd_callback'action_thread_ident`, shift(shift($@)));
PT_WAIT_WHILE(pt, ecmd_callback_blocking'action_thread_ident` == 1);'})

ifdef(`ecmd_callback_defined'action_thread_ident, `', `
define(`ecmd_callback_defined'action_thread_ident, 1)
define(`old_divert', divnum)dnl
divert(globals_divert)dnl
uint8_t ecmd_callback_blocking'action_thread_ident`;
uint8_t ecmd_callback_buffer'action_thread_ident`[ECMD_INPUTBUF_LENGTH];
uint8_t ecmd_callback_buffer_len'action_thread_ident`;
char* ecmd_buffer'action_thread_ident`;

void ecmd_callback'action_thread_ident`(char *text, uint8_t len) {
ecmd_callback_buffer_len'action_thread_ident` = len;
if (text) {
memset(ecmd_callback_buffer'action_thread_ident`, 0, ECMD_INPUTBUF_LENGTH);
memcpy(ecmd_callback_buffer'action_thread_ident`, text,
(ECMD_INPUTBUF_LENGTH - 1) < len ? ECMD_INPUTBUF_LENGTH - 1 : len);

}
ecmd_callback_blocking'action_thread_ident` = 0;
}')
divert(old_divert)')')

define(`ESENDGET_BUFFER', `INTHREAD(`', `DIE(`Can use ESENDGET_BUFFER only in a THREAD')')`ecmd_callback_buffer'action_thread_ident')
define(`ESENDGET_BUFFER_LEN', `INTHREAD(`', `DIE(`Can use ESENDGET_BUFFER_LEN only in a THREAD')')`ecmd_callback_buffer_len'action_thread_ident')

62 changes: 15 additions & 47 deletions control6/lang.d/50_uecmd_sender.m4
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,23 @@ divert(globals_divert)
#error Please define emcd sender udp support
#endif

#include "protocols/ecmd/via_tcp/ecmd_state.h"

static char* control6_uesend_printf(PGM_P format, ...)
{
va_list args;
uint8_t len = strlen_P(format);
uint8_t wlen = len;

// first round: assume output length < format string length
char* buf = malloc(len);

va_start(args, format);
while (wlen == len)
{
if (buf == NULL) return NULL;
wlen = vsnprintf_P(buf, len, format, args) + 1;

// actual size requirement in wlen now -> reallocate
buf = realloc(buf, wlen);
if (wlen <= len)
break;

// need a second round, this time with actual size requirement ...
len = wlen;
}
va_end(args);
return buf;
}

divert(old_divert)')')

define(`UESEND', `UECMD_SENDER_USED()ifelse(`$#', 2,dnl
do {IPADDR($1);uecmd_sender_pgm_send_command(&ip, PSTR($2), NULL); } while(0),
do {IPADDR($1);
char* buf = control6_uesend_printf(PSTR($2), shift(shift($@)));
if (buf != 0)
uecmd_sender_send_command(&ip, buf, NULL); } while(0))')
define(`UESEND', `UECMD_SENDER_USED()dnl
{IPADDR($1);
ifelse(`$#', 2, `uecmd_sender_send_command_P(&ip, NULL, PSTR($2))',
`uecmd_sender_send_command_P(&ip, NULL, PSTR($2), shift(shift($@)))');}')

define(`UESENDGET', `INTHREAD(`', `DIE(`Can use UESENDGET only in a THREAD')')UECMD_SENDER_USED()ifelse(`$#', 2,dnl
{IPADDR($1);
`uecmd_callback_blocking'action_thread_ident` = 1;
uecmd_sender_pgm_send_command(&ip, PSTR($2), uecmd_callback'action_thread_ident`);
`uecmd_callback_blocking'action_thread_ident` = 1;
uecmd_sender_send_command_P(&ip, uecmd_callback'action_thread_ident`, PSTR($2));
PT_WAIT_WHILE(pt, uecmd_callback_blocking'action_thread_ident` == 1);' },
{IPADDR($1);
`uecmd_callback_blocking'action_thread_ident` = 1;
uecmd_buffer'action_thread_ident` = control6_uesend_printf(PSTR($2), shift(shift($@)));
uecmd_sender_send_command(&ip, uecmd_buffer'action_thread_ident`, uecmd_callback'action_thread_ident`);
PT_WAIT_WHILE(pt, uecmd_callback_blocking'action_thread_ident` == 1);' })
`uecmd_callback_blocking'action_thread_ident` = 1;
uecmd_sender_send_command_P(&ip, uecmd_callback'action_thread_ident`, shift(shift($@)));
PT_WAIT_WHILE(pt, uecmd_callback_blocking'action_thread_ident` == 1);'})

ifdef(`uecmd_callback_defined'action_thread_ident, `', `
define(`uecmd_callback_defined'action_thread_ident, 1)
define(`old_divert', divnum)dnl
Expand All @@ -67,18 +36,17 @@ uint8_t uecmd_callback_buffer_len'action_thread_ident`;
char* uecmd_buffer'action_thread_ident`;

void uecmd_callback'action_thread_ident`(char *text, uint8_t len) {
uecmd_callback_blocking'action_thread_ident` = 0;
uecmd_callback_buffer_len'action_thread_ident` = len;
if (text) {
memset(uecmd_callback_buffer'action_thread_ident`, 0, ECMD_INPUTBUF_LENGTH);
memcpy(uecmd_callback_buffer'action_thread_ident`, text,
memcpy(uecmd_callback_buffer'action_thread_ident`, text,
(ECMD_INPUTBUF_LENGTH - 1) < len ? ECMD_INPUTBUF_LENGTH - 1 : len);

}
uecmd_callback_blocking'action_thread_ident` = 0;
}')

divert(old_divert)')')

define(`UESENDGET_BUFFER', `INTHREAD(`', `DIE(`Can use USENDGET_BUFFER only in a THREAD')')`uecmd_callback_buffer'action_thread_ident')
define(`UESENDGET_BUFFER_LEN', `INTHREAD(`', `DIE(`Can use USENDGET_BUFFER_LEN only in a THREAD')')`uecmd_callback_buffer_len'action_thread_ident')
define(`UESENDGET_BUFFER', `INTHREAD(`', `DIE(`Can use UESENDGET_BUFFER only in a THREAD')')`uecmd_callback_buffer'action_thread_ident')
define(`UESENDGET_BUFFER_LEN', `INTHREAD(`', `DIE(`Can use UESENDGET_BUFFER_LEN only in a THREAD')')`uecmd_callback_buffer_len'action_thread_ident')

1 change: 0 additions & 1 deletion protocols/ecmd/sender/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ include $(TOPDIR)/.config

$(ECMD_SENDER_SUPPORT)_SRC += protocols/ecmd/sender/ecmd_sender_net.c
$(UECMD_SENDER_SUPPORT)_SRC += protocols/ecmd/sender/uecmd_sender_net.c
$(UECMD_SENDER_SUPPORT)_SRC += protocols/ecmd/sender/uecmd_sender_pgm_net.c

##############################################################################
# generic fluff
Expand Down
120 changes: 83 additions & 37 deletions protocols/ecmd/sender/ecmd_sender_net.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2007 by Christian Dietrich <stettberger@dokucode.de>
* Copyright (c) 2015 by Erik Kunze <ethersex@erik-kunze.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
Expand All @@ -20,59 +20,105 @@
* http://www.gnu.org/copyleft/gpl.html
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

#include "config.h"
#include "ecmd_sender_net.h"
#include "protocols/uip/uip.h"
#include "core/debug.h"
#include "ecmd_sender_net.h"

#include <string.h>

/* module local prototypes */
typedef int (*fptr_t) (char *, size_t, const char *, va_list);

uip_conn_t *
ecmd_sender_send_command(uip_ipaddr_t *ipaddr, const char *pgm_data,
client_return_text_callback_t callback)
{
uip_conn_t *conn = uip_connect(ipaddr, HTONS(2701), ecmd_sender_net_main);
if (conn) {
conn->appstate.ecmd_sender.to_be_sent = pgm_data;
conn->appstate.ecmd_sender.callback = callback;
conn->appstate.ecmd_sender.sent = 0;
}
return conn;
}

void ecmd_sender_net_main(void)
static void
ecmd_sender_net_main(void)
{
struct ecmd_sender_connection_state_t *state = &uip_conn->appstate.ecmd_sender;
struct ecmd_sender_connection_state_t *state =
&uip_conn->appstate.ecmd_sender;

if(uip_newdata() && uip_len > 0 ) { //&& !uip_connected()) {
if (state->callback != NULL) {
/* Response */
if (uip_newdata() && uip_len > 0)
{
if (state->callback != NULL)
{
state->callback(uip_appdata, uip_len);
state->callback = NULL; /* we must set this to NULL, because
otherwise it would be called on close */
state->callback = NULL; /* we must set this to NULL, because
* otherwise it would be called on close */
}
uip_close();
uip_close();
}

if (uip_closed() && state->callback != NULL) {
state->callback(NULL, 0);
state->callback = NULL;
if (uip_closed() && state->callback != NULL)
{
state->callback(NULL, 0);
state->callback = NULL;
}

if(uip_acked())
if (uip_acked())
state->sent = 1;

if(uip_rexmit() ||
uip_acked() ||
uip_connected() ||
uip_poll()) {
/* Send one buffer of data */
if (state->sent) return;
((char *) uip_appdata)[sizeof(uip_appdata) - 1] = 0;
strncpy_P((char *)uip_appdata, state->to_be_sent, uip_mss() - 1);
uip_udp_send(strlen((char *) uip_appdata));
if (uip_rexmit() || uip_acked() || uip_connected() || uip_poll())
{
/* Send one bufer of data */
if (!state->sent)
{
strncpy((char *) uip_appdata, state->buf, uip_mss() - 1);
((char *) uip_appdata)[uip_mss() - 2] = 0;
uip_send((char *) uip_appdata, strlen((char *) uip_appdata));
}
}
}

static uip_conn_t *
ecmd_sender_send(fptr_t f, uip_ipaddr_t * ipaddr,
client_return_text_callback_t callback,
const char *message, va_list ap)
{
uip_conn_t *conn = uip_connect(ipaddr, HTONS(ECMD_TCP_PORT),
ecmd_sender_net_main);
if (conn)
{
struct ecmd_sender_connection_state_t *state =
&conn->appstate.ecmd_sender;
f(state->buf, sizeof(state->buf), message, ap);
state->buf[sizeof(state->buf) - 1] = 0;
state->callback = callback;
state->sent = 0;
}
else
{
callback(NULL, 0);
}
return conn;
}

uip_conn_t *
ecmd_sender_send_command_P(uip_ipaddr_t * ipaddr,
client_return_text_callback_t callback,
const char *message, ...)
{
va_list va;
va_start(va, message);
uip_conn_t *conn = ecmd_sender_send(&vsnprintf_P, ipaddr,
callback, message, va);
va_end(va);
return conn;
}

uip_conn_t *
ecmd_sender_send_command(uip_ipaddr_t * ipaddr,
client_return_text_callback_t callback,
const char *message, ...)
{
va_list va;
va_start(va, message);
uip_conn_t *conn = ecmd_sender_send(&vsnprintf, ipaddr,
callback, message, va);
va_end(va);
return conn;
}

/*
Expand Down
33 changes: 18 additions & 15 deletions protocols/ecmd/sender/ecmd_sender_net.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2007 by Christian Dietrich <stettberger@dokucode.de>
* Copyright (c) 2015 by Erik Kunze <ethersex@erik-kunze.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
Expand All @@ -24,23 +24,26 @@
#define ECMD_SENDER_NET_H

#include <stdint.h>
typedef void (*client_return_text_callback_t)(char* text, uint8_t len);
#include "protocols/uip/uip.h"
#include <avr/pgmspace.h>

uip_conn_t *ecmd_sender_send_command (uip_ipaddr_t *ipaddr,
const char *pgm_data,
client_return_text_callback_t callback);
void ecmd_sender_net_main(void);
#include "config.h"
#include "protocols/uip/uip.h"


typedef void (*client_return_text_callback_t) (char *, uint8_t);

void uecmd_sender_pgm_send_command (uip_ipaddr_t *ipaddr,
PGM_P pgm_data,
client_return_text_callback_t callback);
void uecmd_sender_pgm_net_main(void);
uip_conn_t *ecmd_sender_send_command_P(uip_ipaddr_t *,
client_return_text_callback_t,
PGM_P, ...);
uip_conn_t *ecmd_sender_send_command(uip_ipaddr_t *,
client_return_text_callback_t,
const char *, ...);

void uecmd_sender_send_command (uip_ipaddr_t *ipaddr,
char *data,
client_return_text_callback_t callback);
void uecmd_sender_net_main(void);
uip_udp_conn_t *uecmd_sender_send_command_P(uip_ipaddr_t *,
client_return_text_callback_t,
PGM_P, ...);
uip_udp_conn_t *uecmd_sender_send_command(uip_ipaddr_t *,
client_return_text_callback_t,
const char *, ...);

#endif /* ECMD_SENDER_NET_H */
9 changes: 6 additions & 3 deletions protocols/ecmd/sender/ecmd_sender_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@
#ifndef ECMD_SENDER_STATE_H
#define ECMD_SENDER_STATE_H

#include "ecmd_sender_net.h"
#include <avr/pgmspace.h>

#include "protocols/ecmd/via_tcp/ecmd_state.h"
#include "ecmd_sender_net.h"

struct ecmd_sender_connection_state_t {
uint16_t sent;
PGM_P to_be_sent;
client_return_text_callback_t callback;
char buf[ECMD_INPUTBUF_LENGTH];
uint8_t retry;
uint8_t sent;
};

#endif /* ECMD_SENDER_STATE_H */