Make message/text sending aware of the sending destination.

Point of this change is to allow using these functions for
writing to the display, too, without duplicating all the code.

To reduce confusion, functions were renamed (they're no longer
'serial', after all:

  serwrite_xxx() -> write_xxx()
  sersendf_P()   -> sendf_P()

To avoid changing all the existing code, a couple of macros
with the old names are provided. They might even be handy as
convenience macros.

Nicely, this addition costs no additional RAM. Not surprising, it
costs quite some binary size, 278 bytes. Sizes now:

Program:  24058 bytes      168%       79%       38%       19%
   Data:   1525 bytes      149%       75%       38%       19%
 EEPROM:     32 bytes        4%        2%        2%        1%

Regarding USB Serial: code was adjusted without testing on
hardware.
This commit is contained in:
Markus Hitter 2016-04-25 02:45:24 +02:00
parent 6577578051
commit e633222cd3
15 changed files with 143 additions and 96 deletions

1
dda.c
View File

@ -15,7 +15,6 @@
#include "cpu.h" #include "cpu.h"
#include "timer.h" #include "timer.h"
#include "serial.h" #include "serial.h"
#include "sermsg.h"
#include "gcode_parse.h" #include "gcode_parse.h"
#include "dda_queue.h" #include "dda_queue.h"
#include "debug.h" #include "debug.h"

View File

@ -17,7 +17,6 @@
#include "timer.h" #include "timer.h"
#include "delay.h" #include "delay.h"
#include "serial.h" #include "serial.h"
#include "sermsg.h"
#include "gcode_parse.h" #include "gcode_parse.h"
#include "dda_queue.h" #include "dda_queue.h"
#include "debug.h" #include "debug.h"

View File

@ -9,7 +9,6 @@
#include "config_wrapper.h" #include "config_wrapper.h"
#include "timer.h" #include "timer.h"
#include "serial.h" #include "serial.h"
#include "sermsg.h"
#include "temp.h" #include "temp.h"
#include "delay.h" #include "delay.h"
#include "sersendf.h" #include "sersendf.h"

View File

@ -14,7 +14,6 @@
#include "watchdog.h" #include "watchdog.h"
#include "delay.h" #include "delay.h"
#include "serial.h" #include "serial.h"
#include "sermsg.h"
#include "temp.h" #include "temp.h"
#include "heater.h" #include "heater.h"
#include "timer.h" #include "timer.h"

View File

@ -17,6 +17,7 @@
#include "config_wrapper.h" #include "config_wrapper.h"
#include "display.h" #include "display.h"
#include "font.h" #include "font.h"
#include "sendf.h"
static void i2c_test(void) { static void i2c_test(void) {
@ -25,7 +26,7 @@ static void i2c_test(void) {
128 columns, so we offset by 32 columns to get it to the center. 128 columns, so we offset by 32 columns to get it to the center.
*/ */
display_set_cursor(1, 32); display_set_cursor(1, 32);
display_writestr_P(PSTR("Welcome to Teacup")); sendf_P(display_writechar, PSTR("Welcome to Teacup"));
} }
#endif /* I2C_TEST */ #endif /* I2C_TEST */

View File

@ -1,44 +1,44 @@
#include "sermsg.h"
/** \file sermsg.c /** \file msg.c
\brief primitives for sending numbers over the serial link
\brief Primitives for sending numbers over links.
*/ */
#include "serial.h" #include "msg.h"
/** write a single hex digit /** write a single hex digit
\param v hex digit to write, higher nibble ignored \param v hex digit to write, higher nibble ignored
*/ */
void serwrite_hex4(uint8_t v) { void write_hex4(void (*writechar)(uint8_t), uint8_t v) {
v &= 0xF; v &= 0xF;
if (v < 10) if (v < 10)
serial_writechar('0' + v); writechar('0' + v);
else else
serial_writechar('A' - 10 + v); writechar('A' - 10 + v);
} }
/** write a pair of hex digits /** write a pair of hex digits
\param v byte to write. One byte gives two hex digits \param v byte to write. One byte gives two hex digits
*/ */
void serwrite_hex8(uint8_t v) { void write_hex8(void (*writechar)(uint8_t), uint8_t v) {
serwrite_hex4(v >> 4); write_hex4(writechar, v >> 4);
serwrite_hex4(v & 0x0F); write_hex4(writechar, v & 0x0F);
} }
/** write four hex digits /** write four hex digits
\param v word to write \param v word to write
*/ */
void serwrite_hex16(uint16_t v) { void write_hex16(void (*writechar)(uint8_t), uint16_t v) {
serwrite_hex8(v >> 8); write_hex8(writechar, v >> 8);
serwrite_hex8(v & 0xFF); write_hex8(writechar, v & 0xFF);
} }
/** write eight hex digits /** write eight hex digits
\param v long word to write \param v long word to write
*/ */
void serwrite_hex32(uint32_t v) { void write_hex32(void (*writechar)(uint8_t), uint32_t v) {
serwrite_hex16(v >> 16); write_hex16(writechar, v >> 16);
serwrite_hex16(v & 0xFFFF); write_hex16(writechar, v & 0xFFFF);
} }
/// list of powers of ten, used for dividing down decimal numbers for sending, and also for our crude floating point algorithm /// list of powers of ten, used for dividing down decimal numbers for sending, and also for our crude floating point algorithm
@ -47,7 +47,7 @@ const uint32_t powers[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 1
/** write decimal digits from a long unsigned int /** write decimal digits from a long unsigned int
\param v number to send \param v number to send
*/ */
void serwrite_uint32(uint32_t v) { void write_uint32(void (*writechar)(uint8_t), uint32_t v) {
uint8_t e, t; uint8_t e, t;
for (e = 9; e > 0; e--) { for (e = 9; e > 0; e--) {
@ -58,7 +58,7 @@ void serwrite_uint32(uint32_t v) {
do do
{ {
for (t = 0; v >= powers[e]; v -= powers[e], t++); for (t = 0; v >= powers[e]; v -= powers[e], t++);
serial_writechar(t + '0'); writechar(t + '0');
} }
while (e--); while (e--);
} }
@ -66,20 +66,20 @@ void serwrite_uint32(uint32_t v) {
/** write decimal digits from a long signed int /** write decimal digits from a long signed int
\param v number to send \param v number to send
*/ */
void serwrite_int32(int32_t v) { void write_int32(void (*writechar)(uint8_t), int32_t v) {
if (v < 0) { if (v < 0) {
serial_writechar('-'); writechar('-');
v = -v; v = -v;
} }
serwrite_uint32(v); write_uint32(writechar, v);
} }
/** write decimal digits from a long unsigned int /** write decimal digits from a long unsigned int
\param v number to send \param v number to send
\param fp number of decimal places to the right of the decimal point \param fp number of decimal places to the right of the decimal point
*/ */
void serwrite_uint32_vf(uint32_t v, uint8_t fp) { void write_uint32_vf(void (*writechar)(uint8_t), uint32_t v, uint8_t fp) {
uint8_t e, t; uint8_t e, t;
for (e = 9; e > 0; e--) { for (e = 9; e > 0; e--) {
@ -93,9 +93,9 @@ void serwrite_uint32_vf(uint32_t v, uint8_t fp) {
do do
{ {
for (t = 0; v >= powers[e]; v -= powers[e], t++); for (t = 0; v >= powers[e]; v -= powers[e], t++);
serial_writechar(t + '0'); writechar(t + '0');
if (e == fp) if (e == fp)
serial_writechar('.'); writechar('.');
} }
while (e--); while (e--);
} }
@ -104,11 +104,11 @@ void serwrite_uint32_vf(uint32_t v, uint8_t fp) {
\param v number to send \param v number to send
\param fp number of decimal places to the right of the decimal point \param fp number of decimal places to the right of the decimal point
*/ */
void serwrite_int32_vf(int32_t v, uint8_t fp) { void write_int32_vf(void (*writechar)(uint8_t), int32_t v, uint8_t fp) {
if (v < 0) { if (v < 0) {
serial_writechar('-'); writechar('-');
v = -v; v = -v;
} }
serwrite_uint32_vf(v, fp); write_uint32_vf(writechar, v, fp);
} }

24
msg.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _SERMSG_H
#define _SERMSG_H
#include <stdint.h>
// functions for sending hexadecimal
void write_hex4(void (*writechar)(uint8_t), uint8_t v);
void write_hex8(void (*writechar)(uint8_t), uint8_t v);
void write_hex16(void (*writechar)(uint8_t), uint16_t v);
void write_hex32(void (*writechar)(uint8_t), uint32_t v);
// functions for sending decimal
#define write_uint8(v, w) write_uint32(v, w)
#define write_int8(v, w) write_int32(v, w)
#define write_uint16(v, w) write_uint32(v, w)
#define write_int16(v, w) write_int32(v, w)
void write_uint32(void (*writechar)(uint8_t), uint32_t v);
void write_int32(void (*writechar)(uint8_t), int32_t v);
void write_uint32_vf(void (*writechar)(uint8_t), uint32_t v, uint8_t fp);
void write_int32_vf(void (*writechar)(uint8_t), int32_t v, uint8_t fp);
#endif /* _SERMSG_H */

View File

@ -1,4 +1,3 @@
#include "sersendf.h"
/** \file sersendf.c /** \file sersendf.c
\brief Simplified printf implementation \brief Simplified printf implementation
@ -6,13 +5,18 @@
#include <stdarg.h> #include <stdarg.h>
#include "serial.h" #include "sendf.h"
#include "sermsg.h" #include "msg.h"
/** \brief Simplified printf /** \brief Simplified printf
\param format pointer to output format specifier string stored in FLASH.
\param ... output data \param writechar The function to use for writing a character. Typically
serial_writechar() or display_writechar().
\param format Pointer to output format specifier string stored in FLASH.
\param ... Data according to the placeholders in format.
Implements only a tiny subset of printf's format specifiers :- Implements only a tiny subset of printf's format specifiers :-
@ -31,7 +35,11 @@
Example: Example:
\code sersendf_P(PSTR("X:%ld Y:%ld temp:%u.%d flags:%sx Q%su/%su%c\n"), target.X, target.Y, current_temp >> 2, (current_temp & 3) * 25, dda.allflags, mb_head, mb_tail, (queue_full()?'F':(queue_empty()?'E':' '))) \endcode \code sersendf_P(serial_writechar,
PSTR("X:%ld Y:%ld temp:%u.%d flags:%sx Q%su/%su%c\n"),
target.X, target.Y, current_temp >> 2,
(current_temp & 3) * 25, dda.allflags, mb_head, mb_tail,
(queue_full()?'F':(queue_empty()?'E':' '))) \endcode
*/ */
/** /**
@ -45,7 +53,7 @@
#define GET_ARG(T) ((T)va_arg(args, int)) #define GET_ARG(T) ((T)va_arg(args, int))
#endif #endif
void sersendf_P(PGM_P format_P, ...) { void sendf_P(void (*writechar)(uint8_t), PGM_P format_P, ...) {
va_list args; va_list args;
va_start(args, format_P); va_start(args, format_P);
@ -62,44 +70,45 @@ void sersendf_P(PGM_P format_P, ...) {
break; break;
case 'u': case 'u':
if (j == 1) if (j == 1)
serwrite_uint8((uint8_t)GET_ARG(uint16_t)); write_uint8(writechar, (uint8_t)GET_ARG(uint16_t));
else if (j == 2) else if (j == 2)
serwrite_uint16((uint16_t)GET_ARG(uint16_t)); write_uint16(writechar, (uint16_t)GET_ARG(uint16_t));
else else
serwrite_uint32(GET_ARG(uint32_t)); write_uint32(writechar, GET_ARG(uint32_t));
j = 0; j = 0;
break; break;
case 'd': case 'd':
if (j == 1) if (j == 1)
serwrite_int8((int8_t)GET_ARG(int16_t)); write_int8(writechar, (int8_t)GET_ARG(int16_t));
else if (j == 2) else if (j == 2)
serwrite_int16((int16_t)GET_ARG(int16_t)); write_int16(writechar, (int16_t)GET_ARG(int16_t));
else else
serwrite_int32(GET_ARG(int32_t)); write_int32(writechar, GET_ARG(int32_t));
j = 0; j = 0;
break; break;
case 'c': case 'c':
serial_writechar((uint8_t)GET_ARG(uint16_t)); writechar((uint8_t)GET_ARG(uint16_t));
j = 0; j = 0;
break; break;
case 'x': case 'x':
serial_writestr_P(PSTR("0x")); writechar('0');
writechar('x');
if (j == 1) if (j == 1)
serwrite_hex8((uint8_t)GET_ARG(uint16_t)); write_hex8(writechar, (uint8_t)GET_ARG(uint16_t));
else if (j == 2) else if (j == 2)
serwrite_hex16((uint16_t)GET_ARG(uint16_t)); write_hex16(writechar, (uint16_t)GET_ARG(uint16_t));
else else
serwrite_hex32(GET_ARG(uint32_t)); write_hex32(writechar, GET_ARG(uint32_t));
j = 0; j = 0;
break; break;
/* case 'p': /* case 'p':
serwrite_hex16(GET_ARG(uint16_t));*/ serwrite_hex16(writechar, GET_ARG(uint16_t));*/
case 'q': case 'q':
serwrite_int32_vf(GET_ARG(uint32_t), 3); write_int32_vf(writechar, GET_ARG(uint32_t), 3);
j = 0; j = 0;
break; break;
default: default:
serial_writechar(c); writechar(c);
j = 0; j = 0;
break; break;
} }
@ -109,7 +118,7 @@ void sersendf_P(PGM_P format_P, ...) {
j = 2; j = 2;
} }
else { else {
serial_writechar(c); writechar(c);
} }
} }
} }

11
sendf.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _SENDF_H
#define _SENDF_H
#include "arduino.h"
// No __attribute__ ((format (printf, 1, 2)) here because %q isn't supported.
void sendf_P(void (*writechar)(uint8_t), PGM_P format_P, ...);
#endif /* _SENDF_H */

View File

@ -199,9 +199,10 @@ void serial_init() {
serial_writestr_P(PSTR("\nSerial port parameters were calculated at ")); serial_writestr_P(PSTR("\nSerial port parameters were calculated at "));
serial_writestr_P(PSTR("runtime.\nInsert these values to the list of ")); serial_writestr_P(PSTR("runtime.\nInsert these values to the list of "));
serial_writestr_P(PSTR("known settings in serial-arm.c:\n")); serial_writestr_P(PSTR("known settings in serial-arm.c:\n"));
sersendf_P(PSTR(" UART_DLM %sx\n"), (DL >> 8) & 0xFF); sersendf_P(serial_writechar, PSTR(" UART_DLM %sx\n"), (DL >> 8) & 0xFF);
sersendf_P(PSTR(" UART_DLL %sx\n"), (DL >> 0) & 0xFF); sersendf_P(serial_writechar, PSTR(" UART_DLL %sx\n"), (DL >> 0) & 0xFF);
sersendf_P(PSTR(" UART_FDR %sx\n"), (DivAddVal << 0) | (MulVal << 4)); sersendf_P(serial_writechar, PSTR(" UART_FDR %sx\n"),
(DivAddVal << 0) | (MulVal << 4));
serial_writestr_P(PSTR("Doing so will speed up serial considerably.\n\n")); serial_writestr_P(PSTR("Doing so will speed up serial considerably.\n\n"));
#endif #endif
} }

View File

@ -10,7 +10,6 @@
#define serial_init() usb_init() #define serial_init() usb_init()
#define serial_rxchars() usb_serial_available() #define serial_rxchars() usb_serial_available()
#define serial_popchar() usb_serial_getchar() #define serial_popchar() usb_serial_getchar()
#define serial_writechar(c) usb_serial_putchar(c)
#else #else
// initialise serial subsystem // initialise serial subsystem
void serial_init(void); void serial_init(void);

View File

@ -1,24 +1,22 @@
#ifndef _SERMSG_H
#define _SERMSG_H
#include <stdint.h> #ifndef _MSG_H
#define _MSG_H
// functions for sending hexadecimal #include "msg.h"
void serwrite_hex4(uint8_t v); #include "serial.h"
void serwrite_hex8(uint8_t v);
void serwrite_hex16(uint16_t v);
void serwrite_hex32(uint32_t v);
// functions for sending decimal /**
#define serwrite_uint8(v) serwrite_uint32(v) Before we had display support, all messages went to the serial link,
#define serwrite_int8(v) serwrite_int32(v) so this destination was hardcoded. These macros avoid changing some
#define serwrite_uint16(v) serwrite_uint32(v) older code.
#define serwrite_int16(v) serwrite_int32(v)
void serwrite_uint32(uint32_t v); Deprecated macros? Convenience macros? Dunno.
void serwrite_int32(int32_t v); */
#define serwrite_uint8(v) write_uint8(serial_writechar, v)
#define serwrite_int8(v) write_int8(serial_writechar, v)
#define serwrite_uint16(v) write_uint32(serial_writechar, v)
#define serwrite_int16(v) write_int32(serial_writechar, v)
#define serwrite_uint32(v) write_uint32(serial_writechar, v);
#define serwrite_int32(v) write_int32(serial_writechar, v);
void serwrite_uint32_vf(uint32_t v, uint8_t fp); #endif /* _MSG_H */
void serwrite_int32_vf(int32_t v, uint8_t fp);
#endif /* _SERMSG_H */

View File

@ -1,10 +1,16 @@
#ifndef _SERSENDF_H #ifndef _SERSENDF_H
#define _SERSENDF_H #define _SERSENDF_H
#include "arduino.h" #include "sendf.h"
#include "serial.h"
/**
Before we had display support, all messages went to the serial link,
so this destination was hardcoded. This macro avoids changing a whole lot
of older code.
// No __attribute__ ((format (printf, 1, 2)) here because %q isn't supported. Deprecated macro? Convenience macro? Dunno.
void sersendf_P(PGM_P format_P, ...); */
#define sersendf_P(...) sendf_P(serial_writechar, __VA_ARGS__)
#endif /* _SERSENDF_H */ #endif /* _SERSENDF_H */

View File

@ -413,13 +413,15 @@ void usb_serial_flush_input(void)
} }
} }
// transmit a character. 0 returned on success, -1 on error /**
int8_t usb_serial_putchar(uint8_t c) Transmit a character.
{ */
void serial_writechar(uint8_t c) {
uint8_t timeout, intr_state; uint8_t timeout, intr_state;
// if we're not online (enumerated and configured), error // if we're not online (enumerated and configured), error
if (!usb_configuration) return -1; if ( ! usb_configuration) return;
// interrupts are disabled so these functions can be // interrupts are disabled so these functions can be
// used from the main program or interrupt context, // used from the main program or interrupt context,
// even both in the same program! // even both in the same program!
@ -430,7 +432,7 @@ int8_t usb_serial_putchar(uint8_t c)
if (transmit_previous_timeout) { if (transmit_previous_timeout) {
if (!(UEINTX & (1<<RWAL))) { if (!(UEINTX & (1<<RWAL))) {
SREG = intr_state; SREG = intr_state;
return -1; return;
} }
transmit_previous_timeout = 0; transmit_previous_timeout = 0;
} }
@ -444,10 +446,11 @@ int8_t usb_serial_putchar(uint8_t c)
// is not running an application that is listening // is not running an application that is listening
if (UDFNUML == timeout) { if (UDFNUML == timeout) {
transmit_previous_timeout = 1; transmit_previous_timeout = 1;
return -1; return;
} }
// has the USB gone offline? // has the USB gone offline?
if (!usb_configuration) return -1; if ( ! usb_configuration)
return;
// get ready to try checking again // get ready to try checking again
intr_state = SREG; intr_state = SREG;
cli(); cli();
@ -459,7 +462,6 @@ int8_t usb_serial_putchar(uint8_t c)
if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A; if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
SREG = intr_state; SREG = intr_state;
return 0;
} }

View File

@ -20,7 +20,7 @@ uint8_t usb_serial_available(void); // number of bytes in receive buffer
void usb_serial_flush_input(void); // discard any buffered input void usb_serial_flush_input(void); // discard any buffered input
// transmitting data // transmitting data
int8_t usb_serial_putchar(uint8_t c); // transmit a character void serial_writechar(uint8_t c); // Transmit a character.
int8_t usb_serial_putchar_nowait(uint8_t c); // transmit a character, do not wait int8_t usb_serial_putchar_nowait(uint8_t c); // transmit a character, do not wait
int8_t usb_serial_write(const uint8_t *buffer, uint16_t size); // transmit a buffer int8_t usb_serial_write(const uint8_t *buffer, uint16_t size); // transmit a buffer
void usb_serial_flush_output(void); // immediately transmit any buffered output void usb_serial_flush_output(void); // immediately transmit any buffered output