Merge pull request #690 from fredizzimo/unit_test

Add Unit Testing support
pull/697/head
Jack Humbert 8 years ago committed by GitHub
commit 4fd5ac8326

3
.gitmodules vendored

@ -7,3 +7,6 @@
[submodule "lib/ugfx"]
path = lib/ugfx
url = https://bitbucket.org/Tectu/ugfx
[submodule "lib/googletest"]
path = lib/googletest
url = https://github.com/google/googletest

@ -10,7 +10,10 @@ env:
global:
- secure: vBTSL34BDPxDilKUuTXqU4CJ26Pv5hogD2nghatkxSQkI1/jbdnLj/DQdPUrMJFDIY6TK3AltsBx72MaMsLQ1JO/Ou24IeHINHXzUC1FlS9yQa48cpxnhX5kzXNyGs3oa0qaFbvnr7RgYRWtmD52n4bIZuSuW+xpBv05x2OCizdT2ZonH33nATaHGFasxROm4qYZ241VfzcUv766V6RVHgL4x9V08warugs+RENVkfzxxwhk3NmkrISabze0gSVJLHBPHxroZC6EUcf/ocobcuDrCwFqtEt90i7pNIAFUE7gZsN2uE75LmpzAWin21G7lLPcPL2k4FJVd8an1HiP2WmscJU6U89fOfMb2viObnKcCzebozBCmKGtHEuXZo9FcReOx49AnQSpmESJGs+q2dL/FApkTjQiyT4J6O5dJpoww0/r57Wx0cmmqjETKBb5rSgXM51Etk3wO09mvcPHsEwrT7qH8r9XWdyCDoEn7FCLX3/LYnf/D4SmZ633YPl5gv3v9XEwxR5+04akjgnvWDSNIaDbWBdxHNb7l4pMc+WR1bwCyMyA7KXj0RrftEGOrm9ZRLe6BkbT4cycA+j77nbPOMcyZChliV9pPQos+4TOJoTzcK2L8yWVoY409aDNVuAjdP6Yum0R2maBGl/etLmIMpJC35C5/lZ+dUNjJAM=
script:
- make all-keyboards AUTOGEN=true
- make $TARGET AUTOGEN=$AUTOGEN
env:
- TARGET=all-keyboards AUTOGEN=true
- TARGET=test AUTOGEN=false
addons:
apt:
packages:
@ -22,4 +25,7 @@ addons:
- binutils-arm-none-eabi
- libnewlib-arm-none-eabi
- diffutils
after_success: bash util/travis_compiled_push.sh
after_success:
if [ "$AUTOGEN" == "true" ]; then
bash util/travis_compiled_push.sh;
fi

@ -2,6 +2,10 @@ ifndef VERBOSE
.SILENT:
endif
# Never run this makefile in parallel, as it could screw things up
# It won't affect the submakes, so you still get the speedup from specifying -jx
.NOTPARALLEL:
# Allow the silent with lower caps to work the same way as upper caps
ifdef silent
SILENT = $(silent)
@ -28,6 +32,7 @@ ABS_ROOT_MAKEFILE := $(abspath $(ROOT_MAKEFILE))
ABS_STARTING_DIR := $(dir $(ABS_STARTING_MAKEFILE))
ABS_ROOT_DIR := $(dir $(ABS_ROOT_MAKEFILE))
STARTING_DIR := $(subst $(ABS_ROOT_DIR),,$(ABS_STARTING_DIR))
TEST_DIR := $(ROOT_DIR)/.build/test
MAKEFILE_INCLUDED=yes
@ -224,6 +229,8 @@ define PARSE_RULE
# PARSE_ALL_KEYBOARDS
ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,allkb),true)
$$(eval $$(call PARSE_ALL_KEYBOARDS))
else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,test),true)
$$(eval $$(call PARSE_TEST))
# If the rule starts with the name of a known keyboard, then continue
# the parsing from PARSE_KEYBOARD
else ifeq ($$(call TRY_TO_MATCH_RULE_FROM_LIST,$$(KEYBOARDS)),true)
@ -356,7 +363,6 @@ define PARSE_KEYMAP
MAKE_TARGET := $$(patsubst -%,%,$$(RULE))
# We need to generate an unique indentifer to append to the COMMANDS list
COMMAND := COMMAND_KEYBOARD_$$(CURRENT_KB)_SUBPROJECT_$(CURRENT_SP)_KEYMAP_$$(CURRENT_KM)
COMMANDS += $$(COMMAND)
# If we are compiling a keyboard without a subproject, we want to display just the name
# of the keyboard, otherwise keyboard/subproject
ifeq ($$(CURRENT_SP),)
@ -368,13 +374,18 @@ define PARSE_KEYMAP
KB_SP := $(BOLD)$$(KB_SP)$(NO_COLOR)
# Specify the variables that we are passing forward to submake
MAKE_VARS := KEYBOARD=$$(CURRENT_KB) SUBPROJECT=$$(CURRENT_SP) KEYMAP=$$(CURRENT_KM)
MAKE_VARS += VERBOSE=$(VERBOSE) COLOR=$(COLOR)
# And the first part of the make command
MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_keyboard.mk $$(MAKE_TARGET)
# The message to display
MAKE_MSG := $$(MSG_MAKE_KB)
# We run the command differently, depending on if we want more output or not
# The true version for silent output and the false version otherwise
$$(eval $$(call BUILD))
endef
define BUILD
MAKE_VARS += VERBOSE=$(VERBOSE) COLOR=$(COLOR)
COMMANDS += $$(COMMAND)
COMMAND_true_$$(COMMAND) := \
printf "$$(MAKE_MSG)" | \
$$(MAKE_MSG_FORMAT); \
@ -388,7 +399,10 @@ define PARSE_KEYMAP
fi;
COMMAND_false_$$(COMMAND) := \
printf "$$(MAKE_MSG)\n\n"; \
$$(MAKE_CMD) $$(MAKE_VARS) SILENT=false;
$$(MAKE_CMD) $$(MAKE_VARS) SILENT=false; \
if [ $$$$? -gt 0 ]; \
then error_occured=1; \
fi;
endef
# Just parse all the keymaps for a specifc keyboard
@ -396,6 +410,41 @@ define PARSE_ALL_KEYMAPS
$$(eval $$(call PARSE_ALL_IN_LIST,PARSE_KEYMAP,$$(KEYMAPS)))
endef
define BUILD_TEST
TEST_NAME := $1
MAKE_TARGET := $2
COMMAND := $1
MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_test.mk $$(MAKE_TARGET)
MAKE_VARS := TEST=$$(TEST_NAME)
MAKE_MSG := $$(MSG_MAKE_TEST)
$$(eval $$(call BUILD))
ifneq ($$(MAKE_TARGET),clean)
TEST_EXECUTABLE := $$(TEST_DIR)/$$(TEST_NAME).elf
TESTS += $$(TEST_NAME)
TEST_MSG := $$(MSG_TEST)
$$(TEST_NAME)_COMMAND := \
printf "$$(TEST_MSG)\n"; \
$$(TEST_EXECUTABLE); \
if [ $$$$? -gt 0 ]; \
then error_occured=1; \
fi; \
printf "\n";
endif
endef
define PARSE_TEST
TESTS :=
TEST_NAME := $$(firstword $$(subst -, ,$$(RULE)))
TEST_TARGET := $$(subst $$(TEST_NAME),,$$(subst $$(TEST_NAME)-,,$$(RULE)))
ifeq ($$(TEST_NAME),all)
MATCHED_TESTS := $$(TEST_LIST)
else
MATCHED_TESTS := $$(foreach TEST,$$(TEST_LIST),$$(if $$(findstring $$(TEST_NAME),$$(TEST)),$$(TEST),))
endif
$$(foreach TEST,$$(MATCHED_TESTS),$$(eval $$(call BUILD_TEST,$$(TEST),$$(TEST_TARGET))))
endef
# Set the silent mode depending on if we are trying to compile multiple keyboards or not
# By default it's on in that case, but it can be overriden by specifying silent=false
# from the command line
@ -440,12 +489,13 @@ $(SUBPROJECTS): %: %-allkm
# But we return the error code at the end, to trigger travis failures
+error_occured=0; \
$(foreach COMMAND,$(COMMANDS),$(RUN_COMMAND)) \
if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi
if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi;\
$(foreach TEST,$(TESTS),$($(TEST)_COMMAND)) \
if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi;\
# All should compile everything
.PHONY: all
all: all-keyboards
all: all-keyboards test-all
# Define some shortcuts, mostly for compability with the old syntax
.PHONY: all-keyboards
@ -454,9 +504,16 @@ all-keyboards: allkb-allsp-allkm
.PHONY: all-keyboards-defaults
all-keyboards-defaults: allkb-allsp-default
.PHONY: test
test: test-all
.PHONY: test-clean
test-clean: test-all-clean
# Generate the version.h file
GIT_VERSION := $(shell git describe --abbrev=6 --dirty --always --tags 2>/dev/null || date +"%Y-%m-%d-%H:%M:%S")
BUILD_DATE := $(shell date +"%Y-%m-%d-%H:%M:%S")
$(shell echo '#define QMK_VERSION "$(GIT_VERSION)"' > $(ROOT_DIR)/quantum/version.h)
$(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h)
$(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h)
include $(ROOT_DIR)/testlist.mk

