Linux SMBus Block transaction types - linux

The latest SMBus spec V3.0 20th Dec 2014 shows only one type of block write/read (excluding block process call):
6.5.7 Block Write/Read
Write: Address(Wr), Command, Count = N, Byte 1, Byte 2, ..., Byte N [, PEC]
Read: Address(Wr), Command, Address(Rd), Count = N, Byte 1, Byte 2, ..., Byte N [, PEC]
However, looking at the Linux user-space interface, there are 3 block transaction types to use with ioctl I2C_SMBUS from uapi/linux/i2c.h:
#define I2C_SMBUS_BLOCK_DATA 5
#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
#define I2C_SMBUS_I2C_BLOCK_DATA 8
Following the code under drivers/i2c/* it delegates to smbus_xfer/master_xfer(if emulated) in i2c_algorithm, which is specific to an adapter/device.
1. Do all these transaction types end up following the block wire spec for SMBus 3.0?
2. And how would I decide which one I need to use?
I am creating a Java JNA interface on Raspbian GNU/Linux 10 (buster)

Do all these transaction types end up following the block wire spec for SMBus 3.0?
At the moment I'm writing the answer, I2C module within Linux kernel still doesn't support SMBus 3.0/3.1. It implements SMBus 2.0 communication.
And for the 3 types - this can't be answered. I guess no. To learn how these commands work, look into KMD sources. For example, I2C_SMBUS_I2C_BLOCK_BROKEN gets converted into I2C_SMBUS_I2C_BLOCK_DATA with the following comment:
/* Convert old I2C block commands to the new
convention. This preserves binary compatibility. */
And whether I2C_SMBUS_I2C_BLOCK_DATA follows block data protocol - it's up to the user. The command which does enforce the protocol is I2C_SMBUS_BLOCK_DATA.
And how would I decide which one I need to use?
If you want to just use block protocol, then just use I2C_SMBUS_BLOCK_DATA.
If you want more control, or want to overcome restrictions from SMBus 2.0, you'll have to use I2C_SMBUS_I2C_BLOCK_DATA. Though in these cases you will likely have to move to constructing SMBus messages manually, as I2C_SMBUS_I2C_BLOCK_DATA still keeps you quite restricted - you'll get one more byte in max message length, but it's still far from 255.
If you're writing according to SMBus 1 spec, use I2C_SMBUS_I2C_BLOCK_BROKEN when appropriate.

Related

spi_write_then_read with variant register size

As I understand the term "word length" (spi_bits_per_word) in spi, defines the CS (chip select) active time.
It therefore seems that linux driver will function correctly when dealing with simple spi protocols which keeps word size constant.
But, How can we deal with spi protocols which use different spi size as part of protocol.
for example cs need to be active for sending spi word - 9 bits, and then reading spi - 8 bits or 24 bits (the length of the register read is different each time, depends on register)
How can we implement that using spi_write_then_read ?
Do we need to set bits_per_word size for the sending and then another bits_per_word for the receiving ?
Regards,
Ran
"word length" means number of bits you can send in one transaction. It doesn't defines the CS (chip select) active time. You can keep it active for whatever time you want(least is for word-length).
SPI has got some format. You cannot randomly read-write whatever number of bits you want.Most of SPI supports 4-bit, 8-bit, 16-bit and 32-bit mode. If the given mode doesn't satisfy your requirement then you need to break your requirement. For eg:- To read 24-bit data, we need to use 8-bit word-length transfer for 3 times.
Generally SPI is fullduplex means it will read at same time it will write.

What exactly is the class byte in JavaCard?

