├── .gitattributes ├── readme ├── all.jpg ├── debug.png ├── 115200.png └── result.png ├── .gitignore ├── LICENSE ├── serial.py ├── main.c ├── modserial.c ├── readme.md ├── sw_serial.h ├── for_idf5.1 ├── py_serial.h ├── soft_urat_esp8285_57600.h └── app_main.c /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /readme/all.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junhuanchen/esp-idf-software-serial/HEAD/readme/all.jpg -------------------------------------------------------------------------------- /readme/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junhuanchen/esp-idf-software-serial/HEAD/readme/debug.png -------------------------------------------------------------------------------- /readme/115200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junhuanchen/esp-idf-software-serial/HEAD/readme/115200.png -------------------------------------------------------------------------------- /readme/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junhuanchen/esp-idf-software-serial/HEAD/readme/result.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Juwan 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /serial.py: -------------------------------------------------------------------------------- 1 | 2 | # Github: junhuanchen 3 | # Copyright (c) 2018 Juwan 4 | # Licensed under the MIT license: 5 | # http://www.opensource.org/licenses/mit-license.php 6 | 7 | import time 8 | import machine 9 | import serial 10 | 11 | 12 | class uart: 13 | 14 | def __init__(self, tx=22, rx=21, Inverse=False, buffSize=512): 15 | self.port = serial.new(tx, rx, Inverse, buffSize) 16 | 17 | def __del__(self): 18 | # pass # will reset 19 | serial.delete(self.port) 20 | 21 | def any(self): 22 | return serial.any(self.port) 23 | 24 | def open(self, baudRate): 25 | return serial.open(self.port, baudRate) 26 | 27 | def stop(self): 28 | return serial.stop(self.port) 29 | 30 | def write(self, byte): 31 | return serial.write(self.port, byte) 32 | 33 | def read(self): 34 | return serial.read(self.port) 35 | 36 | 37 | def unit_test(): 38 | try: 39 | com = uart(22, 21, False, 512) 40 | com.open(9600) 41 | 42 | while True: 43 | time.sleep(1) 44 | if com.any() > 0: 45 | print(hex(com.read())) 46 | 47 | com.write(0x11) 48 | 49 | except Exception as e: 50 | print(e) 51 | finally: 52 | com.__del__() 53 | 54 | 55 | if __name__ == "__main__": 56 | unit_test() 57 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Github: junhuanchen 3 | Copyright (c) 2018 Juwan 4 | Licensed under the MIT license: 5 | http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | #include 9 | 10 | #include "sw_serial.h" 11 | 12 | int app_main() 13 | { 14 | SwSerial *tmp = sw_new(22, 21, false, 512); 15 | printf("%u\n", tmp->bitTime); 16 | if (tmp != NULL) 17 | { 18 | 19 | sw_open(tmp, 115200); // 115200 > 9600 20 | 21 | // puts("sw_write test"); 22 | 23 | // for (size_t i = 0; i < 256; i++) 24 | // { 25 | // sw_write(tmp, (uint8_t)i); 26 | // } 27 | 28 | puts("sw_write test"); 29 | for (size_t i = 0; i < 127; i++) 30 | { 31 | sw_write(tmp, (uint8_t)i); 32 | } 33 | vTaskDelay(500 / portTICK_RATE_MS); 34 | 35 | puts("sw_write test"); 36 | for (size_t i = 127; i < 256; i++) 37 | { 38 | sw_write(tmp, (uint8_t)i); 39 | } 40 | vTaskDelay(500 / portTICK_RATE_MS); 41 | 42 | while (true) 43 | { 44 | 45 | vTaskDelay(1000 / portTICK_RATE_MS); 46 | puts("check recvd data"); 47 | int len = sw_any(tmp); 48 | 49 | if (len > 0) 50 | { 51 | for (size_t i = 0; i < len; i++) 52 | { 53 | printf("%02X ", sw_read(tmp)); 54 | } 55 | 56 | printf("\nrecv sw_any %02u %02u %02u \n", sw_any(tmp), tmp->inPos, tmp->outPos); 57 | 58 | } 59 | 60 | } 61 | 62 | } 63 | 64 | sw_del(tmp); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /modserial.c: -------------------------------------------------------------------------------- 1 | /* 2 | Github: junhuanchen 3 | Copyright (c) 2018 Juwan 4 | Licensed under the MIT license: 5 | http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | #include "sw_serial.h" 9 | 10 | #include "py/runtime.h" 11 | #include "py/mperrno.h" 12 | #include "py/mphal.h" 13 | #include "py/nlr.h" 14 | 15 | STATIC mp_obj_t serial_initialize() { 16 | return mp_const_none; 17 | } 18 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(serial_initialize_obj, serial_initialize); 19 | 20 | STATIC mp_obj_t serial_new(size_t n_args, const mp_obj_t *args) { 21 | if (n_args == 4) { 22 | mp_obj_t TxPin = args[0], RxPin = args[1], Inverse = args[2], buffSize = args[3]; 23 | 24 | /* 25 | if (RxPin != XX) { 26 | nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, 27 | "RxPin(arg 0) %d ", mp_obj_get_int(RxPin))); 28 | } 29 | */ 30 | 31 | SwSerial *self = sw_new(mp_obj_get_int(TxPin), mp_obj_get_int(RxPin), mp_obj_get_int(Inverse), mp_obj_get_int(buffSize)); 32 | // printf("%d %d %d %d\n", mp_obj_get_int(TxPin), mp_obj_get_int(RxPin), mp_obj_get_int(Inverse), mp_obj_get_int(buffSize)); 33 | if (self != NULL) { 34 | // sw_open(self, 115200); 35 | // sw_stop(self); 36 | return MP_OBJ_FROM_PTR(self); 37 | } 38 | } 39 | return mp_const_none; 40 | } 41 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(serial_new_obj, 0, 4, serial_new); 42 | 43 | STATIC mp_obj_t serial_del(mp_obj_t self) { 44 | SwSerial *tmp = (SwSerial *)self; 45 | sw_del(tmp); 46 | return mp_const_none; 47 | } 48 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_del_obj, serial_del); 49 | 50 | STATIC mp_obj_t serial_write(mp_obj_t self, mp_obj_t data) { 51 | SwSerial *tmp = (SwSerial *)self; 52 | 53 | // printf("write %d \n", (uint8_t)mp_obj_get_int(data)); 54 | 55 | sw_write(tmp, (uint8_t)mp_obj_get_int(data)); 56 | 57 | return mp_const_none; 58 | } 59 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(serial_write_obj, serial_write); 60 | 61 | STATIC mp_obj_t serial_read(mp_obj_t self) { 62 | SwSerial *tmp = (SwSerial *)self; 63 | 64 | int res = sw_read(tmp); 65 | 66 | // printf("read %d \n", (uint8_t)res); 67 | 68 | return mp_obj_new_int(res); 69 | } 70 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_read_obj, serial_read); 71 | 72 | STATIC mp_obj_t serial_any(mp_obj_t self) { 73 | SwSerial *tmp = (SwSerial *)self; 74 | 75 | int res = sw_any(tmp); 76 | 77 | if (res > 0) 78 | { 79 | return mp_obj_new_int(res); 80 | } 81 | 82 | return mp_obj_new_int(0); 83 | } 84 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_any_obj, serial_any); 85 | 86 | STATIC mp_obj_t serial_stop(mp_obj_t self) { 87 | SwSerial *tmp = (SwSerial *)self; 88 | return mp_obj_new_int(sw_stop(tmp)); 89 | } 90 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(serial_stop_obj, serial_stop); 91 | 92 | STATIC mp_obj_t serial_open(mp_obj_t self, mp_obj_t baudRate) { 93 | SwSerial *tmp = (SwSerial *)self; 94 | esp_err_t res = sw_open(tmp, mp_obj_get_int(baudRate)); 95 | return mp_obj_new_int(res); 96 | } 97 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(serial_open_obj, serial_open); 98 | 99 | STATIC const mp_rom_map_elem_t serial_module_globals_table[] = { 100 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_serial) }, 101 | { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&serial_initialize_obj) }, 102 | 103 | { MP_ROM_QSTR(MP_QSTR_new), MP_ROM_PTR(&serial_new_obj) }, 104 | { MP_ROM_QSTR(MP_QSTR_del), MP_ROM_PTR(&serial_del_obj) }, 105 | { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&serial_open_obj) }, 106 | { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&serial_stop_obj) }, 107 | { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&serial_write_obj) }, 108 | { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&serial_read_obj) }, 109 | { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&serial_any_obj) }, 110 | 111 | { MP_ROM_QSTR(MP_QSTR_EOF), MP_ROM_INT((mp_int_t)SW_EOF)}, 112 | }; 113 | 114 | STATIC MP_DEFINE_CONST_DICT(serial_module_globals, serial_module_globals_table); 115 | 116 | const mp_obj_module_t serial_module = { 117 | .base = { &mp_type_module }, 118 | .globals = (mp_obj_dict_t*)&serial_module_globals, 119 | }; 120 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ESP-IDF SoftWare Serial 2 | 3 | Github Arduino [Esp32-SoftwareSerial](https://github.com/junhuanchen/Esp32-SoftwareSerial) 4 | 5 | 花了点时间写了一下软串口,因为娱乐和工程需要,所以我从过去自己在 Arduino 上实现的软串口移植到 ESP-IDF 下,为此也写一周了吧,使用硬件为 Bpi:Uno (esp32)。 6 | 7 | 8 | 9 | > 更新了一次 esp8266 rtos 用的软串口,大概只做到了 57600 这个范围内稳定使用,但开头总有一两个字节要出错,应该是硬件电平上的干扰,持续使用是没有问题的。 10 | > 11 | > soft_urat_esp8285_57600.c 12 | > 更新后的博文 https://www.cnblogs.com/juwan/p/13772185.html 13 | 14 | 15 | 16 | ## 本模块的意义是? 17 | 18 | 大多数传感器接口,会采用 9600 的通信协议,而 ESP32 的硬串口很少(其中一个无法进行发送数据),举例来说,如果我们想要集成了 GRPS 模块、RS232 模块、MicroPython REPL、XX 串口传感器的模块,此时怎样都不够用,所以软串口可以解决此问题。 19 | 20 | ## 注意不能使用的引脚 21 | 22 | 在 arduino 里有这样的定义,NULL 的意味着它无法作为接收引脚,其他的一般都可以作为发送引脚,注意别和硬串口冲突(比如 0 2 16 17 ),不然就是浪费了。 23 | 24 | ```c++ 25 | 26 | static void (*ISRList[MAX_PIN + 1])() = { 27 | sws_isr_0, 28 | NULL, 29 | sws_isr_2, 30 | NULL, 31 | sws_isr_4, 32 | sws_isr_5, 33 | NULL, 34 | NULL, 35 | NULL, 36 | NULL, 37 | NULL, 38 | NULL, 39 | sws_isr_12, 40 | sws_isr_13, 41 | sws_isr_14, 42 | sws_isr_15, 43 | sws_isr_16, 44 | sws_isr_17, 45 | sws_isr_18, 46 | sws_isr_19, 47 | NULL, 48 | sws_isr_21, 49 | sws_isr_22, 50 | sws_isr_23, 51 | NULL, 52 | sws_isr_25, 53 | sws_isr_26, 54 | sws_isr_27, 55 | NULL, 56 | NULL, 57 | NULL, 58 | NULL, 59 | sws_isr_32, 60 | sws_isr_33, 61 | sws_isr_34, 62 | sws_isr_35}; 63 | 64 | ``` 65 | 66 | ## Unit Test 67 | 68 | - 9600 在 ESP-IDF 和 MicroPython 环境下测试完美,其中 0x00 - 0xFF 256 个字节的数据发送与接收均正常,多次测试的结果非常好。 69 | - 57600 在 ESP-IDF 环境下测试和 9600 的效果一致,但是 MicroPython 中多次发送数据后,数据会抖动,需要优化一下每个字节的发送部分的间隔才能改善,另外 0x00 - 0xFF 256 个字节的数据接收正常。 70 | - 115200 在 ESP-IDF 环境下测试收发通信正常,但是在 MicroPython 下无法正常,轻微的 4us 误差数据抖动,就会导致每次采集数据不准确,也没有对此添加过采样(多次采样选其一),所以需要设定波特率到 136000 才能相对准确(更快的发送,从而忽略掉两次执行发送间隔的影响,这个部分我想在还需要多加优化才能相对完美)。 71 | 72 | 所以 esp-idf 中,你可以任意使用 9600 57600 115200 的波特率,但如果发现存在问题,需要去修改 sw_serial.h 中的两个参数 rx_start_time 和 rx_end_time ,或设置其他波特率。 73 | 74 | ```c++ 75 | 76 | // suggest max datalen <= 256 and baudRate <= 115200 77 | esp_err_t sw_open(SwSerial *self, uint32_t baudRate) 78 | { 79 | // The oscilloscope told me 80 | self->bitTime = (esp_clk_cpu_freq() / baudRate); 81 | 82 | // Rx bit Timing Settings 83 | switch (baudRate) 84 | { 85 | case 115200: 86 | self->rx_start_time = (self->bitTime / 256); 87 | self->rx_end_time = (self->bitTime * 127 / 256); 88 | break; 89 | 90 | case 9600: 91 | self->rx_start_time = (self->bitTime / 9); 92 | self->rx_end_time = (self->bitTime * 8 / 9); 93 | break; 94 | 95 | default: // tested 57600 len 256 96 | self->rx_start_time = (self->bitTime / 9); 97 | self->rx_end_time = (self->bitTime * 8 / 9); 98 | break; 99 | } 100 | 101 | // printf("sw_open %u %d\n", self->rx_start_time, self->rx_end_time); 102 | 103 | sw_write(self, 0x00); // Initialization uart link 104 | 105 | return sw_enableRx(self, true); 106 | } 107 | 108 | ``` 109 | 110 | 而 micropython 中,不超过 57600 都是可以正常使用的,但 115200 只能靠改参数来满足,比如 115200 改成 137000 可以让局部数据准确传输,通常我们认为完整的数据范围是 0x00 - 0xFF 之间。 111 | 112 | ## DSView Tool 113 | 114 | 对于其中的数据传输情况,你需要一个逻辑分析仪,例如我使用的是这个 [dreamsourcelab](https://www.dreamsourcelab.com/) 。 115 | 116 | 比如我下图做的分析。 117 | 118 | ![](readme/115200.png) 119 | 120 | ![](readme/debug.png) 121 | 122 | ## MicroPyhton 的效果 123 | 124 | ![](readme/result.png) 125 | 126 | ## harvest 127 | 128 | 首先我学会了使用逻辑分析仪 :),我可以自己去捕获数据的情况来分析数据源,分析它的发送和接收都是相对麻烦的事情,但从编程上讲,一定是发送要比接收更简单。 129 | 130 | ### how to do 131 | 132 | 首先我最早在 Arduino 上使用软串口,作为软件出身的,我知道如何进行逻辑分析和拆解,因此我从 Arduino 上分离了逻辑到 ESP-IDF ,但是当我移植完成后完全不能使用,因为这个不同于软件模块,迁移之后只需要关系逻辑问题,这个还要结合通信时序来分析问题。 133 | 134 | 因此,我移植完成后,先审核数据发送接口的逻辑,最先遇到的问题的是 主频 和 时间周期的关系,经过群里小伙伴的教育后,我才知道 波特率 以及主频频率的意义,所谓的 115200 波特率是指 1 * 1000 * 1000 us 下的 bit 数量(可能描述不准确,主要就是量化 bit 的传输周期),因此在 1 秒下 115200 波特率的 bit 周期为 8 us , 结合标准的传输内容 起始位 数据位 停止位,总共 10 个 bit ,也就是 80 us 一个字节,因此 115200 下传输一个字节需要 80 us 左右。 135 | 136 | 基于此继续说,所以发送的时候,假设为上升沿触发后,将会持续 80us 的过程进行字节判定,对方将会捕获此数据进行协议解析,而没有逻辑分析仪,你就无法准确判断,怎么才是正确的数据。 137 | 138 | 所以我从师弟手上抢掠了一台萝莉分析仪,先是捕获 CH340 的发送数据,以确保标准发送的数据源,再结合自己产生的数据做比较,结果才发现,发送的逻辑结构是一样的,但周期间隔完全不一样,因此假设逻辑已经正确,消除时序的周期差异,只需要解决差异的倍数就可以了,所以回到 主频 和 时间的关系,例如 esp32 160 的时候此时 芯片的 1 us 差应该如何获得,为了能够创造这个 1 us 的关系,实际上就是假设为单周期的计数器的结果,所以我们可以假设 160 次累加后相当于 1 us,所以 8u 就是放大 8 * 160 的结果,有了这个基准,就可以准确的进行每次数据的发送间隔,在代码中的 WaitBitTime 和 getCycleCount 就是做这个用途的。 139 | 140 | 有了周期的基准,也有了逻辑结构,程序的功能已经成型,那么就是核对测试的问题。 141 | 142 | 本以为有了这一切都已经可以正常发送数据了后。 143 | 144 | 结果发现硬件存在一点差异化问题,不知为何,第一个字节发送的一定会错误,因为分析仪得到的数据中有一个极小的抖动,突然向下跳了一下,导致后续数据混乱,所以先发一个数据,清理掉这个不知道是不是上电带来的影响(软解),此后数据一切正常。 145 | 146 | 接着测试发送 0x00 - 0xFF 的定义域数据,核对边界,切换 9600 、57600、115200 进行核对,期间没有什么异常。 147 | 148 | 进入到接收部分开发,中断触发已经确认,但发现,此时逻辑分析仪已经无法派上用场了,因为解析全指望芯片的寄存器和中断函数不出问题,处理这部分的时候,幸运的结合了 Arduino 的经验,假设数据源为 CH340 ,选择起始位的上升沿的 1 / 9 区域作为捕获上升沿信号的采样(没有过采样),此后依次采样,然后 停止位的时候 8 / 9 的区域收尾停止位 bit ,此时一帧完成。 149 | 150 | 这个逻辑在 9600 和 57600 的时候没有出现太大问题,当 115200 出现后,1 / 9 的比例无法保障 256 字节数据传输过程中的执行误差。(还是因为没有过采样XD),所以 115200 的时候,出现了接收错误,没有办法使用逻辑分析仪,结合代码逻辑,尽量优化中断函数的操作,然后确保每次中断函数的独占和退出都最小化影响,并调整到 1 / 256 的区间,此时 256 定义域字节数据一切正常,测试完成。 151 | 152 | ESP-IDF 开发完成,移植到 MicroPyton 存在的问题。 153 | 154 | 主要是发送数据的函数间隔和接收数据的其他函数影响,总体来讲。 155 | 156 | 发送函数在 Python 环境中,所以 115200 的时候,数据位的发送过程中与 标准源的误差去到了 4us ,这意味着可能错过半个位,因此可以通过设置较高的波特率调快发送的位等待(bit wait time),但接收函数就无法保证了,所以 115200 还存在一些需要深度优化的才能解决的细节问题(比如过采样XD,也需要测试一下 ESP32 的 IO 翻转速度)。 157 | 158 | ## problem 159 | 160 | 目前是半双工的软串口,所以你需要一个 CH340 之类的做数据收发测试,注意发送的数据,不能乱发,容易让电脑蓝屏(使用的时候尽量是 ASCII)。 161 | 162 | MicroPython 暂时无法使用 115200 的波特率,但你如果是指定的某些数据协议,还是可以通过修改源码的时序尽可能解决的,但这个做法并不通用。 163 | 164 | 还需要更长的数据和更大量的数据传输来测试,否则也只是消费级的娱乐代码水准。 165 | 166 | ## result 167 | 168 | 最后 萝莉分析仪真是个好东西,还有我的空气果可以搬到 MicroPython 上了,来一张全家桶合照。 169 | 170 | ![](readme/all.png) 171 | -------------------------------------------------------------------------------- /sw_serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | Github: junhuanchen 3 | Copyright (c) 2018 Juwan 4 | Licensed under the MIT license: 5 | http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #define SW_EOF -1 19 | 20 | typedef struct sw_serial 21 | { 22 | gpio_num_t rxPin, txPin; 23 | uint32_t buffSize, bitTime, rx_start_time, rx_end_time; 24 | bool invert, overflow; 25 | volatile uint32_t inPos, outPos; 26 | uint8_t *buffer; 27 | } SwSerial; 28 | 29 | SwSerial *sw_new(gpio_num_t Tx, gpio_num_t Rx, bool Inverse, int buffSize) 30 | { 31 | SwSerial *tmp = (SwSerial *)malloc(sizeof(SwSerial)); 32 | 33 | if (NULL != tmp) 34 | { 35 | tmp->invert = Inverse; 36 | tmp->overflow = false; 37 | tmp->inPos = tmp->outPos = 0; 38 | tmp->buffSize = buffSize; 39 | tmp->buffer = (uint8_t *)malloc(buffSize); 40 | if (NULL != tmp->buffer) 41 | { 42 | tmp->rxPin = Rx; 43 | gpio_pad_select_gpio(Rx); 44 | gpio_set_direction(Rx, GPIO_MODE_INPUT); 45 | 46 | tmp->txPin = Tx; 47 | gpio_pad_select_gpio(Tx); 48 | gpio_set_direction(Tx, GPIO_MODE_OUTPUT); 49 | 50 | // For the TTL level of positive logic, the starting bit is the low level of one bit time. 51 | gpio_set_level(Tx, !Inverse); 52 | // Too short leads to sticky bags 53 | // One byte of time 9600 104us * 10 115200 18us 54 | vTaskDelay(2 / portTICK_RATE_MS); 55 | 56 | return tmp; 57 | } 58 | free(tmp), tmp = NULL; 59 | } 60 | 61 | return tmp; 62 | } 63 | 64 | void sw_del(SwSerial *self) 65 | { 66 | if (NULL != self->buffer) 67 | { 68 | free(self->buffer); 69 | } 70 | 71 | free(self); 72 | } 73 | 74 | uint32_t getCycleCount() 75 | { 76 | return esp_cpu_get_ccount(); 77 | } 78 | 79 | #define WaitBitTime(wait) \ 80 | for (uint32_t start = getCycleCount(); getCycleCount() - start < wait;) 81 | 82 | // The first byte will wrong, after normal 83 | static void IRAM_ATTR sw_rx_handler(void *args) 84 | { 85 | SwSerial *self = (SwSerial *)args; 86 | 87 | uint8_t rec = 0; 88 | 89 | portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 90 | portENTER_CRITICAL(&mux); 91 | 92 | // (self->invert) flag invert set Start 1 And Stop 0 invert 93 | // But myself not need, so need extra added by yourself 94 | 95 | // Wait Start Bit To Start 96 | WaitBitTime(self->rx_start_time); 97 | if (0 == gpio_get_level(self->rxPin)) 98 | { 99 | for (uint8_t i = 0; i != 8; i++) 100 | { 101 | rec >>= 1; 102 | WaitBitTime(self->bitTime); 103 | if (gpio_get_level(self->rxPin)) 104 | { 105 | rec |= 0x80; 106 | } 107 | } 108 | // Wait Start Bit To End 109 | WaitBitTime(self->rx_end_time); 110 | if (1 == gpio_get_level(self->rxPin)) 111 | { 112 | // Stop bit Allow Into RecvBuffer 113 | // Store the received value in the buffer unless we have an overflow 114 | int next = (self->inPos + 1) % self->buffSize; 115 | if (next != self->outPos) 116 | { 117 | self->buffer[self->inPos] = (self->invert) ? ~rec : rec; 118 | self->inPos = next; 119 | } 120 | else 121 | { 122 | self->overflow = true; 123 | } 124 | } 125 | } 126 | 127 | portEXIT_CRITICAL(&mux); 128 | // Must clear this bit in the interrupt register, 129 | // it gets set even when interrupts are disabled 130 | 131 | // Esp32 GPIO.status_w1tc interrupt auto recovery 132 | } 133 | 134 | esp_err_t sw_enableRx(SwSerial *self, bool State) 135 | { 136 | esp_err_t error = ESP_OK; 137 | if (State) 138 | { 139 | gpio_set_intr_type(self->rxPin, (self->invert) ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE); 140 | gpio_install_isr_service(0); 141 | error = gpio_isr_handler_add(self->rxPin, sw_rx_handler, (void*)self); 142 | 143 | } 144 | else 145 | { 146 | error = gpio_isr_handler_remove(self->rxPin); 147 | gpio_uninstall_isr_service(); 148 | } 149 | 150 | return error; 151 | } 152 | 153 | int sw_write(SwSerial *self, uint8_t byte) 154 | { 155 | if (self->invert) 156 | { 157 | byte = ~byte; 158 | } 159 | 160 | // Disable interrupts in order to get a clean transmit 161 | portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 162 | portENTER_CRITICAL(&mux); 163 | 164 | // create tx interrupts to start bit. 165 | gpio_set_level(self->txPin, 1), gpio_set_level(self->txPin, 0); 166 | 167 | WaitBitTime(self->bitTime); 168 | 169 | for (uint8_t i = 0; i != 8; i++) 170 | { 171 | gpio_set_level(self->txPin, (byte & 1) ? 1 : 0); 172 | WaitBitTime(self->bitTime); 173 | 174 | byte >>= 1; 175 | } 176 | 177 | // Stop bit 178 | gpio_set_level(self->txPin, 1); 179 | WaitBitTime(self->bitTime); 180 | 181 | // re-enable interrupts 182 | portEXIT_CRITICAL(&mux); 183 | 184 | return 1; 185 | } 186 | 187 | int sw_read(SwSerial *self) 188 | { 189 | if (self->inPos != self->outPos) 190 | { 191 | uint8_t ch = self->buffer[self->outPos]; 192 | self->outPos = (self->outPos + 1) % self->buffSize; 193 | return ch; 194 | } 195 | return -1; 196 | } 197 | 198 | // suggest max datalen <= 256 and baudRate <= 115200 199 | esp_err_t sw_open(SwSerial *self, uint32_t baudRate) 200 | { 201 | // The oscilloscope told me 202 | self->bitTime = (esp_clk_cpu_freq() / baudRate); 203 | 204 | // Rx bit Timing Settings 205 | switch (baudRate) 206 | { 207 | case 115200: 208 | self->rx_start_time = (self->bitTime / 256); 209 | self->rx_end_time = (self->bitTime * 127 / 256); 210 | break; 211 | 212 | case 9600: 213 | self->rx_start_time = (self->bitTime / 9); 214 | self->rx_end_time = (self->bitTime * 8 / 9); 215 | break; 216 | 217 | default: // tested 57600 len 256 218 | self->rx_start_time = (self->bitTime / 9); 219 | self->rx_end_time = (self->bitTime * 8 / 9); 220 | break; 221 | } 222 | 223 | // printf("sw_open %u %d\n", self->rx_start_time, self->rx_end_time); 224 | 225 | sw_write(self, 0x00); // Initialization uart link 226 | 227 | return sw_enableRx(self, true); 228 | } 229 | 230 | esp_err_t sw_stop(SwSerial *self) 231 | { 232 | return sw_enableRx(self, false); 233 | } 234 | 235 | int sw_any(SwSerial *self) 236 | { 237 | int avail = self->inPos - self->outPos; 238 | return (avail < 0) ? avail + self->buffSize : avail; 239 | } 240 | 241 | void sw_flush(SwSerial *self) 242 | { 243 | self->inPos = self->outPos = 0; 244 | self->overflow = false; 245 | } 246 | 247 | bool sw_overflow(SwSerial *self) 248 | { 249 | return self->overflow; 250 | } 251 | 252 | int sw_peek(SwSerial *self) 253 | { 254 | if (self->inPos != self->outPos) 255 | { 256 | return self->buffer[self->outPos]; 257 | } 258 | return -1; 259 | } 260 | -------------------------------------------------------------------------------- /for_idf5.1: -------------------------------------------------------------------------------- 1 | /* 2 | Github: junhuanchen 3 | Copyright (c) 2018 Juwan 4 | Licensed under the MIT license: 5 | http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define SW_EOF -1 19 | 20 | typedef struct sw_serial 21 | { 22 | gpio_num_t rxPin, txPin; 23 | uint32_t buffSize, bitTime, rx_start_time, rx_end_time; 24 | bool invert, overflow; 25 | volatile uint32_t inPos, outPos; 26 | uint8_t *buffer; 27 | } SwSerial; 28 | /// @brief 创建一个软窗口 29 | /// @param Tx 发送io 30 | /// @param Rx 接收io 31 | /// @param Inverse 电平逻辑 32 | /// @param buffSize 缓冲区大小 33 | /// @return 串口接口 34 | SwSerial *sw_new(gpio_num_t Tx, gpio_num_t Rx, bool Inverse, int buffSize) 35 | { 36 | SwSerial *tmp = (SwSerial *)malloc(sizeof(SwSerial)); 37 | 38 | if (NULL != tmp) 39 | { 40 | tmp->invert = Inverse; 41 | tmp->overflow = false; 42 | tmp->inPos = tmp->outPos = 0; 43 | tmp->buffSize = buffSize; 44 | tmp->buffer = (uint8_t *)malloc(buffSize); 45 | if (NULL != tmp->buffer) 46 | { 47 | tmp->rxPin = Rx; 48 | 49 | esp_rom_gpio_pad_select_gpio(Rx); 50 | gpio_set_direction(Rx, GPIO_MODE_INPUT); 51 | 52 | tmp->txPin = Tx; 53 | 54 | esp_rom_gpio_pad_select_gpio(Tx); 55 | gpio_set_direction(Tx, GPIO_MODE_OUTPUT); 56 | 57 | // For the TTL level of positive logic, the starting bit is the low level of one bit time. 58 | // 对于正逻辑的TTL电平,起始位是一位时间的低电平。 59 | gpio_set_level(Tx, !Inverse); 60 | // Too short leads to sticky bags 61 | // One byte of time 9600 104us * 10 115200 18us 62 | vTaskDelay(1); 63 | 64 | return tmp; 65 | } 66 | free(tmp), tmp = NULL; 67 | } 68 | 69 | return tmp; 70 | } 71 | /// @brief 清空缓冲区 72 | /// @param self 接口 73 | void sw_del(SwSerial *self) 74 | { 75 | if (NULL != self->buffer) 76 | { 77 | free(self->buffer); 78 | } 79 | 80 | free(self); 81 | } 82 | /// @brief 获取周期计数 83 | /// @return 84 | uint32_t getCycleCount() 85 | { 86 | // return 0; 87 | return esp_cpu_get_cycle_count(); 88 | } 89 | 90 | #define WaitBitTime(wait) \ 91 | for (uint32_t start = getCycleCount(); getCycleCount() - start < wait;) 92 | 93 | // The first byte will wrong, after normal 94 | static void IRAM_ATTR sw_rx_handler(void *args) 95 | { 96 | SwSerial *self = (SwSerial *)args; 97 | 98 | uint8_t rec = 0; 99 | 100 | portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 101 | portENTER_CRITICAL(&mux); 102 | 103 | // (self->invert) flag invert set Start 1 And Stop 0 invert 104 | // But myself not need, so need extra added by yourself 105 | 106 | // Wait Start Bit To Start 107 | WaitBitTime(self->rx_start_time); 108 | if (0 == gpio_get_level(self->rxPin)) 109 | { 110 | for (uint8_t i = 0; i != 8; i++) 111 | { 112 | rec >>= 1; 113 | WaitBitTime(self->bitTime); 114 | if (gpio_get_level(self->rxPin)) 115 | { 116 | rec |= 0x80; 117 | } 118 | } 119 | // Wait Start Bit To End 120 | WaitBitTime(self->rx_end_time); 121 | if (1 == gpio_get_level(self->rxPin)) 122 | { 123 | // Stop bit Allow Into RecvBuffer 124 | // Store the received value in the buffer unless we have an overflow 125 | int next = (self->inPos + 1) % self->buffSize; 126 | if (next != self->outPos) 127 | { 128 | self->buffer[self->inPos] = (self->invert) ? ~rec : rec; 129 | self->inPos = next; 130 | } 131 | else 132 | { 133 | self->overflow = true; 134 | } 135 | } 136 | } 137 | 138 | portEXIT_CRITICAL(&mux); 139 | // Must clear this bit in the interrupt register, 140 | // it gets set even when interrupts are disabled 141 | 142 | // Esp32 GPIO.status_w1tc interrupt auto recovery 143 | } 144 | 145 | esp_err_t sw_enableRx(SwSerial *self, bool State) 146 | { 147 | esp_err_t error = ESP_OK; 148 | if (State) 149 | { 150 | gpio_set_intr_type(self->rxPin, (self->invert) ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE); 151 | gpio_install_isr_service(0); 152 | error = gpio_isr_handler_add(self->rxPin, sw_rx_handler, (void*)self); 153 | 154 | } 155 | else 156 | { 157 | error = gpio_isr_handler_remove(self->rxPin); 158 | gpio_uninstall_isr_service(); 159 | } 160 | 161 | return error; 162 | } 163 | /// @brief 窗口写数据 164 | /// @param self 接口 165 | /// @param byte 数据 166 | /// @return 167 | int sw_write(SwSerial *self, uint8_t byte) 168 | { 169 | if (self->invert) 170 | { 171 | byte = ~byte; 172 | } 173 | 174 | // Disable interrupts in order to get a clean transmit 175 | portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 176 | portENTER_CRITICAL(&mux); 177 | 178 | // create tx interrupts to start bit. 179 | gpio_set_level(self->txPin, 1), gpio_set_level(self->txPin, 0); 180 | 181 | WaitBitTime(self->bitTime); 182 | 183 | for (uint8_t i = 0; i != 8; i++) 184 | { 185 | gpio_set_level(self->txPin, (byte & 1) ? 1 : 0); 186 | WaitBitTime(self->bitTime); 187 | 188 | byte >>= 1; 189 | } 190 | 191 | // Stop bit 192 | gpio_set_level(self->txPin, 1); 193 | WaitBitTime(self->bitTime); 194 | 195 | // re-enable interrupts 196 | portEXIT_CRITICAL(&mux); 197 | 198 | return 1; 199 | } 200 | /// @brief 读取串口数据 201 | /// @param self 接口 202 | /// @return 接收到的数据 203 | int sw_read(SwSerial *self) 204 | { 205 | if (self->inPos != self->outPos) 206 | { 207 | uint8_t ch = self->buffer[self->outPos]; 208 | self->outPos = (self->outPos + 1) % self->buffSize; 209 | return ch; 210 | } 211 | return -1; 212 | } 213 | 214 | // suggest max datalen <= 256 and baudRate <= 115200 215 | /// @brief 开启软串口 216 | /// @param self 接口 217 | /// @param baudRate 波特率 115200 9600 218 | /// @return 219 | esp_err_t sw_open(SwSerial *self, uint32_t baudRate) 220 | { 221 | // The oscilloscope told me 222 | self->bitTime = (esp_clk_cpu_freq() / baudRate); 223 | 224 | // Rx bit Timing Settings 225 | switch (baudRate) 226 | { 227 | case 115200: 228 | self->rx_start_time = (self->bitTime / 256); 229 | self->rx_end_time = (self->bitTime * 127 / 256); 230 | break; 231 | 232 | case 9600: 233 | self->rx_start_time = (self->bitTime / 9); 234 | self->rx_end_time = (self->bitTime * 8 / 9); 235 | break; 236 | 237 | default: // tested 57600 len 256 238 | self->rx_start_time = (self->bitTime / 9); 239 | self->rx_end_time = (self->bitTime * 8 / 9); 240 | break; 241 | } 242 | 243 | // printf("sw_open %u %d\n", self->rx_start_time, self->rx_end_time); 244 | 245 | // sw_write(self, 0x00); // I不需要初始化标志 246 | 247 | return sw_enableRx(self, true); 248 | } 249 | /// @brief 关闭软串口 250 | /// @param self 接口 251 | /// @return 252 | esp_err_t sw_stop(SwSerial *self) 253 | { 254 | return sw_enableRx(self, false); 255 | } 256 | /// @brief 获取数据大小 257 | /// @param self 258 | /// @return 259 | int sw_any(SwSerial *self) 260 | { 261 | int avail = self->inPos - self->outPos; 262 | return (avail < 0) ? avail + self->buffSize : avail; 263 | } 264 | 265 | void sw_flush(SwSerial *self) 266 | { 267 | self->inPos = self->outPos = 0; 268 | self->overflow = false; 269 | } 270 | 271 | bool sw_overflow(SwSerial *self) 272 | { 273 | return self->overflow; 274 | } 275 | 276 | int sw_peek(SwSerial *self) 277 | { 278 | if (self->inPos != self->outPos) 279 | { 280 | return self->buffer[self->outPos]; 281 | } 282 | return -1; 283 | } 284 | -------------------------------------------------------------------------------- /py_serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Github: junhuanchen 4 | 5 | Copyright (c) 2018 Juwan 6 | 7 | Licensed under the MIT license: 8 | 9 | http://www.opensource.org/licenses/mit-license.php 10 | 11 | */ 12 | 13 | 14 | 15 | #include 16 | 17 | 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | 26 | 27 | #include 28 | 29 | #include 30 | 31 | 32 | 33 | #define SW_EOF -1 34 | 35 | 36 | 37 | typedef struct sw_serial 38 | 39 | { 40 | 41 | gpio_num_t rxPin, txPin; 42 | 43 | uint32_t buffSize, bitTime, rx_start_time, rx_end_time; 44 | 45 | bool invert, overflow; 46 | 47 | volatile uint32_t inPos, outPos; 48 | 49 | uint8_t *buffer; 50 | 51 | } SwSerial; 52 | 53 | 54 | 55 | SwSerial *sw_new(gpio_num_t Tx, gpio_num_t Rx, bool Inverse, int buffSize) 56 | 57 | { 58 | 59 | SwSerial *tmp = (SwSerial *)malloc(sizeof(SwSerial)); 60 | 61 | 62 | 63 | if (NULL != tmp) 64 | 65 | { 66 | 67 | tmp->invert = Inverse; 68 | 69 | tmp->overflow = false; 70 | 71 | tmp->inPos = tmp->outPos = 0; 72 | 73 | tmp->buffSize = buffSize; 74 | 75 | tmp->buffer = (uint8_t *)malloc(buffSize); 76 | 77 | if (NULL != tmp->buffer) 78 | 79 | { 80 | 81 | tmp->rxPin = Rx; 82 | 83 | gpio_pad_select_gpio(Rx); 84 | 85 | gpio_set_direction(Rx, GPIO_MODE_INPUT); 86 | 87 | 88 | 89 | tmp->txPin = Tx; 90 | 91 | gpio_pad_select_gpio(Tx); 92 | 93 | gpio_set_direction(Tx, GPIO_MODE_OUTPUT); 94 | 95 | 96 | 97 | // For the TTL level of positive logic, the starting bit is the low level of one bit time. 98 | 99 | gpio_set_level(Tx, !Inverse); 100 | 101 | // Too short leads to sticky bags 102 | 103 | // One byte of time 9600 104us * 10 115200 18us 104 | 105 | vTaskDelay(2 / portTICK_RATE_MS); 106 | 107 | 108 | 109 | return tmp; 110 | 111 | } 112 | 113 | free(tmp), tmp = NULL; 114 | 115 | } 116 | 117 | 118 | 119 | return tmp; 120 | 121 | } 122 | 123 | 124 | 125 | void sw_del(SwSerial *self) 126 | 127 | { 128 | 129 | if (NULL != self->buffer) 130 | 131 | { 132 | 133 | free(self->buffer); 134 | 135 | } 136 | 137 | 138 | 139 | free(self); 140 | 141 | } 142 | 143 | 144 | 145 | uint32_t getCycleCount() 146 | 147 | { 148 | 149 | uint32_t ccount; 150 | 151 | __asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount)); 152 | 153 | return ccount; 154 | 155 | } 156 | 157 | 158 | 159 | #define WaitBitTime(wait) \ 160 | 161 | for (uint32_t start = getCycleCount(); getCycleCount() - start < wait;) 162 | 163 | 164 | 165 | // The first byte will wrong, after normal 166 | 167 | static void IRAM_ATTR sw_rx_handler(void *args) 168 | 169 | { 170 | 171 | SwSerial *self = (SwSerial *)args; 172 | 173 | 174 | 175 | uint8_t rec = 0; 176 | 177 | 178 | 179 | portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 180 | 181 | portENTER_CRITICAL(&mux); 182 | 183 | 184 | 185 | // (self->invert) flag invert set Start 1 And Stop 0 invert 186 | 187 | // But myself not need, so need extra added by yourself 188 | 189 | 190 | 191 | // Wait Start Bit To Start 192 | 193 | WaitBitTime(self->rx_start_time); 194 | 195 | if (0 == gpio_get_level(self->rxPin)) 196 | 197 | { 198 | 199 | for (uint8_t i = 0; i != 8; i++) 200 | 201 | { 202 | 203 | rec >>= 1; 204 | 205 | WaitBitTime(self->bitTime); 206 | 207 | if (gpio_get_level(self->rxPin)) 208 | 209 | { 210 | 211 | rec |= 0x80; 212 | 213 | } 214 | 215 | } 216 | 217 | // Wait Start Bit To End 218 | 219 | WaitBitTime(self->rx_end_time); 220 | 221 | if (1 == gpio_get_level(self->rxPin)) 222 | 223 | { 224 | 225 | // Stop bit Allow Into RecvBuffer 226 | 227 | // Store the received value in the buffer unless we have an overflow 228 | 229 | int next = (self->inPos + 1) % self->buffSize; 230 | 231 | if (next != self->outPos) 232 | 233 | { 234 | 235 | self->buffer[self->inPos] = (self->invert) ? ~rec : rec; 236 | 237 | self->inPos = next; 238 | 239 | } 240 | 241 | else 242 | 243 | { 244 | 245 | self->overflow = true; 246 | 247 | } 248 | 249 | } 250 | 251 | } 252 | 253 | 254 | 255 | portEXIT_CRITICAL(&mux); 256 | 257 | // Must clear this bit in the interrupt register, 258 | 259 | // it gets set even when interrupts are disabled 260 | 261 | 262 | 263 | // Esp32 GPIO.status_w1tc interrupt auto recovery 264 | 265 | } 266 | 267 | 268 | 269 | esp_err_t sw_enableRx(SwSerial *self, bool State) 270 | 271 | { 272 | 273 | esp_err_t error = ESP_OK; 274 | 275 | if (State) 276 | 277 | { 278 | 279 | error = gpio_set_intr_type(self->rxPin, (self->invert) ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE); 280 | // printf("error = %d\n", error); 281 | 282 | // error = gpio_install_isr_service(0); // see machine_pin.c 283 | // printf("error = %d\n", error); 284 | 285 | error = gpio_isr_handler_add(self->rxPin, sw_rx_handler, (void*)self); 286 | // printf("error = %d\n", error); 287 | 288 | } 289 | 290 | else 291 | 292 | { 293 | 294 | error = gpio_isr_handler_remove(self->rxPin); 295 | // printf("error = %d\n", error); 296 | 297 | // gpio_uninstall_isr_service(); // see machine_pin.c 298 | // printf("error = %d\n", error); 299 | 300 | } 301 | 302 | 303 | 304 | return error; 305 | 306 | } 307 | 308 | 309 | 310 | int sw_write(SwSerial *self, uint8_t byte) 311 | 312 | { 313 | 314 | if (self->invert) 315 | 316 | { 317 | 318 | byte = ~byte; 319 | 320 | } 321 | 322 | 323 | 324 | // Disable interrupts in order to get a clean transmit 325 | 326 | portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 327 | 328 | portENTER_CRITICAL(&mux); 329 | 330 | 331 | 332 | // create tx interrupts to start bit. 333 | 334 | gpio_set_level(self->txPin, 1), gpio_set_level(self->txPin, 0); 335 | 336 | 337 | 338 | WaitBitTime(self->bitTime); 339 | 340 | 341 | 342 | for (uint8_t i = 0; i != 8; i++) 343 | 344 | { 345 | 346 | gpio_set_level(self->txPin, (byte & 1) ? 1 : 0); 347 | 348 | WaitBitTime(self->bitTime); 349 | 350 | 351 | 352 | byte >>= 1; 353 | 354 | } 355 | 356 | 357 | 358 | // Stop bit 359 | 360 | gpio_set_level(self->txPin, 1); 361 | 362 | WaitBitTime(self->bitTime); 363 | 364 | 365 | 366 | // re-enable interrupts 367 | 368 | portEXIT_CRITICAL(&mux); 369 | 370 | 371 | 372 | return 1; 373 | 374 | } 375 | 376 | 377 | 378 | int sw_read(SwSerial *self) 379 | 380 | { 381 | 382 | if (self->inPos != self->outPos) 383 | 384 | { 385 | 386 | uint8_t ch = self->buffer[self->outPos]; 387 | 388 | self->outPos = (self->outPos + 1) % self->buffSize; 389 | 390 | return ch; 391 | 392 | } 393 | 394 | return -1; 395 | 396 | } 397 | 398 | 399 | 400 | // suggest max datalen <= 256 and baudRate <= 115200 401 | 402 | esp_err_t sw_open(SwSerial *self, uint32_t baudRate) 403 | 404 | { 405 | 406 | // The oscilloscope told me 407 | 408 | self->bitTime = (esp_clk_cpu_freq() / baudRate); 409 | 410 | 411 | 412 | // Rx bit Timing Settings 413 | 414 | switch (baudRate) 415 | 416 | { 417 | 418 | case 115200: 419 | 420 | self->rx_start_time = (self->bitTime / 256); 421 | 422 | self->rx_end_time = (self->bitTime * 127 / 256); 423 | 424 | break; 425 | 426 | 427 | 428 | case 9600: 429 | 430 | self->rx_start_time = (self->bitTime / 9); 431 | 432 | self->rx_end_time = (self->bitTime * 8 / 9); 433 | 434 | break; 435 | 436 | 437 | 438 | default: // tested 57600 len 256 439 | 440 | self->rx_start_time = (self->bitTime / 9); 441 | 442 | self->rx_end_time = (self->bitTime * 8 / 9); 443 | 444 | break; 445 | 446 | } 447 | 448 | 449 | 450 | // printf("sw_open %u %d\n", self->rx_start_time, self->rx_end_time); 451 | 452 | 453 | 454 | sw_write(self, 0x00); // Initialization uart link 455 | 456 | 457 | 458 | return sw_enableRx(self, true); 459 | 460 | } 461 | 462 | 463 | 464 | esp_err_t sw_stop(SwSerial *self) 465 | 466 | { 467 | 468 | return sw_enableRx(self, false); 469 | 470 | } 471 | 472 | 473 | 474 | int sw_any(SwSerial *self) 475 | 476 | { 477 | 478 | int avail = self->inPos - self->outPos; 479 | 480 | return (avail < 0) ? avail + self->buffSize : avail; 481 | 482 | } 483 | 484 | 485 | 486 | void sw_flush(SwSerial *self) 487 | 488 | { 489 | 490 | self->inPos = self->outPos = 0; 491 | 492 | self->overflow = false; 493 | 494 | } 495 | 496 | 497 | 498 | bool sw_overflow(SwSerial *self) 499 | 500 | { 501 | 502 | return self->overflow; 503 | 504 | } 505 | 506 | 507 | 508 | int sw_peek(SwSerial *self) 509 | 510 | { 511 | 512 | if (self->inPos != self->outPos) 513 | 514 | { 515 | 516 | return self->buffer[self->outPos]; 517 | 518 | } 519 | 520 | return -1; 521 | 522 | } 523 | -------------------------------------------------------------------------------- /soft_urat_esp8285_57600.h: -------------------------------------------------------------------------------- 1 | /* 2 | Github: junhuanchen 3 | Copyright (c) 2018 Juwan 4 | Licensed under the MIT license: 5 | http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include "esp_freertos_hooks.h" 14 | 15 | #include 16 | #include 17 | #include "driver/soc.h" 18 | #include "rom/ets_sys.h" 19 | 20 | #define SW_EOF -1 21 | 22 | typedef struct sw_serial 23 | { 24 | uint32_t rxPin, txPin; 25 | uint32_t buffSize, bitTime, rx_start_time, rx_end_time; 26 | bool invert, overflow; 27 | volatile uint32_t inPos, outPos; 28 | uint8_t *buffer; 29 | } SwSerial; 30 | 31 | SwSerial *sw_new(uint32_t Tx, uint32_t Rx, bool Inverse, int buffSize) 32 | { 33 | SwSerial *tmp = (SwSerial *)malloc(sizeof(SwSerial)); 34 | 35 | if (NULL != tmp) 36 | { 37 | tmp->invert = Inverse; 38 | tmp->overflow = false; 39 | tmp->inPos = tmp->outPos = 0; 40 | tmp->buffSize = buffSize; 41 | tmp->buffer = (uint8_t *)malloc(buffSize); 42 | if (NULL != tmp->buffer) 43 | { 44 | gpio_config_t io_conf; 45 | io_conf.intr_type = Inverse ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE; 46 | io_conf.pin_bit_mask = 1ULL << Rx; 47 | io_conf.mode = GPIO_MODE_INPUT; 48 | io_conf.pull_up_en = 1; 49 | io_conf.pull_down_en = 1; 50 | gpio_config(&io_conf); 51 | 52 | // disable interrupt 53 | io_conf.intr_type = GPIO_INTR_DISABLE; 54 | // set as output mode 55 | io_conf.mode = GPIO_MODE_OUTPUT; 56 | // bit mask of the pins that you want to set 57 | io_conf.pin_bit_mask = (1ULL << Tx); 58 | // disable pull-down mode 59 | io_conf.pull_down_en = 1; 60 | // disable pull-up mode 61 | io_conf.pull_up_en = 1; 62 | // configure GPIO with the given settings 63 | ESP_ERROR_CHECK(gpio_config(&io_conf)); 64 | ESP_ERROR_CHECK(gpio_set_level(Tx, Inverse)); 65 | 66 | tmp->txPin = Tx; 67 | tmp->rxPin = Rx; 68 | 69 | // For the TTL level of positive logic, the starting bit is the low level of one bit time. 70 | // gpio_set_level(Tx, !Inverse); 71 | // Too short leads to sticky bags 72 | // One byte of time 9600 104us * 10 115200 18us 73 | vTaskDelay(2 / portTICK_RATE_MS); 74 | 75 | return tmp; 76 | } 77 | free(tmp), tmp = NULL; 78 | } 79 | 80 | return tmp; 81 | } 82 | 83 | void sw_del(SwSerial *self) 84 | { 85 | if (NULL != self->buffer) 86 | { 87 | free(self->buffer); 88 | } 89 | 90 | free(self); 91 | } 92 | 93 | // uint32_t getCycleCount() 94 | // { 95 | // uint32_t ccount; 96 | // __asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount)); 97 | // return ccount; 98 | // } 99 | 100 | 101 | #define WaitBitTime(wait) \ 102 | for (uint32_t start = (soc_get_ccount()); (soc_get_ccount()) - start < (wait);) 103 | 104 | // 0.1 us == soc_get_ccount() / g_esp_ticks_per_us / 10 105 | 106 | // #define WaitBitTime(wait) ets_delay_us(8) 107 | 108 | static inline bool IRAM_ATTR wait_bit_state(uint8_t pin, uint8_t state, uint8_t limit) 109 | { 110 | for (uint i = 0; i != limit; i++) 111 | { 112 | // ets_delay_us(1); 113 | WaitBitTime(limit); 114 | if (state == gpio_get_level(pin)) 115 | { 116 | return true; 117 | } 118 | } 119 | // ets_delay_us(1); 120 | return false; 121 | } 122 | 123 | static inline uint8_t IRAM_ATTR check_bit_state(uint8_t pin, uint8_t limit) 124 | { 125 | uint8_t flag[2] = { 0 }; 126 | for (uint i = 0; i != limit; i++) 127 | { 128 | flag[gpio_get_level(pin)] += 1; 129 | ets_delay_us(1); 130 | } 131 | return flag[0] < flag[1];// flag[0] < flag[1] ? 1 : 0; 132 | } 133 | 134 | // The first byte will wrong, after normal 135 | static void IRAM_ATTR sw_rx_handler(void *args) 136 | { 137 | portENTER_CRITICAL(); 138 | SwSerial *self = (SwSerial *)args; 139 | uint8_t rec = 0; 140 | 141 | // portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 142 | // (self->invert) flag invert set Start 1 And Stop 0 invert 143 | // But myself not need, so need extra added by yourself 144 | 145 | // Wait Start Bit To Start 146 | // WaitBitTime(self->rx_start_time); 147 | // if (self->invert == gpio_get_level(self->rxPin)) 148 | if (wait_bit_state(self->rxPin, self->invert, self->rx_start_time)) 149 | { 150 | for (uint8_t i = 0; i != 8; i++) 151 | { 152 | rec >>= 1; 153 | uint32_t tmp = self->bitTime - (i * 35); 154 | WaitBitTime(tmp); 155 | if (gpio_get_level(self->rxPin)) 156 | { 157 | rec |= 0x80; 158 | } 159 | } 160 | // Wait Start Bit To End 161 | // WaitBitTime(self->rx_end_time); 162 | // if (!self->invert == gpio_get_level(self->rxPin)) 163 | if (wait_bit_state(self->rxPin, !self->invert, self->rx_end_time)) 164 | { 165 | // Stop bit Allow Into RecvBuffer 166 | // Store the received value in the buffer unless we have an overflow 167 | int next = (self->inPos + 1) % self->buffSize; 168 | if (next != self->outPos) 169 | { 170 | self->buffer[self->inPos] = (self->invert) ? ~rec : rec; 171 | self->inPos = next; 172 | } 173 | else 174 | { 175 | self->overflow = true; 176 | } 177 | } 178 | } 179 | 180 | portEXIT_CRITICAL(); 181 | // Must clear this bit in the interrupt register, 182 | // it gets set even when interrupts are disabled 183 | 184 | // Esp32 GPIO.status_w1tc interrupt auto recovery 185 | } 186 | 187 | esp_err_t sw_enableRx(SwSerial *self, bool State) 188 | { 189 | esp_err_t error = ESP_OK; 190 | if (State) 191 | { 192 | gpio_set_intr_type(self->rxPin, (self->invert) ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE); 193 | gpio_install_isr_service(0); 194 | error = gpio_isr_handler_add(self->rxPin, sw_rx_handler, (void*)self); 195 | 196 | } 197 | else 198 | { 199 | error = gpio_isr_handler_remove(self->rxPin); 200 | gpio_uninstall_isr_service(); 201 | } 202 | 203 | return error; 204 | } 205 | 206 | int sw_write(SwSerial *self, uint8_t byte) 207 | { 208 | if (self->invert) 209 | { 210 | byte = ~byte; 211 | } 212 | 213 | // Disable interrupts in order to get a clean transmit 214 | // portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 215 | portENTER_CRITICAL(); 216 | 217 | // create tx interrupts to start bit. 218 | gpio_set_level(self->txPin, 0); 219 | gpio_set_level(self->txPin, 1); 220 | // WaitBitTime(self->bitTime); 221 | ets_delay_us(8 * 2); // 115200 = 8 * 1 us 222 | 223 | for (uint8_t i = 0; i != 8; i++) 224 | { 225 | gpio_set_level(self->txPin, (byte & 1) ? 1 : 0); 226 | ets_delay_us(8 * 2); // 115200 = 8 * 1 us 227 | 228 | byte >>= 1; 229 | } 230 | 231 | // Stop bit 232 | gpio_set_level(self->txPin, 0); 233 | ets_delay_us(8 * 2); // 115200 = 8 * 1 us 234 | 235 | // re-enable interrupts 236 | portEXIT_CRITICAL(); 237 | 238 | return 1; 239 | } 240 | 241 | int sw_read(SwSerial *self) 242 | { 243 | if (self->inPos != self->outPos) 244 | { 245 | uint8_t ch = self->buffer[self->outPos]; 246 | self->outPos = (self->outPos + 1) % self->buffSize; 247 | return ch; 248 | } 249 | return -1; 250 | } 251 | 252 | // suggest max datalen <= 256 and baudRate <= 115200 253 | esp_err_t sw_open(SwSerial *self, uint32_t baudRate) 254 | { 255 | // The oscilloscope told me 256 | self->bitTime = (esp_clk_cpu_freq() / (baudRate)); 257 | 258 | // Rx bit Timing Settings 259 | switch (baudRate) 260 | { 261 | case 115200: 262 | self->rx_start_time = (self->bitTime / 256); 263 | self->rx_end_time = (self->bitTime / 256); 264 | break; 265 | 266 | case 9600: 267 | self->rx_start_time = (self->bitTime / 9); 268 | self->rx_end_time = (self->bitTime * 8 / 9); 269 | break; 270 | 271 | default: // tested 57600 len 256 272 | self->rx_start_time = (self->bitTime / 9); 273 | self->rx_end_time = (self->bitTime / 9); 274 | break; 275 | } 276 | 277 | // printf("sw_open %u %d\n", self->rx_start_time, self->rx_end_time); 278 | 279 | sw_write(self, 0x00); // Initialization uart link 280 | 281 | return sw_enableRx(self, true); 282 | } 283 | 284 | esp_err_t sw_stop(SwSerial *self) 285 | { 286 | return sw_enableRx(self, false); 287 | } 288 | 289 | int sw_any(SwSerial *self) 290 | { 291 | int avail = self->inPos - self->outPos; 292 | return (avail < 0) ? avail + self->buffSize : avail; 293 | } 294 | 295 | void sw_flush(SwSerial *self) 296 | { 297 | self->inPos = self->outPos = 0; 298 | self->overflow = false; 299 | } 300 | 301 | bool sw_overflow(SwSerial *self) 302 | { 303 | return self->overflow; 304 | } 305 | 306 | int sw_peek(SwSerial *self) 307 | { 308 | if (self->inPos != self->outPos) 309 | { 310 | return self->buffer[self->outPos]; 311 | } 312 | return -1; 313 | } -------------------------------------------------------------------------------- /app_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ESPRESSIF MIT License 3 | * 4 | * Copyright (c) 2017 5 | * 6 | * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case, 7 | * it is free of charge, to any person obtaining a copy of this software and associated 8 | * documentation files (the "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished 11 | * to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * 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, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "freertos/FreeRTOS.h" 29 | #include "freertos/task.h" 30 | #include "esp_system.h" 31 | #include "nvs_flash.h" 32 | 33 | #ifdef CONFIG_AT_WIFI_COMMAND_SUPPORT 34 | #include "esp_event_loop.h" 35 | #include "esp_wifi.h" 36 | #endif 37 | 38 | #if defined(CONFIG_BT_ENABLED) 39 | #include "esp_bt.h" 40 | #endif 41 | 42 | #include "esp_at.h" 43 | 44 | #ifdef CONFIG_AT_OTA_SUPPORT 45 | #include "at_upgrade.h" 46 | #endif 47 | 48 | #include "at_interface.h" 49 | #include "at_default_config.h" 50 | 51 | #ifdef CONFIG_AT_ETHERNET_SUPPORT 52 | #include "at_eth_init.h" 53 | #endif 54 | 55 | #ifdef CONFIG_AT_OTA_SUPPORT 56 | static uint8_t at_exeCmdCipupdate(uint8_t *cmd_name)//add get station ip and ap ip 57 | { 58 | 59 | if (esp_at_upgrade_process(ESP_AT_OTA_MODE_NORMAL,NULL)) { 60 | esp_at_response_result(ESP_AT_RESULT_CODE_OK); 61 | esp_at_port_wait_write_complete(portMAX_DELAY); 62 | esp_restart(); 63 | for(;;){ 64 | } 65 | } 66 | 67 | return ESP_AT_RESULT_CODE_ERROR; 68 | } 69 | 70 | static uint8_t at_setupCmdCipupdate(uint8_t para_num) 71 | { 72 | int32_t ota_mode = 0; 73 | int32_t cnt = 0; 74 | uint8_t* version = NULL; 75 | 76 | if (esp_at_get_para_as_digit (cnt++,&ota_mode) != ESP_AT_PARA_PARSE_RESULT_OK) { 77 | return ESP_AT_RESULT_CODE_ERROR; 78 | } 79 | 80 | if (cnt < para_num) { 81 | if(esp_at_get_para_as_str (cnt++,&version) != ESP_AT_PARA_PARSE_RESULT_OK) { 82 | return ESP_AT_RESULT_CODE_ERROR; 83 | } 84 | } 85 | 86 | if (cnt != para_num) { 87 | return ESP_AT_RESULT_CODE_ERROR; 88 | } 89 | 90 | if (esp_at_upgrade_process(ota_mode,version)) { 91 | esp_at_response_result(ESP_AT_RESULT_CODE_OK); 92 | esp_at_port_wait_write_complete(portMAX_DELAY); 93 | esp_restart(); 94 | for(;;){ 95 | } 96 | } 97 | 98 | return ESP_AT_RESULT_CODE_ERROR; 99 | } 100 | 101 | static esp_at_cmd_struct at_update_cmd[] = { 102 | {"+CIUPDATE", NULL, NULL, at_setupCmdCipupdate, at_exeCmdCipupdate}, 103 | }; 104 | #endif 105 | 106 | #ifdef CONFIG_AT_WIFI_COMMAND_SUPPORT 107 | static esp_err_t at_wifi_event_handler(void *ctx, system_event_t *event) 108 | { 109 | esp_err_t ret = esp_at_wifi_event_handler(ctx, event); 110 | 111 | return ret; 112 | } 113 | 114 | static void initialise_wifi(void) 115 | { 116 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 117 | 118 | ESP_ERROR_CHECK( esp_event_loop_init(at_wifi_event_handler, NULL) ); 119 | 120 | ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); 121 | ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); 122 | ESP_ERROR_CHECK( esp_wifi_start() ); 123 | } 124 | #endif 125 | 126 | #include "driver/uart.h" 127 | #include "at_webai_cmd.h" 128 | #include "soft_urat.h" 129 | 130 | void app_main() 131 | { 132 | const esp_partition_t * partition = esp_at_custom_partition_find(0x40, 0xff, "factory_param"); 133 | char* data = NULL; 134 | uint32_t module_id = 0; 135 | 136 | if (partition) { 137 | data = (char*)malloc(ESP_AT_FACTORY_PARAMETER_SIZE); // Notes 138 | assert(data != NULL); 139 | if(esp_partition_read(partition, 0, data, ESP_AT_FACTORY_PARAMETER_SIZE) != ESP_OK){ 140 | free(data); 141 | printf("esp_partition_read failed\r\n"); 142 | return ; 143 | } else { 144 | module_id = data[3]; 145 | free(data); 146 | } 147 | } else { 148 | printf("factory_parameter partition missed\r\n"); 149 | } 150 | 151 | const char* module_name = esp_at_get_module_name_by_id(module_id); 152 | uint8_t *version = (uint8_t *)malloc(256); 153 | #ifdef CONFIG_AT_COMMAND_TERMINATOR 154 | uint8_t cmd_terminator[2] = {CONFIG_AT_COMMAND_TERMINATOR,0}; 155 | #endif 156 | 157 | nvs_flash_init(); 158 | tcpip_adapter_init(); 159 | #ifdef CONFIG_AT_WIFI_COMMAND_SUPPORT 160 | initialise_wifi(); 161 | #endif 162 | at_interface_init(); 163 | 164 | sprintf((char*)version, "compile time(%s):%s %s\r\n", ESP_AT_PROJECT_COMMIT_ID, __DATE__, __TIME__); 165 | #ifdef CONFIG_ESP_AT_FW_VERSION 166 | if ((strlen(CONFIG_ESP_AT_FW_VERSION) > 0) && (strlen(CONFIG_ESP_AT_FW_VERSION) <= 128)){ 167 | printf("%s\r\n", CONFIG_ESP_AT_FW_VERSION); 168 | sprintf((char*)version + strlen((char*)version),"Bin version:%s(%s)\r\n", CONFIG_ESP_AT_FW_VERSION, module_name); 169 | } 170 | #endif 171 | esp_at_module_init (CONFIG_AT_SOCKET_MAX_CONN_NUM, version); // reserved one for server 172 | free(version); 173 | esp_at_factory_parameter_init(); 174 | 175 | #ifdef CONFIG_AT_BASE_COMMAND_SUPPORT 176 | if(esp_at_base_cmd_regist() == false) { 177 | printf("regist base cmd fail\r\n"); 178 | } 179 | #endif 180 | 181 | #ifdef CONFIG_AT_WIFI_COMMAND_SUPPORT 182 | if(esp_at_wifi_cmd_regist() == false) { 183 | printf("regist wifi cmd fail\r\n"); 184 | } 185 | #endif 186 | 187 | #ifdef CONFIG_AT_NET_COMMAND_SUPPORT 188 | if(esp_at_net_cmd_regist() == false) { 189 | printf("regist net cmd fail\r\n"); 190 | } 191 | #endif 192 | 193 | #ifdef CONFIG_AT_MQTT_COMMAND_SUPPORT 194 | if(esp_at_mqtt_cmd_regist() == false) { 195 | printf("regist mqtt cmd fail\r\n"); 196 | } 197 | #endif 198 | 199 | #ifdef CONFIG_AT_HTTP_COMMAND_SUPPORT 200 | if(esp_at_http_cmd_regist() == false) { 201 | printf("regist http cmd fail\r\n"); 202 | } 203 | #endif 204 | 205 | #ifdef CONFIG_AT_BLE_COMMAND_SUPPORT 206 | if(esp_at_ble_cmd_regist() == false) { 207 | printf("regist ble cmd fail\r\n"); 208 | } 209 | #endif 210 | 211 | #ifdef CONFIG_AT_BLE_HID_COMMAND_SUPPORT 212 | if(esp_at_ble_hid_cmd_regist() == false) { 213 | printf("regist ble hid cmd fail\r\n"); 214 | } 215 | #endif 216 | 217 | #ifdef CONFIG_AT_BLUFI_COMMAND_SUPPORT 218 | if(esp_at_blufi_cmd_regist() == false) { 219 | printf("regist blufi cmd fail\r\n"); 220 | } 221 | #endif 222 | 223 | #ifdef CONFIG_AT_BT_COMMAND_SUPPORT 224 | if(esp_at_bt_cmd_regist() == false) { 225 | printf("regist bt cmd fail\r\n"); 226 | } 227 | #ifdef CONFIG_AT_BT_SPP_COMMAND_SUPPORT 228 | if(esp_at_bt_spp_cmd_regist() == false) { 229 | printf("regist bt spp cmd fail\r\n"); 230 | } 231 | #endif 232 | #ifdef CONFIG_AT_BT_A2DP_COMMAND_SUPPORT 233 | if(esp_at_bt_a2dp_cmd_regist() == false) { 234 | printf("regist bt a2dp cmd fail\r\n"); 235 | } 236 | #endif 237 | #endif 238 | 239 | #if defined(CONFIG_BT_ENABLED) 240 | #if defined(CONFIG_AT_BLE_COMMAND_SUPPORT) || defined(CONFIG_AT_BLE_HID_COMMAND_SUPPORT) || defined(CONFIG_AT_BLUFI_COMMAND_SUPPORT) 241 | #if !defined(CONFIG_AT_BT_COMMAND_SUPPORT) 242 | esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); 243 | #endif 244 | #else 245 | #if defined(CONFIG_AT_BT_COMMAND_SUPPORT) 246 | esp_bt_controller_mem_release(ESP_BT_MODE_BLE); 247 | #else 248 | esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); 249 | #endif 250 | #endif 251 | #endif 252 | 253 | #if defined(CONFIG_AT_MDNS_COMMAND_SUPPORT) 254 | if(esp_at_mdns_cmd_regist() == false) { 255 | printf("regist mdns cmd fail\r\n"); 256 | } 257 | #endif 258 | 259 | #if defined(CONFIG_AT_WPS_COMMAND_SUPPORT) 260 | if(esp_at_wps_cmd_regist() == false) { 261 | printf("regist wps cmd fail\r\n"); 262 | } 263 | #endif 264 | 265 | #if defined(CONFIG_AT_SMARTCONFIG_COMMAND_SUPPORT) 266 | if(esp_at_smartconfig_cmd_regist() == false) { 267 | printf("regist smartconfig cmd fail\r\n"); 268 | } 269 | #endif 270 | 271 | #if defined(CONFIG_AT_PING_COMMAND_SUPPORT) 272 | if(esp_at_ping_cmd_regist() == false) { 273 | printf("regist ping cmd fail\r\n"); 274 | } 275 | #endif 276 | 277 | #ifdef CONFIG_AT_ETHERNET_SUPPORT 278 | if(at_eth_init() == false) { 279 | printf("ethernet init fail\r\n"); 280 | }else { 281 | if(esp_at_eth_cmd_regist() == false) { 282 | printf("regist ethernet cmd fail\r\n"); 283 | } 284 | } 285 | #endif 286 | 287 | #ifdef CONFIG_AT_FS_COMMAND_SUPPORT 288 | if(esp_at_fs_cmd_regist() == false) { 289 | printf("regist fs cmd fail\r\n"); 290 | } 291 | #endif 292 | 293 | #ifdef CONFIG_AT_EAP_COMMAND_SUPPORT 294 | if(esp_at_eap_cmd_regist() == false) { 295 | printf("regist eap cmd fail\r\n"); 296 | } 297 | #endif 298 | 299 | #ifdef CONFIG_AT_COMMAND_TERMINATOR 300 | esp_at_custom_cmd_line_terminator_set((uint8_t*)&cmd_terminator); 301 | #endif 302 | 303 | #ifdef CONFIG_AT_OTA_SUPPORT 304 | esp_at_custom_cmd_array_regist (at_update_cmd, sizeof(at_update_cmd)/sizeof(at_update_cmd[0])); 305 | #endif 306 | 307 | at_setupWebAICmd(); 308 | at_custom_init(); 309 | 310 | SwSerial *tmp = sw_new(14, 12, true, 512); 311 | printf("%u\n", tmp->bitTime); 312 | if (tmp != NULL) 313 | { 314 | 315 | sw_open(tmp, 57600); // 115200 > 9600 316 | 317 | // puts("sw_write test"); 318 | 319 | // for (size_t i = 0; i < 256; i++) 320 | // { 321 | // sw_write(tmp, (uint8_t)i); 322 | // } 323 | 324 | puts("sw_write test"); 325 | for (int i = 0; i <= 0xFF; i++) 326 | { 327 | sw_write(tmp, (uint8_t)i); 328 | } 329 | 330 | // vTaskDelay(500 / portTICK_RATE_MS); 331 | // sw_write(tmp, (uint8_t)0x00); 332 | // vTaskDelay(100 / portTICK_RATE_MS); 333 | // sw_write(tmp, (uint8_t)0x01); 334 | // vTaskDelay(100 / portTICK_RATE_MS); 335 | // sw_write(tmp, (uint8_t)0x02); 336 | // vTaskDelay(100 / portTICK_RATE_MS); 337 | // sw_write(tmp, (uint8_t)0x03); 338 | // vTaskDelay(100 / portTICK_RATE_MS); 339 | while (true) 340 | { 341 | 342 | vTaskDelay(1000 / portTICK_RATE_MS); 343 | puts("check recvd data"); 344 | int len = sw_any(tmp); 345 | 346 | if (len > 0) 347 | { 348 | for (size_t i = 0; i < len; i++) 349 | { 350 | uint8_t data = sw_read(tmp); 351 | sw_write(tmp, (uint8_t)data); 352 | printf("%02X ", data); 353 | } 354 | 355 | printf("\nrecv sw_any %02u %02u %02u \n", sw_any(tmp), tmp->inPos, tmp->outPos); 356 | 357 | } 358 | 359 | } 360 | 361 | } 362 | 363 | sw_del(tmp); 364 | } 365 | --------------------------------------------------------------------------------