Cleaned up build tool, added stub for ds3231.
This commit is contained in:
		
							parent
							
								
									d6d6007e62
								
							
						
					
					
						commit
						8b076146cb
					
				| 
						 | 
					@ -1 +1,2 @@
 | 
				
			||||||
bin/
 | 
					bin/
 | 
				
			||||||
 | 
					build
 | 
				
			||||||
							
								
								
									
										27
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										27
									
								
								Makefile
								
								
								
								
							| 
						 | 
					@ -1,27 +0,0 @@
 | 
				
			||||||
all: clean build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
clean:
 | 
					 | 
				
			||||||
	rm -rf bin/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# The following settings are very important!
 | 
					 | 
				
			||||||
# -c arduino for flashing to an AVR device with arduino bootloader.
 | 
					 | 
				
			||||||
# -p atmega328p is for the specific microcontroller.
 | 
					 | 
				
			||||||
# -b 57600 is the baudrate for transmission. Nano boards ONLY accept 57600, uno boards might accept 115200.
 | 
					 | 
				
			||||||
# -P specifies the port.
 | 
					 | 
				
			||||||
flash: build
 | 
					 | 
				
			||||||
	avrdude -c arduino -p atmega328p -P /dev/ttyUSB0 -b 57600 -U flash:w:bin/gympal.hex:i
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
build: gympal.hex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gympal.hex: gympal.o control.o
 | 
					 | 
				
			||||||
	avr-gcc -Os -mmcu=atmega328p -o bin/gympal.elf bin/gympal.o bin/control.o
 | 
					 | 
				
			||||||
	avr-objcopy -O ihex -R .eeprom bin/gympal.elf bin/gympal.hex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gympal.o: src/gympal.c bin
 | 
					 | 
				
			||||||
	avr-gcc -Wall -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o bin/gympal.o src/gympal.c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
control.o: src/control.c bin
 | 
					 | 
				
			||||||
	avr-gcc -Wall -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o bin/control.o src/control.c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bin:
 | 
					 | 
				
			||||||
	mkdir bin
 | 
					 | 
				
			||||||
| 
						 | 
					@ -6,9 +6,13 @@ The GymPal is a lightweight piece of hardware with built-in storage, time-keepin
 | 
				
			||||||
## Development
 | 
					## Development
 | 
				
			||||||
