This commit is contained in:
Tamer Oeztuerk 2025-06-12 12:49:53 +02:00
parent 5dfa85ffa5
commit 814421d43d
11 changed files with 100669 additions and 0 deletions

178
automat.c Normal file
View File

@ -0,0 +1,178 @@
/**********************************************************************\
* Kurzbeschreibung: automat.c
* Stellt Funktionen zur Realisierung eines Automaten zur Verf<EFBFBD>gung,
* die <EFBFBD>ber die in der automat.h vorgegebene C-Schnittstelle
* mit einer grafischen Schnittstelle kommunizieren.
*
* Datum: Autor: Grund der Aenderung:
*
*
\**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "automat.h"
/*--- #defines -------------------------------------------------------*/
/* Macro zur Ermittlung der Array Groesse */
#define SIZE_OF(a) (sizeof((a)) / sizeof(*(a)))
#define NR_OF_STATES (I - A + 1)
/*--- Datentypen (typedef) -------------------------------------------*/
/* Definition der Zustaende */
typedef enum
{
A = 0,
B,
C,
D,
E,
F,
G,
H,
I
} state_t;
/* Definition der fsm-spezifischen Variablen */
/* Struktur zur Beschreibung eines Uebergangs mit "Don't Care"-Moeglichkeit */
typedef struct
{
int input;
int mask;
state_t nxtstate;
} fsm_state_t;
/* Struktur zur Beschreibung aller Uebergaenge eines Zustands */
typedef struct
{
const fsm_state_t *transitions;
int nrOfTransitions;
state_t defaultNxtState;
} fsm_full_state_t;
/*--- Modulglobale static Variablen ----------------------------------*/
/* Definition der Zustandsvariablen */
static state_t s_curstate = A; /* Initialisierung */
/* Definition aller Zustandsuebergaenge fuer jeden Zustand */
static const fsm_state_t s_transitions_A[] =
{/* input mask nxtstate */
{0x002, ~0x004, B},
{0x003, ~0x004, C}};
static const fsm_state_t s_transitions_B[] =
{/* input mask nxtstate */
{0x002, ~0x004, C},
{0x003, ~0x004, D}};
static const fsm_state_t s_transitions_C[] =
{/* input mask nxtstate */
{0x002, ~0x004, D},
{0x003, ~0x000, F},
{0x007, ~0x000, H}};
static const fsm_state_t s_transitions_D[] =
{/* input mask nxtstate */
{0x002, ~0x000, F},
{0x003, ~0x004, E},
{0x006, ~0x000, H}};
static const fsm_state_t s_transitions_E[] =
{
/* input mask nxtstate */
{0x000, ~0x005, D},
{0x002, ~0x000, F},
{0x006, ~0x000, H}};
static const fsm_state_t s_transitions_F[] =
{
/* input mask nxtstate */
{0x002, ~0x001, G},
{0x006, ~0x001, I},
{0x004, ~0x001, H}};
static const fsm_state_t s_transitions_G[] =
{
/* input mask nxtstate */
{0x000, ~0x001, F},
{0x004, ~0x001, H},
{0x006, ~0x001, I},
};
static const fsm_state_t s_transitions_H[] =
{
/* input mask nxtstate */
{0x000, ~0x001, A},
{0x002, ~0x000, B},
{0x003, ~0x000, C},
{0x006, ~0x001, I}};
static const fsm_state_t s_transitions_I[] =
{
/* input mask nxtstate */
{0x000, ~0x001, A},
{0x002, ~0x000, B},
{0x003, ~0x000, C},
{0x004, ~0x001, H}};
/* Definition der Uebergangstabelle */
/* Die Reihenfolge der Zustaende in der enum Definition muss der
* Reihenfolge der Zustaende in der Uebergangstabelle entsprechen
* [Zeile] [Spalte] */
static const fsm_full_state_t s_state_table[NR_OF_STATES] =
{
/* transitions nrOfTransitions defaultNxtState */
{s_transitions_A, SIZE_OF(s_transitions_A), A},
{s_transitions_B, SIZE_OF(s_transitions_B), B},
{s_transitions_C, SIZE_OF(s_transitions_C), C},
{s_transitions_D, SIZE_OF(s_transitions_D), D},
{s_transitions_E, SIZE_OF(s_transitions_E), E},
{s_transitions_F, SIZE_OF(s_transitions_F), F},
{s_transitions_G, SIZE_OF(s_transitions_G), G},
{s_transitions_H, SIZE_OF(s_transitions_H), H},
{s_transitions_I, SIZE_OF(s_transitions_I), I}};
/* Definition der Ausgaenge */
static const fsm_action_t s_out_table[NR_OF_STATES] =
{
/* display muenz_rueck kaffee_los guthaben, display_string */
{false, false, false, 0, "Warten"}, /* state A */
{false, false, false, 1, "1 Euro"}, /* state B */
{false, false, false, 2, "2 Euro"}, /* state C */
{false, false, false, 3, "3 Euro"}, /* state D */
{false, true, false, 3, "3 Euro + M"}, /* state E */
{true, false, false, 4, "4 Euro"}, /* state F */
{true, true, false, 4, "4 Euro + M"}, /* state G */
{true, false, true, 0, "Glühwein"}, /* state H */
{true, true, true, 0, "Glühwein + M"}, /* state I */
};
/*--- Funktionsdefinition --------------------------------------------*/
void automat_reset(void)
{
printf("---- automat_reset ----\n");
s_curstate = A;
}
/*--- Funktionsdefinition --------------------------------------------*/
void automat_transition(BOOL becher, BOOL muenze, BOOL muenz_wert)
{
printf("---- automat_transition becher(%0d) muenze(%0d) muenz_wert(%0d) ----\n",
becher, muenze, muenz_wert);
int bitTrain = (becher << 2 | muenze << 1 | muenz_wert);
fsm_full_state_t curState = s_state_table[s_curstate];
for (int i = 0; i < curState.nrOfTransitions; i++)
{
if ((curState.transitions[i].input & curState.transitions[i].mask) == (bitTrain & curState.transitions[i].mask))
{
s_curstate = curState.transitions[i].nxtstate;
}
}
}
/*--- Funktionsdefinition --------------------------------------------*/
fsm_action_t automat_output(void)
{
return s_out_table[s_curstate];
}

