Compare commits

..

No commits in common. "495cbbba44991104599e0698b8b7418f5716fe33" and "e6a3815dc2c8cb7f7e73b4efea9c16760a3a8cbe" have entirely different histories.

8 changed files with 147 additions and 230 deletions

View File

@ -54,7 +54,7 @@ void parse_command(uint8_t command[], uint8_t command_len) {
return; return;
} }
// Validate that we have a second 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;
@ -69,11 +69,7 @@ void parse_command(uint8_t command[], uint8_t command_len) {
// Configuration parameters // Configuration parameters
case 0x11: // Read config case 0x11: // Read config
case 0x21: // Write config case 0x21: // Write config
if (param == 0x01) { // TODO: Handle parameters for config
context.conf = SAMPLE_TIME;
} else {
context.conf = CNF_NONE;
}
break; break;
// Voltage parameters // Voltage parameters
@ -93,6 +89,7 @@ void parse_command(uint8_t command[], uint8_t command_len) {
case 0x14: // Read current fan speed case 0x14: // Read current fan speed
case 0x15: // Read bulk fan speed case 0x15: // Read bulk fan speed
case 0x22: // Clear stored fan speed data case 0x22: // Clear stored fan speed data
context.command = READ_BULK_FAN_SPEED;
if (param == 0x01) { if (param == 0x01) {
context.fan = FAN1; context.fan = FAN1;
} else if (param == 0x02) { } else if (param == 0x02) {
@ -108,9 +105,9 @@ void parse_command(uint8_t command[], uint8_t command_len) {
break; break;
} }
///////////////////////////////// ////////////////////////////////
// Third parameter selection // // Second parameter selection //
///////////////////////////////// ////////////////////////////////
// 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.
@ -118,7 +115,7 @@ void parse_command(uint8_t command[], uint8_t command_len) {
return; return;
} }
// Validate that we have a third 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;
@ -128,31 +125,7 @@ void parse_command(uint8_t command[], uint8_t command_len) {
// Store the parameter // Store the parameter
param = command[2]; param = command[2];
context.conf = param; // TODO: Handle the config parameters
////////////////////////////////
// Fourth parameter selection //
////////////////////////////////
// Validate that we have a fourth parameter, else requirements for command are
// not fulfilled. return unknown command. Second parameter is u16, thus two bytes.
if (command_len < 4) {
context.command = UNKNOWN_COMMAND;
return;
}
// Extract the value
union {
uint16_t value;
uint8_t bytes[2];
} config_value;
config_value.bytes[0] = command[3];
config_value.bytes[1] = command[4];
// Store the value
context.conf_val = config_value.value;
// exit // exit
return; return;
@ -160,107 +133,26 @@ void parse_command(uint8_t command[], uint8_t command_len) {
uint8_t route_command(int pos) { uint8_t route_command(int pos) {
switch (context.command) { switch (context.command) {
case WRITE_CONFIG: WRITE_CONFIG:
switch (context.conf) { return WRITE_CONFIG;
case SAMPLE_TIME:
// Overwrite the config value
config.ms_fanspeed_sample_rate = context.conf_val;
// Set the flag to store it in the EEPROM
store_config = true;
break; break;
} READ_CONFIG:
return READ_CONFIG;
break; break;
case READ_CONFIG: READ_VOLTAGE:
{ return READ_VOLTAGE;
switch (context.conf) {
case SAMPLE_TIME:
{
// Validate that pos is within the valid range
if (pos >= 2) { return 0x00; }
// Config only has one parameter so we sent that parameter
// Create a union to store the data
union {
uint16_t value;
uint8_t bytes[2];
} config_value;
config_value.value = config.ms_fanspeed_sample_rate;
// Return the corresponding data byte
return config_value.bytes[1-pos];
}
break; break;
} READ_TERMPERATURE:
} return READ_TERMPERATURE;
break; break;
READ_FAN_SPEED:
case READ_VOLTAGE: return READ_FAN_SPEED;
{
// Create a union to store the data
union {
int16_t v;
uint8_t bytes[2];
} voltage;
// Figure out which voltage source to read
switch (context.src_voltage) {
case SRC_INTERNAL:
voltage.v = internal_voltage_read();
break; break;
case SRC_EXTRNAL: CLEAR_BULK_FAN_SPEED:
voltage.v = external_voltage_read(); return CLEAR_BULK_FAN_SPEED;
break; break;
case SRC_THERMISTOR: UNKNOWN_COMMAND:
voltage.v = thermistor_voltage_read();
break;
default:
return 0xFF; return 0xFF;
break; break;
} }
// Send the data
return voltage.bytes[pos];
}
case READ_TERMPERATURE:
{
uint16_t v_therm = thermistor_voltage_read();
union {
int16_t temp;
uint8_t bytes[2];
} temperature;
temperature.temp = (int16_t) ( calculate_thermistor_temp(v_therm) * 1000 );
return temperature.bytes[pos];
}
break;
case READ_FAN_SPEED:
if (context.fan == FAN1) {
return fan1_history[0];
} else if (context.fan == FAN2) {
return fan2_history[0];
} else {
return 0;
}
break;
case READ_BULK_FAN_SPEED:
if (context.fan == FAN1) {
return fan1_history[pos];
} else if (context.fan == FAN2) {
return fan2_history[pos];
} else {
return 0;
}
break;
case CLEAR_BULK_FAN_SPEED:
// Overwrite the content of the desired fan array with zeroes
if (context.fan == FAN1) {
memset(fan1_history, 0, sizeof(fan1_history));
} else if (context.fan == FAN2) {
memset(fan2_history, 0, sizeof(fan2_history));
}
break;
case UNKNOWN_COMMAND:
default:
return 0xFF;
}
} }

View File

@ -12,22 +12,19 @@
extern "C" { extern "C" {
#endif #endif
#include "eeprom.h"
#include <avr/io.h> #include <avr/io.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "voltage.h"
#include "themistor-temp.h"
// Enum of all valid command types // Enum of all valid command types
typedef enum { typedef enum {
WRITE_CONFIG = 0x21, // Change the configuration WRITE_CONFIG, // Change the configuration
READ_CONFIG = 0x11, // Read, and print the current configuration READ_CONFIG, // Read, and print the current configuration
READ_VOLTAGE = 0x12, // Read, and print a voltage READ_VOLTAGE, // Read, and print a voltage
READ_TERMPERATURE = 0x13, // Read, and print the temperature READ_TERMPERATURE, // Read, and print the temperature
READ_FAN_SPEED = 0x14, // Read, and print the current fan speed READ_FAN_SPEED, // Read, and print the current fan speed
READ_BULK_FAN_SPEED = 0x15, // Read, and print the stored back fan speed data READ_BULK_FAN_SPEED, // Read, and print the stored back fan speed data
CLEAR_BULK_FAN_SPEED = 0x22, // Clear the buffer of stored fan speed data CLEAR_BULK_FAN_SPEED, // Clear the buffer of stored fan speed data
UNKNOWN_COMMAND // An unrecognized command has been sent UNKNOWN_COMMAND // An unrecognized command has been sent
} command_t; } command_t;
@ -42,15 +39,14 @@ typedef enum {
// Enum of all valid config options // Enum of all valid config options
// TODO: Move into config header file // TODO: Move into config header file
typedef enum { typedef enum {
SAMPLE_TIME = 0x01, // Time between each fan speed sample
CNF_NONE, // No config option CNF_NONE, // No config option
} config_option_t; } config_option_t;
// Enum of all valid fans // Enum of all valid fans
// TODO: Consider moving into it's own fan page // TODO: Consider moving into it's own fan page
typedef enum { typedef enum {
FAN1 = 1, // The first fan FAN1, // The first fan
FAN2 = 2, // The second fan FAN2, // The second fan
FAN_NONE // No fan FAN_NONE // No fan
} fans_t; } fans_t;
@ -60,17 +56,9 @@ typedef struct {
src_voltage_t src_voltage; // The selected voltage source src_voltage_t src_voltage; // The selected voltage source
fans_t fan; // The selected fan fans_t fan; // The selected fan
config_option_t conf; // The configuration option to cange config_option_t conf; // The configuration option to cange
uint16_t conf_val; // The value of the config option to change // TODO: Add config value field for writing
} command_context_t; } command_context_t;
// Fan history variables
extern volatile uint16_t fan1_history[512];
extern volatile uint16_t fan2_history[512];
// Config
extern volatile config_t config;
extern volatile bool store_config;
// Parses the input string and outputs one of the valid commands // Parses the input string and outputs one of the valid commands
void parse_command(uint8_t *command, uint8_t command_len); void parse_command(uint8_t *command, uint8_t command_len);

View File

@ -1,9 +1,17 @@
#include "eeprom.h" #include "eeprom.h"
// The start address for the controller data // The start address for the controller data
uint16_t EEMEM start_address_controller = 0x1400; uint8_t EEMEM start_address_controller = 0x00;
// Checks if the EEPROM memory is ready to be written in and waits until it is. // Where the writing of the fans points start
uint8_t EEMEM start_address_fan1 = 0x30;
uint8_t EEMEM start_address_fan2 = 0x60;
// The placement for the next datapoint form the fans.
uint8_t EEMEM current_address_fan1 = 0x30;
uint8_t EEMEM current_address_fan2 = 0x60;
// Checks if the EEPROM memory is ready to be written in.
void check_eeprom_is_ready(){ void check_eeprom_is_ready(){
while(1){ while(1){
if (eeprom_is_ready()){ if (eeprom_is_ready()){
@ -15,28 +23,77 @@ void check_eeprom_is_ready(){
} }
// Takes inn a struct by the form of config_t
// Checks if the eeprom is ready to be written in
// Checks if it has been written information at the address
// If true, the infromation is replaced with the intaken struct
// else the intaken struct is written at the address.
void write_struct_from_EEPROM(config_t write_struct){ void write_struct_from_EEPROM(config_t write_struct){
// Calculate the required storage size
uint8_t struct_size = sizeof(write_struct); uint8_t struct_size = sizeof(write_struct);
// Wait for the EEPROM to be ready
check_eeprom_is_ready(); check_eeprom_is_ready();
// Update the stored config stuct
eeprom_update_block((void*) &write_struct,(void*) &start_address_controller, struct_size); eeprom_update_block((void*) &write_struct,(void*) &start_address_controller, struct_size);
} }
// Reads the memory block at the address start_address_controller
// returns a struct in form of config_t
config_t read_struct_from_EEPROM(){ config_t read_struct_from_EEPROM(){
// Create a config struct to hold the received data //is eeprom ready??
config_t read_struct = { 0 }; config_t read_struct;
uint8_t struct_size = sizeof(read_struct); uint8_t struct_size = sizeof(read_struct);
// Wait for the EEPROM to be ready
check_eeprom_is_ready(); check_eeprom_is_ready();
// Read the data from the EEPROM
eeprom_read_block((void *) &read_struct,(void*) &start_address_controller, struct_size); eeprom_read_block((void *) &read_struct,(void*) &start_address_controller, struct_size);
// Return the data
return read_struct; return read_struct;
} }
// Takes inn a dataPoint and what data set it belongs to
// checks if EEPROM is ready
// If the dataset is 1, the datapoint is written at the address.
// If the dataset is 2 its written at another point.
int write_data_point_in_EEPROM(uint8_t byte, uint8_t fan_num){
check_eeprom_is_ready();
if (fan_num == 1){
eeprom_update_byte(current_address_fan1, byte);
current_address_fan1++;
return 1;
} else if (fan_num == 2){
eeprom_update_byte(current_address_fan2, byte);
current_address_fan2++;
return 1;
} else{
return 0;
}
}
// Reads all the datapoints to the choosen data.
// it writes the data points in the USART stream.
uint8_t read_data_point_speed_info(uint8_t fan_num, uint8_t *array){
uint8_t byte = 0;
if (fan_num == 1){
uint8_t len = current_address_fan1 - start_address_fan1;
check_eeprom_is_ready();
for (uint8_t i = 0; i <len; i++){
byte = eeprom_read_byte(i + start_address_fan1);
array[i] = byte;
printf("Fanspeed nr %u : %u", i, byte);
}
} else if (fan_num == 2){
uint8_t len = current_address_fan2 - start_address_fan2;
check_eeprom_is_ready();
for (uint8_t i = 0; i <len; i++){
byte = eeprom_read_byte(i + start_address_fan2);
array[i] = byte;
printf("Fanspeed nr %u : %u", i, byte);
}
}
return sizeof(array);
}

View File

@ -1,6 +1,6 @@
/* /*
* File: eeprom.h * File: eeprom.h
* Author: Helle Augland Grasmo, Sebastian H. Gabrielli * Author: Helle Augland Grasmo
* *
* Created on 06 March 2024, 15:30 * Created on 06 March 2024, 15:30
*/ */
@ -19,20 +19,28 @@ extern "C" {
#include <avr/eeprom.h> #include <avr/eeprom.h>
#include <stdbool.h> #include <stdbool.h>
// Struct for information on the controller. // Struct for information on the controller.
typedef struct { typedef struct {
uint16_t ms_fanspeed_sample_rate; uint8_t fanSpeed;
} config_t; } config_t;
// Check if EEPROM is ready to be written to // Check if EEPROM is ready to be written in
void check_eeprom_is_ready(); void check_eeprom_is_ready();
// Writes a config_t struct to the EEPROM // Writes a struct in EEPROM
void write_struct_from_EEPROM(config_t write_struct); void write_struct_from_EEPROM(config_t write_struct);
// Read data from EEPROM and return it as a config_t struct // Read data from EEPROM and return it as a controller struct
config_t read_struct_from_EEPROM(); config_t read_struct_from_EEPROM();
// Writes a datapoint in EEPROM
int write_data_point_from_EEPROM(uint8_t byte, uint8_t fan_num);
// Reads all the dataPoints form EEPROM
uint8_t read_data_point_speed_info(uint8_t fan_num, uint8_t *array);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -8,9 +8,9 @@
// read request // read request
volatile bool last_action_write = false; volatile bool last_action_write = false;
// Buffer to hold the received data volatile uint8_t i2c_recv[I2C_RECV_BUF_SIZE] = {
volatile uint8_t i2c_recv_buf[I2C_RECV_BUF_SIZE] = {0}; 0}; // Arbitrary length array to hold the received
// Counter to know which datapoint we're on // data, longer than max expected command
volatile uint8_t i2c_recv_len = 0; volatile uint8_t i2c_recv_len = 0;
void init_i2c(void) { void init_i2c(void) {
@ -47,18 +47,13 @@ void init_i2c(void) {
void i2c_reset_recv() { void i2c_reset_recv() {
i2c_recv_len = 0; i2c_recv_len = 0;
for (int i = 0; i < I2C_RECV_BUF_SIZE; i++) { for (int i = 0; i < I2C_RECV_BUF_SIZE; i++) {
i2c_recv_buf[i] = 0; i2c_recv[i] = 0;
} }
} }
void i2c_write_handler(uint8_t data) { void i2c_write_handler(uint8_t data) {
last_action_write = true; last_action_write = true;
i2c_recv[i2c_recv_len] = data;
// Validate that we are not overflowing the buffer
if (i2c_recv_len >= I2C_RECV_BUF_SIZE) { return; }
// Write the data to the receive buffer
i2c_recv_buf[i2c_recv_len] = data;
i2c_recv_len++; i2c_recv_len++;
} }
@ -71,14 +66,8 @@ void i2c_read_handler() {
void i2c_stop_handler() { void i2c_stop_handler() {
if (last_action_write) { if (last_action_write) {
// Parse the received command data // Parse the received command data
parse_command(i2c_recv_buf, i2c_recv_len); parse_command(i2c_recv, i2c_recv_len);
// If the received command is a write only command we want to route it now.
if (i2c_recv_buf[0] == CLEAR_BULK_FAN_SPEED || i2c_recv_buf[0] == WRITE_CONFIG) {
route_command(0);
} }
}
// Reset the buffer for future transmissions // Reset the buffer for future transmissions
i2c_reset_recv(); i2c_reset_recv();
} }
@ -90,16 +79,19 @@ ISR(TWI0_TWIS_vect) {
// 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;
if (((TWI0.SSTATUS & TWI_DIR_bm) >> TWI_DIR_bp) == 0) { if (((TWI0.SSTATUS & TWI_DIR_bm) >> TWI_DIR_bp) == 0) {
// Data write Controller -> Target // Data write Master -> Slave
uint8_t data = TWI0.SDATA; data = TWI0.SDATA;
// Send the data to the write handler // Send the data to the write handler
i2c_write_handler(data); i2c_write_handler(data);
} else { } else {
// Data read Controller <- Target // Data read Master <- Slave
i2c_read_handler(); i2c_read_handler();
// data = TWI0.SDATA;
// TWI0.SDATA = 1;
} }
// Acknowledge having received // Acknowledge having received

View File

@ -20,9 +20,8 @@ extern "C" {
#include <stdbool.h> #include <stdbool.h>
#include <util/twi.h> #include <util/twi.h>
// Received data buffer size // Received data info
// The size is larger than any expected command length #define I2C_RECV_BUF_SIZE 64
#define I2C_RECV_BUF_SIZE 16
// Reset recv to initial state // Reset recv to initial state
void i2c_reset_recv(); void i2c_reset_recv();

View File

@ -1,56 +1,40 @@
/* /*
* File: main.c * File: main.c
* Author: Sebastian H. Gabrielli, Helle Augland Grasmo, Ina Min Rørnes * Author: Sebastian H. Gabrielli, Helle Augland Grasmo
* *
* Created on March 6, 2024, 12:34 PM * Created on March 6, 2024, 12:34 PM
*/ */
#include <stdbool.h>
#include "uart.h" #include "uart.h"
#include "voltage.h" #include "voltage.h"
#define RTC_PERIOD (511) #define RTC_PERIOD (511)
#define DELAY_TIME 1000 #define DELAY_TIME 1000
#include "eeprom.h" #include "eeprom.h"
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define F_CPU 4E6 #define F_CPU 4E6
#include "command-handler.h" #include "command-handler.h"
#include "i2c.h" #include "i2c.h"
#include "themistor-temp.h"
#include "uart.h" #include "uart.h"
#include <avr/io.h> #include <avr/io.h>
#include <stdint.h>
#include <util/delay.h> #include <util/delay.h>
#include <stdint.h>
// Fan history variables #include "themistor-temp.h"
volatile uint16_t fan1_history[512] = { 0 };
volatile uint16_t fan2_history[512] = { 0 };
// Default config is 500ms sample rate
volatile config_t config = { 500 };
volatile bool store_config = false;
int main() { int main() {
// Initialize functionality
init_uart((uint16_t)9600); init_uart((uint16_t)9600);
ADC0_init();
init_led();
init_i2c(); init_i2c();
stdout = &USART_stream; stdout = &USART_stream;
// Read the stored config struct
config = read_struct_from_EEPROM();
PORTB.DIRSET = PIN3_bm; PORTB.DIRSET = PIN3_bm;
sei(); sei();
while (1) { while (1) {
// If we have made a config change, store it. // uint16_t adcVal = ADC0_read();
if (store_config) { // printf("The values: \n%u , %u\n",VREF_REFSEL_VDD_gc , adcVal);
write_struct_from_EEPROM(config); ;
store_config = false;
}
} }
} }

View File

@ -27,9 +27,6 @@
<itemPath>uart.c</itemPath> <itemPath>uart.c</itemPath>
<itemPath>eeprom.c</itemPath> <itemPath>eeprom.c</itemPath>
<itemPath>voltage.c</itemPath> <itemPath>voltage.c</itemPath>
<itemPath>i2c.c</itemPath>
<itemPath>command-handler.c</itemPath>
<itemPath>thermistor-temp.c</itemPath>
</logicalFolder> </logicalFolder>
</logicalFolder> </logicalFolder>
<projectmakefile>Makefile</projectmakefile> <projectmakefile>Makefile</projectmakefile>
@ -42,7 +39,7 @@
<targetPluginBoard></targetPluginBoard> <targetPluginBoard></targetPluginBoard>
<platformTool>nEdbgTool</platformTool> <platformTool>nEdbgTool</platformTool>
<languageToolchain>XC8</languageToolchain> <languageToolchain>XC8</languageToolchain>
<languageToolchainVersion>2.46</languageToolchainVersion> <languageToolchainVersion>2.45</languageToolchainVersion>
<platform>2</platform> <platform>2</platform>
</toolsSet> </toolsSet>
<packs> <packs>