[C/Arduino] Passa byte array till funktion

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
toffie
Inlägg: 1785
Blev medlem: 22 juli 2004, 21:38:07
Ort: Töreboda / Stockholm
Kontakt:

[C/Arduino] Passa byte array till funktion

Inlägg av toffie »

Hej på er,

Jag har verkligen svårt att förstå vissa saker och oavsett hur mycket jag försöker hitta och läsa, så.. det går inte in! Jag behöver hjälp, av er!

Följande är koden;

Testkod.ino

Kod: Markera allt

#include "crc16.h"
byte GPIOoff[5] = { 0x06, 0x0B, 0x00, 0x01, 0x00 };

extern Crc16 crc;

void setup()
{
    uint8_t testVariabel = 1;
}

void loop()
{
    if ( testVariabel == 1 )
    {
        sendCommand(GPIOoff);
    }
}

void sendCommand(byte doThisCommand)
{
    sizeOfVar = sizeof(doThisCommand);
    crcvalue = crc.MCRF4XXCrc(doThisCommand,0,sizeOfVar);
    Serial.write(doThisCommand, sizeOfVar);
    Serial.write( highByte(crcvalue) );
    Serial.write(  lowByte(crcvalue) );
}
Allt som har med CRC att göra är inget som strular, men inkluderar crc16.h filen längst ned i kodblock.

Det är sendCommand funktionen som jag har problem med. Som ni kan se överst i testkod.ino så har jag GPIOoff deklarerad som en byte array. Detta är vad jag behöver skicka, i HEX via serieport till en annan IC för kontroll av GPIO pinnar. Till denna byte array räknas sedan en CRC16 ut och skickas efter själva "kommandot" (GPIOoff).

Det i sig fungerar utan problem, om jag lägger det i exempelvis loop().

Däremot så fungerar det inte när jag lägger det i en egen funktion som i koden ovan. Jag förstår att "byte doThisCommand" kanske bara deklarerar att endast 1 byte får tas emot och när jag skickar en array med fem stycken värden så kanske den bara tar första eller sista och är nöjd sen. För när jag gör en Serial.print(sizeOfVar) så får jag alltid 2 utskrivet.

Men hur går jag till väga för att ta emot hela byte arrayen, i funktionen?

Något jag tänkt kanske kan strula är att vissa bytes kommer att vara 0x00, som är "null"? Kan det möjligen strula eller ska det fungera ändå?

Behöver verkligen er hjälp, kommer inte vidare i detta alls nu.

Många tack på förhand!!




crc16.h

Kod: Markera allt

//-------------------------------------------------------------------------------------
// CRC16 support class
// Based on various examples found on the web
// Copyright (C) 2014 Vincenzo Mennella (see license.txt)
// History
//  0.1.0 31/05/2014:   First public code release
//  0.1.1 17/12/2014:   Minor revision and commented code
//  0.1.2 06/06/2019:   Fix reflect routine for 16 bit data
//                      Added ModBus and Mcrf4XX inline functions
//
// License
// "MIT Open Source Software License":
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in the
// Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//-------------------------------------------------------------------------------------
#include "Arduino.h"

#ifndef CRC16_H
#define CRC16_H
#define LIBRARY_VERSION_CRC16_H   "0.1.2"

class Crc16 {
   private:
        //Crc parameters
        uint16_t _msbMask;
        uint16_t _mask;
        uint16_t _xorIn;
        uint16_t _xorOut;
        uint16_t _polynomial;
        uint8_t _reflectIn;
        uint8_t _reflectOut;
        //Crc value
        uint16_t _crc;
        uint8_t reflect(uint8_t data);
        uint16_t reflect(uint16_t data);