44
automat.h Normal file
View File

@ -0,0 +1,44 @@
/**********************************************************************\
* Kurzbeschreibung: automat.h
* Stellt Funktionen zur Realisierung eines Automaten zur Verfügung,
* die über die in der automat.h vorgegebene C-Schnittstelle
* mit einer grafischen Schnittstelle kommunizieren.
*
* Datum: Autor: Grund der Aenderung:
*
*
\**********************************************************************/
#ifndef AUTOMAT_H
#define AUTOMAT_H
/*--- #defines -------------------------------------------------------*/
#define true 1
#define false 0
/*--- Datentypen (typedef) -------------------------------------------*/
typedef int BOOL;
typedef struct {
BOOL display;
BOOL muenz_rueck;
BOOL kaffee_los;
int guthaben;
const char * display_string;
} fsm_action_t;
/*--- Prototypen globaler Funktionen ---------------------------------*/
/*--------------------------------------------------------------------*
* Setzt den Automat in IDLE state *
*--------------------------------------------------------------------*/
extern void automat_reset(void);
/*--------------------------------------------------------------------*
* Fuehrt Zustandsuebergaenge durch *
*--------------------------------------------------------------------*/
extern void automat_transition(BOOL becher, BOOL muenze, BOOL muenz_wert);
/*--------------------------------------------------------------------*
* Gibt Informationen ueber aktuellen Zustand zurueck *
*--------------------------------------------------------------------*/
extern fsm_action_t automat_output(void);
#endif /* AUTOMAT_H */

14
bitTrainTest.c Normal file
View File

