Update documentation and do some basic housekeeping
This commit is contained in:
12
.gitmodules
vendored
12
.gitmodules
vendored
@@ -1,7 +1,7 @@
|
|||||||
[submodule "opt/tools"]
|
[submodule "tools"]
|
||||||
path = opt/tools
|
path = opt/tools
|
||||||
url = git@github.com:madcow/drybox-tools.git
|
url = git@github.com:madcow/drybox-tools.git
|
||||||
|
|
||||||
[submodule "opt/webgui"]
|
[submodule "webgui"]
|
||||||
path = opt/webgui
|
path = opt/webgui
|
||||||
url = git@github.com:madcow/drybox-webgui.git
|
url = git@github.com:madcow/drybox-webgui.git
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -62,7 +62,7 @@ flash: $(TARGET)
|
|||||||
-c $(ASP) -p $(ARCH) \
|
-c $(ASP) -p $(ARCH) \
|
||||||
-U lfuse:w:0xff:m \
|
-U lfuse:w:0xff:m \
|
||||||
-U hfuse:w:0x91:m \
|
-U hfuse:w:0x91:m \
|
||||||
-U flash:w:$(TARGET)
|
-U flash:w:$<
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@@ -85,6 +85,11 @@ listen: ./opt/tools/serial-listen.py
|
|||||||
$(E) "[PY3] $<"
|
$(E) "[PY3] $<"
|
||||||
$(Q) ./$<
|
$(Q) ./$<
|
||||||
|
|
||||||
|
.PHONY: listen-web
|
||||||
|
listen-web: ./opt/webgui/Makefile
|
||||||
|
$(E) "[MAK] $(<D)"
|
||||||
|
$(Q) $(MAKE) -sC $(<D)
|
||||||
|
|
||||||
$(TMPDIRS):
|
$(TMPDIRS):
|
||||||
$(E) "[DIR] $@"
|
$(E) "[DIR] $@"
|
||||||
$(Q) $(MKDIR) $@
|
$(Q) $(MKDIR) $@
|
||||||
|
|||||||
73
docs/CHANGELOG.md
Normal file
73
docs/CHANGELOG.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
## Changelog
|
||||||
|
|
||||||
|
### v0.75-alpha1
|
||||||
|
- Fix parser tail pointer semantics.
|
||||||
|
- Improve sensor log readability and minor naming fixes.
|
||||||
|
- Add multiple README sections and use markdown formatting.
|
||||||
|
- Reduce RXBUF size to match parser and space out log messages.
|
||||||
|
- Prevent redundant writes and start implementing parser timeout.
|
||||||
|
- Fix large serial command input triggering watchdog.
|
||||||
|
- Merge pull request #5 from madcow/parser.
|
||||||
|
- Implement serial command parser with floating point support.
|
||||||
|
- Merge pull request #4 from madcow/eeprom-sentinel-v2.
|
||||||
|
- Use reference sentinel to efficiently reset dirty flags on rollover.
|
||||||
|
- Merge pull request #3 from madcow/eeprom-testing.
|
||||||
|
- Pass variable structure as argument for memory functions.
|
||||||
|
- Fix possible race condition and ensure proper reset flag detection.
|
||||||
|
- Check MCUCSR for WDRF flag only and add TODO.
|
||||||
|
- Implement memory wear leveling algorithm.
|
||||||
|
- Define memory manager constants and add TODO.
|
||||||
|
- Merge pull request #2 from madcow/eeprom.
|
||||||
|
- Dump EEPROM to ensure low level memory access is working correctly.
|
||||||
|
- Implement raw EEPROM read and write functionality.
|
||||||
|
- Burn EESAVE fuse to preserve EEPROM on chip erase.
|
||||||
|
- Define basic EEPROM data structures and functions.
|
||||||
|
- Merge pull request #1 from madcow/thermistor.
|
||||||
|
- Implement alternate voltage divider equation.
|
||||||
|
- Calculate average dewpoint from multiple sensor measurements.
|
||||||
|
- Test different approach for resistance calculation.
|
||||||
|
- Ensure math functions are named consistently.
|
||||||
|
- Make sure dewpoint calculations are correct.
|
||||||
|
- Split thermistor functions into separate logical units and add TODO.
|
||||||
|
- Implement all required conversion functions.
|
||||||
|
- Define conversion functions for TD, T and RH.
|
||||||
|
- Update planned FREQ, ARCH, MCU and fix superfluous whitespace.
|
||||||
|
- Define basic structure for primary state machine and update TODOs.
|
||||||
|
- Remove executable bit from pdf files.
|
||||||
|
- Add data sheet for ATMEGA1284P-PU.
|
||||||
|
- Poll ADC mode bit until conversion has finished.
|
||||||
|
- Set FAN03 to maximum duty and declutter log output.
|
||||||
|
- Calculate temperature from thermistor resistance.
|
||||||
|
- Set ADC gain to 6.144V and fix multiplexer channel documentation.
|
||||||
|
- Define constants for ADC multiplexer settings and describe I2C status flags.
|
||||||
|
- Define constants for watchdog timeout flags.
|
||||||
|
- Initialize OCR1A to FAN02\_MIN\_DUTY and add PWM documentation.
|
||||||
|
- Minor coding style and consistency fixes.
|
||||||
|
- Jump to reset vector when program exceeds specified watchdog timeout.
|
||||||
|
- Start implementing watchdog timer.
|
||||||
|
- Make log output slightly more readable.
|
||||||
|
- Implement ADS1115 register reading and writing.
|
||||||
|
- Try setting variable PWM frequency with timer2.
|
||||||
|
- Set pin for light MOSFET to low in MOS\_Init.
|
||||||
|
- Remove invisible runtime assertions.
|
||||||
|
- Rename module TWI to I2C and add comments.
|
||||||
|
- Read and translate AHT20 sensor readings.
|
||||||
|
- Move PWM and MOSFET implementations into separate module files.
|
||||||
|
- Ensure correct naming for PWM devices.
|
||||||
|
- Calculate PWM\_CYCLE\_TOP from F\_CPU.
|
||||||
|
- Add more general SetMosState() and SetPwmValue() functions.
|
||||||
|
- Configure PWM timers for 25 KHz.
|
||||||
|
- Handle PWM on pin PD4, PD5 and PD7.
|
||||||
|
- Start working on system initialization.
|
||||||
|
- Add data sheets for ADS1115 and AHT20.
|
||||||
|
- Handle I2C multiplexer channel selection.
|
||||||
|
- Implement USART with bot RX and TX interrupts.
|
||||||
|
- Rewrite logging system and sync state with clients.
|
||||||
|
- Handle numeric arguments for TEMP/DEWP commands.
|
||||||
|
- Update documentation and add USART specification.
|
||||||
|
- Start implementing proper parser state machine.
|
||||||
|
- Add optional project submodules 'tools' and 'webgui'.
|
||||||
|
- Implement ring buffer and auxiliary functions.
|
||||||
|
- Add swapfiles and bin/ to .gitignore.
|
||||||
|
- Handle USART\_RXC interrupt.
|
||||||
|
- Implement basic UART reading.
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
You must have avr-gcc and avrdude installed. To install both
|
You must have avr-gcc and avrdude installed. To install both
|
||||||
tools on a debian-based system, please run the following
|
tools on a Debian-based system, please run the following
|
||||||
command:
|
command:
|
||||||
|
|
||||||
apt install avr-gcc avrdude
|
apt install avr-gcc avrdude
|
||||||
@@ -12,35 +12,51 @@ The names for these dependencies may differ for other package
|
|||||||
managers and distributions. Please check the package sources
|
managers and distributions. Please check the package sources
|
||||||
on your system for more information.
|
on your system for more information.
|
||||||
|
|
||||||
|
You will also need an in-circuit programmer for Atmel AVR
|
||||||
|
controllers like the [USBasp](https://www.fischl.de/usbasp).
|
||||||
|
If you want to send commands and receive debug output you
|
||||||
|
must make sure to have a serial interface available at
|
||||||
|
`/dev/ttyUSB0`.
|
||||||
|
|
||||||
### Build and Install
|
### Build and Install
|
||||||
|
|
||||||
Run this next command in the project root directory to
|
Run this next command in the project root directory to
|
||||||
build and install the project using an USBasp programmer:
|
build and install the project:
|
||||||
|
|
||||||
make all
|
make all
|
||||||
|
|
||||||
If there are any errors during the flashing process you
|
If there are any errors during the flashing process you
|
||||||
should find more information in core.log in the bin/
|
should find more information in core.log in the bin/
|
||||||
directory. See the Makefile for different settings for
|
directory. See the Makefile for different settings for
|
||||||
your specific build environment. To remove all build
|
your specific build environment.
|
||||||
related auxiliary files you may run these commands:
|
|
||||||
|
To remove all build related auxiliary files you may run
|
||||||
|
these commands:
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
make distclean
|
make distclean
|
||||||
|
|
||||||
You can listen on the serial debug interface using the
|
You can listen on the serial debug interface using the
|
||||||
command below (if you have initialized the optional
|
command below (if you have initialized the optional
|
||||||
submodules as described in the next section):
|
submodules as described in the 'Setting a New Target'
|
||||||
|
section):
|
||||||
|
|
||||||
make listen
|
make listen
|
||||||
|
|
||||||
### Temperature and Dewpoint Targets
|
Alternatively you can spin up a web server on port 443
|
||||||
|
to interface with the device using the following command.
|
||||||
|
Make sure to read section 'Webinterface Example' for more
|
||||||
|
information.
|
||||||
|
|
||||||
You can use the script below to send serial commands (you
|
make listen-web
|
||||||
may need to run `git submodule update --init` if the tools
|
|
||||||
|
### Setting a New Target
|
||||||
|
|
||||||
|
The script below allows you to send serial commands (you
|
||||||
|
may need to run `git submodule update --init` if the tools/
|
||||||
directory is empty):
|
directory is empty):
|
||||||
|
|
||||||
./opt/tools/serial-send.py <command> <args, ...>
|
./opt/tools/serial-send.py <command> <args ...>
|
||||||
|
|
||||||
Issue the SET command to update the target settings:
|
Issue the SET command to update the target settings:
|
||||||
|
|
||||||
@@ -50,3 +66,19 @@ Settings are stored in EEPROM and are persistent until a new
|
|||||||
SET command is issued. Keywords are not case-sensitive. Both
|
SET command is issued. Keywords are not case-sensitive. Both
|
||||||
arguments may contain a decimal point followed by a sequence
|
arguments may contain a decimal point followed by a sequence
|
||||||
of digits.
|
of digits.
|
||||||
|
|
||||||
|
### Webinterface Example
|
||||||
|
|
||||||
|
There is an example Python web server utilizing websockets you
|
||||||
|
can check out in `opt/webgui`. It should give you a basis for
|
||||||
|
writing a custom network bridge and integrating the device into
|
||||||
|
your home automation system.
|
||||||
|
|
||||||
|
You must generate a self-signed certificate before you run the
|
||||||
|
server. The configuration script will take care of it:
|
||||||
|
|
||||||
|
./opt/webgui/configure
|
||||||
|
|
||||||
|
See the README file in the webgui/ directory for prerequisites
|
||||||
|
and more information. Please be aware that development for the
|
||||||
|
web server has paused until the core has reached version v1.0.
|
||||||
|
|||||||
Submodule opt/webgui updated: b616559a36...bd60c0e13d
@@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#define UNUSED(s) (void)(s)
|
#define UNUSED(s) (void)(s)
|
||||||
#define BIT(n) (0x1U << (n))
|
#define BIT(n) (0x1U << (n))
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
#define CLAMP(n, hi, lo) (MIN((hi), MAX((n), (lo))))
|
#define CLAMP(n, hi, lo) (MIN((hi), MAX((n), (lo))))
|
||||||
|
|
||||||
void Info(const char *fmt, ...);
|
void Info(const char *fmt, ...);
|
||||||
|
|||||||
@@ -62,19 +62,19 @@ void MEM_Write(mem_block_t *in)
|
|||||||
WriteBlock(head, in);
|
WriteBlock(head, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MEM_Read(mem_block_t *out)
|
bool MEM_Read(mem_block_t *out)
|
||||||
{
|
{
|
||||||
int head;
|
int head;
|
||||||
|
|
||||||
head = GetUsedBlock();
|
head = GetUsedBlock();
|
||||||
|
|
||||||
if (head < 0) { // Empty?
|
if (head < 0) { // Empty?
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadBlock(head, out);
|
ReadBlock(head, out);
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MEM_Free(void)
|
void MEM_Free(void)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef MAD_CORE_COMMON_MEMORY_H
|
#ifndef MAD_CORE_COMMON_MEMORY_H
|
||||||
#define MAD_CORE_COMMON_MEMORY_H
|
#define MAD_CORE_COMMON_MEMORY_H
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
typedef struct mem_block_s mem_block_t;
|
typedef struct mem_block_s mem_block_t;
|
||||||
|
|
||||||
// Important: Must reset EEPROM memory when the size of
|
// Important: Must reset EEPROM memory when the size of
|
||||||
@@ -13,7 +15,7 @@ struct mem_block_s {
|
|||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
void MEM_Write(mem_block_t *in);
|
void MEM_Write(mem_block_t *in);
|
||||||
int MEM_Read(mem_block_t *out);
|
bool MEM_Read(mem_block_t *out);
|
||||||
void MEM_Free(void);
|
void MEM_Free(void);
|
||||||
void MEM_Dump(void);
|
void MEM_Dump(void);
|
||||||
|
|
||||||
|
|||||||
50
src/main.c
50
src/main.c
@@ -76,17 +76,11 @@ static int Init(void)
|
|||||||
WDT_Enable();
|
WDT_Enable();
|
||||||
WDT_SetTimeoutFlag(WDT2000); // 2 seconds
|
WDT_SetTimeoutFlag(WDT2000); // 2 seconds
|
||||||
|
|
||||||
// Test persistent settings from EEPROM. There must
|
// See if there are persistent target settings
|
||||||
// be some sanity checking before these values are
|
// stored in EEPROM and load them. Some sanity
|
||||||
// used.
|
// checking must be done before using those.
|
||||||
|
|
||||||
// mem.temp = 20.50f;
|
if (MEM_Read(&mem)) { // Any valid blocks found?
|
||||||
// mem.dewp = 10.25f;
|
|
||||||
// MEM_Write(&mem);
|
|
||||||
// MEM_Dump();
|
|
||||||
// MEM_Free();
|
|
||||||
|
|
||||||
if (MEM_Read(&mem) == 0) {
|
|
||||||
Info("Found persistent configuration in EEPROM!");
|
Info("Found persistent configuration in EEPROM!");
|
||||||
Info("Using targets TEMP=%.2fC, DEWP=%.2fC.",
|
Info("Using targets TEMP=%.2fC, DEWP=%.2fC.",
|
||||||
mem.temp, mem.dewp);
|
mem.temp, mem.dewp);
|
||||||
@@ -95,6 +89,12 @@ static int Init(void)
|
|||||||
dewp_target = mem.dewp;
|
dewp_target = mem.dewp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mem.temp = 20.50f;
|
||||||
|
// mem.dewp = 10.25f;
|
||||||
|
// MEM_Write(&mem);
|
||||||
|
// MEM_Dump();
|
||||||
|
// MEM_Free();
|
||||||
|
|
||||||
// There is a possiblity to use interrupt signals
|
// There is a possiblity to use interrupt signals
|
||||||
// for I2C communication but only as one large
|
// for I2C communication but only as one large
|
||||||
// branching routine for the whole I2C system.
|
// branching routine for the whole I2C system.
|
||||||
@@ -156,7 +156,7 @@ static void Update(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get sensor values
|
// Get latest sensor values
|
||||||
FetchSensorValues();
|
FetchSensorValues();
|
||||||
|
|
||||||
// Handle state
|
// Handle state
|
||||||
@@ -179,23 +179,25 @@ static void SetTarget(float t, float td)
|
|||||||
Print("\r\n");
|
Print("\r\n");
|
||||||
Info("Updating target configuration:");
|
Info("Updating target configuration:");
|
||||||
Info("Setting temperature to %.2fC.", t);
|
Info("Setting temperature to %.2fC.", t);
|
||||||
Info("Setting new dewpoint to %.2fC.", td);
|
Info("Setting dewpoint to %.2fC.", td);
|
||||||
|
|
||||||
if (MEM_Read(&mem) == 0) {
|
// Even with level wearing there is a finite number
|
||||||
|
// of EEPROM write cycles so we should always check
|
||||||
|
// for redundant values. This could be handled by
|
||||||
|
// the underlying memory implementation.
|
||||||
|
|
||||||
|
if (MEM_Read(&mem)) {
|
||||||
if (t == mem.temp && td == mem.dewp) {
|
if (t == mem.temp && td == mem.dewp) {
|
||||||
return; // Nothing to do
|
return; // Nothing to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.temp = t;
|
// Update current targets
|
||||||
mem.dewp = td;
|
mem.temp = temp_target = t;
|
||||||
|
mem.dewp = dewp_target = td;
|
||||||
|
|
||||||
// Keep in EEPROM
|
// Store in EEPROM
|
||||||
MEM_Write(&mem);
|
MEM_Write(&mem);
|
||||||
|
|
||||||
// Update state
|
|
||||||
temp_target = t;
|
|
||||||
dewp_target = td;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FetchSensorValues(void)
|
static void FetchSensorValues(void)
|
||||||
@@ -204,23 +206,19 @@ static void FetchSensorValues(void)
|
|||||||
float t[6], rh[3], td[3];
|
float t[6], rh[3], td[3];
|
||||||
|
|
||||||
Print("\r\n");
|
Print("\r\n");
|
||||||
Info("Reading sensor values...");
|
Info("Fetching sensor values...");
|
||||||
|
|
||||||
I2C_SetChannel(AHT01);
|
I2C_SetChannel(AHT01);
|
||||||
I2C_AHT20_Read(&t[0], &rh[0]);
|
I2C_AHT20_Read(&t[0], &rh[0]);
|
||||||
|
|
||||||
I2C_SetChannel(AHT02);
|
I2C_SetChannel(AHT02);
|
||||||
I2C_AHT20_Read(&t[1], &rh[1]);
|
I2C_AHT20_Read(&t[1], &rh[1]);
|
||||||
|
|
||||||
I2C_SetChannel(AHT03);
|
I2C_SetChannel(AHT03);
|
||||||
I2C_AHT20_Read(&t[2], &rh[2]);
|
I2C_AHT20_Read(&t[2], &rh[2]);
|
||||||
|
|
||||||
raw = I2C_ADS1115_ReadRaw(ADS01);
|
raw = I2C_ADS1115_ReadRaw(ADS01);
|
||||||
t[3] = SteinhartHart(Resistance(raw));
|
t[3] = SteinhartHart(Resistance(raw));
|
||||||
|
|
||||||
raw = I2C_ADS1115_ReadRaw(ADS02);
|
raw = I2C_ADS1115_ReadRaw(ADS02);
|
||||||
t[4] = SteinhartHart(Resistance(raw));
|
t[4] = SteinhartHart(Resistance(raw));
|
||||||
|
|
||||||
raw = I2C_ADS1115_ReadRaw(ADS03);
|
raw = I2C_ADS1115_ReadRaw(ADS03);
|
||||||
t[5] = SteinhartHart(Resistance(raw));
|
t[5] = SteinhartHart(Resistance(raw));
|
||||||
|
|
||||||
@@ -230,7 +228,7 @@ static void FetchSensorValues(void)
|
|||||||
|
|
||||||
temp = (t[0] + t[1] + t[2]) / 3;
|
temp = (t[0] + t[1] + t[2]) / 3;
|
||||||
rhum = (rh[0] + rh[1] + rh[2]) / 3;
|
rhum = (rh[0] + rh[1] + rh[2]) / 3;
|
||||||
dewp = Dewpoint(temp, rhum);
|
dewp = (td[0] + td[1] + td[2]) / 3;
|
||||||
|
|
||||||
Info("T1=%.2fC, TD1=%.2fC, RH1=%.2f%%, NT1=%.2fC", t[0], td[0], rh[0], t[3]);
|
Info("T1=%.2fC, TD1=%.2fC, RH1=%.2f%%, NT1=%.2fC", t[0], td[0], rh[0], t[3]);
|
||||||
Info("T2=%.2fC, TD2=%.2fC, RH2=%.2f%%, NT2=%.2fC", t[1], td[1], rh[1], t[4]);
|
Info("T2=%.2fC, TD2=%.2fC, RH2=%.2f%%, NT2=%.2fC", t[1], td[1], rh[1], t[4]);
|
||||||
|
|||||||
Reference in New Issue
Block a user