BWP-SS19-01/Fein Design/EMS

Aus Verteilte Systeme - Wiki
Zur Navigation springen Zur Suche springen

Energy Management System

Das Energy Management System besteht, aus Software-Sicht, aus einem eigenen Header-File (Energy_Management_System.h) und zwei Source-Files (Energy_Management_System.c und Battery_Control.c).

Die Aufgaben des Energy Management Systems sind:

  • Auf Anfrage Energie-Werte liefern
    • Batteriestand
    • Verbrauch durch das System
    • Einnahme durch die Solar Panel
  • Das Simulieren momentaner Energie-Werte je nach Systemzustand
  • Das Bereitstellen des Energiesparmodus

Energy_Management_System.h

Im Header-File befinden sich Konstanten und Funktionsdeklarationen, die für dieses Modul benötigt werden. Speziell die Funktionsdeklarationen der Funktionen, die aus der Battery_Control.c heraus im Energy Management Thread in Energy_Management_System.c benötigt werden.

Außerdem ist hier beschreiben, das die GPIO-Callback-Funktionen bei einer HIGH EDGE ausgelöst werden sollen:

 #define EDGE (GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW) 

Energy_Management_System.c

Das Energy_Management_System.c File beinhaltet den Thread, der das Energy Management System darstellt.

Zur Kommunikation mit dem Haupt-Thread wird hierbei ein Pointer erzeugt und auf eine globale statische Struct gesetzt.


// Global

	static struct data_item_t edata;

	struct data_item_t * edata_ptr;

// Thread

	edata_ptr = &edata;

Außerdem wird über die selbe Technik der Timer in dem Energy_Management_System.c File manipuliert.

Darüber hinaus ist der Haupt-Thread des Energy_Management_Systems in diesem File definiert.

Dieser initialisiert direkt nach seinem Start die Battery Contol:


