This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF9160 MQTT Serial

Hello All,

I am trying to publish the data gathered from UART using MQTT. So far I was able to get serial data in the inData buffer. I am not able to publish data automatically as soon as data is received on serial port. Can some one please help me out with the same. I would really appreciate it.

void mqtt_evt_handler(struct mqtt_client *const c,
		      const struct mqtt_evt *evt)
{
	int err;

	switch (evt->type) {
	case MQTT_EVT_CONNACK:
		if (evt->result != 0) {
			printk("MQTT connect failed %d\n", evt->result);
			break;
		}

		connected = true;
		printk("[%s:%d] MQTT client connected!\n", __func__, __LINE__);
		subscribe();
		break;

	case MQTT_EVT_DISCONNECT:
		printk("[%s:%d] MQTT client disconnected %d\n", __func__,
		       __LINE__, evt->result);

		connected = false;
		break;

	case MQTT_EVT_PUBLISH: {
		const struct mqtt_publish_param *p = &evt->param.publish;

		printk("[%s:%d] MQTT PUBLISH result=%d len=%d\n", __func__,
		       __LINE__, evt->result, p->message.payload.len);
		err = publish_get_payload(c, p->message.payload.len);
		if (err >= 0) {
			data_print("Received: ", inData,
				sizeof(inData));
			/* Echo back received data */
			data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE,
				inData, sizeof(inData));
		} else {
			printk("mqtt_read_publish_payload: Failed! %d\n", err);
			printk("Disconnecting MQTT client...\n");

			err = mqtt_disconnect(c);
			if (err) {
				printk("Could not disconnect: %d\n", err);
			}
		}
	} break;

	case MQTT_EVT_PUBACK:
		if (evt->result != 0) {
			printk("MQTT PUBACK error %d\n", evt->result);
			break;
		}

		printk("[%s:%d] PUBACK packet id: %u\n", __func__, __LINE__,
				evt->param.puback.message_id);
		break;

	case MQTT_EVT_SUBACK:
		if (evt->result != 0) {
			printk("MQTT SUBACK error %d\n", evt->result);
			break;
		}

		printk("[%s:%d] SUBACK packet id: %u\n", __func__, __LINE__,
				evt->param.suback.message_id);
		break;

	default:
		printk("[%s:%d] default: %d\n", __func__, __LINE__,
				evt->type);
		break;
	}
}