I've started to work with the JavaCards and trying to grasp the sense of CLA byte.
If to read RFC 5.4.1 Class byte
5.4.1 Class byte
According to table 8 used in conjunction with table 9, the class byte
CLA of a command is used to indicate to what extent the command and the response comply with this part of ISO/IEC 7816 and when applicable (see table 9), the format of secure messaging and the logical channel number.
So... CLA flag is used for the indication, but what exact? Because, the table and description as for the beginner is rather difficult, I understand that usually are used the next CLA bytes: 0x00, 0x80, 0x84.
For e.g. if to read the content from table:
0X' Structure and coding of command and response according to this part of ISO/IEC 7816 (for coding of 'X' see table 9)
10 to 7F RFU
Reserved for PTS
I understand that for the fine developing - I should read GlobalPlatform specification, the specification about the exact card (mine is NXP one) and other related materials, but I want to admit, that it's difficult to understand the content.
I've expected the following (pseudo-table):
0x00 -> for reading streams from file system
0x01 -> for writing byte buffer to memory blocks
0x02 -> call AES/RSA methods
The CLASS byte is defined in ISO 7816-4. The first bit indicates the interindustry class. Java Card applets shall operate in this interindustry standard. Global Platform is another specification to manage and maintain the card and all commands will have class byte 0x80 - 0x8F. Class byte 0xFF is used for communication with the card reader in some cases and is otherwise invalid for a card.
The interindustry meaning for the CLA serves 3 major functions:
Function 1: Chaining
bit5 = 1 signalizes that the current command is not the last command of a chain, meaning that multiple APDUs all belong together and the card may therefore do additional things
Function 2: Secure Messaging
bit4+3 serve to signalize the secure messaging status of the current command. This means that the APDU is authenticated(e.g. MACed) and the data is encrypted(e.g. block cipher). The command header is never encrypted.
Function 3: Logical Channel
bit2+1 serve to identify the logical channel number. Logical channels are parallel communication interfaces through the card, therefore an applet A can be selected on Channel 0 and an applet B can be selected on Channel 1 while both applets remain in their internal state(no RAM is reset). Most cards do not support logical channels or you have to enable them explicitly.
CLA byte is a typical trap for Java Card beginners and its usually best that you leave at 0x00 for the start.

what is the meaning of this macro _IOR(MY_MACIG, 0, int)?

i was going through ioctl sample programs to check how it communicates with kernel space. in program WRITE_IOCTL is used as command
#define WRITE_IOCTL _IOW(MY_MACIG, 1, int)
ioctl(fd, WRITE_IOCTL, "hello world")
I am not able to understand what is _IOW(MY_MACIG, 1, int).
here is the link from where i downloaded the program. please help me.
http://people.ee.ethz.ch/~arkeller/linux/multi/kernel_user_space_howto-4.html
As you may know, an ioctl should be unique, as explained in the Linux Device Drivers book:
The ioctl command numbers should be unique across the system in order
to prevent errors caused by issuing the right command to the wrong
device.Such a mismatch is not unlikely to happen, and a program might
find itself trying to change the baudrate of a non-serial-port input
stream, such as a FIFO or an audio device. If each ioctl number is
unique, the application gets an EINVAL error rather than succeeding in
doing something unintended.
Furthermore, an ioctl can require to write data to and/or read data from kernel space.
When one creates it's own driver that performs ioctls, he will need to describe all this in the ioctl command.
_IO, _IOW, _IOR, _IORW are helper macros to create a unique ioctl identifier and add the required R/W needed features (direction).
These can take the following params: magic number, the command id, and the data type that will be passed (if any)
The magic number is a unique number that will allow the driver to detect errors such as the one mentioned in the LDD book's quote.
The command id, is a way for your dirver to understand what command is needed to be called.
Last parameter (the type) will allow the kernel to understand the size to be copied.
hope this helps.
PS: you can have more details in Linux Device Drivers book (chapter 6)
https://lwn.net/images/pdf/LDD3/ch06.pdf
From http://www.circlemud.org/jelson/software/fusd/docs/node31.html:
The Linux header file /usr/include/asm/ioctl.h defines macros that must be used to create the ioctl command number. These macros take various combinations of three arguments:
type, an 8-bit integer selected to be specific to the device driver. type should be chosen so as not to conflict with other drivers that might be ``listening'' to the same file descriptor. (Inside the kernel, for example, the TCP and IP stacks use distinct numbers since an ioctl sent to a socket file descriptor might be examined by both stacks.)
number, an 8-bit integer command number. Within a driver, distinct numbers should be chosen for each different kind of ioctl command that the driver services
data_type, the name of a type used to compute how many bytes are exchanged between the client and the driver. This argument is, for example, the name of a structure.
The macros used to generate command numbers are:
_IO(int type, int number), used for a simple ioctl that sends nothing but the type and number, and receives back nothing but an (integer) retval
_IOR(int type, int number, data_type), used for an ioctl that reads data from the device driver. The driver will be allowed to return sizeof(data_type) bytes to the user
_IOW(int type, int number, data_type), similar to _IOR, but used to write data to the driver
_IORW(int type, int number, data_type), a combination of _IOR and _IOW. That is, data is both written to the driver and then read back from the driver by the client

