aboutsummaryrefslogtreecommitdiffstats
path: root/src/glutt-o-logique
diff options
context:
space:
mode:
Diffstat (limited to 'src/glutt-o-logique')
-rw-r--r--src/glutt-o-logique/FreeRTOSConfig.h3
-rw-r--r--src/glutt-o-logique/Makefile133
-rw-r--r--src/glutt-o-logique/audio.c220
-rw-r--r--src/glutt-o-logique/common.c7
-rw-r--r--src/glutt-o-logique/cw.c4
-rw-r--r--src/glutt-o-logique/debug.c77
-rw-r--r--src/glutt-o-logique/debug.h47
-rw-r--r--src/glutt-o-logique/delay.c51
-rw-r--r--src/glutt-o-logique/ds18b20/README1
-rw-r--r--src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.c394
-rw-r--r--src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.h317
-rw-r--r--src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.c414
-rw-r--r--src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.h300
-rw-r--r--src/glutt-o-logique/fsm.c8
-rw-r--r--src/glutt-o-logique/gps.c4
-rw-r--r--src/glutt-o-logique/i2c.c350
-rw-r--r--src/glutt-o-logique/leds.c42
-rw-r--r--src/glutt-o-logique/leds.h4
-rw-r--r--src/glutt-o-logique/main.c69
-rw-r--r--src/glutt-o-logique/minmea.c1
-rw-r--r--src/glutt-o-logique/pio.c187
-rw-r--r--src/glutt-o-logique/temperature.c93
-rw-r--r--src/glutt-o-logique/usart.c156
23 files changed, 2882 insertions, 0 deletions
diff --git a/src/glutt-o-logique/FreeRTOSConfig.h b/src/glutt-o-logique/FreeRTOSConfig.h
new file mode 100644
index 0000000..8d6f128
--- /dev/null
+++ b/src/glutt-o-logique/FreeRTOSConfig.h
@@ -0,0 +1,3 @@
+#include "../../../common/src/Core/FreeRTOSConfig.h"
+
+#define configCHECK_FOR_STACK_OVERFLOW 2 // Default: 2
diff --git a/src/glutt-o-logique/Makefile b/src/glutt-o-logique/Makefile
new file mode 100644
index 0000000..d9ff944
--- /dev/null
+++ b/src/glutt-o-logique/Makefile
@@ -0,0 +1,133 @@
+###
+# GNU ARM Embedded Toolchain
+CC=arm-none-eabi-gcc
+LD=arm-none-eabi-ld
+AR=arm-none-eabi-ar
+AS=arm-none-eabi-as
+CP=arm-none-eabi-objcopy
+OD=arm-none-eabi-objdump
+SIZE=arm-none-eabi-size
+
+###
+# Directory Structure
+BINDIR=bin
+SRCDIR=.
+
+SOURCES=$(shell find -L $(SRCDIR) -name '*.s')
+SOURCES+=$(shell find -L $(SRCDIR) -name '*.c')
+HEADERS=$(shell find -L $(SRCDIR) -name '*.h')
+
+INC=$(shell find -L $(SRCDIR) -name '*.h' -exec dirname {} \; | uniq)
+INC+=../common/includes
+INCLUDES=$(INC:%=-I%)
+
+# Create object list
+OBJECTS=$(SOURCES:%.c=obj/%.o)
+
+# Define output files ELF & IHEX
+BINELF=outp.elf
+BINHEX=outp.hex
+
+###
+# MCU FLAGS
+MCFLAGS=-mcpu=cortex-m4 -mthumb -mlittle-endian \
+-mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb-interwork
+# COMPILE FLAGS
+DEFS=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DARM_MATH_CM4 -D__FPU_PRESENT=1
+CFLAGS =-Wall -ggdb -std=c99 -c $(MCFLAGS) $(DEFS) $(INCLUDES)
+# LINKER FLAGS
+LDSCRIPT= $(SRCDIR)/bsp/stm32_flash.ld
+LDFLAGS =-T $(LDSCRIPT) --specs=nosys.specs $(MCFLAGS) -Wl,-Map=$(BINDIR)/outp.map
+
+###
+# Optimizations
+OPT?='O2 O3 O6'
+# O1 and O4 are irrelevant
+# O5 breaks FreeRTOS somehow
+# I'm not trusting O7
+
+ifneq ($(filter O1,$(OPT)),)
+CXXFLAGS+=-fno-exceptions # Uncomment to disable exception handling
+DEFS+=-DNO_EXCEPTIONS # The source code has to comply with this rule
+endif
+
+ifneq ($(filter O2,$(OPT)),)
+CFLAGS+=-Os # Optimize for size https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
+CXXFLAGS+=-Os
+LDFLAGS+=-Os # Optimize for size https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
+endif
+
+ifneq ($(filter O3,$(OPT)),)
+CFLAGS+=-ffunction-sections -fdata-sections # Place each function or data item into its own section in the output file
+CXXFLAGS+=-ffunction-sections -fdata-sections # -||-
+LDFLAGS+=-Wl,-gc-sections # Remove isolated unused sections
+endif
+
+ifneq ($(filter O4,$(OPT)),)
+CFLAGS+=-fno-builtin # Disable C++ exception handling
+CXXFLAGS+=-fno-builtin # Disable C++ exception handling
+endif
+
+ifneq ($(filter O5,$(OPT)),)
+CFLAGS+=-flto # Enable link time optimization
+CXXFLAGS+=-flto # Enable link time optimization
+LDFLAGS+=-flto # Enable link time optimization
+endif
+
+ifneq ($(filter O6,$(OPT)),)
+CXXFLAGS+=-fno-rtti # Disable type introspection
+endif
+
+ifneq ($(findstring O7,$(OPT)),)
+LDFLAGS+=--specs=nano.specs # Use size optimized newlib
+endif
+
+###
+# Build Rules
+.PHONY: all release debug clean
+
+all: release
+
+release: $(BINDIR)/$(BINHEX)
+
+debug: CFLAGS+=-g
+debug: LDFLAGS+=-g
+debug: release
+
+$(BINDIR)/$(BINHEX): $(BINDIR)/$(BINELF)
+ $(CP) -O ihex $< $@
+
+$(BINDIR)/$(BINELF): vc.h $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+ $(SIZE) $(BINDIR)/$(BINELF)
+
+dir_guard=@mkdir -p $(@D)
+
+obj/%.o: %.c $(HEADERS)
+ $(dir_guard)
+ @echo [CC] $<
+ @$(CC) $(CFLAGS) $< -o $@
+
+obj/%.o: %.s $(HEADERS)
+ $(dir_guard)
+ @echo [AS] $<
+ @$(CC) $(CFLAGS) $< -o $@
+
+vc.h: ../../.git/logs/HEAD
+ echo "// This file is generated by Makefile." > vc.h
+ echo "// Do not edit this file!" >> vc.h
+ git log -1 --format="format:#define GIT_VERSION \"%h\"" >> vc.h
+ echo >> vc.h
+ echo >> vc.h
+
+clean:
+ rm -f $(OBJECTS) $(BINDIR)/$(BINELF) $(BINDIR)/$(BINHEX)
+
+# Connect to openocd's gdb server on port 3333
+deploy: $(BINDIR)/$(BINELF)
+ifeq ($(wildcard /opt/openocd/bin/openocd),)
+ /usr/bin/openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg -c "program bin/"$(BINELF)" verify reset" -c "init" -c "reset" -c "exit"
+else
+ /opt/openocd/bin/openocd -f /opt/openocd/share/openocd/scripts/board/stm32f4discovery.cfg -c "program bin/"$(BINELF)" verify reset" -c "init" -c "reset" -c "exit"
+endif
+
diff --git a/src/glutt-o-logique/audio.c b/src/glutt-o-logique/audio.c
new file mode 100644
index 0000000..bdb2961
--- /dev/null
+++ b/src/glutt-o-logique/audio.c
@@ -0,0 +1,220 @@
+#include "GPIO/i2c.h"
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+
+#include "../../../common/src/Audio/audio.c"
+
+void audio_initialize_platform(int plln, int pllr, int i2sdiv, int i2sodd, int rate) {
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ // Turn on peripherals.
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
+
+ // Assume I2C is set up
+
+ // Configure reset pin.
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOD, &GPIO_InitStructure);
+
+ // Configure I2S MCK, SCK, SD pins.
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_10 | GPIO_Pin_12;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+ GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_SPI3);
+ GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SPI3);
+ GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3);
+
+ // Configure I2S WS pin.
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI3);
+
+ // Reset the codec.
+ GPIO_ResetBits(GPIOD, GPIO_Pin_4);
+ for (volatile int i = 0; i < 0x4fff; i++) {
+ __asm__ volatile("nop");
+ }
+ GPIO_SetBits(GPIOD, GPIO_Pin_4);
+
+ // Configure codec.
+ audio_write_register(0x02, 0x01); // Keep codec powered off.
+ audio_write_register(0x04, 0xaf); // SPK always off and HP always on.
+
+ audio_write_register(0x05, 0x81); // Clock configuration: Auto detection.
+ audio_write_register(0x06, 0x04); // Set slave mode and Philips audio standard.
+
+ // Power on the codec.
+ audio_write_register(0x02, 0x9e);
+
+ // Configure codec for fast shutdown.
+ audio_write_register(0x0a, 0x00); // Disable the analog soft ramp.
+ audio_write_register(0x0e, 0x04); // Disable the digital soft ramp.
+
+ audio_write_register(0x27, 0x00); // Disable the limiter attack level.
+ audio_write_register(0x1f, 0x0f); // Adjust bass and treble levels.
+
+ audio_write_register(0x1a, 0x0a); // Adjust PCM volume level.
+ audio_write_register(0x1b, 0x0a);
+
+ // Disable I2S.
+ SPI3 ->I2SCFGR = 0;
+
+ // I2S clock configuration
+ RCC ->CFGR &= ~RCC_CFGR_I2SSRC; // PLLI2S clock used as I2S clock source.
+ RCC ->PLLI2SCFGR = (pllr << 28) | (plln << 6);
+
+ // Enable PLLI2S and wait until it is ready.
+ RCC ->CR |= RCC_CR_PLLI2SON;
+ while (!(RCC ->CR & RCC_CR_PLLI2SRDY ))
+ ;
+
+ // Configure I2S.
+ SPI3 ->I2SPR = i2sdiv | (i2sodd << 8) | SPI_I2SPR_MCKOE;
+ SPI3 ->I2SCFGR = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SCFG_1
+ | SPI_I2SCFGR_I2SE; // Master transmitter, Phillips mode, 16 bit values, clock polarity low, enable.
+
+}
+
+void audio_on() {
+ audio_write_register(0x02, 0x9e);
+ SPI3 ->I2SCFGR = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SCFG_1
+ | SPI_I2SCFGR_I2SE; // Master transmitter, Phillips mode, 16 bit values, clock polarity low, enable.
+}
+
+void audio_off() {
+ audio_write_register(0x02, 0x9f);
+ SPI3 ->I2SCFGR = 0;
+}
+
+void audio_set_volume(int volume) {
+ audio_write_register(0x20, (volume + 0x19) & 0xff);
+ audio_write_register(0x21, (volume + 0x19) & 0xff);
+}
+
+void audio_output_sample(int16_t sample) {
+ while (!(SPI3 ->SR & SPI_SR_TXE ))
+ ;
+ SPI3 ->DR = sample;
+}
+
+
+void audio_output_sample_without_blocking(int16_t sample) {
+ SPI3 ->DR = sample;
+}
+
+void audio_play_with_callback(AudioCallbackFunction *callback, void *context) {
+ audio_stop_dma();
+
+ NVIC_EnableIRQ(DMA1_Stream7_IRQn);
+ NVIC_SetPriority(DMA1_Stream7_IRQn, 5);
+
+ SPI3 ->CR2 |= SPI_CR2_TXDMAEN; // Enable I2S TX DMA request.
+
+ callback_function = callback;
+ callback_context = context;
+ buffer_number = 0;
+
+ if (callback_function)
+ callback_function(callback_context, buffer_number);
+}
+
+void audio_stop() {
+ audio_stop_dma();
+ SPI3 ->CR2 &= ~SPI_CR2_TXDMAEN; // Disable I2S TX DMA request.
+ NVIC_DisableIRQ(DMA1_Stream7_IRQn);
+ callback_function = NULL;
+}
+
+void audio_provide_buffer(void *samples, int numsamples) {
+ while (!audio_provide_buffer_without_blocking(samples, numsamples))
+ __asm__ volatile ("wfi");
+}
+
+bool audio_provide_buffer_without_blocking(void *samples, int numsamples) {
+ if (next_buffer_samples)
+ return false;
+
+ NVIC_DisableIRQ(DMA1_Stream7_IRQn);
+
+ next_buffer_samples = samples;
+ next_buffer_length = numsamples;
+
+ if (!dma_running)
+ audio_start_dma_and_request_buffers();
+
+ NVIC_EnableIRQ(DMA1_Stream7_IRQn);
+
+ return true;
+}
+
+static void audio_start_dma_and_request_buffers() {
+ // Configure DMA stream.
+ DMA1_Stream7 ->CR = (0 * DMA_SxCR_CHSEL_0 ) | // Channel 0
+ (1 * DMA_SxCR_PL_0 ) | // Priority 1
+ (1 * DMA_SxCR_PSIZE_0 ) | // PSIZE = 16 bit
+ (1 * DMA_SxCR_MSIZE_0 ) | // MSIZE = 16 bit
+ DMA_SxCR_MINC | // Increase memory address
+ (1 * DMA_SxCR_DIR_0 ) | // Memory to peripheral
+ DMA_SxCR_TCIE; // Transfer complete interrupt
+ DMA1_Stream7 ->NDTR = next_buffer_length;
+ DMA1_Stream7 ->PAR = (uint32_t) &SPI3 ->DR;
+ DMA1_Stream7 ->M0AR = (uint32_t) next_buffer_samples;
+ DMA1_Stream7 ->FCR = DMA_SxFCR_DMDIS;
+ DMA1_Stream7 ->CR |= DMA_SxCR_EN;
+
+ // Update state.
+ next_buffer_samples = NULL;
+ buffer_number ^= 1;
+ dma_running = true;
+
+ // Invoke callback if it exists to queue up another buffer.
+ if (callback_function)
+ callback_function(callback_context, buffer_number);
+}
+
+static void audio_stop_dma() {
+ DMA1_Stream7 ->CR &= ~DMA_SxCR_EN; // Disable DMA stream.
+ while (DMA1_Stream7 ->CR & DMA_SxCR_EN )
+ ; // Wait for DMA stream to stop.
+
+ dma_running = false;
+}
+
+void DMA1_Stream7_IRQHandler() {
+ DMA1 ->HIFCR |= DMA_HIFCR_CTCIF7; // Clear interrupt flag.
+
+ if (next_buffer_samples) {
+ audio_start_dma_and_request_buffers();
+ } else {
+ dma_running = false;
+ }
+}
+
+// Warning: don't i2c_write call from IRQ handler !
+static void audio_write_register(uint8_t address, uint8_t value)
+{
+ const uint8_t device = 0x4a;
+ const uint8_t data[2] = {address, value};
+ i2c_transaction_start();
+ i2c_write(device, data, 2);
+ i2c_transaction_end();
+}
+
diff --git a/src/glutt-o-logique/common.c b/src/glutt-o-logique/common.c
new file mode 100644
index 0000000..a647d26
--- /dev/null
+++ b/src/glutt-o-logique/common.c
@@ -0,0 +1,7 @@
+#include <stm32f4xx.h>
+
+#include "../../../common/src/Core/common.c"
+
+void hard_fault_handler_extra() {
+ usart_debug("SCB_SHCSR = %x\n", SCB->SHCSR);
+}
diff --git a/src/glutt-o-logique/cw.c b/src/glutt-o-logique/cw.c
new file mode 100644
index 0000000..028ae82
--- /dev/null
+++ b/src/glutt-o-logique/cw.c
@@ -0,0 +1,4 @@
+#include "../../../common/src/Audio/cw.c"
+
+void cw_message_sent(const char* str) {
+}
diff --git a/src/glutt-o-logique/debug.c b/src/glutt-o-logique/debug.c
new file mode 100644
index 0000000..2e33a32
--- /dev/null
+++ b/src/glutt-o-logique/debug.c
@@ -0,0 +1,77 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Matthias P. Braendli
+ *
+ * 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 <stddef.h>
+#include <stdint.h>
+
+#include "debug.h"
+
+#if _DEBUG
+
+void debug_send_command(int command, void *message)
+{
+ __asm__ volatile (
+ "mov r0, %[cmd];"
+ "mov r1, %[msg];"
+ "bkpt #0xAB"
+ :
+ : [cmd] "r" (command), [msg] "r" (message)
+ : "r0", "r1", "memory");
+}
+
+void put_char(char c)
+{
+ __asm__ volatile (
+ "mov r0, #0x03\n" /* SYS_WRITEC */
+ "mov r1, %[msg]\n"
+ "bkpt #0xAB\n"
+ :
+ : [msg] "r" (&c)
+ : "r0", "r1"
+ );
+}
+
+void debug_print(const char* str)
+{
+ const int std_err = 2;
+
+ int strlen = 0;
+ const char* s;
+ s = str;
+ while (*s) {
+ strlen++;
+ s++;
+ }
+
+ uint32_t m[] = { std_err, (uint32_t)str, strlen };
+ debug_send_command(0x05, m);
+}
+
+#else
+void debug_send_command(int command, void *message) { }
+void put_char(char c) { }
+void debug_print(const char* str) { }
+
+#endif
+
diff --git a/src/glutt-o-logique/debug.h b/src/glutt-o-logique/debug.h
new file mode 100644
index 0000000..6215e5f
--- /dev/null
+++ b/src/glutt-o-logique/debug.h
@@ -0,0 +1,47 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Matthias P. Braendli
+ *
+ * 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.
+*/
+
+/* Debugging utilities using the ARM semihosting facilities. Warning, it's quite
+ * slow.
+ *
+ * when used with OpenOCD's gdb server, requires the gdb command
+ *
+ * monitor arm semihosting enable
+ */
+#ifndef __DEBUG_H_
+#define __DEBUG_H_
+
+/* Example usage for the send_command function
+const char *s = "Hello world\n";
+uint32_t m[] = { 2, (uint32_t)s, sizeof(s)/sizeof(char) };
+send_command(0x05, m);
+// some interrupt ID
+
+*/
+
+/* Print a string to the OpenOCD console */
+void debug_print(const char* str);
+
+#endif // __DEBUG_H_
+
diff --git a/src/glutt-o-logique/delay.c b/src/glutt-o-logique/delay.c
new file mode 100644
index 0000000..af959f7
--- /dev/null
+++ b/src/glutt-o-logique/delay.c
@@ -0,0 +1,51 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony
+ *
+ * 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 "Core/delay.h"
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+
+uint32_t delay_multiplier = 1;
+
+void delay_us(uint32_t micros)
+{
+ micros = micros * delay_multiplier - 10;
+ while (micros--);
+}
+
+void delay_ms(uint32_t millis)
+{
+ for (int i = 0; i < 1000; i++) {
+ delay_us(millis);
+ }
+}
+
+void delay_init()
+{
+ RCC_ClocksTypeDef RCC_Clocks;
+ RCC_GetClocksFreq(&RCC_Clocks);
+
+ delay_multiplier = RCC_Clocks.HCLK_Frequency / 4000000;
+}
+
diff --git a/src/glutt-o-logique/ds18b20/README b/src/glutt-o-logique/ds18b20/README
new file mode 100644
index 0000000..0cd66d5
--- /dev/null
+++ b/src/glutt-o-logique/ds18b20/README
@@ -0,0 +1 @@
+This folder contains a library to access Dallas 1-wire temperature sensors.
diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.c b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.c
new file mode 100644
index 0000000..d16e48c
--- /dev/null
+++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.c
@@ -0,0 +1,394 @@
+/**
+ * |----------------------------------------------------------------------
+ * | Copyright (C) Tilen Majerle, 2014
+ * |
+ * | This program is free software: you can redistribute it and/or modify
+ * | it under the terms of the GNU General Public License as published by
+ * | the Free Software Foundation, either version 3 of the License, or
+ * | any later version.
+ * |
+ * | This program is distributed in the hope that it will be useful,
+ * | but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * | GNU General Public License for more details.
+ * |
+ * | You should have received a copy of the GNU General Public License
+ * | along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * |----------------------------------------------------------------------
+ */
+#include "tm_stm32f4_ds18b20.h"
+
+uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ /* Check if device is DS18B20 */
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Start temperature conversion */
+ TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP);
+
+ return 1;
+}
+
+void TM_DS18B20_StartAll(TM_OneWire_t* OneWire) {
+ /* Reset pulse */
+ TM_OneWire_Reset(OneWire);
+ /* Skip rom */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_SKIPROM);
+ /* Start conversion on all connected devices */
+ TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP);
+}
+
+uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWire, uint8_t *ROM, float *destination) {
+ uint16_t temperature;
+ uint8_t resolution;
+ int8_t digit, minus = 0;
+ float decimal;
+ uint8_t i = 0;
+ uint8_t data[9];
+ uint8_t crc;
+
+ /* Check if device is DS18B20 */
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Check if line is released, if it is, then conversion is complete */
+ if (!TM_OneWire_ReadBit(OneWire)) {
+ /* Conversion is not finished yet */
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Get data */
+ for (i = 0; i < 9; i++) {
+ /* Read byte by byte */
+ data[i] = TM_OneWire_ReadByte(OneWire);
+ }
+
+ /* Calculate CRC */
+ crc = TM_OneWire_CRC8(data, 8);
+
+ /* Check if CRC is ok */
+ if (crc != data[8]) {
+ /* CRC invalid */
+ return 0;
+ }
+
+ /* First two bytes of scratchpad are temperature values */
+ temperature = data[0] | (data[1] << 8);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+
+ /* Check if temperature is negative */
+ if (temperature & 0x8000) {
+ /* Two's complement, temperature is negative */
+ temperature = ~temperature + 1;
+ minus = 1;
+ }
+
+
+ /* Get sensor resolution */
+ resolution = ((data[4] & 0x60) >> 5) + 9;
+
+
+ /* Store temperature integer digits and decimal digits */
+ digit = temperature >> 4;
+ digit |= ((temperature >> 8) & 0x7) << 4;
+
+ /* Store decimal digits */
+ switch (resolution) {
+ case 9: {
+ decimal = (temperature >> 3) & 0x01;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_9BIT;
+ } break;
+ case 10: {
+ decimal = (temperature >> 2) & 0x03;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_10BIT;
+ } break;
+ case 11: {
+ decimal = (temperature >> 1) & 0x07;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_11BIT;
+ } break;
+ case 12: {
+ decimal = temperature & 0x0F;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_12BIT;
+ } break;
+ default: {
+ decimal = 0xFF;
+ digit = 0;
+ }
+ }
+
+ /* Check for negative part */
+ decimal = digit + decimal;
+ if (minus) {
+ decimal = 0 - decimal;
+ }
+
+ /* Set to pointer */
+ *destination = decimal;
+
+ /* Return 1, temperature valid */
+ return 1;
+}
+
+uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ uint8_t conf;
+
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 4 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ /* 5th byte of scratchpad is configuration register */
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ /* Return 9 - 12 value according to number of bits */
+ return ((conf & 0x60) >> 5) + 9;
+}
+
+uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWire, uint8_t *ROM, TM_DS18B20_Resolution_t resolution) {
+ uint8_t th, tl, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ if (resolution == TM_DS18B20_Resolution_9bits) {
+ conf &= ~(1 << DS18B20_RESOLUTION_R1);
+ conf &= ~(1 << DS18B20_RESOLUTION_R0);
+ } else if (resolution == TM_DS18B20_Resolution_10bits) {
+ conf &= ~(1 << DS18B20_RESOLUTION_R1);
+ conf |= 1 << DS18B20_RESOLUTION_R0;
+ } else if (resolution == TM_DS18B20_Resolution_11bits) {
+ conf |= 1 << DS18B20_RESOLUTION_R1;
+ conf &= ~(1 << DS18B20_RESOLUTION_R0);
+ } else if (resolution == TM_DS18B20_Resolution_12bits) {
+ conf |= 1 << DS18B20_RESOLUTION_R1;
+ conf |= 1 << DS18B20_RESOLUTION_R0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_Is(uint8_t *ROM) {
+ /* Checks if first byte is equal to DS18B20's family code */
+ if (*ROM == DS18B20_FAMILY_CODE) {
+ return 1;
+ }
+ return 0;
+}
+
+uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ if (temp > 125) {
+ temp = 125;
+ }
+ if (temp < -55) {
+ temp = -55;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ tl = (uint8_t)temp;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ if (temp > 125) {
+ temp = 125;
+ }
+ if (temp < -55) {
+ temp = -55;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ th = (uint8_t)temp;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ th = 125;
+ tl = (uint8_t)-55;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWire) {
+ /* Start alarm search */
+ return TM_OneWire_Search(OneWire, DS18B20_CMD_ALARMSEARCH);
+}
+
+uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWire) {
+ /* If read bit is low, then device is not finished yet with calculation temperature */
+ return TM_OneWire_ReadBit(OneWire);
+}
+
+
diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.h b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.h
new file mode 100644
index 0000000..337883e
--- /dev/null
+++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_ds18b20.h
@@ -0,0 +1,317 @@
+/**
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.com
+ * @link http://stm32f4-discovery.com/2014/05/13-reading-temperature-with-dallas-ds18b20-on-stm32f429-discovery-board/
+ * @version v2.0
+ * @ide Keil uVision
+ * @license GNU GPL v3
+ * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors.
+ *
+@verbatim
+ ----------------------------------------------------------------------
+ Copyright (C) Tilen Majerle, 2015
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------
+@endverbatim
+ */
+/**
+ * Library for interfacing DS18B20 temperature sensor from Dallas semiconductors.
+ *
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.com
+ * @link http://stm32f4-discovery.com/2014/05/13-reading-temperature-with-dallas-ds18b20-on-stm32f429-discovery-board/
+ * @version v2.0
+ * @ide Keil uVision
+ * @license GNU GPL v3
+ *
+ * |----------------------------------------------------------------------
+ * | Copyright (C) Tilen Majerle, 2014
+ * |
+ * | This program is free software: you can redistribute it and/or modify
+ * | it under the terms of the GNU General Public License as published by
+ * | the Free Software Foundation, either version 3 of the License, or
+ * | any later version.
+ * |
+ * | This program is distributed in the hope that it will be useful,
+ * | but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * | GNU General Public License for more details.
+ * |
+ * | You should have received a copy of the GNU General Public License
+ * | along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * |----------------------------------------------------------------------
+ *
+ * Version 2.0
+ * - January 04, 2015
+ * - New system, supporting OneWire library 2.0
+ *
+ * Version 1.1
+ * - December 06, 2014
+ * - Now CRC is calculated and checked if data are valid
+ * - New version of OneWire library is required, download already available on stm32f4-discovery.com
+ *
+ * With this you can read temperature, set and get temperature resolution from 9 to 12 bits
+ * and check if device is DS18B20
+ *
+ * Pin for STM32F4xx is the same as set with TM ONEWIRE library.
+ */
+#ifndef TM_DS18B20_H
+#define TM_DS18B20_H 200
+
+/**
+ * @addtogroup TM_STM32F4xx_Libraries
+ * @{
+ */
+
+/**
+ * @defgroup TM_DS12820
+ * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors - http://stm32f4-discovery.com/2014/05/13-reading-temperature-with-dallas-ds18b20-on-stm32f429-discovery-board/
+ * @{
+ *
+ * With this you can read temperature, set and get temperature resolution from 9 to 12 bits and check if device is DS18B20.
+ *
+ * Pin for STM32F4xx is the same as set with TM ONEWIRE library.
+ *
+ * \par Changelog
+ *
+@verbatim
+ Version 2.0
+ - January 04, 2015
+ - New system, supporting OneWire library 2.0
+
+ Version 1.1
+ - December 06, 2014
+ - Now CRC is calculated and checked if data are valid
+ - New version of OneWire library is required, download already available on stm32f4-discovery.com
+
+ Version 1.0
+ - First release
+@endverbatim
+ *
+ * \par Dependencies
+ *
+@verbatim
+ - STM32F4xx
+ - TM ONEWIRE
+ - TM GPIO
+@endverbatim
+ */
+
+#include "stm32f4xx.h"
+#include "tm_stm32f4_onewire.h"
+
+/* OneWire version check */
+#if TM_ONEWIRE_H < 200
+#error "Please update TM ONEWIRE LIB, minimum required version is 2.0.0. Download available on stm32f4-discovery.com website"
+#endif
+
+/**
+ * @defgroup TM_DS18B20_Macros
+ * @brief Library defines
+ * @{
+ */
+
+/* Every onewire chip has different ROM code, but all the same chips has same family code */
+/* in case of DS18B20 this is 0x28 and this is first byte of ROM address */
+#define DS18B20_FAMILY_CODE 0x28
+#define DS18B20_CMD_ALARMSEARCH 0xEC
+
+/* DS18B20 read temperature command */
+#define DS18B20_CMD_CONVERTTEMP 0x44 /* Convert temperature */
+#define DS18B20_DECIMAL_STEPS_12BIT 0.0625
+#define DS18B20_DECIMAL_STEPS_11BIT 0.125
+#define DS18B20_DECIMAL_STEPS_10BIT 0.25
+#define DS18B20_DECIMAL_STEPS_9BIT 0.5
+
+/* Bits locations for resolution */
+#define DS18B20_RESOLUTION_R1 6
+#define DS18B20_RESOLUTION_R0 5
+
+/* CRC enabled */
+#ifdef DS18B20_USE_CRC
+#define DS18B20_DATA_LEN 9
+#else
+#define DS18B20_DATA_LEN 2
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_DS18B20_Typedefs
+ * @brief Library Typedefs
+ * @{
+ */
+
+/**
+ * @brief DS18B0 Resolutions available
+ */
+typedef enum {
+ TM_DS18B20_Resolution_9bits = 9, /*!< DS18B20 9 bits resolution */
+ TM_DS18B20_Resolution_10bits = 10, /*!< DS18B20 10 bits resolution */
+ TM_DS18B20_Resolution_11bits = 11, /*!< DS18B20 11 bits resolution */
+ TM_DS18B20_Resolution_12bits = 12 /*!< DS18B20 12 bits resolution */
+} TM_DS18B20_Resolution_t;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_DS18B20_Functions
+ * @brief Library Functions
+ * @{
+ */
+
+/**
+ * @brief Starts temperature conversion for specific DS18B20 on specific onewire channel
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval 1 if device is DS18B20 or 0 if not
+ */
+uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Starts temperature conversion for all DS18B20 devices on specific onewire channel
+ * @note This mode will skip ROM addressing
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval None
+ */
+void TM_DS18B20_StartAll(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads temperature from DS18B20
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param *destination: Pointer to float variable to store temperature
+ * @retval Temperature status:
+ * - 0: Device is not DS18B20 or conversion is not done yet or CRC failed
+ * - > 0: Temperature is read OK
+ */
+uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWireStruct, uint8_t* ROM, float* destination);
+
+/**
+ * @brief Gets resolution for temperature conversion from DS18B20 device
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Resolution:
+ * - 0: Device is not DS18B20
+ * - 9 - 12: Resolution of DS18B20
+ */
+uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Sets resolution for specific DS18B20 device
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param resolution: Resolution for DS18B20 device. This parameter can be a value of @ref TM_DS18B20_Resolution_t enumeration.
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Resolution set OK
+ */
+uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM, TM_DS18B20_Resolution_t resolution);
+
+/**
+ * @brief Checks if device with specific ROM number is DS18B20
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Device status
+ * - 0: Device is not DS18B20
+ * - > 0: Device is DS18B20
+ */
+uint8_t TM_DS18B20_Is(uint8_t* ROM);
+
+/**
+ * @brief Sets high alarm temperature to specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param temp: integer value for temperature between -55 to 125 degrees
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: High alarm set OK
+ */
+uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp);
+
+/**
+ * @brief Sets low alarm temperature to specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param temp: integer value for temperature between -55 to 125 degrees
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Low alarm set OK
+ */
+uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp);
+
+/**
+ * @brief Disables alarm temperature for specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Alarm disabled OK
+ */
+uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Searches for devices with alarm flag set
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval Alarm search status
+ * - 0: No device found with alarm flag set
+ * - > 0: Device is found with alarm flag
+ * @note To get all devices on one onewire channel with alarm flag set, you can do this:
+@verbatim
+while (TM_DS18B20_AlarmSearch(&OneWireStruct)) {
+ //Read device ID here
+ //Print to user device by device
+}
+@endverbatim
+ * @retval 1 if any device has flag, otherwise 0
+ */
+uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Checks if all DS18B20 sensors are done with temperature conversion
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval Conversion status
+ * - 0: Not all devices are done
+ * - > 0: All devices are done with conversion
+ */
+uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif
+
diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.c b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.c
new file mode 100644
index 0000000..44ec8db
--- /dev/null
+++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.c
@@ -0,0 +1,414 @@
+/**
+ * |----------------------------------------------------------------------
+ * | Copyright (C) Tilen Majerle, 2014
+ * |
+ * | This program is free software: you can redistribute it and/or modify
+ * | it under the terms of the GNU General Public License as published by
+ * | the Free Software Foundation, either version 3 of the License, or
+ * | any later version.
+ * |
+ * | This program is distributed in the hope that it will be useful,
+ * | but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * | GNU General Public License for more details.
+ * |
+ * | You should have received a copy of the GNU General Public License
+ * | along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * |----------------------------------------------------------------------
+ */
+#include "tm_stm32f4_onewire.h"
+
+void delay_us(uint32_t);
+
+static void
+TM_GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIO_SetBits(GPIOx, GPIO_Pin);
+}
+
+static void
+TM_GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIO_ResetBits(GPIOx, GPIO_Pin);
+}
+
+
+static void
+TM_GPIO_SetPinAsInput(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ GPIO_SetBits(GPIOx, GPIO_Pin);
+}
+
+static void
+TM_GPIO_SetPinAsOutput(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+#if 0
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_Init(GPIOx, &GPIO_InitStructure);
+#endif
+ GPIO_ResetBits(GPIOx, GPIO_Pin);
+}
+
+static int
+TM_GPIO_GetInputPinValue(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
+{
+ return GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) ? 1 : 0;
+}
+
+static void
+ONEWIRE_DELAY(uint32_t micros)
+{
+ delay_us(micros);
+}
+
+void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {
+ ONEWIRE_INPUT(OneWireStruct);
+ /* Save settings */
+ OneWireStruct->GPIOx = GPIOx;
+ OneWireStruct->GPIO_Pin = GPIO_Pin;
+}
+
+uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct) {
+ uint8_t i;
+
+ /* Line low, and wait 480us */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(480);
+
+ /* Release line and wait for 70us */
+ ONEWIRE_INPUT(OneWireStruct);
+ ONEWIRE_DELAY(70);
+
+ /* Check bit value */
+ i = TM_GPIO_GetInputPinValue(OneWireStruct->GPIOx, OneWireStruct->GPIO_Pin);
+
+ /* Delay for 410 us */
+ ONEWIRE_DELAY(410);
+
+ /* Return value of presence pulse, 0 = OK, 1 = ERROR */
+ return i;
+}
+
+void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit) {
+ if (bit) {
+ /* Set line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(10);
+
+ /* Bit high */
+ ONEWIRE_INPUT(OneWireStruct);
+
+ /* Wait for 55 us and release the line */
+ ONEWIRE_DELAY(55);
+ ONEWIRE_INPUT(OneWireStruct);
+ } else {
+ /* Set line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(65);
+
+ /* Bit high */
+ ONEWIRE_INPUT(OneWireStruct);
+
+ /* Wait for 5 us and release the line */
+ ONEWIRE_DELAY(5);
+ ONEWIRE_INPUT(OneWireStruct);
+ }
+
+}
+
+uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct) {
+ uint8_t bit = 0;
+
+ /* Line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(3);
+
+ /* Release line */
+ ONEWIRE_INPUT(OneWireStruct);
+ ONEWIRE_DELAY(10);
+
+ /* Read line value */
+ if (TM_GPIO_GetInputPinValue(OneWireStruct->GPIOx, OneWireStruct->GPIO_Pin)) {
+ /* Bit is HIGH */
+ bit = 1;
+ }
+
+ /* Wait 50us to complete 60us period */
+ ONEWIRE_DELAY(50);
+
+ /* Return bit value */
+ return bit;
+}
+
+void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte) {
+ uint8_t i = 8;
+ /* Write 8 bits */
+ while (i--) {
+ /* LSB bit is first */
+ TM_OneWire_WriteBit(OneWireStruct, byte & 0x01);
+ byte >>= 1;
+ }
+}
+
+uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct) {
+ uint8_t i = 8, byte = 0;
+ while (i--) {
+ byte >>= 1;
+ byte |= (TM_OneWire_ReadBit(OneWireStruct) << 7);
+ }
+
+ return byte;
+}
+
+uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct) {
+ /* Reset search values */
+ TM_OneWire_ResetSearch(OneWireStruct);
+
+ /* Start with searching */
+ return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM);
+}
+
+uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct) {
+ /* Leave the search state alone */
+ return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM);
+}
+
+void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct) {
+ /* Reset the search state */
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+}
+
+uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command) {
+ uint8_t id_bit_number;
+ uint8_t last_zero, rom_byte_number, search_result;
+ uint8_t id_bit, cmp_id_bit;
+ uint8_t rom_byte_mask, search_direction;
+
+ /* Initialize for search */
+ id_bit_number = 1;
+ last_zero = 0;
+ rom_byte_number = 0;
+ rom_byte_mask = 1;
+ search_result = 0;
+
+ // if the last call was not the last one
+ if (!OneWireStruct->LastDeviceFlag) {
+ // 1-Wire reset
+ if (TM_OneWire_Reset(OneWireStruct)) {
+ /* Reset the search */
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ return 0;
+ }
+
+ // issue the search command
+ TM_OneWire_WriteByte(OneWireStruct, command);
+
+ // loop to do the search
+ do {
+ // read a bit and its complement
+ id_bit = TM_OneWire_ReadBit(OneWireStruct);
+ cmp_id_bit = TM_OneWire_ReadBit(OneWireStruct);
+
+ // check for no devices on 1-wire
+ if ((id_bit == 1) && (cmp_id_bit == 1)) {
+ break;
+ } else {
+ // all devices coupled have 0 or 1
+ if (id_bit != cmp_id_bit) {
+ search_direction = id_bit; // bit write value for search
+ } else {
+ // if this discrepancy if before the Last Discrepancy
+ // on a previous next then pick the same as last time
+ if (id_bit_number < OneWireStruct->LastDiscrepancy) {
+ search_direction = ((OneWireStruct->ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
+ } else {
+ // if equal to last pick 1, if not then pick 0
+ search_direction = (id_bit_number == OneWireStruct->LastDiscrepancy);
+ }
+
+ // if 0 was picked then record its position in LastZero
+ if (search_direction == 0) {
+ last_zero = id_bit_number;
+
+ // check for Last discrepancy in family
+ if (last_zero < 9) {
+ OneWireStruct->LastFamilyDiscrepancy = last_zero;
+ }
+ }
+ }
+
+ // set or clear the bit in the ROM byte rom_byte_number
+ // with mask rom_byte_mask
+ if (search_direction == 1) {
+ OneWireStruct->ROM_NO[rom_byte_number] |= rom_byte_mask;
+ } else {
+ OneWireStruct->ROM_NO[rom_byte_number] &= ~rom_byte_mask;
+ }
+
+ // serial number search direction write bit
+ TM_OneWire_WriteBit(OneWireStruct, search_direction);
+
+ // increment the byte counter id_bit_number
+ // and shift the mask rom_byte_mask
+ id_bit_number++;
+ rom_byte_mask <<= 1;
+
+ // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
+ if (rom_byte_mask == 0) {
+ //docrc8(ROM_NO[rom_byte_number]); // accumulate the CRC
+ rom_byte_number++;
+ rom_byte_mask = 1;
+ }
+ }
+ } while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
+
+ // if the search was successful then
+ if (!(id_bit_number < 65)) {
+ // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
+ OneWireStruct->LastDiscrepancy = last_zero;
+
+ // check for last device
+ if (OneWireStruct->LastDiscrepancy == 0) {
+ OneWireStruct->LastDeviceFlag = 1;
+ }
+
+ search_result = 1;
+ }
+ }
+
+ // if no device found then reset counters so next 'search' will be like a first
+ if (!search_result || !OneWireStruct->ROM_NO[0]) {
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ search_result = 0;
+ }
+
+ return search_result;
+}
+
+int TM_OneWire_Verify(TM_OneWire_t* OneWireStruct) {
+ unsigned char rom_backup[8];
+ int i,rslt,ld_backup,ldf_backup,lfd_backup;
+
+ // keep a backup copy of the current state
+ for (i = 0; i < 8; i++)
+ rom_backup[i] = OneWireStruct->ROM_NO[i];
+ ld_backup = OneWireStruct->LastDiscrepancy;
+ ldf_backup = OneWireStruct->LastDeviceFlag;
+ lfd_backup = OneWireStruct->LastFamilyDiscrepancy;
+
+ // set search to find the same device
+ OneWireStruct->LastDiscrepancy = 64;
+ OneWireStruct->LastDeviceFlag = 0;
+
+ if (TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM)) {
+ // check if same device found
+ rslt = 1;
+ for (i = 0; i < 8; i++) {
+ if (rom_backup[i] != OneWireStruct->ROM_NO[i]) {
+ rslt = 1;
+ break;
+ }
+ }
+ } else {
+ rslt = 0;
+ }
+
+ // restore the search state
+ for (i = 0; i < 8; i++) {
+ OneWireStruct->ROM_NO[i] = rom_backup[i];
+ }
+ OneWireStruct->LastDiscrepancy = ld_backup;
+ OneWireStruct->LastDeviceFlag = ldf_backup;
+ OneWireStruct->LastFamilyDiscrepancy = lfd_backup;
+
+ // return the result of the verify
+ return rslt;
+}
+
+void TM_OneWire_TargetSetup(TM_OneWire_t* OneWireStruct, uint8_t family_code) {
+ uint8_t i;
+
+ // set the search state to find SearchFamily type devices
+ OneWireStruct->ROM_NO[0] = family_code;
+ for (i = 1; i < 8; i++) {
+ OneWireStruct->ROM_NO[i] = 0;
+ }
+
+ OneWireStruct->LastDiscrepancy = 64;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+}
+
+void TM_OneWire_FamilySkipSetup(TM_OneWire_t* OneWireStruct) {
+ // set the Last discrepancy to last family discrepancy
+ OneWireStruct->LastDiscrepancy = OneWireStruct->LastFamilyDiscrepancy;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+
+ // check for end of list
+ if (OneWireStruct->LastDiscrepancy == 0) {
+ OneWireStruct->LastDeviceFlag = 1;
+ }
+}
+
+uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index) {
+ return OneWireStruct->ROM_NO[index];
+}
+
+void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr) {
+ uint8_t i;
+ TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM);
+
+ for (i = 0; i < 8; i++) {
+ TM_OneWire_WriteByte(OneWireStruct, *(addr + i));
+ }
+}
+
+void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t *ROM) {
+ uint8_t i;
+ TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM);
+
+ for (i = 0; i < 8; i++) {
+ TM_OneWire_WriteByte(OneWireStruct, *(ROM + i));
+ }
+}
+
+void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex) {
+ uint8_t i;
+ for (i = 0; i < 8; i++) {
+ *(firstIndex + i) = OneWireStruct->ROM_NO[i];
+ }
+}
+
+uint8_t TM_OneWire_CRC8(uint8_t *addr, uint8_t len) {
+ uint8_t crc = 0, inbyte, i, mix;
+
+ while (len--) {
+ inbyte = *addr++;
+ for (i = 8; i; i--) {
+ mix = (crc ^ inbyte) & 0x01;
+ crc >>= 1;
+ if (mix) {
+ crc ^= 0x8C;
+ }
+ inbyte >>= 1;
+ }
+ }
+
+ /* Return calculated CRC */
+ return crc;
+}
diff --git a/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.h b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.h
new file mode 100644
index 0000000..9b14109
--- /dev/null
+++ b/src/glutt-o-logique/ds18b20/tm_stm32f4_onewire.h
@@ -0,0 +1,300 @@
+/**
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.com
+ * @link http://stm32f4-discovery.com/2014/05/library-12-onewire-library-for-stm43f4xx/
+ * @version v2.1
+ * @ide Keil uVision
+ * @license GNU GPL v3
+ * @brief Onewire library for STM32F4 devices
+ *
+@verbatim
+ ----------------------------------------------------------------------
+ Copyright (C) Tilen Majerle, 2015
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ ----------------------------------------------------------------------
+@endverbatim
+ */
+#ifndef TM_ONEWIRE_H
+#define TM_ONEWIRE_H 210
+
+/* C++ detection */
+#ifdef __cplusplus
+extern C {
+#endif
+
+/**
+ * @addtogroup TM_STM32F4xx_Libraries
+ * @{
+ */
+
+/**
+ * @defgroup TM_ONEWIRE
+ * @brief Onewire library for STM32F4 devices - http://stm32f4-discovery.com/2014/05/library-12-onewire-library-for-stm43f4xx/
+ * @{
+ *
+ * As of version 2.0 you can now use more than just one one-wire "port" on STM32F4. This allows you to group devices to separate ports.
+ *
+ * Because if you have a loot devices on one port, if one device fail, everything is failed. You can prevent this by use more than just one port.
+ *
+ * To set your port and pin for OneWire protocol, you can do this when calling @ref TM_OneWire_Init function.
+ *
+ * \par Changelog
+ *
+@verbatim
+ Version 2.1
+ - March 10, 2015
+ - Added support for new GPIO library
+
+ Version 2.0
+ - January 04, 2015
+ - New OneWire system
+ - With support for multiple OneWire ports to separate group of devices
+
+ Version 1.1
+ - December 06, 2014
+ - Added 8-bit CRC calculation for 1-Wire devices, algorithm from Dallas
+
+ Version 1.0
+ - First release
+@endverbatim
+ *
+ * \par Dependencies
+ *
+@verbatim
+ - STM32F4xx
+ - STM32F4xx RCC
+ - STM32F4xx GPIO
+ - TM GPIO
+@endverbatim
+ */
+#include "stm32f4xx.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_gpio.h"
+
+/**
+ * @defgroup TM_ONEWIRE_Macros
+ * @brief Library defines
+ * @{
+ */
+
+/* Pin settings */
+
+#define ONEWIRE_LOW(structure) TM_GPIO_ResetBits((structure)->GPIOx, (structure)->GPIO_Pin)
+#define ONEWIRE_HIGH(structure) TM_GPIO_SetBits((structure)->GPIOx, (structure)->GPIO_Pin)
+#define ONEWIRE_INPUT(structure) TM_GPIO_SetPinAsInput(structure->GPIOx, (structure)->GPIO_Pin)
+#define ONEWIRE_OUTPUT(structure) TM_GPIO_SetPinAsOutput(structure->GPIOx, (structure)->GPIO_Pin)
+
+/* OneWire commands */
+#define ONEWIRE_CMD_RSCRATCHPAD 0xBE
+#define ONEWIRE_CMD_WSCRATCHPAD 0x4E
+#define ONEWIRE_CMD_CPYSCRATCHPAD 0x48
+#define ONEWIRE_CMD_RECEEPROM 0xB8
+#define ONEWIRE_CMD_RPWRSUPPLY 0xB4
+#define ONEWIRE_CMD_SEARCHROM 0xF0
+#define ONEWIRE_CMD_READROM 0x33
+#define ONEWIRE_CMD_MATCHROM 0x55
+#define ONEWIRE_CMD_SKIPROM 0xCC
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_ONEWIRE_Typedefs
+ * @brief Library Typedefs
+ * @{
+ */
+
+/**
+ * @brief OneWire working struct
+ * @note Except ROM_NO member, everything is fully private and should not be touched by user
+ */
+typedef struct {
+ GPIO_TypeDef* GPIOx; /*!< GPIOx port to be used for I/O functions */
+ uint16_t GPIO_Pin; /*!< GPIO Pin to be used for I/O functions */
+ uint8_t LastDiscrepancy; /*!< Search private */
+ uint8_t LastFamilyDiscrepancy; /*!< Search private */
+ uint8_t LastDeviceFlag; /*!< Search private */
+ uint8_t ROM_NO[8]; /*!< 8-bytes address of last search device */
+} TM_OneWire_t;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_ONEWIRE_Functions
+ * @brief Library Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes OneWire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t empty working onewire structure
+ * @param *Pointer to GPIO port used for onewire channel
+ * @param GPIO_Pin: GPIO Pin on specific GPIOx to be used for onewire channel
+ * @retval None
+ */
+void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
+
+/**
+ * @brief Resets OneWire bus
+ *
+ * @note Sends reset command for OneWire
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval None
+ */
+uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads byte from one wire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval Byte from read operation
+ */
+uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Writes byte to bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @param byte: 8-bit value to write over OneWire protocol
+ * @retval None
+ */
+void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte);
+
+/**
+ * @brief Writes single bit to onewire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @param bit: Bit value to send, 1 or 0
+ * @retval None
+ */
+void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit);
+
+/**
+ * @brief Reads single bit from one wire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval Bit value:
+ * - 0: Bit is low (zero)
+ * - > 0: Bit is high (one)
+ */
+uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Searches for OneWire devices on specific Onewire port
+ * @note Not meant for public use. Use @ref TM_OneWire_First and @ref TM_OneWire_Next for this.
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure where to search
+ * @param Device status:
+ * - 0: No devices detected
+ * - > 0: Device detected
+ */
+uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command);
+
+/**
+ * @brief Resets search states
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values
+ * @retval None
+ */
+void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Starts search, reset states first
+ * @note When you want to search for ALL devices on one onewire port, you should first use this function.
+@verbatim
+/...Initialization before
+status = TM_OneWire_First(&OneWireStruct);
+while (status) {
+ //Save ROM number from device
+ TM_OneWire_GetFullROM(ROM_Array_Pointer);
+ //Check for new device
+ status = TM_OneWire_Next(&OneWireStruct);
+}
+@endverbatim
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values
+ * @param Device status:
+ * - 0: No devices detected
+ * - > 0: Device detected
+ */
+uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads next device
+ * @note Use @ref TM_OneWire_First to start searching
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param Device status:
+ * - 0: No devices detected any more
+ * - > 0: New device detected
+ */
+uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Gets ROM number from device from search
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param index: Because each device has 8-bytes long ROm address, you have to call this 8 times, to get ROM bytes from 0 to 7
+ * @reetval ROM byte for index (0 to 7) at current found device
+ */
+uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index);
+
+/**
+ * @brief Gets all 8 bytes ROM value from device from search
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *firstIndex: Pointer to first location for first byte, other bytes are automatically incremented
+ * @retval None
+ */
+void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex);
+
+/**
+ * @brief Selects specific slave on bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *addr: Pointer to first location of 8-bytes long ROM address
+ * @retval None
+ */
+void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr);
+
+/**
+ * @brief Selects specific slave on bus with pointer address
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *ROM: Pointer to first byte of ROM address
+ * @retval None
+ */
+void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Calculates 8-bit CRC for 1-wire devices
+ * @param *addr: Pointer to 8-bit array of data to calculate CRC
+ * @param len: Number of bytes to check
+ *
+ * @retval Calculated CRC from input data
+ */
+uint8_t TM_OneWire_CRC8(uint8_t* addr, uint8_t len);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/* C++ detection */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/glutt-o-logique/fsm.c b/src/glutt-o-logique/fsm.c
new file mode 100644
index 0000000..99413ba
--- /dev/null
+++ b/src/glutt-o-logique/fsm.c
@@ -0,0 +1,8 @@
+#include "../../../common/src/Core/fsm.c"
+
+
+void fsm_state_switched(char * new_state) {
+ usart_debug_puts("FSM: ");
+ usart_debug_puts(new_state);
+ usart_debug_puts("\r\n");
+}
diff --git a/src/glutt-o-logique/gps.c b/src/glutt-o-logique/gps.c
new file mode 100644
index 0000000..10afe88
--- /dev/null
+++ b/src/glutt-o-logique/gps.c
@@ -0,0 +1,4 @@
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+
+#include "../../../common/src/GPS/gps.c"
diff --git a/src/glutt-o-logique/i2c.c b/src/glutt-o-logique/i2c.c
new file mode 100644
index 0000000..750f5de
--- /dev/null
+++ b/src/glutt-o-logique/i2c.c
@@ -0,0 +1,350 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Matthias P. Braendli
+ *
+ * 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 "GPIO/i2c.h"
+#include "Core/common.h"
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx.h"
+#include "FreeRTOS.h"
+#include "FreeRTOSConfig.h"
+#include "task.h"
+#include "semphr.h"
+#include "GPIO/usart.h"
+
+/* I2C 1 on PB9 and PB6
+ * See pio.txt for PIO allocation details */
+const uint16_t GPIOB_PIN_SDA = GPIO_Pin_9;
+const uint16_t GPIOB_PIN_SCL = GPIO_Pin_6;
+
+
+static int i2c_init_done = 0;
+static int i2c_error = 0;
+
+static I2C_TypeDef* const I2Cx = I2C1;
+
+static SemaphoreHandle_t i2c_semaphore;
+
+static void i2c_device_init(void);
+
+/* According to I2C spec UM10204:
+ * 3.1.16 Bus clear
+ * In the unlikely event where the clock (SCL) is stuck LOW, the preferential
+ * procedure is to reset the bus using the HW reset signal if your I2C devices
+ * have HW reset inputs. If the I2C devices do not have HW reset inputs, cycle
+ * power to the devices to activate the mandatory internal Power-On Reset (POR)
+ * circuit.
+ *
+ * If the data line (SDA) is stuck LOW, the master should send nine clock
+ * pulses. The device that held the bus LOW should release it sometime within
+ * those nine clocks. If not, then use the HW reset or cycle power to clear the
+ * bus.
+ */
+static void i2c_recover_from_lockup(void)
+{
+ usart_debug_puts("ERROR: I2C lockup\r\n");
+
+ I2C_SoftwareResetCmd(I2Cx, ENABLE);
+
+ // Configure I2C SCL and SDA pins.
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = GPIOB_PIN_SCL | GPIOB_PIN_SDA;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ const TickType_t delay = 5 / portTICK_PERIOD_MS;
+
+ GPIO_SetBits(GPIOB, GPIOB_PIN_SDA | GPIOB_PIN_SCL);
+ vTaskDelay(delay);
+
+ for (int i = 0; i < 10; i++) {
+ GPIO_ResetBits(GPIOB, GPIOB_PIN_SCL);
+ vTaskDelay(delay);
+ GPIO_SetBits(GPIOB, GPIOB_PIN_SCL);
+ vTaskDelay(delay);
+ }
+
+ I2C_SoftwareResetCmd(I2Cx, DISABLE);
+
+ i2c_device_init();
+}
+
+static void i2c_device_init(void)
+{
+ // Configure I2C SCL and SDA pins.
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = GPIOB_PIN_SCL | GPIOB_PIN_SDA;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
+ GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
+
+ // Reset I2C.
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
+
+ // configure I2C1
+ I2C_InitTypeDef I2C_InitStruct;
+ I2C_InitStruct.I2C_ClockSpeed = 100000; //Hz
+ I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle
+ I2C_InitStruct.I2C_OwnAddress1 = 0x00; // not relevant in master mode
+
+ // disable acknowledge when reading (can be changed later on)
+ I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;
+
+ I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+ I2C_Init(I2C1, &I2C_InitStruct);
+
+ // enable I2C1
+ I2C_Cmd(I2C1, ENABLE);
+}
+
+void i2c_init()
+{
+ if (i2c_init_done == 1) {
+ return;
+ }
+
+ i2c_semaphore = xSemaphoreCreateBinary();
+
+ if ( i2c_semaphore == NULL ) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+ else {
+ xSemaphoreGive(i2c_semaphore);
+ }
+
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
+
+ i2c_device_init();
+ i2c_init_done = 1;
+}
+
+static int i2c_check_busy_flag(void)
+{
+ const TickType_t i2c_timeout = 1000ul / portTICK_PERIOD_MS;
+ const TickType_t time_start = xTaskGetTickCount();
+
+ while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)) {
+ const TickType_t time_now = xTaskGetTickCount();
+
+ if (time_now - time_start > i2c_timeout) {
+ i2c_error = 1;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int i2c_check_event(uint32_t event)
+{
+ const TickType_t i2c_timeout = 1000ul / portTICK_PERIOD_MS;
+ const TickType_t time_start = xTaskGetTickCount();
+
+ while (!I2C_CheckEvent(I2Cx, event)) {
+ const TickType_t time_now = xTaskGetTickCount();
+
+ if (time_now - time_start > i2c_timeout) {
+ i2c_error = 1;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int i2c_start(uint8_t device, uint8_t direction)
+{
+ I2C_GenerateSTART(I2Cx, ENABLE);
+
+ // wait for bus free
+ if (!i2c_check_event(I2C_EVENT_MASTER_MODE_SELECT)) {
+ I2C_GenerateSTART(I2Cx, DISABLE);
+ return 0;
+ }
+
+ I2C_Send7bitAddress(I2Cx, device << 1, direction);
+
+ /* wait for I2C1 EV6, check if
+ * either Slave has acknowledged Master transmitter or
+ * Master receiver mode, depending on the transmission
+ * direction
+ */
+ uint32_t event = 0;
+ if (direction == I2C_Direction_Transmitter) {
+ event = I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED;
+ }
+ else if (direction == I2C_Direction_Receiver) {
+ event = I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED;
+ }
+ else {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ if (!i2c_check_event(event)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int i2c_send(uint8_t data)
+{
+ I2C_SendData(I2Cx, data);
+
+ // wait for I2C1 EV8_2 --> byte has been transmitted
+ return i2c_check_event(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
+}
+
+int i2c_write(uint8_t device, const uint8_t *txbuf, int len)
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ int success = i2c_check_busy_flag();
+
+ if (success) {
+ success = i2c_start(device, I2C_Direction_Transmitter);
+ }
+
+ if (success) {
+ for (int i = 0; i < len; i++) {
+ success = i2c_send(txbuf[i]);
+ if (!success) {
+ break;
+ }
+ }
+
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+ success = i2c_check_event(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
+ }
+
+ return success;
+}
+
+static int i2c_read_nobuscheck(uint8_t device, uint8_t *rxbuf, int len)
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ if (i2c_start(device, I2C_Direction_Receiver)) {
+ for (int i = 0; i < len; i++) {
+ if (i == len-1) {
+ I2C_AcknowledgeConfig(I2Cx, DISABLE);
+ }
+ else {
+ I2C_AcknowledgeConfig(I2Cx, ENABLE);
+ }
+
+ // wait until one byte has been received, possibly timout
+ if (!i2c_check_event(I2C_EVENT_MASTER_BYTE_RECEIVED)) {
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+ return 0;
+ }
+
+ if (i == len-1) {
+ I2C_GenerateSTOP(I2Cx, ENABLE);
+ }
+
+ rxbuf[i] = I2C_ReceiveData(I2Cx);
+ }
+ return len;
+ }
+
+ return 0;
+}
+
+int i2c_read(uint8_t device, uint8_t *rxbuf, int len)
+{
+ int success = i2c_check_busy_flag();
+
+ if (success) {
+ success = i2c_read_nobuscheck(device, rxbuf, len);
+ }
+
+ return success;
+}
+
+int i2c_read_from(uint8_t device, uint8_t address, uint8_t *rxbuf, int len)
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ int success = i2c_check_busy_flag();
+
+ if (success) {
+ success = i2c_start(device, I2C_Direction_Transmitter);
+ }
+
+ if (success) {
+ success = i2c_send(address);
+ }
+ // Don't do a STOP
+
+ if (success) {
+ success = i2c_read_nobuscheck(device, rxbuf, len);
+ }
+
+ return success;
+}
+
+
+
+void i2c_transaction_start()
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+ xSemaphoreTake(i2c_semaphore, portMAX_DELAY);
+}
+
+void i2c_transaction_end()
+{
+ if (i2c_init_done == 0) {
+ trigger_fault(FAULT_SOURCE_I2C);
+ }
+
+ if ( i2c_error ) {
+ i2c_recover_from_lockup();
+
+ i2c_error = 0;
+ }
+
+ xSemaphoreGive(i2c_semaphore);
+}
+
diff --git a/src/glutt-o-logique/leds.c b/src/glutt-o-logique/leds.c
new file mode 100644
index 0000000..88b46bf
--- /dev/null
+++ b/src/glutt-o-logique/leds.c
@@ -0,0 +1,42 @@
+#include "../../../common/src/GPIO/leds.c"
+
+#include "stm32f4xx_conf.h"
+
+#include "leds.h"
+
+void leds_turn_on(int l) {
+
+ switch (l) {
+ case LED_GREEN:
+ GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_GREEN);
+ break;
+ case LED_ORANGE:
+ GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_ORANGE);
+ break;
+ case LED_RED:
+ GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_RED);
+ break;
+ case LED_BLUE:
+ GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_BLUE);
+ break;
+
+ }
+}
+
+void leds_turn_off(int l) {
+
+ switch (l) {
+ case LED_GREEN:
+ GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_GREEN);
+ break;
+ case LED_ORANGE:
+ GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_ORANGE);
+ break;
+ case LED_RED:
+ GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_RED);
+ break;
+ case LED_BLUE:
+ GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_BLUE);
+ break;
+ }
+}
diff --git a/src/glutt-o-logique/leds.h b/src/glutt-o-logique/leds.h
new file mode 100644
index 0000000..869a032
--- /dev/null
+++ b/src/glutt-o-logique/leds.h
@@ -0,0 +1,4 @@
+#define GPIOD_BOARD_LED_GREEN GPIO_Pin_12
+#define GPIOD_BOARD_LED_ORANGE GPIO_Pin_13
+#define GPIOD_BOARD_LED_RED GPIO_Pin_14
+#define GPIOD_BOARD_LED_BLUE GPIO_Pin_15
diff --git a/src/glutt-o-logique/main.c b/src/glutt-o-logique/main.c
new file mode 100644
index 0000000..21df1d0
--- /dev/null
+++ b/src/glutt-o-logique/main.c
@@ -0,0 +1,69 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony
+ *
+ * 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 "stm32f4xx_conf.h"
+
+#include "leds.h"
+#include "../../../common/src/Core/main.c"
+
+
+void init() {
+ /* Initialise the onboard peripherals
+ * Four LEDs and one push-button
+ */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+
+ // Configure PD12, PD13, PD14 and PD15 in output pushpull mode
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin =
+ GPIOD_BOARD_LED_GREEN |
+ GPIOD_BOARD_LED_ORANGE |
+ GPIOD_BOARD_LED_RED |
+ GPIOD_BOARD_LED_BLUE;
+
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOD, &GPIO_InitStructure);
+
+ // Init PushButton
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // TODO is there an external pullup ?
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+
+ /* Setup Watchdog
+ * The IWDG runs at 32kHz. With a prescaler of 32 -> 1kHz.
+ * Counting to 2000 / 1000 = 2 seconds
+ */
+ IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
+ IWDG_SetPrescaler(IWDG_Prescaler_32);
+ IWDG_SetReload(2000);
+ IWDG_Enable();
+}
diff --git a/src/glutt-o-logique/minmea.c b/src/glutt-o-logique/minmea.c
new file mode 100644
index 0000000..10df198
--- /dev/null
+++ b/src/glutt-o-logique/minmea.c
@@ -0,0 +1 @@
+#include "../../../common/src/GPS/minmea.c"
diff --git a/src/glutt-o-logique/pio.c b/src/glutt-o-logique/pio.c
new file mode 100644
index 0000000..d8780fe
--- /dev/null
+++ b/src/glutt-o-logique/pio.c
@@ -0,0 +1,187 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Matthias P. Braendli
+ *
+ * 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 "stm32f4xx_rcc.h"
+#include "stm32f4xx_gpio.h"
+
+/* See pio.txt for PIO allocation details */
+
+/* On GPIO C */
+#define GPIO_PIN_QRP_n GPIO_Pin_1
+#define GPIO_PIN_TX GPIO_Pin_2
+#define GPIO_PIN_1750_n GPIO_Pin_4
+#define GPIO_PIN_MOD_OFF GPIO_Pin_5
+#define GPIO_PIN_SQ_n GPIO_Pin_6
+#define GPIO_PIN_U GPIO_Pin_8
+#define GPIO_PIN_QRP_out GPIO_Pin_9
+#define GPIO_PIN_D GPIO_Pin_11
+#define GPIO_PIN_REPLIE_n GPIO_Pin_13
+#define GPIO_PIN_FAX_n GPIO_Pin_14
+
+
+#define GPIOC_OUTPUT_PINS ( \
+ GPIO_PIN_TX | \
+ GPIO_PIN_MOD_OFF | \
+ GPIO_PIN_QRP_out | \
+ 0)
+
+#undef GPIOC_OPENDRAIN_PINS
+#undef GPIOC_INPUT_PU_PINS
+
+#define GPIOC_INPUT_PINS ( \
+ GPIO_PIN_QRP_n | \
+ GPIO_PIN_1750_n | \
+ GPIO_PIN_SQ_n | \
+ GPIO_PIN_U | \
+ GPIO_PIN_D | \
+ GPIO_PIN_REPLIE_n | \
+ 0 )
+
+#include "GPIO/pio.h"
+#include "Core/common.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+void read_fsm_input_task(void *pvParameters);
+
+struct fsm_input_signals_t pio_signals;
+
+void pio_init()
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ // Init pio
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
+
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_Pin = GPIOC_OUTPUT_PINS;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+#if defined(GPIOC_OPENDRAIN_PINS)
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_Pin = GPIOC_OPENDRAIN_PINS;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+#endif
+
+#if defined(GPIOC_INPUT_PU_PINS)
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStructure.GPIO_Pin = GPIOC_INPUT_PU_PINS;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+#endif
+
+#if defined(GPIOC_INPUT_PINS)
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStructure.GPIO_Pin = GPIOC_INPUT_PINS;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+#endif
+
+ xTaskCreate(
+ read_fsm_input_task,
+ "TaskPIO",
+ configMINIMAL_STACK_SIZE,
+ (void*) NULL,
+ tskIDLE_PRIORITY + 2UL,
+ NULL);
+}
+
+void pio_set_fsm_signals(struct fsm_input_signals_t* sig)
+{
+ *sig = pio_signals;
+}
+
+void read_fsm_input_task(void *pvParameters)
+{
+ while (1) {
+ pio_signals.qrp =
+ GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_QRP_n) ? 0 : 1;
+
+ pio_signals.tone_1750 =
+ GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_1750_n) ? 0 : 1;
+
+ pio_signals.sq =
+ GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_SQ_n) ? 0 : 1;
+
+ pio_signals.discrim_u =
+ GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_U) ? 1 : 0;
+
+ pio_signals.discrim_d =
+ GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_D) ? 1 : 0;
+
+ pio_signals.wind_generator_ok =
+ GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_REPLIE_n) ? 1 : 0;
+
+ pio_signals.sstv_mode =
+ GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_FAX_n) ? 0 : 1;
+
+ vTaskDelay(100 / portTICK_RATE_MS);
+ }
+}
+
+void pio_set_tx(int on)
+{
+ if (on) {
+ GPIO_SetBits(GPIOC, GPIO_PIN_TX);
+ }
+ else {
+ GPIO_ResetBits(GPIOC, GPIO_PIN_TX);
+ }
+}
+
+void pio_set_qrp(int on)
+{
+ if (on) {
+ GPIO_SetBits(GPIOC, GPIO_PIN_QRP_out);
+ }
+ else {
+ GPIO_ResetBits(GPIOC, GPIO_PIN_QRP_out);
+ }
+}
+
+void pio_set_mod_off(int mod_off)
+{
+ if (mod_off) {
+ GPIO_SetBits(GPIOC, GPIO_PIN_MOD_OFF);
+ }
+ else {
+ GPIO_ResetBits(GPIOC, GPIO_PIN_MOD_OFF);
+ }
+}
+
+int pio_read_button() {
+ return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == Bit_SET;
+}
diff --git a/src/glutt-o-logique/temperature.c b/src/glutt-o-logique/temperature.c
new file mode 100644
index 0000000..780a019
--- /dev/null
+++ b/src/glutt-o-logique/temperature.c
@@ -0,0 +1,93 @@
+/* On wire connection: PA1
+ */
+
+#define TEMPERATURE_ONEWIRE_PIN GPIO_Pin_1
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+
+#include "tm_stm32f4_ds18b20.h"
+#include "tm_stm32f4_onewire.h"
+#include "Core/delay.h"
+
+
+#include "../../../common/src/GPIO/temperature.c"
+
+const TickType_t _temperature_delay = 60000 / portTICK_PERIOD_MS; // 60s
+
+static TM_OneWire_t tm_onewire;
+
+
+
+void ds18b20_init() {
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = TEMPERATURE_ONEWIRE_PIN;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+ vTaskSuspendAll();
+ TM_OneWire_Init(&tm_onewire, GPIOA, TEMPERATURE_ONEWIRE_PIN);
+ xTaskResumeAll();
+}
+
+int ds18b20_gettemp_one(float *temperature) {
+
+ vTaskSuspendAll();
+
+ uint8_t rom_addr[8];
+
+ TM_DS18B20_StartAll(&tm_onewire);
+ int status = TM_OneWire_First(&tm_onewire);
+ if (status) {
+ //Save ROM number from device
+ TM_OneWire_GetFullROM(&tm_onewire, rom_addr);
+ TM_DS18B20_Start(&tm_onewire, rom_addr);
+
+ // The sensor needs time to do the conversion
+ xTaskResumeAll();
+ delay_ms(100);
+ vTaskSuspendAll();
+ status = TM_DS18B20_Read(&tm_onewire, rom_addr, temperature);
+ }
+
+ xTaskResumeAll();
+
+ return status;
+}
+
+int ds18b20_gettemp(float *temperature) {
+ int status;
+ for (int i = 0; i < 10; i++) {
+ status = ds18b20_gettemp_one(temperature);
+
+ if (status) {
+ break;
+ }
+ delay_ms(5);
+ }
+ return status;
+}
+
+static void temperature_task(void *pvParameters) {
+
+ while (1) {
+
+ if (!_temperature_valid) {
+ ds18b20_init();
+ }
+
+ if (ds18b20_gettemp(&_temperature_last_value)) {
+ _temperature_valid = 1;
+ } else {
+ _temperature_valid = 0;
+ }
+
+ vTaskDelay(_temperature_delay);
+
+ }
+}
diff --git a/src/glutt-o-logique/usart.c b/src/glutt-o-logique/usart.c
new file mode 100644
index 0000000..d174719
--- /dev/null
+++ b/src/glutt-o-logique/usart.c
@@ -0,0 +1,156 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Matthias P. Braendli
+ *
+ * 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 <stm32f4xx.h>
+#include <stm32f4xx_usart.h>
+#include <stm32f4xx_conf.h>
+
+/* USART 3 on PD8 and PD9
+ * See pio.txt for PIO allocation details */
+const uint16_t GPIOD_PIN_USART3_TX = GPIO_Pin_8;
+const uint16_t GPIOD_PIN_USART3_RX = GPIO_Pin_9;
+
+/* USART 2 on PA2 and PA3 */
+const uint16_t GPIOA_PIN_USART2_RX = GPIO_Pin_3;
+const uint16_t GPIOA_PIN_USART2_TX = GPIO_Pin_2;
+
+static void usart_puts(USART_TypeDef*, const char*);
+
+#include "../../../common/includes/GPIO/usart.h"
+#include "../../../common/src/GPIO/usart.c"
+
+
+void usart_init() {
+ // ============== PC DEBUG USART ===========
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitStruct.GPIO_Pin = GPIOA_PIN_USART2_RX | GPIOA_PIN_USART2_TX;
+ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
+ GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
+
+ // Setup USART2 for 9600,8,N,1
+ USART_InitTypeDef USART_InitStruct;
+ USART_InitStruct.USART_BaudRate = 9600;
+ USART_InitStruct.USART_WordLength = USART_WordLength_8b;
+ USART_InitStruct.USART_StopBits = USART_StopBits_1;
+ USART_InitStruct.USART_Parity = USART_Parity_No;
+ USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+ USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
+ USART_Init(USART2, &USART_InitStruct);
+
+#if USART2_RECEIVE_ENABLE
+ // enable the USART2 receive interrupt
+ USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
+
+ NVIC_InitTypeDef NVIC_InitStructure;
+ NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ NVIC_SetPriority(USART2_IRQn, 6);
+#endif
+
+ // finally this enables the complete USART2 peripheral
+ USART_Cmd(USART2, ENABLE);
+}
+
+void usart_gps_specific_init() {
+
+ // ============== GPS USART ===========
+ // Setup GPIO D and connect to USART 3
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitStruct.GPIO_Pin = GPIOD_PIN_USART3_RX | GPIOD_PIN_USART3_TX;
+ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(GPIOD, &GPIO_InitStruct);
+
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3);
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);
+
+ // Setup USART3 for 9600,8,N,1
+ USART_InitTypeDef USART_InitStruct;
+ USART_InitStruct.USART_BaudRate = 9600;
+ USART_InitStruct.USART_WordLength = USART_WordLength_8b;
+ USART_InitStruct.USART_StopBits = USART_StopBits_1;
+ USART_InitStruct.USART_Parity = USART_Parity_No;
+ USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+ USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
+ USART_Init(USART3, &USART_InitStruct);
+
+
+ // enable the USART3 receive interrupt
+ USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
+
+ NVIC_InitTypeDef NVIC_InitStructure;
+ NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ NVIC_SetPriority(USART3_IRQn, 6);
+
+ // finally this enables the complete USART3 peripheral
+ USART_Cmd(USART3, ENABLE);
+}
+
+// Make sure Tasks are suspended when this is called!
+static void usart_puts(USART_TypeDef* USART, const char* str) {
+ while(*str) {
+ // wait until data register is empty
+ USART_SendData(USART, *str);
+ while(USART_GetFlagStatus(USART, USART_FLAG_TXE) == RESET) ;
+ str++;
+ }
+}
+
+void USART3_IRQHandler(void) {
+ if (USART_GetITStatus(USART3, USART_IT_RXNE)) {
+ char t = USART3->DR;
+ usart_gps_process_char(t);
+ }
+}
+
+void USART2_IRQHandler(void) {
+ if (USART_GetITStatus(USART2, USART_IT_RXNE)) {
+ char t = USART2->DR;
+ usart_process_char(t);
+ }
+}