void energy_management_system(void* arg1, void* arg2, void* arg3) {

	if (Battery_Control_init()) {
		printk("Battery_Control_init(): ERROR\n");
		return;
	} else {
		printk("Battery-controll initialisation successfully finished\n");
	}


Die Hauptaufgabe des Threads (Diese läuft in einer Endlos-Schleife) ist jedoch die Bearbeitung einer Aufgabe die er von der Main Control erhält.

Dafür wird jeweils immer auf die Aufgabe der Main Control gewartet:

while (edata.sig_id == 0)
	k_sleep(SLEEP_SEC/5);

Danach wird entschieden was sie bedeutet bzw was für eine Aufgabe erledigt werden soll:

edata.sig = choose_workstate (edata.sig_id, edata.sig);

Intern entscheidet die Funktion choose_workstate() welche Aufgabe erfüllt werden soll mit einem switch-case.

Eine weitere erwähnenswerte Funktion in dem Energy_Management_Systems.c File ist der Sleep State:

sys_set_power_state(SYS_POWER_STATE_SLEEP);

k_sched_lock();

k_sleep( (SLEEP_SEC*60) * arg); // <-- Sleeping 

k_sched_unlock();

Hierfür wird das System erst in ein niedrigeres Power-level gesetzt. Anschließend wird der Scheduler auf den aktuellen Thread "festgenagelt". Jetzt kann der aktuelle Thread schlafen gelegt werden, was den Ruhe-Modus repräsentiert. Nach dem Ruhe-Modus wird der Scheduler wieder entsperrt.

Diese Umsetzung wurde bewusst so gewählt, da sonst die device driver der einzelnen Module neu hätten initialisiert werden müssen, was in der aktuellen Datei-Struktur nur schwer umsetzbar ist.

Battery_Control.c

Dieses File beinhaltet alle modul-spezifischen Funktionen, die nicht Teil des Energy Management Threads sind. Außerdem sind hier die GPIO-Ports und ihre Callback-Funktionen implementiert. Auch ist hier der Timer zu finden, über den die Simulation der Energiewerte läuft.

Zunächst werden die dafür die Register und die device driver für die GPIO-Port und ihre Callback_Funktionen benötigt:

static int energy_income;
static int energy_consumption;
static int battery_level;

struct device * counter_income;
struct device * counter_consumption;

Außerdem sind am Anfang die device driver für die GPIO-Pins definiert die für den Timer und damit für die Simulation von, von Außerhalb kommenden Leistungs-Stößen, benötigt werden.

struct device * counter_income_test;
struct device * counter_consumption_test;

struct k_timer my_timer;
static int cnt = 0;

Als nächstes sind die GPIO-Callback Funktionen implementiert, die ein Wert in einem der oben genannten Registern inkrementieren.

static struct gpio_callback gpio_cb1, gpio_cb2;

void counter_income_int(struct device *gpiob, struct gpio_callback *cb,
		    u32_t pins)
{
	energy_income++;
}

void counter_consumption_int(struct device *gpiob, struct gpio_callback *cb,
		    u32_t pins)
{
	energy_consumption++;
}

Für die Simulation der Energie Werte werden in einer Timer Funktion die zwei anderen Pins, abhängig von einer globalen Variable unterschiedlich schnell getoggelt. Diese Timer Funktion wird Aufgerufen wenn der Timer 0 erreich. Der Timer erreicht 0 alle 250 ms.

Als Beispiel (innerhalb des switch-case der Timer Funktion):

case ENERGY_STATE_FORWARD:
	gpio_pin_write(counter_income_test, ENERGY_INCOME_PIN_TEST, cnt % 8);
	gpio_pin_write(counter_consumption_test, ENERGY_CONSUMPTION_PIN_TEST, cnt % 2);

In diesem Fall ist cnt ein Wert der durchgängig inkrementiert wird. Das beutet das bei cnt % 8 ein Signal (11111110) und bei cnt % 2 ein Signal (10101010) raus kommt. Da nur die High Edge gezählt wird ist der Timer sozusagen für cnt % 2 schneller als für cnt % 8.

In der darauffolgenden Battery_Control_init() Funktion werden die einzelnen Modul-Teile initialisiert und vorkonfiguriert.

/* resets variables on initialising Battery Control */
Battery_Control_reset();

counter_income           = device_get_binding(GPIO_DRIVER);
counter_consumption      = device_get_binding(GPIO_DRIVER);
counter_income_test      = device_get_binding(GPIO_DRIVER);
counter_consumption_test = device_get_binding(GPIO_DRIVER);


if (counter_income == NULL || counter_consumption == NULL || counter_income_test == NULL || counter_consumption_test == NULL) {
	printk("Battery_Control_init(): ERROR");
	return ERROR;
}

/* Conigurating Ports, so that they call a callback function on high edge */
gpio_pin_configure(counter_income          , ENERGY_INCOME_PIN          , (GPIO_DIR_IN | GPIO_INT | EDGE));
gpio_pin_configure(counter_consumption     , ENERGY_CONSUMPTION_PIN     , (GPIO_DIR_IN | GPIO_INT | EDGE));


gpio_init_callback(&gpio_cb1, counter_income_int      , BIT(ENERGY_INCOME_PIN     ));
gpio_init_callback(&gpio_cb2, counter_consumption_int , BIT(ENERGY_CONSUMPTION_PIN));

gpio_add_callback(counter_income     , &gpio_cb1);
gpio_add_callback(counter_consumption, &gpio_cb2);

gpio_pin_enable_callback(counter_income     , ENERGY_INCOME_PIN);
gpio_pin_enable_callback(counter_consumption, ENERGY_CONSUMPTION_PIN);

/*
*  Testing the power edges:
* init timer which peridicaly switches pins (ENERGY_INCOME_PIN_TEST, ENERGY_CONSUMPTION_PIN_TEST) between 1 and 0
*/

gpio_pin_configure(counter_income_test     , ENERGY_INCOME_PIN_TEST     , GPIO_DIR_OUT );
gpio_pin_configure(counter_consumption_test, ENERGY_CONSUMPTION_PIN_TEST, GPIO_DIR_OUT );

k_timer_init(&my_timer, timer_expiry_function, NULL);

/* start periodic timer that expires once every quarter of a second */
k_timer_start(&my_timer, K_SECONDS(1)/4, K_SECONDS(1)/4);

Am Ende des Files folgen nun noch die Get() Methoden der Variablen die die Energie-Messung repräsentieren. Wichtig ist hierbei nur nochmal auf die Berechnung des Akku-Stands hinzuweisen:

battery_level += ( energy_income - energy_consumption );

Dieser setzt sich aus der Einnahme und dem Verbrauch zusammen.