<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/core.h>
#include <lightmodbus/parser.h>
#include <lightmodbus/slave/stypes.h>
#include <lightmodbus/slave/scoils.h>

uint8_t modbusParseRequest0102( ModbusSlave *status, union ModbusParser *parser )
{
	//Read multiple coils or discrete inputs
	//Using data from union pointer

	//Update frame length
	uint8_t frameLength = 8;
	uint8_t coil = 0;
	uint16_t i = 0;

	//Check if given pointers are valid
	if ( status == NULL || parser == NULL || ( parser->base.function != 1 && parser->base.function != 2 ) ) return MODBUS_ERROR_OTHER;

	//Don't do anything when frame is broadcasted
	//Base of the frame can be always safely checked, because main parser function takes care of that
	if ( parser->base.address == 0 ) return MODBUS_ERROR_OK;

	//Check if frame length is valid
	if ( status->request.length != frameLength )
		return modbusBuildException( status, parser->base.function, MODBUS_EXCEP_ILLEGAL_VAL );

	//Swap endianness of longer members (but not crc)
	uint16_t index = modbusSwapEndian( parser->request0102.index );
	uint16_t count = modbusSwapEndian( parser->request0102.count );

	//Check if coil is in valid range
	if ( count == 0 || count > 2000 )
		return modbusBuildException( status, parser->base.function, MODBUS_EXCEP_ILLEGAL_VAL );

	if ( index >= ( parser->base.function == 1 ? status->coilCount : status->discreteInputCount ) || \
		(uint32_t) index + (uint32_t) count > (uint32_t) ( parser->base.function == 1 ? status->coilCount : status->discreteInputCount ) )
			return modbusBuildException( status, parser->base.function, MODBUS_EXCEP_ILLEGAL_ADDR );

	//Respond
	frameLength = 5 + BITSTOBYTES( count );

	status->response.frame = (uint8_t *) calloc( frameLength, sizeof( uint8_t ) ); //Reallocate response frame memory to needed memory
	if ( status->response.frame == NULL ) return MODBUS_ERROR_ALLOC;
	union ModbusParser *builder = (union ModbusParser *) status->response.frame;

	//Set up basic response data
	builder->base.address = status->address;
	builder->base.function = parser->base.function;
	builder->response0102.length = BITSTOBYTES( count );

	//Copy registers to response frame
	for ( i = 0; i < count; i++ )
	{
		if ( ( coil = modbusMaskRead( parser->base.function == 1 ? status->coils : status->discreteInputs, \
			BITSTOBYTES( status->coilCount ), i + index ) ) == 255 )
				return MODBUS_ERROR_OTHER;
		if ( modbusMaskWrite( builder->response0102.values, 125, i, coil ) == 255 )
			return MODBUS_ERROR_OTHER;
	}

	//Calculate crc
	//That could be written as a single line, without the temporary variable, but avr-gcc doesn't like that
	//warning: dereferencing type-punned pointer will break strict-aliasing rules
	uint16_t *crc = (uint16_t*)( builder->frame + frameLength - 2 );
	*crc = modbusCRC( builder->frame, frameLength - 2 );

	//Set frame length - frame is ready
	status->response.length = frameLength;<commit_msg>Fix fake limit :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/core.h>
#include <lightmodbus/parser.h>
#include <lightmodbus/slave/stypes.h>
#include <lightmodbus/slave/scoils.h>

uint8_t modbusParseRequest0102( ModbusSlave *status, union ModbusParser *parser )
{
	//Read multiple coils or discrete inputs
	//Using data from union pointer

	//Update frame length
	uint8_t frameLength = 8;
	uint8_t coil = 0;
	uint16_t i = 0;

	//Check if given pointers are valid
	if ( status == NULL || parser == NULL || ( parser->base.function != 1 && parser->base.function != 2 ) ) return MODBUS_ERROR_OTHER;

	//Don't do anything when frame is broadcasted
	//Base of the frame can be always safely checked, because main parser function takes care of that
	if ( parser->base.address == 0 ) return MODBUS_ERROR_OK;

	//Check if frame length is valid
	if ( status->request.length != frameLength )
		return modbusBuildException( status, parser->base.function, MODBUS_EXCEP_ILLEGAL_VAL );

	//Swap endianness of longer members (but not crc)
	uint16_t index = modbusSwapEndian( parser->request0102.index );
	uint16_t count = modbusSwapEndian( parser->request0102.count );

	//Check if coil is in valid range
	if ( count == 0 || count > 2000 )
		return modbusBuildException( status, parser->base.function, MODBUS_EXCEP_ILLEGAL_VAL );

	if ( index >= ( parser->base.function == 1 ? status->coilCount : status->discreteInputCount ) || \
		(uint32_t) index + (uint32_t) count > (uint32_t) ( parser->base.function == 1 ? status->coilCount : status->discreteInputCount ) )
			return modbusBuildException( status, parser->base.function, MODBUS_EXCEP_ILLEGAL_ADDR );

	//Respond
	frameLength = 5 + BITSTOBYTES( count );

	status->response.frame = (uint8_t *) calloc( frameLength, sizeof( uint8_t ) ); //Reallocate response frame memory to needed memory
	if ( status->response.frame == NULL ) return MODBUS_ERROR_ALLOC;
	union ModbusParser *builder = (union ModbusParser *) status->response.frame;

	//Set up basic response data
	builder->base.address = status->address;
	builder->base.function = parser->base.function;
	builder->response0102.length = BITSTOBYTES( count );

	//Copy registers to response frame
	for ( i = 0; i < count; i++ )
	{
		if ( ( coil = modbusMaskRead( parser->base.function == 1 ? status->coils : status->discreteInputs, \
			BITSTOBYTES( status->coilCount ), i + index ) ) == 255 )
				return MODBUS_ERROR_OTHER;
		if ( modbusMaskWrite( builder->response0102.values, 250, i, coil ) == 255 )
			return MODBUS_ERROR_OTHER;
	}

	//Calculate crc
	//That could be written as a single line, without the temporary variable, but avr-gcc doesn't like that
	//warning: dereferencing type-punned pointer will break strict-aliasing rules
	uint16_t *crc = (uint16_t*)( builder->frame + frameLength - 2 );
	*crc = modbusCRC( builder->frame, frameLength - 2 );

	//Set frame length - frame is ready
	status->response.length = frameLength;
{'fraction_non_alphanumeric': 0.1039348710990502, 'fraction_numerical': 0.019810040705563095, 'mean_word_length': 4.227659574468085, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 87, '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': '722861', 'n_tokens_mistral': 2435, 'n_tokens_neox': 2227, 'n_words': 776}