diff --git a/docs/diagrams/state_diagram.gaphor b/docs/diagrams/state_diagram.gaphor new file mode 100644 index 0000000..a95414d --- /dev/null +++ b/docs/diagrams/state_diagram.gaphor @@ -0,0 +1,2699 @@ + + + + + +diagram { + /* line-style: sloppy 0.3; */ +} + +controlflow { + dash-style: 0; +} + + + + + +Modellname hier eintragen + + + + + + + + + + + + + + + + + + + + + + + + +Ablauf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +reset + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, -63.3325267095356, 704.3999999999999) + + +(0.0, 0.0) + + +20.0 + + +20.0 + + + + + + + + + + + + + +State Machine + + + + + + + + + + + + + + + + + + + + +MSP430-StateMachine + + + + + + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 8.0, 8.0) + + +(-244.4958441384397, 0.0) + + +1269.9964112440239 + + +1090.6165284444828 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 964.0223449626474, 377.1943371546741) + + +[(-999.3548716721831, 345.2056628453259), (-918.0223449626474, 345.2056628453259)] + + + + + + + + + + + + + + + + + + + + + + +idle + + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 37.99999999999999, 688.4000000000001) + + +(0.0, 0.0) + + +50.0 + + +52.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 41.5, 76.80000000000001) + + +(0.0, 0.0) + + +97.0 + + +52.0 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 393.39724202029396, 505.245117941848) + + +[(-297.39724202029396, 217.154882058152), (-74.97622731113597, 217.154882058152), (-74.97622731113597, -280.07774097662934), (43.72938384182612, -280.0925817502037)] + + + + + + + + + + + + + + + + + + + +B + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 20.0, 238.8) + + +(0.0, 0.0) + + +132.0 + + +52.0 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 643.143217001042, 515.2616677405409) + + +[(-158.14659113892185, -276.19423450621), (-160.87659113892187, -166.19423450621002)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1-9 + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 1224.7708753118209, 192.0609942360434) + + +[(-690.6442494497007, 9.666438998287447), (-653.9328056755969, 10.426382729175202), (-653.9328056755969, 33.106382729175266), (-690.6442494497007, 32.34643899828751)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A-D + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 1427.73323171514, 78.54009651752189) + + +[(-880.1066058530198, 285.735336716809), (-856.8951620789159, 286.49528044769687), (-856.895162078916, 308.07928044769704), (-880.1066058530198, 307.31933671680906)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0-9 + + + + + + + + + + +select_count + + + + + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 387.6266258621201, 102.26743323433087) + + +(0.0, 0.0) + + +218.5401732597482 + + +321.71317763289477 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +select_count + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, -186.34092585307778, 108.85295935581789) + + +(-17.420949104009978, 0.0) + + +211.01531575913464 + + +308.54212538992067 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A + + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 42.0, 76.80000000000007) + + +(0.0, 0.0) + + +50.0 + + +52.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +B + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 38.513999999999996, 206.7470406441821) + + +(0.0, 0.0) + + +50.0 + + +52.0 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 489.5561200877478, 513.2583577808024) + + +[(-73.9294942256277, -141.28487196142697), (-141.5561200877478, -141.28487196142697), (-141.5561200877478, -216.13433573002413), (-293.47612008774774, -216.13433573002413)] + + + + + + + + + + + + + + + + + + + +confirmed + + + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 110.08000000000007, 263.12402205077825) + + +(0.0, 0.0) + + +78.0 + + +59.44772460066565 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 448.15438091981633, 663.5066047611988) + + +[(-291.07438091981635, -392.38258271042054), (-291.07438091981635, -450.4391715268679), (-11.027755057696254, -450.4391715268679)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A-D + + + + + + + + + + + + + + + + + + +door_open + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 20.5, 526.4) + + +(0.0, 0.0) + + +85.0 + + +52.0 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 441.4766810540209, 672.1876145867328) + + +[(-323.39668105402086, -371.33973023562174), (-357.48868105402084, -371.33973023562174), (-357.4886810540209, -137.78761458673284)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[door_opened] + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 220.4448154961932, 680.2008544256873) + + +[(-191.9448154961932, -108.46085442568733), (-392.1669709364176, -108.46085442568733), (-392.16697093641756, -460.5478950698694), (-356.785741349271, -460.5478950698694)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A-D + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 160.34551670403462, 553.9923269621543) + + +[(-275.1724425571124, -308.3393676063363), (-271.6664425571124, -230.39232696215436)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1-9 + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 179.71084631484126, 540.6369272305632) + + +[(-266.051772167919, -332.65396787474526), (-244.5898039023392, -332.65396787474526), (-244.58980390233924, -309.31396787474523), (-266.051772167919, -309.31396787474523)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A-D + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 74.20318843527397, 551.3212470158361) + + +[(-189.03011428835177, -175.72124701583607), (-189.03011428835177, 9.078752984163884), (-45.70318843527397, 9.078752984163998)] + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 139.3259873559967, 990.4406496907525) + + +[(-68.32598735599674, -404.0406496907525), (-68.32598735599669, -294.0406496907524)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[door_closed] + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 84.701519406319, 347.93376630251197) + + +[(-174.5284452593968, 1.6662336974880532), (-124.20521750379442, 1.6662336974880532), (-124.20521750379442, 212.46623369748812), (-56.201519406318994, 212.96623369748804)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"*" + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 88.70813932579625, 203.0276792147518) + + +[(-200.0290651788741, -9.374719858933844), (-200.0290651788741, -36.059579275295164), (-42.70813932579625, -36.059579275295164), (-42.70813932579614, 331.3723207852482)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"*" + + + + + + + + + + +reset_transactions + + + + + + + +reset_transaction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# + + + + + + + + + + + + + + + +append_transaction + + + + + + + +commit_transactions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0-9 + + + + + + + +# + + + + + + + + + + +append_transaction + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 148.1396681313753, 322.55850681248944) + + +[(0.0, 8.013239838954462), (0.0, 27.041493187510582), (32.052959355817904, 27.041493187510582), (32.052959355817904, 8.013239838954462)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +* + + + + + + + + + + +beep_invalid + + + + + + + + + + + + + +error + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 471.89671249199426, 688.4000000000001) + + +(0.0, 0.0) + + +50.0 + + +52.0 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 87.37259935263717, 737.9114384649632) + + +[(8.627400647362826, 0.0), (392.5241131393571, 0.0)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[door_opened] + + + + + + + + + + +beep_alarm; audit_append + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 479.353581474827, 710.5328690152021) + + +[(25.543131017167184, 37.867130984797996), (25.543131017167184, 70.7836185774313), (-408.3535814748271, 70.7836185774313), (-408.3535814748271, 37.867130984797996)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[door_closed] + + + + + + + + + + + + + + + + + +edit_stock + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 21.987999999999975, 862.70353963793) + + +(0.0, 0.0) + + +81.0 + + +52.0 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 46.40788002783745, 738.485082295181) + + +[(10.684319785272635, 9.914917704819118), (10.684319785272692, 132.21845734274905)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"*" + + + + + + + + + + + + + + + + + + + + + +A + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, -216.12067557025176, 862.70353963793) + + +(0.0, 0.0) + + +71.0 + + +52.0 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, -41.73775820066183, 906.7631189132248) + + +[(71.7257582006618, -10.059579275294823), (-95.38291736958985, -10.059579275294823)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, -246.075374094001, 825.7936719647736) + + +[(60.93028835734205, 44.90986767315644), (60.93028835734205, -5.131424383112517), (90.14520574794861, -5.131424383112517), (90.14520574794861, 44.90986767315644)] + + + + + + + + + + +A-D + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 38.39464018888299, 876.045699530566) + + +[(-8.406640188883014, 10.684319785272692), (-49.41497900688597, 10.684319785272692), (-49.41497900688603, -138.1342610656028), (7.605359811117005, -138.1342610656028)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"*" + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 190.24448135224117, 319.3398715996364) + + +[(5.835518647758903, -8.275000228027409), (33.85227366011213, -8.275000228027409), (33.85227366011213, 388.1727379692849), (-94.24448135224117, 388.1727379692849)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +* + + + + + + + + + + +reset_transactions + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, 506.19903551328713, 428.4194200599975) + + +[(0.0, 3.5611908072281153), (-1.3023230212929775, 267.9805799400026)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[door_opened] + + + + + + + + + + +beep_alarm; audit_append + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A-D + + + + + + + + + + + + + + + + +B + + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, -215.61203029881133, 963.9718205940161) + + +(0.0, 0.0) + + +71.7797497171739 + + +48.23858452867603 + + + + + + + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, -170.63743778763262, 910.8243190787935) + + +[(-1.9832377826191419, 11.87922055913657), (-1.9832377826191419, 61.14750151522264)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1-9 + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, -150.25493728255827, 1003.2249880351305) + + +[(14.42265670092084, 1.3588333670047632), (48.23858452867597, 1.3588333670047632), (48.23858452867597, -15.626583720557164), (14.42265670092084, -15.626583720557164)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0-9 + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, -53.22137172001912, 1058.2577393988308) + + +[(-119.39930385023268, -38.04733427613871), (-119.39930385023268, 6.114750151522571), (124.22137172001914, 6.114750151522571), (124.22137172001918, -135.55419976090104)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"*" + + + + + + + + + + +False + + +False + + + + + +(1.0, 0.0, 0.0, 1.0, -155.01085406707563, 1017.4927383886825) + + +[(0.0, 2.71766673400964), (-0.9193142789767421, 16.985417087562155), (209.96877107313378, 16.98541708756204), (209.96877107313378, -94.78919875075246)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# + + + + + + + + + + +update_stock + + + + \ No newline at end of file diff --git a/docs/images/abstract.png b/docs/images/abstract.png new file mode 100644 index 0000000..bcce645 Binary files /dev/null and b/docs/images/abstract.png differ diff --git a/docs/images/state_diagram.png b/docs/images/state_diagram.png new file mode 100644 index 0000000..7ecca00 Binary files /dev/null and b/docs/images/state_diagram.png differ diff --git a/doxygen.conf b/doxygen.conf index d571e7d..9d6674e 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -1096,7 +1096,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which Doxygen is # run. -EXCLUDE = driverlib/ +EXCLUDE = driverlib/ jsmn/ src/Board.h # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/src/door_sensor.c b/src/door_sensor.c index 65878cb..465a596 100644 --- a/src/door_sensor.c +++ b/src/door_sensor.c @@ -1,3 +1,11 @@ +/** + * \file door_sensor.c + * \brief Implementation of the door sensor driver using MSP430 GPIO interrupts. + * + * This module configures a GPIO pin to detect door open/close events and invokes + * user-provided callbacks on confirmed state changes. + */ + #include #include #include @@ -5,32 +13,60 @@ #include "door_sensor.h" #include "constants.h" +/**\brief GPIO port used for the door sensor. */ #define SENSOR_PORT GPIO_PORT_P2 +/**\brief GPIO pin used for the door sensor. */ #define SENSOR_PIN GPIO_PIN0 +/**\brief Interrupt vector associated with the sensor port. */ #define SENSOR_VECTOR PORT2_VECTOR -/** User callback invoked on confirmed key press */ +/** + * \brief Callback invoked when the door is detected as opened. + * + * User must supply a function matching this type to be notified of an open event. + */ static DoorOpenedCallback_t doorOpenedCallback = NULL; +/** + * \brief Callback invoked when the door is detected as closed. + * + * User must supply a function matching this type to be notified of a close event. + */ static DoorClosedCallback_t doorClosedCallback = NULL; +/** + * \brief Initialize the door sensor driver. + * + * Configures the GPIO pin for input with pull-up resistor and enables + * interrupts on the specified edge. Also stores the user-provided callbacks. + * + * \param ocb Function to call when the door opens (rising edge). + * \param ccb Function to call when the door closes (falling edge). + */ void door_init(DoorOpenedCallback_t ocb, DoorClosedCallback_t ccb) { doorOpenedCallback = ocb; doorClosedCallback = ccb; /* Configure port as pull up with interrupt */ - GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN0); - GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN0); - GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_LOW_TO_HIGH_TRANSITION); - GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN0); + GPIO_setAsInputPinWithPullUpResistor(SENSOR_PORT, SENSOR_PIN); + GPIO_clearInterrupt(SENSOR_PORT, SENSOR_PIN); + GPIO_selectInterruptEdge(SENSOR_PORT, SENSOR_PIN, GPIO_LOW_TO_HIGH_TRANSITION); + GPIO_enableInterrupt(SENSOR_PORT, SENSOR_PIN); /* Enable global interrupts */ __enable_interrupt(); } +/** + * \brief Tracks the last known door state (open = true, closed = false). + */ volatile bool door_last_open = false; /** - * @brief Interrupt Service Routine for PORT2 + * \brief ISR for PORT2 interrupt handling door sensor events. + * + * Detects whether the door is opening or closing based on interrupt edge, + * invokes the corresponding callback, and reconfigures the interrupt edge + * for the next transition. */ #pragma vector=SENSOR_VECTOR __interrupt void SENSOR_ISR(void) @@ -39,17 +75,19 @@ __interrupt void SENSOR_ISR(void) if (status) { if (door_last_open) { + /* Door was open, now closed */ if (doorClosedCallback) doorClosedCallback(); - GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_LOW_TO_HIGH_TRANSITION); + GPIO_selectInterruptEdge(SENSOR_PORT, SENSOR_PIN, GPIO_LOW_TO_HIGH_TRANSITION); } else { + /* Door was closed, now opened */ if (doorOpenedCallback) doorOpenedCallback(); - GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_HIGH_TO_LOW_TRANSITION); + GPIO_selectInterruptEdge(SENSOR_PORT, SENSOR_PIN, GPIO_HIGH_TO_LOW_TRANSITION); } } + /* Clear the interrupt flag and toggle stored state */ GPIO_clearInterrupt(SENSOR_PORT, SENSOR_PIN); - door_last_open = !door_last_open; } diff --git a/src/door_sensor.h b/src/door_sensor.h index 5b43318..45b8cc0 100644 --- a/src/door_sensor.h +++ b/src/door_sensor.h @@ -1,13 +1,38 @@ +/** + * \file door_sensor.h + * \brief Public interface for the door sensor driver. + * + * This header declares the callback types and initialization function + * for detecting door open and close events using GPIO interrupts. + */ + #ifndef DOOR_H #define DOOR_H /** - * @brief Callback invoked on a confirmed key press. - * @param key ASCII character of the pressed key. + * \brief Callback type invoked when the door is detected as opened. + * + * This function is called by the driver on a confirmed open event. */ typedef void (*DoorOpenedCallback_t)(void); + +/** + * \brief Callback type invoked when the door is detected as closed. + * + * This function is called by the driver on a confirmed close event. + */ typedef void (*DoorClosedCallback_t)(void); +/** + * \brief Initialize the door sensor driver. + * + * Configures the GPIO pin for input with pull-up resistor and enables + * interrupts on the door sensor line. The provided callbacks are invoked + * on door open and close events respectively. + * + * \param ocb User-provided callback to invoke on door open. + * \param ccb User-provided callback to invoke on door close. + */ void door_init(DoorOpenedCallback_t ocb, DoorClosedCallback_t ccb); -#endif // DOOR_H \ No newline at end of file +#endif // DOOR_H diff --git a/src/i2c.c b/src/i2c.c index 2bfcc89..b036449 100644 --- a/src/i2c.c +++ b/src/i2c.c @@ -1,12 +1,13 @@ -/* ========================================================================== */ -/* I2C.c */ -/* ========================================================================== */ +/* File: i2c.c */ /** - * @file I2C.c - * @author wehrberger - * @date 31.05.2025 + * @file i2c.c + * @brief I²C master routines and missing standard C90 constants for MSP430FR2355. * - * @brief Implementierung eines minimalen blockierenden I²C-Master-Treibers. + * Implements byte-wise I²C transmit and single-register read with automatic + * STOP handling and interrupt-driven operation. + * + * @author (based on work by) Luis Wehrberger + * @date 2025-07-02 */ #include "i2c.h" @@ -14,104 +15,127 @@ #include #include -/** Pointer auf das aktuell zu übertragende Byte. */ -static char *packet; +/** Pointer to the current transmit buffer. */ +static char *i2c_tx_buffer; -/** Index des nächsten zu übertragenden Bytes. */ -static unsigned int dataCount; +/** Number of bytes left to send (buffer length). */ +static unsigned int i2c_tx_length; -/** Anzahl der Bytes in @ref packet. */ -static unsigned int packetLength; +/** Index of the next byte to transmit. */ +static unsigned int i2c_tx_index; -/** Speicher für das zuletzt vom ISR empfangene Byte. */ -static char dataIn; +/** Last byte received by the ISR. */ +static char i2c_rx_byte; -static volatile bool i2cDone = false; +/** Flag set when I²C transfer completes (STOP or NACK). */ +static volatile bool i2c_transfer_complete = false; +/** + * @brief Initialize USCI_B0 module for I²C master mode at 50 kHz. + * + * Configures SMCLK source, sets clock divider, 7-bit addressing, + * automatic STOP generation, port mapping for SDA/SCL, and enables + * relevant interrupts. + */ void i2c_init(void) { - // USCI in Reset setzen um Konfiguration zu ermöglichen + // Put eUSCI_B0 into reset state for configuration UCB0CTLW0 |= UCSWRST; - // SMCLK wählen und durch 20 teilen → 50 kHz SCL + // Select SMCLK and divide by 20 → 50 kHz SCL UCB0CTLW0 |= UCSSEL_3; - UCB0BRW = 50; + UCB0BRW = 50; - // I²C Master, 7-Bit Adressierung + // Configure as I²C master with 7-bit addressing UCB0CTLW0 |= UCMODE_3 | UCMST; - // Automatischer STOP nach Byte-Zähler (UCB0TBCNT) erreicht Null + // Enable automatic STOP when byte counter (UCB0TBCNT) reaches zero UCB0CTLW1 |= UCASTP_2; - // Port-Mapping: P1.2 = SDA, P1.3 = SCL + // Assign P1.2 = SDA, P1.3 = SCL via port mapping P1SEL1 &= ~(BIT2 | BIT3); - P1SEL0 |= BIT2 | BIT3; + P1SEL0 |= (BIT2 | BIT3); - // Modul aktivieren + // Release eUSCI_B0 for operation UCB0CTLW0 &= ~UCSWRST; - // Interrupts: RX, TX, STOP, NACK + // Enable RX, TX, STOP, and NACK interrupts UCB0IE |= UCRXIE0 | UCTXIE0 | UCSTPIE | UCNACKIE; __enable_interrupt(); } +/** + * @brief Transmit a sequence of bytes to a given I²C slave. + * + * @param slaveAddress 7-bit I²C address of the slave device. + * @param data Pointer to data buffer to send. + * @param length Number of bytes to transmit. + */ void i2c_write(uint8_t slaveAddress, char data[], uint8_t length) { + // Set target slave address UCB0I2CSA = slaveAddress; - packet = data; - packetLength = length; - dataCount = 0; - // Master-Transmit-Modus + // Initialize transmit buffer and counters + i2c_tx_buffer = data; + i2c_tx_length = length; + i2c_tx_index = 0; + + // Configure for master-transmit mode and set byte counter UCB0CTLW0 |= UCTR; - UCB0TBCNT = length; + UCB0TBCNT = length; - // START generieren, dann schlafen bis STOP + // Generate START and wait for STOP flag in ISR UCB0CTLW0 |= UCTXSTT; - i2cDone = false; - while (!i2cDone) + i2c_transfer_complete = false; + while (!i2c_transfer_complete) { - LPM3; // Warten auf STOP → ISR weckt uns auf + LPM3; // Enter low-power mode, will wake on STOP or NACK } } -char i2c_read_reg(uint8_t slaveAddress, uint8_t registerAddress) -{ - // Registeradresse zuerst senden - char addressBuffer[1] = {registerAddress}; - i2c_write(slaveAddress, addressBuffer, 1); - - // In Empfangsmodus wechseln und 1 Byte anfordern - UCB0CTLW0 &= ~UCTR; - UCB0TBCNT = 1; - - UCB0CTLW0 |= UCTXSTT; // Repeated START - - i2cDone = false; - while (!i2cDone) - { - LPM3; // Warten auf STOP → ISR weckt uns auf - } - - return dataIn; -} - -/* ========================================================================== */ -/* Interrupt Service Routine */ -/* ========================================================================== */ - /** - * @brief Vereinheitlichte ISR für alle USCI_B0 I²C-Ereignisse. + * @brief Read a single register byte from an I²C slave. * - * Nur vier Interrupt-Ursachen werden derzeit behandelt: - * - UCNACKIFG : Kennzeichnet fehlendes ACK (nur Debug-Hook) - * - UCSTPIFG : STOP erkannt → LPM3 verlassen - * - UCRXIFG0 : Ein Byte empfangen - * - UCTXIFG0 : Sendepuffer bereit für nächstes Byte + * Performs a write of the register address, followed by a repeated START + * to read one byte, with automatic STOP and interrupt-based wake-up. * - * Alle anderen Ursachen fallen durch zum default. + * @param slaveAddress 7-bit I²C address of the slave device. + * @param registerAddress Register address to read. + * @return Byte read from the register. + */ +char i2c_read_reg(uint8_t slaveAddress, uint8_t registerAddress) +{ + // Send register address first + char addr_buf[1] = { (char)registerAddress }; + i2c_write(slaveAddress, addr_buf, 1); + + // Switch to master-receive mode and request one byte + UCB0CTLW0 &= ~UCTR; + UCB0TBCNT = 1; + + // Generate repeated START condition + UCB0CTLW0 |= UCTXSTT; + + i2c_transfer_complete = false; + while (!i2c_transfer_complete) + { + LPM3; // Wait for ISR to clear STOP flag + } + + return i2c_rx_byte; +} + +/** + * @brief USCI_B0 I²C interrupt handler. + * + * Handles NACK, STOP, RX, and TX events: + * - NACK: terminate transfer and wake CPU + * - STOP: terminate transfer and wake CPU + * - RXBUF: store received byte + * - TXBUF: send next byte or reset index */ #pragma vector = EUSCI_B0_VECTOR __interrupt void EUSCI_B0_I2C_ISR(void) @@ -119,31 +143,34 @@ __interrupt void EUSCI_B0_I2C_ISR(void) switch (__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG)) { case USCI_I2C_UCNACKIFG: - // NACK → CPU aufwecken (LPM3 verlassen) - i2cDone = true; + // NACK received: signal completion and wake CPU + i2c_transfer_complete = true; __bic_SR_register_on_exit(LPM3_bits); break; case USCI_I2C_UCSTPIFG: - // STOP → CPU aufwecken (LPM3 verlassen) - i2cDone = true; + // STOP condition detected: signal completion and wake CPU + i2c_transfer_complete = true; __bic_SR_register_on_exit(LPM3_bits); break; case USCI_I2C_UCRXIFG0: - // Empfangenes Byte speichern - dataIn = UCB0RXBUF; + // Read received byte into buffer + i2c_rx_byte = UCB0RXBUF; break; case USCI_I2C_UCTXIFG0: - // Nächstes Datenbyte senden oder Übertragung beenden - UCB0TXBUF = packet[dataCount++]; - if (dataCount >= packetLength) - dataCount = 0; // Für nächste Transaktion zurücksetzen + // Transmit next byte or reset index if done + UCB0TXBUF = i2c_tx_buffer[i2c_tx_index++]; + if (i2c_tx_index >= i2c_tx_length) + { + // Reset index for subsequent transactions + i2c_tx_index = 0; + } break; default: - // Unbehandelter Vektor – nichts zu tun + // Unhandled interrupts: no action break; } -} \ No newline at end of file +} diff --git a/src/i2c.h b/src/i2c.h index f74dfc6..4d95a85 100644 --- a/src/i2c.h +++ b/src/i2c.h @@ -19,7 +19,7 @@ #include /** - * @brief Initialize the I2C module as master (SMCLK/20 → 50 kHz SCL). + * @brief Initialize the I2C module as master. */ void i2c_init(void); diff --git a/src/keypad.c b/src/keypad.c index 0570bbc..9968eb4 100644 --- a/src/keypad.c +++ b/src/keypad.c @@ -13,7 +13,7 @@ * - Wait for key release and debounce * - Clear flags and re-enable column interrupts * - * @author + * @author Frederik Beimgraben * @date 2025-07-02 */ diff --git a/src/keypad.h b/src/keypad.h index d391715..ebd1260 100644 --- a/src/keypad.h +++ b/src/keypad.h @@ -5,10 +5,7 @@ * * Interrupt-driven scanning with callback on key press. * - * @authors - * Frederik Beimgraben - * Minh Dan Cam - * Luis Meyer + * @author Frederik Beimgraben * @date 2025-07-02 */ diff --git a/src/lcd.c b/src/lcd.c index 8b73843..422dc88 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -1,34 +1,65 @@ +/** + * \file lcd.c + * \brief I2C-based LCD driver for MSP430FR2355. + * + * This module provides initialization and basic control functions + * for a character LCD connected via an I2C expander. It supports + * 4-bit communication mode and includes routines for sending commands + * and data to the display. + */ + #include "lcd.h" -#include "i2c.h" /* Ihr I²C-Master-Treiber */ -#include /* für __delay_cycles() */ +#include "i2c.h" /**< I²C master driver */ +#include /**< MSP430 definitions for __delay_cycles() */ #include -/* --- Interne Helfer: sendet eine 4-Bit-Halbnibble plus Control-Bits --- */ +/** + * \brief Send a 4-bit nibble with control flags over I2C to the LCD. + * + * This helper composes a byte containing the nibble (in the high 4 bits), + * the control signals (RS, RW, EN), and the backlight bit, then toggles + * the enable line to latch the data. + * + * \param nibble 4-bit data to send (lower nibble used). + * \param control Control flags (e.g., RS, R/W). + */ static void lcd_write_nibble(uint8_t nibble, uint8_t control) { char buf[1]; - /* High-Nibble in die oberen 4 Bits */ - buf[0] = (nibble << 4) | control | LCD_BACKLIGHT; - /* EN=1 */ + /* High nibble placed in upper data bits, include control and backlight */ + buf[0] = (uint8_t)((nibble << 4) | control | LCD_BACKLIGHT); + /* Pulse EN high */ i2c_write(LCD_I2C_ADDR, buf, 1); buf[0] |= LCD_ENABLE; i2c_write(LCD_I2C_ADDR, buf, 1); - __delay_cycles(500); /* ca. 50 µs @ 1 MHz */ - /* EN=0 */ - buf[0] &= ~LCD_ENABLE; + __delay_cycles(500); /**< ~50µs at 1MHz */ + /* EN low */ + buf[0] &= (char)~LCD_ENABLE; i2c_write(LCD_I2C_ADDR, buf, 1); __delay_cycles(500); } -/* Sendet ein volles Byte (2×4-Bit) als Befehl (RS=0) */ +/** + * \brief Send an 8-bit command to the LCD. + * + * Splits the command into two 4-bit nibbles and sends each with RS=0. + * + * \param cmd Command byte to send. + */ static void lcd_send_cmd(uint8_t cmd) { lcd_write_nibble(cmd >> 4, 0x00); lcd_write_nibble(cmd & 0x0F, 0x00); } -/* Sendet ein volles Byte als Daten (RS=1) */ +/** + * \brief Send an 8-bit data value (character) to the LCD. + * + * Splits the data into two 4-bit nibbles and sends each with RS=1. + * + * \param data Data byte (character) to display. + */ static void lcd_send_data(uint8_t data) { lcd_write_nibble(data >> 4, LCD_RS); @@ -37,10 +68,10 @@ static void lcd_send_data(uint8_t data) void lcd_init(void) { - /* Wartezeit nach Power-Up */ - __delay_cycles(50000); /* ca. 50 ms */ + /* Delay for LCD power-up (approx. 50 ms) */ + __delay_cycles(50000); - /* Initial­sequenz 8-Bit-Befehle (3×) */ + /* Initialization sequence in 8-bit mode: 3 pulses */ lcd_write_nibble(0x03, 0x00); __delay_cycles(20000); lcd_write_nibble(0x03, 0x00); @@ -48,37 +79,57 @@ void lcd_init(void) lcd_write_nibble(0x03, 0x00); __delay_cycles(2000); - /* In 4-Bit-Modus schalten */ + /* Switch to 4-bit mode */ lcd_write_nibble(0x02, 0x00); __delay_cycles(2000); - /* Funktion: 4-Bit, 2 Zeilen, 5×8 Punkte */ + /* Function set: 4-bit, 2 lines, 5x8 dots */ lcd_send_cmd(0x28); /* Display off */ lcd_send_cmd(0x08); - /* Clear */ + /* Clear display */ lcd_send_cmd(0x01); __delay_cycles(2000); - /* Entry mode: Cursor++ */ + /* Entry mode set: increment cursor */ lcd_send_cmd(0x06); - /* Display on, Cursor off, Blink off */ + /* Display on, cursor off, blink off */ lcd_send_cmd(0x0C); } void lcd_clear(void) { + /** + * \brief Clear display and reset cursor. + * + * Sends the clear command and waits for the LCD to process it. + */ lcd_send_cmd(0x01); __delay_cycles(2000); } void lcd_set_cursor(uint8_t row, uint8_t col) { + /** + * \brief Set cursor to specified position. + * + * Calculates the DDRAM address based on row and column. + * + * \param row Row index (0 or 1). + * \param col Column index (0-15). + */ uint8_t addr = (row == 0 ? 0x00 : 0x40) + (col & 0x0F); lcd_send_cmd(0x80 | addr); } void lcd_print(const char *str) { + /** + * \brief Print a null-terminated string to the LCD. + * + * Iterates through the string and sends each character as data. + * + * \param str Pointer to a null-terminated C string. + */ while (*str) { lcd_send_data((uint8_t)*str++); diff --git a/src/state_machine.h b/src/state_machine.h index b18f493..5372897 100644 --- a/src/state_machine.h +++ b/src/state_machine.h @@ -6,9 +6,10 @@ * This module drives a keypad‐and‐LCD UI to select beverage types (A–D), * choose quantities, confirm orders, detect door events, and edit stock levels. * - * @author Frederik Beimgraben - * @author Minh Dan Cam - * @author Luis Meyer + * @authors + * Frederik Beimgraben + * Minh Dan Cam + * Luis Meyer * @date 2025-07-03 */ diff --git a/src/timer.c b/src/timer.c index 10950cc..3a9ba78 100644 --- a/src/timer.c +++ b/src/timer.c @@ -1,41 +1,70 @@ +/** + * \file timer.c + * \brief MSP430 Timer B driver and blocking delay implementation. + * + * This module provides a millisecond-level blocking delay function using + * low-power mode and global interrupts, as well as initialization for Timer B + * in up mode to generate periodic 1ms interrupts. + */ + #include #include #include #include "timer.h" /** - * @brief Führt eine blockierende Wartezeit aus. - * @param ms Zeit in Millisekunden + * \brief Block execution for a given number of milliseconds. + * + * Implements a blocking delay by entering LPM0 and waking up via the + * Timer interrupt on each millisecond tick. + * + * \param ms Number of milliseconds to delay. */ void sleep(uint16_t ms) { while (ms--) { + /* Enter low-power mode 0 with interrupts enabled */ __bis_SR_register(LPM0_bits + GIE); + /* No operation, wait for interrupt */ __no_operation(); } } +/** + * \brief Initialize Timer B0 in up mode to generate 1ms period interrupts. + * + * Configures Timer B0 to use SMCLK, no divider, and a period of 999 ticks + * to achieve a 1ms overflow (assuming 1MHz SMCLK). Enables CCR0 interrupt + * to exit low-power mode on each tick. + */ void init_timer(void) { static Timer_B_initUpModeParam param = {0}; + /* Select SMCLK as clock source */ param.clockSource = TIMER_B_CLOCKSOURCE_SMCLK; + /* No division: tick = 1MHz / 1 = 1MHz */ param.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_1; - param.timerPeriod = 999; // wenn 1000 Taktimpulse gezählt - // wurden, erfolgt ein Interrupt - // Periodendauer somit 1ms - param.timerInterruptEnable_TBIE = - TIMER_B_TBIE_INTERRUPT_DISABLE; // no interrupt on 0x0000 + /* Period = 999 -> interrupt every 1000 ticks => 1ms */ + param.timerPeriod = 999; + /* Disable interrupt on timer rollover (TBIE) */ + param.timerInterruptEnable_TBIE = TIMER_B_TBIE_INTERRUPT_DISABLE; + /* Enable CCR0 interrupt on timer compare match */ param.captureCompareInterruptEnable_CCR0_CCIE = - TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE; // interrupt on TRmax + TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE; + /* Clear timer and start immediately */ param.timerClear = TIMER_B_DO_CLEAR; param.startTimer = true; - // start Timer: + /* Initialize and start Timer B0 in up mode */ Timer_B_initUpMode(TB0_BASE, ¶m); } -// TimerB0 Interrupt Vector (TBxIV) handler +/** + * \brief ISR for Timer0_B0 (CCR0) comparison event. + * + * Exits low-power mode 0 to resume the sleeping function. + */ #pragma vector=TIMER0_B0_VECTOR -__interrupt void TIMER0_B0_ISR(void) -{ +__interrupt void TIMER0_B0_ISR(void) { + /* Clear LPM0 bits on exit to wake up CPU */ __bic_SR_register_on_exit(LPM0_bits); } diff --git a/src/timer.h b/src/timer.h index 703f61e..b60dbad 100644 --- a/src/timer.h +++ b/src/timer.h @@ -1,7 +1,31 @@ +/** + * \file timer.h + * \brief Interface for millisecond delay and Timer B initialization on MSP430. + * + * This header declares functions for creating a blocking delay using low-power + * mode and for initializing Timer B0 in up mode to generate periodic 1ms interrupts. + */ + #ifndef TIMER_H #define TIMER_H +/** + * \brief Block execution for a specified number of milliseconds. + * + * This function enters low-power mode 0 (LPM0) and wakes on each + * Timer B CCR0 interrupt to achieve an approximate millisecond delay. + * + * \param ms Number of milliseconds to sleep. + */ void sleep(uint16_t ms); + +/** + * \brief Initialize Timer B0 to generate 1ms interrupts. + * + * Configures Timer B0 with SMCLK as the clock source, no divider, + * and a period of 999 ticks (for a 1MHz clock) to create a 1ms interval. + * Enables CCR0 compare interrupt to wake from low-power mode on each tick. + */ void init_timer(void); -#endif // TIMER_H \ No newline at end of file +#endif // TIMER_H