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/