Add an aditional (void *) arg to the RMT callback (much like Ticker() et.al.). (#3345)
* Add an aditional (void *) arg to the RMT callback - to allow more flexible handling of the callback (e.g. by passing a private struct or a class pointer). Same pattern as used by the Ticker() and many others. Example updated & new example with a trapoline added. * Fix example for new API * Fix lint warnings * Add a second missed example. * Correct timeout & improve socket error handling.
This commit is contained in:
		
							parent
							
								
									831f0ac29a
								
							
						
					
					
						commit
						d79a1f3d10
					
				| @ -94,6 +94,7 @@ struct rmt_obj_s | ||||
|     transaction_state_t tx_state; | ||||
|     rmt_rx_data_cb_t cb; | ||||
|     bool data_alloc; | ||||
|     void * arg; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -104,14 +105,14 @@ static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { | ||||
| }; | ||||
| 
 | ||||
| static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
|     { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -324,6 +325,7 @@ bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size) | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool rmtBeginReceive(rmt_obj_t* rmt) | ||||
| { | ||||
|     if (!rmt) { | ||||
| @ -357,7 +359,7 @@ bool rmtReceiveCompleted(rmt_obj_t* rmt) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) | ||||
| bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg) | ||||
| { | ||||
|     if (!rmt && !cb) { | ||||
|         return false; | ||||
| @ -365,6 +367,7 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) | ||||
|     int channel = rmt->channel; | ||||
| 
 | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt->arg = arg; | ||||
|     rmt->intr_mode = E_RX_INTR; | ||||
|     rmt->tx_state = E_FIRST_HALF; | ||||
|     rmt->cb = cb; | ||||
| @ -391,6 +394,19 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool rmtEnd(rmt_obj_t* rmt) { | ||||
|     if (!rmt) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
| 
 | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     RMT.conf_ch[channel].conf1.rx_en = 1; | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
| 
 | ||||
|     return  true; | ||||
| } | ||||
| 
 | ||||
| bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout) | ||||
| { | ||||
|     if (!rmt) { | ||||
| @ -523,6 +539,8 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) | ||||
|     rmt->tx_not_rx = tx_not_rx; | ||||
|     rmt->buffers =buffers; | ||||
|     rmt->channel = channel; | ||||
|     rmt->arg = NULL; | ||||
| 
 | ||||
|     _initPin(pin, channel, tx_not_rx); | ||||
| 
 | ||||
|     // Initialize the registers in default mode:
 | ||||
| @ -544,6 +562,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) | ||||
|     RMT.conf_ch[channel].conf1.idle_out_lv = 0;     // signal level for idle
 | ||||
|     RMT.conf_ch[channel].conf1.idle_out_en = 1;     // enable idle
 | ||||
|     RMT.conf_ch[channel].conf1.ref_always_on = 0;     // base clock
 | ||||
| 
 | ||||
|     RMT.apb_conf.fifo_mask = 1; | ||||
| 
 | ||||
|     if (tx_not_rx) { | ||||
| @ -659,7 +678,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) | ||||
|                     } | ||||
|                     if (g_rmt_objects[ch].cb) { | ||||
|                         // actually received data ptr                        
 | ||||
|                         (g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch)); | ||||
|                         (g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch), g_rmt_objects[ch].arg); | ||||
| 
 | ||||
|                         // restart the reception
 | ||||
|                         RMT.conf_ch[ch].conf1.mem_owner = 1; | ||||
|  | ||||
| @ -40,7 +40,7 @@ typedef enum { | ||||
| 
 | ||||
| typedef struct rmt_obj_s rmt_obj_t; | ||||
| 
 | ||||
| typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len); | ||||
| typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len, void *arg); | ||||
| 
 | ||||
| typedef struct { | ||||
|     union { | ||||
| @ -90,8 +90,13 @@ bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag | ||||
| *    and callback with data from ISR | ||||
| * | ||||
| */ | ||||
| bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb); | ||||
| bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg); | ||||
| 
 | ||||
| /***
 | ||||
|  * Ends async receive started with rmtRead(); but does not | ||||
|  * rmtDeInit(). | ||||
|  */ | ||||
| bool rmtEnd(rmt_obj_t* rmt); | ||||
| 
 | ||||
| /*  Additional interface */ | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										64
									
								
								libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| #include "Arduino.h" | ||||
| #include "esp32-hal.h" | ||||
| 
 | ||||
| extern "C" void receive_trampoline(uint32_t *data, size_t len, void * arg); | ||||
| 
 | ||||
| class MyProcessor { | ||||
|   private: | ||||
|     rmt_obj_t* rmt_recv = NULL; | ||||
|     float realNanoTick; | ||||
|     uint32_t buff; // rolling buffer of most recent 32 bits.
 | ||||
|     int at = 0; | ||||
| 
 | ||||
|   public: | ||||
|     MyProcessor(uint8_t pin, float nanoTicks) { | ||||
|       assert((rmt_recv = rmtInit(21, false, RMT_MEM_192))); | ||||
| 
 | ||||
|       realNanoTick = rmtSetTick(rmt_recv, nanoTicks); | ||||
|     }; | ||||
|     void begin() { | ||||
|       rmtRead(rmt_recv, receive_trampoline, this); | ||||
|     }; | ||||
| 
 | ||||
|     void process(rmt_data_t *data, size_t len) { | ||||
|       for (int i = 0; len; len--) { | ||||
|         if (data[i].duration0 == 0) | ||||
|           break; | ||||
|         buff = (buff << 1) | (data[i].level0 ? 1 : 0); | ||||
|         i++; | ||||
| 
 | ||||
|         if (data[i].duration1 == 0) | ||||
|           break; | ||||
|         buff = (buff << 1) | (data[i].level1 ? 1 : 0); | ||||
|         i++; | ||||
|       }; | ||||
|     }; | ||||
|     uint32_t val() { | ||||
|       return buff; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void receive_trampoline(uint32_t *data, size_t len, void * arg) | ||||
| { | ||||
|   MyProcessor * p = (MyProcessor *)arg; | ||||
|   p->process((rmt_data_t*) data, len); | ||||
| } | ||||
| 
 | ||||
| // Attach 3 processors to GPIO 4, 5 and 10 with different tick/speeds.
 | ||||
| MyProcessor mp1 = MyProcessor(4, 1000); | ||||
| MyProcessor mp2 = MyProcessor(5, 1000); | ||||
| MyProcessor mp3 = MyProcessor(10, 500); | ||||
| 
 | ||||
| void setup() | ||||
| { | ||||
|   Serial.begin(115200); | ||||
|   mp1.begin(); | ||||
|   mp2.begin(); | ||||
|   mp3.begin(); | ||||
| } | ||||
| 
 | ||||
| void loop() | ||||
| { | ||||
|   Serial.printf("GPIO 4: %08x 5: %08x 6: %08x\n", mp1.val(), mp2.val(), mp3.val()); | ||||
|   delay(500); | ||||
| } | ||||
| @ -172,7 +172,7 @@ void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels){ | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| extern "C" void receive_data(uint32_t *data, size_t len) | ||||
| extern "C" void receive_data(uint32_t *data, size_t len, void * arg) | ||||
| { | ||||
|     parseRmt((rmt_data_t*) data, len, channels); | ||||
| } | ||||
| @ -192,7 +192,7 @@ void setup() | ||||
|     Serial.printf("real tick set to: %fns\n", realTick); | ||||
| 
 | ||||
|     // Ask to start reading
 | ||||
|     rmtRead(rmt_recv, receive_data); | ||||
|     rmtRead(rmt_recv, receive_data, NULL); | ||||
| } | ||||
| 
 | ||||
| void loop()  | ||||
|  | ||||
| @ -80,12 +80,16 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p | ||||
| 
 | ||||
|     if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { | ||||
|         if(timeout <= 0){ | ||||
|             timeout = 30000; | ||||
|             timeout = 30000; // Milli seconds.
 | ||||
|         } | ||||
|         lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); | ||||
|         lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); | ||||
|         lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)); | ||||
|         lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); | ||||
|         timeval so_timeout = { .tv_sec = timeout / 1000, .tv_usec = (timeout % 1000) * 1000 }; | ||||
| 
 | ||||
| #define ROE(x,msg) { if (((x)<0)) { log_e("LWIP Socket config of " msg " failed."); return -1; }} | ||||
|         ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &so_timeout, sizeof(so_timeout)),"SO_RCVTIMEO"); | ||||
|         ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &so_timeout, sizeof(so_timeout)),"SO_SNDTIMEO"); | ||||
| 
 | ||||
|         ROE(lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY"); | ||||
|         ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE"); | ||||
|     } else { | ||||
|         log_e("Connect to Server failed!"); | ||||
|         return -1; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user