Difficulty establishing Bulk Transfer In USB Driver - linux

I'm trying to send BULK data using BULK end point. But each time I submit the URB, it never fires the URB Callback function until I disconnect the device. Once I disconnect, it fires the callback throwing an EPROTO error. Anyone faced similar condition? Am I doing something incorrectly? I'm sure my device and data cable is okay. Here goes my code. Please suggest possible solution
static void urb_received(struct urb *urb)
{
printk("URB Received\n");
switch (urb->status) {
case 0:
printk("case SUCCESS\n");
break;
case -ETIMEDOUT:
printk("case ETIMEDOUT\n");
return;
case -ENOENT:
printk("case ENONET\n");
return;
case -EPROTO:
printk("case EPROTO\n");
return;
case -ECONNRESET:
printk("case ECONNRESET\n");
return;
case -ESHUTDOWN:
printk("case ESHUTDOWN\n");
return;
default:
printk("unknown urb status %i\n", urb->status);
}
printk("URB Received Exit\n");
}
static int myprobe(struct usb_interface *intf,
const struct usb_device_id *id)
{
static int intfcount = 0;
int ret = 0;
int i;
struct device *dev = &intf->dev;
struct mydevice *mydev;
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct usb_host_interface *interface_descriptor;
struct usb_endpoint_descriptor *endpoint;
if (id->idVendor == MY_DEVICE_ID && id->idProduct == MY_PRODUCT_ID){
interface_descriptor = intf->cur_altsetting;
mydev = kzalloc(sizeof(struct mydev), GFP_KERNEL);
mydev->dev = dev;
mydev->udev = usb_get_dev(interface_to_usbdev(intf));
interface_descriptor = intf->cur_altsetting;
for(i=0; i<interface_descriptor->desc.bNumEndpoints; i++){
endpoint = &interface_descriptor->endpoint[i].desc;
if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
(endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK
){
printk("MEDEV: Bulk out endpoint");
mydev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
break;
}
}
bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
bulk_urb->transfer_buffer = kzalloc(8, GFP_ATOMIC);
usb_fill_bulk_urb(bulk_urb, usb_dev, usb_sndbulkpipe(mydev->udev, endpoint->bEndpointAddress),
bulk_urb->transfer_buffer, 8,
urb_received, NULL);
printk("BULK OUT PIPE = %d\n", mydev->bulk_out_pipe);
ret = usb_submit_urb(bulk_urb, GFP_ATOMIC);
return 0;
}
}
Just found out one interesting & same time annoying thing.
If in the above code I declare the usb_fill_bulk_urb with buffer_length=4, then it works perfectly. I can get the data from my android device. Even though I'm creating a buffer size of 8 bytes, I can't use buffer_length=8. I also played with other number but seems it only works for buffer_length=4.
To be sure I checked the endpoint descriptor of my device using lsusb -v command which shows it has a capacity of 512 bytes. Also in my android app, I've taken care off how many bytes I want to read. There is nothing wrong with the android app. I just can't understand why I won't be able to send more than 4 bytes at a time. By the way, if I send less than 4 bytes, that also works.

Related

ESP8266 / Arduino modbus RTU Buffer data conversion

