Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SoftwareSerial RS485 Arduino.h to Simba.h #203

Closed
softov opened this issue Sep 23, 2018 · 3 comments
Closed

SoftwareSerial RS485 Arduino.h to Simba.h #203

softov opened this issue Sep 23, 2018 · 3 comments

Comments

@softov
Copy link

softov commented Sep 23, 2018

As mentioned in #202 In reply to @eerimoq,

PS. I this the UART soft driver cannot handle simultaneous TX and RX. I strongly recommend you to use the non-soft driver, often automatically started as the console which uses stdin and stdout. DS.

I have tried to write a code to figure how to migrate.

This is a sample code to proxy HardwareSerial to SoftwareSerial RS485, and vice-versa

In Arduino I made that way

/* Import needed libraries */
#include <Arduino.h>
#include <SoftwareSerial.h>
/* Declare Constants and Pin Numbers */
#define PIN_TX 2 // Serial Transmit pin DI
#define PIN_RX 3 // Serial Receive pin RO
#define PIN_TX_CONTROL 4 //RS485 Direction control pin RE+DE
#define RS485_TOGGLE_TRANSMIT HIGH
#define RS485_TOGGLE_RECEIVE LOW

/* Declare objects */
SoftwareSerial RS485Serial(PIN_RX, PIN_TX); // RX, TX

/* Declare Variables */
int byteReceived;
int byteSend;

void setup() /****** SETUP: RUNS ONCE ******/
{
    // Start the built-in serial port, probably to Serial Monitor
    Serial.begin(9600);
    Serial.println("BrByte.com SoftwareSerial example");
    Serial.println("Use Serial Monitor, type in upper window, ENTER");

    pinMode(PIN_TX_CONTROL, OUTPUT);
    digitalWrite(PIN_TX_CONTROL, RS485_TOGGLE_RECEIVE); // Init Transceiver

    // Start the software serial port, to another device
    RS485Serial.begin(9600); // set the data rate

} // end setup

void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
    //Look for data from Serial
    if (Serial.available())
    {
        byteReceived = Serial.read();
        digitalWrite(PIN_TX_CONTROL, RS485_TOGGLE_TRANSMIT); // Enable RS485 Transmit
        RS485Serial.write(byteReceived);               // Send byte to Remote Arduino
        delay(10);
        digitalWrite(PIN_TX_CONTROL, RS485_TOGGLE_RECEIVE); // Disable RS485 Transmit
    }

    //Look for data from RS485
    if (RS485Serial.available())
    {
        byteReceived = RS485Serial.read(); // Read received byte
        Serial.write(byteReceived);        // Show on Serial Monitor
        delay(10);
    }

} // end main loop

The main resource that I use is XXX.available(), so I can read, only if there is something.
I don't known how to do that in simba, so I have used a chan_list.
This test is mean to do the same

/*
 * main.c
 * CONFIG_UART_SOFT 1 in config.h
 */

#include "simba.h"

/************************************************************/
int loopExample1(struct uart_driver_t *s_hw, struct uart_soft_driver_t *s_485, struct pin_driver_t *pinT)
{
    struct chan_list_t list;
    struct chan_list_t elements[2];
    void *chan_ptr = NULL;
    char c = 0;

    /* Wait for data from PC and HC-0X. */
    chan_list_init(&list, &elements, membersof(elements));

    /* HERE - INVERT ORDER */
    chan_list_add(&list, &s_485->chin);
    chan_list_add(&list, &s_hw->chin);

    while (1)
    {
        chan_ptr = chan_list_poll(&list, NULL);

        if (chan_ptr == &s_hw->chin)
        {
            chan_read(&s_hw->chin, &c, sizeof(c));
            /* enable sending */
            pin_write(pinT, 1);
            chan_write(&s_485->chout, &c, sizeof(c));
            /* disable sending */
            pin_write(pinT, 0);
        }
        else if (chan_ptr == &s_485->chin)
        {
            /* Write all output from HC-0X to the PC. */
            chan_read(&s_485->chin, &c, sizeof(c));
            chan_write(&s_hw->chout, &c, sizeof(c));
        }
        else
        {
            std_printf(OSTR("bad input channel 0x%02x 0x%02x 0x%02x\r\n"),
                       (int)chan_ptr,
                       (int)&s_485->chin,
                       (int)&s_hw->chin);
        }
    }

    chan_list_destroy(&list);

    return 0;
}
/************************************************************/
int main()
{
    char hw_buf[32];
    char rs485_buf[32];
    struct pin_driver_t pin_REDE;

    struct uart_driver_t serial_hw;
    struct uart_soft_driver_t serial_rs485;

    int op_status;

    /* Start the system. */
    sys_start();

    pin_module_init();

    /* Initialize the LED pin as output. */
    op_status = pin_init(&pin_REDE, &pin_d4_dev, PIN_OUTPUT);

    if (op_status != 0)
        return 0;

    /* Initialize the UART. */
    uart_module_init();

    /* Initialize the Hardware Serial */
    op_status = uart_init(&serial_hw, &uart_device[0], 9600, hw_buf, sizeof(hw_buf));
    uart_start(&serial_hw);

    /* Initialize the RS485 Serial */
    op_status = uart_soft_init(&serial_rs485, &pin_d2_dev, &pin_d3_dev, &exti_d3_dev, 9600, rs485_buf, sizeof(rs485_buf));

    if (op_status != 0)
        return 0;

    sys_set_stdout(&serial_hw.chout);
    log_set_default_handler_output_channel(sys_get_stdout());

    /* Print the system information. */
    std_printf(sys_get_info());

    loopExample1(&serial_hw, &serial_rs485, &pin_REDE);
}
/************************************************************/