@ -0,0 +1,14 @@
#include <stdio.h>
typedef int BOOL;
int main(void)
{
BOOL becher = 0;
BOOL muenze = 0;
BOOL muenz_wert = 1;
char bitTrain = (becher << 2 | muenze << 1 | muenz_wert);
printf("%#08x", bitTrain);
return 0;
}

123
checker.c Normal file
View File

@ -0,0 +1,123 @@
#include "checker.h"
#include <stdio.h>
typedef struct {
BOOL reset;
BOOL muenz_wert;
BOOL muenze;
BOOL becher;
} fsm_input_t;
typedef struct {
fsm_input_t input;
fsm_action_t output;
} fsm_transaction_t;
#include "s_transaction_list.h"
static const int s_transaction_list_size =
sizeof(s_transaction_list) / sizeof(*s_transaction_list);
#define ERROR_STRING_SIZE 1000
static char s_error_string[ERROR_STRING_SIZE] = { 0 };
static void checker_propagate_input(fsm_input_t input);
static BOOL checker_compare(fsm_action_t o1, fsm_action_t o2);
static void checker_write_error_string(
fsm_action_t current, fsm_input_t input,
fsm_action_t actual, fsm_action_t expected);
static void checker_clear_error_string(void);
/*****************************************************************************/
/* implementation of extern functions ****************************************/
/*****************************************************************************/
BOOL checker_check()
{
fsm_action_t last_out;
fsm_action_t new_out;
int i;
automat_reset();
for (i = 0; i < s_transaction_list_size; i++) {
last_out = automat_output();
checker_propagate_input(s_transaction_list[i].input);
new_out = automat_output();
if (!checker_compare(new_out, s_transaction_list[i].output)) {
checker_write_error_string(last_out, s_transaction_list[i].input,
new_out, s_transaction_list[i].output);
return false;
}
}
checker_clear_error_string();
return true;
}
const char * checker_error_string() { return s_error_string; }
/*****************************************************************************/
/* implementation of static functions ****************************************/
/*****************************************************************************/
void checker_propagate_input(fsm_input_t input)
{
if (input.reset) automat_reset();
else automat_transition(input.becher, input.muenze, input.muenz_wert);
}
BOOL checker_compare(fsm_action_t o1, fsm_action_t o2)
{
return o1.display == o2.display &&
o1.muenz_rueck == o2.muenz_rueck &&
o1.kaffee_los == o2.kaffee_los &&
o1.guthaben == o2.guthaben;
}
void checker_write_error_string(
fsm_action_t current, fsm_input_t input,
fsm_action_t actual, fsm_action_t expected)
{
if (input.reset) {
/* actually wanna use snprintf, but it's defined in c99 */
sprintf(s_error_string,
"Ausgangsvektor enthält nicht die erwarteten Werte:\n"
"Letzter Zustand: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
"Eingang: Reset\n"
"Ausgang: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
"Erwartet: disp:%d rueck:%d los:%d guthaben:%d",
current.display, current.muenz_rueck, current.kaffee_los,
current.guthaben, current.display_string,
actual.display, actual.muenz_rueck, actual.kaffee_los,
actual.guthaben, actual.display_string,
expected.display, expected.muenz_rueck, expected.kaffee_los,
expected.guthaben);
} else {
/* actually wanna use snprintf, but it's defined in c99 */
sprintf(s_error_string,
"Ausgangsvektor enthält nicht die erwarteten Werte:\n"
"Letzter Zustand: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
"Eingang: becher:%d muenze:%d muenz_wert:%d\n"
"Ausgang: disp:%d rueck:%d los:%d guthaben:%d \"%s\"\n"
"Erwartet: disp:%d rueck:%d los:%d guthaben:%d",
current.display, current.muenz_rueck, current.kaffee_los,
current.guthaben, current.display_string,
input.becher, input.muenze, input.muenz_wert,
actual.display, actual.muenz_rueck, actual.kaffee_los,
actual.guthaben, actual.display_string,
expected.display, expected.muenz_rueck, expected.kaffee_los,
expected.guthaben);
}
}
void checker_clear_error_string()
{
s_error_string[0] = '\0';
}