c++ serial communication linux 9data bits

a bit exotic question :D
I'm programming c++ in ubuntu 10 and i need to code a mdb(multi drop bus) protocol which uses 9 data bits in serial communication (YES 9 data bits :D)
Some drivers do support 9 data bits on some uart chips, but mostly they do not.
To explain briefly:
mdb uses 8 data bits for data and 9th data bit for mode set.
So when master sends first BYTE it sets mode=9thbit to 1 which means that all devices on the bus are interrupted and are looking for this first byte that holds the address of a device.
If the listening device (one of many) finds its address in this first byte it knows that the following bytes will be data bytes for it. data bytes have bit 9 = mode bit set to 0
example in bits: 000001011 000000010 000000100 000000110 (1stbyte address and 3 data bytes)
The return situation from slave -> master mode bit is used for end of transmission.
So the master reads from serial so long until it finds a 9bit packet that has 9th bit = 1 usualy the last 9bit sequence is a chk byte + mode = 1
So finally my question:
I know how to user CMPAR flag in termios to use parity bit for mode bit eg. setting it to either MARK(1) or SPACE(0)
example FOR ALL that don't know how:
First check if this is defined if not probably no support in termios:
# define CMSPAR 010000000000 /* mark or space (stick) parity */
And the code for sending with mark or space parity eg. simulating 9th data bit
struct termios tio;
bzero(&tio, sizeof(tio));
tcgetattr(portFileDescriptor, &tio);
if(useMarkParity)
{
// Send with mark parity
tio.c_cflag |= PARENB | CMSPAR | PARODD;
tcsetattr(portFileDescriptor, TCSADRAIN, &tio);
}
else
{
// Send with space parity
tio.c_cflag |= PARENB | CMSPAR;
tio.c_cflag &= ~PARODD;
tcsetattr(portFileDescriptor, TCSADRAIN, &tio);
}
write(portFileDescriptor,DATA, DATALEN);
Now what i don't know HOW to set the parity checking on receive, i have tried almost all combinations and i cannot get that error parity byte sequence.
Can anyone help me how to set parity checking on receive that it does not ignore parity and does not strip bytes but it adds DEL before "bad" received byte:
As it says in the POSIX Serial help
INPCK and PARMRK If IGNPAR is enabled, a NUL character (000 octal) is
sent to your program before every character with a parity error.
Otherwise, a DEL (177 octal) and NUL character is sent along with
the bad character.
So how to correctly set PARMRK AND INPCK that it will detect mode bit = 1 as parity bit error and insert DEL 177 octal in the return stream.
Thank you :D
It sounds to me like you want to set space parity on the receiver and don't enable IGNPAR. That way when a byte with mark parity is received it should generate the parity error with the DEL.
I was having the same problem running in a Linux guest OS. Running the same program on another machine with Linux as the host OS works. I suspect that the virtual serial port does not pass on the parity error. See PARMRK termios behavior not working on Linux. It is still possible that the VM is not the problem because it was a completely different computer. I was able to get parity errors using Realterm in Windows (the host OS on the computer where Linux was the guest), however.
Also, note the code in n_tty.c shows it inserts '\377' '\0' rather than '\177' '\0'. This was also verified on the working configuration.