   public:
        inline Crc16()
        {
            //Default to XModem parameters
            _reflectIn = false;
            _reflectOut = false;
            _polynomial = 0x1021;
            _xorIn = 0x0000;
            _xorOut = 0x0000;
            _msbMask = 0x8000;
            _mask = 0xFFFF;
            _crc = _xorIn;
        }
        inline Crc16(uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask)
        {
            _reflectIn = reflectIn;
            _reflectOut = reflectOut;
            _polynomial = polynomial;
            _xorIn = xorIn;
            _xorOut = xorOut;
            _msbMask = msbMask;
            _mask = mask;
            _crc = _xorIn;
        }
        inline void clearCrc();
        inline void updateCrc(uint8_t data);
        inline uint16_t getCrc();
        inline unsigned int fastCrc(uint8_t data[], uint8_t start, uint16_t length, uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask);
        inline unsigned int XModemCrc(uint8_t data[], uint8_t start, uint16_t length)
		{
            //  XModem parameters: poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000
            return fastCrc(data, start, length, false, false, 0x1021, 0x0000, 0x0000, 0x8000, 0xffff);
		}
        inline unsigned int Mcrf4XXCrc(uint8_t data[], uint8_t start, uint16_t length)
        {
          return fastCrc(data, start, length, true, true, 0x1021, 0xffff, 0x0000, 0x8000, 0xffff);
        }
        inline unsigned int Modbus(uint8_t data[], uint8_t start, uint16_t length)
        {
          return fastCrc(data, start, length, true, true, 0x8005, 0xffff, 0x0000, 0x8000, 0xffff);
        }
};

//---------------------------------------------------
// Initialize crc calculation
//---------------------------------------------------
void Crc16::clearCrc()
{
	_crc = _xorIn;
}
//---------------------------------------------------
// Update crc with new data
//---------------------------------------------------
void Crc16::updateCrc(uint8_t data)
{
	if (_reflectIn != 0)
		data = (uint8_t) reflect(data);

	int j = 0x80;

	while (j > 0)
	{
		uint16_t bit = (uint16_t)(_crc & _msbMask);
		
		_crc <<= 1;

		if ((data & j) != 0)
		{
			bit = (uint16_t)(bit ^ _msbMask);
		}

		if (bit != 0)
		{
			_crc ^= _polynomial;
		}

		j >>= 1;
	}
}

//---------------------------------------------------
// Get final crc value
//---------------------------------------------------
uint16_t Crc16::getCrc()
{
  if (_reflectOut != 0)
		_crc = (unsigned int)((reflect(_crc) ^ _xorOut) & _mask);

	return _crc;
}

//---------------------------------------------------
// Calculate generic crc code on data array
// Examples of crc 16:
// Kermit: 		width=16 poly=0x1021 init=0x0000 refin=true  refout=true  xorout=0x0000 check=0x2189
// Modbus: 		width=16 poly=0x8005 init=0xffff refin=true  refout=true  xorout=0x0000 check=0x4b37
// XModem: 		width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3
// CCITT-False:	width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1
//---------------------------------------------------
unsigned int Crc16::fastCrc(uint8_t data[], uint8_t start, uint16_t length, uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask)
{
  uint16_t crc = xorIn;

	int j;
	uint8_t c;
	unsigned int bit;

	if (length == 0) return crc;

	for (int i = start; i < (start + length); i++)
	{
		c = data[i];

		if (reflectIn != 0)
			c = (uint8_t) reflect(c);

		j = 0x80;

		while (j > 0)
		{
			bit = (unsigned int)(crc & msbMask);
			crc <<= 1;

			if ((c & j) != 0)
			{
				bit = (unsigned int)(bit ^ msbMask);
			}

			if (bit != 0)
			{
				crc ^= polynomial;
			}

			j >>= 1;
		}
	}

  if (reflectOut != 0)
    crc = (unsigned int)((reflect((uint16_t) crc) ^ xorOut) & mask);

	return crc;
}

