I have read that the TSS contains information about registers, etc. Right now, I am trying to implement the switch from kernel to user mode and back. I have read the the Intel 80386 manual, and was looking at this resource: http://www.brokenthorn.com/Resources/OSDev23.html for a general workflow. They do this:
void install_tss (uint32_t idx, uint16_t kernelSS, uint16_t kernelESP) {
//! install TSS descriptor
uint32_t base = (uint32_t) &TSS;
gdt_set_descriptor (idx, base, base + sizeof (tss_entry),
I86_GDT_DESC_ACCESS|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_DPL|I86_GDT_DESC_MEMORY,
0);
//! initialize TSS
memset ((void*) &TSS, 0, sizeof (tss_entry));
TSS.ss0 = kernelSS;
TSS.esp0 = kernelESP;
TSS.cs=0x0b;
TSS.ss = 0x13;
TSS.es = 0x13;
TSS.ds = 0x13;
TSS.fs = 0x13;
TSS.gs = 0x13;
//! flush tss
flush_tss (idx * sizeof (gdt_descriptor));
}
I am confused as to why RPL = 3
In my case, when I am in user mode and I want to use a trap gate to get to kernel mode, the cs segment in the trap gate would have RPL 0 (the last 2 bits of the 16 bit segment) and the GDT entry corresponding to the cs segment would also have DPL 0. And I've read that an inter-level privilege switch switches stacks (only??) looking at the TSS. I'm guessing that the above piece of code must have a TSS.ss = 0x10.
Note: We're assuming the classic 0x08 = Kernel code, 0x10 = Kernel data, .... GDT structure here
The TSS structure has a lot of fields that are used for hardware task switching (e.g. TSS.ss, which is where the ss register's contents would be saved/loaded if a hardware task switch happened), plus a few fields that are used for switching the task to a higher privilege level ((e.g. (e.g.TSS.ss0` for switching to CPL=0).
You're looking at fields that are used for hardware task switching (which typically aren't worth bothering with because it's faster to do software task switching instead); and I'd guess someone shoved some "hardware task switch compatible" values in there (even though they're not used) to avoid uninitialized values.
Instead, you want to look at the TSS.esp0 and TSS.ss0 fields of the TSS, which are the only 2 fields of the TSS that matter for switching to CPL=0 (and might be the only 2 fields of the TSS you ever use).
Related
ARM Cortex supports bit-banded memory, where individual bits are mapped to "bytes" in certain regions. I believe that only certain parts of RAM are bit-banded. I'd like to use bit-banding from C and C++.
How do I this? It seems I'd need to:
Tell the compiler to place certain variables in bit-banded regions. How? What if the variables are elements of a struct?
Tell the compiler, when I want to access a bit, to turn if (flags & 0x4) into if (flags_bb_04). Ideally, I'd like this to be automatic, and to fall back to the former if bit banding isn't available.
The simplest solution is to use regular variables and access them through thier bit-band address. For that you do not need to "tell the compiler" anything. For example, given:
extern "C" volatile uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
volatile uint32_t* bit_address = 0;
uint32_t addr = reinterpret_cast<uint32_t>(address);
// This bit maniplation makes the function valid for RAM
// and Peripheral bitband regions
uint32_t word_band_base = addr & 0xf0000000;
uint32_t bit_band_base = word_band_base | 0x02000000;
uint32_t offset = addr - word_band_base;
// Calculate bit band address
bit_address = reinterpret_cast<volatile uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));
return bit_address ;
}
you could create a 32bit "array" thus:
uint32_t word = 0 ;
uint32_t* bits = getBitbandAddress( word, 0 ) ;
bits[5] = 1 ; // word now == 32 (bit 5 set).
Now if you have a part with external or CCM memory for example that is not bitbandable, you do need to ensure that the linker ( not the compiler) places the normal memory object in bitbandable memory. How that is done is toolchain specific but in gnu for example you might have:
uint32_t word __attribute__ ((section ("ISRAM1"))) = 0 ;
Bitbanding is perhaps most useful for atomically accessing individual bits in peripheral registers. For fast and thread-safe access.
Some compilers are bitband aware and may automatically optimise single bit bitfield access using bitbanding. So for example;
struct
{
bit1 : 1 ;
bit2 : 1 ;
} bits __attribute__ ((section ("BITBANDABLE")));
The compiler (at least armcc v5) may optimise this to utilise the bitband access to bits.bit1 and bits.bit2. YMMV.
There are quite a few similar questions, but none seem to have quite the same issue. I am connecting an STML4 MCU to a 6-axis sensor (LSM6DS3). I have successfully implemented everything in I2C, but would like the extra speed of SPI (and DMA, if I can get these first steps working...). So for a first step, I am trying to read the WHO_AM_I register (0x0F) of the device, which should reply with 0x69. Here is the code:
uint8_t who = 0;
// Sanity check/debugging aid should get 0x5D
who = 0x43 + 0x1A;
// Set SS low
GPIO_WritePin (GPIOB, LL_GPIO_PIN_7, GPIO_PIN_RESET);
// while tx buffer is in use, wait
while (!LL_SPI_IsActiveFlag_TXE(SPI1));
// Send READ command to the WHO_AM_I register
(SPI1->DR) = 0x8F;
// while rx buffer is in use, wait
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
// Get data off the register
who = (SPI1->DR);
// Wait for everything to wrap up before setting SS high again
while (LL_SPI_IsActiveFlag_BSY(SPI1));
// OK, now we can set SS high
GPIO_WritePin (GPIOB, LL_GPIO_PIN_7, GPIO_PIN_SET);
On the scope/analyzer, I see everything run as expected, including the sensor sending back 0x69. However, when I set a break on the other side of this code block, I see that who goes from 0 to 0x5D to 0xFF. It never reads the 0x69. I looked through other code examples and some people have a second transmit with the data set to some dummy value (usually 0xFF or 0x0), so I also tried that, but the sensor seems to get confused during the second attempt and who ends up being 0x48. I have tried every permutation of waiting for the RXNE/TXE/BSY flags that I could have, as well as many many other things to get the variable to correctly read the SPI1 data register, including reading other registers off the sensor, but all to no avail.
So then the question is, how does one correctly read values off this register?
I should also mention that I can successfully write to the device's registers. I can send the command I want, then read it back and see that it worked on the scope, even though I can never get the values assigned to a variable in code. I always get 0xFF.
I include a screen of my analyzer showing the sensor sending back 0x69 from a single read request, as well as the garbled mess it sends if I try the "dummy transmit" method.
SPI always (if the receiver is enabled) receives the data when you transfer.
This is the problem with the libraries that you do not know what is there. SPI is a lot easier to program using registers.
I assume that your data is 8bits.
You need to set the 1/4 (one byte) FIFO threshold during the SPI initialization by:
SPI1 -> CR2 |= SPI_CR2_FRXTH;
next you need to read the data from the FIFO after every write (you need also to force the compiler to use the correct size (in this case 8bits) load and store instructions):
*(volatile uint8_t *)&SPI1->DR = 0x8F; // write exactly 8 bits to the FIFO
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
dummy = *(volatile uint8_t *)&SPI-> DR;
*(volatile uint8_t *)&SPI1->DR = 0; // dummy write
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
who = *(volatile uint8_t *)&(SPI1->DR);
I do not know what is the point of using the LL libraries.
instead of
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
use registers
while (!(SPI1 -> SR & SPI_SR_RNE));
You can also wrap it into the function:
uint8_t SPI_ReadWrite8(SPI_TypeDef *spi, uint8_t data)
{
while(!(spi -> SR & SPI_SR_TXE));
*(volatile uint8_t *)&spi->DR = data;
while (!(spi -> SR & SPI_SR_RNE));
return *(volatile uint8_t *)&spi-> DR;
}
And
SPI_ReadWrite8(SPI1, 0x8f);
who = SPI_ReadWrite8(SPI1, 0);
I am working on a library for controlling the M95128-W EEPROM from an STM32 device. I have the library writing and reading back data however the first byte of each page it not as expected and seems to be fixed at 0x04.
For example I write 128 bytes across two pages starting at 0x00 address with value 0x80. When read back I get:
byte[0] = 0x04;
byte[1] = 0x80;
byte[2] = 0x80;
byte[3] = 0x80;
.......
byte[64] = 0x04;
byte[65] = 0x80;
byte[66] = 0x80;
byte[67] = 0x80;
I have debugged the SPI with a logic analyzer and confirmed the correct bytes are being sent. When using the logic analyzer on the read command the mysterios 0x04 is transmitted from the EEPROM.
Here is my code:
void FLA::write(const void* data, unsigned int dataLength, uint16_t address)
{
int pagePos = 0;
int pageCount = (dataLength + 64 - 1) / 64;
int bytePos = 0;
int startAddress = address;
while (pagePos < pageCount)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2, GPIO_PIN_SET); // WP High
chipSelect();
_spi->transfer(INSTRUCTION_WREN);
chipUnselect();
uint8_t status = readRegister(INSTRUCTION_RDSR);
chipSelect();
_spi->transfer(INSTRUCTION_WRITE);
uint8_t xlow = address & 0xff;
uint8_t xhigh = (address >> 8);
_spi->transfer(xhigh); // part 1 address MSB
_spi->transfer(xlow); // part 2 address LSB
for (unsigned int i = 0; i < 64 && bytePos < dataLength; i++ )
{
uint8_t byte = ((uint8_t*)data)[bytePos];
_spi->transfer(byte);
printConsole("Wrote byte to ");
printConsoleInt(startAddress + bytePos);
printConsole("with value ");
printConsoleInt(byte);
printConsole("\n");
bytePos ++;
}
_spi->transfer(INSTRUCTION_WRDI);
chipUnselect();
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2, GPIO_PIN_RESET); //WP LOW
bool writeComplete = false;
while (writeComplete == false)
{
uint8_t status = readRegister(INSTRUCTION_RDSR);
if(status&1<<0)
{
printConsole("Waiting for write to complete....\n");
}
else
{
writeComplete = true;
printConsole("Write complete to page ");
printConsoleInt(pagePos);
printConsole("# address ");
printConsoleInt(bytePos);
printConsole("\n");
}
}
pagePos++;
address = address + 64;
}
printConsole("Finished writing all pages total bytes ");
printConsoleInt(bytePos);
printConsole("\n");
}
void FLA::read(char* returndata, unsigned int dataLength, uint16_t address)
{
chipSelect();
_spi->transfer(INSTRUCTION_READ);
uint8_t xlow = address & 0xff;
uint8_t xhigh = (address >> 8);
_spi->transfer(xhigh); // part 1 address
_spi->transfer(xlow); // part 2 address
for (unsigned int i = 0; i < dataLength; i++)
returndata[i] = _spi->transfer(0x00);
chipUnselect();
}
Any suggestion or help appreciated.
UPDATES:
I have tried writing sequentially 255 bytes increasing data to check for rollover. The results are as follows:
byte[0] = 4; // Incorrect Mystery Byte
byte[1] = 1;
byte[2] = 2;
byte[3] = 3;
.......
byte[63] = 63;
byte[64] = 4; // Incorrect Mystery Byte
byte[65] = 65;
byte[66] = 66;
.......
byte[127] = 127;
byte[128] = 4; // Incorrect Mystery Byte
byte[129} = 129;
Pattern continues. I have also tried writing just 8 bytes from address 0x00 and the same problem persists so I think we can rule out rollover.
I have tried removing the debug printConsole and it has had no effect.
Here is a SPI logic trace of the write command:
And a close up of the first byte that is not working correctly:
Code can be viewed on gitlab here:
https://gitlab.com/DanielBeyzade/stm32f107vc-home-control-master/blob/master/Src/flash.cpp
Init code of SPI can be seen here in MX_SPI_Init()
https://gitlab.com/DanielBeyzade/stm32f107vc-home-control-master/blob/master/Src/main.cpp
I have another device on the SPI bus (RFM69HW RF Module) which works as expected sending and receiving data.
The explanation was actually already given by Craig Estey in his answer. You do have a rollover. You write full page and then - without cycling the CS pin - you send INSTRUCTION_WRDI command. Guess what's the binary code of this command? If you guessed that it's 4, then you're absolutely right.
Check your code here:
chipSelect();
_spi->transfer(INSTRUCTION_WRITE);
uint8_t xlow = address & 0xff;
uint8_t xhigh = (address >> 8);
_spi->transfer(xhigh); // part 1 address MSB
_spi->transfer(xlow); // part 2 address LSB
for (unsigned int i = 0; i < 64 && bytePos < dataLength; i++ )
{
uint8_t byte = ((uint8_t*)data)[bytePos];
_spi->transfer(byte);
// ...
bytePos ++;
}
_spi->transfer(INSTRUCTION_WRDI); // <-------------- ROLLOEVER!
chipUnselect();
With these devices, each command MUST start with cycling CS. After CS goes low, the first byte is interpreted as command. All remaining bytes - until CS is cycled again - are interpreted as data. So you cannot send multiple commands in a single "block" with CS being constantly pulled low.
Another thing is that you don't need WRDI command at all - after the write instruction is terminated (by CS going high), the WEL bit is automatically reset. See page 18 of the datasheet:
The Write Enable Latch (WEL) bit, in fact, becomes reset by any of the
following events:
• Power-up
• WRDI instruction execution
• WRSR instruction completion
• WRITE instruction completion.
Caveat: I don't have a definitive solution, just some observations and suggestions [that would be too large for a comment].
From 6.6: Each time a new data byte is shifted in, the least significant bits of the internal address counter are incremented. If more bytes are sent than will fit up to the end of the page, a condition known as “roll-over” occurs. In case of roll-over, the bytes exceeding the page size are overwritten from location 0 of the same page.
So, in your write loop code, you do: for (i = 0; i < 64; i++). This is incorrect in the general case if the LSB of address (xlow) is non-zero. You'd need to do something like: for (i = xlow % 64; i < 64; i++)
In other words, you might be getting the page boundary rollover. But, you mentioned that you're using address 0x0000, so it should work, even with the code as it exists.
I might remove the print statements from the loop as they could have an effect on the serialization timing.
I might try this with an incrementing data pattern: (e.g.) 0x01,0x02,0x03,... That way, you could see which byte is rolling over [if any].
Also, try writing a single page from address zero, and write less than the full page size (i.e. less that 64 bytes) to guarantee that you're not getting rollover.
Also, from figure 13 [the timing diagram for WRITE], it looks like once you assert chip select, the ROM wants a continuous bit stream clocked precisely, so you may have a race condition where you're not providing the data at precisely the clock edge(s) needed. You may want to use the logic analyzer to verify that the data appears exactly in sync with clock edge as required (i.e. at clock rising edge)
As you've probably already noticed, offset 0 and offset 64 are getting the 0x04. So, this adds to the notion of rollover.
Or, it could be that the first data byte of each page is being written "late" and the 0x04 is a result of that.
I don't know if your output port has a SILO so you can send data as in a traditional serial I/O port or do you have to maintain precise bit-for-bit timing (which I presume the _spi->transfer would do)
Another thing to try is to write a shorter pattern (e.g. 10 bytes) starting at a non-zero address (e.g. xhigh = 0; xlow = 4) and the incrementing pattern and see how things change.
UPDATE:
From your update, it appears to be the first byte of each page [obviously].
From the exploded view of the timing, I notice SCLK is not strictly uniform. The pulse width is slightly erratic. Since the write data is sampled on the clock rising edge, this shouldn't matter. But, I wonder where this comes from. That is, is SCLK asserted/deasserted by the software (i.e. transfer) and SCLK is connected to another GPIO pin? I'd be interested in seeing the source for the transfer function [or a disassembly].
I've just looked up SPI here: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus and it answers my own question.
From that, here is a sample transfer function:
/*
* Simultaneously transmit and receive a byte on the SPI.
*
* Polarity and phase are assumed to be both 0, i.e.:
* - input data is captured on rising edge of SCLK.
* - output data is propagated on falling edge of SCLK.
*
* Returns the received byte.
*/
uint8_t SPI_transfer_byte(uint8_t byte_out)
{
uint8_t byte_in = 0;
uint8_t bit;
for (bit = 0x80; bit; bit >>= 1) {
/* Shift-out a bit to the MOSI line */
write_MOSI((byte_out & bit) ? HIGH : LOW);
/* Delay for at least the peer's setup time */
delay(SPI_SCLK_LOW_TIME);
/* Pull the clock line high */
write_SCLK(HIGH);
/* Shift-in a bit from the MISO line */
if (read_MISO() == HIGH)
byte_in |= bit;
/* Delay for at least the peer's hold time */
delay(SPI_SCLK_HIGH_TIME);
/* Pull the clock line low */
write_SCLK(LOW);
}
return byte_in;
}
So, the delay times need be at least the ones the ROM needs. Hopefully, you can verify that is the case.
But, I also notice that on the problem byte, the first bit of the data appears to lag its rising clock edge. That is, I would want the data line to be stabilized before clock rising edge.
But, that assumes CPOL=0,CPHA=1. Your ROM can be programmed for that mode or CPOL=0,CPHA=0, which is the mode used by the sample code above.
This is what I see from the timing diagram. It implies that the transfer function does CPOL=0,CPHA=0:
SCLK
__
| |
___| |___
DATA
___
/ \
/ \
This is what I originally expected (CPOL=0,CPHA=1) based on something earlier in the ROM document:
SCLK
__
| |
___| |___
DATA
___
/ \
/ \
The ROM can be configured to use either CPOL=0,CPHA=0 or CPOL=1,CPHA=1. So, you may need to configure these values to match the transfer function (or vice-versa) And, verify that the transfer function's delay times are adequate for your ROM. The SDK may do all this for you, but, since you're having trouble, double checking this may be worthwhile (e.g. See Table 18 et. al. in the ROM document).
However, since the ROM seems to respond well for most byte locations, the timing may already be adequate.
One thing you might also try. Since it's the first byte that is the problem, and here I mean first byte after the LSB address byte, the memory might need some additional [and undocumented] setup time.
So, after the transfer(xlow), add a small spin loop after that before entering the data transfer loop, to give the ROM time to set up for the write burst [or read burst].
This could be confirmed by starting xlow at a non-zero value (e.g. 3) and shortening the transfer. If the problem byte tracks xlow, that's one way to verify that the setup time may be required. You'd need to use a different data value for each test to be sure you're not just reading back a stale value from a prior test.
I am trying to read the data from FXLS8471Q 3-Axis, Linear Accelerometer using SPI. I am using bit banging method to read the data from Accelerometer. I am using LPC 2184 ARM processor. I used the following code.
unsigned char spiReadReg (const unsigned char regAddr)
{
unsigned char SPICount;
unsigned char SPIData;
SPI_CS = 1;
SPI_CK = 0;
SPIData = regAddr;
SPI_CS = 0;
for (SPICount = 0; SPICount < 8; SPICount++)
{
if (SPIData & 0x80)
SPI_MOSI = 1;
else
SPI_MOSI = 0;
SPI_CK = 1;
SPI_CK = 0;
SPIData <<= 1;
}
SPI_MOSI = 0;
SPIData = 0;
for (SPICount = 0; SPICount < 8; SPICount++)
{
SPIData <<=1;
SPI_CK = 1;
SPIData += SPI_MISO;
SPI_CK = 0;
SPIData &=(0xFE);
}
SPI_CS = 1;
return ((unsigned char)SPIData);
}
But instead of getting valid value 0x6A , I am getting garbage value.
Please help me out to solve this problem;
SPIData &=(0xFE); as pointed out in another answer, is definitely wrong as it erases the bit you just received.
However, there are other major issues with your code.
An SPI slave device sends you data by setting the value of MISO on a rising or falling clock, depending on the type of device. However, you didn't wait in your code for the value to appear on MISO.
You control the communication by setting the clock to 1 and 0. The datasheet of the accelerometer says on page 19, that
Data is sampled during the rising edge of SCLK and set up during the falling edge of SCLK.
This means that in order to read from it, your processor needs to change the clock from one to zero, thereby signaling the accelerometer to send the next bit to the MISO. This means you did the reverse, you in your code read on a rising edge while you should be reading on the falling edge. After setting the clock to zero, you have to wait a little while until the value appears on MISO, and only then should you read it and add it to your SPIData variable. Table 9, SPI timing indicates how much you have to wait: at least 500 nanoseconds. That's not much, but if your CPU runs faster than 2 MHz then if you don't use a delay, you will try to read the MISO before the accelerometer had time to properly set it.
You also forgot the slave Select, which is actually required to indicate the beginning and the end of a datagram.
Check the Figure 7. SPI Timing Diagram in the datasheet, it indicates what you are required to do and in what order, to communicate with the device using SPI.
I also suggest reading about how the rotating registers of the SPI work, because it seems from its datasheet, that the accelerometer needs to receive a well specified number of bits before useful data appears on its output. Don't forget, as you send a single bit to the device, it also has to send a bit back to you, so if it didn't decode a command yet, it can only send gibberish. Your code, as the master, can only "push" bits in, and collect the bits which "pop out" on the other side. This means you have to send a command, and then send further bits until all the answer is pushed out to you bit by bit.
If you get stuck, I think you will have much more luck getting help on https://electronics.stackexchange.com/, but instead of just putting this same code there (which seems to be blindly copied from www.maximintegrated.com and has absolutely nothing to do with the problem you try to solve), I strongly recommend trying to understand the "Figure 7. SPI Timing Diagram" I was suggesting before, and alter your code accordingly.
Without understanding how the device you try to communicate with works, you will never succeed if you just blindly copy the code from a completely different project just because it says "spi" in the title.
SPIData &=(0xFE);
The above line is causing the problem. Here the LSB is reset to 0 (which contained the data bit just taken from MISO) -- basically you are destroying the bit you just read. Omitting the line should correct the problem.
be sure to compile your function with NO optimization
as that will corrupt the bitbang operation.
this is the code from the maxum site for the spiReadReg function.
(which looks like were you got your code.
However, this is just a guide for the 'general' sequence of operations for communicating with the maxim 1481 part.
the accel. part needs several setup commands and reads completely differently
Suggest reading the app notes and white papers available at freescale.com for the specific part number.
Those app notes/white papers will indicate the sequence of commands needed for setting up a specific mode of operation and how to request/interpret the resulting data.
There are a number of device specifics that your code has not taken into account.
Per the spec sheet the first bit transmitted is a read/write indicator, followed by 8 bits of register address, followed by 7 trash bits (suggest sending all 0's for the trash bits.) followed by the data bits.
Depending on the setup commands, those data bits could be 8 bits or 14 bits or multiple registers of 8 or 14 bits per register.
How can i generate a unique ID in VxWorks 6.8 that are unique within a closed net?
Each device in the net requires a associated ID, set once on startup and are kept until shutdown. They don't have to be random nor cryptographically secure - just unique within the closed net.
The available length is 6 Byte.
Restrictions:
Devices may boot at once (or very close together) as well as separated in time
Devices may vary in types / architectures (however, each supports whether dTSEC or eTSEC)
Devices run with same (at least or similar) VxWorks 6.8 Kernel
ID's cant be set manually or hard coded
No 3rd Party libraries
No network communication / negotiation
I've made some attempts for testing and development purposes using some kind of "random voodoo" (e.g. see code below); until now they worked without a collision but i'm not sure if they are unique enough to stay secure.
What i need is a real solution.
At the moment i use the nanosecond time of CLOCK_MONOTONIC and an id for each microcontroller architecture:
#ifdef ARCH_1
# define MC_ARCH_ID 0x01
#elif defined(ARCH_2)
# define MC_ARCH_ID 0x02
/* ... */
#else
# define MC_ARCH_ID 0x00
#endif /* MC_ARCH_ID */
/* ... */
char id[6];
struct timespec tspec;
clock_gettime(CLOCK_MONOTONIC, &tspec);
UINT32 t = htonl(tspec.tv_nsec); /* consistent endian */
id[0] = MC_ARCH_ID; /* 1 Byte ID set for each arch. */
id[1] = (UINT8) ((UINT8*) &t)[0];
id[2] = (UINT8) ((UINT8*) &t)[1];
id[3] = (UINT8) ((UINT8*) &t)[2];
id[4] = (UINT8) ((UINT8*) &t)[3];
id[5] = 0x00; /* Not used yet */
(Hopefully) the monotonic nanoseconds are different everywhere in the net (remember: those ID's are set once at startup) - hence the ID is "unique". But as the "hopefully" indicates: there's a chance they are not. Time is not the best choice here.
As a better and more secure solution i considered the usage of the MAC-address. Unfortunately
char mac[6];
muxIoctl(muxCookie, EIOCGADDR, mac);
returns just garbage.