I am using ESP8266 and ModbusMaster.h library to communicate with RS485 enabled power meter. Communication works fine but responses are the ones are confusing me and I can not get correct values. My power meter shows 1.49 kWh but response from Modbus is 16318. Here is my code:
#include <ArduinoOTA.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <ModbusMaster.h>
#include <ESP8266WiFi.h>
/*
Debug. Change to 0 when you are finished debugging.
*/
const int debug = 1;
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
int timerTask1, timerTask2, timerTask3;
float battBhargeCurrent, bvoltage, ctemp, btemp, bremaining, lpower, lcurrent, pvvoltage, pvcurrent, pvpower;
float stats_today_pv_volt_min, stats_today_pv_volt_max;
uint8_t result;
// this is to check if we can write since rs485 is half duplex
bool rs485DataReceived = true;
float data[100];
ModbusMaster node;
SimpleTimer timer;
// tracer requires no handshaking
void preTransmission() {}
void postTransmission() {}
// a list of the regisities to query in order
typedef void (*RegistryList[])();
RegistryList Registries = {
AddressRegistry_0001 // samo potrosnju
};
// keep log of where we are
uint8_t currentRegistryNumber = 0;
// function to switch to next registry
void nextRegistryNumber() {
currentRegistryNumber = (currentRegistryNumber + 1) % ARRAY_SIZE( Registries);
}
void setup()
{
// Serial.begin(115200);
Serial.begin(9600, SERIAL_8E1); //, SERIAL_8E1
// Modbus slave ID 1
node.begin(1, Serial);
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
// WiFi.mode(WIFI_STA);
while (Blynk.connect() == false) {}
ArduinoOTA.setHostname(OTA_HOSTNAME);
ArduinoOTA.begin();
timerTask1 = timer.setInterval(9000, updateBlynk);
timerTask2 = timer.setInterval(9000, doRegistryNumber);
timerTask3 = timer.setInterval(9000, nextRegistryNumber);
}
// --------------------------------------------------------------------------------
void doRegistryNumber() {
Registries[currentRegistryNumber]();
}
void AddressRegistry_0001() {
uint8_t j;
uint16_t dataval[2];
result = node.readHoldingRegisters(0x00, 2);
if (result == node.ku8MBSuccess)
{
for (j = 0; j < 2; j++) // set to 0,1 for two
datablocks
{
dataval[j] = node.getResponseBuffer(j);
}
terminal.println("---------- Show power---------");
terminal.println("kWh: ");
terminal.println(dataval[0]);
terminal.println("crc: ");
terminal.println(dataval[1]);
terminal.println("-----------------------");
terminal.flush();
node.clearResponseBuffer();
node.clearTransmitBuffer();
} else {
rs485DataReceived = false;
}
}
void loop()
{
Blynk.run();
// ArduinoOTA.handle();
timer.run();
}
I have tried similar thing but with Raspberry Pi and USB-RS485 and it works.
Sample of NodeJS code is below. It looks similar to Arduino code.
// create an empty modbus client
var ModbusRTU = require("modbus-serial");
var client = new ModbusRTU();
// open connection to a serial port
client.connectRTUBuffered("/dev/ttyUSB0", { baudRate: 9600, parity: 'even' }, read);
function write() {
client.setID(1);
// write the values 0, 0xffff to registers starting at address 5
// on device number 1.
client.writeRegisters(5, [0 , 0xffff])
.then(read);
}
function read() {
// read the 2 registers starting at address 5
// on device number 1.
console.log("Ocitavanje registra 0000: ");
client.readHoldingRegisters(0000, 12)
.then(function(d) {
var floatA = d.buffer.readFloatBE(0);
// var floatB = d.buffer.readFloatBE(4);
// var floatC = d.buffer.readFloatBE(8);
// console.log("Receive:", floatA, floatB, floatC); })
console.log("Potrosnja u kWh: ", floatA); })
.catch(function(e) {
console.log(e.message); })
.then(close);
}
function close() {
client.close();
}
This code displays 1.493748298302 in console.
How can I implement this var floatA = d.buffer.readFloatBE(0); in Arduino? Looks like that readFloatBE(0) does the trick, but available only in NodeJS / javascript.
Here i part of datasheet for my device
Here is what I am getting as result from original software that came with device:
If someone could point me in better direction I would be thenkfull.
UPDATE:
I found ShortBus Modbus Scanner software and tested readings.
Library read result as Unsigned integer, but need Floating Point and Word Order swapped. It is shown on image below.
Can someone tell how to set proper conversion please.
Right, so indeed the issue is with the part done by var floatA = d.buffer.readFloatBE(0);Modbus returns an array of bytes, and the client has to interpret those bytes, ideally done by the library you're using, but if not available on Arduino, you may try manually with byte decoding functions, with the following considerattions:
Modbus registers are 16 bit in length, so length 1 = 16 bits, length
2 = 32 bits, hence the data type noted on the docs as float32 means
"2 registers used for this value, interpret as float".
Therefore, on client.readHoldingRegisters(0000, 12)you're asking to read the register with address 00, and size 12... so this makes no sense, you only need 2 registers.
On your sample Node code, first you're writing
2 registers to address 5 in client.writeRegisters(5, [0 , 0xffff])
register 5 = 0, and register 6 = 0xFFFF, why? Then you go and read
from address 0, in read(), which is the address for Total KwH per
your docs.
So, you should get an array of bytes, and you need to
decode them as a float. Modbus is Big Endian for words and bytes, so
you need to use those in the decoding functions. I don't know exactly
what is available in Arduino, but hopefully you can figure it out
with this extra info.
I suppose that if you just send the buffer to print, you'll get an integer interpretation of the value, hence the problem

