From 9fd877aab525364bb29c7433331c6ea8d82ff3ac Mon Sep 17 00:00:00 2001 From: "Sebastian H. Gabrielli" Date: Tue, 16 Apr 2024 15:30:38 +0200 Subject: [PATCH] Command handing works! The command handler can now receive a command, then it can run a function / return some data based on it. --- prosjekt.X/command-handler.c | 50 ++++++++--- prosjekt.X/command-handler.h | 5 +- prosjekt.X/i2c.c | 114 ++++++++++++++---------- prosjekt.X/i2c.h | 8 +- prosjekt.X/main.c | 7 +- prosjekt.X/nbproject/configurations.xml | 3 + 6 files changed, 122 insertions(+), 65 deletions(-) diff --git a/prosjekt.X/command-handler.c b/prosjekt.X/command-handler.c index 75d91d1..cb485ba 100644 --- a/prosjekt.X/command-handler.c +++ b/prosjekt.X/command-handler.c @@ -1,9 +1,10 @@ #include "command-handler.h" -command_context_t parse_command(uint8_t *command, uint8_t command_len) { - // Create the context - command_context_t context; +// Initialize empty, global command context +volatile command_context_t context = {UNKNOWN_COMMAND, SRC_NONE, FAN_NONE, + CNF_NONE}; +void parse_command(uint8_t command[], uint8_t command_len) { /////////////////////// // Command selection // /////////////////////// @@ -11,11 +12,12 @@ command_context_t parse_command(uint8_t *command, uint8_t command_len) { // Validate that we have a command if (command_len < 1) { context.command = UNKNOWN_COMMAND; - return context; } + uint8_t foo = command[0]; + // Figure out which command to run - switch (command[0]) { + switch (foo) { case 0x11: // Read config context.command = READ_CONFIG; break; @@ -48,14 +50,14 @@ command_context_t parse_command(uint8_t *command, uint8_t command_len) { // Check if the command does not require a parameter. If it does not, return. if (context.command == READ_TERMPERATURE) { - return context; + return; } // Validate that we have a first parameter, else requirements for command are // not fulfilled. return unknown command. if (command_len < 2) { context.command = UNKNOWN_COMMAND; - return context; + return; } // Store the parameter @@ -109,14 +111,14 @@ command_context_t parse_command(uint8_t *command, uint8_t command_len) { // Check if the command does not require a second parameter. If it does not, // return. Only config write requires a second parameter. if (context.command != WRITE_CONFIG) { - return context; + return; } // Validate that we have a first parameter, else requirements for command are // not fulfilled. return unknown command. if (command_len < 3) { context.command = UNKNOWN_COMMAND; - return context; + return; } // Store the parameter @@ -124,8 +126,32 @@ command_context_t parse_command(uint8_t *command, uint8_t command_len) { // TODO: Handle the config parameters - // Return the context - return context; + // exit + return; } -void route_command(command_context_t command); +uint8_t route_command() { + switch (context.command) { + WRITE_CONFIG: + return WRITE_CONFIG; + break; + READ_CONFIG: + return READ_CONFIG; + break; + READ_VOLTAGE: + return READ_VOLTAGE; + break; + READ_TERMPERATURE: + return READ_TERMPERATURE; + break; + READ_FAN_SPEED: + return READ_FAN_SPEED; + break; + CLEAR_BULK_FAN_SPEED: + return CLEAR_BULK_FAN_SPEED; + break; + UNKNOWN_COMMAND: + return 0xFF; + break; + } +} diff --git a/prosjekt.X/command-handler.h b/prosjekt.X/command-handler.h index d59305a..dd87e15 100644 --- a/prosjekt.X/command-handler.h +++ b/prosjekt.X/command-handler.h @@ -12,6 +12,7 @@ extern "C" { #endif +#include #include #include @@ -59,10 +60,10 @@ typedef struct { } command_context_t; // Parses the input string and outputs one of the valid commands -command_context_t parse_command(uint8_t *command, uint8_t command_len); +void parse_command(uint8_t *command, uint8_t command_len); // Routes the provided command to the appropriate function to handle it -void route_command(command_context_t command); +uint8_t route_command(); #ifdef __cplusplus } diff --git a/prosjekt.X/i2c.c b/prosjekt.X/i2c.c index 75cdb5f..278f689 100644 --- a/prosjekt.X/i2c.c +++ b/prosjekt.X/i2c.c @@ -1,18 +1,26 @@ #include "i2c.h" +#include "command-handler.h" -// Basic I2C handling structure is heavily inspired by: https://github.com/microchip-pic-avr-examples/avr128db48-bare-metal-twi-mplab/blob/master/twi-client.X/peripherals/TWI/TWI_client.c +// Basic I2C handling structure is heavily inspired by: +// https://github.com/microchip-pic-avr-examples/avr128db48-bare-metal-twi-mplab/blob/master/twi-client.X/peripherals/TWI/TWI_client.c -volatile uint8_t i2c_recv[I2C_RECV_BUF_SIZE]; // Arbitrary length array to hold the received data, longer than max expected command -volatile uint8_t i2c_recv_len; +// We need to keep track of if the stop confition is in regards to a write or +// read request +volatile bool last_action_write = false; + +volatile uint8_t i2c_recv[I2C_RECV_BUF_SIZE] = { + 0}; // Arbitrary length array to hold the received + // data, longer than max expected command +volatile uint8_t i2c_recv_len = 0; void init_i2c(void) { // Pin setup PORTA.DIRSET = PIN2_bm | PIN3_bm; PORTA.PINCTRLUPD = PIN2_bm | PIN3_bm; - + // Enable operating in debug TWI0.DBGCTRL = TWI_DBGRUN_bm; - + // Initialize the control A register TWI0.CTRLA = TWI_INPUTLVL_I2C_gc // I2C voltage transition level | TWI_SDASETUP_4CYC_gc // Four clock cycles setup time @@ -30,7 +38,7 @@ void init_i2c(void) { | PIN2_bm // Respond to all TWI addresses | TWI_ENABLE_bm // Enable acting as a slave ; - + // Reset the received stuff i2c_reset_recv(); } @@ -39,59 +47,73 @@ void init_i2c(void) { void i2c_reset_recv() { i2c_recv_len = 0; for (int i = 0; i < I2C_RECV_BUF_SIZE; i++) { - i2c_recv[i] = 0; + i2c_recv[i] = 0; } } void i2c_write_handler(uint8_t data) { - i2c_recv[i2c_recv_len] = data; - i2c_recv_len++; + last_action_write = true; + i2c_recv[i2c_recv_len] = data; + i2c_recv_len++; } void i2c_read_handler() { - printf("Master wanted to read.\n"); + last_action_write = false; + TWI0.SDATA = route_command(); } void i2c_stop_handler() { - // Reset counter and clear receive buffer - i2c_recv[i2c_recv_len] = '\0'; - printf("%s\n", i2c_recv); - i2c_reset_recv(); + if (last_action_write) { + // Parse the received command data + parse_command(i2c_recv, i2c_recv_len); + } else { + // route_command(); + ; + } + // Reset the buffer for future transmissions + i2c_reset_recv(); } // Address received ISR(TWI0_TWIS_vect) { - // Check for the data interrupt flag - if (TWI0.SSTATUS & TWI_DIF_bm) { - uint8_t data = 0; - - if ( ((TWI0.SSTATUS & TWI_DIR_bm) >> TWI_DIR_bp) == 0 ) { - // Data write Master -> Slave - data = TWI0.SDATA; - - // Send the data to the write handler - i2c_write_handler(data); - } else { - // Data read Master <- Slave - i2c_read_handler(); - data = TWI0.SDATA; - } - - // Acknowledge having received - TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc; + // Disable interrupts while handling I2C + cli(); + + // Check for the data interrupt flag + if (TWI0.SSTATUS & TWI_DIF_bm) { + uint8_t data = 0; + + if (((TWI0.SSTATUS & TWI_DIR_bm) >> TWI_DIR_bp) == 0) { + // Data write Master -> Slave + data = TWI0.SDATA; + + // Send the data to the write handler + i2c_write_handler(data); + } else { + // Data read Master <- Slave + i2c_read_handler(); + // data = TWI0.SDATA; + // TWI0.SDATA = 1; } - - // Check for address match or STOP - if (TWI0.SSTATUS & TWI_APIF_bm) { - - if (TWI0.SSTATUS & TWI_AP_ADR_gc) { - // Address match, just send ack - TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc; - } else { - // STOP condition received - i2c_stop_handler(); - // Send ACK - TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc; - } + + // Acknowledge having received + TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc; + } + + // Check for address match or STOP + if (TWI0.SSTATUS & TWI_APIF_bm) { + + if (TWI0.SSTATUS & TWI_AP_ADR_gc) { + // Address match, just send ack + TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc; + } else { + // STOP condition received + i2c_stop_handler(); + // Send ACK + TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc; } -} \ No newline at end of file + } + + // Re-enable interrupts + sei(); +} diff --git a/prosjekt.X/i2c.h b/prosjekt.X/i2c.h index 6b4214c..342f459 100644 --- a/prosjekt.X/i2c.h +++ b/prosjekt.X/i2c.h @@ -13,13 +13,15 @@ extern "C" { #endif // Include the IO for I2C -#include -#include +#include "command-handler.h" #include "uart.h" +#include +#include +#include #include // Received data info -#define I2C_RECV_BUF_SIZE 64 +#define I2C_RECV_BUF_SIZE 64 // Reset recv to initial state void i2c_reset_recv(); diff --git a/prosjekt.X/main.c b/prosjekt.X/main.c index 25f1319..fb95de5 100644 --- a/prosjekt.X/main.c +++ b/prosjekt.X/main.c @@ -11,17 +11,20 @@ #include #include "uart.h" #include "i2c.h" +#include "command-handler.h" #include +#include int main() { init_uart((uint16_t)9600); init_i2c(); stdout = &USART_stream; + PORTB.DIRSET = PIN3_bm; + sei(); while (1) { - printf("\n"); - _delay_ms(500); + ; } } \ No newline at end of file diff --git a/prosjekt.X/nbproject/configurations.xml b/prosjekt.X/nbproject/configurations.xml index 528acb5..e65594c 100644 --- a/prosjekt.X/nbproject/configurations.xml +++ b/prosjekt.X/nbproject/configurations.xml @@ -149,6 +149,9 @@ + + +