I'm currently developing a contiki programm that runs on a Z1 device for debugging purposes. I would like to send UART messages to that device and found out that Cooja appears to supports that with a function called "Show serial port on Z1". That tool in fact helped me to read UART messages sent from the mote, but when I try to send somethin back, the Int handler just doesn't get called.
Here's how I initialize UART in code:
uart0_init(0);
uart0_set_input(uart_handler);
uart0_writeb('U');
In the handler itself, I just toggle all LEDs (which definitely works) - however, they never get toggled. I even tried to send a byte in the ISR handler within the uart0-library but even that byte never gets sent. This means that the whole UART communication between Cooja and the Z1 mote does not seem to work correctly. Has anyone ever had the same problem and is able to provide me with a solution for that? It would be a great help!
I did manage to figure it out in the mean time. Here's the solution for anybody who is facing the same problem.
The following code works. Depending on whether you define USE_SERIAL_LINE you can decide if you would like to use the serial-line-module or your own int handler.
#include <stdio.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "dev/uart0.h"
#define USE_SERIAL_LINE
#ifdef USE_SERIAL_LINE
#include "dev/serial-line.h"
#endif
PROCESS(init_system_proc, "Init system process");
AUTOSTART_PROCESSES(&init_system_proc);
int uart_handler(unsigned char c){
printf("Single Byte input.\n");
return 1;
}
PROCESS_THREAD(init_system_proc, ev, data){
PROCESS_BEGIN();
uart0_init(0);
#ifdef USE_SERIAL_LINE
serial_line_init();
uart0_set_input(serial_line_input_byte);
#else
uart0_set_input(uart_handler);
#endif
while (1) {
PROCESS_YIELD();
#ifdef USE_SERIAL_LINE
if(ev == serial_line_event_message)
printf("Serial input.\n");
#endif
}
PROCESS_END();
}
There's one thing you need to keep in mind when using printf for UART output. A UART message will only be send when "\n" appears - this means that every printf-statement should end with a new line character. Otherwise your string only gets buffered and send out once a new line character appears.
Related
I am extremely disconcerted.
I'm making a remote controlled machine using a pi pico to drive the motors and read some sensors, and a raspberry pi 4 to send commands to the pi pico via serial and host the web interface.
The following code seems to work... but... If I remove the if with uart_is_writable coding and its content it doesn't work. Does anyone have any idea why?
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
//DEFINES
#define UART_ID uart0
#define BAUD_RATE 19200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN
static int chars_rxed = 0;
volatile char uCommand[32] = {0, 0};
void on_uart_rx(void) {
char tmp_string[] = {0, 0};
new_command = true;
while (uart_is_readable(UART_ID)) {
uint8_t ch = uart_getc(UART_ID);
tmp_string[0] = ch;
strcat(uCommand, tmp_string);
if(uart_is_writable(UART_ID)){
uart_putc(UART_ID, '-');
uart_puts(UART_ID, uCommand);
uart_putc(UART_ID, '-');
}
chars_rxed++;
}
}
int main(){
uart_init(UART_ID, BAUD_RATE);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
uart_set_hw_flow(UART_ID, false, false);
uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
uart_set_fifo_enabled(UART_ID, false);
int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;
irq_set_exclusive_handler(UART_IRQ, on_uart_rx);
irq_set_enabled(UART_IRQ, true);
uart_set_irq_enables(UART_ID, true, false);
uart_puts(UART_ID, "\nOK\n");
while (1){
tight_loop_contents();
if(uCommand[0] != 0){
uart_putc(UART_ID, '/');
uart_puts(UART_ID, uCommand);
memset(uCommand, 0, sizeof(uCommand));
}
}
}
The example code you linked to is for a simple tty/echo implementation.
You'll need to tweak it for your use case.
Because Tx interrupts are disabled, all output to the transmitter has to be polled I/O. Also, the FIFOs in the uart are disabled, so only single char I/O is used.
Hence, the uart_is_writable to check whether a char can be transmitted.
The linked code ...
echos back the received char in the Rx ISR. So, it needs to call the above function. Note that if Tx is not ready (i.e. full), the char is not echoed and is dropped.
I don't know whether uart_putc and uart_puts check for ready-to-transmit in this manner.
So, I'll assume that they do not.
This means that if you call uart_putc/uart_puts and the Tx is full, the current/pending char in the uart may get trashed/corrupted.
So, uart_is_writable should be called for any/each char to be sent.
Or ... uart_putc/uart_puts do check and will block until space is available in the uart Tx fifo. For you use case, such blocking is not desirable.
What you want ...
Side note: I have done similar [product/commercial grade] programming on an RPi for motor control via a uart, so some of this is from my own experience.
For your use case, you do not want to echo the received char. You want to append it to a receive buffer.
To implement this, you probably want to use ring queues: one for received chars and one for chars to be transmitted.
I assume you have [or will have] devised some sort of simple packet protocol to send/receive commands. The Rpi sends commands that are (e.g.):
Set motor speed
Get current sensor data
The other side should respond to these commands and execute the desired action or return the desired data.
Both processors probably need to have similar service loops and ISRs.
The Rx ISR just checks for space available in the Rx ring queue. If space is available, it gets a char from the uart and enqueues it. If no Rx char is available in the uart, the ISR may exit.
The base level code service loop should:
Check if the uart Tx can accept another character (via uart_is_writable) and, if so, it can dequeue a char from the Tx ring queue [if available] and send it (via uart_putc). It can loop on this to keep the uart transmitter busy.
Check to see if enough chars are received to form a packet/message from the other side. If there is such a packet, it can service the "request" contained in it [dequeueing the chars to make more space in the Rx ring queue].
If the base level needs to send a message, it should enqueue it to the Tx ring queue. It will be sent [eventually] in the prior step.
Some additional thoughts ...
The linked code only enables Rx interrupts and runs the Tx in polled mode. This may be enough. But, for maximum throughput and lowest latency, you may want to make the Tx interrupt driven as well.
You may also wish the enable the FIFOs in the uart so you can queue up multiple characters. This can reduce the number of calls to the ISR and provide better throughput/latency because the service loop doesn't have to poll so often.
I have some driver code that I am testing out for use with an SSD1306 driven OLED screen which is 128x32 (same as the OLED adafruit model). I need this to run in debian (I am using Linario-4.4.9)
I have followed the Debian guides on how to start creating a file handler for the device, this can be seen as follows below. The only thing in oled.h is the device adress (0x3C) and the proto types. I followed the initialization approach taken on the adafruit github (as I tried their code out first on an Ardunio to ensure the screen does in fact work). I believe I may be doing something wrong but I'm not entirely sure what I am doing wrong. I have also listed my init process below.
#include <errno.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/i2c-dev.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "oled.h"
int oled;
int lcd_driver_init(void)
{
///< Begin the init proc.
int dloc = open("/dev/i2c-1", O_RDWR);
if (dloc < 0 )
{
fprintf(stderr, "Error opening i2c device\n");
return -1;
}
if(ioctl(dloc, I2C_SLAVE, SCR_ADDR) < 0)
{
fprintf(stderr, "Error in ioctl. Errno :%i\n",errno);
return -2;
}
oled = dloc;
fprintf(stderr, "init success, device open and local\n");
return EXIT_SUCCESS;
}
int oled_command( uint8_t cmd)
{
char command[2]= {0};
command[1] = cmd;
int check = (write(oled, command, 2));
return check;
}
void oled_cmd_start()
{
int check = (write(oled, 0x00, sizeof(uint8_t)));
if(check<0)
fprintf(stderr, "Errno set:: %i\n", errno);
return;
}
void oled_data_start()
{
uint8_t _data_start_[1] ={ 0x40 };
int check = (write(oled, _data_start_, sizeof(uint8_t)));
if(check<0)
fprintf(stderr, "Errno set oled_data_start:: %i\n", errno);
return;
}
int oled_data (uint8_t xmit)
{
int check = (write(oled, &xmit, (sizeof(uint8_t))));
if(check<0)
fprintf(stderr, "Errno set oled_data:: %i\n", errno);
return check;
}
INIT PROCESS
void sendcommand(unsigned char payload)
{
oled_data(0x00); //Control Byte - Command
oled_data(payload); //payload
}
void lcd_init(void)
{
sendcommand(0xAE);//--Set Display off
sendcommand(0x00);//--set low column address
sendcommand(0x10);//--set high column address
sendcommand(0x81);//--set contrast control register
sendcommand(0x7f);
sendcommand(0xa1);//--set segment re-map 95 to 0
sendcommand(0xA6);//--set normal display
sendcommand(0xa8);//--set multiplex ratio(1 to 16)
sendcommand(0x1f);//--duty 1/32
sendcommand(0xd3);//--set display offset
sendcommand(0x00);//--not offset
sendcommand(0xd5);//--set display clock divide ratio/oscillator frequency
sendcommand(0xf0);//--set divide ratio
sendcommand(0xd9);//--set pre-charge period
sendcommand(0x22);
sendcommand(0xda);//--set com pins hardware configuration
sendcommand(0x02);//disable left/right remap and set for sequential
sendcommand(0xdb);//--set vcomh
sendcommand(0x49);//--0.83*vref
sendcommand(0x8d);//--set DC-DC enable
sendcommand(0x14);//
sendcommand(0xAF);//--turn on oled panel
sendcommand(0xA4);//--Entire Display ON
}
Following this, I send alternating 0xFF to try and make stripes on the screen. The only thing that shows up is random pixels. Nothing coherent.
I have connected a logic analyzer to sniff the I2C lines, and it appears that when I have the LA connected, the I2C lines no longer function and ERRNO returns an IO fault (#5).
There doesn't ever seem to be an issue opening up the device to get the file pointer however.
I do get ERRNO as timeout sometimes, but I have read that this is just an issue with I2C devices using the protocal as write expects a quicker response than I2C might give.
I am also compiling with -std=c99 -O0 to ensure all of the inline functions are there as well as ensuring that loop variables are available.
If anyone can point me in the right direction of can point out some flaw in my approach it would be much appreciated. Thank you.
EDIT
I've checked the device tree and the i2c device is correctly enabled. However none of the i2c_freq speeds seem to be enabled. Could this be causing the timeouts and the garbage data transfer?
I have connected a logic analyzer to sniff the I2C lines, and it appears that when I have the LA connected, the I2C lines no longer function and ERRNO returns an IO fault (#5).
logic analyzer is just a device for measurement. It converts the captured data into timing diagrams, decodes protocol which you have set. So it will not be responsible for any I2C read write error (until your grounding and h/w connections are correct).
For timeout issue either you can try by decreasing the i2c clock-frequency or ioctl I2C_TIMEOUT.
It turns out the SOM has an internal regulator for the I2C lines to be 1V8 where as the SSD1306 chip is running at 3V3 causing information to be mishandled. This behavior wasn't documented on the SOM.
Applying a level shifting chip to the design allowed for proper communication.
If someone has this same problem, check your schematics for voltage mismatch levels.
I need to free the processor while I wait for a change in the level of a GPIO pin (either rising or falling edge), so I created a simple code to poll a GPIO sysfs value file, but I'm running into some trouble:
In the first poll() call, it exits imediatelly, with both POLLPRI and POLLERR set in revents;
After this, I lseek() and read() the fd, and loop back to poll();
Now poll() hangs.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/fcntl.h>
#define GPIO_DIR "/sys/class/gpio/"
#define GPIO_EXPORT GPIO_DIR "export"
int main(int argc, char **argv)
{
int gpio_fd;
struct pollfd gpio_fdset[1];
char pin_value[] = GPIO_DIR "gpioXYZ/value";
sprintf(pin_value, GPIO_DIR "gpio%s/value", argv[1]);
gpio_fd = open(pin_value, O_RDONLY);
while (1)
{
char buffer[64];
gpio_fdset[0].fd = gpio_fd;
gpio_fdset[0].events = POLLPRI;
gpio_fdset[0].revents = 0;
poll(gpio_fdset, 1, -1);
if (gpio_fdset[0].revents & POLLPRI)
{
printf("revents returned POLLPRI!\n");
lseek(gpio_fdset[0].fd, 0, SEEK_SET);
read(gpio_fdset[0].fd, buffer, 64);
}
}
}
Before calling it, I export the pin I wish to monitor (GPIO1_30 or 62 in the kernel numbering scheme). I've tried setting this pin as input, output, generating interrupts on rising and falling edges, but the behaviour is always the same. What am I missing?
From what I've read, when I use the sysfs, I should not need to use the gpio_request(), gpio_to_irq() and other related functions to be able to poll this pin. Is this right?
Regards,
Guilherme
I've discovered how to overcome this issue. Simply perform a dummy read() after setting opening the file descriptor. Apparently this is due to the fact that a recently opened fd is considered as changed (at least for GPIOs). As for the POLLERR on revents, this is standard sysfs behaviour.
If I understand your requirement right, then you want to take some action when the pin goes high.
you can poll the pin in application layer it self.
Download the "SimpleGPIO.h" and "SimpleGPIO.cpp" from the below URL:
https://github.com/derekmolloy/beaglebone
The SimpleGPIO.h/cpp is self explanatory and you can do all operations with GPIO using the simple function calls.
This one will work fine for any am335x processor. Then to poll you can use in your code some thing like this
int main()
{
//Your code
while(1)
{
if(gpio_get_value())
{
//Do what ever you want to do.
}
}
}
NOTE::
If you want to send any signal to your application process from kernel level using irq then the approach will be little different, But only for polling this code will work fine.
Hope this helps.
Edit:
Please refer below url for more details, it explains your question. You need to use any signal between (Signal number 32 to 64) to detect the change of GPIO status. You need to register your processId with your kernel module.
http://yongbingchen.github.io/blog/2013/03/11/sending-a-signal-from-linux-kernel/
When there is a change in GPIO status, Kernel sends a signal to application layer on which a dedicated function in application layer can execute.
There is a problem with the following code. I need it to give access to the ports 0x300 to 0x307 so i do this:
#ifdef LINUX
if(ioperm(PORT1,9,1)==-1) printf("Error in ioperm()");
#endif
Where PORT1=0x300.
then i do this:
int j5inp(unsigned int addr){
#ifdef DOS
return inp(addr);
#endif
#ifdef LINUX
return inb(addr);
#endif
}
void j5outp(unsigned int addr, unsigned int val){
#ifdef DOS
outp(addr,val);
#endif
#ifdef LINUX
outb(val,addr);
#endif
}
/************/
hrd_check()
{
j5outp(PCHECK,0xAA);
if (j5inp(PCHECK)!=0xAA) return(0);
j5outp(PCHECK,0x55);
if (j5inp(PCHECK)!=0x55) return(0);
return(1);
}
where PCHECK=0x307.
I have tested this and i found that i am able to retrieve the value 0xAA from the port after i sent it, but the second one (0x55) fails because inb() still returns 0xAA.
Am i doing anything wrong? can this be a hardware problem? Should i try calling the ioperm() function for every call to inb() or should i try using iopl() ?
by the way, the board i am using is the advantech PCM-3342
Well i guess this is one of those problems that simply goes away. I believe i corrected a little bug that i was sure was unrelated to this problem. But when i did it the problem went away.
I would give a better description of how i solved it but i don't really know how i did it.
I will start by saying that I am a college student with little c++ experience. How many times have you heard that right? I am working with the test program testISO_TCP (simplified version) from the libnodave library. This program does a simple read of flag values and data blocks while it is connected to a seimens 300 PLC. The program doesn't bring up any errors per se. What I am trying to do is hopefully add some code to this program that will protect the reads from ever crashing. Let me explain a little better. Say for example I have a lot of reads implemented in the code. As of now there are only two reads. Eventually I will run this code with many more reads. Now, say that I am running the test program and for some reason I lose the connection to the PLC. I would like to have the program do one of two things: 1) Once the connection is lost, do a retry connect a certain amount of times and when it runs out of tries, exit. or 2) Somehow continue to read from the PLC until they are all done.
I hope this is enough information to get some help. I will post the code that I have been looking at for so long without any idea how to do this effectively. Thanks to all in advance.
#define PLAY_WITH_KEEPALIVE
#include <stdlib.h>
#include <stdio.h>
#include "nodavesimple.h"
#include "openSocket.h"
#ifdef PLAY_WITH_KEEPALIVE
#include <winsock.h>
#endif
int main(int argc, char **argv) {
int a,b,c,res, doRun, doStop, doRead, doreadFlag, useProtocol, useSlot;
#ifdef PLAY_WITH_KEEPALIVE
int opt;
#endif
float d;
daveInterface * di;
daveConnection * dc;
_daveOSserialType fds;
doRun=0;
doStop=0;
doRead=0;
doreadFlag=0;
useProtocol=daveProtoISOTCP;
useSlot=2;
fds.rfd=openSocket(102, argv[1]);
#ifdef PLAY_WITH_KEEPALIVE
errno=0;
opt=1;
//res=setsockopt(fds.rfd, SOL_SOCKET, SO_KEEPALIVE, &opt, 4);
//LOG3("setsockopt %s %d\n", strerror(errno),res);
#endif
fds.wfd=fds.rfd;
if (fds.rfd>0)
{
di =daveNewInterface(fds,"IF1",0, daveProtoISOTCP, daveSpeed187k);
daveSetTimeout(di,5000000);
dc =daveNewConnection(di,2,0, 2); // insert your rack and slot here
if (0==daveConnectPLC(dc))
{
printf("Connected.\n");
res=daveReadBytes(dc,daveFlags,0,0,16,NULL);
if (0==res)
{
a=daveGetU32(dc);
b=daveGetU32(dc);
c=daveGetU32(dc);
d=daveGetFloat(dc);
printf("FD0: %d\n",a);
printf("FD4: %d\n",b);
printf("FD8: %d\n",c);
printf("FD12: %f\n",d);
}//end 0==res
}//end daveConnectPLC
else
{
printf("Couldn't connect to PLC.\n Please make sure you use the -2 option with a CP243 but not with CPs 343 or 443.\n");
//closeSocket(fds.rfd);
//return -2;
}
}//end fds.rfd
fds.rfd=openSocket(102, argv[1]);
fds.wfd=fds.rfd;
if (fds.rfd>0)
{
di =daveNewInterface(fds,"IF1",0, daveProtoISOTCP, daveSpeed187k);
daveSetTimeout(di,5000000);
dc =daveNewConnection(di,2,0, 2); // insert your rack and slot here
if (0==daveConnectPLC(dc))
{
printf("Connected.\n");
res=daveReadBytes(dc,daveDB,1,0,64,NULL);
if (0==res)
{
a=daveGetU16(dc);
printf("DB1:DW0: %d\n",a);
a=daveGetU16(dc);
printf("DB1:DW1: %d\n...\n",a);
a=daveGetU16At(dc,62);
printf("DB1:DW32: %d\n",a);
}//end 0==res
return 0;
}//end daveConnectPLC
else
{
printf("Couldn't connect to PLC.\n Please make sure you use the -2 option with a CP243 but not with CPs 343 or 443.\n");
closeSocket(fds.rfd);
return -2;
}
}//end fds.rfd
else
{
printf("Couldn't open TCP port. \nPlease make sure a CP is connected and the IP address is ok. \n");
return -1;
}
}// end main
You have to check the return value of the daveReadBytes function.
If it is not zero, something went wrong and you can use the daveStrerror function to get a proper error message:
printf ("error: %s\n", daveStrerror(res));
After that it's up to you to decide to either simply retry the read or disconnect (with closeSocket(...)) and then create a new connection from the beginning. Check the documentation on what errorcodes there are. Some errors can't be resolved by retrying (e.g. because you try reading a data block that doesn't exist).
I have a loop that attempts to connect 3 times and exits gracefully if it fails
You may be able to write some other code to first check to see if the connection is up and also if the PLC is up.
Typically if you try to connect to an IP address that doesn't esond; it will hang there and tie up resources...
I am also new programmer.But want to say that. First we have to differentiate between the TCP/IP connection with the ethernet card ISO_TCP. The openSocket() function does the connection to remote IP adress in the given port/Service (102 ISO_TCP). When called next, the function daveNewInterface(), it will initialise the specific interface for doing a connection to the PLC. After this, the function daveNewConnection() tries to open a connection on a given MPI adress, and very important, the given rack and slot. If this function returns the value 0, it will call the daveConnectPLC() function to connect to the PLC. At this point it´s established a ethernet connection,and also the PLC Connection.
Now you can use all the function from the libnodave library for read or write data, stop or run the PLC and much more.
In the actually simplified TCP_ISO code there are no function to disconnect the adapter or close the connection with the PLC, in your code there is the closeSocket() function and also the function that returns -2. Find at what line the code breaks, introducing for example a log after every function to see the returns values.
All info for detecting loss of communication is in the documentation.