The software for this system is developed in C, using [avr-libc](https://www.nongnu.org/avr-libc/), and the build toolchain is managed by make, using [avr-gcc](https://linux.die.net/man/1/avr-gcc) and [avr-dude](https://github.com/avrdudes/avrdude) to upload firmware to the Atmega328p microcontroller.
 | 
					The software for this system is developed in C, using [avr-libc](https://www.nongnu.org/avr-libc/), and the build toolchain is managed by make, using [avr-gcc](https://linux.die.net/man/1/avr-gcc) and [avr-dude](https://github.com/avrdudes/avrdude) to upload firmware to the Atmega328p microcontroller.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To compile the firmware, you can run `make`.
 | 
					```shell
 | 
				
			||||||
 | 
					sudo apt install gcc-avr
 | 
				
			||||||
 | 
					sudo apt install avr-libc
 | 
				
			||||||
 | 
					sudo apt install avrdude
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To upload the firmware to an Arduino, run `make flash`.
 | 
					After cloning this repository, you must first compile the build script with `./prepare-build-tools.d`. Then, you can run `./build <command>` to run various build commands. See `./build help` for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Hardware
 | 
					## Hardware
 | 
				
			||||||
Here's a list of the hardware that this project uses, just for reference:
 | 
					Here's a list of the hardware that this project uses, just for reference:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					# Build-Tools
 | 
				
			||||||
 | 
					This directory contains the sources for a small D program that manages compilation and uploading of code to AVR devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run `./prepare-build-tools.d` from the main project directory to compile it.
 | 
				
			||||||
| 
						 | 
					@ -9,13 +9,9 @@ import std.file;
 | 
				
			||||||
import std.string;
 | 
					import std.string;
 | 
				
			||||||
import std.conv;
 | 
					import std.conv;
 | 
				
			||||||
import std.path;
 | 
					import std.path;
 | 
				
			||||||
import std.digest.md;
 | 
					 | 
				
			||||||
import std.base64;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const string MCU_ID = "atmega328p";
 | 
					import util;
 | 
				
			||||||
const ulong CPU_FREQ = 16_000_000;
 | 
					import hash;
 | 
				
			||||||
const string BOOTLOADER = "arduino";
 | 
					 | 
				
			||||||
const ulong AVRDUDE_BAUDRATE = 57_600;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const string SOURCE_DIR = "src";
 | 
					const string SOURCE_DIR = "src";
 | 
				
			||||||
const string BUILD_DIR = "bin";
 | 
					const string BUILD_DIR = "bin";
 | 
				
			||||||
| 
						 | 
					@ -28,12 +24,20 @@ const string[] COMPILER_FLAGS = [
 | 
				
			||||||
    "-mmcu=atmega328p"
 | 
					    "-mmcu=atmega328p"
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const string[] AVRDUDE_FLAGS = [
 | 
				
			||||||
 | 
					    "-c arduino",
 | 
				
			||||||
 | 
					    "-p m328p",
 | 
				
			||||||
 | 
					    "-P /dev/ttyUSB0",
 | 
				
			||||||
 | 
					    "-b 57600",
 | 
				
			||||||
 | 
					    "-u"
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
alias BuildCommand = int function(string[]);
 | 
					alias BuildCommand = int function(string[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(string[] args) {
 | 
					int main(string[] args) {
 | 
				
			||||||
    string command;
 | 
					    string command;
 | 
				
			||||||
    if (args.length < 2) {
 | 
					    if (args.length < 2) {
 | 
				
			||||||
        command = "help";
 | 
					        command = "build";
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        command = args[1].strip.toLower;
 | 
					        command = args[1].strip.toLower;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -57,16 +61,21 @@ int main(string[] args) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int helpCommand(string[] args) {
 | 
					int helpCommand(string[] args) {
 | 
				
			||||||
    writeln("build.d - A simple build script for C files.");
 | 
					    writeln("build.d - A simple build script for C files.");
 | 
				
			||||||
 | 
					    writeln("--------------------------------------------");
 | 
				
			||||||
 | 
					    writeln("Usage: ./build.d <command> [args...]");
 | 
				
			||||||
 | 
					    writeln("");
 | 
				
			||||||
    writeln("The following commands are available:");
 | 
					    writeln("The following commands are available:");
 | 
				
			||||||
    writeln("build [-f] - Compiles source code. Use -f to force rebuild.");
 | 
					    writeln("  build [-f]    Compiles source code. Use -f to force rebuild.");
 | 
				
			||||||
    writeln("  By default, sources are hashed, and only built if changes are detected.");
 | 
					    writeln("                By default, sources are hashed, and only built if changes are detected.");
 | 
				
			||||||
    writeln("flash [buildArgs] - Flashes code onto a connected AVR device via AVRDude.");
 | 
					    writeln("                This is also the default command if none is specified.");
 | 
				
			||||||
    writeln("clean - Removes all build files.");
 | 
					    writeln("  flash         Flashes code onto a connected AVR device via AVRDude.");
 | 
				
			||||||
    writeln("help - Shows this help information.");
 | 
					    writeln("  clean         Removes all build files.");
 | 
				
			||||||
 | 
					    writeln("  help          Shows this help information.");
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int clean(string[] args) {
 | 
					int clean(string[] args) {
 | 
				
			||||||
 | 
					    if (!exists(BUILD_DIR)) return 0;
 | 
				
			||||||
    rmdirRecurse(BUILD_DIR);
 | 
					    rmdirRecurse(BUILD_DIR);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -77,9 +86,16 @@ int buildCommand(string[] args) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int flashCommand(string[] args) {
 | 
					int flashCommand(string[] args) {
 | 
				
			||||||
    int result = buildCommand(args);
 | 
					    string hexFilePath = buildPath(BUILD_DIR, "gympal.hex");
 | 
				
			||||||
    if (result != 0) return result;
 | 
					    if (!exists(hexFilePath)) {
 | 
				
			||||||
    return flashToMCU(buildPath("bin", "gympal.hex"));
 | 
					        writeln("Hex file doesn't exist yet; building it now.");
 | 
				
			||||||
 | 
					        int result = buildCommand(args);
 | 
				
			||||||
 | 
					        if (result != 0) return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    string flags = join(AVRDUDE_FLAGS, " ");
 | 
				
			||||||
 | 
					    string cmd = format!"avrdude %s -U flash:w:%s:i"(flags, hexFilePath);
 | 
				
			||||||
 | 
					    writeln(cmd);
 | 
				
			||||||
 | 
					    return run(cmd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int build(bool force = false) {
 | 
					int build(bool force = false) {
 | 
				
			||||||
| 
						 | 
					@ -101,35 +117,8 @@ int build(bool force = false) {
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//-------- Utility functions below here -------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int run(string shellCommand) {
 | 
					 | 
				
			||||||
    import std.process : Pid, spawnShell, wait;
 | 
					 | 
				
			||||||
    Pid pid = spawnShell(shellCommand);
 | 
					 | 
				
			||||||
    return wait(pid);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void runOrQuit(string shellCommand, int[] successExitCodes = [0]) {
 | 
					 | 
				
			||||||
    import core.stdc.stdlib : exit;
 | 
					 | 
				
			||||||
    import std.algorithm : canFind;
 | 
					 | 
				
			||||||
    int result = run(shellCommand);
 | 
					 | 
				
			||||||
    if (!canFind(successExitCodes, result)) exit(result);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void quitIfNonZero(int n) {
 | 
					 | 
				
			||||||
    import core.stdc.stdlib : exit;
 | 
					 | 
				
			||||||
    if (n != 0) exit(n);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool shouldCompileSource(string sourcePath) {
 | 
					bool shouldCompileSource(string sourcePath) {
 | 
				
			||||||
    string name = baseName(sourcePath);
 | 
					    return !contentMatchesHash(sourcePath);
 | 
				
			||||||
    name = name[0 .. name.lastIndexOf('.')];
 | 
					 | 
				
			||||||
    string hashPath = buildPath("bin", "hash", name ~ ".md5");
 | 
					 | 
				
			||||||
    string objectPath = buildPath("bin", name ~ ".o");
 | 
					 | 
				
			||||||
    if (!exists(hashPath) || !exists(objectPath)) return true;
 | 
					 | 
				
			||||||
    ubyte[] storedHash = Base64.decode(readText(hashPath).strip());
 | 
					 | 
				
			||||||
    ubyte[16] currentHash = md5Of(readText(sourcePath));
 | 
					 | 
				
			||||||
    return storedHash != currentHash;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
string compileSourceToObject(string sourcePath, bool force = false) {
 | 
					string compileSourceToObject(string sourcePath, bool force = false) {
 | 
				
			||||||
| 
						 | 
					@ -137,7 +126,6 @@ string compileSourceToObject(string sourcePath, bool force = false) {
 | 
				
			||||||
    string name = baseName(sourcePath);
 | 
					    string name = baseName(sourcePath);
 | 
				
			||||||
    name = name[0 .. name.lastIndexOf('.')];
 | 
					    name = name[0 .. name.lastIndexOf('.')];
 | 
				
			||||||
    string objectPath = buildPath("bin", name ~ ".o");
 | 
					    string objectPath = buildPath("bin", name ~ ".o");
 | 
				
			||||||
    string hashPath = buildPath("bin", "hash", name ~ ".md5");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!force && !shouldCompileSource(sourcePath)) {
 | 
					    if (!force && !shouldCompileSource(sourcePath)) {
 | 
				
			||||||
        writefln!"Not compiling %s because no changes detected."(sourcePath);
 | 
					        writefln!"Not compiling %s because no changes detected."(sourcePath);
 | 
				
			||||||
| 
						 | 
					@ -151,12 +139,7 @@ string compileSourceToObject(string sourcePath, bool force = false) {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    writeln(cmd);
 | 
					    writeln(cmd);
 | 
				
			||||||
    runOrQuit(cmd);
 | 
					    runOrQuit(cmd);
 | 
				
			||||||
 | 
					    saveHash(sourcePath);
 | 
				
			||||||
    ubyte[16] hash = md5Of(readText(sourcePath));
 | 
					 | 
				
			||||||
    string hashDir = buildPath("bin", "hash");
 | 
					 | 
				
			||||||
    if (!exists(hashDir)) mkdir(hashDir);
 | 
					 | 
				
			||||||
    std.file.write(hashPath, Base64.encode(hash));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return objectPath;
 | 
					    return objectPath;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,25 +167,3 @@ string copyToHex(string elfFile) {
 | 
				
			||||||
    runOrQuit(cmd);
 | 
					    runOrQuit(cmd);
 | 
				
			||||||
    return hexFile;
 | 
					    return hexFile;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
int flashToMCU(string hexFile) {
 | 
					 | 
				
			||||||
    string cmd = format!"avrdude -c %s -p m328p -P /dev/ttyUSB0 -b %d -u -U flash:w:%s:i"(
 | 
					 | 
				
			||||||
        BOOTLOADER,
 | 
					 | 
				
			||||||
        AVRDUDE_BAUDRATE,
 | 
					 | 
				
			||||||
        hexFile
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    writeln(cmd);
 | 
					 | 
				
			||||||
    return run(cmd);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
string[] findFiles(string path, string suffix = null) {
 | 
					 | 
				
			||||||
    import std.array;
 | 
					 | 
				
			||||||
    import std.algorithm;
 | 
					 | 
				
			||||||
    auto app = appender!(string[]);
 | 
					 | 
				
			||||||
    foreach (DirEntry entry; dirEntries(path, SpanMode.breadth, false)) {
 | 
					 | 
				
			||||||
        if (entry.isFile && (suffix is null || entry.name.endsWith(suffix))) {
 | 
					 | 
				
			||||||
            app ~= entry.name;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return app[];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,65 @@
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * Helper for hashing the content of source files to determine if we need to
 | 
				
			||||||
 | 
					 * re-compile certain sources.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					module hash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import std.stdio;
 | 
				
			||||||
 | 
					import std.file;
 | 
				
			||||||
 | 
					import std.string;
 | 
				
			||||||
 | 
					import std.digest.md;
 | 
				
			||||||
 | 
					import std.base64;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const HASH_FILE = "bin/hash.txt";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * Determines if the content of the source file at the given path matches
 | 
				
			||||||
 | 
					 * the hash we have for it (if possible).
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *   sourcePath = The path to the source file.
 | 
				
			||||||
 | 
					 * Returns: True if we have a hash for the source file, and it matches the
 | 
				
			||||||
 | 
					 * current hash of the file contents. False if we don't have a hash or it
 | 
				
			||||||
 | 
					 * doesn't match.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool contentMatchesHash(string sourcePath) {
 | 
				
			||||||
 | 
					    if (!exists(sourcePath) || !isFile(sourcePath)) return false;
 | 
				
			||||||
 | 
					    string[string] hashes = readHashes();
 | 
				
			||||||
 | 
					    if (sourcePath !in hashes) return false;
 | 
				
			||||||
 | 
					    ubyte[16] rawHash = md5Of(readText(sourcePath));
 | 
				
			||||||
 | 
					    ubyte[] savedHash = Base64.decode(hashes[sourcePath]);
 | 
				
			||||||
 | 
					    return rawHash == savedHash;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * Saves the hash of the given source path to the hash file.
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *   sourcePath = The source path of the file to save.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void saveHash(string sourcePath) {
 | 
				
			||||||
 | 
					    if (!exists(sourcePath) || !isFile(sourcePath)) return;
 | 
				
			||||||
 | 
					    ubyte[16] rawHash = md5Of(readText(sourcePath));
 | 
				
			||||||
 | 
					    string hash = Base64.encode(rawHash);
 | 
				
			||||||
 | 
					    string[string] hashes = readHashes();
 | 
				
			||||||
 | 
					    hashes[sourcePath] = hash;
 | 
				
			||||||
 | 
					    saveHashes(hashes);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private string[string] readHashes() {
 | 
				
			||||||
 | 
					    string[string] hashes;
 | 
				
			||||||
 | 
					    if (!exists(HASH_FILE)) return hashes;
 | 
				
			||||||
 | 
					    auto file = File(HASH_FILE, "r");
 | 
				
			||||||
 | 
					    foreach (string line; lines(file)) {
 | 
				
			||||||
 | 
					        string[] parts = split(line, ":");
 | 
				
			||||||
 | 
					        string sourcePath = parts[0].strip;
 | 
				
			||||||
 | 
					        string hashBase64 = parts[1].strip;
 | 
				
			||||||
 | 
					        hashes[sourcePath] = hashBase64;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return hashes;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private void saveHashes(string[string] hashes) {
 | 
				
			||||||
 | 
					    auto file = File(HASH_FILE, "w");
 | 
				
			||||||
 | 
					    foreach (string sourcePath, string hash; hashes) {
 | 
				
			||||||
 | 
					        file.writefln!"%s:%s"(sourcePath, hash);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,56 @@
 | 
				
			||||||
 | 
					module util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * Runs the given shell command.
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *   shellCommand = The command to run.
 | 
				
			||||||
 | 
					 * Returns: The exit code of the command.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int run(string shellCommand) {
 | 
				
			||||||
 | 
					    import std.process : Pid, spawnShell, wait;
 | 
				
			||||||
 | 
					    Pid pid = spawnShell(shellCommand);
 | 
				
			||||||
 | 
					    return wait(pid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * Runs the given command, and exits if an unsatisfactory exit code is returned.
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *   shellCommand = The command to run.
 | 
				
			||||||
 | 
					 *   successExitCodes = The list of exit codes which are considered success.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void runOrQuit(string shellCommand, int[] successExitCodes = [0]) {
 | 
				
			||||||
 | 
					    import core.stdc.stdlib : exit;
 | 
				
			||||||
 | 
					    import std.algorithm : canFind;
 | 
				
			||||||
 | 
					    int result = run(shellCommand);
 | 
				
			||||||
 | 
					    if (!canFind(successExitCodes, result)) exit(result);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * Exits the program if the given number is non-zero.
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *   n = The number to check.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void quitIfNonZero(int n) {
 | 
				
			||||||
 | 
					    import core.stdc.stdlib : exit;
 | 
				
			||||||
 | 
					    if (n != 0) exit(n);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * Finds a list of files in a directory which match a given suffix.
 | 
				
			||||||
 | 
					 * Params:
 | 
				
			||||||
 | 
					 *   path = The path to look in.
 | 
				
			||||||
 | 
					 *   suffix = The suffix to match.
 | 
				
			||||||
 | 
					 * Returns: The list of paths to files that match.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					string[] findFiles(string path, string suffix = null) {
 | 
				
			||||||
 | 
					    import std.array;
 | 
				
			||||||
 | 
					    import std.algorithm;
 | 
				
			||||||
 | 
					    import std.file;
 | 
				
			||||||
 | 
					    auto app = appender!(string[]);
 | 
				
			||||||
 | 
					    foreach (DirEntry entry; dirEntries(path, SpanMode.breadth, false)) {
 | 
				
			||||||
 | 
					        if (entry.isFile && (suffix is null || entry.name.endsWith(suffix))) {
 | 
				
			||||||
 | 
					            app ~= entry.name;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return app[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env rdmd
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Simple script that just compiles this project's build system to an executable.
 | 
				
			||||||
 | 
					 * Run this before building: `./prepare-build-tools.d`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					module prepare_build_tools;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import std.process;
 | 
				
			||||||
 | 
					import std.array;
 | 
				
			||||||
 | 
					import std.file;
 | 
				
			||||||
 | 
					import std.algorithm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main() {
 | 
				
			||||||
 | 
					    auto sourceApp = appender!(string[]);
 | 
				
			||||||
 | 
					    foreach (DirEntry entry; dirEntries("build-tools", SpanMode.shallow, false)) {
 | 
				
			||||||
 | 
					        if (entry.isFile && endsWith(entry.name, ".d")) {
 | 
				
			||||||
 | 
					            sourceApp ~= entry.name;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    string[] sources = sourceApp[];
 | 
				
			||||||
 | 
					    string sourcesStr = join(sources, " ");
 | 
				
			||||||
 | 
					    Pid pid = spawnShell("dmd -O " ~ sourcesStr ~ " -release -of=build");
 | 
				
			||||||
 | 
					    scope (exit) {
 | 
				
			||||||
 | 
					        if (exists("build.o")) {
 | 
				
			||||||
 | 
					            std.file.remove("build.o");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return wait(pid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#include "display.h"
 | 
					#include "display.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Chip Select
 | 
				
			||||||
struct signal cs = { .ddr = &DDRB, .port = &PORTB, .pin = 2 };
 | 
					struct signal cs = { .ddr = &DDRB, .port = &PORTB, .pin = 2 };
 | 
				
			||||||
// Back Light
 | 
					// Back Light
 | 
				
			||||||
struct signal bl = { .ddr = &DDRB, .port = &PORTB, .pin = 1 };
 | 
					struct signal bl = { .ddr = &DDRB, .port = &PORTB, .pin = 1 };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,13 +7,18 @@
 | 
				
			||||||
#ifndef DISPLAY_H
 | 
					#ifndef DISPLAY_H
 | 
				
			||||||
#define DISPLAY_H
 | 
					#define DISPLAY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "st7735.h"
 | 
					#include "lib/st7735.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief Initializes the display.
 | 
					 * @brief Initializes the display.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void display_init();
 | 
					void display_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Gets a pointer to the underlying ST7735 LCD struct, which can be used
 | 
				
			||||||
 | 
					 * for calling functions on it manually.
 | 
				
			||||||
 | 
					 * @return A pointer to the ST7735 LCD struct.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct st7735* display_get_lcd();
 | 
					struct st7735* display_get_lcd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void display_show_str(char* str);
 | 
					void display_show_str(char* str);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					#include "ds3231.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Implement this!
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					#ifndef DS3231_H
 | 
				
			||||||
 | 
					#define DS3231_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Implement this!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ds3231_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
		Reference in New Issue