Can anyone reverse this method? - c

I'm reading midi pitchwheel messages with this method ( from here http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec/wheel.htm )that combines 2 hex bytes into a 14bit unsigned short. It is working pretty well but now I'm trying to send out pitchwheel messages which need to be in the 2 bytes hex format. Does anyone know how to reverse this method so that it will take a integer like 12401 and return two bytes?
unsigned short CombineBytes(unsigned char First, unsigned char Second)
{
unsigned short _14bit;
_14bit = (unsigned short)Second;
_14bit <<= 7;
_14bit |= (unsigned short)First;
return(_14bit);
}
This is my bad attempt:
unsigned char CreateBytes(unsigned short value)
{
unsigned char First;
unsigned char Second;
unsigned char FullValue;
FullValue = (unsigned short)value;
First = FullValue;
First >>= 7;
Second |= (unsigned short) value;
return(First, Second);
}

first = (combined & 0x3f80) >> 7; // 0b11111110000000
second = (combined & 0x007f); // 0b00000001111111

Related

Extracting specific bits from an integer and saving them into a string in C?

I'm having trouble with extracting specific bits from a 32-bit long integer and saving those specific bits into a string.
To better explain my problem, I'll explain it like this:
Okay, let's say I have this integer:
01010101010101010101000011010100
I want to extract (going from MSB to LSB) from the 2nd (included) to the 21th bit (included).
So I can simply create a mask that will keep only the 20 bits I want and zero all others.
Integer: 01010101010101010101000011010100
Mask: 01111111111111111111100000000000
New integer = Integer & Mask = 01010101010101010101000000000000
After that, I have no idea, how to save those 20 bits to a string.
Okay, now lets say we have a char array that can hold 100 characters.
I then need to copy those 20 bits from the integer into the char array so that only those 20 bits are displayed as text. This is how it should be:
printf("Text: %s", string); -> "Text: 10101010101010101010"
I hope I explained it well enough. If you still have questions, let me know.
unsigned long long extractbits(unsigned long long data, unsigned start, unsigned end)
{
unsigned long long mask;
if(start > end)
{
unsigned tmp = start;
end = start;
start = tmp;
}
mask = (end == sizeof(unsigned long long) * 8 - 1) ? ~0ULL : (1ULL << (end + 1))) - 1;
return ((data & mask) >> start);
}
char *to_string(char *buff, unsigned long long data)
{
char *cptr = buff;
char *sptr = buff;
while(data)
{
*cptr++ = (data & 1) ? '1' : '0';
data >>= 1;
}
*cptr-- = 0;
while(cptr > buff)
{
char tmp = *cptr;
*cptr-- = *buff;
*buff++ = tmp;
}
return sptr;
}
int main()
{
char buff[25];
printf("%s\n", to_string(buff, extractbits(0b11100011100011100011ULL, 4, 17)));
return 0;
}

Extracting 3 bytes to a number

What is the FASTEST way, using bit operators to return the number, represented with 3 different unsigned char variables ?
unsigned char byte1 = 200;
unsigned char byte2 = 40;
unsigned char byte3 = 33;
unsigned long number = byte1 + byte2 * 256 + byte3 * 256 * 256;
is the slowest way possible.
Just shift each one into place, and OR them together:
#include <stdint.h>
int main(void)
{
uint8_t a = 0xAB, b = 0xCD, c = 0xEF;
/*
* 'a' must be first cast to uint32_t because of the implicit conversion
* to int, which is only guaranteed to be at least 16 bits.
* (Thanks Matt McNabb and Tim Čas.)
*/
uint32_t i = ((uint32_t)a << 16) | (b << 8) | c;
printf("0x%X\n", i);
return 0;
}
Do note however, that almost any modern compiler will replace a multiplication by a power of two with a bit-shift of the appropriate amount.
The fastest way would be the direct memory writing, assuming you know the endian of your system (here the assumption is little endian):
unsigned char byte1 = 200;
unsigned char byte2 = 40;
unsigned char byte3 = 33;
unsigned long number = 0;
((unsigned char*)&number)[0] = byte1;
((unsigned char*)&number)[1] = byte2;
((unsigned char*)&number)[2] = byte3;
Or if you don't mind doing some excercise, you can do something like:
union
{
unsigned long ulongVal;
unsigned char chars[4]; // In case your long is 32bits
} a;
and then by assigning:
a.chars[0] = byte1;
a.chars[1] = byte2;
a.chars[2] = byte3;
a.chars[3] = 0;
you will read the final value from a.ulongVal. This will spare extra memory operations.

Splitting a hex number

newbie question.
Say for example, I have the hex number 0xABCDEF, how would i split it into 0xAB,0xCD and 0xEF?
Is it like this?
unsigned int number = 0xABCDEF
unsigned int ef = a & 0x000011;
unsigned int cd = (a>>8) & 0x000011;
unsigned int ab = (a>>16) & 0x000011;
Thanks
Use 0xff as your mask to remove all but 8 bits of a number:
unsigned int number = 0xABCDEF
unsigned int ef = number & 0xff;
unsigned int cd = (number>>8) & 0xff;
unsigned int ab = (number>>16) & 0xff;
unsigned int number = 0xABCDEF
unsigned int ef = number & 0xff;
unsigned int cd = (number >> 8) & 0xff;
unsigned int ab = (number >> 16) & 0xff;
Instead of the bitwise and (&) operation, you might intead want ef, cd, ab to be unsigned char types, depending on the rest of your code and how you're working with these variables. In which case you cast to unsigned char:
unsigned int number = 0xABCDEF
unsigned char ef = (unsigned char) number;
unsigned char cd = (unsigned char) (number >> 8);
unsigned char ab = (unsigned char) (number >> 16);
The mask to use would be 0xFF, not 0x11. Apart of this, you are right.
void splitByte(unsigned char * split, unsigned int a,int quantBytes)
{
unsigned char aux;
int i;
for(i=0;i<quantBytes;i++)
{
split[i]=a&0x00FF;
a=(a>>8);
}
for(i=0;i<quantBytes-1;i++)
{
aux = split[i];
split[i] = split[quantBytes-i-1];
split[quantBytes-i-1] = aux;
}
}
In the main:
unsigned char split[4];
splitByte(split, 0xffffffff, 4);

