So I've been making an SD card music player on a DE2-155 board for a while. I've finally finished the hardware and have moved into coding in C to finish it up. However, before I can build the project I keep getting the error: "Invalid suffix "0b00100000" on integer constant."
Here is my C code:
#include <io.h>
#include <system.h>
#include "altera_up_avalon_audio_and_video_config.h"
#include "altera_up_avalon_audio.h"
#define SD_CARD_OFFSET_RXTX 0
#define SD_CARD_OFFSET_CMD 560
#define SD_CARD_OFFSET_CMD_ARG 556
#define SD_CARD_OFFSET_ASR 564
#define SD_CONNECTED 0x02
#define SD_COMPLETE 0x04
#define SD_BLOCK_SIZE 512
#define SD_CMD_READ 0x11
int main()
{
int *sd_asr = (int *)(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_BASE + SD_CARD_OFFSET_ASR);
short int sd_status;
int res;
int sector_count, byte_count;
unsigned int l_buff,r_buff;
alt_up_av_config_dev* cfg_dev;
alt_up_audio_dev* audio_dev;
/* Wait for SD-Card */
printf("Wait for SD-Card to be connected...\n");
do{
sd_status=(short int)IORD_16DIRECT(sd_asr,0);
}while((sd_status & SD_CONNECTED) == 0);
printf("SD-Card connected.\n");
/* Initialize CFG/Audio Device */
cfg_dev=alt_up_av_config_open_dev("/dev/audio_and_video_config_0");
if(cfg_dev == NULL){
printf("Config device not found.\n");
}else{
printf("Config device opened for configuration.\n");
}
printf("Resetting config device and peripherals...\n");
res = alt_up_av_config_reset(cfg_dev);
alt_up_av_config_write_audio_cfg_register(cfg_dev,0x08,0b00100000);
if(res == 0){
printf("Reset successful.\n");
}else{
printf("Reset failed.\n");
}
/* Play Music */
audio_dev = alt_up_audio_open_dev("/dev/audio_0");
if(audio_dev == NULL){
printf("Failed to open audio device.\n");
}else{
printf("Audio device opened.\n");
}
printf("Starting playback!\n");
sector_count=0;
while(1)
{
/* Read 512B sector from SD-Card */
IOWR_32DIRECT(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_BASE,SD_CARD_OFFSET_CMD_ARG,sector_count*512);
IOWR_16DIRECT(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_BASE,SD_CARD_OFFSET_CMD,SD_CMD_READ);
do{
sd_status=(short int)IORD_16DIRECT(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_BASE,SD_CARD_OFFSET_ASR);
}while((sd_status & SD_COMPLETE) != 0);
byte_count=0;
while(byte_count < 512){
l_buff = (unsigned int)IORD_16DIRECT(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_BASE,SD_CARD_OFFSET_RXTX+byte_count);
r_buff = (unsigned int)IORD_16DIRECT(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_BASE,SD_CARD_OFFSET_RXTX+(byte_count+2));
byte_count+=4;
while(alt_up_audio_write_fifo_space(audio_dev,ALT_UP_AUDIO_RIGHT) < 4){ asm("NOP"); }
alt_up_audio_write_fifo (audio_dev, &(r_buff), 1, ALT_UP_AUDIO_RIGHT);
alt_up_audio_write_fifo (audio_dev, &(l_buff), 1, ALT_UP_AUDIO_LEFT);
}
sector_count++;
}
return 0;
}
The error is on line
alt_up_av_config_write_audio_cfg_register(cfg_dev,0x08,0b00100000);
0b00100000 is an integer value. If an integer value starts with a 0, the next character must be either an x to declare the integer number as hexadecimal number, or it will be interpreted as octal number. An octal number can have only the digits 0 to 7.
0b00100000 is binary which is decimal 32 or hexadecimal 0x20.
See also Can I use a binary literal in C or C++?
A binary notation like 0b00100000 is supported only by GCC with enabled GCC extensions.
Related
I'm writing a program to get certain pieces of information from the headers in a pcap. I'm not sure if I did this right. It works with all of my professor's tests, however, there are hidden tests that I need to be aware of. It's the TCP flags I'm not sure about. It works in index 47, but don't know why, should be 46. (Ethernet Header(14) + IPv4 header(20) + 13th byte in TCP header (13) -1 (to account for arrays starting at 0) = 46). Is it a fluke that it works on spot 47?
Here's my code:
#include <pcap/pcap.h>
#include <stdlib.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
/*
* Most of this file is the background functionality to open a capture file or to
* open an inteface for a live capture. You can ignore all this unless you are
* interested in an example of how pcap works.
*
* To use the file, simply insert your code in the "Put your code here" section and
* create a Makefile for compilation.
*/
/* Maximum time that the OS will buffer packets before giving them to your program. */
#define MAX_BUFFER_TIME_MS (300)
/* Maximum time the program will wait for a packet during live capture.
* Measured in MAX_BUFFER_TIME_MS units. Program closes when it expires. */
#define MAX_IDLE_TIME 100 /* 100*MAX_BUFFER_TIME_MS idle time at most */
/* Function that creates the structures necessary to perform a packet capture and
* determines capture source depending on arguments. Function will terminate the
* program on error, so return value always valid. */
pcap_t* setup_capture(int argc, char *argv[], char *use_file);
/* Cleanup the state of the capture. */
void cleanup_capture(pcap_t *handle);
/* Check for abnormal conditions during capture.
* 1 returned if a packet is ready, 0 if a packet is not available.
* Terminates program if an unrecoverable error occurs. */
char valid_capture(int return_value, pcap_t *pcap_handle, char use_file);
int main(int argc, char *argv[]) {
pcap_t *pcap_handle = NULL; /* Handle for PCAP library */
struct pcap_pkthdr *packet_hdr = NULL; /* Packet header from PCAP */
const u_char *packet_data = NULL; /* Packet data from PCAP */
int ret = 0; /* Return value from library calls */
char use_file = 0; /* Flag to use file or live capture */
/* Setup the capture and get the valid handle. */
pcap_handle = setup_capture(argc, argv, &use_file);
/* Loop through all the packets in the trace file.
* ret will equal -2 when the trace file ends.
* ret will never equal -2 for a live capture. */
ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);
struct ether_header
{
u_int8_t ether_dhost[6]; /* destination eth addr */
u_int8_t ether_shost[6]; /* source ether addr */
u_int16_t ether_type; /* packet type ID field */
};
struct ether_header *eptr;
char src[INET_ADDRSTRLEN];
char dst[INET_ADDRSTRLEN];
char src6[INET6_ADDRSTRLEN];
char dst6[INET6_ADDRSTRLEN];
while( ret != -2 ) {
if( valid_capture(ret, pcap_handle, use_file) ){
eptr = (struct ether_header *) packet_data;
fprintf(stdout,"%s -> ",ether_ntoa((const struct ether_addr *)&eptr->ether_shost));
fprintf(stdout,"%s \n",ether_ntoa((const struct ether_addr *)&eptr->ether_dhost));
if(packet_data[12] == 0x08 && packet_data[13] == 0x00)
{
printf(" [IPv4] ");
fprintf(stdout,"%s -> ", inet_ntop(AF_INET,(const void *)packet_data+26,src,INET_ADDRSTRLEN));
fprintf(stdout,"%s\n", inet_ntop(AF_INET,(const void *)packet_data+30,dst,INET_ADDRSTRLEN));
if(packet_data[23] == 0x06)
{
printf(" [TCP] %d -> ",packet_data[34]*256+packet_data[35]);
printf("%d ",packet_data[36]*256+packet_data[37]);
// printf("%02X ",packet_data[47]); //print out value of flag;
if(packet_data[47] & (1!=0))
printf("FIN \n");
else if((packet_data[47] == 0x02 || packet_data[47] == 0x12) & (2!=0))
printf("SYN \n");
else{
printf("\n");
}
}
else if(packet_data[23] == 0x11)
{
printf(" [UDP] %d -> ",packet_data[34]*256+packet_data[35]);
printf("%d \n",packet_data[36]*256+packet_data[37]);
}
else{
printf(" [%d] \n",packet_data[23]);
}
}
else if(packet_data[12] == 0x86 && packet_data[13] == 0xdd)
{
printf(" [IPv6] ");
printf("%s -> ", inet_ntop(AF_INET6, (const void *)packet_data+22, src6, INET6_ADDRSTRLEN));
printf("%s \n", inet_ntop(AF_INET6, (const void *)packet_data+38, dst6, INET6_ADDRSTRLEN));
if(packet_data[20] == 0x06)
{
printf(" [TCP] %d -> ",packet_data[54]*256+packet_data[55]);
printf("%d ",packet_data[56]*256+packet_data[57]);
// printf("%02X ",packet_data[67]); //print out value of flag
if(packet_data[67] & (1!=0))
printf("FIN \n");
else if((packet_data[67] == 0x02 || packet_data[67] == 0x12) & (2!=0))
printf("SYN \n");
else{
printf("\n");
}
}
else if(packet_data[20] == 0x11)
{
printf(" [UDP] %d -> ",packet_data[54]*256+packet_data[55]);
printf("%d \n",packet_data[56]*256+packet_data[57]);
}
else{
printf(" [%d] \n",packet_data[20]);
}
} else {
fprintf(stdout," [%d] \n",ntohs(eptr->ether_type));
}
}
/* Get the next packet */
ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);
}
cleanup_capture(pcap_handle);
return 0;
}
pcap_t* setup_capture(int argc, char *argv[], char *use_file) {
char *trace_file = NULL; /* Trace file to process */
pcap_t *pcap_handle = NULL; /* Handle for PCAP library to return */
char pcap_buff[PCAP_ERRBUF_SIZE]; /* Error buffer used by pcap functions */
char *dev_name = NULL; /* Device name for live capture */
/* Check command line arguments */
if( argc > 2 ) {
fprintf(stderr, "Usage: %s [trace_file]\n", argv[0]);
exit(-1);
}
else if( argc > 1 ){
*use_file = 1;
trace_file = argv[1];
}
else {
*use_file = 0;
}
/* Open the trace file, if appropriate */
if( *use_file ){
pcap_handle = pcap_open_offline(trace_file, pcap_buff);
if( pcap_handle == NULL ){
fprintf(stderr, "Error opening trace file \"%s\": %s\n", trace_file, pcap_buff);
exit(-1);
}
}
/* Lookup and open the default device if trace file not used */
else{
dev_name = pcap_lookupdev(pcap_buff);
if( dev_name == NULL ){
fprintf(stderr, "Error finding default capture device: %s\n", pcap_buff);
exit(-1);
}
/* Use buffer length as indication of warning, per pcap_open_live(3). */
pcap_buff[0] = 0;
pcap_handle = pcap_open_live(dev_name, BUFSIZ, 1, MAX_BUFFER_TIME_MS, pcap_buff);
if( pcap_handle == NULL ){
fprintf(stderr, "Error opening capture device %s: %s\n", dev_name, pcap_buff);
exit(-1);
}
if( pcap_buff[0] != 0 ) {
printf("Warning: %s\n", pcap_buff);
}
printf("Capturing on interface '%s'\n", dev_name);
}
return pcap_handle;
}
void cleanup_capture(pcap_t *handle) {
/* Close the trace file or device */
pcap_close(handle);
}
char valid_capture(int return_value, pcap_t *pcap_handle, char use_file) {
static int idle_count = 0; /* Count of idle periods with no packets */
char ret = 0; /* Return value, invalid by default */
/* A general error occurred */
if( return_value == -1 ) {
pcap_perror(pcap_handle, "Error processing packet:");
cleanup_capture(pcap_handle);
exit(-1);
}
/* Timeout occured for a live packet capture */
else if( (return_value == 0) && (use_file == 0) ){
if( ++idle_count >= MAX_IDLE_TIME ){
printf("Timeout waiting for additional packets on interface\n");
cleanup_capture(pcap_handle);
exit(0);
}
}
/* Unexpected/unknown return value */
else if( return_value != 1 ) {
fprintf(stderr, "Unexpected return value (%i) from pcap_next_ex()\n", return_value);
cleanup_capture(pcap_handle);
exit(-1);
}
/* Normal operation, packet arrived */
else{
idle_count = 0;
ret = 1;
}
return ret;
}
Here's a few sample print outs: (the left is the professors results, the right is mine, I have extra printout to see what's in that spot in the array). Thanks
0:0:86:5:80:da -> 0:60:97:7:69:ea 0:0:86:5:80:da -> 0:60:97:7:69:ea
[IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e [IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e
[TCP] 1022 -> 22 SYN | [TCP] 1022 -> 22 02 SYN
0:60:97:7:69:ea -> 0:0:86:5:80:da 0:60:97:7:69:ea -> 0:0:86:5:80:da
[IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da [IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da
[TCP] 22 -> 1022 SYN | [TCP] 22 -> 1022 12 SYN
Here's how you can locate the TCP flags:
If we assume that we are talking about Ethernet, the Ethernet frame header will be 14 bytes: a 6 byte destination followed by a 6 byte source and then a 2 byte ether type (for 802.3/SNAP/Ethernet II, which is most likely)
If the Ethertype at offset 12/13 from the start of the frame contains 0x0800, you are looking at TCP/IP.
if(frame[12]==0x08 && frame[13]==0x00) { /* IP packet inside */ }
Assuming that you have an IP Ethertype, the next byte will contain two nibble sized fields: The IP version number (likely 0x40 for you) and then the IP header length (likely 0x05). Putting those nibbles together, you would have 0x45 sitting in that field. It is very important to check that field. You could mask off the upper nibble like so:
ihl = frame[14]&0x0f;
to grab the IP header length field. This number will tell you where to find the next protocol layer's header. Typically you will have a 5 here (20 byte header), but if there are IP options, this number will be larger. Let's take this number and calculate from here:
embedded_protocol_header = frame[ihl * 4];
Next, you should verify that you actually have a TCP packet. This can be verified by examining byte offset 9 in the IP header:
ip_header_start = frame[14];
embedded_protocol = ip_header_start[9];
if(embedded_protocol == 6) { tcp_header = embedded_protocol_header; }
Now that we know it is TCP, we can grab the TCP flags. These will be at offset 13 in the TCP header:
tcp_flags = tcp_header[13];
To examine the SYN/ACK bits, you can mask everything else off:
synack = tcp_flags & 0x3f;
You can now check to see if it's a SYN ACK:
if(synack == 0x12) { /* SYN and ACK were set */
You may wonder about the 0x3f mask above. The reason for it is that the two high order bits in the TCP flags are used for ECN if the system supports ECN. If it is supported, ECN negotiation occurs during the 3 way handshake in these bits and the two low order bits in the TOS byte of the IP header (differentiated services byte). Rather than dealing with all of the possible cases, the simplest thing is to turn those bits off completely and check to see if you still have SYN and ACK.
I am trying to read one value from a memory location on the I2C bus after writing to it. I am getting strange output when I run it in the terminal.
Here is my program
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE 0x00
int main (int argc, char *argv[])
{
int file;
int addr = 0X00; /* XGPIOPS_DATA_LOW_OFFSET */
if((file = open(I2C_ADAPTER, O_RDWR)) < 0) {
printf("Failed to open the bus");
return -1;
}
if(ioctl(file, I2C_SLAVE, addr) < 0) {
printf("Unable to open device as slave %s", strerror(errno));
return -1;
}
char buf[10];
buf[0] = addr;
buf[1] = 0x10;
if(write(file, buf, 2) != 2) {
printf("Failed to write to bus %s.\n\n", strerror(errno));
}
else {
printf("Successful write\n");
printf(buf);
printf("\n\n");
}
if(read(file, buf, 2) != 2) {
printf("Failed to read from the i2c bus. %s\n\n", strerror(errno));
}
else {
printf("Successful read\n");
printf(buf);
printf("\n\n");
}
return 0;
}
The output from the program looks like this
Successful write
Successful read ��
On my terminal those blocks look more like question marks inside of diamonds. I am not sure what that corresponds to in ASCII.
Why am I not reading back that 0x10 which is the second byte after the address byte that I originally write?
Based on the first set of answers, here is the updated code:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE 0x00
int main (int argc, char *argv[])
{
int file;
long addr, reg_addr;
char *end;
if(argc == 3) {
addr = strtol(argv[1], &end, 16);
printf("Value of addr is: %ld\n", addr);
reg_addr = strtol(argv[2], &end, 16);
printf("Value of reg_addr is: %ld\n", reg_addr);
}
else {
printf("arg failed\n\n.");
addr = 0x00;
}
if((file = open(I2C_ADAPTER, O_RDWR)) < 0) {
printf("Failed to open the bus\n");
return -1;
}
if(ioctl(file, I2C_SLAVE, addr) < 0) {
printf("Unable to open device as slave \n%s\n", strerror(errno));
return -1;
}
char buf[10];
buf[0] = addr;
buf[1] = reg_addr;
buf[2] = 0x10;
if(write(file, buf, 3) != 3) {
printf("Failed to write to bus %s.\n\n", strerror(errno));
}
else {
printf("Successful write\n");
printf(buf);
printf("\n\n");
}
if(read(file, buf, 3) != 3) {
printf("Failed to read from the i2c bus.\n %s\n\n", strerror(errno));
}
else {
printf("Successful read\n");
printf("Buf = [%02X,%02X,%02X]\n", buf[0], buf[1], buf[2]);
printf("\n\n");
}
return 0;
}
At this point, whenever I use 0x00 as the addr, I get FF, FF, FF as the output, no matter what argv[2] is. Here is the applicable part of the device tree file. Note that this is being emulated, so I cannot probe the physical device.
&i2c0 {
status = "okay";
clock-frequency = <400000>;
pinctrl-names = "default";
i2cswitch#74 {
compatible = "nxp,pca9548";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x74>;
i2c#0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
si570: clock-generator#5d {
#clock-cells = <0>;
compatible = "silabs,si570";
temperature-stability = <50>;
reg = <0x5d>;
factory-fout = <156250000>;
clock-frequency = <148500000>;
};
};
i2c#2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
eeprom#54 {
compatible = "at,24c08";
reg = <0x54>;
};
};
i2c#3 {
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
gpio#21 {
compatible = "ti,tca6416";
reg = <0x21>;
gpio-controller;
#gpio-cells = <2>;
};
};
i2c#4 {
#address-cells = <1>;
#size-cells = <0>;
reg = <4>;
rtc#51 {
compatible = "nxp,pcf8563";
reg = <0x51>;
};
};
i2c#7 {
#address-cells = <1>;
#size-cells = <0>;
reg = <7>;
hwmon#52 {
compatible = "ti,ucd9248";
reg = <52>;
};
hwmon#53 {
compatible = "ti,ucd9248";
reg = <53>;
};
hwmon#54 {
compatible = "ti,ucd9248";
reg = <54>;
};
};
};
};
Here are a couple of example tests
Try to test the SiLabs clock generator
root#plnx_arm:~# /usr/bin/i2c-test-mem-location 0x54 0x00
Value of addr is: 84
Value of reg_addr is: 0
Unable to open device as slave
Device or resource busy
Try to test the eeprom device
root#plnx_arm:~# /usr/bin/i2c-test-mem-location 0x5d 0x00
Value of addr is: 93
Value of reg_addr is: 0
Unable to open device as slave
Device or resource busy
This is my program on the third try. After taking to mind the notes made in the answers, I have this written
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define DEVICE_ADDRESS 0x54
int main (int argc, char *argv[])
{
int file;
uint8_t reg, value;
char *end;
printf("The device address on the bus: %d", DEVICE_ADDRESS);
if(argc == 3) {
reg = strtol(argv[1], &end, 16);
printf("Value of register address: %d\n", reg);
value = strtol(argv[2], &end, 16);
printf("value to write is: %d\n", value);
}
else {
printf("arg failed\n\n.");
}
if((file = open(I2C_ADAPTER, O_RDWR)) < 0) {
printf("Failed to open the bus\n");
return -1;
}
if(ioctl(file, I2C_SLAVE, DEVICE_ADDRESS) < 0) {
printf("Unable to open device as slave \n%s\n", strerror(errno));
return -1;
}
char buf[10];
buf[0] = reg;
buf[1] = value;
if(write(file, buf, 2) != 2) {
printf("Failed to write to bus %s.\n\n", strerror(errno));
}
else {
printf("Successful write\n");
printf(buf);
printf("\n\n");
}
if(read(file, buf, 2) != 2) {
printf("Failed to read from the i2c bus.\n %s\n\n", strerror(errno));
}
else {
printf("Successful read\n");
printf("Buf = [%02X,%02X,%02X]\n", buf[0], buf[1], buf[2]);
printf("\n\n");
}
return 0;
}
Unfortunately, even still, I am getting the same error.
root#plnx_arm:~# /usr/bin/i2c-test-mem-location 0x00 0x10
The device address on the bus: 84Value of register address: 0
value to write is: 16
Unable to open device as slave
Device or resource busy
root#plnx_arm:~# /usr/bin/i2c-test-mem-location 0x30 0x10
The device address on the bus: 84Value of register address: 48
value to write is: 16
Unable to open device as slave
Device or resource busy
EDIT 2: I think you might not be setting your I2C device address correctly. What you have as your I2C_ADAPTER ("/dev/i2c-0") indicates which I2C bus the device is on. You aren't even using your I2C_DEVICE macro, but that's what you should be passing to your ioctl call (e.g. ioctl(file, I2C_SLAVE, I2C_DEVICE);) and it should be the I2C address of the device you want to access (e.g. 0x5D for the Clock Generator) instead of 0x00.
I also think your reads/writes are incorrect. Once you've specified the bus and device via open() and ioctl() you don't need to worry about those anymore. You only need to worry about the register you want to access (if your I2C device uses registers) and the actual data.
To write to your I2C device, assuming it uses a one-byte register, write a buffer of two bytes: The first is the register, the second is the value you want to write:
bool i2cdev_byte_write(int file, uint8_t reg, uint8_t val)
{
uint8_t bytes[2];
bytes[0] = reg;
bytes[1] = val;
/* Write the register followed by the value */
if (write(file, bytes, 2) != 2)
return false;
return true;
}
To read from your I2C device, assuming it uses a one-byte register, write a buffer of one byte (the register address) then read a buffer of one or more bytes (the value at that register and subsequent registers):
bool i2cdev_bytes_read(int file, uint8_t reg, unsigned int count, uint8_t *out_buf)
{
if (!out_buf)
return false;
/* Write the register */
if (write(file, ®, 1) != 1)
{
printf("Failed to write register value\n");
return false;
}
/* Read the specified number of bytes */
if (read(file, out_buf, count) != count)
{
printf("Failed to read from the i2c bus\n");
return false;
}
return true;
}
Again, note that all the above comments depend on it being an I2C device that uses a single-byte register address and that it supports auto-incrementing the register address when reading multiple bytes at a time. You'll need to check the datasheet for your I2C device to determine exactly how it needs to be accessed.
EDIT: This is a printf() newbie failure. You can't just try to printf an array of bytes. That's not how printf() works.
Try this:
printf("Buf = [%02X,%02X]\n", buf[0], buf[1]);
Also, as I wrote in my original response, you likely need to write the register address back out again prior to reading the register contents.
The i2c protocol requires that you specify a device address (i.e. 0x00) and a register address. You can then write the value (in your case, 0x10) to that register address. Try this instead:
char buf[10];
buf[0] = addr;
buf[1] = [REGISTER ADDRESS];
buf[2] = 0x10;
if(write(file, buf, 3) != 3) {
printf("Failed to write to bus %s.\n\n", strerror(errno));
}
else {
printf("Successful write\n");
printf("Addr: %02x Subaddr: %02x Value: %02x\n\n", buf[0], buf[1], buf[2]);
}
Once this write has been completed, you should be able to read with:
if(read(file, buf, 1) != 1) {
printf("Failed to read from the i2c bus. %s\n\n", strerror(errno));
}
else {
printf("Successful read\n");
printf("Value: %02x\n\n", buf[0]);
}
Based on the device tree, the address that needs to be fed to IOCtl is the i2cswitch mux address. This address is 0x74, which can be seen in the device tree. Opening the i2c-0 device file corresponds to the i2c0 entry in the device tree which is parent to the mux. When writing to EEPROM, the first byte in the buffer should be the device address, as mentioned by #AndrewCottrell. This address is 0x54. The second byte should be the data you want to write
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_SWITHC_MUX_ADDRESS 0x74
#define DEVICE_ADDRESS 0x54
...
file = open(I2C_ADAPTER, O_RDWR); /* Check for error */
ioctl(file, I2C_SLAVE_FORCE, I2C_SWITHC_MUX_ADDRESS); /* Check for error */
uint8_t reg, value;
reg = DEVICE_ADDRESS;
buf[0] = reg;
buf[1] = value;
write(file, buf, 2); /* Check for error */
read(file, buf, 1); /* Check for error */
/* buf[0] should be value*/
I also have problems reading data from the memory of an NTAG 5 boost component and I found this thread while looking for the reason for this problem. Indeed, for each I2C reading I do on the component, I receive the "FF" value. I didn't find the answer in this thread but maybe you answer my question in this thread.
I am using this source code to read from the serial port of a linux machine. I am able to read from the port, but all of the values are in ascii gibberish ( i am reading the input from an xbox controller). I know I am sending it correctly, i.e. i can see on my side I am sending -128 - 127 as a char, but when I am converting it on my linux machine using atoi its returning 0, or when I try to cast the data to int it returns -48 , equivalent to 0 in ascii.
Is there a way for me to convert the incoming ascii into a readable integer like 64 or -114? I appreciate any help, thank you.
#include <stdlib.h>
#include <stdio.h>
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
#include "rs232.h"
int main()
{
int i, n,
cport_nr=0, /* /dev/ttyS0 (COM1 on windows) */
bdrate=9600; /* 9600 baud */
unsigned char buf[4096];
char mode[]={'8','N','1',0};
if(RS232_OpenComport(cport_nr, bdrate, mode))
{
printf("Can not open comport\n");
return(0);
}
while(1)
{
n = RS232_PollComport(cport_nr, buf, 4095);
if(n > 0)
{
buf[n] = 0; /* always put a "null" at the end of a string! */
for(i=0; i < n; i++)
{
if(buf[i] < 32) /* replace unreadable control-codes by dots */
{
buf[i] = '.';
}
}
printf("received %i bytes: %s\n", n, (char *)buf);
}
#ifdef _WIN32
Sleep(100);
#else
usleep(100000); /* sleep for 100 milliSeconds */
#endif
}
return(0);
}
I have an instrument which I need to talk to by RS232. I am using C and following is the code. The problem is that, when I try to read field value (reading from meter) which is 11 byte long, one read command is reading only 8 bytes and subsequently I have to issue another read command which gives me final 3 bytes. Finally I am concatenating both read buffers to make final meaningful value.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXWAIT 30
#define BAUDRATE B9600
#define TESLAMETER "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
#define NOREAD 255
volatile int STOP = FALSE;
int fd;
struct termios oldtp, newtp;
int openComPort(void)
{
fd = open(TESLAMETER, O_RDWR | O_NOCTTY |O_NDELAY );
if (fd <0)
{
perror(TESLAMETER);
return fd;
}
else
fcntl(fd,F_SETFL,0);
tcgetattr(fd,&oldtp); /* save current serial port settings */
bzero(&newtp, sizeof(newtp));
newtp.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
newtp.c_iflag = IGNPAR | ICRNL;
newtp.c_oflag = 0;
newtp.c_lflag = 0;//ICANON;
newtp.c_cc[VINTR] = 0; /* Ctrl-c */
newtp.c_cc[VQUIT] = 0; /* Ctrl-\ */
newtp.c_cc[VERASE] = 0; /* del */
newtp.c_cc[VKILL] = 0; /* # */
newtp.c_cc[VEOF] = 4; /* Ctrl-d */
newtp.c_cc[VTIME] = 1; /* inter-character timer unused, 0.5 seconds read timeout */
newtp.c_cc[VMIN] = 0; /* blocking or non blocking read until 1 character arrives */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtp);
return fd;
}
float readMagField()
{
unsigned char cmd[]="FA0\r"; // Read Field
char buff2[11] = {0x00};
char buff3[11] = {0x00};
float fieldFloat = 0.00;
int n_written= 0, spot = 0, res;
do
{
n_written = write( fd, &cmd[spot], 1 );
spot += n_written;
} while (cmd[spot-1] != '\r' && n_written > 0);
if (n_written < 0)
{
printf("write() of 4 bytes failed!\n");
return FALSE;
}
else
{
//printf("Field Read Command sent successfully %d\n",n_written);
res = read(fd,buff2,11); // Reads 8 bytes
res = read(fd,buff3,11); // Reads remaining 3 bytes
fieldFloat = atof(strcat(buff2,buff3)); // Final string of 11 bytes here
return fieldFloat;
}
}
Is there something that I am doing or setting wrong? Because, I can read the complete set of characters in one go using Python serial module, but not in C. I am working on Ubuntu 12.04 LTS.
read() may return without reading the specified length.
read(2) - Linux manual page
RETURN VALUE
On success, the number of bytes read is returned (zero indicates end
of file), and the file position is advanced by this number. It is
not an error if this number is smaller than the number of bytes
requested; this may happen for example because fewer bytes are
actually available right now (maybe because we were close to end-of-
file, or because we are reading from a pipe, or from a terminal), or
because read() was interrupted by a signal. See also NOTES.
How about retrying until the desired length of data have been read?
ssize_t read2(int fd, void *buf, size_t count) {
ssize_t read_length = 0;
while (read_length < count) {
ssize_t delta = read(fd, buf + read_length, count - read_length);
if (delta == -1) return -1;
read_length += delta;
}
return read_length;
}
I have a problem trying to compare the uart input data (from a GPS) with '$' in order to detect a new package. I am sure that the problem is in how I manipulate the charRead variable. I tried one thousand of things, but probably because of my inexperience I have not figured out what it is the problem.
The code compiles and the data is coming all the time, but once I load the code into the beaglebone, it gets stacked but and it doesn't enter in the "if (charRead =='$')".
Thank you in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#include <iostream>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>
#include "Payload.h"
#define SLOTS "/sys/devices/bone_capemgr.9/slots"
#define CR 0x0d
#define SPACE 0x20
#define COMMA 0x2C
#define MAXSIZE 100
unsigned long time_data;
unsigned int button = 45;
int i,z =0, j=0, value;
int rx_length;
int main()
{
//uart4 configuration using termios
int fd;
//unsigned char *mess;
unsigned int value = 0;
gpio_export(button);
//Wait until the button is pushed
while (value != 1){
if (z==0){
printf("waiting\n");}
z++;
gpio_get_value(button, &value);}
//OPEN THE UART
//open uart4 for tx/rx, not controlling device
if((fd = open("/dev/ttyO4", O_RDONLY | O_NOCTTY|O_NONBLOCK)) < 0){
printf("Unable to open uart4 access.\n");
}
termios uart4;
cfsetospeed(&uart4, B9600); //Set the speed
//set attributes of uart4
uart4.c_iflag = 0;
uart4.c_oflag = 0;
uart4.c_lflag = 0;
tcsetattr(fd, TCSANOW, &uart4);
//----- CHECK FOR ANY RX BYTES -----
// Read up to 100 characters from the port if they are there
unsigned char stringRead[MAXSIZE];
unsigned char charRead;
do{
if (rx_length = read(fd, (void*)charRead, MAXSIZE)>0){
if (charRead =='$'){
i=0;
stringRead[i] = charRead; //Store in the first position of the char --> $
do {
rx_length = read(fd, (void*)charRead, MAXSIZE); //Read the next bit
if( (charRead != '\0') ) {
i++;
stringRead[i] = charRead; //write into stringRead
}
} while(charRead != 'CR'); //ASCII Carriage Return
stringRead[i+1] = charRead;
printf("%s", stringRead);
}}
if (rx_length==0){
//No data
}
gpio_get_value(button, &value);
}while (value!=0);
gpio_unexport(button);
close(fd);
return 0;
}
You're passing a cast of the variable value of charRead rather than a pointer to a memory location as the function read() expects void *.
read(fd, (void*)charRead, MAXSIZE)
You need to either read one character at a time:
read(fd, &charRead, 1)
Or change your reading logic to maximize amount read and data processing. I also recommend adding a bounds check on accessing stringRead.
// The following should handle the reading of a GPS NMEA message and display it
// I have not run the program, but compiling it was successful
// note:
// 1) the handling of the 'i' variable
// 2) the calls to reading the GPS input
// 3) the handling of error conditions
// 4) the simple logic flow
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
//#include <iostream> // this is not C++ so this line not needed
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>
#include "Payload.h"
// #define SLOTS "/sys/devices/bone_capemgr.9/slots" // not used, raises compiler warning
#define CR (0x0D)
// #define SPACE (0x20) // not used, raises compiler warning
// #define COMMA (0x2C) // not used, raises compiler warning
#define MAXSIZE (100)
#define BUTTON_PORT (45)
// unsigned long time_data; // not used, raises compiler warning
// int j=0; // not used, raises compiler warning
// int value = 0; // not used, raises compiler warning about variable masking
int main()
{
int i;
int z = 0; // flag used to control execution flow
int rx_length; // return status value from read()
//uart4 configuration using termios
int fd; // file descriptor number
//unsigned char *mess; // not used, raises compiler warning
unsigned int value = 0;
gpio_export(BUTTON_PORT);
//Wait until the button is pushed
// burn mass CPU cycles, while waiting
while (0 == value)
{
if (z==0)
{
printf("waiting\n");
z++; // to stop re-entry to this 'if' block
}
// suggest using nsleep() to free up CPU
gpio_get_value(BUTTON_PORT, &value);
} // end while
//open uart4 for rx
if((fd = open("/dev/ttyO4", O_RDONLY | O_NOCTTY|O_NONBLOCK)) < 0)
{
perror("open failed for /dev/tty04");
exit(1);
}
// implied else, open successful
termios uart4;
cfsetospeed(&uart4, B9600); //Set the speed to match the GPS output
//set attributes of uart4
// Note: probably better to read the current termois values
// then modify them to the desired states
uart4.c_iflag = 0;
uart4.c_oflag = 0;
uart4.c_lflag = 0;
tcsetattr(fd, TCSANOW, &uart4);
//----- CHECK FOR ANY RX BYTES -----
// Read up to 100 characters from the port if they are there
unsigned char stringRead[MAXSIZE]; // will contain a GPS NMEA message
unsigned char charRead; // input buffer
do{
while(1)
{
rx_length = read(fd, &charRead, 1);
if( 0 == rx_length )
{ // this will execute a lot since fd set to non-blocking
; // do nothing, while hogging CPU cycles
// suggest using nsleep() to free CPU
}
else if( 0 > rx_length )
{
perror( "read failed" );
exit(1);
}
else if (charRead =='$')
{
stringRead[0] = charRead; //Store first char of NMEA GPS message
i=1; // index for second char of NMEA message from GPS
}
else
{
stringRead[i] = charRead; //Store char
i++; // index for next char into stringRead buffer
if( MAXSIZE <= i )
{ // then overrun input buffer
perror( "read- overrun input buffer, GPS message too long");
exit(2);
}
if( CR == charRead ) //ASCII Carriage Return - end of message
{ // then, got complete message
break; // exit read loop, so can process message
}
} // end if
} // end while
stringRead[i] = '\0'; // terminate string so it can be printed
printf("%s", stringRead);
// get button state via BUTTON_PORT(45)
gpio_get_value(BUTTON_PORT, &value);
} while (value!=0); // then read next gps message
gpio_unexport(BUTTON_PORT);
close(fd);
return 0;
}