//-------------------------------------------------------
// Reflects bit in a uint8_t
//-------------------------------------------------------
uint8_t Crc16::reflect(uint8_t data)
{
  const uint8_t bits = 8;
	unsigned long reflection = 0x00000000;
	// Reflect the data about the center bit.
	for (uint8_t bit = 0; bit < bits; bit++)
	{
		// If the LSB bit is set, set the reflection of it.
		if ((data & 0x01) != 0)
		{
			reflection |= (unsigned long)(1 << ((bits - 1) - bit));
		}

		data = (uint8_t)(data >> 1);
	}

	return reflection;
}
//-------------------------------------------------------
// Reflects bit in a uint16_t
//-------------------------------------------------------
uint16_t Crc16::reflect(uint16_t data)
{
  const uint8_t bits = 16;
  unsigned long reflection = 0x00000000;
  // Reflect the data about the center bit.
  for (uint8_t bit = 0; bit < bits; bit++)
  {
    // If the LSB bit is set, set the reflection of it.
    if ((data & 0x01) != 0)
    {
      reflection |= (unsigned long)(1 << ((bits - 1) - bit));
    }

    data = (uint16_t)(data >> 1);
  }

  return reflection;
}

#endif
Shimonu
Inlägg: 294
Blev medlem: 21 oktober 2015, 22:44:33

Re: [C/Arduino] Passa byte array till funktion

Inlägg av Shimonu »

sendCommand tar in en byte, inte en byte-array eller en byte-pekare. Misstänker att det är ditt problem.

EDIT: Noterade att du typ konstaterat det.

Tror man kan ta emot en byte[] doThisCommand. Annars tar man emot en pekare och en till parameter som sager hur mycket det finns i arrayen.
Användarvisningsbild
adent
Inlägg: 4094
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: [C/Arduino] Passa byte array till funktion

Inlägg av adent »

Förklaras nog ganska bra här:

https://www.tutorialspoint.com/arduino/ ... ctions.htm

Edit: njae, tycker den misslyckas med att förklara något och koden är oindenterad. Hemskt.

Men iaf följande borde funka:

void myfunc(byte arr[], int size);

...

byte minfinaarray[5] = { ... };

myfunc(minafinaarray, 5);

...


Så bör du kunna använda arr och size lokalt i myfunc. Du har då pass-by-reference. Ändrar du i arr ändrar du i arrayen du skickade in.
Användarvisningsbild
toffie
Inlägg: 1785
Blev medlem: 22 juli 2004, 21:38:07
Ort: Töreboda / Stockholm
Kontakt:

Re: [C/Arduino] Passa byte array till funktion

Inlägg av toffie »

Tack Shimonu och adent!

Det känns som att jag inte är alltför off i det här ändå, hade på känn att jag kanske behövde bygga det på det sätt som jag gjort nu. Jag vet inte varför jag trodde att jag kunde göra det enklare, men det är förmodligen min bakgrund i PHP där sånt här "komplicerat", om man nu kan kalla det så, görs åt en i bakgrunden.

Med hjälp av er skrev jag då detta som fungerar precis som tänkt, och som jag lite hade på känn att jag behövde göra igår innan jag skrev denna tråd. Men då det känns som långt mycket mer kod än vad som kanske behövdes så var jag tvungen att fråga om hjälp :)

Ni ska ha superstort tack för er hjälp!

Kod: Markera allt

void sendCommand(byte commandDo[], int commandSize)
{
    uint8_t i=0;
    unsigned short value = "";
    
    for (i=0; i<=(commandSize-1); i++)
    {
        tmp_commandDo[i] = commandDo[i];
    }

    Serial.write(tmp_commandDo, i);
    value = crc.MCRF4XXCrc(tmp_commandDo,0,i);
    Serial.write( highByte(value) );
    Serial.write(  lowByte(value) );
}
Och kallar på funktionen gör jag på detta sätt;

Kod: Markera allt

sendCommand(GPIO0on,sizeof(GPIO0on));
Samt definition av GPIO0on;

Kod: Markera allt

byte GPIO0on[5] = { 0x06, 0x0B, 0x00, 0x01, 0x01 };

Jag är grymt nöjd, så riktigt stort tack till er! :D
Användarvisningsbild
adent
Inlägg: 4094
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: [C/Arduino] Passa byte array till funktion

Inlägg av adent »

