I need to transfer data to BeagleBone Black via Modbus RTU using Rs485. To work with Modbus RTU,but I don't know how to toggle rts in rs-485.HELP
Modbus RTU data transmission code
how to add RS485 code to this,to use the Modbus library libmodbus
#include "modbus-rtu.h"
#include <stdio.h>
#include <errno.h>
int main(){
int connected;
modbus_t *ctx;
uint16_t tab_reg[64];
int rc;
int i;
ctx = modbus_new_rtu("/dev/ttyS4", 9600, 'N', 8, 1);
if(ctx == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
}
else {
modbus_set_slave(ctx, 1);
modbus_set_debug(ctx, TRUE);
connected = modbus_connect(ctx);
printf("modbus_set_slave return: %d\n", rc);
if (rc != 0)
{
printf("modbus_set_slave: %s \n"modbus_strerror(errno));
}
rc = modbus_read_registers(ctx, 0, 3, tab_reg);
for (i = 0; i < rc; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
if(rc == -1)
{
fprintf(stderr, "%s\n", modbus_strerror(errno));
}
modbus_close(ctx);
modbus_free(ctx);
}
return 0;
}
First I would check if your hardware support automatic (hardware) half-duplex direction control.
If not, then you can take a look at this answer. In there you have all the details you need to compile and install libmodbus with support for toggling the line with software.
I'm using this solution in my RPi and CHIP computers but you should be able to use it right away on your BBB. You might find a small caveat if the GPIO file name has a 3 or 4-digit number (take a look in /sys/class/gpio). If that's the case, take a look here, I had to modify the code to correct that problem.
Related
I am trying to get a temperature readout from a LM77 using I2C communication with and FTDI FT232H. I don't think it is a hardware problem since I have checked the connections along with multiple colleagues. The communication with the PC to the FT232H is okay, it is initializing and everything is good on that end. The FT232H sends a read setup byte and gets an ACK from the LM77. After that there is no more data. I expect the LM77 to send 10 bits of data for a temperature readout, but it is not. This is what the readout looks like on a logic probe.
I would expect to then see an additional two bytes come in after the ACK but am getting nothing. The code is pretty straightforward and I am using the libMPSSE I2C API. The address I am using 0x48 comes from the address given in the datasheet bit shifted right by 1. I do not understand why I am getting an ACK but no temperature readout after. The ftStatus for the read gives an error code FT_DEVICE_NOT_FOUND. I am not sure why it's giving this error code if there is an ACK.
#include <stdio.h>
#include <stdlib.h>
#include "libMPSSE_i2c.h"
#define DEVICE_ADDR 0x48
FT_STATUS ftStatus;
FT_HANDLE ftHandle;
int i2cInit(void)
{
int numChannels = 0;
FT_DEVICE_LIST_INFO_NODE chanInfo;
ChannelConfig chConfig = {.ClockRate = 100000,
.LatencyTimer = 255,
.Options = 0x0000};
ftStatus = I2C_GetNumChannels(&numChannels);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Number of channels: %d\n", numChannels);
}
ftStatus = I2C_GetChannelInfo(0, &chanInfo);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Channel info obtained\n");
}
ftStatus = I2C_OpenChannel(0, &ftHandle);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Channel opened\n");
}
ftStatus = I2C_InitChannel(ftHandle, &chConfig);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Channel initialized\n");
}
}
int lm77ReadTemp()
{
unsigned char writeBuffer[20] = {0};
unsigned char readBuffer[20] = {0};
unsigned char bytesTransferred = 0;
unsigned int bytesRead = 0;
ftStatus = I2C_DeviceRead(ftHandle, DEVICE_ADDR, 2, readBuffer, &bytesRead, I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT);
if (ftStatus != FT_OK)
{
printf("Read failed status code %d\n", ftStatus);
}
}
int main(void)
{
i2cInit();
lm77ReadTemp();
return 0;
}
The problem was on the hardware side. The MPSSE engine does not have bidirectional pins. On the FTDI chip side, you need a separate pin for SDA_out and SDA_in. There is a diagram in the FTDI documentation that shows it. If you don't have the pins connected like this you won't receive any data from the I2C slave.
I'm working on a embedded linux system (yocto based) and I'm trying to simply get a list of the camera USB video devices (webcams) numbers with the related connected usb port from a C program.
I'm able to get the devices list with vendor ID and connected port doing this:
void usbdevs()
{
libusb_device*** list=NULL;
libusb_context *context = NULL;
ssize_t count;
uint8_t port;
char ncameras=0;
libusb_init(&context);
count = libusb_get_device_list(context,&list);
for(int i=0; i < MAX_NUM_CAMS; i++)
usb_dev_list[i]=0;
for (size_t idx = 0; idx < count; ++idx) {
libusb_device *device = list[idx];
struct libusb_device_descriptor desc = {0};
libusb_get_device_descriptor(device, &desc);
port = libusb_get_port_number(device);
printf("Vendor:Device = %04x:%04x Port: %d\n", desc.idVendor, desc.idProduct,port);
}
libusb_free_device_list(list, count);
libusb_exit(context);
}
What I need now is to know (from the C application) what v4l2 device number is related to the usb camera port, eg. I've got two webcam (same vendor ID) connected which appear as /dev/video0 and /dev/video1 respectively and I can get the connected port for each one using the above code, but, how can I know which ports are connected each one?
I tried to get information from the devices using ioctl calls as it is recommended in this question but when I run the code:
int checkvideodev()
{
int fd;
struct video_capability video_cap;
struct video_window video_win;
struct video_picture video_pic;
if((fd = open("/dev/video0", O_RDONLY)) == -1){
perror("cam_info: Can't open device");
return 1;
}
if(xioctl(fd, VIDIOCGCAP, &video_cap) == -1)
perror("cam_info: Can't get capabilities");
else {
printf("Name:\t\t '%s'\n", video_cap.name);
printf("Minimum size:\t%d x %d\n", video_cap.minwidth, video_cap.minheight);
printf("Maximum size:\t%d x %d\n", video_cap.maxwidth, video_cap.maxheight);
}
if(xioctl(fd, VIDIOCGWIN, &video_win) == -1)
perror("cam_info: Can't get window information");
else
printf("Current size:\t%d x %d\n", video_win.width, video_win.height);
if(xioctl(fd, VIDIOCGPICT, &video_pic) == -1)
perror("cam_info: Can't get picture information");
else
printf("Current depth:\t%d\n", video_pic.depth);
close(fd);
return 0;
}
I've got the next errors:
cam_info: Can't get capabilities: Inappropriate ioctl for device
cam_info: Can't get window information: Inappropriate ioctl for device
cam_info: Can't get picture information: Inappropriate ioctl for device
If I'm checking through command line for instance I can get the capabilities without issues running:
v4l2-ctl --device-/dev/video0 --list-formats-ext
Any ideas how can this be done?
Thanks in advance.
I don't know if this specifically answers your question, but you can get useful information by globbing certain patterns under /dev or /sys, for example this will return the full device path (including PCI bus) of each video device,
#include <glob.h>
#include <unistd.h>
void list_videos() {
int i;
glob_t globbuf;
if (glob("/sys/class/video4linux/video*", 0, NULL, &globbuf) != 0) {
perror("glob");
return;
}
for (i=0; i < globbuf.gl_pathc; i++) {
char buf[256] = {};
if (readlink(globbuf.gl_pathv[i], buf, sizeof(buf)-1) > 0) {
puts(buf);
}
}
}
On one system with 2 cameras this prints,
../../devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1.1/2-1.1:1.0/video4linux/video0
../../devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/video4linux/video1
Other interesting glob strings include /dev/v4l/by-id/* and /dev/v4l/by-path/*.
I have weird problem. I try to communicate with ifm AY1020 via modbusTCP using libmodbus from PC.
My code looks as follow:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus/modbus.h>
int main()
{
modbus_t *ctx;
uint16_t *tab_reg;
int rc;
int i;
ctx = modbus_new_tcp("192.168.1.250", 502);
modbus_set_debug(ctx, TRUE);
tab_reg = (uint16_t *) malloc(5 * sizeof(uint16_t));
memset(tab_reg, 0, 5 * sizeof(uint16_t));
if (modbus_connect(ctx) == -1)
{
fprintf(stderr, "Connection failed: %s\n",modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
rc = modbus_read_registers(ctx, 3002, 2, tab_reg);
if (rc == -1)
{
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
for (i=0; i < rc; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
modbus_close(ctx);
modbus_free(ctx);
}
Thanks to debug I was able to get the frame that is generated in modbus_read_registers function:
[00][01][00][00][00][06][FF][03][0B][BA][00][02]
And I get this
ERROR Gateway path unavailable
Gateway path unavailable
After analysis you can find that device id in that frame is FF, but according to this error PLC expects 1.
Going further if during debugging I force change this value from FF to 01 everything works fine. It looks like it assign wrong ID.
I would be grateful for any help, advice, solution.
Best,
Paweł
Looking at the Man
You should call modbus_set_slave to set a specific destination device.
TCP
The slave number is only required in TCP if the message must reach a device on a serial network. The special value MODBUS_TCP_SLAVE (0xFF) can be used in TCP mode to restore the default value.
Emphasis mine
Your code should be
modbus_set_slave(ctx, 1);
rc = modbus_read_registers(ctx, 3002, 2, tab_reg);
I am New to audio programming.I want to create small application which is capable of playing and gives volume control . I am using alsa-lib.
I want to know what is the purpose of switch (ex.Master Playback switch), enum in mixer elements and what value should i set to those switchs .
Please suggest me some tutorial for mixer settings as well as alsa programming .
Just collecting some here, that have example code:
ALSA Programming HOWTO v.1.0.0 [alsamodular.sourceforge.net]
A tutorial on using the ALSA Audio API [equalarea.com] 2002
A close look at ALSA [volkerschatz.com]
ALSA API - Sample Programs With Source Code By Aquiles Yanez 2005
Introduction to Sound Programming with ALSA | Linux Journal (pg3 with example code) 2004
Note that some of these are old, and API may have changed in the meantime... you can also look up aplay.c (the source for the command line arecord and aplay), but that one is not the easiest to read for starters...
You'll have a tough time finding anything concrete on ALSA, as I have have found from just starting learning it too. The best place to begin is the ALSA project homepage where they link to a number of tutorials, the best one being Dr Nagorni's one IMO.
From what it sounds like you're trying to do, JACK would most likely be a quicker and easier solution, though.
Check out the docs. There are some good examples.
http://www.alsa-project.org/alsa-doc/alsa-lib/examples.html
Be aware of the safe alsa subset.
https://www.winehq.org/pipermail/wine-bugs/2009-June/179698.html
Here's something small I put together using the various sources I could find. It miiiiiiiiiight be a good starting point.
/* Compile with gcc -lasound -pthread threadaudio.c */
#include <alsa/asoundlib.h>
#include <pthread.h>
#include <stdio.h>
unsigned char audiobuffer[0x400];
pthread_mutex_t audiomutex = PTHREAD_MUTEX_INITIALIZER;
void changeaudio (int volume) {
int i;
pthread_mutex_lock(&audiomutex);
for (i = 0; i < sizeof(audiobuffer); i++)
audiobuffer[i] = (random() & 0xff) * volume / 10;
pthread_mutex_unlock(&audiomutex);
}
void *startaudio (void *param)
{
static char *device = "default";
snd_output_t *output = NULL;
int *audiostop = (int*)param;
int err;
snd_pcm_t *handle;
snd_pcm_sframes_t frames;
changeaudio(5);
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
if ((err = snd_pcm_set_params(handle,
SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
48000,
1,
100000)) < 0) { /* 0.1sec */
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
while (!*audiostop) {
err = snd_pcm_wait(handle, 1000);
if (err < 0) {
fprintf (stderr, "poll failed (%d)\n", err);
break;
}
pthread_mutex_lock(&audiomutex);
frames = snd_pcm_writei(handle, audiobuffer, sizeof(audiobuffer));
pthread_mutex_unlock(&audiomutex);
if (frames < 0)
err = snd_pcm_recover(handle, frames, 0);
if (err < 0) {
printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
break;
}
if (frames > 0 && frames < (long)sizeof(audiobuffer))
printf("Short write (expected %li, wrote %li)\n", (long)sizeof(audiobuffer), frames);
}
snd_pcm_close(handle);
}
int main(void)
{
pthread_t audiothread;
int audiostop = 0;
int volume;
pthread_create(&audiothread, NULL, startaudio, &audiostop);
while (1) {
printf("Enter volume 1 through 10. [0 to quit.]: ");
scanf("%d", &volume);
if (volume == 0) break;
changeaudio(volume);
}
audiostop = 1;
pthread_join(audiothread, NULL);
return 0;
}
And after reading the code above you'll probably want to read this article regarding (among other things) not using locks.
http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing
It's a FT2232D chip, and the LED is connected to BDBUS6.
The library is less documented than I might like (better than FTDI's own library though, which doesn't even work on modern kernels), the only example code I can find that does this uses a deprecated function (I tried, it doesn't seem to work), and I'm absolutely stumped.
The harder I try with this thing, the more difficult it seems. I'm not looking for someone to do my homework for me so much as I just need a nudge in the right direction. Any help appreciated (even speculative).
Update: I've been trying this, though ftdi_enable_bitbang() is deprecated. The following code compiles, it runs without barfing, but no blinkenlighten. Schematics of the device in question are available at http://www.semtech.com/images/datasheet/sx1211ska_v1_std.pdf , page 23. BDBUS6 and BDBUS7 are hooked up to the LEDs.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <ftdi.h>
#define FTDI_VID 0x0403
#define FTDI_PID 0x6010
static struct ftdi_context ftdic_context;
int main(void) {
int ret;
unsigned int i;
unsigned char c = 0;
// Initialize bitbang.
// ret = ft2232_bb_init();
ftdi_usb_open(&ftdic_context, FTDI_VID, FTDI_PID);
ftdi_set_interface(&ftdic_context, INTERFACE_B);
ftdi_enable_bitbang(&ftdic_context, 0xb0);
// Trying to blink some lights.
printf("\nNow let's try to blinkenlights...\n");
for (i = 0; i < 20; i++) {
c ^= 0x80;
ftdi_write_data(&ftdic_context, &c, 1);
sleep(1);
}
return EXIT_SUCCESS;
}
You need to initialize the ftdi context before you can open a device with it.
ftdi_init(&ftdic_context);
Also you need to set the interface channel before you open the device.
Heres the function I use to set up a ftdi context
int initFTDI(struct ftdi_context * ftdic)
{
unsigned char Mask = 0x1F;
int ret=0;
fprintf(stderr,"start init\n");
ftdi_init(ftdic);
//for multi-channel ftdi chips eg(ft2232)
if(ftdi_set_interface(ftdic,INTERFACE_B))
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if((ret = ftdi_usb_open(ftdic, VID, PID)) < 0){
fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret, ftdi_get_error_string(ftdic));
return EXIT_FAILURE;
}
if(ftdi_usb_reset(ftdic))
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_usb_purge_buffers(ftdic)) //clean buffers
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_write_data_set_chunksize(ftdic,65536)) //64k transfer size
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_read_data_set_chunksize(ftdic,4096)) //64k transfer size
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_set_event_char(ftdic,false,0)) //disable event chars
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_set_error_char(ftdic,false,0)) //disable error chars
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_set_latency_timer(ftdic,2)) //Set the latency timer to 1mS (default is 16mS)
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_set_baudrate(ftdic,921600))
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if(ftdi_setflowctrl(ftdic,SIO_RTS_CTS_HS)) //set flow control
fprintf(stderr,"%s\n",ftdi_get_error_string(ftdic));
if ((ret = ftdi_set_bitmode( ftdic, 0x00, BITMODE_RESET )) < 0 )
{
fprintf(stderr, "can't set bitmode to %x: %d (%s)\n", BITMODE_RESET, ret, ftdi_get_error_string(ftdic));
fprintf( stderr, "RESET\n" );
return EXIT_FAILURE;
}
if ((ret = ftdi_set_bitmode( ftdic, Mask, BITMODE_BITBANG )) < 0 )
fprintf(stderr, "can't set bitmode to %x: %d (%s)\n", BITMODE_BITBANG, ret, ftdi_get_error_string(ftdic));
fprintf( stderr, "RESET\n" );
return EXIT_FAILURE;
}
//fprintf(stderr,"end init\n");
return ret;
}
ftdi_enable_bitbang
is deprecated,
you should use
ftdi_set_bitmode(&ftdic, LED,BITMODE_BITBANG);
instead, see the documentation:
Same Answer as here: I'm having trouble finding example code for libftdi's mpsse (SPI) mode
http://flashrom.org/Downloads
Its mainly MPSSE mode, but it also sets the nCS signal via bitbang command.