How to decrement value on a MIFARE Classic value block using PN532 reader? - rfid

I'm trying to manage value block with a Mifare Classic and PN532 reader.
I'm using an open source library named "libnfc" but I do not see anything related to value blocks in this library.
Does anyone know how I could make increment, decrement and transfer calls with this reader & library?

Have a look at the header utils/mifare.h (and its associated implementation utils/mifare.c). They contain an implementation of the MIFARE reader commands. For instance, for the increment command, you would use something like:
mp.mpv.abtValue[0] = 1;
mp.mpv.abtValue[1] = 0;
mp.mpv.abtValue[2] = 0;
mp.mpv.abtValue[3] = 0;
nfc_initiator_mifare_cmd(pnd, MC_INCREMENT, blockNumber, &mp);
Where pnd is a nfc_device *, mp is a mifare_param and you previously authenticated to that sector (see utils/nfc-mfclassic.c).

Related

Inserting and item into CComboBoxEx and ReleaseBuffer

Code:
m_cbReminderInterval.ResetContent();
for (int i = 1; i <= m_iMaxReminderInterval; i++)
{
COMBOBOXEXITEM cmbItem = {};
CString strNumber;
strNumber.Format(_T("%d"), i);
cmbItem.mask = CBEIF_TEXT;
cmbItem.iItem = static_cast<INT_PTR>(i) - 1;
cmbItem.pszText = strNumber.GetBuffer(_MAX_PATH);
strNumber.ReleaseBuffer(); // TODO: When should I release the buffer - NOW or AFTER the InsertItem call?
m_cbReminderInterval.InsertItem(&cmbItem);
}
My question is:
Is it better to use GetString instead of GetBuffer in this context? The only issue I see is that pszText is LPWSTR whereas GetString returns LPCWSTR. If I should continue to use GetBuffer then when should it actually be released? Before or after the InsertItem call?
There's a common pattern in the Windows API you'll see over and over again: Structures that are less const-correct than what would appear to be possible. Undoubtedly, some of them are oversights, but not this one: COMBOBOXEXITEM is used both to insert and query an item's data.
This is hinted to, in part, in the documentation for the pszText member:
A pointer to a character buffer that contains or receives the item's text. If text information is being retrieved, this member must be set to the address of a character buffer that will receive the text.
The second part of the contract is omitted from the documentation, sadly. When setting an item's text, the control makes a copy of the string passed in, and neither takes ownership over the pointed to data, nor modifies it. In other words: When using the COMBOBOXEXITEM structure to insert an item, all pointers can be assumed to point to const.
Following that, it is perfectly valid to pass the pointer received from GetString():
for (int i = 1; i <= m_iMaxReminderInterval; i++)
{
COMBOBOXEXITEM cmbItem = {};
CString strNumber;
strNumber.Format(_T("%d"), i);
cmbItem.mask = CBEIF_TEXT;
cmbItem.iItem = static_cast<INT_PTR>(i) - 1;
cmbItem.pszText = const_cast<TCHAR*>(strNumber.GetString());
m_cbReminderInterval.InsertItem(&cmbItem);
}
According to CSimpleStringT::GetBuffer:
If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before you use any other CSimpleStringT member methods.
You are not modifying the string, so you don't need to call ReleaseBuffer.
But as you said, it's better to use GetString, at least you indicate your intent to NOT modify it.

Passing params from alsa application to kernel driver

