не имеет особого значения, чего они там повторяют. Эти "правила начальной школы" тоже неявные так-то, просто общепринятые.
[uquote="a5021",url="/forum/viewtopic.php?p=3392898#p3392898"]Наружные, кстати, скобки имеют объяснение с позиций "культуры написания кода" ?[/uquote]
да.
[uquote="a5021",url="/forum/viewtopic.php?p=3392898#p3392898"]Никто не пишет код "вообще", не применительно ни к какой платформе.[/uquote]
говорите за себя
Спойлер
Код: Выделить всё
/*
* modbus_tiny.c
*
* Author: arkhnchul
*/
#include <stdint.h>
#include "modbus_tiny.h"
#include "crc16.h"
volatile mb_data_t MB;
void mb_init() {
MB.state = MB_STATE_IDLE;
MB.ADU_length = 0;
}
void mb_cycle_tick() {
switch (MB.state) {
case MB_STATE_REQUEST_READY:
MB.state = MB_STATE_PROCESSING;
mb_process_request();
break;
case MB_STATE_RESPONSE_READY:
mb_crc_fill();
MB.state = MB_STATE_TRANSMITTING;
mb_port_transmit_response();
break;
}
}
void mb_process_request() {
/* incoming frame already contains 2-byte CRC at the end */
const uint16_t crc_computed = crc16_compute(MB.buffer, MB.ADU_length - 2);
/* CRC transmits as little-endian FTGJ. */
const uint16_t crc_received = MB_COMBINE_UINT16(
MB.buffer[MB.ADU_length - 1], MB.buffer[MB.ADU_length - 2]);
/* frame with mismatched CRC must be ignored silently */
if (crc_computed != crc_received) {
MB.state = MB_STATE_IDLE;
return;
}
switch (MB_ADU_FUNCTION) {
#ifdef MB_HAS_FUNCTION_DIAGNOSTICS
case MB_FUNC_DIAGNOSTICS:
mb_function_diagnostic();
break;
#endif
#if defined(MB_HAS_FUNCTION_READ_HOLDING_REGISTERS) || defined(MB_HAS_FUNCTION_READ_INPUT_REGISTERS)
#ifdef MB_HAS_FUNCTION_READ_HOLDING_REGISTERS
case MB_FUNC_READ_HOLDING_REGISTERS:
#endif
#ifdef MB_HAS_FUNCTION_READ_INPUT_REGISTERS
case MB_FUNC_READ_INPUT_REGISTERS:
#endif
mb_function_read_registers();
break;
#endif
#ifdef MB_HAS_FUNCTION_WRITE_SINGLE_REGISTER
case MB_FUNC_WRITE_SINGLE_REGISTER:
mb_function_write_single_register();
break;
#endif
#if defined(MB_HAS_FUNCTION_READ_COILS) || defined(MB_HAS_FUNCTION_READ_DISCRETE_INPUTS)
#ifdef MB_HAS_FUNCTION_READ_COILS
case MB_FUNC_READ_COILS:
#endif
#ifdef MB_HAS_FUNCTION_READ_DISCRETE_INPUTS
case MB_FUNC_READ_DISCRETE_INPUTS:
#endif
mb_function_read_coils();
break;
#endif
default:
mb_raise_exception(MB_EXCEPTION_FUNCTION_UNSUPPORTED);
}
if (MB.state == MB_STATE_PROCESSING)
MB.state = MB_STATE_RESPONSE_READY;
}
#if defined(MB_HAS_FUNCTION_READ_HOLDING_REGISTERS)||defined(MB_HAS_FUNCTION_READ_INPUT_REGISTERS)
void mb_function_read_registers(void) {
const uint16_t register_start_address = MB_ADU_GET_UINT16(2);
/* Modbus spec says that register count is 2-byte field,
* but simultaneously it has to be less or equal 125 (decimal)
* so we can take just LSB */
const uint8_t register_count = MB.buffer[5];
if (register_count == 0) {
mb_raise_exception(MB_EXCEPTION_WRONG_ADDRESS);
return;
}
/* check if we have enough space for response in MB.buffer */
if (register_count > (MB_BUFFER_SIZE - 5) / 2) {
mb_raise_exception(MB_EXCEPTION_INTERNAL_FAILURE);
return;
}
/* response "byte count" field; each register value consumes two bytes */
MB.buffer[2] = register_count * 2;
/* as for now, ADU buffer contains 3 bytes - slave address, function code and byte count */
MB.ADU_length = 3;
/* now fill rest of buffer with registers values */
for (uint16_t i = register_start_address;
i < register_start_address + register_count; i++) {
uint16_t register_value;
// TODO: implement device-specific read actions
register_value = mb_port_read_register(i);
/* check if exception had been raised */
if (MB.state == MB_STATE_RESPONSE_READY)
break;
MB_ADU_SET_UINT16(MB.ADU_length, register_value);
MB.ADU_length += 2;
}
}
#endif
#ifdef MB_HAS_FUNCTION_DIAGNOSTICS
static enum {
MB_SUB_RETURN_QUERY = (uint16_t) 0x00
};
void mb_function_diagnostic(void) {
switch (MB_ADU_SUBFUNCTION) {
case MB_SUB_RETURN_QUERY:
/* "Return Query" does nothing, just echoes back the request */
MB.ADU_length-=2;
break;
default:
mb_raise_exception(MB_EXCEPTION_FUNCTION_UNSUPPORTED);
}
}
#endif
#ifdef MB_HAS_FUNCTION_WRITE_SINGLE_REGISTER
void mb_function_write_single_register(void) {
const uint16_t register_address = MB_ADU_GET_UINT16(2);
uint16_t register_value;
register_value = MB_ADU_GET_UINT16(4);
// TODO: implement device-specific write actions
mb_port_write_register(register_address, register_value);
}
#endif
#if defined(MB_HAS_FUNCTION_READ_COILS) || defined(MB_HAS_FUNCTION_READ_DISCRETE_INPUTS)
void mb_function_read_coils(void) {
const uint16_t start_address=MB_ADU_GET_UINT16(2);
const uint16_t coil_count=MB_ADU_GET_UINT16(4);
uint8_t *byte_count=&(MB.buffer[2]);
uint8_t *current_byte=&(MB.buffer[3]);
uint8_t current_bit=0;
MB.ADU_length = 4;
if (coil_count == 0) {
mb_raise_exception(MB_EXCEPTION_WRONG_ADDRESS);
return;
}
/* check if we have enough space for response in MB.buffer */
if(coil_count > (MB_BUFFER_SIZE - 5) * 8) {
mb_raise_exception(MB_EXCEPTION_INTERNAL_FAILURE);
return;
}
*current_byte=0;
*byte_count=1;
for(uint16_t coil_address=start_address;
coil_address < start_address+coil_count;
coil_address++) {
uint8_t coil_value=mb_port_read_coil(coil_address);
/* check if exception had been raised */
if(MB.state==MB_STATE_RESPONSE_READY)
break;
if(current_bit>7) {
current_byte++;
*current_byte=0;
current_bit=0;
(*byte_count)++;
MB.ADU_length++;
}
if(current_bit) {
(*current_byte)<<=1;
}
if(coil_value) {
(*current_byte) |= 1;
}
current_bit++;
}
}
#endif
#ifdef MB_HAS_FUNCTION_WRITE_SINGLE_COIL
void mb_function_write_single_coil(void) {
const uint16_t coil_address = MB_ADU_GET_UINT16(2);
uint16_t coil_value = MB_ADU_GET_UINT16(4);
// TODO: implement device-specific write actions
switch(coil_value){
case 0x0000:
mb_port_write_coil(coil_address, 0x00);
break;
case 0xff00:
mb_port_write_coil(coil_address, 0x01);
break;
default:
mb_raise_exception(MB_EXCEPTION_WRONG_VALUE);
}
}
#endif
void mb_raise_exception(mb_exception_t exception) {
MB_ADU_FUNCTION|= 0x80;
MB_ADU_EXCEPTION = exception;
MB.ADU_length = 3;
if(MB.state==MB_STATE_PROCESSING)
MB.state = MB_STATE_RESPONSE_READY;
}
void mb_rx_byte(uint8_t byte) {
if (MB.state == MB_STATE_IDLE) {
if (byte == MB.slave_addr)
MB.state = MB_STATE_RECEIVING;
else
MB.state = MB_STATE_IGNORE;
}
#if MB_BUFFER_SIZE < 256
if (MB.ADU_length >= MB_BUFFER_SIZE) {
MB.state = MB_STATE_IGNORE;
} else
#endif
if (MB.state == MB_STATE_RECEIVING) {
MB.buffer[MB.ADU_length] = byte;
MB.ADU_length++;
}
}
void mb_rx_completed() {
/* Incoming data can be treated as somehow valid only if it was recognized
* as frame addressed to our slave during idle state and we had started
* to accept bytes */
if (MB.state == MB_STATE_RECEIVING) {
MB.state = MB_STATE_REQUEST_READY;
}
/* otherwise the whole portion should been ignored */
else {
MB.ADU_length = 0;
MB.state = MB_STATE_IDLE;
}
}
void mb_transmit_completed(void) {
MB.ADU_length = 0;
MB.state = MB_STATE_IDLE;
}
void mb_crc_fill(void) {
uint16_t crc_computed;
uint8_t * tmp = &MB.buffer[MB.ADU_length]; // pointer to future position of CRC in ADU
crc_computed = crc16_compute(MB.buffer, MB.ADU_length);
MB.ADU_length += 2;
/* CRC transmits as little-endian FTGJ. */
tmp[0] = MB_LSB(crc_computed);
tmp[1] = MB_MSB(crc_computed);
}