9
checker.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __CHECKER_H__
#define __CHECKER_H__
#include "automat.h"
extern BOOL checker_check(void);
extern const char * checker_error_string(void);
#endif /* __CHECKER_H__ */

80
io.c Normal file
View File

@ -0,0 +1,80 @@
#include "io.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
/******************************************************************************/
/* Module intern macros *******************************************************/
/******************************************************************************/
/* unfortunatly can't write this code as function, because of stack management
* => use makro instead */
#define DO_PRINTING(output_str) \
do { \
if (output_str != NULL) { \
va_list args; \
va_start(args, output_str); \
vprintf(output_str, args); \
va_end(args); \
} \
} while (0)
/******************************************************************************/
/* Implementations ************************************************************/
/******************************************************************************/
char * io_read_string(char * read_buffer, size_t buffer_size,
const char * output_str, ...)
{
char * ret, * ptr;
DO_PRINTING(output_str);
ret = fgets(read_buffer, buffer_size, stdin);
if (ret == NULL) return NULL;
/* search for \n */
ptr = strchr(read_buffer, '\n');
/* if found write \0 instead of \n */
if (ptr) *ptr = '\0';
/* else buffer is not read completly => clear buffer */
else while (getchar() != '\n');
return read_buffer;
}
int io_read_signed_number(const char * output_str, ...)
{
int number;
while (1) {
int ret;
DO_PRINTING(output_str);
ret = scanf("%d", &number);
/* clear buffer */
while (getchar() != '\n');
if (ret == 1) break;
else printf("Eingabefehler!!!\n");
}
return number;
}
unsigned int io_read_unsigned_number(const char * output_str, ...)
{
unsigned int number;
while (1) {
int ret;
DO_PRINTING(output_str);
ret = scanf("%u", &number);
/* clear buffer */
while (getchar() != '\n');
if (ret == 1) break;
else printf("Eingabefehler!!!\n");
}
return number;
}

18
io.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __IO_H__
#define __IO_H__
#include <stddef.h> /* for size_t */
/* prints the given string (if not NULL) and reads a string from stdin and
* removes \n
* the functions returns the value of fgets */
extern char * io_read_string(char * read_buffer, size_t buffer_size,
const char * output_str, ...);
/* prints the given string (if not NULL) and reads signed number from stdin */
extern int io_read_signed_number(const char * output_str, ...);
/* prints the given string (if not NULL) and reads unsigned number from stdin */
extern unsigned int io_read_unsigned_number(const char * output_str, ...);
#endif /* __IO_H__ */

70
main.c Normal file
View File

@ -0,0 +1,70 @@
#include <stdio.h>
#include "view.h"
#include "automat.h"
#include "checker.h"
void insert_1_euro(void)
{
view_set_coin(1);
automat_transition(view_has_cup(), true, false);
}
void insert_2_euro(void)
{
view_set_coin(2);
automat_transition(view_has_cup(), true, true);
}
void toggle_cup(void)
{
view_set_coin(0);
view_toggle_cup();
automat_transition(view_has_cup(), false, false);
}
void check(void)
{
printf("\n");
if (checker_check()) {
printf("Der Zustandsautomat ist correct\n");
} else {
printf("%s\n", checker_error_string());
}
printf("\nWeiter mit Return ...");
while (getchar() != '\n');
automat_reset();
}
int main(void)
{
int finished = 0;
automat_reset();
view_reset();
while (!finished) {
view_menu_t selection;
view_show(automat_output());
selection = view_menu();
switch (selection) {
case VIEW_1_EURO: insert_1_euro(); break;
case VIEW_2_EURO: insert_2_euro(); break;
case VIEW_CUP: toggle_cup(); break;
case VIEW_RESET: automat_reset(); view_reset(); break;
case VIEW_CHECK: check(); break;
case VIEW_EXIT: finished = 1; break;
case VIEW_INVALID: break;
}
}
return 0;
}

100002
s_transaction_list.h Normal file

File diff suppressed because it is too large Load Diff

115
view.c Normal file
View File

