UML en code generatie

Door de jaren heen heb ik meerdere Software pakketten bekeken die volledige ondersteuning konden geven vanuit UML naar source code. Wat ik hiermee bedoel dat ik meer wil dan alleen een code skelet (functie headers en prototypes). Een jaar of 7 terug had ik het pakket van Software Ideas Modeler bekeken. Toen was het nog heel instabiel maar had wel veel potentie. Vorig jaar weer eens een nieuwe versie bekeken en inmiddels een licentie gekocht. Je kan als gebruiker allerlei filters en templates maken waardoor je het zodanig op kan zetten dat ALLE code uit de UML modellen komen. Reverse engineering (dus terug van de code naar de UML) werkt nog deels. Kwestie van tijd.
Waarom zou je? In de professionele wereld wordt er door de klant verwacht dat de code toekomst bestendig is voor een aantal jaren. Daarvoor wordt documentatie gemaakt. Helaas, documentatie maken en laat staan bijhouden wordt als vervelend ervaren en voor je het weet loopt de documentatie achter (en uit de pas) van de realiteit. Voordeel van een pakket als deze is dat je dus de volledige code kan 'hergenereren' vanuit het model. Bijgaand een voorbeeld van een eenvoudige CO2 sensor meting waarbij de PPM (parts per million) een relais aanschakelt als deze onder een drempel waarde komt. continu wordt de ppm tevens op een display getoond.

de context diagram is als volgt :

Door op de use case de klikken krijg ik mijn klasse diagram:

Alle componenten worden gedocumenteerd in de verschillende objecten. Ook de specifieke code voor een bepaalde operatie binnen een klasse. De sketch (bij mij is dat een .cpp file vanwege Eclipse)

/**
 * Project         CO2_Sensor
 * @file           CO2_Sensor.cpp
 * @sketch name    CO2_Sensor
 * @diagram        SysteemOverzicht  
 * @author         Nico Verduin
 * @date generated 22-5-2017 16:10:15
 */
 
#include <Arduino.h>
#include "LiquidCrystal_I2C.h"
#include "SystemParameters.h"
#include "ProcessSensor.h"
 
//
// global variables 
//
uint32_t timer_1 = 0;    // Timer for flipping led
LiquidCrystal_I2C lcd(0x27,COLUMNS,ROWS);    // Creatie van lcd object
 
/**
 * @name    setup
 * @returns void
 */
void setup()
{
    pinMode(RELAIS_PIN, OUTPUT);
    digitalWrite(RELAIS_PIN, LOW);    
}
 
/**
 * @name    loop
 * @returns void
 */
void loop()
{
     
}

De enumeratie :

#ifndef SYSTEMPARAMETERS_H
#define SYSTEMPARAMETERS_H
/**
 * Project         CO2_Sensor
 * @file           SystemParameters.h
 * @enum           SystemParameters
 * @diagram        SysteemOverzicht  
 * @author         Nico Verduin
 * @date generated 22-5-2017 16:10:15
 * Enumeratie van alle systeem parameters die door het programma gebruikt worden. Na deze aangepast te hebben kan er een source code hergeneratie plaatsvinden en daarna de compilatie en flash.
 */
 
 
enum SystemParameters {
    SENSOR_PIN = A0,    // Aansluiting van de sensor op de analog ingang
    RELAIS_PIN = 8,    // Aansluiting van het relais op de Arduino. 
    OPSTART_TIJD = 180000UL,    // De CO2 sensor heeft 3 minuten opstart tijd nodig alvorens een correcte meting te kunnen afgeven
    PPM_DREMPEL = 450,    // PPM_DREMPEL een waarde waarop het systeem op zal reageren
    COLUMNS = 16,    // Aantal kolommen op LCD display
    ROWS = 2    // Aantal Regels op display
 
};
#endif

De ProcessSensor.h

#ifndef PROCESSSENSOR_H
#define PROCESSSENSOR_H
/**
 * Project         CO2_Sensor
 * @file           ProcessSensor.h
 * @class          ProcessSensor
 * @diagram        SysteemOverzicht  
 * @author         Nico Verduin
 * @date generated 22-5-2017 16:10:15
 * 
 */
 
#include <Arduino.h>
#include "SystemParameters.h"
 
class ProcessSensor
{
    private:
        int16_t _sensorValue;    // signed integer waarde van de analoge lezing van de sensor.
 
        bool _sensorOperable;    // Geeft aan of de sensor voorbij de opstart tijd is. Zie parameter OPSTART_TIJD
 
    public:
        ProcessSensor ();
        bool IsReady ();
        int16_t leesSensor (uint8_t sensorPin);
        int16_t Get_sensorvalue ();
 
};
#endif

en ProcessSensor.cpp

/**
 * Project         CO2_Sensor
 * @file           ProcessSensor.cpp
 * @class          ProcessSensor
 * @diagram        SysteemOverzicht  
 * @author         Nico Verduin
 * @date generated 22-5-2017 16:10:15
 * 
 */
 
#include "Arduino.h"
#include "SystemParameters.h"
#include "ProcessSensor.h"
 
/**
 * @name    ProcessSensor
 * Constructor
 */
ProcessSensor::ProcessSensor()
{
    //
    // initialiseer object
    //
    _sensorOperable = false;
    _sensorValue    = -1;    
}
 
/**
 * @name    IsReady
 * @returns bool
 * Controleert of de sensor voldoende is opgewarmd. Zo ja wordt er een true teruggegeven. Zo nee dan een false
 */
bool ProcessSensor::IsReady()
{
    //
    // kijk of de sensor al warm is
    //
    if (!_sensorOperable) {
        //
        // nog niet dus controleer of de opwarm tijd voorbij is
        //
        if (millis() > OPSTART_TIJD){
            _sensorOperable = true;
        }
    }
    //
    // geef de status terug
    //
    return _sensorOperable;    
}
 
/**
 * @name    leesSensor
 * @param   sensorPin  uint8_t   
 * @returns int16_t
 * Leest de sensor uit
 
 */
int16_t ProcessSensor::leesSensor(uint8_t sensorPin)
{
    //
    // controleer dat opstart tijd voorbij is
    //
    if (_sensorOperable) {
        _sensorValue = analogRead(sensorPin);
    } else {
        _sensorValue = -1;     // ongeldige waarde
    }
    return _sensorValue;    
}
 
/**
 * @name    Get_sensorvalue
 * @returns int16_t
 * Geeft de laatst gelezen sensorwaarde terug
 */
int16_t ProcessSensor::Get_sensorvalue()
{
    return _sensorValue;    
}

Ik heb dus zelf geen enkele aanpassing in de sources hoeven maken. Libraries heb ik gepresenteerd als Packages (juiste naam is wel noodzakelijk). EN je moet UML enigzins beheersen. Het is allemaal nog in ontwikkeling maar door alles te kunnen 'hergenereren' houd ik de documentatie consistent met de code. En verder kun je allerlei reports eruit genereren.
Zie verder : https://www.softwareideas.net/