Could I/O memory access be used inside ISR under Linux (ARM)?

I'm creating driver for communication with FPGA under Linux. FPGA is connected via GPMC interface. When I tested read/write from driver context - everithing works perfectly. But the problem is that I need to read some address on interrupt. So I created interrupt handler, registred it and put iomemory reading in it (readw function). But when interrupt is fired - only zero's are readed. I tested every part of driver from the top to the bottom and it seems like the problem is in iomemory access inside ISR. When I replaced io access with constant value - it successfully passed to user-level application.
ARM version: armv7a (Cortex ARM-A8 (DM3730))
Compiler: CodeSourcery 2014.05
Here is some code from driver which represents performed actions:
// Request physical memory region for FPGA address IO
void* uni_PhysMem_request(const unsigned long addr, const unsigned long size) {
// Handle to be returned
void* handle = NULL;
// Check if memory region successfully requested (mapped to module)
if (!request_mem_region(addr, size, moduleName)) {
printk(KERN_ERR "\t\t\t\t%s() failed to request_mem_region(0x%p, %lu)\n", __func__, (void*)addr, size);
}
// Remap physical memory
if (!(handle = ioremap(addr, size))) {
printk(KERN_ERR "\t\t\t\t%s() failed to ioremap(0x%p, %lu)\n", __func__, (void*)addr, size);
}
// Return virtual address;
return handle;
}
// ...
// ISR
static irqreturn_t uni_IRQ_handler(int irq, void *dev_id) {
size_t readed = 0;
if (irq == irqNumber) {
printk(KERN_DEBUG "\t\t\t\tIRQ handling...\n");
printk(KERN_DEBUG "\t\t\t\tGPIO %d pin is %s\n", irqGPIOPin, ((gpio_get_value(irqGPIOPin) == 0) ? "LOW" : "HIGH"));
// gUniAddr is a struct which holds GPMC remapped virtual address (from uni_PhysMem_request), offset and read size
if ((readed = uni_ReadBuffer_IRQ(gUniAddr.gpmc.addr, gUniAddr.gpmc.offset, gUniAddr.size)) < 0) {
printk(KERN_ERR "\t\t\t\tunable to read data\n");
}
else {
printk(KERN_INFO "\t\t\t\tdata readed success (%zu bytes)\n", readed);
}
}
return IRQ_HANDLED;
}
// ...
// Read buffer by IRQ
ssize_t uni_ReadBuffer_IRQ(void* physAddr, unsigned long physOffset, size_t buffSize) {
size_t size = 0;
size_t i;
for (i = 0; i < buffSize; i += 2) {
size += uni_RB_write(readw(physAddr + physOffset)); // Here readed value sent to ring buffer. When "readw" replaced with any constant - everything OK
}
return size;
}
Looks like the problem was in code optimizations. I changed uni_RB_write function to pass physical address and data size, also read now performed via ioread16_rep function. So now everything works just fine.

FFMpeg How to use multithreading?

