Command handing works!

The command handler can now receive a command, then it can run a
function / return some data based on it.
This commit is contained in:
Sebastian H. Gabrielli 2024-04-16 15:30:38 +02:00
parent 8e3607cbda
commit 9fd877aab5
6 changed files with 122 additions and 65 deletions

View File

@ -1,9 +1,10 @@
#include "command-handler.h" #include "command-handler.h"
command_context_t parse_command(uint8_t *command, uint8_t command_len) { // Initialize empty, global command context
// Create the context volatile command_context_t context = {UNKNOWN_COMMAND, SRC_NONE, FAN_NONE,
command_context_t context; CNF_NONE};
void parse_command(uint8_t command[], uint8_t command_len) {
/////////////////////// ///////////////////////
// Command selection // // Command selection //
/////////////////////// ///////////////////////
@ -11,11 +12,12 @@ command_context_t parse_command(uint8_t *command, uint8_t command_len) {
// Validate that we have a command // Validate that we have a command
if (command_len < 1) { if (command_len < 1) {
context.command = UNKNOWN_COMMAND; context.command = UNKNOWN_COMMAND;
return context;
} }
uint8_t foo = command[0];
// Figure out which command to run // Figure out which command to run
switch (command[0]) { switch (foo) {
case 0x11: // Read config case 0x11: // Read config
context.command = READ_CONFIG; context.command = READ_CONFIG;
break; 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. // Check if the command does not require a parameter. If it does not, return.
if (context.command == READ_TERMPERATURE) { if (context.command == READ_TERMPERATURE) {
return context; return;
} }
// Validate that we have a first parameter, else requirements for command are // Validate that we have a first parameter, else requirements for command are
// not fulfilled. return unknown command. // not fulfilled. return unknown command.
if (command_len < 2) { if (command_len < 2) {
context.command = UNKNOWN_COMMAND; context.command = UNKNOWN_COMMAND;
return context; return;
} }
// Store the parameter // 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, // Check if the command does not require a second parameter. If it does not,
// return. Only config write requires a second parameter. // return. Only config write requires a second parameter.
if (context.command != WRITE_CONFIG) { if (context.command != WRITE_CONFIG) {
return context; return;
} }
// Validate that we have a first parameter, else requirements for command are // Validate that we have a first parameter, else requirements for command are
// not fulfilled. return unknown command. // not fulfilled. return unknown command.
if (command_len < 3) { if (command_len < 3) {
context.command = UNKNOWN_COMMAND; context.command = UNKNOWN_COMMAND;
return context; return;
} }
// Store the parameter // Store the parameter
@ -124,8 +126,32 @@ command_context_t parse_command(uint8_t *command, uint8_t command_len) {
// TODO: Handle the config parameters // TODO: Handle the config parameters
// Return the context // exit
return context; 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;
}
}

View File

@ -12,6 +12,7 @@
extern "C" { extern "C" {
#endif #endif
#include <avr/io.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -59,10 +60,10 @@ typedef struct {
} command_context_t; } command_context_t;
// Parses the input string and outputs one of the valid commands // 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 // Routes the provided command to the appropriate function to handle it
void route_command(command_context_t command); uint8_t route_command();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,9 +1,17 @@
#include "i2c.h" #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 // We need to keep track of if the stop confition is in regards to a write or
volatile uint8_t i2c_recv_len; // 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) { void init_i2c(void) {
// Pin setup // Pin setup
@ -44,23 +52,33 @@ void i2c_reset_recv() {
} }
void i2c_write_handler(uint8_t data) { void i2c_write_handler(uint8_t data) {
last_action_write = true;
i2c_recv[i2c_recv_len] = data; i2c_recv[i2c_recv_len] = data;
i2c_recv_len++; i2c_recv_len++;
} }
void i2c_read_handler() { void i2c_read_handler() {
printf("Master wanted to read.\n"); last_action_write = false;
TWI0.SDATA = route_command();
} }
void i2c_stop_handler() { void i2c_stop_handler() {
// Reset counter and clear receive buffer if (last_action_write) {
i2c_recv[i2c_recv_len] = '\0'; // Parse the received command data
printf("%s\n", i2c_recv); parse_command(i2c_recv, i2c_recv_len);
} else {
// route_command();
;
}
// Reset the buffer for future transmissions
i2c_reset_recv(); i2c_reset_recv();
} }
// Address received // Address received
ISR(TWI0_TWIS_vect) { ISR(TWI0_TWIS_vect) {
// Disable interrupts while handling I2C
cli();
// Check for the data interrupt flag // Check for the data interrupt flag
if (TWI0.SSTATUS & TWI_DIF_bm) { if (TWI0.SSTATUS & TWI_DIF_bm) {
uint8_t data = 0; uint8_t data = 0;
@ -74,7 +92,8 @@ ISR(TWI0_TWIS_vect) {
} else { } else {
// Data read Master <- Slave // Data read Master <- Slave
i2c_read_handler(); i2c_read_handler();
data = TWI0.SDATA; // data = TWI0.SDATA;
// TWI0.SDATA = 1;
} }
// Acknowledge having received // Acknowledge having received
@ -94,4 +113,7 @@ ISR(TWI0_TWIS_vect) {
TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc; TWI0.SCTRLB = TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc;
} }
} }
// Re-enable interrupts
sei();
} }

View File

@ -13,9 +13,11 @@ extern "C" {
#endif #endif
// Include the IO for I2C // Include the IO for I2C
#include <avr/io.h> #include "command-handler.h"
#include <avr/interrupt.h>
#include "uart.h" #include "uart.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdbool.h>
#include <util/twi.h> #include <util/twi.h>
// Received data info // Received data info

View File

@ -11,17 +11,20 @@
#include <stdlib.h> #include <stdlib.h>
#include "uart.h" #include "uart.h"
#include "i2c.h" #include "i2c.h"
#include "command-handler.h"
#include <util/delay.h> #include <util/delay.h>
#include <avr/io.h>
int main() { int main() {
init_uart((uint16_t)9600); init_uart((uint16_t)9600);
init_i2c(); init_i2c();
stdout = &USART_stream; stdout = &USART_stream;
PORTB.DIRSET = PIN3_bm;
sei(); sei();
while (1) { while (1) {
printf("\n"); ;
_delay_ms(500);
} }
} }

View File

@ -149,6 +149,9 @@
<property key="program-the-device-with-default-config-words" value="false"/> <property key="program-the-device-with-default-config-words" value="false"/>
<property key="remove-unused-sections" value="true"/> <property key="remove-unused-sections" value="true"/>
</HI-TECH-LINK> </HI-TECH-LINK>
<Tool>
<property key="debugoptions.useswbreakpoints" value="true"/>
</Tool>
<XC8-CO> <XC8-CO>
<property key="coverage-enable" value=""/> <property key="coverage-enable" value=""/>
<property key="stack-guidance" value="false"/> <property key="stack-guidance" value="false"/>