@ -0,0 +1,115 @@
#include "view.h"
#include "io.h"
#include <stdio.h>
#define S_MACHINE_HEAD \
" /-----------------------------------\\\n" \
" | %33s |\n" \
" \\-----------------------------------/\n" \
" \n" \
" /~~~~~~~~~~~/| \n" \
" / /#########/ / |\n" \
" / /_________/ / |\n" \
" =============== /||\n" \
" | %03d EUR |/ ||\n" \
" |_____________|/ ||\n" \
" | \\___..___/ ||\n" \
" | || ||\n"
#define S_MACHINE_NO_COFFEE \
" | ||\n" \
" | ||\n" \
" | ||\n"
#define S_MACHINE_COFFEE \
" | ) ( ||\n" \
" | ( ) ) ||\n" \
" | ) ( ( ||\n" \
#define S_MACHINE_NO_CUP \
" _________ | ||\n" \
" .-'---------| |_______________||\n" \
" ( C|/\\/\\/\\/\\/| | / |\n" \
" '-./\\/\\/\\/\\/| _|_ _ _ _ _ _ _/ |\n" \
" '_________' | | / \n" \
" '-------' |_______________|/ \n" \
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n"
#define S_MACHINE_CUP \
" | _________ ||\n" \
" .-'---------|___||\n" \
" ( C|/\\/\\/\\/\\/| / |\n" \
" _'-./\\/\\/\\/\\/|_/ |\n" \
" | '_________' | / \n" \
" |____'-------'__|/ \n" \
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n"
#define S_MACHINE_NO_COIN_RETURN "\n"
#define S_MACHINE_INVALID_COIN_RETURN \
" -> keine Muenze verfuegbar !!!\n"
#define S_MACHINE_COIN_RETURN \
" -> %0d Euro zurueck\n"
/* machine status variables */
static int s_has_cup = 0;
static int s_coin_value = 0;
/* function implementations */
void view_show(fsm_action_t out_vector)
{
int i;
for (i = 0; i < 100; i++) printf("\n");
printf(S_MACHINE_HEAD, out_vector.display_string, out_vector.guthaben);
if (out_vector.kaffee_los) printf(S_MACHINE_COFFEE);
else printf(S_MACHINE_NO_COFFEE);
if (s_has_cup) printf(S_MACHINE_CUP);
else printf(S_MACHINE_NO_CUP);
if (out_vector.muenz_rueck) {
if (s_coin_value) printf(S_MACHINE_COIN_RETURN, s_coin_value);
else printf(S_MACHINE_INVALID_COIN_RETURN);
} else {
printf(S_MACHINE_NO_COIN_RETURN);
}
}
view_menu_t view_menu()
{
int read = io_read_signed_number(
"\n"
" 0) Einwurf 1 Euro\n"
" 1) Einwurf 2 Euro\n"
" 2) Becher verstellen\n"
" 3) Reset\n"
" 4) Automatischer Testlauf\n"
" 5) Programm beenden\n"
"\n"
" Auswahl: ");
switch (read) {
case 0: return VIEW_1_EURO;
case 1: return VIEW_2_EURO;
case 2: return VIEW_CUP;
case 3: return VIEW_RESET;
case 4: return VIEW_CHECK;
case 5: return VIEW_EXIT;
default: return VIEW_INVALID;
}
}
void view_toggle_cup() { s_has_cup = s_has_cup ? 0 : 1; }
int view_has_cup() { return s_has_cup; }
void view_set_coin(int value) { s_coin_value = value; }
void view_reset()
{
s_has_cup = 0;
s_coin_value = 0;
}

16
view.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "automat.h"
typedef enum { VIEW_1_EURO, VIEW_2_EURO, VIEW_CUP, VIEW_RESET, VIEW_CHECK, VIEW_EXIT, VIEW_INVALID } view_menu_t;
extern void view_show(fsm_action_t out_vector);
extern view_menu_t view_menu(void);
extern void view_toggle_cup(void);
extern int view_has_cup(void);
extern void view_set_coin(int value);
extern void view_reset(void);