I want to decode H264 by ffmpeg, BUT finally I found the decode function only used one cpu core
system monitor
env: Ubuntu 14.04 FFMpeg 3.2.4 CPU i7-7500U
So, I search ffmpeg multithreading and decide using all cpu cores for decoding.
I set AVCodecContext as this:
//Init works
//codecId=AV_CODEC_ID_H264;
avcodec_register_all();
pCodec = avcodec_find_decoder(codecId);
if (!pCodec)
{
printf("Codec not found\n");
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx)
{
printf("Could not allocate video codec context\n");
return -1;
}
pCodecParserCtx=av_parser_init(codecId);
if (!pCodecParserCtx)
{
printf("Could not allocate video parser context\n");
return -1;
}
pCodecCtx->thread_count = 4;
pCodecCtx->thread_type = FF_THREAD_FRAME;
pCodec->capabilities &= CODEC_CAP_TRUNCATED;
pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
printf("Could not open codec\n");
return -1;
}
av_log_set_level(AV_LOG_QUIET);
av_init_packet(&packet);
//parse and decode
//after av_parser_parse2, the packet has a complete frame data
//in decode function, I just call avcodec_decode_video2 and do some frame copy work
while (cur_size>0)
{
int len = av_parser_parse2(
pCodecParserCtx, pCodecCtx,
&packet.data, &packet.size,
cur_ptr, cur_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
cur_ptr += len;
cur_size -= len;
if(GetPacketSize()==0)
continue;
AVFrame *pFrame = av_frame_alloc();
int ret = Decode(pFrame);
if (ret < 0)
{
continue;
}
if (ret)
{
//some works
}
}
But nothing different with before.
How can I use multithreading in FFMpeg? Any advise?
pCodec->capabilities &= CODEC_CAP_TRUNCATED;
And that's your bug. Please remove this line. The return value of avcodec_find_decoder() should for all practical intents and purposes be considered const.
Specifically, this statement removes the AV_CODEC_CAP_FRAME_THREADS flag from the codec's capabilities, thus effectively disabling frame-multithreading in the rest of the code.

Uinput and Raspberry Pi

I tried to ask this question on the Raspberry Pi forums, but I have received no responses at all. I thought I might query the minds of the StackOverflow community that has been so helpful in the past.
I'm writing a userspace driver for the Raspberry Pi (specifically, may be ported to other platforms later) which makes use of the bcm2835 library (GPIO) and uinput (Linux user-input virtual devices). I need to read GPIO pins and translate their values into simulated keypresses on a virtual keyboard. The GPIO part has been completed, and the translation part is also completed. Unfortunately, the virtual-keyboard part has not been solved. Uinput refuses to cooperate.
Now, the exact same code works perfectly on a Debian desktop machine. The evdev and uinput modules are required, both of which were loaded in all test cases. On the desktop, inputs can be triggered, however, on the Raspberry Pi, I can verify that the GPIO subsystem has registered the input, but the uinput events do not trigger. Does anyone have a lead on what I might do?
Thank you very much, if you need any information, logs, or otherwise, please let me know and I will post them as soon as I can.
This is a complete solution that works for me. I have a custom-made keypad and these are the keys I have defined. Here is the link to original pdf I used.
Of course you can define whatever key you want, just add it to the array.
Note: this code only works with elevated permission.
int allowed_keys[allowed_KEYS_size][2] = {0};
void main()
{
init_keys();
int fd = open_uinput();
int key_evt = getKeyEVT(49); // ASCII code for 1
// simulate key press and key release
emit(fd, EV_KEY, key_evt, 1);
emit(fd, EV_SYN, SYN_REPORT, 0);
emit(fd, EV_KEY, key_evt, 0);
emit(fd, EV_SYN, SYN_REPORT, 0);
}
long int emit(int fd, int type, int code, int val)
{
struct input_event ie;
ie.type = type;
ie.code = code;
ie.value = val;
/* timestamp values below are ignored */
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
long int y = write(fd, &ie, sizeof(ie));
return y;
}
int open_uinput()
{
int fdui = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fdui < 0)
{
printf("uinput fd creation failed!\n");
exit(EXIT_FAILURE);
}
ioctl(fdui, UI_SET_EVBIT, EV_KEY);
ioctl(fdui, UI_SET_EVBIT, EV_SYN); //added by behzad
for (int i = 0; i < allowed_KEYS_size; i++)
ioctl(fdui, UI_SET_KEYBIT, allowed_keys[i][1]);
struct uinput_setup usetup;
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1234; /* sample vendor */
usetup.id.product = 0x5678; /* sample product */
strcpy(usetup.name, "My Keypad. Ver 1.1");
ioctl(fdui, UI_DEV_SETUP, &usetup);
ioctl(fdui, UI_DEV_CREATE);
sleep(2);
return fdui;
}
int getKeyEVT(int k)
{
for (int i = 0; i < allowed_KEYS_size; i++)
{
if (allowed_keys[i][0] == k)
return allowed_keys[i][1];
}
return -1;
}
void init_keys()
{
// Reference:
// https://www.alt-codes.net/arrow_alt_codes.php
// /usr/include/linux/input-event-codes.h
allowed_keys[0][0] = 48; //ASCII ---> 0
allowed_keys[0][1] = KEY_0; //LINUX
allowed_keys[1][0] = 49; //ASCII
allowed_keys[1][1] = KEY_1; //LINUX
allowed_keys[2][0] = 50; //ASCII
allowed_keys[2][1] = KEY_2; //LINUX
allowed_keys[3][0] = 51; //ASCII
allowed_keys[3][1] = KEY_3; //LINUX
}

