<commit_before>/*
	liblightmodbus - a lightweight, multiplatform Modbus library
	Copyright (C) 2016 <NAME> <<EMAIL>>

	This file is part of liblightmodbus.

	Liblightmodbus is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Liblightmodbus is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <lightmodbus/master.h>
#include <lightmodbus/core.h>
#include <lightmodbus/parser.h>
#include <lightmodbus/master/mpregs.h>
#include <lightmodbus/master/mpcoils.h>

uint8_t modbusParseException( ModbusMaster *status, union ModbusParser *parser )
{
	//Parse exception frame and write data to MODBUSMaster structure

	//Check if given pointers are valid
	if ( status == NULL || parser == NULL ) return MODBUS_ERROR_OTHER;

	//Copy data (modbusParseResponse checked if length is 5 so it should be safe)
	status->exception.address = parser->exception.address;
	status->exception.function = parser->exception.function;
	status->exception.code = parser->exception.code;

	return MODBUS_ERROR_EXCEPTION;
}

uint8_t modbusParseResponse( ModbusMaster *status )
{
	//This function parses response from master
	//Calling it will lead to losing all data and exceptions stored in MODBUSMaster (space will be reallocated)

	//Note: crc is now checked here

	//If non-zero some parser failed its job
	uint8_t err = 0;

	//Check if given pointer is valid
	if ( status == NULL ) return MODBUS_ERROR_OTHER;

	//Reset output registers before parsing frame
	status->exception.address = 0;
	status->exception.function = 0;
	status->exception.code = 0;

	#ifndef LIGHTMODBUS_STATIC_MEM_MASTER_DATA
		free( status->data.coils );
		status->data.coils = NULL;
		status->data.regs = NULL;
	#endif
	status->data.length = 0;
	status->data.index = 0;
	status->data.count = 0;
	status->data.type = 0;
	status->data.address = 0;
	status->data.function = 0;

	//Check if frames are not too short and return error (to avoid problems with memory allocation)
	//That enables us to ommit the check in each parsing function
	if ( status->response.length < 4u || status->response.frame == NULL || \
	 	status->request.length < 4u || status->request.frame == NULL )
			return MODBUS_ERROR_OTHER;

	//Check both response and request frames CRC
	//Has to be done the weird way, which isn't safer at all, because avr-gcc didn't like it
	//warning: dereferencing type-punned pointer will break strict-aliasing rules
	uint16_t *crcresp = (uint16_t*)status->response.frame + status->response.length - 2;
	uint16_t *crcreq = (uint16_t*)status->request.frame + status->request.length - 2;
	if ( *crcresp != modbusCRC( status->response.frame, status->response.length - 2 ) ||\
		*crcreq != modbusCRC( status->request.frame, status->request.length - 2 ) )
			return MODBUS_ERROR_CRC;

	union ModbusParser *parser = (union ModbusParser*) status->response.frame;
	union ModbusParser *requestParser = (union ModbusParser*) status->request.frame;

	//Check if frame is exception response
	if ( parser->base.function & 128 && status->response.length == 5 )
	{
		err = modbusParseException( status, parser );
	}
	else
	{
		switch ( parser->base.function )
		{
			case 1: //Read multiple coils
			case 2: //Read multiple discrete inputs
				if ( LIGHTMODBUS_MASTER_COILS ) err = modbusParseResponse0102( status, parser, requestParser );
				else err = MODBUS_ERROR_PARSE;
				break;

			case 3: //Read multiple holding registers
			case 4: //Read multiple input registers
				if ( LIGHTMODBUS_MASTER_REGISTERS ) err = modbusParseResponse0304( status, parser, requestParser );
				else err = MODBUS_ERROR_PARSE;
				break;
<commit_msg>Fix segmentation fault caused by invalid pointer cast :bangbang:<commit_after>/*
	liblightmodbus - a lightweight, multiplatform Modbus library
	Copyright (C) 2016 <NAME> <<EMAIL>>

	This file is part of liblightmodbus.

	Liblightmodbus is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Liblightmodbus is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <lightmodbus/master.h>
#include <lightmodbus/core.h>
#include <lightmodbus/parser.h>
#include <lightmodbus/master/mpregs.h>
#include <lightmodbus/master/mpcoils.h>

uint8_t modbusParseException( ModbusMaster *status, union ModbusParser *parser )
{
	//Parse exception frame and write data to MODBUSMaster structure

	//Check if given pointers are valid
	if ( status == NULL || parser == NULL ) return MODBUS_ERROR_OTHER;

	//Copy data (modbusParseResponse checked if length is 5 so it should be safe)
	status->exception.address = parser->exception.address;
	status->exception.function = parser->exception.function;
	status->exception.code = parser->exception.code;

	return MODBUS_ERROR_EXCEPTION;
}

uint8_t modbusParseResponse( ModbusMaster *status )
{
	//This function parses response from master
	//Calling it will lead to losing all data and exceptions stored in MODBUSMaster (space will be reallocated)

	//Note: crc is now checked here

	//If non-zero some parser failed its job
	uint8_t err = 0;

	//Check if given pointer is valid
	if ( status == NULL ) return MODBUS_ERROR_OTHER;

	//Reset output registers before parsing frame
	status->exception.address = 0;
	status->exception.function = 0;
	status->exception.code = 0;

	#ifndef LIGHTMODBUS_STATIC_MEM_MASTER_DATA
		free( status->data.coils );
		status->data.coils = NULL;
		status->data.regs = NULL;
	#endif
	status->data.length = 0;
	status->data.index = 0;
	status->data.count = 0;
	status->data.type = 0;
	status->data.address = 0;
	status->data.function = 0;

	//Check if frames are not too short and return error (to avoid problems with memory allocation)
	//That enables us to ommit the check in each parsing function
	if ( status->response.length < 4u || status->response.frame == NULL || \
	 	status->request.length < 4u || status->request.frame == NULL )
			return MODBUS_ERROR_OTHER;

	//Check both response and request frames CRC
	//Has to be done the weird way, which isn't safer at all, because avr-gcc didn't like it
	//warning: dereferencing type-punned pointer will break strict-aliasing rules
	uint16_t *crcresp = (uint16_t*)( status->response.frame + status->response.length - 2 );
	uint16_t *crcreq = (uint16_t*)( status->request.frame + status->request.length - 2 );
	if ( *crcresp != modbusCRC( status->response.frame, status->response.length - 2 ) ||\
		*crcreq != modbusCRC( status->request.frame, status->request.length - 2 ) )
			return MODBUS_ERROR_CRC;

	union ModbusParser *parser = (union ModbusParser*) status->response.frame;
	union ModbusParser *requestParser = (union ModbusParser*) status->request.frame;

	//Check if frame is exception response
	if ( parser->base.function & 128 && status->response.length == 5 )
	{
		err = modbusParseException( status, parser );
	}
	else
	{
		switch ( parser->base.function )
		{
			case 1: //Read multiple coils
			case 2: //Read multiple discrete inputs
				if ( LIGHTMODBUS_MASTER_COILS ) err = modbusParseResponse0102( status, parser, requestParser );
				else err = MODBUS_ERROR_PARSE;
				break;

			case 3: //Read multiple holding registers
			case 4: //Read multiple input registers
				if ( LIGHTMODBUS_MASTER_REGISTERS ) err = modbusParseResponse0304( status, parser, requestParser );
				else err = MODBUS_ERROR_PARSE;
				break;

{'fraction_non_alphanumeric': 0.09723406847812843, 'fraction_numerical': 0.011941025953454368, 'mean_word_length': 4.120399251403618, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 91, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2167577', 'n_tokens_mistral': 2643, 'n_tokens_neox': 2415, 'n_words': 870}