Print absolute slot number - c

I want to print the Absolute slot number inside the tsch_calculate_channelfunction.
The ASN is defined as:
/* The ASN is an absolute slot number over 5 bytes. */
struct tsch_asn_t {
uint32_t ls4b; /* least significant 4 bytes */
uint8_t ms1b; /* most significant 1 byte */
};
I tried it with:
/* Channel hopping utility functions */
/* Return channel from ASN and channel offset */
uint8_t
tsch_calculate_channel(struct tsch_asn_t *asn, uint8_t channel_offset)
{
int value = (asn->ms1b << 8) | asn->ls4b ;
printf("%d \n\n", value);
uint16_t index_of_0 = TSCH_ASN_MOD(*asn, tsch_hopping_sequence_length);
uint16_t index_of_offset = (index_of_0 + channel_offset) % tsch_hopping_sequence_length.val;
return tsch_hopping_sequence[index_of_offset];
}
Which prints: 48041, 48048, 48055, 48062, 48069....
How can i combine/merge those to bytes to print the correct ASN?.

Related

What is the safest way to hash a list of non-repeating integers without taking order into account?

I am looking for a hash function, that can hash a list of non-repeating integers while ignoring the order of them.
Example
I want the two lists
l1 = [0, 1, 3, 7]
l2 = [7, 3, 1, 0]
to have the same hash.
Background
I have an algorithm that finds a list of vertices on a graph. In an undirected graph, the algorithm will find certain lists multiple times in different orders. With my current understanding of the algorithm, it is easier to filter out the duplicates rather than re-inventing the algorithm. For performance reasons, I understand it to be easier to hash the found lists of vertices rather than comparing the whole lists.
Possible answers
Now, I see that
an XOR or a simple sum might be an answer.
Unfortunately, both offer too much potential for hash collisions, as I see it.
The not-very-efficient working method is to sort a list, and then use this sorted list to compare the new list (also sorted) against.
Other Thoughts
Given that
The lists contain only integers.
The integers will be the vertex indices, and the graph can have billions of vertices.
The integers in a list are non-repeating, and their order doesn't matter.
The lists can and will consist of between 2 and 100 (and in some cases > 1000) entries.
No need for cryptographically-secure randomness.
I have this feeling that there should be a relatively easy and straight-forward answer, and I just have not found it.
Use a combination of the product, sum and ^. All are communitive (order independent) with unsigned math.
unsigned long long product = 1;
unsigned sum = 0; // Maybe unsigned long long
unsigned x = 0;
for (i=0; i < array_element_count; i++) {
product *= l[i];
sum += l[i];
x ^= l[i];
}
unsigned long long pre_hash = product + sum + ((unsigned long long) x << 32));
unsigned hash = pre_hash % hash_table_size;
Tip: hash_table_size should be a prime to effectively use all pre_hash bits.
If array_element_count was high, I would consider p *= shift_right_until_odd(l[i]), else p will too often become 0.
If l[i] == 0 p *= l[i] deserves something different. A simple mitigation is p *= l[i] | 1, but that is something pulled out of the air.
Hashing takes time for good design and the above are candidate building blocks for OP.
Any CRC will do the job. Just XOR (I have used 64bit numbers, but 32bits crc, but it should work also with full 64 xor/crc or 32bit xor/crc) the elements together (to eliminate any order between them, as the XOR operation is conmutative, you eliminate the dependency on the order) mod 2&31, then take a CRC32 of the result (that will spread the set of values uniformly, as it warrants ---or tries to--- that a change in one bit will affect half of the bits in the result) See here for sample code and several crc tables. The repository is BSD license, so you can use it as desired.
Below is a sample implementation that generates random lists, and reorders them, comparing their hashes:
crc32ieee8023.h
#ifndef CRC32IEEE8023_H
#define CRC32IEEE8023_H
#include "crc.h"
extern CRC_STATE crc32ieee8023[];
#endif /* CRC32IEEE8023_H */
crc.h
#ifndef CRC_H
#define CRC_H
#include <stdlib.h>
#include <stdint.h>
#define CRC_TABLE_SIZE 256
#define CRC_BYTE_SIZE 8
#define CRC_BYTE_MASK 0xff
typedef uint8_t CRC_BYTE;
typedef uint64_t CRC_STATE;
CRC_STATE do_crc(
CRC_STATE state,
CRC_BYTE *buff,
size_t nbytes,
CRC_STATE *table);
#endif /* CRC_H */
test_xor_crc_hash.c
(This is the important file, where all the stuff is included.)
/* test_crc_table -- program to test a crc hash algorithm that
* checks a list of numbers and generates the same crc in a form
* that is independent on the list order presented.
* Program generates a list of random numbers (32bit) then it
* generates a random permutation of the list and a sorted list,
* calculates the hash over the three lists, and compares them.
*/
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "crc.h"
#include "crc32ieee8023.h"
#define DFLT_N 10
#define RANDOM_DEV "/dev/urandom"
int long_compare(
const void *_a,
const void *_b);
void print(
const char *name,
const uint64_t *v,
int vsz,
CRC_STATE crc,
uint64_t xor);
int
main(int argc, char **argv)
{
int opt;
int n = DFLT_N,
res;
/* process options */
while ((opt = getopt(argc, argv, "n:")) != EOF) {
switch (opt) {
case 'n': res = sscanf(optarg, "%u", &n);
if (res != 1) {
fprintf(stderr,
"%s: invalid format (-n)\n",
optarg);
}
break;
} /* switch */
} /* while */
/* initialization of random number generator */
unsigned short random_state[3];
int fd = open(RANDOM_DEV, O_RDONLY);
if (fd < 0) {
fprintf(stderr,
"open: %s: %s\n",
RANDOM_DEV, strerror(errno));
exit(EXIT_FAILURE);
}
res = read(fd, random_state, sizeof random_state);
if (res < 0) { /* error */
fprintf(stderr,
"read: %s: %s\n",
RANDOM_DEV, strerror(errno));
exit(EXIT_FAILURE);
}
if (res < sizeof random_state) {
fprintf(stderr,
"read: %s: incomplete read (%d/%zd)\n",
RANDOM_DEV, res, sizeof random_state);
exit(EXIT_FAILURE);
}
seed48(random_state);
close(fd);
/* generate a list of random numbers and make two copies */
uint64_t *original = calloc(n, sizeof *original),
*copy_sorted = calloc(n, sizeof *copy_sorted),
*random_sort = calloc(n, sizeof *random_sort);
/* make two copies */
for (int i = 0; i < n; i++) {
original[i] = copy_sorted[i]
= random_sort[i]
= (long)lrand48() | ((long)lrand48() << 32);
}
/* sort the numbers */
qsort(copy_sorted, n, sizeof *copy_sorted, long_compare);
/* and random permutation */
for (int i = 0; i < n-1; i++) {
int j = lrand48() % (n - i);
if (i != j) {
uint64_t temp = random_sort[i];
random_sort[i] = random_sort[j];
random_sort[j] = temp;
}
}
/* calculate the sorts */
uint64_t xor_original = 0, xor_sorted = 0, xor_random = 0;
for (int i = 0; i < n; i++) {
xor_original ^= original[i];
xor_sorted ^= copy_sorted[i];
xor_random ^= random_sort[i];
}
/* now, calculate the crc's (a crc64 would be better for long) */
CRC_STATE
crc_original = do_crc(0xffffffff, (unsigned char *)&xor_original,
sizeof xor_original, crc32ieee8023),
crc_sorted = do_crc(0xffffffff, (unsigned char *)&xor_sorted,
sizeof xor_sorted, crc32ieee8023),
crc_random = do_crc(0xffffffff, (unsigned char *)&xor_random,
sizeof xor_random, crc32ieee8023);
print("original", original, n, crc_original, xor_original);
print(" sorted", copy_sorted, n, crc_sorted, xor_sorted);
print(" random", random_sort, n, crc_random, xor_random);
if (crc_original != crc_sorted || crc_sorted != crc_random) {
fprintf(stderr, "crc's don't match (crc_original == 0x%08lx, "
"crc_sorted == 0x%08lx, crc_random == 0x%08lx)\n",
crc_original, crc_sorted, crc_random);
}
/* change only one bit in one element to see how it changes the hash */
int bit_to_change = lrand48() % (n * 64),
elem_to_change = bit_to_change % n;
bit_to_change %= 64;
original[elem_to_change] ^= (1UL << bit_to_change); /* change the bit */
/* we should do the calculation over all elements, but just
* changing a bit in one element will change just the same bit in the
* xor_original accumulation variable */
uint64_t xor_original_new = xor_original;
xor_original_new ^= (1UL << bit_to_change);
printf("element=%d, bit=%d\n", elem_to_change, bit_to_change);
uint64_t crc_original_new = do_crc(0xffffffff, (unsigned char *)&xor_original_new, sizeof xor_original_new, crc32ieee8023);
print(" chg1bit", original, n, crc_original_new, xor_original_new);
}
int long_compare(const void *_a, const void *_b)
{
const uint64_t *a = _a, *b = _b;
return *a == *b
? 0
: *a > *b
? +1
: -1;
}
void print(const char *name, const uint64_t *v, int vsz, CRC_STATE crc, uint64_t xor)
{
printf("%s: { ", name);
char *sep = "";
for (int i = 0; i < vsz; i++) {
printf("%s0x%016lx", sep, v[i]);
sep = ", ";
}
printf(" }\n"
" xor = 0x%016lx, crc = 0x%08lx\n",
xor, crc);
}
crc.c
#include <sys/types.h>
#include "crc.h"
/* table based CRC calculation */
CRC_STATE do_crc(
CRC_STATE state,
CRC_BYTE *buff,
size_t nbytes,
CRC_STATE *table)
{
CRC_STATE index;
while (nbytes--) {
state ^= *buff++;
index = state & CRC_BYTE_MASK;
state >>= CRC_BYTE_SIZE;
state ^= table[index];
} /* while */
return state;
} /* do_crc */
crc32ieee8023.c
#include "crc.h"
/* variables */
CRC_STATE crc32ieee8023[] = {
/* Comando usado: mkcrc -gpedb88320 */
/* Polinomio: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 */
/* 0 */ 0x0, 0x77073096, 0xee0e612c, 0x990951ba,
/* 4 */ 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
/* 8 */ 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
/* 12 */ 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
/* 16 */ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
/* 20 */ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
/* 24 */ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
/* 28 */ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
/* 32 */ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
/* 36 */ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
/* 40 */ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
/* 44 */ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
/* 48 */ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
/* 52 */ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
/* 56 */ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
/* 60 */ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
/* 64 */ 0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a,
/* 68 */ 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433,
/* 72 */ 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818,
/* 76 */ 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,
/* 80 */ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
/* 84 */ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
/* 88 */ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
/* 92 */ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
/* 96 */ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
/* 100 */ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
/* 104 */ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
/* 108 */ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
/* 112 */ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
/* 116 */ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
/* 120 */ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
/* 124 */ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
/* 128 */ 0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a,
/* 132 */ 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683,
/* 136 */ 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8,
/* 140 */ 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,
/* 144 */ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
/* 148 */ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
/* 152 */ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
/* 156 */ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
/* 160 */ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
/* 164 */ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
/* 168 */ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
/* 172 */ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
/* 176 */ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
/* 180 */ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
/* 184 */ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
/* 188 */ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
/* 192 */ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a,
/* 196 */ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713,
/* 200 */ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38,
/* 204 */ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,
/* 208 */ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
/* 212 */ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
/* 216 */ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
/* 220 */ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
/* 224 */ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
/* 228 */ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
/* 232 */ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
/* 236 */ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
/* 240 */ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
/* 244 */ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
/* 248 */ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
/* 252 */ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
}; /* crc32ieee8023 */
Makefile
targets = test_xch
toclean = $(targets)
test_xch_deps =
test_xch_objs = crc32ieee8023.o crc.o test_xor_crc_hash.o
test_xch_libs =
test_xch_ldfl =
toclean += $(test_xch_objs)
all: $(targets)
clean:
$(RM) $(toclean)
test_xch: $(test_xch_deps) $(test_xch_objs)
$(CC) $(LDFLAGS) $($#_ldfl) -o $# $($#_objs) $($#_libs) $(LIBS)
To make the program, just run:
$ make
and to run it, you can use option -n that allows you to specify the number of random elements to generate.
I think you will have to invent one to avoid the slow sorting option. In addition to XOR and arithmetic addition, there are bit rotations, and bit masks you could use. If you need high collision resistance, you could just combine more than one of the hash functions. e.g. Assuming the d_i and arithmetic are modular like with uint32_t for example,
H_1 = sum_{i = 1 to n} d_i
H_2 = xor_{i = 1 to n} d_i
H_3 = xor_{i = 1 to n} (rotl(d_i, d_i & 0x1f) + c)
Then take H1H2H3 as a 12 byte hash.

How to parse string to struct?

I want to know if there is any way to convert a string like "5ABBF13A000A01" to the next struct using struct and union method:
struct xSensorData2{
unsigned char flags;
unsigned int refresh_rate;
unsigned int timestamp;
};
Data should be:
flags = 0x01 (last byte);
refresh_rate = 0x000A (two bytes);
timestamp = 5ABBF13A (four bytes);
I'm thinking in next struct of data:
struct xData{
union{
struct{
unsigned char flags:8;
unsigned int refresh_rate:16;
unsigned int timestamp:32;
};
char pcBytes[8];
};
}__attribute__ ((packed));
But I got a struct of 12 bytes, I think it's because bit fields don't work for different types of data. I should just convert string to array of hex, copy to pcBytes and have access to each field.
Update:
In stm32 platform i used this code:
bool bDecode_HexString(char *p)
{
uint64_t data = 0; /* exact width type for conversion
*/
char *endptr = p; /* endptr for strtoul validation */
errno = 0; /* reset errno */
data = strtoull (p, &endptr, 16); /* convert input to uint64_t */
if (p == endptr && data == 0) { /* validate digits converted */
fprintf (stderr, "error: no digits converted.\n");
return false;
}
if (errno) { /* validate no error occurred during conversion */
fprintf (stderr, "error: conversion failure.\n");
return false;
}
//printf ("data: 0x%" PRIx64 "\n\n", data); /* output conerted string */
sensor.flags = data & 0xFF; /* set flags */
sensor.rate = (data >> CHAR_BIT) & 0xFFFF; /* set rate */
sensor.tstamp = (data >> (3 * CHAR_BIT)) & 0xFFFFFFFF; /* set timestamp */
return true;
/* output sensor struct */
// printf ("sensor.flags : 0x%02" PRIx8 "\nsensor.rate : 0x%04" PRIx16
// "\nsensor.tstamp: 0x%08" PRIx32 "\n", sensor.flags, sensor.rate,
// sensor.tstamp);
}
and call the function:
char teste[50] = "5ABBF13A000A01";
bDecode_HexString(teste);
I get data = 0x3a000a01005abbf1
If you are still struggling with the separation of your input into flags, rate & timestamp, then the suggestions in the comments regarding using an unsigned type to hold your input string converted to a value, and using the exact width types provided in <stdint.h>, will avoid potential problems inherent in manipulating signed types (e.g. potential sign-extension, etc.)
If you want to separate the values and coordinate those in struct, that is 100% fine. The work come in separating the individual flags, rate & timestamp. How you choose to store them so they are convenient within your code is up to you. A simple struct utilizing exact-width type could be:
typedef struct { /* struct holding sensor data */
uint8_t flags;
uint16_t rate;
uint32_t tstamp;
} sensor_t;
In a conversion from char * to uint64_t with strtoull, you have two primary validation checks:
utilize both the pointer to the string to convert and the endptr parameter to validate that digits were in fact converted (strtoull sets endptr to point 1-character after the last digit converted). You use this to compare endptr with the original pointer for the data converted to confirm that a conversion took place (if no digits were converted the original pointer and endptr will be the same and the value returned will be zero); and
you set errno = 0; before the conversion and then check again after the conversion to insure no error occurred during the conversion itself. If strtoull encounters an error, value exceeds range, etc.., errno is set to a positive value.
(and if you have specific range validations, e.g. you want to store the result in a size less than that of the conversion, like uint32_t instead of uint64_t, you need to validate the final value can be stored in the smaller type)
A simple approach would be:
uint64_t data = 0; /* exact width type for conversion */
...
char *p = argc > 1 ? argv[1] : "0x5ABBF13A000A01", /* input */
*endptr = p; /* endptr for strtoul validation */
errno = 0; /* reset errno */
...
data = strtoull (p, &endptr, 0); /* convert input to uint64_t */
if (p == endptr && data == 0) { /* validate digits converted */
fprintf (stderr, "error: no digits converted.\n");
return 1;
}
if (errno) { /* validate no error occurred during conversion */
fprintf (stderr, "error: conversion failure.\n");
return 1;
}
printf ("data: 0x%" PRIx64 "\n\n", data); /* output conerted string */
Finally, separating the value in data into the individual values of flags, rate & timestamp, can be done with simple shifts & ANDS, e.g.
sensor_t sensor = { .flags = 0 }; /* declare instance of sensor */
...
sensor.flags = data & 0xFF; /* set flags */
sensor.rate = (data >> CHAR_BIT) & 0xFFFF; /* set rate */
sensor.tstamp = (data >> (3 * CHAR_BIT)) & 0xFFFFFFFF; /* set timestamp */
/* output sensor struct */
printf ("sensor.flags : 0x%02" PRIx8 "\nsensor.rate : 0x%04" PRIx16
"\nsensor.tstamp: 0x%08" PRIx32 "\n", sensor.flags, sensor.rate,
sensor.tstamp);
Putting it altogether, you could do something similar to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <limits.h>
typedef struct { /* struct holding sensor data */
uint8_t flags;
uint16_t rate;
uint32_t tstamp;
} sensor_t;
int main (int argc, char **argv) {
uint64_t data = 0; /* exact width type for conversion */
sensor_t sensor = { .flags = 0 }; /* declare instace of sensor */
char *p = argc > 1 ? argv[1] : "0x5ABBF13A000A01", /* input */
*endptr = p; /* endptr for strtoul validation */
errno = 0; /* reset errno */
data = strtoull (p, &endptr, 0); /* convert input to uint64_t */
if (p == endptr && data == 0) { /* validate digits converted */
fprintf (stderr, "error: no digits converted.\n");
return 1;
}
if (errno) { /* validate no error occurred during conversion */
fprintf (stderr, "error: conversion failure.\n");
return 1;
}
printf ("data: 0x%" PRIx64 "\n\n", data); /* output conerted string */
sensor.flags = data & 0xFF; /* set flags */
sensor.rate = (data >> CHAR_BIT) & 0xFFFF; /* set rate */
sensor.tstamp = (data >> (3 * CHAR_BIT)) & 0xFFFFFFFF; /* set timestamp */
/* output sensor struct */
printf ("sensor.flags : 0x%02" PRIx8 "\nsensor.rate : 0x%04" PRIx16
"\nsensor.tstamp: 0x%08" PRIx32 "\n", sensor.flags, sensor.rate,
sensor.tstamp);
return 0;
}
Example Use/Output
$ ./bin/struct_sensor_bitwise
data: 0x5abbf13a000a01
sensor.flags : 0x01
sensor.rate : 0x000a
sensor.tstamp: 0x5abbf13a
Look things over and let me know if you have further questions.
Here, you have a string of length 14, representing a 7-byte value, consisting of 14 hexadecimal values. Consider this code using strtol, which hexadecimally converts your string into a long int, and then decodes it digit-wise.
uint64_t n = strtoul(str, NULL, 16); // Convert to hexadecimal
int flags = n % 0x10;
int refresh_rate = (n / 0x100) % 0x100000;
int timestamp = n / 0x1000000;
Here is a test case (#import <stdlib.h>):
char str[16] = "5ABBF13EE00AFF";
uint64_t n = strtoul(str, NULL, 16); // Convert to hexadecimal
// Use divide and mod to extract digit segment
int flags = n % 0x100;
int refresh_rate = (n / 0x100) % 0x10000;
int timestamp = n / 0x1000000;
// Print timestamp, refresh rate, and flags
printf("%p %p %p", timestamp, refresh_rate, flags);
The expected result is 0x5abbf13e 0xe00a 0xff as expected.

C Convert Large Integer To Binary

I have IP addresses coming into a box in the form of, for example, 21211328.
I want to take this integer and convert it to its binary form.
The problem I'm getting right now is that my function spits out, based off of the example, -62674752.
This is obviously wrong, as it can't be negative and this isn't in binary.
The function I am using looks like this:
int toBinary(int decimalNo){
if (decimalNo == 0) return 0;
if (decimalNo == 1) return 1; /* optional */
return (decimalNo % 2) + 10 * toBinary(decimalNo / 2);
}
I am using it as follows:
int num_converted = toBinary(iph->saddr); // convert it to binary
printk(KERN_INFO "BSADDR: %d", num_converted); // print the binary conversion to kernel for debugging
if ((num_converted & mask_array) == masked_sub){
return NF_DROP;
}
And this is returning the incorrect output in my kernel logs as seen above.
iph->saddr returns the 21211328, and int num_converted = toBinary(iph->saddr); returns -62674752.
First, ip addresses are normally represented (for human consumption) as quartets of individual bytes (four numbers separated by dots in network byte order) and not as binary sequences.
The address you post (21211328) represents the address 1.67.168.192 (which I guess is a wrong representation ---you need to consider that all ip addresses are in network byte order, most signifiant byte first--- of address 192.168.67.1)
to successfully decode an ip address, you have first to consider if you machine will treat it in the correct endianness or you will have to switch bytes to be able to interpret it as a number. The correct integer (in decimal) for the address 192.168.67.1 would be 3,232,252,673. This number cannot be represented as a signed int, because it has the most signifiant bit on, so it would be represented as a negative number.
To decode an IP address, you first have to convert the number you get from the socket interface to host byte order (endianness) by use of the ntohl(3) function. Once you have the address in host byte order, then you have to convert the number to base 256. This is quite easy, and you can do it with the following snippet of code:
unsigned long ip_address = ntohl(server_address.sin_addr.s_addr);
int i;
for (i = 24; i >= 0; i -= 8) {
if (i < 24) printf("."); /* print the dot between the numbers */
printf("%d",
(ip_address >> i) & 0xff);
}
which I'll explain below:
The expression (ip_address >> i) & 0xff means to right shift the bits 24 to 31, by i places (or 24 places, 16 places, 8 places and 0 places) to the right. So first we will put the 8 most signifiant bits in the place 0 to 7 (24..31 => 0..7), next we will do that for the bits next to them (16..23 => 0..7), and so on until the least signifiant bits, which are not shifted at all (0..7 => 0..7). Once we have the bits we are interested in positions 0..7, we mask them with 0xff (which is a value with 1s in bit positions 0..7 and 0s elsewhere) so the and bit operator & will leave only the bits we have moved to the fixed positions 0..7 and will mask out all the others. So we got a number between 0 and 255 finally, which is what we are printing.
In the case you indeed want to represent them in binary form, you can do it by slightly modifying the above code, just considering that instead of having eight bit numbers as digits you have one bit numbers as digits:
unsigned long ip_address = ntohl(server_address.sin_addr.s_addr);
for (i = 31; i >= 0; i--) {
/* In this case, we don't print the dot between the numbers */
printf("%d",
(ip_address >> i) & 0x1);
}
The mask this time is 0x01 which only masks the least signifiant bit of the number.
Finally, I wrote a complete program to illustrate both ways of decoding, showing in addition the use of the ntohl(3) function:
ipaddr.c
/* 00001 */ #include <arpa/inet.h>
/* 00002 */ #include <stdio.h>
/* 00003 */ #ifndef DOTTED_DECIMAL
/* 00004 */ #define DOTTED_DECIMAL 1
/* 00005 */ #endif
/* 00006 */ #if DOTTED_DECIMAL
/* 00007 */ # define NBITS 8
/* 00008 */ # define SEP "."
/* 00009 */ #else /* BINARY */
/* 00010 */ # define NBITS 1
/* 00011 */ # define SEP ""
/* 00012 */ #endif
/* 00013 */ #define MASK ((1 << NBITS) - 1) /* 100..00 - 1 = 011..11, with NBITS `1` bits */
/* 00014 */ char *ip_formatted(long ip, char *sep, char *buff, size_t buffsz);
/* 00015 */ int main()
/* 00016 */ {
/* 00017 */ char line[1024];
/* 00018 */ unsigned long ip_netfmt = 21211328; /* this was the ip you posted (in network byte order) */
/* 00019 */ unsigned long ip_hostfmt = ntohl(ip_netfmt); /* this is the ip in host byte order */
/* 00020 */ printf("%lu => [%s]\n", ip_netfmt, ip_formatted(ip_netfmt, SEP, line, sizeof line));
/* 00021 */ printf("%lu => [%s]\n", ip_hostfmt, ip_formatted(ip_hostfmt, SEP, line, sizeof line));
/* 00022 */ }
/* 00023 */ char *ip_formatted(long ip, char *sep, char *buff, size_t buffsz)
/* 00024 */ {
/* 00025 */ size_t n;
/* 00026 */ char *s = buff;
/* 00027 */ int i;
/* 00028 */ for (i = 32 - NBITS; i >= 0; i -= NBITS) {
/* 00029 */ int digit = (ip >> i) & MASK;
/* 00030 */ n = snprintf(s, buffsz,
/* 00031 */ "%s%d",
/* 00032 */ i == 32 - NBITS ? "" : sep,
/* 00033 */ digit);
/* 00034 */ s += n; buffsz -= n;
/* 00035 */ }
/* 00036 */ return buff;
/* 00037 */ }
compile this code with the following commands:
$ cc -o ipaddr -DDOTTED_DECIMAL=1 ipaddr.c
to see output in dotted decimal, and
$ cc -o ipaddr -DDOTTED_DECIMAL=0 ipaddr.c
to see output in binary digits.
(I included line numbers, so references to the code can be used, and commented, so you can directly compile the code by cut and paste it)
Try this:
#include <stdio.h>
char *getBin( unsigned long val) {
static char buf[33];
int i;
buf[32]='\0';
for(i=31; i>=0; i--){
buf[i] = val & 1?'1':'0';
val/=2;
}
return buf;
}
int main()
{
unsigned long ip=0x80e2d301;
printf( " ip:%08lx, bin:%sB\n", (unsigned long)ip, getBin(ip) );
return 0;
}

File system, unexpected write/read on disk output

I've been working on this for 3 days, can't see the error, I need fresh eyes :)
I work on a online embedded class, and at this particular lab we need to implement a file system.
I have unexpected results as described in the code comments in the main function. (E=expected, R=result)
Write/read functions:
#define EDISK_ADDR_MIN 0x00020000 // Flash Bank1 minimum address
#define EDISK_ADDR_MAX 0x0003FFFF // Flash Bank1 maximum address
// Write an array of 32-bit data to flash starting at given address.
int Flash_FastWrite(uint32_t *source, uint32_t addr, uint16_t count)
{
uint32_t flashkey;
uint32_t volatile *FLASH_FWBn_R = (uint32_t volatile*)0x400FD100;
int writes = 0;
if(MassWriteAddrValid(addr))
{
DisableInterrupts(); // may be optional step
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){}; // wait for hardware idle
while((writes < 32) && (writes < count))
{
FLASH_FWBn_R[writes] = source[writes];
writes = writes + 1;
}
FLASH_FMA_R = addr;
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY) // by default, the key is 0xA442
flashkey = FLASH_FMC_WRKEY;
else // otherwise, the key is 0x71D5
flashkey = FLASH_FMC_WRKEY2;
FLASH_FMC2_R = (flashkey|FLASH_FMC2_WRBUF); // start writing
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){};
EnableInterrupts();
}
return writes;
}
// Write 1 sector of 512 bytes of data to the disk, data comes from RAM
enum DRESULT eDisk_WriteSector(
const uint8_t *buff, // Pointer to the data to be written
uint8_t sector){ // sector number
uint32_t addr;
uint32_t *copybuff;
copybuff =(uint32_t*)(buff);//Flash_WriteArray needs uint32_t format
addr=EDISK_ADDR_MIN+(512*sector);// starting ROM address
if(addr>EDISK_ADDR_MAX) // return RES_PARERR if exceeds
return RES_PARERR;
Flash_WriteArray(copybuff, addr, 512);// write 512 bytes from RAM into ROM
// written by the instructor.
return RES_OK;
}
// Read 1 sector of 512 bytes from the disk, data goes to RAM
enum DRESULT eDisk_ReadSector(
uint8_t *buff, // Pointer to a RAM buffer into which to store
uint8_t sector){ // sector number to read from
uint16_t i;
uint8_t *diskpt;
diskpt=(uint8_t *)(EDISK_ADDR_MIN+512*sector); // starting ROM address
if(EDISK_ADDR_MIN+512*sector>EDISK_ADDR_MAX)
return RES_PARERR;
else
{
for ( i = 0; i < 512; i++ )// copy 512 bytes from ROM into RAM
buff[i] = *diskpt++;
return RES_OK;
}
}
enum DRESULT eDisk_Format(void){
// erase all flash from EDISK_ADDR_MIN to EDISK_ADDR_MAX
for(uint32_t i=EDISK_ADDR_MIN;i<=EDISK_ADDR_MAX;i++)
Flash_Erase(i);
return RES_OK;
}
uint8_t Buff[512];
int main(void)
{
eDisk_Init(0); // if(drive == 0){return RES_OK;}
eDisk_Format();
testbuildbuff("auf0");
eDisk_WriteSector(Buff,0);
testbuildbuff("Excelent"); // writes "Excelent" onto Buff
eDisk_WriteSector(Buff,1);
testbuildbuff("bus3");
eDisk_WriteSector(Buff,2);
testbuildbuff("bus4");
eDisk_WriteSector(Buff,3);
// E=expected. R=result
eDisk_ReadSector(Buff, 0); //E: Buff="auf0" R:Buff="auf0"
eDisk_ReadSector(Buff, 1); //E: Buff="Excelent" R: Buff is empty
eDisk_ReadSector(Buff, 2); //E: Buff="bus3" R: Buff is empty
eDisk_ReadSector(Buff, 3); //E: Buff="bus4" R: 4Buff is empty
return 0;
}
The Buff results after reed are unexpected. Why does it work for 0 but not the rest?
Even more strange is when I run this test:
testbuildbuff("auf0 buf1 buf2");
eDisk_WriteSector(Buff,2);
testbuildbuff("Excelent");
eDisk_WriteSector(Buff,1);
testbuildbuff("bus3");
eDisk_WriteSector(Buff,3);
testbuildbuff("bus4");
eDisk_WriteSector(Buff,4);
eDisk_ReadSector(Buff, 4); //Buff is empty
eDisk_ReadSector(Buff, 3); //Buff is empty
eDisk_ReadSector(Buff, 2); //Buff = "auf0 buf1 buf2"
eDisk_ReadSector(Buff, 1); //Buff = "Excelent"
What is happening?
PS: IDE Keil uVision v5.2, uC: TM4C123
The issue is at call of function Flash_WriteArray().
In Flash_WriteArray(), the last parameter should be the number of words (32-bit or 4 bytes) we want to write. To write 512 bytes, this parameter should be 128 (512/4).
Writing words and reading bytes may give you an endian issue if your cpu is big endian.