I try to follow the path of parameters setting from linux user space (arecord/aplay) down to kernel driver. Let's take arecords --period-size as an example.
It all starts in set_params function in aplay.c:
if (period_time > 0)
err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0);
else
err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0);
The function snd_pcm_hw_params_set_period_size_near() is defined in [pcm.c : 5186](alsa-lib https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm.c#L5186), and here my headache starts... This function starts a chain of calls to other functions which doesn't make much sense to me and doesn't seem to be leading to any end call of driver.
There is _end label so I skipped all calls like snd_pcm_hw_param_set_min() or snd_pcm_hw_param_set_max() and went to snd_pcm_hw_param_set_last() hoping for some driver invocation like:
drv->hw_params_set(...);
but instead I found an end call to:
MASK_INLINE unsigned int snd_mask_min(const snd_mask_t *mask)
{
int i;
assert(!snd_mask_empty(mask));
for (i = 0; i < MASK_SIZE; i++) {
if (mask->bits[i])
return ffs(mask->bits[i]) - 1 + (i << 5);
}
return 0;
}
where return values shall be the parameter set.
So to summarize, I found alsa-lib to be very difficult to read and understand. Maybe I am lacking some knowledge though. My question is simple, how is user space parameter passed to kernel driver. Can you provide a software path showing interfaces called?
Thanks.
The hw_params structure contains a configuration space, which is a description of all possible configurations that the device can support. Numeric parameters are described as intervals (i.e., min and max), access and format as bitmasks.
When you change one parameter, the library calls the kernel driver (SNDRV_PCM_IOCTL_HW_REFINE) to adjust all the other parameters in the hw_params structure that depend on the changed parameter.
After you have reduced the configuration space to the configuration you actually want, you call snd_pcm_hw_params() (→ SNDRV_PCM_IOCTL_HW_PARAMS) to actually configure the device for those parameters. (If some parameter has not been reduced to a single value, snd_pcm_hw_params() will choose a random one.)
snd_pcm_hw_params_set_xxx_near() is more complex because there is no SET_NEAR ioctl. This function tries to adjust the interval so that either its maximum or its minimum is the desired value, and then check whether the actual maximum or minimum is nearer.
For example, assume a device that supports period sizes of 1024, 2048, 4096, and 8192 frames. Initially, the interval is described as [1024, 8192]. When you call snd_pcm_hw_params_set_period_size_near(4000), the snd_pcm_hw_param_set_near() helper function calls set_min(4000) and set_max(4000) (on separate copies of the hw_params structure), so the intervals are [1024, 4000] and [4000, 8192]; after refining, the driver returns the intervals [1024, 2048] and [4096, 8192]. snd_pcm_hw_param_set_near() then sees that 4096 is nearest to the desired calue, so it then calls set_first on the second interval, which results in [4096, 4096].

SPI linux driver

I am trying to learn how to write a basic SPI driver and below is the probe function that I wrote.
What I am trying to do here is setup the spi device for fram(datasheet) and use the spi_sync_transfer()api description to get the manufacturer's id from the chip.
When I execute this code, I can see the data on the SPI bus using logic analyzer but I am unable to read it using the rx buffer. Am I missing something here? Could someone please help me with this?
static int fram_probe(struct spi_device *spi)
{
int err;
unsigned char ch16[] = {0x9F,0x00,0x00,0x00};// 0x9F => 10011111
unsigned char rx16[] = {0x00,0x00,0x00,0x00};
printk("[FRAM DRIVER] fram_probe called \n");
spi->max_speed_hz = 1000000;
spi->bits_per_word = 8;
spi->mode = (3);
err = spi_setup(spi);
if (err < 0) {
printk("[FRAM DRIVER::fram_probe spi_setup failed!\n");
return err;
}
printk("[FRAM DRIVER] spi_setup ok, cs: %d\n", spi->chip_select);
spi_element[0].tx_buf = ch16;
spi_element[1].rx_buf = rx16;
err = spi_sync_transfer(spi, spi_element, ARRAY_SIZE(spi_element)/2);
printk("rx16=%x %x %x %x\n",rx16[0],rx16[1],rx16[2],rx16[3]);
if (err < 0) {
printk("[FRAM DRIVER]::fram_probe spi_sync_transfer failed!\n");
return err;
}
return 0;
}
spi_element is not declared in this example. You should show that and also how all elements of that are array are filled. But just from the code that's there I see a couple mistakes.
You need to set the len parameter of spi_transfer. You've assigned the TX or RX buffer to ch16 or rx16 but not set the length of the buffer in either case.
You should zero out all the fields not used in the spi_transfer.
If you set the length to four, you would not be sending the proper command according to the datasheet. RDID expects a one byte command after which will follow four bytes of output data. You are writing a four byte command in your first transfer and then reading four bytes of data. The tx_buf in the first transfer should just be one byte.
And finally the number of transfers specified as the last argument to spi_sync_transfer() is incorrect. It should be 2 in this case because you have defined two, spi_element[0] and spi_element[1]. You could use ARRAY_SIZE() if spi_element was declared for the purpose of this message and you want to sent all transfers in the array.
Consider this as a way to better fill in the spi_transfers. It will take care of zeroing out fields that are not used, defines the transfers in a easy to see way, and changing the buffer sizes or the number of transfers is automatically accounted for in remaining code.
const char ch16[] = { 0x8f };
char rx16[4];
struct spi_transfer rdid[] = {
{ .tx_buf = ch16, .len = sizeof(ch16) },
{ .rx_buf = rx16, .len = sizeof(rx16) },
};
spi_transfer(spi, rdid, ARRAY_SIZE(rdid));
Since you have a scope, be sure to check that this operation happens under a single chip select pulse. I have found more than one Linux SPI driver to have a bug that pulses chip select when it should not. In some cases switching from TX to RX (like done above) will trigger a CS pulse. In other cases a CS pulse is generated for every word (8 bits here) of data.
Another thing you should change is use dev_info(&spi->dev, "device version %d", id)' and also dev_err() to print messages. This inserts the device name in a standard way instead of your hard-coded non-standard and inconsistent "[FRAME DRIVER]::" text. And sets the level of the message as appropriate.
Also, consider supporting device tree in your driver to read device properties. Then you can do things like change the SPI bus frequency for this device without rebuilding the kernel driver.

verilog set bus equal to array of struct bits

I'm trying to set a bus equal to a bit of a struct, for an array of structs (s.t. the array size == bus size). My struct looks like
typedef struct {
//other stuff
logic valid;
} BFRAME_OUTPUT;
And I've declared the array of structs and bus like
BFRAME_OUTPUT bframe_outs[`BSTACK_SIZE-1:0];
logic [`BSTACK_SIZE-1:0] valid;
I want to do something like either of these to simply make the valid bus equal to the valid bits for the array of structs.
assign valid[`BSTACK_SIZE-1:0] = bframe_outs[`BSTACK_SIZE-1:0].valid;
//
// or
//
for(int i = 0; i < `BSTACK_SIZE; ++i) begin
assign[i] = bframe_outs[i].valid;
end
However I get errors when trying to simulate with vcs:
Error-[XMRE] Cross-module reference resolution error
/modules/branch_stack.sv, 87
Error found while trying to resolve cross-module reference.
token 'bframe_outs'. Originating module 'branch_stack'.
Source info: assign valid[(16 - 1):0] = bframe_outs[(16 - 1):0].valid;
More importantly, there is another error which you have not shown:
Error-[PSNA] Part Select Not Allowed testbench.sv, 14 Part selects
are not allowed on arrays of classes. Source info: assign valid[(5 -
1):0] = bframe_outs[(5 - 1):0].valid; Convert the part select to
refer to each element individually.
As the error points out, you need to convert the assignment to part selection. Here, you can use one of the two ways. Either use logic as reg and use it in always block, or use logic as wire and do some other stuff.
While using it as reg, you need to extract the value in some procedural block. So, just remove the assign statement and use alway_comb. Since you have used logic here, no need to change its datatype.
always_comb
begin
for(int i = 0; i < `BSTACK_SIZE; ++i)
valid[i] = bframe_outs[i].valid;
end
Alternatively, there is a generate block to perform certain things multiple times. Note that by using generate block, you are providing continuous assignments and using logic as wire. Here, you need to provide each bit signal to the wire individually. Here, use generate as follows:
genvar i;
generate
for(i = 0; i < `BSTACK_SIZE; ++i) begin
assign valid[i] = bframe_outs[i].valid;
end
endgenerate
Refer to SystemVerilog IEEE 1800-2012 section 7.2 for structures and this link for generate blocks. I have created a working example at EDAPlayground link.

How to read from a Linux serial port

I am working on robot which has to control using wireless serial communication. The robot is running on a microcontroller (by burning a .hex file). I want to control it using my Linux (Ubuntu) PC. I am new to serial port programming. I am able to send the data, but I am not able to read data.
A few piece of code which is running over at the microcontroller:
Function to send data:
void TxData(unsigned char tx_data)
{
SBUF = tx_data; // Transmit data that is passed to this function
while(TI == 0) // Wait while data is being transmitted
;
}
I am sending data through an array of characters data_array[i]:
for (i=4; i<=6; i++)
{
TxData(data_array[i]);
RI = 0; // Clear receive interrupt. Must be cleared by the user.
TI = 0; // Clear transmit interrupt. Must be cleared by the user.
}
Now the piece of code from the C program running on Linux...
while (flag == 0) {
int res = read(fd, buf, 255);
buf[res] = 0; /* Set end of string, so we can printf */
printf(":%s:%d\n", buf, res);
if (buf[0] == '\0')
flag = 1;
}
It prints out value of res = 0.
Actually I want to read data character-by-character to perform calculations and take further decision. Is there another way of doing this?
Note: Is there good study material (code) for serial port programming on Linux?
How can I read from the Linux serial port...
This is a good guide: Serial Programming Guide for POSIX Operating Systems
The read call may return with no data and errno set to EAGAIN. You need to check the return value and loop around to read again if you're expecting data to arrive.
First, take a look at /proc/tty/driver/serial to see that everything is set up correctly (i.e., you see the signals you should see). Then, have a look at the manual page for termios(3), you may be interested in the VMIN and VTIME explanation.

Resources