Parents
  • Hi,

     

    I am trying to publish the data gathered from UART using MQTT. So far I was able to get serial data in the inData buffer. I am not able to publish data automatically as soon as data is received on serial port. Can some one please help me out with the same. I would really appreciate it.

     How are you pushing the data from the uart to the mqtt module? Your uart_evt_handler will likely execute from an interrupt, which then needs to be scheduled to main priority before calling a mqtt_* prefixed function. I would recommend using a workqueue for such task: https://docs.zephyrproject.org/latest/reference/kernel/threads/workqueue.html?highlight=workqueue#

     

    Kind regards,

    Håkon

  • Thanks for the reply Håkon, The following is the code which I am using.

    void uart_cb(struct device *x)
    {
    	uart_irq_update(x);
    	int data_length = 0;
    
    	if (uart_irq_rx_ready(x)) {
    		data_length = uart_fifo_read(x, uart_buf, sizeof(uart_buf));
    		uart_buf[data_length] = 0;
    	}
    
            if(i==19 || *uart_buf == '?'){ 
            inData[i] = '\0';
            printk("%s\n",inData); // loopback
            i=0;
            data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE,inData, sizeof(inData));
            }
            else{
            memcpy(&inData[i], uart_buf, 1); 
            i++;
            }
    }
    In the function uart_cb I make a string of 20 characters or a smaller string when UART sees "?". I store this string in inData variable and add null terminator to make it a string. Then I add data_publish function to publish the data. This doesn't seem to work. On the serial port, I get the loop back as mentioned in the code in comments but the publish function doesn't work. In addition to that once I try to write on serial port, the serial port doesn't responds back. Don't know what to do. Could you please help me out with this.

  • Hi,

     

    You're calling data_publish() directly from the interrupt, which will not work. Could you try to set a flag and handle it in the main thread instead?

     

    Kind regards,

    Håkon

  • Hi

    I made a global int variable monitor (as flag) and added it in the while loop of the main function.

    while (1) {
    
    
    		err = poll(&fds, 1, K_SECONDS(CONFIG_MQTT_KEEPALIVE));
    		if (err < 0) {
    			printk("ERROR: poll %d\n", errno);
    			break;
    		}
    
    		err = mqtt_live(&client);
    		if (err != 0) {
    			printk("ERROR: mqtt_live %d\n", err);
    			break;
    		}
    
    		if ((fds.revents & POLLIN) == POLLIN) {
    			err = mqtt_input(&client);
    			if (err != 0) {
    				printk("ERROR: mqtt_input %d\n", err);
    				break;
    			}
    		}
    
    		if ((fds.revents & POLLERR) == POLLERR) {
    			printk("POLLERR\n");
    			break;
    		}
    
    		if ((fds.revents & POLLNVAL) == POLLNVAL) {
    			printk("POLLNVAL\n");
    			break;
    		}
                    
                    if(monitor == 1){
                    data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE,
    				inData, sizeof(inData));
                    monitor = 0;
                    } 
                    
    	}
    I set the flag in the interrupt handler as shown here
    void uart_cb(struct device *x)
    {
    	uart_irq_update(x);
    	int data_length = 0;
    
    	if (uart_irq_rx_ready(x)) {
    		data_length = uart_fifo_read(x, uart_buf, sizeof(uart_buf));
    		uart_buf[data_length] = 0;
    	}
    
            if(i==19 || *uart_buf == '?'){ 
            inData[i] = '\0';
            printk("%s\n",inData);
            i=0;
            monitor = 1; // flag
            }
            else{
            memcpy(&inData[i], uart_buf, 1); 
            i++;
            }
    }
    Still triggers after I get the published data. Don't know what to do

    Regards

    NordicUser

Reply
  • Hi

    I made a global int variable monitor (as flag) and added it in the while loop of the main function.

    while (1) {
    
    
    		err = poll(&fds, 1, K_SECONDS(CONFIG_MQTT_KEEPALIVE));
    		if (err < 0) {
    			printk("ERROR: poll %d\n", errno);
    			break;
    		}
    
    		err = mqtt_live(&client);
    		if (err != 0) {
    			printk("ERROR: mqtt_live %d\n", err);
    			break;
    		}
    
    		if ((fds.revents & POLLIN) == POLLIN) {
    			err = mqtt_input(&client);
    			if (err != 0) {
    				printk("ERROR: mqtt_input %d\n", err);
    				break;
    			}
    		}
    
    		if ((fds.revents & POLLERR) == POLLERR) {
    			printk("POLLERR\n");
    			break;
    		}
    
    		if ((fds.revents & POLLNVAL) == POLLNVAL) {
    			printk("POLLNVAL\n");
    			break;
    		}
                    
                    if(monitor == 1){
                    data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE,
    				inData, sizeof(inData));
                    monitor = 0;
                    } 
                    
    	}
    I set the flag in the interrupt handler as shown here
    void uart_cb(struct device *x)
    {
    	uart_irq_update(x);
    	int data_length = 0;
    
    	if (uart_irq_rx_ready(x)) {
    		data_length = uart_fifo_read(x, uart_buf, sizeof(uart_buf));
    		uart_buf[data_length] = 0;
    	}
    
            if(i==19 || *uart_buf == '?'){ 
            inData[i] = '\0';
            printk("%s\n",inData);
            i=0;
            monitor = 1; // flag
            }
            else{
            memcpy(&inData[i], uart_buf, 1); 
            i++;
            }
    }
    Still triggers after I get the published data. Don't know what to do

    Regards

    NordicUser

Children
Related