convert unsigned integer to byte array in C

Can you explain about how to convert the last 3 bytes of data from unsigned integer to a character array?
Example:
unsigned int unint = some value;
unsigned char array[3];
It's more difficult if you have to convert it to an array, but if you just want to access the individual bytes, then you can do
char* bytes = (char*)&unint;
If you really do want to make an array (and therefore make a copy of the last 3 bytes, not leave them in place) you do
unsigned char bytes[3]; // or char, but unsigned char is better
bytes[0] = unint >> 16 & 0xFF;
bytes[1] = unint >> 8 & 0xFF;
bytes[2] = unint & 0xFF;
You can do using it the bitwise right shift operator:
array[0] = unint;
array[1] = unint >> 8;
array[2] = unint >> 16;
The least signifcant byte of uint is stored in the first element of the array.
Depending on your needs, you may prefer an union:
typedef union {
unsigned int unint;
unsigned char array[3];
} byteAndInt;
or bit-shift operations:
for(int i=0; i<3; i++)
array[i] = (unint>>8*i) & 0xFF;
The former is not endian-safe.
If by last three, you mean lsb+1, lsb+2 and msb (in other words every byte other than the lsb), then you can use this.
unsigned int unint = some value;
unsigned char * array = ( (unsigned char*)&some_value ) + 1;

Converting Char array to Long in C

This question may looks silly, but please guide me
I have a function to convert long data to char array
void ConvertLongToChar(char *pSrc, char *pDest)
{
pDest[0] = pSrc[0];
pDest[1] = pSrc[1];
pDest[2] = pSrc[2];
pDest[3] = pSrc[3];
}
And I call the above function like this
long lTemp = (long) (fRxPower * 1000);
ConvertLongToChar ((char *)&lTemp, pBuffer);
Which works fine.
I need a similar function to reverse the procedure. Convert char array to long.
I cannot use atol or similar functions.
You can do:
union {
unsigned char c[4];
long l;
} conv;
conv.l = 0xABC;
and access c[0] c[1] c[2] c[3]. This is good as it wastes no memory and is very fast because there is no shifting or any assignment besides the initial one and it works both ways.
Leaving the burden of matching the endianness with your other function to you, here's one way:
unsigned long int l = pdest[0] | (pdest[1] << 8) | (pdest[2] << 16) | (pdest[3] << 24);
Just to be safe, here's the corresponding other direction:
unsigned char pdest[4];
unsigned long int l;
pdest[0] = l & 0xFF;
pdest[1] = (l >> 8) & 0xFF;
pdest[2] = (l >> 16) & 0xFF;
pdest[3] = (l >> 24) & 0xFF;
Going from char[4] to long and back is entirely reversible; going from long to char[4] and back is reversible for values up to 2^32-1.
Note that all this is only well-defined for unsigned types.
(My example is little endian if you read pdest from left to right.)
Addendum: I'm also assuming that CHAR_BIT == 8. In general, substitute multiples of 8 by multiples of CHAR_BIT in the code.
A simple way would be to use memcpy:
char * buffer = ...;
long l;
memcpy(&l, buff, sizeof(long));
That does not take endianness into account, however, so beware if you have to share data between multiple computers.
If you mean to treat sizeof (long) bytes memory as a single long, then you should do the below:
char char_arr[sizeof(long)];
long l;
memcpy (&l, char_arr, sizeof (long));
This thing can be done by pasting each bytes of the long using bit shifting ans pasting, like below.
l = 0;
l |= (char_arr[0]);
l |= (char_arr[1] << 8);
l |= (char_arr[2] << 16);
l |= (char_arr[3] << 24);
If you mean to convert "1234\0" string into 1234L then you should
l = strtol (char_arr, NULL, 10); /* to interpret the base as decimal */
Does this work:
#include<stdio.h>
long ConvertCharToLong(char *pSrc) {
int i=1;
long result = (int)pSrc[0] - '0';
while(i<strlen(pSrc)){
result = result * 10 + ((int)pSrc[i] - '0');
++i;
}
return result;
}
int main() {
char* str = "34878";
printf("The answer is %d",ConvertCharToLong(str));
return 0;
}
This is dirty but it works:
unsigned char myCharArray[8];
// Put some data in myCharArray here...
long long integer = *((long long*) myCharArray);
char charArray[8]; //ideally, zero initialise
unsigned long long int combined = *(unsigned long long int *) &charArray[0];
Be wary of strings that are null terminated, as you will end up copying any bytes beyond the null terminator into combined; thus in the above assignment, charArray needs to be fully zero-initialised for a "clean" conversion.
Just found this having tried more than one of the above to no avail :=( :
char * vIn = "0";
long vOut = strtol(vIn,NULL,10);
Worked perfectly for me.
To give credit where it is due, this is where I found it:
https://www.convertdatatypes.com/Convert-char-Array-to-long-in-C.html

Resources