But, in this part, if is in this way, s_hw->chin don't read anything

    /* HERE - INVERT ORDER */
    chan_list_add(&list, &s_485->chin);
    chan_list_add(&list, &s_hw->chin);

And in this way, s_485->chin don't read anything

    /* HERE - INVERT ORDER */
    chan_list_add(&list, &s_hw->chin);
    chan_list_add(&list, &s_485->chin);

If i put this code before calling the loop, its work, so I can read and write from

. . . 
    pin_write(&pin_REDE, 1);
    chan_write(&serial_rs485.chout, "1", 1);
    chan_write(&serial_rs485.chout, "2", 1);
    chan_write(&serial_rs485.chout, "3", 1);
    /* disable sending */
    pin_write(&pin_REDE, 0);
 . . .
    loopExample1(&serial_hw, &serial_rs485, &pin_REDE);
  • there is something missing?
  • need to use use non-soft driver? and how to use a non-soft driver in this case

PS, My project is a Nano Slave, running a RS485 module, which will receive/reply some commands from a FreeBSD machine, connected to this network using a MAX485, The commands are something like

  • RA1 - Read Analog 1
  • RA7 - Read Analog 7
  • RD3 - Read Digital 3
  • SD5H - Set Digital 5 to HIGH
  • SD4LO - Set Digital 4 to LOW and OUTPUT
    UART (HardwareSerial) will be used to debug, setup, configuration, etc

As I said, the main core of the project is the Serial (&uart_device[0]) running together with the RS485 Module (uart_soft or something else)
If there is something to help, it will be nice.

@softov
Copy link
Author

softov commented Sep 23, 2018

I have beat the code to work.

Expose get_buffer_used, because is not accessible outside, then use this to see if there is something to read. Get A->B and B->A talking.

RAM_CODE static inline size_t get_buffer_used(struct queue_buffer_t *buffer_p)
{
    if (buffer_p->begin_p == NULL) {
        return (0);
    }

    if (buffer_p->write_p == buffer_p->read_p) {
        return (0);
    } else if (buffer_p->write_p > buffer_p->read_p) {
        return (buffer_p->write_p - buffer_p->read_p);
    } else {
        return ((buffer_p->end_p - buffer_p->begin_p)
                - (buffer_p->read_p - buffer_p->write_p));
    }
}
/************************************************************/
int loopExample1(struct uart_driver_t *s_hw, struct uart_soft_driver_t *s_485, struct pin_driver_t *pinT)
{
    char c = 0;
    while (1)
    {
        while (get_buffer_used(&s_hw->chin.buffer) > 0)
        {
            chan_read(&s_hw->chin, &c, sizeof(c));

            /* enable sending */
            pin_write(pinT, 1);
            chan_write(&s_485->chout, &c, sizeof(c));
            /* disable sending */
            pin_write(pinT, 0);
        }
        while (get_buffer_used(&s_485->chin.buffer) > 0)
        {
            chan_read(&s_485->chin, &c, sizeof(c));
            chan_write(&s_hw->chout, &c, sizeof(c));
        }
    }
    return 0;
}

This is wrong?
I don't known IF this is the right function to call, none if this is the right way.

PS, there is a exemple using shell and threads? I have searched in google, without success.
So, I can put rs485 inside a thread, only to receive/reply commands, and let HardwareSerial to Shell to manage the system.

@eerimoq
Copy link
Owner

eerimoq commented Sep 23, 2018

Sorry, but I don't have time to look into this i detail. But yes, a list can be used if data is expected in one or more channels. Also there is a chan_size() function to see how many betys that can be read.

@mikaelpatel
Copy link

@softov Actually the delay(10); in the original Arduino sketch is really important.

@softov softov closed this as completed Jun 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants