Running out of ram declaring a global 2d array issue - c

I need a different way to have global access to 160*160 bits of data, that wont cause me to run out of ram. I am trying to create a back buffer for a 160*160 LCD black and white screen. so 160*10 ints gives me 160*160 bits because a int is 16bits. However I am running out of RAM on the board. Does anyone have a way to this where I wont use the ram? maybe allocating in someway? but I cant seem to get a proper way to allocate a 2d array. Is there any other way of doing this?
edit:
it is a msp430 rbx430 board,(here is a link to a picture of it http://i.ytimg.com/vi/rr18why8wzY/0.jpg ) and yes int's are 16bits on this device. longs and doubles are 32bits. the device has 64k memory, and I am running it at 16mhz. I am asking for 3,200 bytes
as for it making sense, how does it not? I have a 64k device, where int's are 16bits. I am creating a map for the 160*160 lcd screen by using the 1's and 0's to keep track of when a pixel is on or off. after i turn on all the pixels i want, i then take my map and apply it to the lcd. This way I do not have to draw to the lcd then erase the lcd then draw again. I can simply draw, and then draw over it. this will make it so it will not flicker.
effectively creating a back buffer to draw to the lcd.
static int lcdPixels[160][10];
/*Must call this before using RBX430_graphics*/
void initGraphics(void)
{
int h = 0;
int w = 0;
for(h=0; h < ROW_SIZE; h++)
{
for(w=0; w < COLUMN_SIZE; w++)
{
lcdPixels[h][w] = 0;
}
}
}
---------------------------------here is the rest-----------------------
void pixelOn(int posX, int posY)
{
// first grab the right column
int column = ( ((float)posX/16.0f) + 0.9f);
// next grab the right bit
int bit = posX;
while(bit > 16)
{
bit = bit - 16;
}
//turn on the bit/pixel
lcdPixels[posY][column] |= (1 << bit);
}
void pixelOFF(int posX, int posY)
{
// first grab the right column
int column = ( ((float)posX/16.0f) + 0.9f);
// next grab the right bit
int bit = posX;
while(bit > 16)
{
bit = bit - 16;
}
//turn off the bit/pixel
lcdPixels[posY][column] &= ~(1 << bit);
}
/* Call this to commit the current backBuffer to the LCD display*/
void commitBuffer(void)
{
int h = 0;
int w = 0;
int k = 0;
for(h=0; h < ROW_SIZE; h++)
{
for(w=0; w < COLUMN_SIZE; w++)
{
for(k=0; k < INT_SIZE; k++)
{
if((lcdPixels[h][w] & (1 << k)) >> k)
{
lcd_point(((w * 16) + k), h, ON);
}
else
{
lcd_point(((w * 16) + k), h, OFF);
}
}
}
}
}
So i now tried to allocate the array using malloc, and that is a no go as well. I guess I just can not do this, 160*160 bits is just to much data....

Do you have 64K of RAM or 64K of Flash memory? I think the RBX430 has a msp430f2274 on it (http://www.ti.com/product/msp430f2274) which only has 1K of RAM.

Related

how Converting 2 arrays of bytes (uint8_t) into a word (uint16_t)?

I want to convert two times the Signal[8] values into a uint16_t word, so I can send it via the SPI port.(shift register)?
I tried the following, but it doesn't work:
the code was like that, my you can compile it.
void senddata(void){
uint8_t NZero = 0;
uint16_t timeout;
uint8_t value ;
volatile uint8_t Signal[8]={RGB_NC_0, RGB_1, RGB_2, RGB_3, RGB_4, RGB_5, RGB_6, RGB_NC_7}; // to be set by the state machine
volatile uint8_t SPIData[16]={0};
for(int i=0;i<8;i++){
nonZero|= Signal[i];
}
int i , j;
//Set LATCH low
GPIO_WriteBit(LED_LATCH_PORT, LED_LATCH, Bit_RESET);
//Set blank high
GPIO_WriteBit(LED_BLANK_PORT, LED_BLANK, Bit_SET);
//Enable SPI
SPI_Cmd(LED_SPI, ENABLE);
//iterate through the registers
for(i = 2 - 1; i >= 0; i--){
//iterate through the bits in each registers
for(j = 8 - 1; j >= 0; j--){
valr = Signal[i] & (1 << j);
SPI_I2S_SendData(LED_SPI, value);
while(SPI_I2S_GetFlagStatus(LED_SPI, SPI_I2S_FLAG_TXE) == 0 && timeout < 0xFFFF) //Odota että TXE=1
{ timeout++; }
if(timeout == 0xFFFF){break;}
}
}
SPI_Cmd(LED_SPI, DISABLE); /*!< SPI disable */
GPIO_WriteBit(LED_LATCH_PORT, LED_LATCH, Bit_SET);//Set LATCH high
if(NZero){
GPIO_WriteBit(LED_BLANK_PORT, LED_BLANK, Bit_RESET);//Set BLANK low
}
else{
GPIO_WriteBit(LED_BLANK_PORT, LED_BLANK, Bit_SET);//Set BLANK high
}
}
You can combine each subsequent two bytes into the SPI port register as follows:
for(size_t i = 0; i < sizeof(signal/sizeof(*signal); i += 2)
{
spiPortRegister = (uint16_t)signal[i + 0] << 0
| (uint16_t)signal[i + 1] << 8;
// send via SPI here!
}
// a *totally* generic implementation might add special handling for
// odd arrays, in your specific case you can omit...
Analogously you split back on receiver side:
for(size_t i = 0; i < sizeof(signal/sizeof(*signal); i += 2)
{
// receive via SPI here
signal[i + 0] = (uint8_t) spiPortRegister >> 0;
signal[i + 1] = (uint8_t) spiPortRegister >> 8;
}
Note: Additions or shifts by 0 are unnecessary and only added for code consistency; they will be optimised away by compiler anyway, but you can omit, if you prefer. Similarly the casts in second case, but these in addition silent the compiler from warning about precision loss.
Note, though, that even though promotion to int occurs in first case int might only be of size of 16 bits – and as you apparently operate on a MCU chances for rise – in which case the shift could provoke overflow, thus undefined behaviour, thus the cast should be applied in any case!
Endianness independent
uint16_t get16(volatile uint8_t *table)
{
return *table | ((uint16_t)*(table + 1) << 8);
}
or depending on endianess
uint16_t get16(volatile uint8_t *table)
{
uint16_t result;
memcpy(&result, table, sizeof(result));
return result;
}

CHIP-8 SDL rendering problems

I have coded a chip-8 emulator.Whatever I do, it seems that I cannot show any pixels on the screen.The weird thing is that I have checked the code, top-bottom for 2 days already, and there does not seem to be any problem.It reads the .rom file into memory, and fetches the OP code correctly.
Here is the source code:
SDL_SetRenderDrawColor( renderer, 0, 0, 0, SDL_ALPHA_OPAQUE );
SDL_RenderClear(renderer);
uint32_t pixels[(WINDOW_WIDTH / 10) * (WINDOW_HEIGHT / 10)];
uint16_t i;
for(i = 0; i < 64*32; i++){
pixels[i] = (0x00FFFFFF * display[i]) | 0xFF000000;
}
//upload the pixels to the texture
SDL_UpdateTexture(tex,NULL,pixels, 64 * sizeof(uint32_t));
//Now get the texture to the screen
SDL_RenderCopy(renderer,tex,NULL,NULL);
SDL_RenderPresent(renderer); // Update screen
ch8.drawF = false;
uint16_t x = ch8->V[((ch8->opcode & 0x0F00) >> 8)];
uint16_t y = ch8->V[((ch8->opcode & 0x00F0) >> 4)];
uint8_t n = (ch8->opcode & 0x000F);
for(i = 0; i < n; i++) {
uint8_t pixel= memory[ch8->I.word + i];
for(j = 0; j < 8; j++) {
if((pixel & (0x80 >> j)) != 0){
if(display[x + j + ((y + i) * 64)] == 1) {
ch8->V[0xF] = 1;
}
display[x + j + ((y + i) * 64)] ^= 1;
}
}
}
So basically, the problem was at init() function.I was initially using, SDL_CreateWindow and SDL_CreateRenderer,but now I'm using ,SDL_CreateWindowAndRenderer, which takes pointers to pointers of SDL_Window and SDL_Renderer instead of a pointer to a char and a pointer to a window.
Also there were 3 problems I fixed.
1.I was adding + 0x200 to NNN opcodes,because at firstly I thought that the NNN in ROM's are relative to 0, so I removed +0x200 from each XNNN opcode.Also I forgot a * at SDL_Texture* tex, its supposed to be SDL_Texture** tex, I was merely changing the address the local pointer was poiting too...
2.at opcode 2NNN, instead of (ch8->SP) = ch8->opcode & 0x0FFF; its(ch8->SP) = ch8->PC.word;
3.at opcode FX65 its i <= ((ch8->opcode & 0x0F00) >> 8)
Basically, the differences between SDL_CreateWindowAndRenderer and SDL_CreateWindow&SDL_CreateRenderer had me confused, I should had check'd the documentation first.
Now I only need to make the emulator only redraw the changed pixels, then make the emulator play sound.

Get part of specific length of allocated memory space

I have some billions of bits loaded into RAM by the use of malloc() - will call it big_set. I also have another amount of bits (will call it small_set) in RAM which are all set to 1 and I know its size (how many bits - I will call it ss_size), but can't predict it, as varies on each execution. ss_size can be sometimes as small as 100 or large as hundreds of millions.
I need to do some bitwise operations between small_set and some unpredictable parts of big_set of ss_size bits length. I can't just extend small_set with zeros on both most-significant and least-significant sides to make its size equal big_set's size, as that would be very RAM and CPU expensive (same operations will be done at same time with a lot of differently sized small_sets and also will do shift operations over small_set, expanding it would lead in much more bits to CPU work on).
Example:
big_set: 100111001111100011000111110001100 (would be billions of bits in reality)
small_set: 111111, so ss_size is 6. (may be an unpredictable number of bits).
I need to take 6 bits length parts of big_set, e.g.: 001100, 000111, etc. Obs.: not necessarily Nth 6 bits, it could be from 3rd to 9th bits, for instance. I don't know how can I get it.
I don't want to get a big_set copy with everything zeroed except the 6 bits I would be taking, like on 000000001111100000000000000000000, as that would be also very RAM expensive.
The question is: how can I get N bits from anywhere inside big_set, so I can do bitwise operations between they and small_set? Being N = ss_size.
I'm not sure that the example given below will give an answer to your question, also I am not sure that the realized XOR will work correctly.
But I have tried to show how confusing can be the implementation of the algorithm, if the task is to save memory.
This is my example for case of 40 bit in big_set and 6 bit in small_set:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
void setBitsInMemory(uint8_t * memPtr, size_t from, size_t to)
// sets bits in the memory allocated from memPtr (pointer to the first byte)
// where from and to are numbers of bits to be set
{
for (size_t i = from; i <= to; i++)
{
size_t block = i / 8;
size_t offset = i % 8;
*(memPtr + block) |= 0x1 << offset;
}
}
uint8_t * allocAndBuildSmallSet(size_t bitNum)
// Allocate memory to store bitNum bits and set them to 1
{
uint8_t * ptr = NULL;
size_t byteNum = 1 + bitNum / 8; // determine number of bytes for
ptr = (uint8_t*) malloc(byteNum);
if (ptr != NULL)
{
for (size_t i = 0; i < byteNum; i++) ptr[i] = 0;
setBitsInMemory(ptr, 0, bitNum - 1);
}
return ptr;
}
void printBits(uint8_t * memPtr, size_t from, size_t to)
{
for (size_t i = from; i <= to; i++)
{
size_t block = i / 8;
size_t offset = i % 8;
if (*(memPtr + block) & (0x1 << offset) )
printf("1");
else
printf("0");
}
}
void applyXOR(uint8_t * mainMem, size_t start, size_t cnt, uint8_t * pattern, size_t ptrnSize)
// Applys bitwise XOR between cnt bits of mainMem and pattern
// starting from start bit in mainMem and 0 bit in pattern
// if pattern is smaller than cnt, it will be applyed cyclically
{
size_t ptrnBlk = 0;
size_t ptrnOff = 0;
for (size_t i = start; i < start + cnt; i++)
{
size_t block = i / 8;
size_t offset = i % 8;
*(mainMem + block) ^= ((*(pattern + ptrnBlk) & (0x1 << ptrnOff)) ? 1 : 0) << offset;
ptrnOff++;
if ((ptrnBlk * 8 + ptrnOff) >= ptrnSize)
{
ptrnBlk = 0;
ptrnOff = 0;
}
if (ptrnOff % 8 == 0)
{
ptrnBlk++;
ptrnOff = 0;
}
}
}
int main(void)
{
uint8_t * big_set;
size_t ss_size;
uint8_t * small_set;
big_set = (uint8_t*)malloc(5); // 5 bytes (40 bit) without initialization
ss_size = 6;
small_set = allocAndBuildSmallSet(ss_size);
printf("Initial big_set:\n");
printBits(big_set, 0, 39);
// some operation for ss_size bits starting from 12th
applyXOR(big_set, 12, ss_size, small_set, ss_size);
// output for visual analysis
printf("\nbig_set after XOR with small_set:\n");
printBits(big_set, 0, 39);
printf("\n");
// free memory
free(big_set);
free(small_set);
}
At my PC I can see the following:

Efficient algorithm for finding a byte in a bit array

Given a bytearray uint8_t data[N] what is an efficient method to find a byte uint8_t search within it even if search is not octet aligned? i.e. the first three bits of search could be in data[i] and the next 5 bits in data[i+1].
My current method involves creating a bool get_bit(const uint8_t* src, struct internal_state* state) function (struct internal_state contains a mask that is bitshifted right, &ed with src and returned, maintaining size_t src_index < size_t src_len) , leftshifting the returned bits into a uint8_t my_register and comparing it with search every time, and using state->src_index and state->src_mask to get the position of the matched byte.
Is there a better method for this?
If you're searching an eight bit pattern within a large array you can implement a sliding window over 16 bit values to check if the searched pattern is part of the two bytes forming that 16 bit value.
To be portable you have to take care of endianness issues which is done by my implementation by building the 16 bit value to search for the pattern manually. The high byte is always the currently iterated byte and the low byte is the following byte. If you do a simple conversion like value = *((unsigned short *)pData) you will run into trouble on x86 processors...
Once value, cmp and mask are setup cmp and mask are shifted. If the pattern was not found within hi high byte the loop continues by checking the next byte as start byte.
Here is my implementation including some debug printouts (the function returns the bit position or -1 if pattern was not found):
int findPattern(unsigned char *data, int size, unsigned char pattern)
{
int result = -1;
unsigned char *pData;
unsigned char *pEnd;
unsigned short value;
unsigned short mask;
unsigned short cmp;
int tmpResult;
if ((data != NULL) && (size > 0))
{
pData = data;
pEnd = data + size;
while ((pData < pEnd) && (result == -1))
{
printf("\n\npData = {%02x, %02x, ...};\n", pData[0], pData[1]);
if ((pData + 1) < pEnd) /* still at least two bytes to check? */
{
tmpResult = (int)(pData - data) * 8; /* calculate bit offset according to current byte */
/* avoid endianness troubles by "manually" building value! */
value = *pData << 8;
pData++;
value += *pData;
/* create a sliding window to check if search patter is within value */
cmp = pattern << 8;
mask = 0xFF00;
while (mask > 0x00FF) /* the low byte is checked within next iteration! */
{
printf("cmp = %04x, mask = %04x, tmpResult = %d\n", cmp, mask, tmpResult);
if ((value & mask) == cmp)
{
result = tmpResult;
break;
}
tmpResult++; /* count bits! */
mask >>= 1;
cmp >>= 1;
}
}
else
{
/* only one chance left if there is only one byte left to check! */
if (*pData == pattern)
{
result = (int)(pData - data) * 8;
}
pData++;
}
}
}
return (result);
}
I don't think you can do much better than this in C:
/*
* Searches for the 8-bit pattern represented by 'needle' in the bit array
* represented by 'haystack'.
*
* Returns the index *in bits* of the first appearance of 'needle', or
* -1 if 'needle' is not found.
*/
int search(uint8_t needle, int num_bytes, uint8_t haystack[num_bytes]) {
if (num_bytes > 0) {
uint16_t window = haystack[0];
if (window == needle) return 0;
for (int i = 1; i < num_bytes; i += 1) {
window = window << 8 + haystack[i];
/* Candidate for unrolling: */
for (int j = 7; j >= 0; j -= 1) {
if ((window >> j) & 0xff == needle) {
return 8 * i - j;
}
}
}
}
return -1;
}
The main idea is to handle the 87.5% of cases that cross the boundary between consecutive bytes by pairing bytes in a wider data type (uint16_t in this case). You could adjust it to use an even wider data type, but I'm not sure that would gain anything.
What you cannot safely or easily do is anything involving casting part or all of your array to a wider integer type via a pointer (i.e. (uint16_t *)&haystack[i]). You cannot be ensured of proper alignment for such a cast, nor of the byte order with which the result might be interpreted.
I don't know if it would be better, but i would use sliding window.
uint counter = 0, feeder = 8;
uint window = data[0];
while (search ^ (window & 0xff)){
window >>= 1;
feeder--;
if (feeder < 8){
counter++;
if (counter >= data.length) {
feeder = 0;
break;
}
window |= data[counter] << feeder;
feeder += 8;
}
}
//Returns index of first bit of first sequence occurrence or -1 if sequence is not found
return (feeder > 0) ? (counter+1)*8-feeder : -1;
Also with some alterations you can use this method to search for arbitrary length (1 to 64-array_element_size_in_bits) bits sequence.
If AVX2 is acceptable (with earlier versions it didn't work out so well, but you can still do something there), you can search in a lot of places at the same time. I couldn't test this on my machine (only compile) so the following is more to give to you an idea of how it could be approached than copy&paste code, so I'll try to explain it rather than just code-dump.
The main idea is to read an uint64_t, shift it right by all values that make sense (0 through 7), then for each of those 8 new uint64_t's, test whether the byte is in there. Small complication: for the uint64_t's shifted by more than 0, the highest position should not be counted since it has zeroes shifted into it that might not be in the actual data. Once this is done, the next uint64_t should be read at an offset of 7 from the current one, otherwise there is a boundary that is not checked across. That's fine though, unaligned loads aren't so bad anymore, especially if they're not wide.
So now for some (untested, and incomplete, see below) code,
__m256i needle = _mm256_set1_epi8(find);
size_t i;
for (i = 0; i < n - 6; i += 7) {
// unaligned load here, but that's OK
uint64_t d = *(uint64_t*)(data + i);
__m256i x = _mm256_set1_epi64x(d);
__m256i low = _mm256_srlv_epi64(x, _mm256_set_epi64x(3, 2, 1, 0));
__m256i high = _mm256_srlv_epi64(x, _mm256_set_epi64x(7, 6, 5, 4));
low = _mm256_cmpeq_epi8(low, needle);
high = _mm256_cmpeq_epi8(high, needle);
// in the qword right-shifted by 0, all positions are valid
// otherwise, the top position corresponds to an incomplete byte
uint32_t lowmask = 0x7f7f7fffu & _mm256_movemask_epi8(low);
uint32_t highmask = 0x7f7f7f7fu & _mm256_movemask_epi8(high);
uint64_t mask = lowmask | ((uint64_t)highmask << 32);
if (mask) {
int bitindex = __builtin_ffsl(mask);
// the bit-index and byte-index are swapped
return 8 * (i + (bitindex & 7)) + (bitindex >> 3);
}
}
The funny "bit-index and byte-index are swapped" thing is because searching within a qword is done byte by byte and the results of those comparisons end up in 8 adjacent bits, while the search for "shifted by 1" ends up in the next 8 bits and so on. So in the resulting masks, the index of the byte that contains the 1 is a bit-offset, but the bit-index within that byte is actually the byte-offset, for example 0x8000 would correspond to finding the byte at the 7th byte of the qword that was right-shifted by 1, so the actual index is 8*7+1.
There is also the issue of the "tail", the part of the data left over when all blocks of 7 bytes have been processed. It can be done much the same way, but now more positions contain bogus bytes. Now n - i bytes are left over, so the mask has to have n - i bits set in the lowest byte, and one fewer for all other bytes (for the same reason as earlier, the other positions have zeroes shifted in). Also, if there is exactly 1 byte "left", it isn't really left because it would have been tested already, but that doesn't really matter. I'll assume the data is sufficiently padded that accessing out of bounds doesn't matter. Here it is, untested:
if (i < n - 1) {
// make n-i-1 bits, then copy them to every byte
uint32_t validh = ((1u << (n - i - 1)) - 1) * 0x01010101;
// the lowest position has an extra valid bit, set lowest zero
uint32_t validl = (validh + 1) | validh;
uint64_t d = *(uint64_t*)(data + i);
__m256i x = _mm256_set1_epi64x(d);
__m256i low = _mm256_srlv_epi64(x, _mm256_set_epi64x(3, 2, 1, 0));
__m256i high = _mm256_srlv_epi64(x, _mm256_set_epi64x(7, 6, 5, 4));
low = _mm256_cmpeq_epi8(low, needle);
high = _mm256_cmpeq_epi8(high, needle);
uint32_t lowmask = validl & _mm256_movemask_epi8(low);
uint32_t highmask = validh & _mm256_movemask_epi8(high);
uint64_t mask = lowmask | ((uint64_t)highmask << 32);
if (mask) {
int bitindex = __builtin_ffsl(mask);
return 8 * (i + (bitindex & 7)) + (bitindex >> 3);
}
}
If you are searching a large amount of memory and can afford an expensive setup, another approach is to use a 64K lookup table. For each possible 16-bit value, the table stores a byte containing the bit shift offset at which the matching octet occurs (+1, so 0 can indicate no match). You can initialize it like this:
uint8_t* g_pLookupTable = malloc(65536);
void initLUT(uint8_t octet)
{
memset(g_pLookupTable, 0, 65536); // zero out
for(int i = 0; i < 65536; i++)
{
for(int j = 7; j >= 0; j--)
{
if(((i >> j) & 255) == octet)
{
g_pLookupTable[i] = j + 1;
break;
}
}
}
}
Note that the case where the value is shifted 8 bits is not included (the reason will be obvious in a minute).
Then you can scan through your array of bytes like this:
int findByteMatch(uint8_t* pArray, uint8_t octet, int length)
{
if(length >= 0)
{
uint16_t index = (uint16_t)pArray[0];
if(index == octet)
return 0;
for(int bit, i = 1; i < length; i++)
{
index = (index << 8) | pArray[i];
if(bit = g_pLookupTable[index])
return (i * 8) - (bit - 1);
}
}
return -1;
}
Further optimization:
Read 32 or however many bits at a time from pArray into a uint32_t and then shift and AND each to get byte one at a time, OR with index and test, before reading another 4.
Pack the LUT into 32K by storing a nybble for each index. This might help it squeeze into the cache on some systems.
It will depend on your memory architecture whether this is faster than an unrolled loop that doesn't use a lookup table.

Combining 17bit data into byte array

I'm having a bit of an issue with trying to move groups of 17bit data in to a byte array. I don't want to have to go through step-by-step, but I can't figure out a logical loop.
I need it this way because I'm meant to calculate a checksum by adding up the all the byte values after combining them like this.
So here is what I am struggling with.
I have 16 byte arrays. The first 3 bytes of the array contain the 17 bits I'm after. (8 bits from [0], 8 bits from [1], and the MSB from [2].)
I need to move these 16 17bit values to one separate byte array.
The first one is easy:
int index = 0;
myArray[index++] = driverData[driver][0]; //First byte
myArray[index++] = driverData[driver][1]; //Second byte
myArray[index] = (driverData[driver][2] & 0x80) << 7; //First bit of the third byte.
From here though it gets harder to attempt any kind of loop to move these over.
driver++;<br>
//Take the 7 MSBs from the data array.
myArray[index++] |= (byte)(driverData[driver][0] & 0x7e >> 1);
//This leaves a single bit left over on driverData[driver][0].
myArray[index] = (byte)(driverData[driver][1] & 0x1 << 7);
I think you get the picture. Am I doing this all wrong? Can anyone point me in the right direction?
Sounds like you have a prime number loop large enough to make coding the individual cases a bad idea. This is a classic packing problem. You need a loop that iterates through your destination, and some inner code that gets more bits to pack. Your packing code should know how many bits are available to it from the last iteration, how many it needs, and should be able to increment the source pointer if it doesn't have enough.
OK, so this looks to be working. I probably need to test it more, but this seems to be giving me the result I expect so far. I'm sure I could do this better somehow.
// ... //
void foo()
{
//Lets start by getting all the 17bit values from each driver for the board.
int bitIndex = 7;
int byteIndex = 0;
int stopIndex = chipIndex + GetChipCount();
//Now we start the shiftyness.
for (int driver = chipIndex; driver < stopIndex; driver++) {
int userBits =
(driverData[driver][0] & 0xff) << 9 | (driverData[driver][1]
& 0xff)
<< 1 | (driverData[driver][2] & 0x80) >> 7;
AddBitsToArray(userBits, ref bitIndex, ref byteIndex);
}
}
/// <summary>
/// Takes the 17 bits, and adds them to the byte array.
/// </summary>
private void AddBitsToArray(int userBits, ref int bitIndex, ref int byteIndex)
{
int bitCount = 17;
while (bitCount > 0) {
//First 8 bytes.
checksumBytes[byteIndex] |=
(byte) (((userBits & bitValue(bitCount - 1)) >>
(bitCount - 1)) << bitIndex);
//Move up the bit index to be written to.
bitIndex--;
//Decrement the number of bits left to shift.
bitCount--;
//If we have gone past the 8th bit, reset the bitIndex and increment the byteIndex.
if (bitIndex >= 0)
continue;
bitIndex = 7;
byteIndex++;
}
}
/// <summary>
/// Returns the value of a single bit at the given index.
/// </summary>
private int bitValue(int bitIndex)
{
return (int)(Math.Pow(2, bitIndex));
}
Here is what I came up with. The first part of the method is just setting up some fake input data, so remove that and add arguments as needed. The OutputData array is unnecessarily large but I didn't spend time to calculate its actual length.
I used 170 as the input value which is 10101010 and was helpful in validation.
private void BitShift17()
{
const int NumChunks = 16;
byte[] DriverData = new byte[]
{
170,
170,
170
};
byte[][] InputData = new byte[NumChunks][];
for (int n = 0; n < NumChunks; n++)
InputData[n] = DriverData;
byte[] OutputData = new byte[NumChunks * 3]; // Unnecessarily large
int OutputIndex = 0;
int BitPosition = 0;
for (int Driver = 0; Driver < InputData.Length; Driver++)
{
for (int InputIndex = 0; InputIndex < 3; InputIndex++)
{
byte InputByte = InputIndex == 2 ? (byte)(InputData[Driver][InputIndex] & 128) : InputData[Driver][InputIndex];
if (BitPosition == 0)
{
OutputData[OutputIndex] = InputByte;
if (InputIndex == 2)
BitPosition++;
else
OutputIndex++;
}
else
{
if (InputIndex == 2)
{
OutputData[OutputIndex] |= (byte)(InputByte >> BitPosition);
BitPosition++;
}
else
{
OutputData[OutputIndex] |= (byte)(InputByte >> BitPosition);
OutputIndex++;
OutputData[OutputIndex] = (byte)(InputByte << 8 - BitPosition);
}
}
}
if (BitPosition > 7) BitPosition = 0;
}
}

Resources