This repository has been archived on 2024-01-25. You can view files and clone it, but cannot push or open issues or pull requests.
Solar-Panel/modbus.c

181 lines
5.9 KiB
C
Raw Normal View History

2023-03-15 11:55:57 +00:00
/*!
* @file modbus.c
* @authors Simon Donnet-Monay & Remi Heredero
* @date 14 march 2023
2023-03-17 10:46:31 +00:00
* @brief
2023-03-15 11:55:57 +00:00
*/
2023-02-28 14:00:54 +00:00
#include "modbus.h"
#include "crc.h"
// Modbus functions
2023-03-17 10:46:31 +00:00
#define READ_INPUT_REGISTERS 0x04 // Modbus function for read input register
#define READ_HOLDING_REGISTERS 0x03 // Modbus function for read holding register
#define WRITE_SINGLE_REGISTER 0x06 // Modbus function for write a single register
2023-02-28 14:00:54 +00:00
// Modbus data model
uint8_t modbusAddress;
uint16_t input_registers[2];
uint16_t holding_registers[2];
2023-03-10 12:49:32 +00:00
2023-02-28 14:00:54 +00:00
// Modbus error codes
#define ILLEGAL_FUNCTION 1
#define ILLEGAL_DATA_ADDRESS 2
#define ILLEGAL_DATA_VALUE 3
#define SLAVE_DEVICE_FAILURE 4
/**
* Buffers for serial receive and send operations
* which are more than one byte long
**/
uint8_t rx_buf[256];
uint8_t tx_buf[256];
// Current position pointer for storing receive position
uint8_t recPtr = 0;
2023-03-17 10:46:31 +00:00
/**
* End of MODBUS frame.
*/
2023-03-15 11:55:57 +00:00
void modbus_timer(void) {
2023-03-17 10:46:31 +00:00
INTCONbits.TMR0IF = 0; // Reset flag of the timer0 interrupt
recPtr = 0; // Reset position of the char in the frame
TMR0_StopTimer(); // Stop timer who detect the end of the frame
modbus_analyse_and_answer(); // Run analyse of this frame
2023-02-28 14:00:54 +00:00
}
2023-03-17 10:46:31 +00:00
2023-03-10 14:13:26 +00:00
extern uint16_t measure_voltage();
2023-03-17 10:46:31 +00:00
/**
* @brief Analyse the received frame and build an answer
* @return The error code if the frame isn't valid (TODO)
*/
2023-03-03 15:11:29 +00:00
uint8_t modbus_analyse_and_answer(void) {
2023-03-17 10:46:31 +00:00
// Init lenght of the answer frame at 0
2023-03-14 14:25:45 +00:00
uint16_t length = 0;
2023-03-17 10:46:31 +00:00
// Check if the received frame is for this device
2023-03-10 14:13:26 +00:00
if(rx_buf[0] == modbusAddress){
2023-03-17 10:46:31 +00:00
tx_buf[0] = rx_buf[0]; // Copy the address on the tx buffer
tx_buf[1] = rx_buf[1]; // Copy the function number on the tx buffer
// Init the addresse Register local variable
2023-03-14 14:25:45 +00:00
uint16_t adresseRegister = ((uint16_t)rx_buf[2] << 8) | rx_buf[3];
2023-03-10 14:13:26 +00:00
2023-03-14 14:25:45 +00:00
switch(rx_buf[1]){ // Check the function from rx buffer
2023-03-17 10:46:31 +00:00
// In case of the function is to read input register:
case READ_INPUT_REGISTERS:
// Define length as the number of register we want read
2023-03-14 14:25:45 +00:00
length = ((uint16_t)rx_buf[4] << 8) | rx_buf[5];
2023-03-17 10:46:31 +00:00
// Write this length on the tx buffer for the answer
tx_buf[2] = (uint8_t)(length*2);
// For each register, write the value on the tx buffer (register on 16bits)
2023-03-14 14:25:45 +00:00
for(uint16_t i = 0; i < length; i++){ // Data
tx_buf[i*2+4] = input_registers[adresseRegister+i];
tx_buf[i*2+3] = (input_registers[adresseRegister+i] >> 8);
}
2023-03-17 10:46:31 +00:00
// Transform length as the number of bytes on tx register
length*=2; // 2 bytes by register
length+=3; // + address + function + length
2023-03-10 14:13:26 +00:00
break;
2023-03-17 10:46:31 +00:00
// In case of the function is to read holding register
2023-03-10 14:13:26 +00:00
case READ_HOLDING_REGISTERS:
2023-03-17 10:46:31 +00:00
// Define length as the number of register we want read
2023-03-14 14:25:45 +00:00
length = ((uint16_t)rx_buf[4] << 8) | rx_buf[5];
2023-03-17 10:46:31 +00:00
// Write this length on the tx buffer for the answer
tx_buf[2] = (uint8_t)(length*2);
// For each register, write the value on the tx buffer (register on 16bits))
for(uint16_t i = 0; i < length; i++){
2023-03-14 14:25:45 +00:00
tx_buf[i*2+4] = holding_registers[adresseRegister+i];
tx_buf[i*2+3] = (holding_registers[adresseRegister+i] >> 8);
}
2023-03-17 10:46:31 +00:00
// Transform length as the number of bytes on tx register
length*=2; // 2 bytes by register
length+=3; // + address + function + length
2023-03-10 14:13:26 +00:00
break;
2023-03-17 10:46:31 +00:00
// In case of the funciton is to write a single register
2023-03-10 14:13:26 +00:00
case WRITE_SINGLE_REGISTER:
2023-03-17 10:46:31 +00:00
// Write the value on rx buffer on the holding register define by the adress register we define before
2023-03-14 14:25:45 +00:00
holding_registers[adresseRegister] = ((uint16_t)rx_buf[4] << 8) | rx_buf[5];
2023-03-17 10:46:31 +00:00
// Copy data on the tx buffer
for (uint8_t i = 2; i <= 5; i++) {
2023-03-14 14:25:45 +00:00
tx_buf[i] = rx_buf[i];
length = i+1;
}
2023-03-10 14:13:26 +00:00
break;
}
}
2023-03-17 10:46:31 +00:00
// Clear address on rx buffer (for validate we treat the data)
2023-03-03 15:11:29 +00:00
rx_buf[0] = 0;
2023-03-17 10:46:31 +00:00
// Send the answer frame
modbus_send(length);
2023-03-17 10:46:31 +00:00
// TODO return error code
2023-02-28 14:00:54 +00:00
}
2023-03-17 10:46:31 +00:00
/**
* Record a char when it's received on the modbus
*/
void modbus_char_recvd(void) {
//! Record the received char on the rx buffer and move position of the record pointer for the next char
2023-03-10 12:49:32 +00:00
rx_buf[recPtr++] = RCREG1;
2023-03-17 10:46:31 +00:00
//! Reload and start the timer0 for restart to count the time between char
2023-03-10 12:49:32 +00:00
TMR0_Reload();
TMR0_StartTimer();
2023-02-28 14:00:54 +00:00
}
2023-03-17 10:46:31 +00:00
/**
* Create the CRC and send the tx buffer
* @param length lenght of the frame without the CRC
*/
void modbus_send(uint8_t length) {
// Create the CRC
2023-03-14 14:25:45 +00:00
uint16_t crc = CRC16(tx_buf, length);
2023-03-17 10:46:31 +00:00
// Write CRC on the tx buffer
2023-03-14 14:25:45 +00:00
tx_buf[length] = crc;
tx_buf[length+1] = crc >> 8;
2023-02-28 14:00:54 +00:00
2023-03-17 10:46:31 +00:00
length += 2; //! add 2 CRC bytes for total size
2023-02-28 14:00:54 +00:00
2023-03-17 10:46:31 +00:00
// Send each byte of the frame on the tx buffer
2023-03-14 14:25:45 +00:00
for (uint8_t i = 0; i < length; i++){
EUSART1_Write(tx_buf[i]);
}
2023-02-28 14:00:54 +00:00
}
2023-03-17 10:46:31 +00:00
/**
* Initialize the modbus with adress and handler function
* @param address The adress of this device on modbus protocole
*/
void modbus_init(uint8_t address) {
// Init the modbus adress
modbusAddress = address;
// Save the modbus adress in the dedicated register
2023-03-14 14:25:45 +00:00
holding_registers[1] = address;
2023-03-17 10:46:31 +00:00
// Set the handler for the character detection
2023-03-10 12:49:32 +00:00
EUSART1_SetRxInterruptHandler(modbus_char_recvd);
2023-03-17 10:46:31 +00:00
// Set the handler for the detection of end frame
2023-03-10 12:49:32 +00:00
TMR0_SetInterruptHandler(modbus_timer);
2023-03-17 10:46:31 +00:00
}