@ -4,19 +4,7 @@ endif
.DEFAULT_GOAL := all
include message.mk
# Directory common source filess exist
TOP_DIR = .
TMK_DIR = tmk_core
TMK_PATH = $(TOP_DIR)/$(TMK_DIR)
LIB_PATH = $(TOP_DIR)/lib
QUANTUM_DIR = quantum
QUANTUM_PATH = $(TOP_DIR)/$(QUANTUM_DIR)
BUILD_DIR := $(TOP_DIR)/.build
include common.mk
ifneq ($(SUBPROJECT),)
TARGET ?= $(KEYBOARD)_$(SUBPROJECT)_$(KEYMAP)
@ -35,6 +23,16 @@ ifdef master
MASTER = $(master)
endif
ifeq ($(MASTER),right)
OPT_DEFS += -DMASTER_IS_ON_RIGHT
else
ifneq ($(MASTER),left)
$(error MASTER does not have a valid value(left/right))
endif
endif
KEYBOARD_PATH := keyboards/$(KEYBOARD)
KEYBOARD_C := $(KEYBOARD_PATH)/$(KEYBOARD).c
@ -167,12 +165,8 @@ ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
endif
ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
SERIAL_DIR = $(QUANTUM_DIR)/serial_link
SERIAL_PATH = $(QUANTUM_PATH)/serial_link
SERIAL_SRC = $(wildcard $(SERIAL_PATH)/protocol/*.c)
SERIAL_SRC += $(wildcard $(SERIAL_PATH)/system/*.c)
SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
OPT_DEFS += -DSERIAL_LINK_ENABLE
OPT_DEFS += $(SERIAL_DEFS)
VAPTH += $(SERIAL_PATH)
endif
@ -185,15 +179,14 @@ ifneq ($(SUBPROJECT),)
VPATH += $(SUBPROJECT_PATH)
endif
VPATH += $(KEYBOARD_PATH)
VPATH += $(TOP_DIR)
VPATH += $(TMK_PATH)
VPATH += $(QUANTUM_PATH)
VPATH += $(QUANTUM_PATH)/keymap_extras
VPATH += $(QUANTUM_PATH)/audio
VPATH += $(QUANTUM_PATH)/process_keycode
VPATH += $(COMMON_VPATH)
include $(TMK_PATH)/common.mk
SRC += $(TMK_COMMON_SRC)
OPT_DEFS += $(TMK_COMMON_DEFS)
EXTRALDFLAGS += $(TMK_COMMON_LDFLAGS)
ifeq ($(PLATFORM),AVR)
include $(TMK_PATH)/protocol/lufa.mk
include $(TMK_PATH)/avr.mk
@ -205,17 +198,24 @@ ifeq ($(strip $(VISUALIZER_ENABLE)), yes)
include $(VISUALIZER_PATH)/visualizer.mk
endif
OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT)
$(KEYMAP_OUTPUT)_SRC := $(SRC)
$(KEYMAP_OUTPUT)_DEFS := $(OPT_DEFS) -DQMK_KEYBOARD=\"$(KEYBOARD)\" -DQMK_KEYMAP=\"$(KEYMAP)\"
$(KEYMAP_OUTPUT)_INC := $(EXTRAINCDIRS) $(VPATH)
$(KEYMAP_OUTPUT)_INC := $(VPATH) $(EXTRAINCDIRS)
$(KEYMAP_OUTPUT)_CONFIG := $(CONFIG_H)
$(KEYBOARD_OUTPUT)_SRC := $(CHIBISRC)
$(KEYBOARD_OUTPUT)_DEFS := $(PROJECT_DEFS)
$(KEYBOARD_OUTPUT)_INC := $(PROJECT_INC)
$(KEYBOARD_OUTPUT)_CONFIG := $(PROJECT_CONFIG)
# Default target.
all: build sizeafter
# Change the build target to build a HEX file or a library.
build: elf hex
#build: elf hex eep lss sym
#build: lib
include $(TMK_PATH)/rules.mk

@ -0,0 +1,57 @@
ifndef VERBOSE
.SILENT:
endif
.DEFAULT_GOAL := all
include common.mk
TARGET=test/$(TEST)
GTEST_OUTPUT = $(BUILD_DIR)/gtest
TEST_OBJ = $(BUILD_DIR)/test_obj
OUTPUTS := $(TEST_OBJ)/$(TEST) $(GTEST_OUTPUT)
GTEST_INC := \
$(LIB_PATH)/googletest/googletest/include\
$(LIB_PATH)/googletest/googlemock/include\
GTEST_INTERNAL_INC :=\
$(LIB_PATH)/googletest/googletest\
$(LIB_PATH)/googletest/googlemock
$(GTEST_OUTPUT)_SRC :=\
googletest/src/gtest-all.cc\
googletest/src/gtest_main.cc\
googlemock/src/gmock-all.cc
$(GTEST_OUTPUT)_DEFS :=
$(GTEST_OUTPUT)_INC := $(GTEST_INC) $(GTEST_INTERNAL_INC)
LDFLAGS += -lstdc++ -lpthread -shared-libgcc
CREATE_MAP := no
VPATH +=\
$(LIB_PATH)/googletest\
$(LIB_PATH)/googlemock
all: elf
VPATH += $(COMMON_VPATH)
include $(TMK_PATH)/common.mk
include $(QUANTUM_PATH)/serial_link/tests/rules.mk
$(TEST_OBJ)/$(TEST)_SRC := $($(TEST)_SRC)
$(TEST_OBJ)/$(TEST)_INC := $($(TEST)_INC) $(VPATH) $(GTEST_INC)
$(TEST_OBJ)/$(TEST)_DEFS := $($(TEST)_DEFS)
include $(TMK_PATH)/native.mk
include $(TMK_PATH)/rules.mk
$(shell mkdir -p $(BUILD_DIR)/test 2>/dev/null)
$(shell mkdir -p $(TEST_OBJ) 2>/dev/null)

@ -0,0 +1,26 @@
include message.mk
# Directory common source files exist
TOP_DIR = .
TMK_DIR = tmk_core
TMK_PATH = $(TOP_DIR)/$(TMK_DIR)
LIB_PATH = $(TOP_DIR)/lib
QUANTUM_DIR = quantum
QUANTUM_PATH = $(TOP_DIR)/$(QUANTUM_DIR)
BUILD_DIR := $(TOP_DIR)/.build
SERIAL_DIR := $(QUANTUM_DIR)/serial_link
SERIAL_PATH := $(QUANTUM_PATH)/serial_link
SERIAL_SRC := $(wildcard $(SERIAL_PATH)/protocol/*.c)
SERIAL_SRC += $(wildcard $(SERIAL_PATH)/system/*.c)
SERIAL_DEFS += -DSERIAL_LINK_ENABLE
COMMON_VPATH := $(TOP_DIR)
COMMON_VPATH += $(TMK_PATH)
COMMON_VPATH += $(QUANTUM_PATH)
COMMON_VPATH += $(QUANTUM_PATH)/keymap_extras
COMMON_VPATH += $(QUANTUM_PATH)/audio
COMMON_VPATH += $(QUANTUM_PATH)/process_keycode
COMMON_VPATH += $(SERIAL_PATH)

@ -0,0 +1 @@
Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780

@ -69,3 +69,11 @@ define GENERATE_MSG_MAKE_KB
endif
endef
MSG_MAKE_KB = $(eval $(call GENERATE_MSG_MAKE_KB))$(MSG_MAKE_KB_ACTUAL)
define GENERATE_MSG_MAKE_TEST
MSG_MAKE_TEST_ACTUAL := Making test $(BOLD)$(TEST_NAME)$(NO_COLOR)
ifneq ($$(MAKE_TARGET),)
MSG_MAKE_TEST_ACTUAL += with target $(BOLD)$$(MAKE_TARGET)$(NO_COLOR)
endif
endef
MSG_MAKE_TEST = $(eval $(call GENERATE_MSG_MAKE_TEST))$(MSG_MAKE_TEST_ACTUAL)
MSG_TEST = Testing $(BOLD)$(TEST_NAME)$(NO_COLOR)

@ -31,9 +31,6 @@ SOFTWARE.
// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
// http://www.stuartcheshire.org/papers/COBSforToN.pdf
#define MAX_FRAME_SIZE 1024
#define NUM_LINKS 2
typedef struct byte_stuffer_state {
uint16_t next_zero;
uint16_t data_pos;

@ -27,6 +27,9 @@ SOFTWARE.
#include <stdint.h>
#define MAX_FRAME_SIZE 1024
#define NUM_LINKS 2
void init_byte_stuffer(void);
void byte_stuffer_recv_byte(uint8_t link, uint8_t data);
void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size);

@ -31,6 +31,10 @@ SOFTWARE.
static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS];
static uint32_t num_remote_objects = 0;
void reinitialize_serial_link_transport(void) {
num_remote_objects = 0;
}
void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) {
unsigned int i;
for(i=0;i<_num_remote_objects;i++) {

@ -82,7 +82,7 @@ typedef struct { \
remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
return triple_buffer_read_internal(obj->object_size, tb); \
return (type*)triple_buffer_read_internal(obj->object_size, tb); \
}
#define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \
@ -112,7 +112,7 @@ typedef struct { \
remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
return triple_buffer_read_internal(obj->object_size, tb); \
return (type*)triple_buffer_read_internal(obj->object_size, tb); \
}
#define SLAVE_TO_MASTER_OBJECT(name, type) \
@ -139,12 +139,13 @@ typedef struct { \
uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
return triple_buffer_read_internal(obj->object_size, tb); \
return (type*)triple_buffer_read_internal(obj->object_size, tb); \
}
#define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name
void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects);
void reinitialize_serial_link_transport(void);
void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size);
void update_transport(void);

@ -22,70 +22,90 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <cgreen/cgreen.h>
#include <cgreen/mocks.h>
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <vector>
#include <algorithm>
extern "C" {
#include "serial_link/protocol/byte_stuffer.h"
#include "serial_link/protocol/byte_stuffer.c"
#include "serial_link/protocol/frame_validator.h"
#include "serial_link/protocol/physical.h"
}
static uint8_t sent_data[MAX_FRAME_SIZE*2];
static uint16_t sent_data_size;
using testing::_;
using testing::ElementsAreArray;
using testing::Args;
Describe(ByteStuffer);
BeforeEach(ByteStuffer) {
init_byte_stuffer();
sent_data_size = 0;
}
AfterEach(ByteStuffer) {}
class ByteStuffer : public ::testing::Test{
public:
ByteStuffer() {
Instance = this;
init_byte_stuffer();
}
void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
mock(data, size);
}
~ByteStuffer() {
Instance = nullptr;
}
MOCK_METHOD3(validator_recv_frame, void (uint8_t link, uint8_t* data, uint16_t size));
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
std::copy(data, data + size, std::back_inserter(sent_data));
}
std::vector<uint8_t> sent_data;
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
memcpy(sent_data + sent_data_size, data, size);
sent_data_size += size;
static ByteStuffer* Instance;
};
ByteStuffer* ByteStuffer::Instance = nullptr;
extern "C" {
void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
ByteStuffer::Instance->validator_recv_frame(link, data, size);
}
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
ByteStuffer::Instance->send_data(link, data, size);
}
}
Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
never_expect(validator_recv_frame);
TEST_F(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.Times(0);
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
never_expect(validator_recv_frame);
TEST_F(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.Times(0);
byte_stuffer_recv_byte(0, 0xFF);
}
Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
never_expect(validator_recv_frame);
TEST_F(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.Times(0);
byte_stuffer_recv_byte(0, 0x4A);
}
Ensure(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
never_expect(validator_recv_frame);
TEST_F(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.Times(0);
byte_stuffer_recv_byte(0, 1);
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_single_byte_valid_frame) {
TEST_F(ByteStuffer, receives_single_byte_valid_frame) {
uint8_t expected[] = {0x37};
expect(validator_recv_frame,
when(size, is_equal_to(1)),
when(data, is_equal_to_contents_of(expected, 1))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 2);
byte_stuffer_recv_byte(0, 0x37);
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_three_bytes_valid_frame) {
TEST_F(ByteStuffer, receives_three_bytes_valid_frame) {
uint8_t expected[] = {0x37, 0x99, 0xFF};
expect(validator_recv_frame,
when(size, is_equal_to(3)),
when(data, is_equal_to_contents_of(expected, 3))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 4);
byte_stuffer_recv_byte(0, 0x37);
byte_stuffer_recv_byte(0, 0x99);
@ -93,23 +113,19 @@ Ensure(ByteStuffer, receives_three_bytes_valid_frame) {
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_single_zero_valid_frame) {
TEST_F(ByteStuffer, receives_single_zero_valid_frame) {
uint8_t expected[] = {0};
expect(validator_recv_frame,
when(size, is_equal_to(1)),
when(data, is_equal_to_contents_of(expected, 1))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 1);
byte_stuffer_recv_byte(0, 1);
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_valid_frame_with_zeroes) {
TEST_F(ByteStuffer, receives_valid_frame_with_zeroes) {
uint8_t expected[] = {5, 0, 3, 0};
expect(validator_recv_frame,
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(expected, 4))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 2);
byte_stuffer_recv_byte(0, 5);
byte_stuffer_recv_byte(0, 2);
@ -118,17 +134,14 @@ Ensure(ByteStuffer, receives_valid_frame_with_zeroes) {
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_two_valid_frames) {
TEST_F(ByteStuffer, receives_two_valid_frames) {
uint8_t expected1[] = {5, 0};
uint8_t expected2[] = {3};
expect(validator_recv_frame,
when(size, is_equal_to(2)),
when(data, is_equal_to_contents_of(expected1, 2))
);
expect(validator_recv_frame,
when(size, is_equal_to(1)),
when(data, is_equal_to_contents_of(expected2, 1))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected1)));
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected2)));
byte_stuffer_recv_byte(1, 2);
byte_stuffer_recv_byte(1, 5);
byte_stuffer_recv_byte(1, 1);
@ -138,12 +151,10 @@ Ensure(ByteStuffer, receives_two_valid_frames) {
byte_stuffer_recv_byte(1, 0);
}
Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
uint8_t expected[] = {5, 7};
expect(validator_recv_frame,
when(size, is_equal_to(2)),
when(data, is_equal_to_contents_of(expected, 2))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(1, 3);
byte_stuffer_recv_byte(1, 1);
byte_stuffer_recv_byte(1, 0);
@ -153,12 +164,10 @@ Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
byte_stuffer_recv_byte(1, 0);
}
Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
uint8_t expected[] = {5, 7};
expect(validator_recv_frame,
when(size, is_equal_to(2)),
when(data, is_equal_to_contents_of(expected, 2))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 2);
byte_stuffer_recv_byte(0, 9);
byte_stuffer_recv_byte(0, 4); // This should have been zero
@ -169,16 +178,14 @@ Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
uint8_t expected[254];
int i;
for (i=0;i<254;i++) {
expected[i] = i + 1;
}
expect(validator_recv_frame,
when(size, is_equal_to(254)),
when(data, is_equal_to_contents_of(expected, 254))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 0xFF);
for (i=0;i<254;i++) {
byte_stuffer_recv_byte(0, i+1);
@ -186,17 +193,15 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
uint8_t expected[255];
int i;
for (i=0;i<254;i++) {
expected[i] = i + 1;
}
expected[254] = 7;
expect(validator_recv_frame,
when(size, is_equal_to(255)),
when(data, is_equal_to_contents_of(expected, 255))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 0xFF);
for (i=0;i<254;i++) {
byte_stuffer_recv_byte(0, i+1);
@ -206,17 +211,15 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
uint8_t expected[255];
int i;
for (i=0;i<254;i++) {
expected[i] = i + 1;
}
expected[254] = 0;
expect(validator_recv_frame,
when(size, is_equal_to(255)),
when(data, is_equal_to_contents_of(expected, 255))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 0xFF);
for (i=0;i<254;i++) {
byte_stuffer_recv_byte(0, i+1);
@ -226,7 +229,7 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
TEST_F(ByteStuffer, receives_two_long_frames_and_some_more) {
uint8_t expected[515];
int i;
int j;
@ -238,10 +241,8 @@ Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
for (i=0;i<7;i++) {
expected[254*2+i] = i + 1;
}
expect(validator_recv_frame,
when(size, is_equal_to(515)),
when(data, is_equal_to_contents_of(expected, 510))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
byte_stuffer_recv_byte(0, 0xFF);
for (i=0;i<254;i++) {
byte_stuffer_recv_byte(0, i+1);
@ -261,12 +262,10 @@ Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
TEST_F(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
uint8_t expected[MAX_FRAME_SIZE] = {};
expect(validator_recv_frame,
when(size, is_equal_to(MAX_FRAME_SIZE)),
when(data, is_equal_to_contents_of(expected, MAX_FRAME_SIZE))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
int i;
byte_stuffer_recv_byte(0, 1);
for(i=0;i<MAX_FRAME_SIZE;i++) {
@ -275,9 +274,10 @@ Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
TEST_F(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
uint8_t expected[1] = {0};
never_expect(validator_recv_frame);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.Times(0);
int i;
byte_stuffer_recv_byte(0, 1);
for(i=0;i<MAX_FRAME_SIZE;i++) {
@ -287,12 +287,10 @@ Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
TEST_F(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
uint8_t expected[1] = {1};
expect(validator_recv_frame,
when(size, is_equal_to(1)),
when(data, is_equal_to_contents_of(expected, 1))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
int i;
byte_stuffer_recv_byte(0, 1);
for(i=0;i<MAX_FRAME_SIZE;i++) {
@ -303,76 +301,68 @@ Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
byte_stuffer_recv_byte(0, 0);
}
Ensure(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
assert_that(sent_data_size, is_equal_to(0));
TEST_F(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
EXPECT_EQ(sent_data.size(), 0);
byte_stuffer_send_frame(0, NULL, 0);
}
Ensure(ByteStuffer, send_one_byte_frame) {
TEST_F(ByteStuffer, send_one_byte_frame) {
uint8_t data[] = {5};
byte_stuffer_send_frame(1, data, 1);
uint8_t expected[] = {2, 5, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_two_byte_frame) {
TEST_F(ByteStuffer, sends_two_byte_frame) {
uint8_t data[] = {5, 0x77};
byte_stuffer_send_frame(0, data, 2);
uint8_t expected[] = {3, 5, 0x77, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_one_byte_frame_with_zero) {
TEST_F(ByteStuffer, sends_one_byte_frame_with_zero) {
uint8_t data[] = {0};
byte_stuffer_send_frame(0, data, 1);
uint8_t expected[] = {1, 1, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
uint8_t data[] = {0, 9};
byte_stuffer_send_frame(1, data, 2);
uint8_t expected[] = {1, 2, 9, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
uint8_t data[] = {9, 0};
byte_stuffer_send_frame(1, data, 2);
uint8_t expected[] = {2, 9, 1, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
TEST_F(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
uint8_t data[] = {9, 0, 0x68};
byte_stuffer_send_frame(0, data, 3);
uint8_t expected[] = {2, 9, 2, 0x68, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
TEST_F(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
uint8_t data[] = {0, 0x55, 0};
byte_stuffer_send_frame(0, data, 3);
uint8_t expected[] = {1, 2, 0x55, 1, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
TEST_F(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
uint8_t data[] = {0, 0, 0};
byte_stuffer_send_frame(0, data, 3);
uint8_t expected[] = {1, 1, 1, 1, 0};
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) {
TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes) {
uint8_t data[254];
int i;
for(i=0;i<254;i++) {
@ -385,11 +375,10 @@ Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) {
expected[i] = i;
}
expected[255] = 0;
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) {
TEST_F(ByteStuffer, sends_frame_with_255_non_zeroes) {
uint8_t data[255];
int i;
for(i=0;i<255;i++) {
@ -404,17 +393,16 @@ Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) {
expected[255] = 2;
expected[256] = 255;
expected[257] = 0;
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
uint8_t data[255];
int i;
for(i=0;i<254;i++) {
data[i] = i + 1;
}
data[255] = 0;
data[254] = 0;
byte_stuffer_send_frame(0, data, 255);
uint8_t expected[258];
expected[0] = 0xFF;
@ -424,53 +412,46 @@ Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
expected[255] = 1;
expected[256] = 1;
expected[257] = 0;
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
EXPECT_THAT(sent_data, ElementsAreArray(expected));
}
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
uint8_t original_data[] = { 1, 2, 3};
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
expect(validator_recv_frame,
when(size, is_equal_to(sizeof(original_data))),
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(original_data)));
int i;
for(i=0;i<sent_data_size;i++) {
byte_stuffer_recv_byte(1, sent_data[i]);
for(auto& d : sent_data) {
byte_stuffer_recv_byte(1, d);
}
}
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
uint8_t original_data[] = { 1, 0, 3, 0, 0, 9};
byte_stuffer_send_frame(1, original_data, sizeof(original_data));
expect(validator_recv_frame,
when(size, is_equal_to(sizeof(original_data))),
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(original_data)));
int i;
for(i=0;i<sent_data_size;i++) {
byte_stuffer_recv_byte(0, sent_data[i]);
for(auto& d : sent_data) {
byte_stuffer_recv_byte(1, d);
}
}
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
uint8_t original_data[254];
int i;
for(i=0;i<254;i++) {
original_data[i] = i + 1;
}
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
expect(validator_recv_frame,
when(size, is_equal_to(sizeof(original_data))),
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
);
for(i=0;i<sent_data_size;i++) {
byte_stuffer_recv_byte(1, sent_data[i]);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(original_data)));
for(auto& d : sent_data) {
byte_stuffer_recv_byte(1, d);
}
}
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
uint8_t original_data[256];
int i;
for(i=0;i<254;i++) {
@ -479,16 +460,14 @@ Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
original_data[254] = 22;
original_data[255] = 23;
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
expect(validator_recv_frame,
when(size, is_equal_to(sizeof(original_data))),
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
);
for(i=0;i<sent_data_size;i++) {
byte_stuffer_recv_byte(1, sent_data[i]);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(original_data)));
for(auto& d : sent_data) {
byte_stuffer_recv_byte(1, d);
}
}
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
uint8_t original_data[255];
int i;
for(i=0;i<254;i++) {
@ -496,11 +475,9 @@ Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
}
original_data[254] = 0;
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
expect(validator_recv_frame,
when(size, is_equal_to(sizeof(original_data))),
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
);
for(i=0;i<sent_data_size;i++) {
byte_stuffer_recv_byte(1, sent_data[i]);
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(original_data)));
for(auto& d : sent_data) {
byte_stuffer_recv_byte(1, d);
}
}

@ -1,231 +0,0 @@
/*
The MIT License (MIT)
Copyright (c) 2016 Fred Sundvik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <cgreen/cgreen.h>
#include <cgreen/mocks.h>
#include "serial_link/protocol/byte_stuffer.c"
#include "serial_link/protocol/frame_validator.c"
#include "serial_link/protocol/frame_router.c"
#include "serial_link/protocol/transport.h"
static uint8_t received_data[256];
static uint16_t received_data_size;
typedef struct {
uint8_t sent_data[256];
uint16_t sent_data_size;
} receive_buffer_t;
typedef struct {
receive_buffer_t send_buffers[2];
} router_buffer_t;
router_buffer_t router_buffers[8];
router_buffer_t* current_router_buffer;
Describe(FrameRouter);
BeforeEach(FrameRouter) {
init_byte_stuffer();
memset(router_buffers, 0, sizeof(router_buffers));
current_router_buffer = 0;
}
AfterEach(FrameRouter) {}
typedef struct {
uint32_t data;
uint8_t extra[16];
} frame_buffer_t;
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
receive_buffer_t* buffer = &current_router_buffer->send_buffers[link];
memcpy(buffer->sent_data + buffer->sent_data_size, data, size);
buffer->sent_data_size += size;
}
static void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
int i;
for(i=0;i<size;i++) {
byte_stuffer_recv_byte(link, data[i]);
}
}
static void activate_router(uint8_t num) {
current_router_buffer = router_buffers + num;
router_set_master(num==0);
}
static void simulate_transport(uint8_t from, uint8_t to) {
activate_router(to);
if (from > to) {
receive_data(DOWN_LINK,
router_buffers[from].send_buffers[UP_LINK].sent_data,
router_buffers[from].send_buffers[UP_LINK].sent_data_size);
}
else if(to > from) {
receive_data(UP_LINK,
router_buffers[from].send_buffers[DOWN_LINK].sent_data,
router_buffers[from].send_buffers[DOWN_LINK].sent_data_size);
}
}
void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
mock(from, data, size);
}
Ensure(FrameRouter, master_broadcast_is_received_by_everyone) {
frame_buffer_t data;
data.data = 0xAB7055BB;
activate_router(0);
router_send_frame(0xFF, (uint8_t*)&data, 4);
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
expect(transport_recv_frame,
when(from, is_equal_to(0)),
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(&data.data, 4))
);
simulate_transport(0, 1);
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
expect(transport_recv_frame,
when(from, is_equal_to(0)),
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(&data.data, 4))
);
simulate_transport(1, 2);
assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
}
Ensure(FrameRouter, master_send_is_received_by_targets) {
frame_buffer_t data;
data.data = 0xAB7055BB;
activate_router(0);
router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
simulate_transport(0, 1);
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
expect(transport_recv_frame,
when(from, is_equal_to(0)),
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(&data.data, 4))
);
simulate_transport(1, 2);
assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
expect(transport_recv_frame,
when(from, is_equal_to(0)),
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(&data.data, 4))
);
simulate_transport(2, 3);
assert_that(router_buffers[3].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[3].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
}
Ensure(FrameRouter, first_link_sends_to_master) {
frame_buffer_t data;
data.data = 0xAB7055BB;
activate_router(1);
router_send_frame(0, (uint8_t*)&data, 4);
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
expect(transport_recv_frame,
when(from, is_equal_to(1)),
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(&data.data, 4))
);
simulate_transport(1, 0);
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
}
Ensure(FrameRouter, second_link_sends_to_master) {
frame_buffer_t data;
data.data = 0xAB7055BB;
activate_router(2);
router_send_frame(0, (uint8_t*)&data, 4);
assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
simulate_transport(2, 1);
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
expect(transport_recv_frame,
when(from, is_equal_to(2)),
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(&data.data, 4))
);
simulate_transport(1, 0);
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
}
Ensure(FrameRouter, master_sends_to_master_does_nothing) {
frame_buffer_t data;
data.data = 0xAB7055BB;
activate_router(0);
router_send_frame(0, (uint8_t*)&data, 4);
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
}
Ensure(FrameRouter, link_sends_to_other_link_does_nothing) {
frame_buffer_t data;
data.data = 0xAB7055BB;
activate_router(1);
router_send_frame(2, (uint8_t*)&data, 4);
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
}
Ensure(FrameRouter, master_receives_on_uplink_does_nothing) {
frame_buffer_t data;
data.data = 0xAB7055BB;
activate_router(1);
router_send_frame(0, (uint8_t*)&data, 4);
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
never_expect(transport_recv_frame);
activate_router(0);
receive_data(UP_LINK,
router_buffers[1].send_buffers[UP_LINK].sent_data,
router_buffers[1].send_buffers[UP_LINK].sent_data_size);
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
}

@ -0,0 +1,229 @@
/*
The MIT License (MIT)
Copyright (c) 2016 Fred Sundvik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <array>
extern "C" {
#include "serial_link/protocol/transport.h"
#include "serial_link/protocol/byte_stuffer.h"
#include "serial_link/protocol/frame_router.h"
}
using testing::_;
using testing::ElementsAreArray;
using testing::Args;
class FrameRouter : public testing::Test {
public:
FrameRouter() :
current_router_buffer(nullptr)
{
Instance = this;
init_byte_stuffer();
}
~FrameRouter() {
Instance = nullptr;
}
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
auto& buffer = current_router_buffer->send_buffers[link];
std::copy(data, data + size, std::back_inserter(buffer));
}
void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
int i;
for(i=0;i<size;i++) {
byte_stuffer_recv_byte(link, data[i]);
}
}
void activate_router(uint8_t num) {
current_router_buffer = router_buffers + num;
router_set_master(num==0);
}
void simulate_transport(uint8_t from, uint8_t to) {
activate_router(to);
if (from > to) {
receive_data(DOWN_LINK,
router_buffers[from].send_buffers[UP_LINK].data(),
router_buffers[from].send_buffers[UP_LINK].size());
}
else if(to > from) {
receive_data(UP_LINK,
router_buffers[from].send_buffers[DOWN_LINK].data(),
router_buffers[from].send_buffers[DOWN_LINK].size());
}
}
MOCK_METHOD3(transport_recv_frame, void (uint8_t from, uint8_t* data, uint16_t size));
std::vector<uint8_t> received_data;
struct router_buffer {
std::vector<uint8_t> send_buffers[2];
};
router_buffer router_buffers[8];
router_buffer* current_router_buffer;
static FrameRouter* Instance;
};
FrameRouter* FrameRouter::Instance = nullptr;
typedef struct {
std::array<uint8_t, 4> data;
uint8_t extra[16];
} frame_buffer_t;
extern "C" {
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
FrameRouter::Instance->send_data(link, data, size);
}
void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
FrameRouter::Instance->transport_recv_frame(from, data, size);
}
}
TEST_F(FrameRouter, master_broadcast_is_received_by_everyone) {
frame_buffer_t data;
data.data = {0xAB, 0x70, 0x55, 0xBB};
activate_router(0);
router_send_frame(0xFF, (uint8_t*)&data, 4);
EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
.With(Args<1, 2>(ElementsAreArray(data.data)));
simulate_transport(0, 1);
EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
.With(Args<1, 2>(ElementsAreArray(data.data)));
simulate_transport(1, 2);
EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
}
TEST_F(FrameRouter, master_send_is_received_by_targets) {
frame_buffer_t data;
data.data = {0xAB, 0x70, 0x55, 0xBB};
activate_router(0);
router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
simulate_transport(0, 1);
EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
.With(Args<1, 2>(ElementsAreArray(data.data)));
simulate_transport(1, 2);
EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
.With(Args<1, 2>(ElementsAreArray(data.data)));
simulate_transport(2, 3);
EXPECT_GT(router_buffers[3].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[3].send_buffers[UP_LINK].size(), 0);
}
TEST_F(FrameRouter, first_link_sends_to_master) {
frame_buffer_t data;
data.data = {0xAB, 0x70, 0x55, 0xBB};
activate_router(1);
router_send_frame(0, (uint8_t*)&data, 4);
EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
EXPECT_CALL(*this, transport_recv_frame(1, _, _))
.With(Args<1, 2>(ElementsAreArray(data.data)));
simulate_transport(1, 0);
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
}
TEST_F(FrameRouter, second_link_sends_to_master) {
frame_buffer_t data;
data.data = {0xAB, 0x70, 0x55, 0xBB};
activate_router(2);
router_send_frame(0, (uint8_t*)&data, 4);
EXPECT_GT(router_buffers[2].send_buffers[UP_LINK].size(), 0);
EXPECT_EQ(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
simulate_transport(2, 1);
EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
EXPECT_CALL(*this, transport_recv_frame(2, _, _))
.With(Args<1, 2>(ElementsAreArray(data.data)));
simulate_transport(1, 0);
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
}
TEST_F(FrameRouter, master_sends_to_master_does_nothing) {
frame_buffer_t data;
data.data = {0xAB, 0x70, 0x55, 0xBB};
activate_router(0);
router_send_frame(0, (uint8_t*)&data, 4);
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
}
TEST_F(FrameRouter, link_sends_to_other_link_does_nothing) {
frame_buffer_t data;
data.data = {0xAB, 0x70, 0x55, 0xBB};
activate_router(1);
router_send_frame(2, (uint8_t*)&data, 4);
EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
}
TEST_F(FrameRouter, master_receives_on_uplink_does_nothing) {
frame_buffer_t data;
data.data = {0xAB, 0x70, 0x55, 0xBB};
activate_router(1);
router_send_frame(0, (uint8_t*)&data, 4);
EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
EXPECT_CALL(*this, transport_recv_frame(_, _, _))
.Times(0);
activate_router(0);
receive_data(UP_LINK,
router_buffers[1].send_buffers[UP_LINK].data(),
router_buffers[1].send_buffers[UP_LINK].size());
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
}

@ -22,24 +22,47 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <cgreen/cgreen.h>
#include <cgreen/mocks.h>
#include "serial_link/protocol/frame_validator.c"
#include "gtest/gtest.h"
#include "gmock/gmock.h"
extern "C" {
#include "serial_link/protocol/frame_validator.h"
}
using testing::_;
using testing::ElementsAreArray;
using testing::Args;
class FrameValidator : public testing::Test {
public:
FrameValidator() {
Instance = this;
}
~FrameValidator() {
Instance = nullptr;
}
MOCK_METHOD3(route_incoming_frame, void (uint8_t link, uint8_t* data, uint16_t size));
MOCK_METHOD3(byte_stuffer_send_frame, void (uint8_t link, uint8_t* data, uint16_t size));
static FrameValidator* Instance;
};
FrameValidator* FrameValidator::Instance = nullptr;
extern "C" {
void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) {
mock(data, size);
FrameValidator::Instance->route_incoming_frame(link, data, size);
}
void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
mock(data, size);
FrameValidator::Instance->byte_stuffer_send_frame(link, data, size);
}
}
Describe(FrameValidator);
BeforeEach(FrameValidator) {}
AfterEach(FrameValidator) {}
Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) {
never_expect(route_incoming_frame);
TEST_F(FrameValidator, doesnt_validate_frames_under_5_bytes) {
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
.Times(0);
uint8_t data[] = {1, 2};
validator_recv_frame(0, 0, 1);
validator_recv_frame(0, data, 2);
@ -47,55 +70,46 @@ Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) {
validator_recv_frame(0, data, 4);
}
Ensure(FrameValidator, validates_one_byte_frame_with_correct_crc) {
TEST_F(FrameValidator, validates_one_byte_frame_with_correct_crc) {
uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
expect(route_incoming_frame,
when(size, is_equal_to(1)),
when(data, is_equal_to_contents_of(data, 1))
);
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(data, 1)));
validator_recv_frame(0, data, 5);
}
Ensure(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
TEST_F(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
uint8_t data[] = {0x44, 0, 0, 0, 0};
never_expect(route_incoming_frame);
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
.Times(0);
validator_recv_frame(1, data, 5);
}
Ensure(FrameValidator, validates_four_byte_frame_with_correct_crc) {
TEST_F(FrameValidator, validates_four_byte_frame_with_correct_crc) {
uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA};
expect(route_incoming_frame,
when(size, is_equal_to(4)),
when(data, is_equal_to_contents_of(data, 4))
);
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(data, 4)));
validator_recv_frame(1, data, 8);
}
Ensure(FrameValidator, validates_five_byte_frame_with_correct_crc) {
TEST_F(FrameValidator, validates_five_byte_frame_with_correct_crc) {
uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
expect(route_incoming_frame,
when(size, is_equal_to(5)),
when(data, is_equal_to_contents_of(data, 5))
);
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(data, 5)));
validator_recv_frame(0, data, 9);
}
Ensure(FrameValidator, sends_one_byte_with_correct_crc) {
TEST_F(FrameValidator, sends_one_byte_with_correct_crc) {
uint8_t original[] = {0x44, 0, 0, 0, 0};
uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
expect(byte_stuffer_send_frame,
when(size, is_equal_to(sizeof(expected))),
when(data, is_equal_to_contents_of(expected, sizeof(expected)))
);
EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
validator_send_frame(0, original, 1);
}
Ensure(FrameValidator, sends_five_bytes_with_correct_crc) {
TEST_F(FrameValidator, sends_five_bytes_with_correct_crc) {
uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0};
uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
expect(byte_stuffer_send_frame,
when(size, is_equal_to(sizeof(expected))),
when(data, is_equal_to_contents_of(expected, sizeof(expected)))
);
EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _))
.With(Args<1, 2>(ElementsAreArray(expected)));
validator_send_frame(0, original, 5);
}

@ -0,0 +1,22 @@
serial_link_byte_stuffer_SRC :=\
$(SERIAL_PATH)/tests/byte_stuffer_tests.cpp \
$(SERIAL_PATH)/protocol/byte_stuffer.c
serial_link_frame_validator_SRC := \
$(SERIAL_PATH)/tests/frame_validator_tests.cpp \
$(SERIAL_PATH)/protocol/frame_validator.c
serial_link_frame_router_SRC := \
$(SERIAL_PATH)/tests/frame_router_tests.cpp \
$(SERIAL_PATH)/protocol/byte_stuffer.c \
$(SERIAL_PATH)/protocol/frame_validator.c \
$(SERIAL_PATH)/protocol/frame_router.c
serial_link_triple_buffered_object_SRC := \
$(SERIAL_PATH)/tests/triple_buffered_object_tests.cpp \
$(SERIAL_PATH)/protocol/triple_buffered_object.c
serial_link_transport_SRC := \
$(SERIAL_PATH)/tests/transport_tests.cpp \
$(SERIAL_PATH)/protocol/transport.c \
$(SERIAL_PATH)/protocol/triple_buffered_object.c

@ -0,0 +1,6 @@
TEST_LIST +=\
serial_link_byte_stuffer\
serial_link_frame_validator\
serial_link_frame_router\
serial_link_triple_buffered_object\
serial_link_transport

@ -1,168 +0,0 @@
/*
The MIT License (MIT)
Copyright (c) 2016 Fred Sundvik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <cgreen/cgreen.h>
#include <cgreen/mocks.h>
#include "serial_link/protocol/transport.c"
#include "serial_link/protocol/triple_buffered_object.c"
void signal_data_written(void) {
mock();
}
static uint8_t sent_data[2048];
static uint16_t sent_data_size;
void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
mock(destination);
memcpy(sent_data + sent_data_size, data, size);
sent_data_size += size;
}
typedef struct {
uint32_t test;
} test_object1_t;
typedef struct {
uint32_t test1;
uint32_t test2;
} test_object2_t;
MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t);
MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t);
SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t);
static remote_object_t* test_remote_objects[] = {
REMOTE_OBJECT(master_to_slave),
REMOTE_OBJECT(master_to_single_slave),
REMOTE_OBJECT(slave_to_master),
};
Describe(Transport);
BeforeEach(Transport) {
add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
sent_data_size = 0;
}
AfterEach(Transport) {}
Ensure(Transport, write_to_local_signals_an_event) {
begin_write_master_to_slave();
expect(signal_data_written);
end_write_master_to_slave();
begin_write_slave_to_master();
expect(signal_data_written);
end_write_slave_to_master();
begin_write_master_to_single_slave(1);
expect(signal_data_written);
end_write_master_to_single_slave(1);
}
Ensure(Transport, writes_from_master_to_all_slaves) {
update_transport();
test_object1_t* obj = begin_write_master_to_slave();
obj->test = 5;
expect(signal_data_written);
end_write_master_to_slave();
expect(router_send_frame,
when(destination, is_equal_to(0xFF)));
update_transport();
transport_recv_frame(0, sent_data, sent_data_size);
test_object1_t* obj2 = read_master_to_slave();
assert_that(obj2, is_not_equal_to(NULL));
assert_that(obj2->test, is_equal_to(5));
}
Ensure(Transport, writes_from_slave_to_master) {
update_transport();
test_object1_t* obj = begin_write_slave_to_master();
obj->test = 7;
expect(signal_data_written);
end_write_slave_to_master();
expect(router_send_frame,
when(destination, is_equal_to(0)));
update_transport();
transport_recv_frame(3, sent_data, sent_data_size);
test_object1_t* obj2 = read_slave_to_master(2);
assert_that(read_slave_to_master(0), is_equal_to(NULL));
assert_that(obj2, is_not_equal_to(NULL));
assert_that(obj2->test, is_equal_to(7));
}
Ensure(Transport, writes_from_master_to_single_slave) {
update_transport();
test_object1_t* obj = begin_write_master_to_single_slave(3);
obj->test = 7;
expect(signal_data_written);
end_write_master_to_single_slave(3);
expect(router_send_frame,
when(destination, is_equal_to(4)));
update_transport();
transport_recv_frame(0, sent_data, sent_data_size);
test_object1_t* obj2 = read_master_to_single_slave();
assert_that(obj2, is_not_equal_to(NULL));
assert_that(obj2->test, is_equal_to(7));
}
Ensure(Transport, ignores_object_with_invalid_id) {
update_transport();
test_object1_t* obj = begin_write_master_to_single_slave(3);
obj->test = 7;
expect(signal_data_written);
end_write_master_to_single_slave(3);
expect(router_send_frame,
when(destination, is_equal_to(4)));
update_transport();
sent_data[sent_data_size - 1] = 44;
transport_recv_frame(0, sent_data, sent_data_size);
test_object1_t* obj2 = read_master_to_single_slave();
assert_that(obj2, is_equal_to(NULL));
}
Ensure(Transport, ignores_object_with_size_too_small) {
update_transport();
test_object1_t* obj = begin_write_master_to_slave();
obj->test = 7;
expect(signal_data_written);
end_write_master_to_slave();
expect(router_send_frame);
update_transport();
sent_data[sent_data_size - 2] = 0;
transport_recv_frame(0, sent_data, sent_data_size - 1);
test_object1_t* obj2 = read_master_to_slave();
assert_that(obj2, is_equal_to(NULL));
}
Ensure(Transport, ignores_object_with_size_too_big) {
update_transport();
test_object1_t* obj = begin_write_master_to_slave();
obj->test = 7;
expect(signal_data_written);
end_write_master_to_slave();
expect(router_send_frame);
update_transport();
sent_data[sent_data_size + 21] = 0;
transport_recv_frame(0, sent_data, sent_data_size + 22);
test_object1_t* obj2 = read_master_to_slave();
assert_that(obj2, is_equal_to(NULL));
}

@ -0,0 +1,188 @@
/*
The MIT License (MIT)
Copyright (c) 2016 Fred Sundvik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "gtest/gtest.h"
#include "gmock/gmock.h"
using testing::_;
using testing::ElementsAreArray;
using testing::Args;
extern "C" {
#include "serial_link/protocol/transport.h"
}
struct test_object1 {
uint32_t test;
};
struct test_object2 {
uint32_t test1;
uint32_t test2;
};
MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1);
MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1);
SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1);
static remote_object_t* test_remote_objects[] = {
REMOTE_OBJECT(master_to_slave),
REMOTE_OBJECT(master_to_single_slave),
REMOTE_OBJECT(slave_to_master),
};
class Transport : public testing::Test {
public:
Transport() {
Instance = this;
add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
}
~Transport() {
Instance = nullptr;
reinitialize_serial_link_transport();
}
MOCK_METHOD0(signal_data_written, void ());
MOCK_METHOD1(router_send_frame, void (uint8_t destination));
void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
router_send_frame(destination);
std::copy(data, data + size, std::back_inserter(sent_data));
}
static Transport* Instance;
std::vector<uint8_t> sent_data;
};
Transport* Transport::Instance = nullptr;
extern "C" {
void signal_data_written(void) {
Transport::Instance->signal_data_written();
}
void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
Transport::Instance->router_send_frame(destination, data, size);
}
}
TEST_F(Transport, write_to_local_signals_an_event) {
begin_write_master_to_slave();
EXPECT_CALL(*this, signal_data_written());
end_write_master_to_slave();
begin_write_slave_to_master();
EXPECT_CALL(*this, signal_data_written());
end_write_slave_to_master();
begin_write_master_to_single_slave(1);
EXPECT_CALL(*this, signal_data_written());
end_write_master_to_single_slave(1);
}
TEST_F(Transport, writes_from_master_to_all_slaves) {
update_transport();
test_object1* obj = begin_write_master_to_slave();
obj->test = 5;
EXPECT_CALL(*this, signal_data_written());
end_write_master_to_slave();
EXPECT_CALL(*this, router_send_frame(0xFF));
update_transport();
transport_recv_frame(0, sent_data.data(), sent_data.size());
test_object1* obj2 = read_master_to_slave();
EXPECT_NE(obj2, nullptr);
EXPECT_EQ(obj2->test, 5);
}
TEST_F(Transport, writes_from_slave_to_master) {
update_transport();
test_object1* obj = begin_write_slave_to_master();
obj->test = 7;
EXPECT_CALL(*this, signal_data_written());
end_write_slave_to_master();
EXPECT_CALL(*this, router_send_frame(0));
update_transport();
transport_recv_frame(3, sent_data.data(), sent_data.size());
test_object1* obj2 = read_slave_to_master(2);
EXPECT_EQ(read_slave_to_master(0), nullptr);
EXPECT_NE(obj2, nullptr);
EXPECT_EQ(obj2->test, 7);
}
TEST_F(Transport, writes_from_master_to_single_slave) {
update_transport();
test_object1* obj = begin_write_master_to_single_slave(3);
obj->test = 7;
EXPECT_CALL(*this, signal_data_written());
end_write_master_to_single_slave(3);
EXPECT_CALL(*this, router_send_frame(4));
update_transport();
transport_recv_frame(0, sent_data.data(), sent_data.size());
test_object1* obj2 = read_master_to_single_slave();
EXPECT_NE(obj2, nullptr);
EXPECT_EQ(obj2->test, 7);
}
TEST_F(Transport, ignores_object_with_invalid_id) {
update_transport();
test_object1* obj = begin_write_master_to_single_slave(3);
obj->test = 7;
EXPECT_CALL(*this, signal_data_written());
end_write_master_to_single_slave(3);
EXPECT_CALL(*this, router_send_frame(4));
update_transport();
sent_data[sent_data.size() - 1] = 44;
transport_recv_frame(0, sent_data.data(), sent_data.size());
test_object1* obj2 = read_master_to_single_slave();
EXPECT_EQ(obj2, nullptr);
}
TEST_F(Transport, ignores_object_with_size_too_small) {
update_transport();
test_object1* obj = begin_write_master_to_slave();
obj->test = 7;
EXPECT_CALL(*this, signal_data_written());
end_write_master_to_slave();
EXPECT_CALL(*this, router_send_frame(_));
update_transport();
sent_data[sent_data.size() - 2] = 0;
transport_recv_frame(0, sent_data.data(), sent_data.size() - 1);
test_object1* obj2 = read_master_to_slave();
EXPECT_EQ(obj2, nullptr);
}
TEST_F(Transport, ignores_object_with_size_too_big) {
update_transport();
test_object1* obj = begin_write_master_to_slave();
obj->test = 7;
EXPECT_CALL(*this, signal_data_written());
end_write_master_to_slave();
EXPECT_CALL(*this, router_send_frame(_));
update_transport();
sent_data.resize(sent_data.size() + 22);
sent_data[sent_data.size() - 1] = 0;
transport_recv_frame(0, sent_data.data(), sent_data.size());
test_object1* obj2 = read_master_to_slave();
EXPECT_EQ(obj2, nullptr);
}

@ -22,53 +22,55 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <cgreen/cgreen.h>
#include "serial_link/protocol/triple_buffered_object.c"
#include "gtest/gtest.h"
extern "C" {
#include "serial_link/protocol/triple_buffered_object.h"
}
typedef struct {
struct test_object{
uint8_t state;
uint32_t buffer[3];
}test_object_t;
test_object_t test_object;
};
Describe(TripleBufferedObject);
BeforeEach(TripleBufferedObject) {
triple_buffer_init((triple_buffer_object_t*)&test_object);
}
AfterEach(TripleBufferedObject) {}
test_object test_object;
class TripleBufferedObject : public testing::Test {
public:
TripleBufferedObject() {
triple_buffer_init((triple_buffer_object_t*)&test_object);
}
};
Ensure(TripleBufferedObject, writes_and_reads_object) {
TEST_F(TripleBufferedObject, writes_and_reads_object) {
*triple_buffer_begin_write(&test_object) = 0x3456ABCC;
triple_buffer_end_write(&test_object);
assert_that(*triple_buffer_read(&test_object), is_equal_to(0x3456ABCC));
EXPECT_EQ(*triple_buffer_read(&test_object), 0x3456ABCC);
}
Ensure(TripleBufferedObject, does_not_read_empty) {
assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
TEST_F(TripleBufferedObject, does_not_read_empty) {
EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
}
Ensure(TripleBufferedObject, writes_twice_and_reads_object) {
TEST_F(TripleBufferedObject, writes_twice_and_reads_object) {
*triple_buffer_begin_write(&test_object) = 0x3456ABCC;
triple_buffer_end_write(&test_object);
*triple_buffer_begin_write(&test_object) = 0x44778899;
triple_buffer_end_write(&test_object);
assert_that(*triple_buffer_read(&test_object), is_equal_to(0x44778899));
EXPECT_EQ(*triple_buffer_read(&test_object), 0x44778899);
}
Ensure(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
TEST_F(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
*triple_buffer_begin_write(&test_object) = 1;
triple_buffer_end_write(&test_object);
uint32_t* read = triple_buffer_read(&test_object);
*triple_buffer_begin_write(&test_object) = 2;
triple_buffer_end_write(&test_object);
assert_that(*read, is_equal_to(1));
assert_that(*triple_buffer_read(&test_object), is_equal_to(2));
assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
EXPECT_EQ(*read, 1);
EXPECT_EQ(*triple_buffer_read(&test_object), 2);
EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
}
Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
TEST_F(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
*triple_buffer_begin_write(&test_object) = 1;
triple_buffer_end_write(&test_object);
uint32_t* read = triple_buffer_read(&test_object);
@ -76,7 +78,7 @@ Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
triple_buffer_end_write(&test_object);
*triple_buffer_begin_write(&test_object) = 3;
triple_buffer_end_write(&test_object);
assert_that(*read, is_equal_to(1));
assert_that(*triple_buffer_read(&test_object), is_equal_to(3));
assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
EXPECT_EQ(*read, 1);
EXPECT_EQ(*triple_buffer_read(&test_object), 3);
EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
}

@ -1137,3 +1137,54 @@ Here is where you can (optionally) define your `KEYMAP` function to remap your m
```
Each of the `kxx` variables needs to be unique, and usually follows the format `k<row><col>`. You can place `KC_NO` where your dead keys are in your matrix.
# Unit Testing
If you are new to unit testing, then you can find many good resources on internet. However most of it is scattered around in small pieces here and there, and there's also many different opinions, so I won't give any recommendations.
Instead I recommend these two books, explaining two different styles of Unit Testing in detail.
* "Test Driven Development: By Example: Kent Beck"
* "Growing Object-Oriented Software, Guided By Tests: Steve Freeman, Nat Pryce"
If you prefer videos there are Uncle Bob's [Clean Coders Videos](https://cleancoders.com/), which unfortunately cost quite a bit, especially if you want to watch many of them. But James Shore has a free [Let's Play](http://www.jamesshore.com/Blog/Lets-Play) video series.
## Google Test and Google Mock
It's possible to Unit Test your code using [Google Test](https://github.com/google/googletest). The Google Test framework also includes another component for writing testing mocks and stubs, called "Google Mock". For information how to write the actual tests, please refer to the documentation on that site.
## Use of C++
Note that Google Test and therefore any test has to be written in C++, even if the rest of the QMK codebases is written in C. This should hopefully not be a problem even if you don't know any C++, since there's quite clear documentation and examples of the required C++ features, and you can write the rest of the test code almost as you would write normal C. Note that some compiler errors which you might get can look quite scary, but just read carefully what it says, and you should be ok.
One thing to remember, is that you have to append `extern "C"` around all of your C file includes.
## Adding tests for new or existing features
If you want to unit test some feature, then take a look at the existing serial_link tests, in the `quantum/serial_link/tests folder`, and follow the steps below to create a similar structure.
1. If it doesn't already exist, add a test subfolder to the folder containing the feature.
2. Create a `testlist.mk` and a `rules.mk` file in that folder.
3. Include those files from the root folder `testlist.mk`and `build_test.mk` respectively.
4. Add a new name for your testgroup to the `testlist.mk` file. Each group defined there will be a separate executable. And that's how you can support mocking out different parts. Note that it's worth adding some common prefix, just like it's done for the serial_link tests. The reason for that is that the make command allows substring filtering, so this way you can easily run a subset of the tests.
5. Define the source files and required options in the `rules.mk` file.
* `_SRC` for source files
* `_DEFS` for additional defines
* `_INC` for additional include folders
6. Write the tests in a new cpp file inside the test folder you created. That file has to be one of the files included from the `rules.mk` file.
Note how there's several different tests, each mocking out a separate part. Also note that each of them only compiles the very minimum that's needed for the tests. It's recommend that you try to do the same. For a relevant video check out [Matt Hargett "Advanced Unit Testing in C & C++](https://www.youtube.com/watch?v=Wmy6g-aVgZI)
## Running the tests
To run all the tests in the codebase, type `make test`. You can also run test matching a substring by typing `make test-matchingsubstring` Note that the tests are always compiled with the native compiler of your platform, so they are also run like any other program on your computer.
## Debugging the tests
If there are problems with the tests, you can find the executable in the `./build/test` folder. You should be able to run those with GDB or a similar debugger.
## Full Integration tests
It's not yet possible to do a full integration test, where you would compile the whole firmware and define a keymap that you are going to test. However there are plans for doing that, because writing tests that way would probably be easier, at least for people that are not used to unit testing.
In that model you would emulate the input, and expect a certain output from the emulated keyboard.

@ -0,0 +1,13 @@
include $(ROOT_DIR)/quantum/serial_link/tests/testlist.mk
define VALIDATE_TEST_LIST
ifneq ($1,)
ifeq ($$(findstring -,$1),-)
$$(error Test names can't contain '-', but '$1' does)
else
$$(eval $$(call VALIDATE_TEST_LIST,$$(firstword $2),$$(wordlist 2,9999,$2)))
endif
endif
endef
$(eval $(call VALIDATE_TEST_LIST,$(firstword $(TEST_LIST)),$(wordlist 2,9999,$(TEST_LIST))))

@ -5,7 +5,7 @@ else ifeq ($(PLATFORM),CHIBIOS)
PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios
endif
SRC += $(COMMON_DIR)/host.c \
TMK_COMMON_SRC += $(COMMON_DIR)/host.c \
$(COMMON_DIR)/keyboard.c \
$(COMMON_DIR)/action.c \
$(COMMON_DIR)/action_tapping.c \
@ -21,98 +21,89 @@ SRC += $(COMMON_DIR)/host.c \
$(PLATFORM_COMMON_DIR)/bootloader.c \
ifeq ($(PLATFORM),AVR)
SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
endif
ifeq ($(PLATFORM),CHIBIOS)
SRC += $(PLATFORM_COMMON_DIR)/printf.c
SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
endif
# Option modules
ifeq ($(strip $(BOOTMAGIC_ENABLE)), yes)
OPT_DEFS += -DBOOTMAGIC_ENABLE
SRC += $(COMMON_DIR)/bootmagic.c
TMK_COMMON_DEFS += -DBOOTMAGIC_ENABLE
TMK_COMMON_SRC += $(COMMON_DIR)/bootmagic.c
else
OPT_DEFS += -DMAGIC_ENABLE
SRC += $(COMMON_DIR)/magic.c
TMK_COMMON_DEFS += -DMAGIC_ENABLE
TMK_COMMON_SRC += $(COMMON_DIR)/magic.c
endif
ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
SRC += $(COMMON_DIR)/mousekey.c
OPT_DEFS += -DMOUSEKEY_ENABLE
OPT_DEFS += -DMOUSE_ENABLE
TMK_COMMON_SRC += $(COMMON_DIR)/mousekey.c
TMK_COMMON_DEFS += -DMOUSEKEY_ENABLE
TMK_COMMON_DEFS += -DMOUSE_ENABLE
endif
ifeq ($(strip $(EXTRAKEY_ENABLE)), yes)
OPT_DEFS += -DEXTRAKEY_ENABLE
TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE
endif
ifeq ($(strip $(CONSOLE_ENABLE)), yes)
OPT_DEFS += -DCONSOLE_ENABLE
TMK_COMMON_DEFS += -DCONSOLE_ENABLE
else
OPT_DEFS += -DNO_PRINT
OPT_DEFS += -DNO_DEBUG
TMK_COMMON_DEFS += -DNO_PRINT
TMK_COMMON_DEFS += -DNO_DEBUG
endif
ifeq ($(strip $(COMMAND_ENABLE)), yes)
SRC += $(COMMON_DIR)/command.c
OPT_DEFS += -DCOMMAND_ENABLE
TMK_COMMON_SRC += $(COMMON_DIR)/command.c
TMK_COMMON_DEFS += -DCOMMAND_ENABLE
endif
ifeq ($(strip $(NKRO_ENABLE)), yes)
OPT_DEFS += -DNKRO_ENABLE
TMK_COMMON_DEFS += -DNKRO_ENABLE
endif
ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
OPT_DEFS += -DUSB_6KRO_ENABLE
TMK_COMMON_DEFS += -DUSB_6KRO_ENABLE
endif
ifeq ($(strip $(SLEEP_LED_ENABLE)), yes)
SRC += $(PLATFORM_COMMON_DIR)/sleep_led.c
OPT_DEFS += -DSLEEP_LED_ENABLE
OPT_DEFS += -DNO_SUSPEND_POWER_DOWN
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/sleep_led.c
TMK_COMMON_DEFS += -DSLEEP_LED_ENABLE
TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN
endif
ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
SRC += $(COMMON_DIR)/backlight.c
OPT_DEFS += -DBACKLIGHT_ENABLE
TMK_COMMON_SRC += $(COMMON_DIR)/backlight.c
TMK_COMMON_DEFS += -DBACKLIGHT_ENABLE
endif
ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
OPT_DEFS += -DBLUETOOTH_ENABLE
TMK_COMMON_DEFS += -DBLUETOOTH_ENABLE
endif
ifeq ($(strip $(ONEHAND_ENABLE)), yes)
OPT_DEFS += -DONEHAND_ENABLE
TMK_COMMON_DEFS += -DONEHAND_ENABLE
endif
ifeq ($(strip $(KEYMAP_SECTION_ENABLE)), yes)
OPT_DEFS += -DKEYMAP_SECTION_ENABLE
TMK_COMMON_DEFS += -DKEYMAP_SECTION_ENABLE
ifeq ($(strip $(MCU)),atmega32u2)
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr35.x
TMK_COMMON_LDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr35.x
else ifeq ($(strip $(MCU)),atmega32u4)
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
TMK_COMMON_LDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
else
EXTRALDFLAGS = $(error no ldscript for keymap section)
TMK_COMMON_LDFLAGS = $(error no ldscript for keymap section)
endif
endif
ifeq ($(MASTER),right)
OPT_DEFS += -DMASTER_IS_ON_RIGHT
else
ifneq ($(MASTER),left)
$(error MASTER does not have a valid value(left/right))
endif
endif
# Bootloader address
ifdef STM32_BOOTLOADER_ADDRESS
OPT_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
TMK_COMMON_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
endif
# Search Path

@ -0,0 +1,24 @@
CC = gcc
OBJCOPY =
OBJDUMP =
SIZE =
AR =
NM =
HEX =
EEP =
BIN =
COMPILEFLAGS += -funsigned-char
COMPILEFLAGS += -funsigned-bitfields
COMPILEFLAGS += -ffunction-sections
COMPILEFLAGS += -fdata-sections
COMPILEFLAGS += -fshort-enums
CFLAGS += $(COMPILEFLAGS)
CFLAGS += -fno-inline-small-functions
CFLAGS += -fno-strict-aliasing
CPPFLAGS += $(COMPILEFLAGS)
CPPFLAGS += -fno-exceptions
CPPFLAGS += -std=gnu++11

@ -21,13 +21,14 @@ VPATH_SRC := $(VPATH)
vpath %.c $(VPATH_SRC)
vpath %.h $(VPATH_SRC)
vpath %.cpp $(VPATH_SRC)
vpath %.cc $(VPATH_SRC)
vpath %.hpp $(VPATH_SRC)
vpath %.S $(VPATH_SRC)
VPATH :=
# Convert all SRC to OBJ
define OBJ_FROM_SRC
$(patsubst %.c,$1/%.o,$(patsubst %.cpp,$1/%.o,$(patsubst %.S,$1/%.o,$($1_SRC))))
$(patsubst %.c,$1/%.o,$(patsubst %.cpp,$1/%.o,$(patsubst %.cc,$1/%.o,$(patsubst %.S,$1/%.o,$($1_SRC)))))
endef
$(foreach OUTPUT,$(OUTPUTS),$(eval $(OUTPUT)_OBJ +=$(call OBJ_FROM_SRC,$(OUTPUT))))
@ -160,6 +161,7 @@ SCANF_LIB =
MATH_LIB = -lm
CREATE_MAP ?= yes
#---------------- Linker Options ----------------
@ -170,7 +172,10 @@ MATH_LIB = -lm
# Comennt out "--relax" option to avoid a error such:
# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
#
LDFLAGS += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref
ifeq ($(CREATE_MAP),yes)
LDFLAGS += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref
endif
#LDFLAGS += -Wl,--relax
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
@ -202,14 +207,6 @@ ALL_ASFLAGS = $(MCUFLAGS) -x assembler-with-cpp $(ASFLAGS) $(EXTRAFLAGS)
MOVE_DEP = mv -f $(patsubst %.o,%.td,$@) $(patsubst %.o,%.d,$@)
# Default target.
all: build sizeafter
# Change the build target to build a HEX file or a library.
build: elf hex
#build: elf hex eep lss sym
#build: lib
elf: $(BUILD_DIR)/$(TARGET).elf
hex: $(BUILD_DIR)/$(TARGET).hex
@ -305,7 +302,13 @@ $1/%.o : %.cpp $1/%.d $1/cppflags.txt $1/compiler.txt | $(BEGIN)
@mkdir -p $$(@D)
@$$(SILENT) || printf "$$(MSG_COMPILING_CPP) $$<" | $$(AWK_CMD)
$$(eval CMD=$$(CC) -c $$($1_CPPFLAGS) $$(GENDEPFLAGS) $$< -o $$@ && $$(MOVE_DEP))
@$(BUILD_CMD)
@$$(BUILD_CMD)
$1/%.o : %.cc $1/%.d $1/cppflags.txt $1/compiler.txt | $(BEGIN)
@mkdir -p $$(@D)
@$$(SILENT) || printf "$$(MSG_COMPILING_CPP) $$<" | $$(AWK_CMD)
$$(eval CMD=$$(CC) -c $$($1_CPPFLAGS) $$(GENDEPFLAGS) $$< -o $$@ && $$(MOVE_DEP))
@$$(BUILD_CMD)
# Assemble: create object files from assembler source files.
$1/%.o : %.S $1/asflags.txt $1/compiler.txt | $(BEGIN)
@ -361,10 +364,10 @@ show_path:
@echo OBJ=$(OBJ)
# Create build directory
$(shell mkdir $(BUILD_DIR) 2>/dev/null)
$(shell mkdir -p $(BUILD_DIR) 2>/dev/null)
# Create object files directory
$(eval $(foreach OUTPUT,$(OUTPUTS),$(shell mkdir $(OUTPUT) 2>/dev/null)))
$(eval $(foreach OUTPUT,$(OUTPUTS),$(shell mkdir -p $(OUTPUT) 2>/dev/null)))
# Include the dependency files.
-include $(patsubst %.o,%.d,$(OBJ))

Loading…
Cancel
Save