Kul att det hjälpte Ett litet tips som ökar läsbarheten ganska mycket!

for (i=0; i<=(commandSize-1); i++)

Skrivs med fördel som:

for (i=0; i<commandSize; i++)

Same same! :)

Edit: Behövs verkligen kopian lokalt i funktionen, kan du inte skicka in parametern direkt i din crc-funktion, eller ändrar den på sin parameter?

MVH: Mikael
Användarvisningsbild
toffie
Inlägg: 1785
Blev medlem: 22 juli 2004, 21:38:07
Ort: Töreboda / Stockholm
Kontakt:

Re: [C/Arduino] Passa byte array till funktion

Inlägg av toffie »

Tack Mikael!

Har faktiskt inte tänkt på det innan, jag tror att jag skriver med likamed tecknet bara för att "vara säker" på att det verkligen är slut när jag kommer till det värdet som är satt. Men visst, att köra endast mindre än gör ju ingen direkt skillnad och ja, det är ju också verkligen slut när den kommer dit.

Bra att tänka på :) gillar när någon annan påpekar eller tipsar om sådant, tycker att jag själv har en ganska bra struktur för övrigt, men finns alltid rum för förbättring!

Jadu.. jag vet faktiskt inte.. Det jag vet dock är ju att Serial.write(tmp_commandDo, i); inte skulle fungera om jag körde commandDo istället, eftersom det var det jag hade problem med :) Men jag har varken funderat eller tänkt på om crc funktionen använder hela parametern eller om den gör likadant..

Edit.. den gör likadant faktiskt så som min funktion blev;

Kod: Markera allt

unsigned int Crc16::fastCrc(uint8_t data[], uint8_t start, uint16_t length, uint8_t reflectIn, uint8_t reflectOut, uint16_t polynomial, uint16_t xorIn, uint16_t xorOut, uint16_t msbMask, uint16_t mask)
{
  uint16_t crc = xorIn;

	int j;
	uint8_t c;
	unsigned int bit;

	if (length == 0) return crc;

	for (int i = start; i < (start + length); i++)
	{
		c = data[i];

		if (reflectIn != 0)
			c = (uint8_t) reflect(c);

		j = 0x80;

		while (j > 0)
		{
			bit = (unsigned int)(crc & msbMask);
			crc <<= 1;

			if ((c & j) != 0)
			{
				bit = (unsigned int)(bit ^ msbMask);
			}

			if (bit != 0)
			{
				crc ^= polynomial;
			}

			j >>= 1;
		}
	}

  if (reflectOut != 0)
    crc = (unsigned int)((reflect((uint16_t) crc) ^ xorOut) & mask);

	return crc;
}
CRC16 biblioteket är för övrigt detta, om någon skulle vara intresserad eller i behov av; https://github.com/vinmenn/Crc16
gkar
Inlägg: 1453
Blev medlem: 31 oktober 2011, 15:28:29
Ort: Linköping

Re: [C/Arduino] Passa byte array till funktion

Inlägg av gkar »

Bra att det köste sig!
Appropå läsbarhet som brukar de flesta företag och projekt kräva att man alltid använder krullar{} på alla if-, while-, for-satser så det är en bra kutym.

Kod: Markera allt

if (length == 0) return crc;

Kod: Markera allt

if (length == 0) 
{
   return crc;
}
Användarvisningsbild
toffie
Inlägg: 1785
Blev medlem: 22 juli 2004, 21:38:07
Ort: Töreboda / Stockholm
Kontakt:

Re: [C/Arduino] Passa byte array till funktion

Inlägg av toffie »

Nu tänkte jag, ja men det är väl inga nyheter, det gör jag ju alltid :humm: Plus att jag alltid kör ny rad och inte klammerkrull på samma rad som if / elseif / else. Precis som du gjorde i ditt exempel.

Sen funderade jag, scrollade upp lite och såg att biblioteket ovan inte gjorde så :P

Förmodligen inget jag ändrar på, då det inte är jag som skrivit just den koden. Men i övrigt håller jag med!
Skriv svar