Is it possible to use 9-bit serial communication in Linux?

RS-232 communication sometimes uses 9-bit bytes. This can be used to communicate with multiple microcontrollers on a bus where 8 bits are data and the extra bit indicates an address byte (rather than data). Inactive controllers only generate an interrupt for address bytes.
Can a Linux program send and receive 9-bit bytes over a serial device? How?
The termios system does not directly support 9 bit operation but it can be emulated on some systems by playing tricks with the CMSPAR flag. It is undocumented and my not appear in all implementations.
Here is a link to a detailed write-up on how 9-bit emulation is done:
http://www.lothosoft.ch/thomas/libmip/markspaceparity.php
9-bit data is a standard part of RS-485 and used in multidrop applications. Hardware based on 16C950 devices may support 9-bits, but only if the UART is used in its 950 mode (rather than the more common 450/550 modes used for RS-232).
A description of the 16C950 may be found here.
This page summarizes Linux RS-485 support, which is baked into more recent kernels (>=3.2 rc3).
9-bit data framing is possible even if a real world UARTs doesn't.
Found one library that also does it under Windows and Linux.
See http://adontec.com/9-bit-serial-communication.htm
basically what he wants is to output data from a linux box, then send it on let's say a 2 wire bus with a bunch of max232 ic's -> some microcontroller with uart or software rs232 implementation
one can leave the individual max232 level converter's away as long as there are no voltage potency issues between the individual microcontrollers (on the same pcb, for example, rather than in different buildings ;) up until the maximum output (ttl) load of the max232 (or clones, or a resistor and invertor/transistor) ic.
can't find linux termios settings for MARK or SPACE parity (Which i'm sure the hardware uarts actually do support, just not linux tty implementation), so we shall just hackzor the actual parity generation a bit.
8 data bits, 2 stop bits is the same length as 8 databits, 1 parity bit, 1 stop bit. (where the first stopbit is a logic 1, negative line voltage).
one would then use the 9th bit as an indicator that the other 8 bits are the address of the individual or group of microcontrollers, which then take the next bytes as some sort of command, or data, as well, they are 'addressed'.
this provides for an 8 bit transparant, although one way traffic, means to address 'a lot of things' (256 different (groups of) things, actually ;) on the same bus. it's one way, for when one would want to do 2 way, you'd need 2 wire pairs, or modulate at multiple frequencies, or implement colission detection and the whole lot of that.
PIC microcontrollers can do 9 bit serial communication with ehm 'some trickery' (the 9th bit is actually in another register ;)
now... considering the fact that on linux and the likes it is not -that- simple...
have you considered simply turning parity on for the 'address word' (the one in which you need 9 bits ;) and then either setting it to odd or even, calculate it so that the right one is chosen to make the 9th (parity) bit '1' with parity on and 8 bit 'data', then turn parity back off and turn 2 stop bits on. (which still keeps a 9 bit word length in as far as your microcontroller is concerned ;)... it's a long time ago but as far as i recall stop bits are just as long as data bits in the timing of things.
this should work on anything that can do 8 bit output, with parity, and with 2 stop bits. which includes pc hardware and linux. (and dos etc)
pc hardware also has options to just turn 'parity' on or off for all words (Without actually calculating it) if i recall correctly from 'back in the days'
furthermore, the 9th bit the pic datasheet speaks about, actually IS the parity bit as in RS-232 specifications. just that you're free to turn it off or on. (on PIC's anyway - in linux it's a bit more complicated than that)
(nothing a few termios settings on linux won't solve i think... just turn it on and off then... we've made that stuff do weirder things ;)
a pic microcontroller actually does exactly the same, just that it's not presented like 'what it actually is' in the datasheet. they actually call it 'the 9th bit' and things like that. on pc's and therefore on linux it works pretty much the same way tho.
anyway if this thing should work 'both ways' then good luck wiring it with 2 pairs or figuring out some way to do collission detection, which is hell a lot more problematic than getting 9 bits out.
either way it's not much more than an overrated shift register. if the uart on the pc doesn't want to do it (which i doubt), just abuse the DTR pin to just shift out the data by hand, or abuse the printer port to do the same, or hook up a shift register to the printer port... but with the parity trick it should work fine anyway.
#include<termios.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdint.h>
#include<string.h>
#include<stdlib.h>
struct termios com1pr;
int com1fd;
void bit9oneven(int fd){
cfmakeraw(&com1pr);
com1pr.c_iflag=IGNPAR;
com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB;
cfsetispeed(&com1pr,B300);
cfsetospeed(&com1pr,B300);
tcsetattr(fd,TCSANOW,&com1pr);
};//bit9even
void bit9onodd(int fd){
cfmakeraw(&com1pr);
com1pr.c_iflag=IGNPAR;
com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB|PARODD;
cfsetispeed(&com1pr,B300);
cfsetospeed(&com1pr,B300);
tcsetattr(fd,TCSANOW,&com1pr);
};//bit9odd
void bit9off(int fd){
cfmakeraw(&com1pr);
com1pr.c_iflag=IGNPAR;
com1pr.c_cflag=CS8|CREAD|CLOCAL|CSTOPB;
cfsetispeed(&com1pr,B300);
cfsetospeed(&com1pr,B300);
tcsetattr(fd,TCSANOW,&com1pr);
};//bit9off
void initrs232(){
com1fd=open("/dev/ttyUSB0",O_RDWR|O_SYNC|O_NOCTTY);
if(com1fd>=0){
tcflush(com1fd,TCIOFLUSH);
}else{printf("FAILED TO INITIALIZE\n");exit(1);};
};//initrs232
void sendaddress(unsigned char x){
unsigned char n;
unsigned char t=0;
for(n=0;n<8;n++)if(x&2^n)t++;
if(t&1)bit9oneven(com1fd);
if(!(t&1))bit9onodd(com1fd);
write(com1fd,&x,1);
};
void main(){
unsigned char datatosend=0x00; //bogus data byte to send
initrs232();
while(1){
bit9oneven(com1fd);
while(1)write(com1fd,&datatosend,1);
//sendaddress(223); // address microcontroller at address 223;
//write(com1fd,&datatosend,1); // send an a
//sendaddress(128); // address microcontroller at address 128;
//write(com1fd,&datatosend,1); //send an a
}
//close(com1fd);
};
somewhat works.. maybe some things the wrong way around but it does send 9 bits. (CSTOPB sets 2 stopbits, meaning that on 8 bit transparant data the 9th bit = 1, in addressing mode the 9th bit = 0 ;)
also take note that the actual rs232 line voltage levels are the other way around from what your software 'reads' (which is the same as the 'inverted' 5v ttl levels your pic microcontroller gets from the transistor or inverter or max232 clone ic). (-19v or -10v (pc) for logic 1, +19/+10 for logic 0), stop bits are negative voltage, like a 1, and the same lenght.
bits go out 0-7 (and in this case: 8 ;)... so start bit -> 0 ,1,2,3,4,5,6,7,
it's a bit hacky but it seems to work on the scope.
Can a Linux program send and receive 9-bit bytes over a serial device?
The standard UART hardware (8251 etc.) doesn't support 9-bit-data modes.
I also made complete demo for 9-bit UART emulation (based on even/odd parity). You can find it here.
All sources available on git.
You can easily adapt it for your device. Hope you like it.

Resources