Call to ioctl() on a usb device using usbfs does not work

I am trying to create my own driver for my Gamepad right now, I found out the original reason why I wanted to create it does not exist but I still want to do it for the experience. So please don't tell me there is a better way to do this than writing my own driver.
The part in kernelspace with the ioctl function that should be called is:
static int xpad_ioctl (struct usb_interface *intf, unsigned int code,void *buf) {
//struct usb_xpad *xpad = usb_get_intfdata(intf);
printk(KERN_INFO"(Ongy)IOCTL called\n");
//if (_IOC_TYPE(code) != XPAD_IOMAGIC) return -ENOTTY;
//if (_IOC_NR(code) > XPAD_IOMAX) return -ENOTTY;
switch(code){
case XPAD_IORMAP:
printk(KERN_INFO"(Ongy)IORMAP called\n");
break;
default:
return -EINVAL;
}
return 0;
}
static struct usb_driver xpad_driver =
{
.name = "Cyborg-V5-driver",
.probe = xpad_probe,
.disconnect = xpad_disconnect,
.unlocked_ioctl = xpad_ioctl,
.id_table = xpad_table,
};
The part in userspace to call it is (this is part of a Qt-application):
int openfile() {
char *device = "/dev/bus/usb/005/009";
printf("Opening device %s\n", device);
return open(device, /*O_RDONLY*/O_WRONLY | O_NONBLOCK );
}
[...] the closefile(int file_desc) is missing here, this and the openfile functions exist because of me not knowing one can call "::open()" when Qt overrides function calls.
void MainContainer::callioctl() {
int file_desc, ret_val;
errno = 0;
file_desc = openfile();
if (file_desc==-1){
printf("Ioctl notcalled because of: error %s\n", strerror(errno));
}
else
{
errno = 0;
//struct usbdevfs_getdriver* driver = (usbdevfs_getdriver*)malloc(sizeof(struct usbdevfs_getdriver));
struct mappingpair* pair = (mappingpair*)malloc(sizeof(struct mappingpair));
ret_val = ioctl(file_desc, XPAD_IORMAP, pair);
//printf("Drivername %s\n", driver->driver);
closefile(file_desc);
if (ret_val==-1) printf("Ioctl failed with error %s\n", strerror(errno));
else printf("Ioctl call successfull\n");
}
}
ok, the string to the file I open I get with a call to lsusb and change it by hand in the code, this is only for debugging and until I get the ioctl calls working
When I call the callioctl() it prints:
Ioctl failed with error Unpassender IOCTL (I/O-Control) für das Gerät
The German part means "wrong ioctl (I/O-Control) for the device" and nothing appears in dmesg, that is why I think my ioctl function in the driver is not called.
If you look at http://www.hep.by/gnu/kernel/usb/usbfs.html it says that to send an ioctl to the usb_driver device you need to do:
struct usbdevfs_ioctl {
int ifno;
int ioctl_code;
void *data;
};
/* user mode call looks like this.
* 'request' becomes the driver->ioctl() 'code' parameter.
* the size of 'param' is encoded in 'request', and that data
* is copied to or from the driver->ioctl() 'buf' parameter.
*/
static int
usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
{
struct usbdevfs_ioctl wrapper;
wrapper.ifno = ifno;
wrapper.ioctl_code = request;
wrapper.data = param;
return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
}
The documentation is listing usb device under /proc/bus so admittedly this may have changed.

Resources