├── 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 | --------------------------------------------------------------------------------