From 044a4181fb2f6730714489e06a9127240e21595c Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Wed, 31 Oct 2018 20:34:10 +0100 Subject: [linux] Add initial implementation of rom-loader --- sw-linux/rom-loader/CMakeLists.txt | 5 + sw-linux/rom-loader/Makefile | 208 +++++++++++++++++++++++++++++++++++++ sw-linux/rom-loader/main.cpp | 139 +++++++++++++++++++++++++ sw-linux/rom-loader/rom-loader | Bin 0 -> 27208 bytes sw-linux/rom-loader/serial.cpp | 89 ++++++++++++++++ sw-linux/rom-loader/serial.hpp | 24 +++++ 6 files changed, 465 insertions(+) create mode 100644 sw-linux/rom-loader/CMakeLists.txt create mode 100644 sw-linux/rom-loader/Makefile create mode 100644 sw-linux/rom-loader/main.cpp create mode 100755 sw-linux/rom-loader/rom-loader create mode 100644 sw-linux/rom-loader/serial.cpp create mode 100644 sw-linux/rom-loader/serial.hpp diff --git a/sw-linux/rom-loader/CMakeLists.txt b/sw-linux/rom-loader/CMakeLists.txt new file mode 100644 index 0000000..6e1ad02 --- /dev/null +++ b/sw-linux/rom-loader/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.7) + +project(rom-loader LANGUAGES CXX) + +add_executable(rom-loader main.cpp serial.cpp) diff --git a/sw-linux/rom-loader/Makefile b/sw-linux/rom-loader/Makefile new file mode 100644 index 0000000..c07b827 --- /dev/null +++ b/sw-linux/rom-loader/Makefile @@ -0,0 +1,208 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.7 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/naopross/docs/projects/z80uPC/sw-linux/rom-loader + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/naopross/docs/projects/z80uPC/sw-linux/rom-loader + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /usr/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/naopross/docs/projects/z80uPC/sw-linux/rom-loader/CMakeFiles /home/naopross/docs/projects/z80uPC/sw-linux/rom-loader/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/naopross/docs/projects/z80uPC/sw-linux/rom-loader/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named rom-loader + +# Build rule for target. +rom-loader: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 rom-loader +.PHONY : rom-loader + +# fast build rule for target. +rom-loader/fast: + $(MAKE) -f CMakeFiles/rom-loader.dir/build.make CMakeFiles/rom-loader.dir/build +.PHONY : rom-loader/fast + +main.o: main.cpp.o + +.PHONY : main.o + +# target to build an object file +main.cpp.o: + $(MAKE) -f CMakeFiles/rom-loader.dir/build.make CMakeFiles/rom-loader.dir/main.cpp.o +.PHONY : main.cpp.o + +main.i: main.cpp.i + +.PHONY : main.i + +# target to preprocess a source file +main.cpp.i: + $(MAKE) -f CMakeFiles/rom-loader.dir/build.make CMakeFiles/rom-loader.dir/main.cpp.i +.PHONY : main.cpp.i + +main.s: main.cpp.s + +.PHONY : main.s + +# target to generate assembly for a file +main.cpp.s: + $(MAKE) -f CMakeFiles/rom-loader.dir/build.make CMakeFiles/rom-loader.dir/main.cpp.s +.PHONY : main.cpp.s + +serial.o: serial.cpp.o + +.PHONY : serial.o + +# target to build an object file +serial.cpp.o: + $(MAKE) -f CMakeFiles/rom-loader.dir/build.make CMakeFiles/rom-loader.dir/serial.cpp.o +.PHONY : serial.cpp.o + +serial.i: serial.cpp.i + +.PHONY : serial.i + +# target to preprocess a source file +serial.cpp.i: + $(MAKE) -f CMakeFiles/rom-loader.dir/build.make CMakeFiles/rom-loader.dir/serial.cpp.i +.PHONY : serial.cpp.i + +serial.s: serial.cpp.s + +.PHONY : serial.s + +# target to generate assembly for a file +serial.cpp.s: + $(MAKE) -f CMakeFiles/rom-loader.dir/build.make CMakeFiles/rom-loader.dir/serial.cpp.s +.PHONY : serial.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... rebuild_cache" + @echo "... edit_cache" + @echo "... rom-loader" + @echo "... main.o" + @echo "... main.i" + @echo "... main.s" + @echo "... serial.o" + @echo "... serial.i" + @echo "... serial.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/sw-linux/rom-loader/main.cpp b/sw-linux/rom-loader/main.cpp new file mode 100644 index 0000000..3c845ba --- /dev/null +++ b/sw-linux/rom-loader/main.cpp @@ -0,0 +1,139 @@ +#include +#include +#include + +#include +#include + +#include "serial.hpp" + +struct args_t +{ + std::string file_name; + bool file_name_set; + std::string port_name; + bool port_name_set; + long baudrate; + bool baudrate_set; +}; + +void usage(void) +{ + std::cout << "rom-loader -p [PORT] -f [FILE]" << std::endl + << std::endl + << "Nao Pross " << std::endl; +} + +bool parse_arguments(const int argc, const char * const argv[], args_t& args) +{ + if (argc < 2) { + usage(); + return false; + } + + args.file_name_set = false; + args.port_name_set = false; + args.baudrate_set = false; + + for (int i = 1; i < argc; i++) { + const std::string arg(argv[i]); + + bool next = false; + std::string next_arg = ""; + + // check that is an option + if (arg.front() != '-') { + usage(); + return false; + } + + // help option + if (arg[1] == 'h') { + usage(); + return false; + } + + // check that threre is an argument + if (i+1 < argc) { + next_arg = std::string(argv[i+1]); + i++; + } else { + std::cerr << "Missing option argument" << std::endl; + return false; + } + + switch (arg[1]) { + case 'p': + args.port_name = next_arg; + args.port_name_set = true; + break; + + case 'f': + args.file_name = next_arg; + args.file_name_set = true; + break; + + case 'b': + args.baudrate = std::stol(next_arg); + args.baudrate_set = true; + break; + + default: + std::cerr << "Invalid option " << arg << std::endl; + return false; + } + } + + if (!args.file_name_set || !args.port_name_set) { + std::cerr << "Missing required options: "; + + if (!args.file_name_set) + std::cerr << "-f [FILE] "; + + if (!args.port_name_set) + std::cerr << "-p [PORT] "; + + std::cerr << std::endl; + + return false; + } + + return true; +} + +int main(int argc, char *argv[]) +{ + args_t args; + + if (!parse_arguments(argc, argv, args)) { + return -1; + } + + FILE *fileptr = std::fopen(args.file_name.c_str(), "rb"); + + if (!fileptr) { + std::cerr << "Failed to open file " << args.file_name << std::endl; + return -2; + } + + serial s_dev(args.port_name, B9600); + + int chr; + while ((chr = std::fgetc(fileptr)) != EOF) { + const char byte = static_cast(chr); + + // std::cout << std::hex << byte << std::endl; + s_dev.write(&byte, 1); + } + + if (std::ferror(fileptr)) + std::cerr << "I/O error when reading file " + << args.file_name << std::endl; + + if (!std::feof(fileptr)) + std::cerr << "The reading ended before reaching EOF" << std::endl; + + std::fclose(fileptr); + + return 0; +} diff --git a/sw-linux/rom-loader/rom-loader b/sw-linux/rom-loader/rom-loader new file mode 100755 index 0000000..6652ef5 Binary files /dev/null and b/sw-linux/rom-loader/rom-loader differ diff --git a/sw-linux/rom-loader/serial.cpp b/sw-linux/rom-loader/serial.cpp new file mode 100644 index 0000000..7d25f02 --- /dev/null +++ b/sw-linux/rom-loader/serial.cpp @@ -0,0 +1,89 @@ +#include "serial.hpp" + +#include + +extern "C" { +#include +#include +#include +} + +serial::serial(const std::string& port, speed_t baud) +{ + m_fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + + if (m_fd < 0) { + throw std::ios_base::failure("Failed to open serial port " + port); + } + + tcgetattr(m_fd, &m_settings); + + // set input and output baudrate + cfsetispeed(&m_settings, baud); + cfsetospeed(&m_settings, baud); + + // disable parity, 1 stop bit, clear data size + m_settings.c_cflag &= ~(PARENB | CSTOPB | CSIZE); + // set data size to 8 + m_settings.c_cflag |= CS8; + + // disable hw flow control + m_settings.c_cflag &= ~CRTSCTS; + // enable receiver and ignore modem lines + m_settings.c_cflag |= CREAD | CLOCAL; + + // disable XON / XOFF flow control + m_settings.c_iflag &= ~(IXON | IXOFF | IXANY); + // non canonical mode + m_settings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); + + // no output processing + m_settings.c_oflag &= ~OPOST; + + // input buffer of 8 bytes + m_settings.c_cc[VMIN] = 8; + // set indefinite timeout + m_settings.c_cc[VTIME] = 0; + + if ((tcsetattr(m_fd, TCSANOW, &m_settings)) != 0) + throw std::ios_base::failure("Failed to set attributes"); + + // clean rx buffer + tcflush(m_fd, TCIFLUSH); +} + +serial::~serial() +{ + if (m_fd > 0) + close(m_fd); +} + +int serial::write(const std::string& data) const +{ + write(data.c_str(), data.length()); +} + +int serial::write(const char * const data, size_t len) const +{ + return ::write(m_fd, data, len); +} + +char serial::read() const +{ + char ch; + + if (::read(m_fd, &ch, 1) < 0) + throw std::ios_base::failure("Failed to read"); + + return ch; +} + +std::string serial::read(size_t howmany) const +{ + char data[howmany] = {}; + + if (::read(m_fd, data, howmany) < 0) + throw std::ios_base::failure("Failed to read"); + + return std::string(data); +} diff --git a/sw-linux/rom-loader/serial.hpp b/sw-linux/rom-loader/serial.hpp new file mode 100644 index 0000000..35b35be --- /dev/null +++ b/sw-linux/rom-loader/serial.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +extern "C" { +#include +} + +class serial +{ +public: + serial(const std::string& port, speed_t baud); + ~serial(); + + int write(const std::string& data) const; + int write(const char * const data, size_t len) const; + + char read() const; + std::string read(size_t howmany) const; + +private: + int m_fd; + struct termios m_settings; +}; -- cgit v1.2.1