├── LICENSE
├── esp
├── Makefile
├── driver
│ ├── uart.c
│ ├── uart.h
│ └── uart_register.h
├── main.c
├── umqtt-esp.c
├── umqtt-esp.h
└── user_config.h
├── umqtt
├── umqtt.c
└── umqtt.h
└── unix
├── Makefile
└── main.c
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2015 Josef Gajdusek
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/esp/Makefile:
--------------------------------------------------------------------------------
1 | NAME = umqtt-esp
2 | CC = xtensa-lx106-elf-gcc
3 |
4 | UMQTT = ../umqtt
5 |
6 | CFLAGS = -I$(UMQTT) -Wall -Wno-implicit-function-declaration -Os -I$(PWD) -mlongcalls -mlongcalls
7 | LDLIBS = -nostdlib -Wl,--start-group -lmain -lupgrade -lnet80211 -lwpa -llwip \
8 | -lpp -lphy -Wl,--end-group -lcirom -lgcc
9 | LDFLAGS = -Teagle.app.v6.ld
10 |
11 | $(NAME)-0x00000.bin: $(NAME)
12 | esptool.py elf2image $^
13 |
14 | $(NAME): \
15 | main.o \
16 | driver/uart.o \
17 | $(UMQTT)/umqtt.c \
18 | umqtt-esp.o
19 | $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS)
20 |
21 | flash: $(NAME)-0x00000.bin
22 | esptool.py write_flash 0x00000 $(NAME)-0x00000.bin 0x40000 $(NAME)-0x40000.bin
23 |
24 | clean:
25 | rm -rf $(NAME) $(NAME)-0x00000.bin $(NAME)-0x40000.bin *.o driver/*.o $(UMQTT)/*.o
26 |
27 |
--------------------------------------------------------------------------------
/esp/driver/uart.c:
--------------------------------------------------------------------------------
1 | /*
2 | * File : uart.c
3 | * Copyright (C) 2013 - 2016, Espressif Systems
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of version 3 of the GNU General Public License as
7 | * published by the Free Software Foundation.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program. If not, see .
16 | */
17 |
18 | #include "ets_sys.h"
19 | #include "osapi.h"
20 | #include "driver/uart.h"
21 | #include "osapi.h"
22 | #include "driver/uart_register.h"
23 | #include "mem.h"
24 | #include "os_type.h"
25 |
26 | // UartDev is defined and initialized in rom code.
27 | extern UartDevice UartDev;
28 |
29 | LOCAL struct UartBuffer* pTxBuffer = NULL;
30 | //LOCAL struct UartBuffer* pRxBuffer = NULL;
31 |
32 | /*uart demo with a system task, to output what uart receives*/
33 | /*this is a example to process uart data from task,please change the priority to fit your application task if exists*/
34 | /*it might conflict with your task, if so,please arrange the priority of different task, or combine it to a different event in the same task. */
35 | #define uart_recvTaskPrio 0
36 | #define uart_recvTaskQueueLen 10
37 | os_event_t uart_recvTaskQueue[uart_recvTaskQueueLen];
38 |
39 | #define DBG
40 | #define DBG1 uart1_sendStr_no_wait
41 | #define DBG2 os_printf
42 |
43 |
44 | LOCAL void uart0_rx_intr_handler(void *para);
45 |
46 | /******************************************************************************
47 | * FunctionName : uart_config
48 | * Description : Internal used function
49 | * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
50 | * UART1 just used for debug output
51 | * Parameters : uart_no, use UART0 or UART1 defined ahead
52 | * Returns : NONE
53 | *******************************************************************************/
54 | LOCAL void ICACHE_FLASH_ATTR
55 | uart_config(uint8 uart_no)
56 | {
57 | if (uart_no == UART1){
58 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
59 | }else{
60 | /* rcv_buff size if 0x100 */
61 | ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
62 | PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
63 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
64 | #if UART_HW_RTS
65 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); //HW FLOW CONTROL RTS PIN
66 | #endif
67 | #if UART_HW_CTS
68 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS); //HW FLOW CONTROL CTS PIN
69 | #endif
70 | }
71 | uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));//SET BAUDRATE
72 |
73 | WRITE_PERI_REG(UART_CONF0(uart_no), ((UartDev.exist_parity & UART_PARITY_EN_M) << UART_PARITY_EN_S) //SET BIT AND PARITY MODE
74 | | ((UartDev.parity & UART_PARITY_M) <> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
118 | break;
119 | }
120 | }
121 | WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
122 | return OK;
123 | }
124 |
125 | /******************************************************************************
126 | * FunctionName : uart1_write_char
127 | * Description : Internal used function
128 | * Do some special deal while tx char is '\r' or '\n'
129 | * Parameters : char c - character to tx
130 | * Returns : NONE
131 | *******************************************************************************/
132 | LOCAL void ICACHE_FLASH_ATTR
133 | uart1_write_char(char c)
134 | {
135 | if (c == '\n'){
136 | uart_tx_one_char(UART0, '\r');
137 | uart_tx_one_char(UART0, '\n');
138 | }else if (c == '\r'){
139 |
140 | }else{
141 | uart_tx_one_char(UART0, c);
142 | }
143 | }
144 |
145 | //os_printf output to fifo or to the tx buffer
146 | LOCAL void ICACHE_FLASH_ATTR
147 | uart0_write_char_no_wait(char c)
148 | {
149 | #if UART_BUFF_EN //send to uart0 fifo but do not wait
150 | uint8 chr;
151 | if (c == '\n'){
152 | chr = '\r';
153 | tx_buff_enq(&chr, 1);
154 | chr = '\n';
155 | tx_buff_enq(&chr, 1);
156 | }else if (c == '\r'){
157 |
158 | }else{
159 | tx_buff_enq(&c,1);
160 | }
161 | #else //send to uart tx buffer
162 | if (c == '\n'){
163 | uart_tx_one_char_no_wait(UART0, '\r');
164 | uart_tx_one_char_no_wait(UART0, '\n');
165 | }else if (c == '\r'){
166 |
167 | }
168 | else{
169 | uart_tx_one_char_no_wait(UART0, c);
170 | }
171 | #endif
172 | }
173 |
174 | /******************************************************************************
175 | * FunctionName : uart0_tx_buffer
176 | * Description : use uart0 to transfer buffer
177 | * Parameters : uint8 *buf - point to send buffer
178 | * uint16 len - buffer len
179 | * Returns :
180 | *******************************************************************************/
181 | void ICACHE_FLASH_ATTR
182 | uart0_tx_buffer(uint8 *buf, uint16 len)
183 | {
184 | uint16 i;
185 | for (i = 0; i < len; i++)
186 | {
187 | uart_tx_one_char(UART0, buf[i]);
188 | }
189 | }
190 |
191 | /******************************************************************************
192 | * FunctionName : uart0_sendStr
193 | * Description : use uart0 to transfer buffer
194 | * Parameters : uint8 *buf - point to send buffer
195 | * uint16 len - buffer len
196 | * Returns :
197 | *******************************************************************************/
198 | void ICACHE_FLASH_ATTR
199 | uart0_sendStr(const char *str)
200 | {
201 | while(*str){
202 | uart_tx_one_char(UART0, *str++);
203 | }
204 | }
205 | void at_port_print(const char *str) __attribute__((alias("uart0_sendStr")));
206 | /******************************************************************************
207 | * FunctionName : uart0_rx_intr_handler
208 | * Description : Internal used function
209 | * UART0 interrupt handler, add self handle code inside
210 | * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
211 | * Returns : NONE
212 | *******************************************************************************/
213 | LOCAL void
214 | uart0_rx_intr_handler(void *para)
215 | {
216 | /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
217 | * uart1 and uart0 respectively
218 | */
219 | uint8 uart_no = UART0;//UartDev.buff_uart_no;
220 | //RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para;
221 |
222 | /*ATTENTION:*/
223 | /*IN NON-OS VERSION SDK, DO NOT USE "ICACHE_FLASH_ATTR" FUNCTIONS IN THE WHOLE HANDLER PROCESS*/
224 | /*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */
225 | /*IF NOT , POST AN EVENT AND PROCESS IN SYSTEM TASK */
226 | if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)){
227 | DBG1("FRM_ERR\r\n");
228 | WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
229 | }else if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)){
230 | uart_rx_intr_disable(UART0);
231 | WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
232 | system_os_post(uart_recvTaskPrio, 0, 0);
233 | }else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)){
234 | uart_rx_intr_disable(UART0);
235 | WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
236 | system_os_post(uart_recvTaskPrio, 0, 0);
237 | }else if(UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)){
238 | /* to output uart data from uart buffer directly in empty interrupt handler*/
239 | /*instead of processing in system event, in order not to wait for current task/function to quit */
240 | /*ATTENTION:*/
241 | /*IN NON-OS VERSION SDK, DO NOT USE "ICACHE_FLASH_ATTR" FUNCTIONS IN THE WHOLE HANDLER PROCESS*/
242 | /*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */
243 | CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
244 | #if UART_BUFF_EN
245 | tx_start_uart_buffer(UART0);
246 | #endif
247 | //system_os_post(uart_recvTaskPrio, 1, 0);
248 | WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
249 |
250 | }else if(UART_RXFIFO_OVF_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)){
251 | WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR);
252 | DBG1("RX OVF!!\r\n");
253 | }
254 |
255 | }
256 |
257 | /******************************************************************************
258 | * FunctionName : uart_init
259 | * Description : user interface for init uart
260 | * Parameters : UartBautRate uart0_br - uart0 bautrate
261 | * UartBautRate uart1_br - uart1 bautrate
262 | * Returns : NONE
263 | *******************************************************************************/
264 | #if UART_SELFTEST&UART_BUFF_EN
265 | os_timer_t buff_timer_t;
266 | void ICACHE_FLASH_ATTR
267 | uart_test_rx()
268 | {
269 | uint8 uart_buf[128]={0};
270 | uint16 len = 0;
271 | len = rx_buff_deq(uart_buf, 128 );
272 | tx_buff_enq(uart_buf,len);
273 | }
274 | #endif
275 |
276 | LOCAL void ICACHE_FLASH_ATTR ///////
277 | uart_recvTask(os_event_t *events)
278 | {
279 | if(events->sig == 0){
280 | #if UART_BUFF_EN
281 | Uart_rx_buff_enq();
282 | #else
283 | uint8 fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
284 | uint8 d_tmp = 0;
285 | uint8 idx=0;
286 | for(idx=0;idxsig == 1){
294 | #if UART_BUFF_EN
295 | //already move uart buffer output to uart empty interrupt
296 | //tx_start_uart_buffer(UART0);
297 | #else
298 |
299 | #endif
300 | }
301 | }
302 |
303 | void ICACHE_FLASH_ATTR
304 | uart_init(UartBautRate uart0_br, UartBautRate uart1_br)
305 | {
306 | /*this is a example to process uart data from task,please change the priority to fit your application task if exists*/
307 | system_os_task(uart_recvTask, uart_recvTaskPrio, uart_recvTaskQueue, uart_recvTaskQueueLen); //demo with a task to process the uart data
308 |
309 | UartDev.baut_rate = uart0_br;
310 | uart_config(UART0);
311 | UartDev.baut_rate = uart1_br;
312 | uart_config(UART1);
313 | ETS_UART_INTR_ENABLE();
314 |
315 | #if UART_BUFF_EN
316 | pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);
317 | pRxBuffer = Uart_Buf_Init(UART_RX_BUFFER_SIZE);
318 | #endif
319 |
320 |
321 | /*option 1: use default print, output from uart0 , will wait some time if fifo is full */
322 | //do nothing...
323 |
324 | /*option 2: output from uart1,uart1 output will not wait , just for output debug info */
325 | /*os_printf output uart data via uart1(GPIO2)*/
326 | os_install_putc1((void *)uart1_write_char); //use this one to output debug information via uart1 //
327 |
328 | /*option 3: output from uart0 will skip current byte if fifo is full now... */
329 | /*see uart0_write_char_no_wait:you can output via a buffer or output directly */
330 | /*os_printf output uart data via uart0 or uart buffer*/
331 | //os_install_putc1((void *)uart0_write_char_no_wait); //use this to print via uart0
332 |
333 | #if UART_SELFTEST&UART_BUFF_EN
334 | os_timer_disarm(&buff_timer_t);
335 | os_timer_setfn(&buff_timer_t, uart_test_rx , NULL); //a demo to process the data in uart rx buffer
336 | os_timer_arm(&buff_timer_t,10,1);
337 | #endif
338 | }
339 |
340 | void ICACHE_FLASH_ATTR
341 | uart_reattach()
342 | {
343 | uart_init(BIT_RATE_115200, BIT_RATE_115200);
344 | }
345 |
346 | /******************************************************************************
347 | * FunctionName : uart_tx_one_char_no_wait
348 | * Description : uart tx a single char without waiting for fifo
349 | * Parameters : uint8 uart - uart port
350 | * uint8 TxChar - char to tx
351 | * Returns : STATUS
352 | *******************************************************************************/
353 | STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar)
354 | {
355 | uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);
356 | if (fifo_cnt < 126) {
357 | WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
358 | }
359 | return OK;
360 | }
361 |
362 | STATUS uart0_tx_one_char_no_wait(uint8 TxChar)
363 | {
364 | uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(UART0))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);
365 | if (fifo_cnt < 126) {
366 | WRITE_PERI_REG(UART_FIFO(UART0) , TxChar);
367 | }
368 | return OK;
369 | }
370 |
371 |
372 | /******************************************************************************
373 | * FunctionName : uart1_sendStr_no_wait
374 | * Description : uart tx a string without waiting for every char, used for print debug info which can be lost
375 | * Parameters : const char *str - string to be sent
376 | * Returns : NONE
377 | *******************************************************************************/
378 | void uart1_sendStr_no_wait(const char *str)
379 | {
380 | while(*str){
381 | uart_tx_one_char_no_wait(UART1, *str++);
382 | }
383 | }
384 |
385 |
386 | #if UART_BUFF_EN
387 | /******************************************************************************
388 | * FunctionName : Uart_Buf_Init
389 | * Description : tx buffer enqueue: fill a first linked buffer
390 | * Parameters : char *pdata - data point to be enqueue
391 | * Returns : NONE
392 | *******************************************************************************/
393 | struct UartBuffer* ICACHE_FLASH_ATTR
394 | Uart_Buf_Init(uint32 buf_size)
395 | {
396 | uint32 heap_size = system_get_free_heap_size();
397 | if(heap_size <=buf_size){
398 | DBG1("no buf for uart\n\r");
399 | return NULL;
400 | }else{
401 | DBG("test heap size: %d\n\r",heap_size);
402 | struct UartBuffer* pBuff = (struct UartBuffer* )os_malloc(sizeof(struct UartBuffer));
403 | pBuff->UartBuffSize = buf_size;
404 | pBuff->pUartBuff = (uint8*)os_malloc(pBuff->UartBuffSize);
405 | pBuff->pInPos = pBuff->pUartBuff;
406 | pBuff->pOutPos = pBuff->pUartBuff;
407 | pBuff->Space = pBuff->UartBuffSize;
408 | pBuff->BuffState = OK;
409 | pBuff->nextBuff = NULL;
410 | pBuff->TcpControl = RUN;
411 | return pBuff;
412 | }
413 | }
414 |
415 |
416 | //copy uart buffer
417 | LOCAL void Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len)
418 | {
419 | if(data_len == 0) return ;
420 |
421 | uint16 tail_len = pCur->pUartBuff + pCur->UartBuffSize - pCur->pInPos ;
422 | if(tail_len >= data_len){ //do not need to loop back the queue
423 | os_memcpy(pCur->pInPos , pdata , data_len );
424 | pCur->pInPos += ( data_len );
425 | pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize );
426 | pCur->Space -=data_len;
427 | }else{
428 | os_memcpy(pCur->pInPos, pdata, tail_len);
429 | pCur->pInPos += ( tail_len );
430 | pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize );
431 | pCur->Space -=tail_len;
432 | os_memcpy(pCur->pInPos, pdata+tail_len , data_len-tail_len);
433 | pCur->pInPos += ( data_len-tail_len );
434 | pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize );
435 | pCur->Space -=( data_len-tail_len);
436 | }
437 |
438 | }
439 |
440 | /******************************************************************************
441 | * FunctionName : uart_buf_free
442 | * Description : deinit of the tx buffer
443 | * Parameters : struct UartBuffer* pTxBuff - tx buffer struct pointer
444 | * Returns : NONE
445 | *******************************************************************************/
446 | void ICACHE_FLASH_ATTR
447 | uart_buf_free(struct UartBuffer* pBuff)
448 | {
449 | os_free(pBuff->pUartBuff);
450 | os_free(pBuff);
451 | }
452 |
453 |
454 | //rx buffer dequeue
455 | uint16 ICACHE_FLASH_ATTR
456 | rx_buff_deq(char* pdata, uint16 data_len )
457 | {
458 | uint16 buf_len = (pRxBuffer->UartBuffSize- pRxBuffer->Space);
459 | uint16 tail_len = pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize - pRxBuffer->pOutPos ;
460 | uint16 len_tmp = 0;
461 | len_tmp = ((data_len > buf_len)?buf_len:data_len);
462 | if(pRxBuffer->pOutPos <= pRxBuffer->pInPos){
463 | os_memcpy(pdata, pRxBuffer->pOutPos,len_tmp);
464 | pRxBuffer->pOutPos+= len_tmp;
465 | pRxBuffer->Space += len_tmp;
466 | }else{
467 | if(len_tmp>tail_len){
468 | os_memcpy(pdata, pRxBuffer->pOutPos, tail_len);
469 | pRxBuffer->pOutPos += tail_len;
470 | pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize );
471 | pRxBuffer->Space += tail_len;
472 |
473 | os_memcpy(pdata+tail_len , pRxBuffer->pOutPos, len_tmp-tail_len);
474 | pRxBuffer->pOutPos+= ( len_tmp-tail_len );
475 | pRxBuffer->pOutPos= (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize );
476 | pRxBuffer->Space +=( len_tmp-tail_len);
477 | }else{
478 | //os_printf("case 3 in rx deq\n\r");
479 | os_memcpy(pdata, pRxBuffer->pOutPos, len_tmp);
480 | pRxBuffer->pOutPos += len_tmp;
481 | pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize );
482 | pRxBuffer->Space += len_tmp;
483 | }
484 | }
485 | if(pRxBuffer->Space >= UART_FIFO_LEN){
486 | uart_rx_intr_enable(UART0);
487 | }
488 | return len_tmp;
489 | }
490 |
491 |
492 | //move data from uart fifo to rx buffer
493 | void Uart_rx_buff_enq()
494 | {
495 | uint8 fifo_len;
496 | uint8 fifo_data;
497 | #if 1
498 | fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
499 | if(fifo_len >= pRxBuffer->Space){
500 | os_printf("buf full!!!\n\r");
501 | }else{
502 | buf_idx=0;
503 | while(buf_idx < fifo_len){
504 | buf_idx++;
505 | fifo_data = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
506 | *(pRxBuffer->pInPos++) = fifo_data;
507 | if(pRxBuffer->pInPos == (pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize)){
508 | pRxBuffer->pInPos = pRxBuffer->pUartBuff;
509 | }
510 | }
511 | pRxBuffer->Space -= fifo_len ;
512 | if(pRxBuffer->Space >= UART_FIFO_LEN){
513 | //os_printf("after rx enq buf enough\n\r");
514 | uart_rx_intr_enable(UART0);
515 | }
516 | }
517 | #endif
518 | }
519 |
520 |
521 | //fill the uart tx buffer
522 | void ICACHE_FLASH_ATTR
523 | tx_buff_enq(char* pdata, uint16 data_len )
524 | {
525 | CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
526 |
527 | if(pTxBuffer == NULL){
528 | DBG1("\n\rnull, create buffer struct\n\r");
529 | pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);
530 | if(pTxBuffer!= NULL){
531 | Uart_Buf_Cpy(pTxBuffer , pdata, data_len );
532 | }else{
533 | DBG1("uart tx MALLOC no buf \n\r");
534 | }
535 | }else{
536 | if(data_len <= pTxBuffer->Space){
537 | Uart_Buf_Cpy(pTxBuffer , pdata, data_len);
538 | }else{
539 | DBG1("UART TX BUF FULL!!!!\n\r");
540 | }
541 | }
542 | #if 0
543 | if(pTxBuffer->Space <= URAT_TX_LOWER_SIZE){
544 | set_tcp_block();
545 | }
546 | #endif
547 | SET_PERI_REG_MASK(UART_CONF1(UART0), (UART_TX_EMPTY_THRESH_VAL & UART_TXFIFO_EMPTY_THRHD)<pOutPos++));
559 | if(pTxBuff->pOutPos == (pTxBuff->pUartBuff + pTxBuff->UartBuffSize)){
560 | pTxBuff->pOutPos = pTxBuff->pUartBuff;
561 | }
562 | }
563 | pTxBuff->pOutPos = (pTxBuff->pUartBuff + (pTxBuff->pOutPos - pTxBuff->pUartBuff) % pTxBuff->UartBuffSize );
564 | pTxBuff->Space += data_len;
565 | }
566 |
567 |
568 | /******************************************************************************
569 | * FunctionName : tx_start_uart_buffer
570 | * Description : get data from the tx buffer and fill the uart tx fifo, co-work with the uart fifo empty interrupt
571 | * Parameters : uint8 uart_no - uart port num
572 | * Returns : NONE
573 | *******************************************************************************/
574 | void tx_start_uart_buffer(uint8 uart_no)
575 | {
576 | uint8 tx_fifo_len = (READ_PERI_REG(UART_STATUS(uart_no))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT;
577 | uint8 fifo_remain = UART_FIFO_LEN - tx_fifo_len ;
578 | uint8 len_tmp;
579 | uint16 tail_ptx_len,head_ptx_len,data_len;
580 | //struct UartBuffer* pTxBuff = *get_buff_prt();
581 |
582 | if(pTxBuffer){
583 | data_len = (pTxBuffer->UartBuffSize - pTxBuffer->Space);
584 | if(data_len > fifo_remain){
585 | len_tmp = fifo_remain;
586 | tx_fifo_insert( pTxBuffer,len_tmp,uart_no);
587 | SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
588 | }else{
589 | len_tmp = data_len;
590 | tx_fifo_insert( pTxBuffer,len_tmp,uart_no);
591 | }
592 | }else{
593 | DBG1("pTxBuff null \n\r");
594 | }
595 | }
596 |
597 | #endif
598 |
599 |
600 | void uart_rx_intr_disable(uint8 uart_no)
601 | {
602 | #if 1
603 | CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
604 | #else
605 | ETS_UART_INTR_DISABLE();
606 | #endif
607 | }
608 |
609 | void uart_rx_intr_enable(uint8 uart_no)
610 | {
611 | #if 1
612 | SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
613 | #else
614 | ETS_UART_INTR_ENABLE();
615 | #endif
616 | }
617 |
618 |
619 | //========================================================
620 | LOCAL void
621 | uart0_write_char(char c)
622 | {
623 | if (c == '\n') {
624 | uart_tx_one_char(UART0, '\r');
625 | uart_tx_one_char(UART0, '\n');
626 | } else if (c == '\r') {
627 | } else {
628 | uart_tx_one_char(UART0, c);
629 | }
630 | }
631 |
632 | void ICACHE_FLASH_ATTR
633 | UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len)
634 | {
635 | SET_PERI_REG_BITS(UART_CONF0(uart_no),UART_BIT_NUM,len,UART_BIT_NUM_S);
636 | }
637 |
638 | void ICACHE_FLASH_ATTR
639 | UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num)
640 | {
641 | SET_PERI_REG_BITS(UART_CONF0(uart_no),UART_STOP_BIT_NUM,bit_num,UART_STOP_BIT_NUM_S);
642 | }
643 |
644 | void ICACHE_FLASH_ATTR
645 | UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask)
646 | {
647 | CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_LINE_INV_MASK);
648 | SET_PERI_REG_MASK(UART_CONF0(uart_no), inverse_mask);
649 | }
650 |
651 | void ICACHE_FLASH_ATTR
652 | UART_SetParity(uint8 uart_no, UartParityMode Parity_mode)
653 | {
654 | CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_PARITY |UART_PARITY_EN);
655 | if(Parity_mode==NONE_BITS){
656 | }else{
657 | SET_PERI_REG_MASK(UART_CONF0(uart_no), Parity_mode|UART_PARITY_EN);
658 | }
659 | }
660 |
661 | void ICACHE_FLASH_ATTR
662 | UART_SetBaudrate(uint8 uart_no,uint32 baud_rate)
663 | {
664 | uart_div_modify(uart_no, UART_CLK_FREQ /baud_rate);
665 | }
666 |
667 | void ICACHE_FLASH_ATTR
668 | UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh)
669 | {
670 | if(flow_ctrl&USART_HardwareFlowControl_RTS){
671 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
672 | SET_PERI_REG_BITS(UART_CONF1(uart_no),UART_RX_FLOW_THRHD,rx_thresh,UART_RX_FLOW_THRHD_S);
673 | SET_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
674 | }else{
675 | CLEAR_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
676 | }
677 | if(flow_ctrl&USART_HardwareFlowControl_CTS){
678 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS);
679 | SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
680 | }else{
681 | CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
682 | }
683 | }
684 |
685 | void ICACHE_FLASH_ATTR
686 | UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us) //do not use if tx flow control enabled
687 | {
688 | uint32 t_s = system_get_time();
689 | while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)){
690 |
691 | if(( system_get_time() - t_s )> time_out_us){
692 | break;
693 | }
694 | WRITE_PERI_REG(0X60000914, 0X73);//WTD
695 |
696 | }
697 | }
698 |
699 |
700 | bool ICACHE_FLASH_ATTR
701 | UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us)
702 | {
703 | uint32 t_start = system_get_time();
704 | uint8 tx_fifo_len;
705 | uint32 tx_buff_len;
706 | while(1){
707 | tx_fifo_len =( (READ_PERI_REG(UART_STATUS(uart_no))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT);
708 | if(pTxBuffer){
709 | tx_buff_len = ((pTxBuffer->UartBuffSize)-(pTxBuffer->Space));
710 | }else{
711 | tx_buff_len = 0;
712 | }
713 |
714 | if( tx_fifo_len==0 && tx_buff_len==0){
715 | return TRUE;
716 | }
717 | if( system_get_time() - t_start > time_out_us){
718 | return FALSE;
719 | }
720 | WRITE_PERI_REG(0X60000914, 0X73);//WTD
721 | }
722 | }
723 |
724 |
725 | void ICACHE_FLASH_ATTR
726 | UART_ResetFifo(uint8 uart_no)
727 | {
728 | SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
729 | CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
730 | }
731 |
732 | void ICACHE_FLASH_ATTR
733 | UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask)
734 | {
735 | WRITE_PERI_REG(UART_INT_CLR(uart_no), clr_mask);
736 | }
737 |
738 | void ICACHE_FLASH_ATTR
739 | UART_SetIntrEna(uint8 uart_no,uint32 ena_mask)
740 | {
741 | SET_PERI_REG_MASK(UART_INT_ENA(uart_no), ena_mask);
742 | }
743 |
744 |
745 | void ICACHE_FLASH_ATTR
746 | UART_SetPrintPort(uint8 uart_no)
747 | {
748 | if(uart_no==1){
749 | os_install_putc1(uart1_write_char);
750 | }else{
751 | /*option 1: do not wait if uart fifo is full,drop current character*/
752 | os_install_putc1(uart0_write_char_no_wait);
753 | /*option 2: wait for a while if uart fifo is full*/
754 | os_install_putc1(uart0_write_char);
755 | }
756 | }
757 |
758 |
759 | //========================================================
760 |
761 |
762 | /*test code*/
763 | void ICACHE_FLASH_ATTR
764 | uart_init_2(UartBautRate uart0_br, UartBautRate uart1_br)
765 | {
766 | // rom use 74880 baut_rate, here reinitialize
767 | UartDev.baut_rate = uart0_br;
768 | UartDev.exist_parity = STICK_PARITY_EN;
769 | UartDev.parity = EVEN_BITS;
770 | UartDev.stop_bits = ONE_STOP_BIT;
771 | UartDev.data_bits = EIGHT_BITS;
772 |
773 | uart_config(UART0);
774 | UartDev.baut_rate = uart1_br;
775 | uart_config(UART1);
776 | ETS_UART_INTR_ENABLE();
777 |
778 | // install uart1 putc callback
779 | os_install_putc1((void *)uart1_write_char);//print output at UART1
780 | }
781 |
782 |
783 |
--------------------------------------------------------------------------------
/esp/driver/uart.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File : uart.h
3 | * Copyright (C) 2013 - 2016, Espressif Systems
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of version 3 of the GNU General Public License as
7 | * published by the Free Software Foundation.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program. If not, see .
16 | */
17 | #ifndef UART_APP_H
18 | #define UART_APP_H
19 |
20 | #include "uart_register.h"
21 | #include "eagle_soc.h"
22 | #include "c_types.h"
23 |
24 | #define UART_TX_BUFFER_SIZE 256 //Ring buffer length of tx buffer
25 | #define UART_RX_BUFFER_SIZE 256 //Ring buffer length of rx buffer
26 |
27 | #define UART_BUFF_EN 0 //use uart buffer , FOR UART0
28 | #define UART_SELFTEST 0 //set 1:enable the loop test demo for uart buffer, FOR UART0
29 |
30 | #define UART_HW_RTS 0 //set 1: enable uart hw flow control RTS, PIN MTDO, FOR UART0
31 | #define UART_HW_CTS 0 //set1: enable uart hw flow contrl CTS , PIN MTCK, FOR UART0
32 |
33 |
34 |
35 |
36 | #define UART0 0
37 | #define UART1 1
38 |
39 |
40 | typedef enum {
41 | FIVE_BITS = 0x0,
42 | SIX_BITS = 0x1,
43 | SEVEN_BITS = 0x2,
44 | EIGHT_BITS = 0x3
45 | } UartBitsNum4Char;
46 |
47 | typedef enum {
48 | ONE_STOP_BIT = 0x1,
49 | ONE_HALF_STOP_BIT = 0x2,
50 | TWO_STOP_BIT = 0x3
51 | } UartStopBitsNum;
52 |
53 | typedef enum {
54 | NONE_BITS = 0x2,
55 | ODD_BITS = 1,
56 | EVEN_BITS = 0
57 | } UartParityMode;
58 |
59 | typedef enum {
60 | STICK_PARITY_DIS = 0,
61 | STICK_PARITY_EN = 1
62 | } UartExistParity;
63 |
64 | typedef enum {
65 | UART_None_Inverse = 0x0,
66 | UART_Rxd_Inverse = UART_RXD_INV,
67 | UART_CTS_Inverse = UART_CTS_INV,
68 | UART_Txd_Inverse = UART_TXD_INV,
69 | UART_RTS_Inverse = UART_RTS_INV,
70 | } UART_LineLevelInverse;
71 |
72 |
73 | typedef enum {
74 | BIT_RATE_300 = 300,
75 | BIT_RATE_600 = 600,
76 | BIT_RATE_1200 = 1200,
77 | BIT_RATE_2400 = 2400,
78 | BIT_RATE_4800 = 4800,
79 | BIT_RATE_9600 = 9600,
80 | BIT_RATE_19200 = 19200,
81 | BIT_RATE_38400 = 38400,
82 | BIT_RATE_57600 = 57600,
83 | BIT_RATE_74880 = 74880,
84 | BIT_RATE_115200 = 115200,
85 | BIT_RATE_230400 = 230400,
86 | BIT_RATE_460800 = 460800,
87 | BIT_RATE_921600 = 921600,
88 | BIT_RATE_1843200 = 1843200,
89 | BIT_RATE_3686400 = 3686400,
90 | } UartBautRate;
91 |
92 | typedef enum {
93 | NONE_CTRL,
94 | HARDWARE_CTRL,
95 | XON_XOFF_CTRL
96 | } UartFlowCtrl;
97 |
98 | typedef enum {
99 | USART_HardwareFlowControl_None = 0x0,
100 | USART_HardwareFlowControl_RTS = 0x1,
101 | USART_HardwareFlowControl_CTS = 0x2,
102 | USART_HardwareFlowControl_CTS_RTS = 0x3
103 | } UART_HwFlowCtrl;
104 |
105 | typedef enum {
106 | EMPTY,
107 | UNDER_WRITE,
108 | WRITE_OVER
109 | } RcvMsgBuffState;
110 |
111 | typedef struct {
112 | uint32 RcvBuffSize;
113 | uint8 *pRcvMsgBuff;
114 | uint8 *pWritePos;
115 | uint8 *pReadPos;
116 | uint8 TrigLvl; //JLU: may need to pad
117 | RcvMsgBuffState BuffState;
118 | } RcvMsgBuff;
119 |
120 | typedef struct {
121 | uint32 TrxBuffSize;
122 | uint8 *pTrxBuff;
123 | } TrxMsgBuff;
124 |
125 | typedef enum {
126 | BAUD_RATE_DET,
127 | WAIT_SYNC_FRM,
128 | SRCH_MSG_HEAD,
129 | RCV_MSG_BODY,
130 | RCV_ESC_CHAR,
131 | } RcvMsgState;
132 |
133 | typedef struct {
134 | UartBautRate baut_rate;
135 | UartBitsNum4Char data_bits;
136 | UartExistParity exist_parity;
137 | UartParityMode parity;
138 | UartStopBitsNum stop_bits;
139 | UartFlowCtrl flow_ctrl;
140 | RcvMsgBuff rcv_buff;
141 | TrxMsgBuff trx_buff;
142 | RcvMsgState rcv_state;
143 | int received;
144 | int buff_uart_no; //indicate which uart use tx/rx buffer
145 | } UartDevice;
146 |
147 | void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
148 | void uart0_sendStr(const char *str);
149 |
150 |
151 | ///////////////////////////////////////
152 | #define UART_FIFO_LEN 128 //define the tx fifo length
153 | #define UART_TX_EMPTY_THRESH_VAL 0x10
154 |
155 |
156 | struct UartBuffer{
157 | uint32 UartBuffSize;
158 | uint8 *pUartBuff;
159 | uint8 *pInPos;
160 | uint8 *pOutPos;
161 | STATUS BuffState;
162 | uint16 Space; //remanent space of the buffer
163 | uint8 TcpControl;
164 | struct UartBuffer * nextBuff;
165 | };
166 |
167 | struct UartRxBuff{
168 | uint32 UartRxBuffSize;
169 | uint8 *pUartRxBuff;
170 | uint8 *pWritePos;
171 | uint8 *pReadPos;
172 | STATUS RxBuffState;
173 | uint32 Space; //remanent space of the buffer
174 | } ;
175 |
176 | typedef enum {
177 | RUN = 0,
178 | BLOCK = 1,
179 | } TCPState;
180 |
181 | //void ICACHE_FLASH_ATTR uart_test_rx();
182 | STATUS uart_tx_one_char(uint8 uart, uint8 TxChar);
183 | STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar);
184 | void uart1_sendStr_no_wait(const char *str);
185 | struct UartBuffer* Uart_Buf_Init();
186 |
187 |
188 | #if UART_BUFF_EN
189 | LOCAL void Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len);
190 | void uart_buf_free(struct UartBuffer* pBuff);
191 | void tx_buff_enq(char* pdata, uint16 data_len );
192 | LOCAL void tx_fifo_insert(struct UartBuffer* pTxBuff, uint8 data_len, uint8 uart_no);
193 | void tx_start_uart_buffer(uint8 uart_no);
194 | uint16 rx_buff_deq(char* pdata, uint16 data_len );
195 | void Uart_rx_buff_enq();
196 | #endif
197 | void uart_rx_intr_enable(uint8 uart_no);
198 | void uart_rx_intr_disable(uint8 uart_no);
199 | void uart0_tx_buffer(uint8 *buf, uint16 len);
200 |
201 | //==============================================
202 | #define FUNC_UART0_CTS 4
203 | #define FUNC_U0CTS 4
204 | #define FUNC_U1TXD_BK 2
205 | #define UART_LINE_INV_MASK (0x3f<<19)
206 | void UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len);
207 | void UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num);
208 | void UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask);
209 | void UART_SetParity(uint8 uart_no, UartParityMode Parity_mode);
210 | void UART_SetBaudrate(uint8 uart_no,uint32 baud_rate);
211 | void UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh);
212 | void UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us); //do not use if tx flow control enabled
213 | void UART_ResetFifo(uint8 uart_no);
214 | void UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask);
215 | void UART_SetIntrEna(uint8 uart_no,uint32 ena_mask);
216 | void UART_SetPrintPort(uint8 uart_no);
217 | bool UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us);
218 | //==============================================
219 |
220 | #endif
221 |
222 |
--------------------------------------------------------------------------------
/esp/driver/uart_register.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File : uart_register.h
3 | * Copyright (C) 2013 - 2016, Espressif Systems
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of version 3 of the GNU General Public License as
7 | * published by the Free Software Foundation.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program. If not, see .
16 | */
17 | /*
18 | * Copyright (c) 2010 - 2011 Espressif System
19 | *
20 | */
21 |
22 | #ifndef UART_REGISTER_H_
23 | #define UART_REGISTER_H_
24 |
25 | #define REG_UART_BASE(i) (0x60000000 + (i)*0xf00)
26 | //version value:32'h062000
27 |
28 | #define UART_FIFO(i) (REG_UART_BASE(i) + 0x0)
29 | #define UART_RXFIFO_RD_BYTE 0x000000FF
30 | #define UART_RXFIFO_RD_BYTE_S 0
31 |
32 | #define UART_INT_RAW(i) (REG_UART_BASE(i) + 0x4)
33 | #define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
34 | #define UART_BRK_DET_INT_RAW (BIT(7))
35 | #define UART_CTS_CHG_INT_RAW (BIT(6))
36 | #define UART_DSR_CHG_INT_RAW (BIT(5))
37 | #define UART_RXFIFO_OVF_INT_RAW (BIT(4))
38 | #define UART_FRM_ERR_INT_RAW (BIT(3))
39 | #define UART_PARITY_ERR_INT_RAW (BIT(2))
40 | #define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
41 | #define UART_RXFIFO_FULL_INT_RAW (BIT(0))
42 |
43 | #define UART_INT_ST(i) (REG_UART_BASE(i) + 0x8)
44 | #define UART_RXFIFO_TOUT_INT_ST (BIT(8))
45 | #define UART_BRK_DET_INT_ST (BIT(7))
46 | #define UART_CTS_CHG_INT_ST (BIT(6))
47 | #define UART_DSR_CHG_INT_ST (BIT(5))
48 | #define UART_RXFIFO_OVF_INT_ST (BIT(4))
49 | #define UART_FRM_ERR_INT_ST (BIT(3))
50 | #define UART_PARITY_ERR_INT_ST (BIT(2))
51 | #define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
52 | #define UART_RXFIFO_FULL_INT_ST (BIT(0))
53 |
54 | #define UART_INT_ENA(i) (REG_UART_BASE(i) + 0xC)
55 | #define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
56 | #define UART_BRK_DET_INT_ENA (BIT(7))
57 | #define UART_CTS_CHG_INT_ENA (BIT(6))
58 | #define UART_DSR_CHG_INT_ENA (BIT(5))
59 | #define UART_RXFIFO_OVF_INT_ENA (BIT(4))
60 | #define UART_FRM_ERR_INT_ENA (BIT(3))
61 | #define UART_PARITY_ERR_INT_ENA (BIT(2))
62 | #define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
63 | #define UART_RXFIFO_FULL_INT_ENA (BIT(0))
64 |
65 | #define UART_INT_CLR(i) (REG_UART_BASE(i) + 0x10)
66 | #define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
67 | #define UART_BRK_DET_INT_CLR (BIT(7))
68 | #define UART_CTS_CHG_INT_CLR (BIT(6))
69 | #define UART_DSR_CHG_INT_CLR (BIT(5))
70 | #define UART_RXFIFO_OVF_INT_CLR (BIT(4))
71 | #define UART_FRM_ERR_INT_CLR (BIT(3))
72 | #define UART_PARITY_ERR_INT_CLR (BIT(2))
73 | #define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
74 | #define UART_RXFIFO_FULL_INT_CLR (BIT(0))
75 |
76 | #define UART_CLKDIV(i) (REG_UART_BASE(i) + 0x14)
77 | #define UART_CLKDIV_CNT 0x000FFFFF
78 | #define UART_CLKDIV_S 0
79 |
80 | #define UART_AUTOBAUD(i) (REG_UART_BASE(i) + 0x18)
81 | #define UART_GLITCH_FILT 0x000000FF
82 | #define UART_GLITCH_FILT_S 8
83 | #define UART_AUTOBAUD_EN (BIT(0))
84 |
85 | #define UART_STATUS(i) (REG_UART_BASE(i) + 0x1C)
86 | #define UART_TXD (BIT(31))
87 | #define UART_RTSN (BIT(30))
88 | #define UART_DTRN (BIT(29))
89 | #define UART_TXFIFO_CNT 0x000000FF
90 | #define UART_TXFIFO_CNT_S 16
91 | #define UART_RXD (BIT(15))
92 | #define UART_CTSN (BIT(14))
93 | #define UART_DSRN (BIT(13))
94 | #define UART_RXFIFO_CNT 0x000000FF
95 | #define UART_RXFIFO_CNT_S 0
96 |
97 | #define UART_CONF0(i) (REG_UART_BASE(i) + 0x20)
98 | #define UART_DTR_INV (BIT(24))
99 | #define UART_RTS_INV (BIT(23))
100 | #define UART_TXD_INV (BIT(22))
101 | #define UART_DSR_INV (BIT(21))
102 | #define UART_CTS_INV (BIT(20))
103 | #define UART_RXD_INV (BIT(19))
104 | #define UART_TXFIFO_RST (BIT(18))
105 | #define UART_RXFIFO_RST (BIT(17))
106 | #define UART_IRDA_EN (BIT(16))
107 | #define UART_TX_FLOW_EN (BIT(15))
108 | #define UART_LOOPBACK (BIT(14))
109 | #define UART_IRDA_RX_INV (BIT(13))
110 | #define UART_IRDA_TX_INV (BIT(12))
111 | #define UART_IRDA_WCTL (BIT(11))
112 | #define UART_IRDA_TX_EN (BIT(10))
113 | #define UART_IRDA_DPLX (BIT(9))
114 | #define UART_TXD_BRK (BIT(8))
115 | #define UART_SW_DTR (BIT(7))
116 | #define UART_SW_RTS (BIT(6))
117 | #define UART_STOP_BIT_NUM 0x00000003
118 | #define UART_STOP_BIT_NUM_S 4
119 | #define UART_BIT_NUM 0x00000003
120 | #define UART_BIT_NUM_S 2
121 | #define UART_PARITY_EN (BIT(1))
122 | #define UART_PARITY_EN_M 0x00000001
123 | #define UART_PARITY_EN_S 1
124 | #define UART_PARITY (BIT(0))
125 | #define UART_PARITY_M 0x00000001
126 | #define UART_PARITY_S 0
127 |
128 | #define UART_CONF1(i) (REG_UART_BASE(i) + 0x24)
129 | #define UART_RX_TOUT_EN (BIT(31))
130 | #define UART_RX_TOUT_THRHD 0x0000007F
131 | #define UART_RX_TOUT_THRHD_S 24
132 | #define UART_RX_FLOW_EN (BIT(23))
133 | #define UART_RX_FLOW_THRHD 0x0000007F
134 | #define UART_RX_FLOW_THRHD_S 16
135 | #define UART_TXFIFO_EMPTY_THRHD 0x0000007F
136 | #define UART_TXFIFO_EMPTY_THRHD_S 8
137 | #define UART_RXFIFO_FULL_THRHD 0x0000007F
138 | #define UART_RXFIFO_FULL_THRHD_S 0
139 |
140 | #define UART_LOWPULSE(i) (REG_UART_BASE(i) + 0x28)
141 | #define UART_LOWPULSE_MIN_CNT 0x000FFFFF
142 | #define UART_LOWPULSE_MIN_CNT_S 0
143 |
144 | #define UART_HIGHPULSE(i) (REG_UART_BASE(i) + 0x2C)
145 | #define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
146 | #define UART_HIGHPULSE_MIN_CNT_S 0
147 |
148 | #define UART_PULSE_NUM(i) (REG_UART_BASE(i) + 0x30)
149 | #define UART_PULSE_NUM_CNT 0x0003FF
150 | #define UART_PULSE_NUM_CNT_S 0
151 |
152 | #define UART_DATE(i) (REG_UART_BASE(i) + 0x78)
153 | #define UART_ID(i) (REG_UART_BASE(i) + 0x7C)
154 |
155 | #endif // UART_REGISTER_H_INCLUDED
156 |
157 |
--------------------------------------------------------------------------------
/esp/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 Josef Gajdusek
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 | #include "driver/uart.h"
21 | #include "umqtt-esp.h"
22 |
23 | #define SSID "SSID"
24 | #define PASSWORD "PASS"
25 | #define MQTT_SERVER "wherever.lan"
26 |
27 | void message_callback(struct umqtt_connection *u, char *topic, uint8_t *data,
28 | int len)
29 | {
30 | os_printf("umqtt: msg: %s %s\n", topic, (char *)data);
31 | }
32 |
33 | void connected_callback(struct umqtt_connection *u)
34 | {
35 | os_printf("umqtt: connect handshake complete\n");
36 | umqtt_subscribe(u, "#");
37 | }
38 |
39 | uint8_t rxbuff[1024];
40 | uint8_t txbuff[1024];
41 |
42 | struct umqtt_esp_config umqttconfig = {
43 | .hostname = MQTT_SERVER,
44 | .port = 1883,
45 | .umqtt = {
46 | .clientid = "esp-umqtt",
47 | .kalive = 60,
48 | .rxbuff = {
49 | .start = rxbuff,
50 | .length = sizeof(rxbuff),
51 | },
52 | .txbuff = {
53 | .start = txbuff,
54 | .length = sizeof(txbuff),
55 | },
56 | .connected_callback = connected_callback,
57 | .message_callback = message_callback,
58 | }
59 | };
60 |
61 | void on_wifi_event(System_Event_t *event)
62 | {
63 | switch (event->event) {
64 | case EVENT_STAMODE_GOT_IP:
65 | umqtt_esp_connect(&umqttconfig);
66 | break;
67 | }
68 | }
69 |
70 | void user_init(void)
71 | {
72 | uart_init(115200, 115200);
73 | struct station_config config = {
74 | .ssid = SSID,
75 | .password = PASSWORD,
76 | };
77 |
78 | wifi_set_event_handler_cb(on_wifi_event);
79 |
80 | wifi_set_opmode(STATION_MODE);
81 | wifi_station_set_config(&config);
82 | wifi_set_phy_mode(PHY_MODE_11B);
83 | wifi_station_connect();
84 | }
85 |
--------------------------------------------------------------------------------
/esp/umqtt-esp.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 Josef Gajdusek
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 | #include
21 | #include "umqtt-esp.h"
22 |
23 | static void umqtt_esp_connect_cb(void *arg)
24 | {
25 | struct espconn *conn = arg;
26 | struct umqtt_esp_config *cfg = conn->reverse;
27 | umqtt_connect(&cfg->umqtt);
28 | }
29 |
30 | static void umqtt_esp_recv_cb(void *arg, char *pdata, unsigned short len)
31 | {
32 | struct espconn *conn = arg;
33 | struct umqtt_esp_config *cfg = conn->reverse;
34 | umqtt_circ_push(&cfg->umqtt.rxbuff, (uint8_t *) pdata, (int) len);
35 | umqtt_process(&cfg->umqtt);
36 | }
37 |
38 | static void umqtt_esp_new_packet_cb(struct umqtt_connection *umqtt)
39 | {
40 | struct umqtt_esp_config *cfg = umqtt->private;
41 | uint8_t buff[512];
42 | int len;
43 |
44 | len = umqtt_circ_pop(&umqtt->txbuff, buff, sizeof(buff));
45 |
46 | espconn_send(&cfg->conn, buff, len);
47 | }
48 |
49 | static void umqtt_esp_ping_timer_cb(void *_cfg)
50 | {
51 | struct umqtt_esp_config *cfg = _cfg;
52 | umqtt_ping(&cfg->umqtt);
53 | }
54 |
55 | static void umqtt_esp_connected_cb(struct umqtt_connection *umqtt)
56 | {
57 | struct umqtt_esp_config *cfg = umqtt->private;
58 | os_timer_setfn(&cfg->ping_timer, umqtt_esp_ping_timer_cb, cfg);
59 | os_timer_arm(&cfg->ping_timer, cfg->umqtt.kalive * 1000, 1);
60 | if (cfg->connected_callback)
61 | cfg->connected_callback(umqtt);
62 | }
63 |
64 | static void umqtt_esp_sent_cb(void *arg)
65 | {
66 | struct espconn *conn = arg;
67 | struct umqtt_esp_config *cfg = conn->reverse;
68 | if (!umqtt_circ_is_empty(&cfg->umqtt.txbuff))
69 | umqtt_esp_new_packet_cb(&cfg->umqtt);
70 | }
71 |
72 | static void umqtt_esp_disconnect_cb(void *arg)
73 | {
74 | struct espconn *conn = arg;
75 | os_printf("umqtt: Disconnected, reconnecting...\n");
76 | umqtt_esp_connect(conn->reverse);
77 | }
78 |
79 | static void umqtt_esp_dns_cb(const char *name, ip_addr_t *ip, void *_cfg)
80 | {
81 | struct umqtt_esp_config *cfg = _cfg;
82 | if (ip == NULL) {
83 | os_printf("umqtt: DNS resolve failed! Retrying...\n");
84 | umqtt_esp_connect(cfg);
85 | return;
86 | }
87 |
88 | cfg->umqtt.private = cfg;
89 | cfg->umqtt.connected_callback = umqtt_esp_connected_cb;
90 | cfg->umqtt.new_packet_callback = umqtt_esp_new_packet_cb;
91 |
92 | os_printf("umqtt: connecting to " IPSTR "...\n", IP2STR(ip));
93 |
94 | cfg->conn.type = ESPCONN_TCP;
95 | cfg->conn.state = ESPCONN_NONE;
96 | cfg->conn.proto.tcp = &cfg->tcp;
97 | cfg->conn.proto.tcp->local_port = espconn_port();
98 | cfg->conn.proto.tcp->remote_port = cfg->port;
99 | cfg->conn.reverse = cfg;
100 | os_memcpy(&cfg->conn.proto.tcp->remote_ip, &ip->addr, 4);
101 | espconn_regist_connectcb(&cfg->conn, umqtt_esp_connect_cb);
102 | espconn_regist_recvcb(&cfg->conn, umqtt_esp_recv_cb);
103 | espconn_regist_sentcb(&cfg->conn, umqtt_esp_sent_cb);
104 | espconn_regist_disconcb(&cfg->conn, umqtt_esp_disconnect_cb);
105 | espconn_connect(&cfg->conn);
106 | }
107 |
108 | void umqtt_esp_connect(struct umqtt_esp_config *cfg)
109 | {
110 | os_printf("umqtt: resolving hostname...\n");
111 | cfg->connected_callback = cfg->umqtt.connected_callback;
112 | espconn_gethostbyname((struct espconn *)cfg, cfg->hostname, &cfg->ip, umqtt_esp_dns_cb);
113 | }
114 |
--------------------------------------------------------------------------------
/esp/umqtt-esp.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 Josef Gajdusek
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 | #include
21 | #include "umqtt.h"
22 |
23 | struct umqtt_esp_config {
24 | char *hostname;
25 | int port;
26 | struct umqtt_connection umqtt;
27 |
28 | void (*connected_callback)(struct umqtt_connection *);
29 | struct espconn conn;
30 | esp_tcp tcp;
31 | struct ip_addr ip;
32 | os_timer_t ping_timer;
33 | };
34 |
35 | void umqtt_esp_connect(struct umqtt_esp_config *cfg);
36 |
--------------------------------------------------------------------------------
/esp/user_config.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atx/umqtt/a3fac676afd9c777dccf599dc8d10589d4e45e91/esp/user_config.h
--------------------------------------------------------------------------------
/umqtt/umqtt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2014-2015 Josef Gajdusek
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | * */
24 |
25 | #include
26 |
27 | #include "umqtt.h"
28 |
29 | static inline uint16_t htons(uint16_t x)
30 | {
31 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
32 | return ((x & 0xff) << 8) | (x >> 8);
33 | #else
34 | return x;
35 | #endif
36 | }
37 |
38 | #define umqtt_insert_messageid(conn, ptr) \
39 | do { \
40 | ptr[0] = conn->message_id >> 8; \
41 | ptr[1] = conn->message_id & 0xff; \
42 | conn->message_id++; \
43 | } while (0)
44 |
45 | #define umqtt_build_header(type, dup, qos, retain) \
46 | (((type) << 4) | ((dup) << 3) | ((qos) << 1) | (retain))
47 |
48 | #define umqtt_header_type(h) \
49 | ((h) >> 4)
50 |
51 | static int umqtt_decode_length(uint8_t *data)
52 | {
53 | int mul = 1;
54 | int val = 0;
55 | int i;
56 |
57 | for (i = 0; i == 0 || (data[i - 1] & 0x80); i++) {
58 | val += (data[i] & 0x7f) * mul;
59 | mul *= 128;
60 | }
61 |
62 | return val;
63 | }
64 |
65 | static int umqtt_encode_length(int len, uint8_t *data)
66 | {
67 | int digit;
68 | int i = 0;
69 |
70 | do {
71 | digit = len % 128;
72 | len /= 128;
73 | if (len > 0)
74 | digit |= 0x80;
75 | data[i] = digit;
76 | i++;
77 | } while (len);
78 |
79 | return i; /* Return the amount of bytes used */
80 | }
81 |
82 | void umqtt_circ_init(struct umqtt_circ_buffer *buff)
83 | {
84 | buff->pointer = buff->start;
85 | buff->datalen = 0;
86 | }
87 |
88 | int umqtt_circ_push(struct umqtt_circ_buffer *buff, uint8_t *data, int len)
89 | {
90 | uint8_t *bend = buff->start + buff->length - 1;
91 | uint8_t *dend = (buff->pointer - buff->start + buff->datalen)
92 | % buff->length + buff->start; /* This points to new byte */
93 |
94 | for (; len > 0; len--) {
95 | if (dend > bend)
96 | dend = buff->start;
97 | if (buff->datalen != 0 && dend == buff->pointer)
98 | break;
99 | *dend = *data;
100 | dend++;
101 | data++;
102 | buff->datalen++;
103 | }
104 |
105 | return len; /* Return amount of bytes left */
106 | }
107 |
108 | int umqtt_circ_peek(struct umqtt_circ_buffer *buff, uint8_t *data, int len)
109 | {
110 | uint8_t *ptr = buff->pointer;
111 | uint8_t *bend = buff->start + buff->length - 1;
112 | int i;
113 |
114 | for (i = 0; i < len && i < buff->datalen; i++) {
115 | data[i] = ptr[i];
116 | if (ptr > bend)
117 | ptr = buff->start;
118 | }
119 |
120 | return i; /* Return the amount of bytes actually peeked */
121 | }
122 |
123 | int umqtt_circ_pop(struct umqtt_circ_buffer *buff, uint8_t *data, int len)
124 | {
125 | uint8_t *bend = buff->start + buff->length - 1;
126 | int i;
127 |
128 | for (i = 0; i < len && buff->datalen > 0; i++) {
129 | data[i] = *buff->pointer;
130 | buff->pointer++;
131 | buff->datalen--;
132 | if (buff->pointer > bend)
133 | buff->pointer = buff->start;
134 | }
135 |
136 | return i; /* Return the amount of bytes actually popped */
137 | }
138 |
139 | void umqtt_connect(struct umqtt_connection *conn)
140 | {
141 | int cidlen = strlen(conn->clientid);
142 | uint8_t fixed;
143 | uint8_t remlen[4];
144 | uint8_t variable[12];
145 | uint16_t paylen;
146 |
147 | umqtt_circ_init(&conn->rxbuff);
148 | umqtt_circ_init(&conn->txbuff);
149 | conn->state = UMQTT_STATE_INIT;
150 | conn->nack_ping = 0;
151 | conn->nack_publish = 0;
152 | conn->nack_subscribe = 0;
153 | conn->message_id = 1;
154 |
155 | fixed = umqtt_build_header(UMQTT_CONNECT, 0, 0, 0);
156 |
157 | variable[0] = 0; /* UTF Protocol name */
158 | variable[1] = 6;
159 | variable[2] = 'M';
160 | variable[3] = 'Q';
161 | variable[4] = 'I';
162 | variable[5] = 's';
163 | variable[6] = 'd';
164 | variable[7] = 'p';
165 |
166 | variable[8] = 3; /* Protocol version */
167 |
168 | variable[9] = 0b00000010; /* Clean session flag */
169 |
170 | variable[10] = conn->kalive >> 8; /* Keep Alive timer */
171 | variable[11] = conn->kalive & 0xff;
172 |
173 | paylen = htons(cidlen);
174 |
175 | umqtt_circ_push(&conn->txbuff, &fixed, 1);
176 | umqtt_circ_push(&conn->txbuff, remlen,
177 | umqtt_encode_length(sizeof(variable) + sizeof(paylen) + cidlen, remlen));
178 | umqtt_circ_push(&conn->txbuff, variable, sizeof(variable));
179 | umqtt_circ_push(&conn->txbuff, (uint8_t *) &paylen, sizeof(paylen));
180 | umqtt_circ_push(&conn->txbuff, conn->clientid, cidlen);
181 |
182 | conn->state = UMQTT_STATE_CONNECTING;
183 | if (conn->new_packet_callback)
184 | conn->new_packet_callback(conn);
185 | }
186 |
187 | void umqtt_subscribe(struct umqtt_connection *conn, char *topic)
188 | {
189 | uint16_t topiclen = strlen(topic);
190 | uint8_t fixed;
191 | uint8_t remlen[4];
192 | uint8_t messageid[2];
193 | uint16_t paylen;
194 | uint8_t qos = 0;
195 |
196 | fixed = umqtt_build_header(UMQTT_SUBSCRIBE, 0, 1, 0);
197 |
198 | umqtt_insert_messageid(conn, messageid);
199 |
200 | paylen = htons(topiclen);
201 |
202 | umqtt_circ_push(&conn->txbuff, &fixed, 1);
203 | umqtt_circ_push(&conn->txbuff, remlen,
204 | umqtt_encode_length(
205 | sizeof(messageid) + sizeof(paylen) + topiclen + sizeof(qos), remlen));
206 | umqtt_circ_push(&conn->txbuff, messageid, sizeof(messageid));
207 | umqtt_circ_push(&conn->txbuff, (uint8_t *) &paylen, sizeof(paylen));
208 | umqtt_circ_push(&conn->txbuff, topic, topiclen);
209 | umqtt_circ_push(&conn->txbuff, &qos, sizeof(qos));
210 |
211 | conn->nack_subscribe++;
212 | if (conn->new_packet_callback)
213 | conn->new_packet_callback(conn);
214 | }
215 |
216 | void umqtt_publish(struct umqtt_connection *conn, char *topic,
217 | uint8_t *data, int datalen)
218 | {
219 | int toplen = strlen(topic);
220 | uint8_t fixed;
221 | uint8_t remlen[4];
222 | uint8_t len[2];
223 |
224 | fixed = umqtt_build_header(UMQTT_PUBLISH, 0, 0, 0);
225 |
226 | umqtt_circ_push(&conn->txbuff, &fixed, 1);
227 | umqtt_circ_push(&conn->txbuff, remlen,
228 | umqtt_encode_length(2 + toplen + datalen, remlen));
229 |
230 | len[0] = toplen >> 8;
231 | len[1] = toplen & 0xff;
232 | umqtt_circ_push(&conn->txbuff, len, sizeof(len));
233 | umqtt_circ_push(&conn->txbuff, (uint8_t *) topic, toplen);
234 |
235 | umqtt_circ_push(&conn->txbuff, data, datalen);
236 | if (conn->new_packet_callback)
237 | conn->new_packet_callback(conn);
238 | }
239 |
240 | void umqtt_ping(struct umqtt_connection *conn)
241 | {
242 | uint8_t packet[] = { umqtt_build_header(UMQTT_PINGREQ, 0, 0, 0), 0 };
243 |
244 | umqtt_circ_push(&conn->txbuff, packet, sizeof(packet));
245 | conn->nack_ping++;
246 | if (conn->new_packet_callback)
247 | conn->new_packet_callback(conn);
248 | }
249 |
250 | static void umqtt_handle_publish(struct umqtt_connection *conn,
251 | uint8_t *data, int len)
252 | {
253 | uint16_t toplen = (data[0] << 8) | data[1];
254 | char topic[toplen + 1];
255 | uint8_t payload[len - 2 - toplen + 1];
256 |
257 | memcpy(topic, data + 2, sizeof(topic));
258 | topic[sizeof(topic) - 1] = 0;
259 | memcpy(payload, data + 2 + toplen, sizeof(payload));
260 | payload[sizeof(payload) - 1] = 0;
261 |
262 | conn->message_callback(conn, topic, payload, sizeof(payload));
263 | }
264 |
265 | static void umqtt_packet_arrived(struct umqtt_connection *conn,
266 | uint8_t header, int len)
267 | {
268 | uint8_t data[len];
269 |
270 | umqtt_circ_pop(&conn->rxbuff, data, len);
271 |
272 | switch (umqtt_header_type(header)) {
273 | case UMQTT_CONNACK:
274 | if (data[1] == 0x00) {
275 | conn->state = UMQTT_STATE_CONNECTED;
276 | if (conn->connected_callback)
277 | conn->connected_callback(conn);
278 | }
279 | else {
280 | conn->state = UMQTT_STATE_FAILED;
281 | }
282 | break;
283 | case UMQTT_SUBACK:
284 | conn->nack_subscribe--;
285 | break;
286 | case UMQTT_PINGRESP:
287 | conn->nack_ping--;
288 | break;
289 | case UMQTT_PUBLISH:
290 | umqtt_handle_publish(conn, data, len);
291 | break;
292 |
293 | }
294 | }
295 |
296 | void umqtt_process(struct umqtt_connection *conn)
297 | {
298 | uint8_t buf[5];
299 | unsigned int i = 2;
300 |
301 | while (conn->rxbuff.datalen >= 2) { /* We do have the fixed header */
302 | umqtt_circ_pop(&conn->rxbuff, buf, 2);
303 | for (i = 2; buf[i - 1] & 0x80 && i < sizeof(buf); i++)
304 | umqtt_circ_pop(&conn->rxbuff, &buf[i], 1);
305 |
306 | umqtt_packet_arrived(conn, buf[0],
307 | umqtt_decode_length(&buf[1]));
308 | }
309 | }
310 |
--------------------------------------------------------------------------------
/umqtt/umqtt.h:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2014-2015 Josef Gajdusek
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | * */
24 |
25 | #ifndef __UMQTT_H__
26 | #define __UMQTT_H__
27 |
28 | #include
29 |
30 | enum umqtt_packet_type {
31 | UMQTT_CONNECT = 1,
32 | UMQTT_CONNACK = 2,
33 | UMQTT_PUBLISH = 3,
34 | UMQTT_SUBSCRIBE = 8,
35 | UMQTT_SUBACK = 9,
36 | UMQTT_UNSUBSCRIBE = 10,
37 | UMQTT_UNSUBACK = 11,
38 | UMQTT_PINGREQ = 12,
39 | UMQTT_PINGRESP = 13,
40 | UMQTT_DISCONNECT = 14,
41 | };
42 |
43 | enum umqtt_client_state {
44 | UMQTT_STATE_INIT,
45 | UMQTT_STATE_CONNECTING,
46 | UMQTT_STATE_CONNECTED,
47 | UMQTT_STATE_FAILED,
48 | };
49 |
50 | struct umqtt_circ_buffer {
51 | uint8_t *start;
52 | int length;
53 |
54 | /* Private */
55 | uint8_t *pointer;
56 | int datalen;
57 | };
58 |
59 | struct umqtt_connection {
60 | struct umqtt_circ_buffer txbuff;
61 | struct umqtt_circ_buffer rxbuff;
62 | uint16_t kalive;
63 | char *clientid;
64 |
65 | void (*connected_callback)(struct umqtt_connection *);
66 | void (*message_callback)(struct umqtt_connection *,
67 | char *topic, uint8_t *data, int len);
68 | void (*new_packet_callback)(struct umqtt_connection *);
69 |
70 | void *private;
71 |
72 | /* Private */
73 | /* ack counters - incremented on sending, decremented on ack */
74 | int nack_publish;
75 | int nack_subscribe;
76 | int nack_ping;
77 |
78 | int message_id;
79 |
80 | uint8_t work_buf[5];
81 | int work_read;
82 |
83 | enum umqtt_client_state state;
84 | };
85 |
86 | #define umqtt_circ_datalen(buff) \
87 | ((buff)->datalen)
88 |
89 | #define umqtt_circ_is_full(buff) \
90 | ((buff)->length == (buff)->datalen)
91 |
92 | #define umqtt_circ_is_empty(buff) \
93 | (umqtt_circ_datalen(buff) == 0)
94 |
95 | void umqtt_circ_init(struct umqtt_circ_buffer *buff);
96 |
97 | /* Return the amount of bytes left */
98 | int umqtt_circ_push(struct umqtt_circ_buffer *buff, uint8_t *data, int len);
99 |
100 | /* Returns amount of bytes popped/peeked */
101 | int umqtt_circ_pop(struct umqtt_circ_buffer *buff, uint8_t *data, int len);
102 | int umqtt_circ_peek(struct umqtt_circ_buffer *buff, uint8_t *data, int len);
103 |
104 | void umqtt_connect(struct umqtt_connection *conn);
105 | void umqtt_subscribe(struct umqtt_connection *conn, char *topic);
106 | void umqtt_publish(struct umqtt_connection *conn, char *topic,
107 | uint8_t *data, int datalen);
108 | void umqtt_ping(struct umqtt_connection *conn);
109 | void umqtt_process(struct umqtt_connection *conn);
110 |
111 | #endif /* __UMQTT_H__ */
112 |
--------------------------------------------------------------------------------
/unix/Makefile:
--------------------------------------------------------------------------------
1 |
2 | CC = gcc
3 | RM = rm
4 | UMQTT = ../umqtt
5 |
6 | CFLAGS = -I$(UMQTT) -I.
7 |
8 | SRC = $(UMQTT)/umqtt.c
9 | SRC += main.c
10 |
11 | umqtt: $(SRC:.c=.o)
12 | $(CC) $(CFLAGS) $^ -o $@
13 |
14 | all: umqtt
15 |
16 | clean:
17 | $(RM) -f *.o umqtt
18 |
--------------------------------------------------------------------------------
/unix/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2014-2015 Josef Gajdusek
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | * */
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include "umqtt.h"
39 |
40 | struct option long_options[] = {
41 | {"topic", required_argument, 0, 't'},
42 | {"host", required_argument, 0, 'h'},
43 | {"port", required_argument, 0, 'p'},
44 | {"message", required_argument, 0, 'm'},
45 | {"id", required_argument, 0, 'i'},
46 | {"verbose", no_argument, 0, 'v'},
47 | {"help", no_argument, 0, 'u'},
48 | };
49 |
50 | const char *usage =
51 | "usage: umqtt -t [-h hostname] [-p port] [-m message] [-i client-id] [-v]\n";
52 |
53 | bool verbose = false;
54 |
55 | uint8_t u_rxbuff[2048];
56 | uint8_t u_txbuff[2048];
57 |
58 | void message_callback(struct umqtt_connection *uc, char *topic, uint8_t *data,
59 | int len)
60 | {
61 | printf("%s %s\n", topic, data);
62 | }
63 |
64 | struct umqtt_connection u_conn = {
65 | .kalive = 30,
66 | .txbuff = {
67 | .start = u_txbuff,
68 | .length = sizeof(u_txbuff),
69 | },
70 | .rxbuff = {
71 | .start = u_rxbuff,
72 | .length = sizeof(u_rxbuff),
73 | },
74 | .message_callback = message_callback,
75 | };
76 |
77 | int main(int argc, char *argv[])
78 | {
79 | struct sockaddr_in serveraddr;
80 | struct hostent *server;
81 | struct timeval timeout;
82 | char *host = "localhost";
83 | char *msg = NULL;
84 | char *topic = NULL;
85 | char *clid = NULL;
86 | uint8_t buff[1024];
87 | int port = 1883;
88 | int sockfd;
89 | uint16_t kalive = 30;
90 | int digit_optind = 0;
91 | int ret;
92 | int c;
93 |
94 | /* Parse command line options */
95 | while (true) {
96 | int option_index = 0;
97 | c = getopt_long(argc, argv, "h:p:m:t:i:v", long_options, &option_index);
98 | if (c == -1)
99 | break;
100 | switch (c) {
101 | case 'h':
102 | host = optarg;
103 | break;
104 | case 'p':
105 | sscanf(optarg, "%d", &port);
106 | break;
107 | case 'm':
108 | msg = optarg;
109 | break;
110 | case 't':
111 | topic = optarg;
112 | break;
113 | case 'v':
114 | verbose = true;
115 | break;
116 | case 'i':
117 | if (strlen(clid) > 23) {
118 | fprintf(stderr, "Client id length cannot exceed 23 characters\n");
119 | exit(EXIT_FAILURE);
120 | }
121 | clid = optarg;
122 | break;
123 | case 0:
124 | puts(usage);
125 | exit(EXIT_SUCCESS);
126 | }
127 | }
128 |
129 | if (topic == NULL) {
130 | fprintf(stderr, "No topic specified!\n");
131 | exit(EXIT_FAILURE);
132 | }
133 |
134 | server = gethostbyname(host);
135 |
136 | bzero((char *) &serveraddr, sizeof(serveraddr));
137 | memcpy((char *) server->h_addr, (char *)&serveraddr.sin_addr.s_addr,
138 | server->h_length);
139 | serveraddr.sin_family = AF_INET;
140 | serveraddr.sin_port = htons(port);
141 |
142 | sockfd = socket(AF_INET, SOCK_STREAM, 0);
143 |
144 | if (connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
145 | perror("Failed to connect");
146 |
147 | if (msg == NULL) {
148 | timeout.tv_sec = kalive;
149 | timeout.tv_usec = 0;
150 | setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
151 | }
152 |
153 | /* Initialize umqtt */
154 | if (clid == NULL) {
155 | srand(time(NULL));
156 | clid = malloc(20);
157 | snprintf(clid, 20, "umqtt-%d", rand());
158 | }
159 | u_conn.clientid = clid;
160 |
161 | if (verbose)
162 | printf("Connecting to %s:%d with client id \"%s\"\n", host, port, clid);
163 |
164 |
165 | umqtt_connect(&u_conn);
166 |
167 | /* Enter main loop */
168 | while (true) {
169 | if (!umqtt_circ_is_empty(&u_conn.txbuff)) {
170 | ret = umqtt_circ_pop(&u_conn.txbuff, buff, 1024);
171 | send(sockfd, buff, ret, 0);
172 | }
173 |
174 | if (umqtt_circ_is_empty(&u_conn.txbuff) && topic == NULL && msg != NULL)
175 | break;
176 |
177 | ret = recv(sockfd, buff, sizeof(buff), 0);
178 | if (ret < 0) {
179 | if (errno == EAGAIN) {
180 | umqtt_ping(&u_conn);
181 | } else {
182 | perror("Failed receiving");
183 | exit(EXIT_FAILURE);
184 | }
185 | }
186 | umqtt_circ_push(&u_conn.rxbuff, buff, ret);
187 | umqtt_process(&u_conn);
188 |
189 | if (topic != NULL && u_conn.state == UMQTT_STATE_CONNECTED) {
190 | if (verbose)
191 | printf("Connected\n");
192 |
193 | if (msg != NULL) {
194 | umqtt_publish(&u_conn, topic, msg, strlen(msg));
195 | } else {
196 | umqtt_subscribe(&u_conn, topic);
197 | if (verbose)
198 | printf("Subscribing to %s\n", topic);
199 | }
200 | topic = NULL;
201 | }
202 | }
203 |
204 | close(sockfd);
205 | }
206 |
--------------------------------------------------------------------------------