Project Archive
A complete index of professional and hobby projects. Search by name, technology, or keyword to explore the full breadth of work.
25 projects
Case Studies
Production Test Cabinet
Safety System ProductsTo take SSP's Simplifier Gateway from certification into stable serial production, I designed the end-of-electronics production test that screens every unit before final assembly. The test focuses on catching hardware and communication faults immediately after the six-PCB assembly is formed, before it is fitted into its mechanical enclosures. The test system loads the target firmware onto each device, and exercises core interfaces (digital I/O, UART, CAN, analog voltages, resistances, and Ethernet reachability), so units leave the station production-ready. It also writes pass/fail, as well as many other stats to our ERP system for good traceability. The solution is a Beckhoff TwinCAT 3 test cabinet built around a CX7080 with RS-232/RS-485, plus EtherCAT terminals selected to cover the device's I/O profile: EL2008 for digital outputs, EL3174 for voltage measurement, EL3692 for resistance measurement, EL6751 to transmit/receive CAN frames (multiplexed via relays across the gateway's two CAN ports), and EL6631 to exercise PROFINET/PROFIsafe paths; the rig also controls a digital power supply over RS232. A .NET (C#) application orchestrates the entire test sequence, talking to the PLC via Beckhoff ADS and to the DUT/ERP directly; the steps are defined in JSON so they can be reordered, skipped, or duplicated without code changes.
BeckhoffTwinCAT.NETVueJSWearable Epilepsy Monitor
RISETechEPIC, short for EPIlepsy Care, was a research-stage wearable monitoring prototype developed with NUST's BIOMISA research group to support detection, logging, and caregiver alerting for generalized tonic-clonic seizure events. I was the main implementation engineer for the wearable itself. My work covered electronics architecture, schematic design, PCB layout, sensor integration, firmware, digital filtering and DSP, BLE communication, battery system, enclosure CAD, prototyping, testing, documentation, and supplier coordination. The system used sEMG, IMU, and PPG sensing on an nRF52832-based biceps-worn wearable. It sampled EMG at 1 kHz, sampled IMU and PPG at 200 Hz, transmitted processed data over BLE GATT, and was iterated through 10 hardware revisions and 26 enclosure revisions before handoff for further research and planned clinical verification.
CnRF52BLEGATTIMUsEMGPPGDSPKiCadSolidWorksSmart Insole Firmware
Wearable Product FirmwareDeveloped embedded firmware and supported electronics redesign for a pair of BLE-connected smart shoe insoles based on Nordic nRF52840. Each insole used 8 force sensing resistors and an ICM-42670 IMU to measure plantar pressure and movement. The firmware sampled sensors at 200 Hz, decimated data to 100 Hz, performed sensor fusion and step-event detection, coordinated a primary/secondary BLE topology, stored sessions in low-power flash when the app was unavailable, and synchronized data later when the app reconnected. The firmware ran on Zephyr through Nordic's nRF Connect SDK and used a hardware-watchdog-enforced, event-driven architecture with lean ISRs and work-queue-based deferred processing. It also used application-level BLE peer authentication, dynamic role resolution, MTU-aware transport behavior, and MCUboot plus mcumgr over BLE for OTA updates.
CnRF52ZephyrBLEGATTFSRIMUSensor FusionMCUbootmcumgrCloudflareAndroidKotlinEzLogger
2024EzLogger is a lightweight asynchronous logging framework for .NET applications, designed to provide dependable runtime logging with minimal setup and low execution overhead. It offers a simple, accessible API for writing log messages at six severity levels: `Critical`, `Error`, `Warning`, `Announce`, `Info`, and `Debug`, while keeping logging work separate from the main application flow. Rather than aiming for the extensive configurability of larger logging ecosystems, EzLogger focuses on practical usability, predictable behavior, and efficient operation for applications that need straightforward logging without unnecessary complexity. At its core, EzLogger follows a queue-based architecture. When the application emits a log message, the message is timestamped, converted into an internal log record, and placed into a thread-safe logging pipeline. Multiline messages are split into individual log lines while preserving their original timestamp, ensuring that output remains clear and structured. Because log generation is decoupled from log writing, the calling thread can continue its normal work immediately instead of being blocked by console or file I/O. The framework processes logs through a dedicated background logger service. This service waits for incoming entries, gathers all currently available messages into a batch, and then dispatches that batch to the configured output targets. Console and file logging are handled independently, allowing each destination to use its own verbosity threshold. This makes it possible, for example, to keep console output concise while still writing more detailed diagnostic information to file. Batch processing further reduces overhead by avoiding unnecessary per-message write operations and improving throughput during periods of heavier log activity. For persistence, EzLogger writes logs to date-based files inside an application-specific log directory. Console output is formatted for readability, while file output is coordinated to ensure safe and consistent writes. In addition to logging itself, the framework includes a separate background cleaner service responsible for automated log retention. This service periodically checks the total size of the log folder and, when the configured limit is exceeded, removes the oldest files until storage usage falls back within bounds. This makes EzLogger suitable for long-running applications where unattended log growth must be controlled. The overall architecture is intentionally compact and service-oriented: the main application produces logs, the logger service processes and writes them asynchronously, and the cleaner service manages storage in the background. During application shutdown, EzLogger completes pending work and flushes queued messages before exiting, helping ensure that important log data is not lost. In this way, EzLogger provides a balanced combination of simplicity, efficiency, and reliability.
.NET
Professional Work
Simplifier Gateway
Safety System ProductsThe Simplifier Gateway is an industrial functional-safety communication device developed as part of the Safety Simplifier ecosystem. It connects decentralized safety devices and safety I/O systems to higher-level industrial safety networks, enabling machine-safety data to be collected, processed, and forwarded to safety controllers. The device is certified up to SIL 3, making it suitable for demanding machine-safety applications that require a high level of diagnostic coverage, deterministic behavior, and compliance with functional safety standards such as IEC 61508. The Gateway architecture contains two dedicated safety cores and one separate communication core. The safety cores are responsible for safety-related processing, diagnostics, monitoring, and validation of safety communication, while the communication core handles network-facing and non-safety communication tasks. This architectural separation supports clear responsibility boundaries between safety and communication functions. In addition to the existing PROFIsafe variant, an FSoE variant has also been developed and is currently submitted for SIL 3 certification. My role in the project covered embedded firmware development, safety verification, automated testing, embedded DevOps, and certification evidence generation. I worked on bare-metal driver development, implementing low-level firmware components close to the hardware and ensuring that the software behavior met the deterministic and reliability requirements expected from a safety-certified embedded device. A major part of my work was the development and maintenance of unit tests for the complete in-scope firmware of the safety cores. I achieved 100% statement and branch coverage for all in-scope safety firmware using a combination of HIL testing and fault insertion, excluding certified third-party components and toolchain libraries. To support this, I developed a custom unit testing framework tailored specifically to the Gateway's firmware architecture and safety-core constraints. This framework enabled systematic, repeatable, and traceable verification of safety firmware behavior and became an important part of the project's quality and certification workflow. I was also involved in code reviews and architectural reviews, focusing on safety, maintainability, traceability, and compliance. I contributed to the project's software quality activities through MISRA analysis and enforcement, code complexity analysis, and the review of safety-relevant implementation decisions. These activities were not only internal quality measures, but also part of the formal evidence required for certification. In addition, I created and maintained official documentation for the certification evidence package, including documents related to code reviews, unit testing, test coverage, MISRA compliance, MISRA deviations, and code quality analysis. These documents formed part of the official document release required by the certifying body when assessing the product for SIL 3 compliance. I also solely developed and maintain the embedded DevOps infrastructure. This included building and maintaining CI pipelines for regular firmware builds, automatically executing unit tests and HIL tests on each build, and generating proof-of-review documentation from GitHub pull requests and review comments. This improved process traceability and helped ensure that review evidence could be collected and presented consistently during certification activities. Beyond implementation and testing, I actively participated in functional safety and compliance meetings, helping to design, review, and verify the device architecture against IEC 61508 requirements. I also developed firmware upgrade utilities for field firmware updates over CAN bus, enabling controlled DFU procedures for deployed devices. Overall, my work on the Simplifier Gateway combined low-level embedded development, safety-critical firmware verification, automated testing, compliance documentation, and certification support for a SIL 3 industrial safety device.
CIEC-61508NonSafe Simplifier Gateway
Safety System ProductsA more affordable version of the Simplifier Gateway, at the cost of not being functional safety compliant. I am responsible for complete development of this product, including its support software for remote updates, mass setup and programming.
C#.NETGateway Setup Tool
Safety System ProductsAn internal tool for mass programming and repairing the software of our NonSafe Simplifier Gateways. While I did create an underlying CLI for it to be integrated into CI/CD and hardware production pipelines, I also made an intuitive GUI for it to be used by individual users (production staff) when needed. I designed the UI to blend in with our other software in terms of its intuitive layout, company colors and fluid animations.
C#WPF.NETGateway Config Tool
Safety System ProductsAn easy to use device configuration app that can read and create configuration files for our Gateways. This app is made available to the customers so that they can create working configuration files every time. The UI of this app was also made on the same design principles as the setup and repair tool.
C#WPF.NETChange in Build System
Safety System ProductsReplaced an IDE-centric build system with a CMake based build system for our embedded software. The biggest motivation and benefit for this change was to automate our builds. Which of course is the basic requirement for automated testing, which in turn is a requirement for Continuous Integration. The exploration and learning of CMake later allowed me to develop my VS Code extension, "C Toolkit".
CCMakeShellCI Pipelines
Safety System ProductsI created Continuous Integration pipelines for automated testing of our embedded software on various test harnesses. These include tests for basic peripherals, stress tests, hardware and software fault insertion tests, and general software quality checks.
GitHubCMakeShellMotion and Light Sensor
MRS TechnologiesI developed an ultra low-power motion and light sensor as part of the MTronic building automation system. This sensor initially had the same Bluetooth SoC as other MTronic devices, allowing us to collectively develop a centralized software stack and use that to accelerate our development time massively. However the high power consumption of the SoC would not allow for a battery life beyond 9 months despite heavy hardware, software and algorithmic optimizations. I migrated the sensor to a much more power efficient, albeit more expensive nRF52 SoC. I independently implemented the necessary basic software components in just two months on Zephyr RTOS, something the team and I had no previous experience in. It took me another month to port the sensor algorithms and external libraries, and a few more days of debugging to get the sensor working perfectly. The sensor now boasts a battery life of 3+ years.
CnRF52ZephyrBluetooth MeshBluetooth Firmware Upgrade
MRS TechnologiesI created a key part of the firmware for all MTronic devices: their ability to upgrade the firmware remotely. The update architecture contained source verification, firmware integrity checks and rollback in case of faulty updates. This allowed us to push feature and security updates to devices that were already in use by the customers. Naturally, the update mechanism was developed, tested and verified in a much more thorough way, relative to other parts of the firmware, as it is arguably one of the most critical features of any IoT device.
CFreeRTOSBluetoothEnergy Logger
MRS TechnologiesI developed an energy monitoring system for a Tier 1 automotive electronics manufacturer to track power usage across their facility. Using a .NET backend and a JavaScript/React frontend, I collected consumption data from energy meters using Modbus TCP, processed it, and stored it in an SQL database. The data was then displayed on a visually appealing dashboard. This system provided the client with valuable insights into their energy consumption, enhancing their operational efficiency and supporting regulatory compliance.
C#.NETJavaScriptSQLFile Format Converter
MRS TechnologiesThis project was the start of my .NET and C# development, which has since been instrumental in my career. I developed a .NET tool for a Tier 1 automotive electronics manufacturer to convert SAE-J1939 CAN bus message information from Excel into .dbc, .sym, and .csv formats. The project involved creating an intuitive WPF GUI with the Prism framework and MVVM architecture. This tool enabled the client to integrate CAN message encoding and decoding into their applications, which are crucial for their operations. The raw data required extensive parsing and cleaning, due to frequent inconsistencies and irregularities in data.
C#.NETWPF
Hobby Projects
C C++ Toolkit
2023A Visual Studio Code extension designed to simplify the development workflow for C and C++ projects that use CMake. It provides an integrated environment for creating, building, running, debugging, and testing projects directly from within VS Code. Instead of requiring users to manually create project folders, CMake files, build configurations, and debug settings, the extension automates much of this setup and presents the most common actions through convenient commands and status bar buttons. The extension has grown into a serious developer tool and has reached over 20,000 downloads. The extension is implemented as a JavaScript-based VS Code extension. Its configuration defines command palette commands, activation behavior for C and C++ projects, code snippets, and integration with supporting tools such as CMake, GCC, GDB, Ninja, Make, Git, and testing or coverage utilities. The extension registers multiple developer actions, including project creation, build type selection, clean builds, running executables, starting debug sessions, running tests, and debugging tests. A major feature of the extension is project generation. It can create new C or C++ projects with a ready-to-use structure, including source files, CMake configuration, and VS Code settings. It also supports creating libraries and adding reusable components to an existing project. These components can include implementation files, headers, mock files, and test files, while the extension updates the CMake configuration so the new code becomes part of the build system automatically. The build workflow is based around CMake. The extension manages build folders, selected build modes, compiler paths, generated executables, and debugger configuration. It supports common build types such as Debug, Release, and Test, allowing users to move between normal development, optimized builds, and test-focused workflows. The testing support is especially useful for structured C/C++ development, where automated tests and coverage tools are often part of the workflow. Another important part of the extension is tool detection and installation support. It can check whether required development tools are available and help install missing tools using platform-specific package managers, reducing setup friction for new environments. Overall, C C++ Toolkit is a practical VS Code extension for C and C++ developers who want a smoother CMake-based workflow. It is useful for beginners setting up projects quickly, as well as experienced developers who want faster project creation, easier build management, integrated debugging, and streamlined testing inside VS Code.
JavaScriptVsCodeGenetic Algorithm
2023C implementation of a genetic algorithm that evolves candidate strings toward a user-defined target. Rather than presenting itself as a generic optimization framework, it is designed as a clear and approachable demonstration of evolutionary search, with an emphasis on readability, traceability, and understanding how the core mechanics of a genetic algorithm work in practice. The program takes two command-line inputs: a target string and the number of offspring to generate in each generation. At startup, it validates that the target contains only characters from the predefined gene pool, checks that the offspring count is within the allowed range, seeds the random number generator, and initializes the target genome. Architecturally, the project is intentionally compact and well separated into small functional layers. The `app_init` module handles argument parsing and validation, the `main.c` application layer drives the generational loop, and the `genetic_algorithm_utils` module contains the core genome operations such as initialization, crossover, mutation, fitness calculation, sorting, copying, printing, and cleanup. A gene is represented as a single `char`, while a genome is represented by a structure containing a dynamically managed gene array, its length, and a cached fitness value. This makes the data model simple enough to follow directly while still being structured enough to support clean separation between orchestration and algorithmic logic. The evolutionary process follows a straightforward cycle. Two parent genomes are first created with random genes drawn from the project's character pool. In each generation, the parents are repeatedly mated to produce the configured number of offspring. Mating uses single-point crossover, and the order of the two parents is randomly flipped so that neither parent always contributes the leading segment. After crossover, a slight mutation is applied, implemented as either zero or one random gene replacement. This mutation step is included specifically to reduce the risk of the population settling into a local maximum too early. Once created, each offspring is scored against the target using a fitness function based on exact positional character matches. Selection is equally direct: the offspring population is sorted by fitness, and the two fittest offspring are deep-copied into the parent slots for the next generation. In this implementation, a perfect match has a fitness of `0`, while less accurate genomes have increasingly negative scores. The loop continues until convergence is achieved or an upper iteration bound is reached. As the README notes, the design intentionally favors clarity over optimization, even keeping some routines, such as fitness evaluation and sorting, simple for ease of understanding and debugging. Overall, the project serves as a readable, self-contained example of parent selection, crossover, mutation, survival of the fittest, and generational convergence in C.
C++CMakePID Controller
2023An implementation of a PID controller in C. A PID controller, short for Proportional-Integral-Derivative controller, is a closed-loop control system that is widely used in engineering applications to control dynamic systems. It works by continuously comparing a desired target value, also called the setpoint, with the current output of a system. The difference between these two values is used to calculate a correction signal that helps move the system toward the target. This project provides a simple and readable implementation of the PID control concept. It is mainly intended as a practice project and learning resource for anyone who wants to understand how PID controllers work at a software level. The code demonstrates how the proportional, integral, and derivative terms are calculated and combined to produce a control output. The proportional term reacts to the current error between the target and measured value. The integral term considers accumulated error over time, which helps reduce long-term steady-state error. The derivative term estimates how quickly the error is changing, which can help reduce overshoot and improve stability. By tuning the three gain values, `kP`, `kI`, and `kD`, the controller response can be adjusted for different systems. The implementation is written in C and organized into separate source and header files. The controller stores values such as the PID gains, sampling time, goal value, and previous error data. A ring buffer is used to store past error values, allowing the controller to calculate accumulated error and observe recent changes in system behavior. The project also makes use of function pointers for flexibility. Users can provide their own input function and transfer function. The transfer function represents the behavior of the system being controlled, or “plant,” by describing how a given control input affects the system output. In the example program, this allows the PID controller to be tested against a simple simulated system without requiring real hardware. Although this is not intended to be a production-ready control library, it is useful as an educational example. It can help students, hobbyists, and developers connect basic control theory with practical C programming. It may also serve as a starting point for more advanced PID implementations, such as adding output limits, anti-windup protection, realtime sampling, or embedded system integration. Overall, this project is a compact learning exercise that introduces the core ideas behind PID control while keeping the implementation simple enough to read, modify, and experiment with.
CCMakeNumerical Calculus
2023This is a small C practice project that demonstrates how numerical derivatives and integrals can be calculated from a sampled dataset. The project is intended as an educational example and a testing ground for the more advanced PID controller project, where derivative and integral calculations are important building blocks. It focuses on presenting the core ideas of numerical calculus in a very easy-to-read and understandable manner, making it especially useful for students who are learning numerical methods and how those methods can be implemented in software. The code works by first defining a mathematical function, `f(x)`, which is used to generate a dataset. In the example, the function is `y = x³`. A fixed number of samples and a resolution factor are configured in the program. The resolution factor determines the time interval between samples, meaning a higher resolution creates smaller time steps and usually produces more accurate numerical results. The generated function values are stored in a ring buffer, which is also used in the related PID controller project. The derivative is calculated using a simple finite difference method. For each sample point, the program compares the current value with the previous value and divides the difference by the time interval. This gives an approximation of the rate of change at that point. The integral is calculated using trapezoidal-style methods, where the area under the curve is estimated by summing small sections of the sampled function. The code includes both a typical trapezoidal implementation and a modified integral function, making it easy to compare and understand different numerical approaches. The implementation is intentionally simple. The main logic is contained in readable C functions such as `calculate_derivative`, `trapezoidal`, and `calculate_integral`. The project is built using CMake and links against my ring buffer module, keeping the structure clear while still showing how code can be split into reusable components. Although this is not intended to be a full numerical analysis library, it is useful as a learning resource. Students, hobbyists, and beginner C programmers can use it to understand how mathematical formulas for derivatives and integrals translate into working code. It can also serve as a starting point for more advanced simulations, control systems, signal processing experiments, or embedded software projects that require simple numerical calculations.
CCMakeRandom Particle Optimization
2021An implementation of a Genetic Algorithm in C. Genetic Algorithms, often abbreviated as GAs, are adaptive heuristic search algorithms inspired by natural selection and genetic evolution. They are commonly used to solve optimization and search problems by repeatedly improving a population of possible solutions over multiple generations. This project is a practice implementation of a genetic algorithm and is designed to be easy to read, understand, and experiment with. The README explains the working of the algorithm in a very simple and beginner-friendly way, making it especially useful for students and developers who are learning how evolutionary algorithms work and how they can be implemented in software. In this implementation, a gene is represented as a single character, while a genome is represented as a collection of characters. The program takes a target string as input and tries to evolve randomly generated genomes until one of them matches the target. Each genome is assigned a fitness score based on how closely it matches the target string. A perfect match has a fitness score of zero, while less accurate genomes receive lower scores. The algorithm begins by creating two random parent genomes and a configurable number of offspring genomes. During each generation, the parent genomes are mated to produce offspring. Mating is performed using a single-point crossover, where part of one parent is combined with part of the other parent. A small random mutation may also be applied to prevent the search from getting stuck too early and to introduce variation into the population. After the offspring are generated, their fitness values are calculated and the population is sorted. The two fittest offspring are selected as the new parents for the next generation. This process continues until the best genome converges to the target string or the iteration limit is reached. The project is organized into separate modules for application initialization and genetic algorithm utilities. It also includes unit tests for important functions such as genome initialization, copying, mutation, mating, random number generation, sorting, and fitness calculation. This helps validate the algorithm implementation itself, not just demonstrate it. Overall, this project is a compact and educational example of a genetic algorithm in C. It is useful for learning about evolutionary computation, optimization concepts, string evolution, randomness, fitness functions, and practical software implementation of algorithmic ideas.
C++MATLABC Asserts
2023A rudimentary assertion library written in C. The library is designed to facilitate simple unit testing by providing straightforward macros and utilities for testing conditions within C programs. If a test condition fails, the library will output the file, line number, and function where the failure occurred.
CCMakeC Queue
2023An implementation of a queue in C, just for practicing C.
CCMakeC Ring Buffer
2023An implementation of a ring buffer in C, just for practicing C.
CCMakeManifest Checker
2024A Rust-based command-line tool designed to ensure the integrity of files within a specified directory by comparing them against a manifest file. It can be useful in environments where ensuring the authenticity and integrity of firmware or software is critical.
RustPower Estimator
2023A power consumption and battery life estimation tool for IoT devices. With classes like 'Source', 'Load', and 'Device', user can easily express their electronics design and estimate the battery life.
C#.NETSerial Logger
2021Logs serial data from available COM ports for specified time, and writes them into a .csv file.
C#.NETPrism
























