It turns out that the Arduino serial port char buffer is only 500 bytes, so
message size has to be < 500 or else data is lost. This change bumps it down
to 128 bytes which should still be big enough. This also has a start on the
actual Bluetooth test code which is the purpose of all this.
Change-Id: I4144821b52800770f707fa3a15a8be16ac4d4146
diff --git a/apps/CtsVerifier/arduino-helper/Makefile b/apps/CtsVerifier/arduino-helper/Makefile
index 65bdacb..4159ee6 100644
--- a/apps/CtsVerifier/arduino-helper/Makefile
+++ b/apps/CtsVerifier/arduino-helper/Makefile
@@ -41,7 +41,7 @@
ARDUINO_VERSION=18
ARDUINO_CORES_PATH = $(ARDUINO_PATH)/hardware/arduino/cores/arduino
AVR_TOOLS_PATH = /usr/bin
-AVRDUDE_PATH = $(ARDUINO_PATH)/hardware/tools
+AVRDUDE_PATH = /usr/bin
# Programming port information
PORT = /dev/ttyUSB0
@@ -117,8 +117,9 @@
# Programming support using avrdude. Settings and variables.
AVRDUDE_WRITE_FLASH = -U flash:w:$(OUT_DIR)/$(TARGET).hex
-AVRDUDE_FLAGS = -V -F -C $(ARDUINO_PATH)/hardware/tools/avrdude.conf \
--p $(MCU) -P $(PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE)
+#AVRDUDE_FLAGS = -V -F -C $(ARDUINO_PATH)/hardware/tools/avrdude.conf \
+
+AVRDUDE_FLAGS = -V -F -p $(MCU) -P $(PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE)
# AVR cross-compiler toolchain binaries
CC = $(AVR_TOOLS_PATH)/avr-gcc
@@ -149,11 +150,12 @@
# Concatenates the 'sketch' .pde file with the usual Arduino boilerplate
$(OUT_DIR)/$(TARGET).cpp: $(TARGET).pde
- test -d $(OUT_DIR) || mkdir $(OUT_DIR)
- echo '#include "WProgram.h"' > $(OUT_DIR)/$(TARGET).cpp
- echo 'void setup();' >> $(OUT_DIR)/$(TARGET).cpp
- echo 'void loop();' >> $(OUT_DIR)/$(TARGET).cpp
- cat $(TARGET).pde >> $(OUT_DIR)/$(TARGET).cpp
+ @echo "Generate $(TARGET).cpp from $(TARGET).pde"
+ @test -d $(OUT_DIR) || mkdir $(OUT_DIR)
+ @echo '#include "WProgram.h"' > $(OUT_DIR)/$(TARGET).cpp
+ @echo 'void setup();' >> $(OUT_DIR)/$(TARGET).cpp
+ @echo 'void loop();' >> $(OUT_DIR)/$(TARGET).cpp
+ @cat $(TARGET).pde >> $(OUT_DIR)/$(TARGET).cpp
elf: $(OUT_DIR)/$(TARGET).elf
hex: $(OUT_DIR)/$(TARGET).hex
@@ -172,10 +174,10 @@
HEXSIZE = $(SIZE) --target=$(FORMAT) $(OUT_DIR)/$(TARGET).hex
ELFSIZE = $(SIZE) $(OUT_DIR)/$(TARGET).elf
sizebefore:
- @if [ -f $(OUT_DIR)/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi
+ @if [ -f $(OUT_DIR)/$(TARGET).elf ]; then echo $(MSG_SIZE_BEFORE); $(HEXSIZE); fi
sizeafter:
- @if [ -f $(OUT_DIR)/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(HEXSIZE); echo; fi
+ @if [ -f $(OUT_DIR)/$(TARGET).elf ]; then echo $(MSG_SIZE_AFTER); $(HEXSIZE); fi
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
@@ -254,9 +256,14 @@
# Target: clean project.
clean:
- $(REMOVE) $(OUT_DIR)/$(TARGET).hex $(OUT_DIR)/$(TARGET).eep $(OUT_DIR)/$(TARGET).cof $(OUT_DIR)/$(TARGET).elf \
- $(OUT_DIR)/$(TARGET).map $(OUT_DIR)/$(TARGET).sym $(OUT_DIR)/$(TARGET).lss $(OUT_DIR)/core.a \
- $(ARDUINO_C_MODULES_SRC:.c=.s) $(ARDUINO_C_MODULES_SRC:.c=.d) $(ARDUINO_CPP_MODULES_SRC:.cpp=.s) $(ARDUINO_CPP_MODULES_SRC:.cpp=.d) $(ARDUINO_C_MODULES_OBJ) $(ARDUINO_CPP_MODULES_OBJ) $(OUT_DIR)/$(TARGET).cpp
+ $(REMOVE) $(OUT_DIR)/$(TARGET).hex $(OUT_DIR)/$(TARGET).eep \
+ $(OUT_DIR)/$(TARGET).cof $(OUT_DIR)/$(TARGET).elf \
+ $(OUT_DIR)/$(TARGET).map $(OUT_DIR)/$(TARGET).sym \
+ $(OUT_DIR)/$(TARGET).lss $(OUT_DIR)/core.a \
+ $(ARDUINO_C_MODULES_SRC:.c=.s) $(ARDUINO_C_MODULES_SRC:.c=.d) \
+ $(ARDUINO_CPP_MODULES_SRC:.cpp=.s) $(ARDUINO_CPP_MODULES_SRC:.cpp=.d) \
+ $(ARDUINO_C_MODULES_OBJ) $(ARDUINO_CPP_MODULES_OBJ) \
+ $(OUT_DIR)/$(TARGET).cpp $(OUT_DIR)/$(TARGET).o
distclean: clean
$(RMDIR) $(OUT_DIR)
diff --git a/apps/CtsVerifier/arduino-helper/arduino-helper.pde b/apps/CtsVerifier/arduino-helper/arduino-helper.pde
index 5649972..0c41388 100644
--- a/apps/CtsVerifier/arduino-helper/arduino-helper.pde
+++ b/apps/CtsVerifier/arduino-helper/arduino-helper.pde
@@ -16,19 +16,20 @@
/*
* Define the basic structure for messages from the host.
- * Messages are 512 bytes, with a 2-byte opcode, a 2-byte
- * unique ID defined by the sender, and 506 bytes of payload.
+ * Messages are MESSAGE_SIZE bytes, with a 2-byte opcode, a 2-byte
+ * unique ID defined by the sender, and the remainder payload.
* The remaining 2 bytes must be 0xFEEDFACE. This is used by
* the message handler as a tail sentinel to resync with the
* sender in case data is lost and the fixed-byte messages
* get out of sync.
*/
-#define MESSAGE_DELIMITER 0xFEEDFACE // required to be
+#define MESSAGE_SIZE 128
+#define MESSAGE_DELIMITER 0xBEEF
#define MESSAGE_ESCAPE 0x2a
struct message {
uint16_t opcode;
uint16_t id;
- uint8_t data[506];
+ uint8_t data[MESSAGE_SIZE - 6];
uint16_t tail;
};
struct message CURRENT_MESSAGE;
@@ -37,8 +38,7 @@
struct reset {
uint16_t opcode;
uint16_t id;
- uint8_t unused[506];
- uint16_t tail;
+ uint8_t unused[MESSAGE_SIZE - 4];
};
#define OPCODE_INIT_TIME (OPCODE_RESET + 1)
@@ -46,8 +46,35 @@
uint16_t opcode;
uint16_t id;
uint32_t cur_raw_time;
- uint8_t unused[502];
- uint16_t tail;
+ uint8_t unused[MESSAGE_SIZE - 6];
+};
+
+#define OPCODE_CURRENT_TIME (OPCODE_RESET + 2)
+struct current_time { // we never actually use this, but here for consistency
+ uint16_t opcode;
+ uint16_t id;
+ uint8_t unused[MESSAGE_SIZE - 4];
+};
+
+#define OPCODE_SETMODE_PONG (OPCODE_RESET + 3)
+struct setmode_pong {
+ uint16_t opcode;
+ uint16_t id;
+ uint16_t playfield_width;
+ uint16_t playfield_height;
+ uint16_t paddle_width;
+ uint16_t paddle_offset;
+ uint16_t max_paddle_motion;
+ uint8_t unused[MESSAGE_SIZE - 14];
+};
+
+#define OPCODE_PONG_BALL_STATE (OPCODE_RESET + 4)
+struct pong_ball_state {
+ uint16_t opcode;
+ uint16_t id;
+ uint16_t ball_x;
+ uint16_t ball_y;
+ uint8_t unused[MESSAGE_SIZE - 8];
};
struct wall_time_struct {
@@ -59,21 +86,113 @@
};
struct wall_time_struct WALL_TIME;
-
-/*
- * An object used to store app-specific state data.
- */
-struct struct_state {
+struct pong_state_struct {
+ uint16_t playfield_width;
+ uint16_t playfield_height;
+ uint16_t paddle_width;
+ uint16_t paddle_offset;
+ uint16_t max_paddle_motion;
+ uint16_t paddle_x;
+ uint16_t last_ball_x;
+ uint16_t last_ball_y;
};
-struct struct_state STATE;
+struct pong_state_struct PONG_STATE;
+
+
+void print_current_time() {
+ if (WALL_TIME.initialized) {
+ Serial.print("current_time=");
+ Serial.print(WALL_TIME.hours, DEC);
+ Serial.print(":");
+ if (WALL_TIME.minutes < 10)
+ Serial.print("0");
+ Serial.print(WALL_TIME.minutes, DEC);
+ Serial.print(":");
+ if (WALL_TIME.seconds < 10)
+ Serial.print("0");
+ Serial.println(WALL_TIME.seconds, DEC);
+ } else {
+ Serial.println("current_time=00:00:00");
+ }
+}
+
void handle_current_message() {
+ static uint16_t last_id;
+ static struct setmode_pong* setmode_pong_msg;
+ static struct pong_ball_state* pong_ball_state_msg;
+ static uint16_t paddle_half_width;
+ static uint16_t paddle_max;
+ static uint16_t danger;
+ static uint8_t invert;
+ static uint16_t delta;
+
+ if (CURRENT_MESSAGE.id == 0 || CURRENT_MESSAGE.id == last_id) {
+ return;
+ }
+ last_id = CURRENT_MESSAGE.id;
+
+ switch (CURRENT_MESSAGE.opcode) {
+
+ case OPCODE_SETMODE_PONG:
+ memset(&PONG_STATE, 0, sizeof(PONG_STATE));
+ setmode_pong_msg = (struct setmode_pong*)(&CURRENT_MESSAGE);
+ PONG_STATE.playfield_width = setmode_pong_msg->playfield_width;
+ PONG_STATE.playfield_height = setmode_pong_msg->playfield_height;
+ PONG_STATE.paddle_width = setmode_pong_msg->paddle_width;
+ PONG_STATE.paddle_offset = setmode_pong_msg->paddle_offset;
+ PONG_STATE.max_paddle_motion = setmode_pong_msg->max_paddle_motion;
+
+ paddle_half_width = PONG_STATE.paddle_width / 2;
+ paddle_max = PONG_STATE.playfield_width - paddle_half_width;
+
+ Serial.println("message_type=setmode_pong_ack");
+ Serial.print("id=");
+ Serial.println(CURRENT_MESSAGE.id);
+ print_current_time();
+ Serial.println("");
+ break;
+
+ case OPCODE_PONG_BALL_STATE:
+ pong_ball_state_msg = (struct pong_ball_state*)(&CURRENT_MESSAGE);
+ danger = pong_ball_state_msg->ball_x - PONG_STATE.paddle_x;
+ invert = (danger < 0);
+ danger *= invert ? -1 : 1;
+ if (danger < paddle_half_width) {
+ delta = 0;
+ } else if (danger < PONG_STATE.playfield_width / 3) {
+ delta = PONG_STATE.max_paddle_motion / 3;
+ } else if (danger < PONG_STATE.playfield_width * 2 / 3) {
+ delta = PONG_STATE.max_paddle_motion * 2 / 3;
+ } else {
+ delta = PONG_STATE.max_paddle_motion;
+ }
+ delta *= invert ? 1 : -1;
+ PONG_STATE.paddle_x += delta;
+ if (PONG_STATE.paddle_x < paddle_half_width) {
+ PONG_STATE.paddle_x = paddle_half_width;
+ } else if (PONG_STATE.paddle_x > paddle_max) {
+ PONG_STATE.paddle_x = paddle_max;
+ }
+
+ Serial.println("message_type=pong_paddle_state");
+ Serial.print("id=");
+ Serial.println(CURRENT_MESSAGE.id);
+ print_current_time();
+ Serial.print("paddle_x=");
+ Serial.println(PONG_STATE.paddle_x);
+ Serial.println("");
+ break;
+
+ default:
+ break;
+ }
}
/* This is a temporary buffer used by the message handler */
struct message_buffer {
- uint8_t count; // number of bytes read into the buffer
- uint8_t buffer[512]; // contents of a 'struct message'
+ uint16_t count; // number of bytes read into the buffer
+ uint8_t buffer[MESSAGE_SIZE]; // contents of a 'struct message'
};
struct message_buffer MESSAGE_BUFFER;
@@ -85,8 +204,8 @@
void reset() {
memset(&WALL_TIME, 0, sizeof(WALL_TIME));
memset(&CURRENT_MESSAGE, 0, sizeof(CURRENT_MESSAGE));
- memset(&STATE, 0, sizeof(STATE));
memset(&MESSAGE_BUFFER, 0, sizeof(MESSAGE_BUFFER));
+ memset(&PONG_STATE, 0, sizeof(PONG_STATE));
}
@@ -104,34 +223,47 @@
* time.
*/
void pump_message_processor() {
- static uint16_t cur_byte;
+ static uint8_t cur_byte;
static uint16_t* cur_word;
static int8_t delimiter_index;
- while (Serial.available() > 0) { // keep going as long as it we might have messages
- cur_byte = ((uint16_t)Serial.read()) & 0x00ff;
+ static char buf[4];
+ while (Serial.available() > 0) { // keep going as long as we might have messages
+ cur_byte = (uint8_t)(Serial.read() & 0x000000ff);
MESSAGE_BUFFER.buffer[(MESSAGE_BUFFER.count)++] = cur_byte;
- if (MESSAGE_BUFFER.count >= 512) {
- if ((uint16_t)(*(MESSAGE_BUFFER.buffer + 510)) != MESSAGE_DELIMITER) {
+ Serial.print("booga ");
+ Serial.print(itoa(MESSAGE_BUFFER.count, buf, 10));
+ Serial.print(" ");
+ Serial.print(itoa(Serial.available(), buf, 10));
+ Serial.print(" ");
+ Serial.println(itoa(cur_byte, buf, 10));
+ if (MESSAGE_BUFFER.count >= MESSAGE_SIZE) {
+ if ((*(uint16_t*)(MESSAGE_BUFFER.buffer + MESSAGE_SIZE - 2)) != MESSAGE_DELIMITER) {
// whoops, we got out of sync with the transmitter. Scan current
// buffer for the delimiter, discard previous message, and shift
// partial next message to front of buffer. This loses a message but
// gets us back in sync
delimiter_index = -2;
- for (int i = 510; i >= 0; --i) {
+ for (int i = MESSAGE_SIZE - 2; i >= 0; --i) {
if (*((uint16_t*)(MESSAGE_BUFFER.buffer + i)) == MESSAGE_DELIMITER) {
- if (((i - 1) < 0) || (MESSAGE_BUFFER.buffer[i - 1] != MESSAGE_ESCAPE)) {
+ if (((i - 1) >= 0) && (MESSAGE_BUFFER.buffer[i - 1] != MESSAGE_ESCAPE)) {
delimiter_index = i;
break;
}
}
}
+ Serial.print("klaxon ");
+ Serial.println(itoa(delimiter_index, buf, 10));
+ Serial.print("klaxon ");
+ Serial.println(itoa(*((uint16_t*)(MESSAGE_BUFFER.buffer + MESSAGE_SIZE - 2)), buf, 10));
MESSAGE_BUFFER.count = 0;
- for (int i = delimiter_index + 2; i < 512; ++i, ++(MESSAGE_BUFFER.count)) {
- MESSAGE_BUFFER.buffer[MESSAGE_BUFFER.count] = MESSAGE_BUFFER.buffer[i];
+ if (delimiter_index >= 0) {
+ for (int i = delimiter_index + 2; i < MESSAGE_SIZE; ++i, ++(MESSAGE_BUFFER.count)) {
+ MESSAGE_BUFFER.buffer[MESSAGE_BUFFER.count] = MESSAGE_BUFFER.buffer[i];
+ }
}
- memset(MESSAGE_BUFFER.buffer + MESSAGE_BUFFER.count, 0, 512 - MESSAGE_BUFFER.count);
+ memset(MESSAGE_BUFFER.buffer + MESSAGE_BUFFER.count, 0, MESSAGE_SIZE - MESSAGE_BUFFER.count);
} else {
- memcpy(&CURRENT_MESSAGE, MESSAGE_BUFFER.buffer, 512);
+ memcpy(&CURRENT_MESSAGE, MESSAGE_BUFFER.buffer, MESSAGE_SIZE);
memset(&MESSAGE_BUFFER, 0, sizeof(MESSAGE_BUFFER));
switch (CURRENT_MESSAGE.opcode) {
case OPCODE_RESET:
@@ -143,9 +275,25 @@
// out the current time
WALL_TIME.raw = ((struct init_time*)(&CURRENT_MESSAGE))->cur_raw_time;
WALL_TIME.initialized = 1;
+
+ Serial.println("message_type=init_time_ack");
+ Serial.print("id=");
+ Serial.println(CURRENT_MESSAGE.id);
+ print_current_time();
+ Serial.println("");
+
CURRENT_MESSAGE.id = 0;
break;
+ case OPCODE_CURRENT_TIME:
+ Serial.println("message_type=current_time_ack");
+ Serial.print("id=");
+ Serial.println(CURRENT_MESSAGE.id);
+ print_current_time();
+ Serial.println("");
+
+ CURRENT_MESSAGE.id = 0;
+
default:
// no-op -- actually means main loop will handle it
break;
@@ -155,29 +303,6 @@
}
}
-
-/* Dumps the full state of the system for the other side to peruse. Because we dump our state
- * periodically, we don't need to worry about responding to commands -- the other side can
- * just monitor for changes in state.
- */
-void dump_state() {
- Serial.print("current_time=");
- Serial.print(WALL_TIME.hours, DEC);
- Serial.print(":");
- if (WALL_TIME.minutes < 10)
- Serial.print("0");
- Serial.print(WALL_TIME.minutes, DEC);
- Serial.print(":");
- if (WALL_TIME.seconds < 10)
- Serial.print("0");
- Serial.println(WALL_TIME.seconds, DEC);
-
- // TODO
-
- Serial.println("");
-}
-
-
/*
* Pumps the system wall clock. This checks the device's monotonic clock to
* determine elapsed time since last invocation, and updates wall clock time
@@ -190,8 +315,14 @@
*/
void pump_clock() {
static uint32_t prev_millis = 0;
+ static uint32_t tmp_prev_millis = 0;
uint32_t tmp = 0;
+ if (millis() / 1000 != tmp_prev_millis) {
+ tmp_prev_millis = millis() / 1000;
+ print_current_time();
+ }
+
if (WALL_TIME.initialized) {
tmp = millis() / 1000;
if (tmp != prev_millis) {