Loosing some bytes on USART transmission with STM32L1XX

I'm facing a problem with the communication between my computer and my board stm32L152RE.
I try to send a string of 1024 bytes and write it on my flash board.
For that, i send packets of 32 bytes.
The algorithm is simple :
I erase my memory with enought space to write my string of 1024
I receive 32 bytes in a string buffer
I write them on the flash
I do that until i receive 1024 bytes and the I stop.
The problem is , when i print what i have in memory step by step, I only receive 16 bytes and i don't know why
Here's my code, maybe it will help understand my program
/*
* bootloader.c
*
* Created on: 9 juin 2015
* Author: tgloaguen
*/
#include "usart.h"
#include "stm32l1xx_flash.h"
#define WRITE_START_ADDR 0x08000000
#define WRITE_END_ADDR 0x08000FFF
#define FLASH_PAGE_SIZE ((uint16_t)0x100) //If a page is 256 bits
#define MY_BL_FUNCTIONS __attribute__((section(".bootsection")))
void BootLoader(void) MY_BL_FUNCTIONS;
FLASH_Status Flash_Write ( uint32_t StartAddress, uint8_t *p, uint32_t Size ) MY_BL_FUNCTIONS;
uint8_t Flash_Erase() MY_BL_FUNCTIONS;
void Receive_Data(char * buffer,int size)MY_BL_FUNCTIONS;
void Receive_Size(char * buffer, int *sizeData)MY_BL_FUNCTIONS;
void BootLoader(void) {
//clear all ITs
USART_ITConfig( USART1, USART_IT_RXNE, DISABLE );
//SendString("HELLO",USART2);
uint8_t status,i;
char buffer[33];
//en dur
uint16_t *adr = WRITE_START_ADDR;
uint16_t sizeBin = 1024,k = 0,k_hexa = 0x20;
//Receive size of BIN
// Receive_Size(buffer,&sizeBin);
Flash_Erase();
//if sizeBin ok
//receive frames
do
{
//receive 32 bytes
Receive_Data(buffer,32);
GPIO_ToggleBits(GPIOA, GPIO_Pin_5);
// //write a sector (1024k)
status = Flash_Write(adr , buffer, 0x20);
// on check si on ecrit bien au bon endroit
SendString("\r\n ", USART2);
// //increment cpt
k += 32;
adr = adr + k_hexa;
// //check CRC
// //TODO
//
} while (k < sizeBin);
SendString("nickel ", USART2);
}
void Receive_Size(char * buffer, int *sizeData) {
int i = 0;
do {
buffer[i] = Uart2ReadChar();
i++;
} while (buffer[i] != '\0');
*sizeData = (buffer[1] << 8) + buffer[0];
}
void Receive_Data(char * buffer,int size){
int i=0;
do{
buffer[i] = Uart2ReadChar();
i++;
}
while(i < size);
}
uint8_t Flash_Erase() {
uint32_t EraseCounter = 0x00, Address = 0x00;//Erase count, write address
uint32_t NbrOfPage = 0x00;//Recording to erase the pages
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;/*FLASH complete erasure marks*/
/*Unlock FLASH*/
FLASH_Unlock();
/*Calculate the number of FLASH pages need to erase */
NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;
/* Remove all hang flags */
FLASH_ClearFlag ( FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |
FLASH_FLAG_SIZERR |
FLASH_FLAG_OPTVERR );
/* Erase the FLASH page*/
for(EraseCounter = 0; (EraseCounter <NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
{
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
}
FLASH_Lock ( );
return (uint8_t)FLASHStatus;
}
FLASH_Status Flash_Write ( uint32_t StartAddress, uint8_t *p, uint32_t Size )
{
uint32_t Address;
__IO FLASH_Status status = FLASH_COMPLETE;
Address = StartAddress;
/* Unlock the FLASH Program memory */
FLASH_Unlock ();
/* Clear all pending flags */
FLASH_ClearFlag ( FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |
FLASH_FLAG_SIZERR |
FLASH_FLAG_OPTVERR );
while ( Address < StartAddress + Size )
{
status = FLASH_FastProgramWord ( Address, *(uint32_t *)p );
//debug
SendChar('|',USART2);
SendChar(*p,USART2);
Address = Address + 4;
p = p + 4;
if ( status != FLASH_COMPLETE ) return status;
}
/* Lock the FLASH Program memory */
FLASH_Lock ( );
return status;
}

Resources