├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── driver
├── Makefile
└── uart.c
├── include
├── driver
│ ├── uart.h
│ └── uart_register.h
└── user_config.h
├── modules
├── Makefile
├── config.c
├── include
│ ├── config.h
│ └── wifi.h
└── wifi.c
├── mqtt
├── Makefile
├── include
│ ├── debug.h
│ ├── mqtt.h
│ ├── mqtt_msg.h
│ ├── proto.h
│ ├── queue.h
│ ├── ringbuf.h
│ ├── typedef.h
│ └── utils.h
├── mqtt.c
├── mqtt_msg.c
├── proto.c
├── queue.c
├── ringbuf.c
└── utils.c
├── roomba
├── mqtt_commands.h
├── roomba.c
├── roomba.h
└── roomba_opcodes.h
├── tools
├── .gitattributes
├── esptool.py
└── makefile.sh
└── user
├── Makefile
└── user_main.c
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.ko
4 | *.obj
5 | *.elf
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Libraries
12 | *.lib
13 | *.a
14 | *.la
15 | *.lo
16 |
17 | # Shared objects (inc. Windows DLLs)
18 | *.dll
19 | *.so
20 | *.so.*
21 | *.dylib
22 |
23 | # Executables
24 | *.exe
25 | *.out
26 | *.app
27 | *.i*86
28 | *.x86_64
29 | *.hex
30 |
31 | # Debug files
32 | *.dSYM/
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Changelog
2 | # Changed the variables to include the header file directory
3 | # Added global var for the XTENSA tool root
4 | #
5 | # This make file still needs some work.
6 | #
7 | #
8 | # Output directors to store intermediate compiled files
9 | # relative to the project directory
10 | BUILD_BASE = build
11 | FW_BASE = firmware
12 | ESPTOOL = tools/esptool.py
13 |
14 |
15 | # name for the target project
16 | TARGET = app
17 |
18 | # linker script used for the above linkier step
19 | LD_SCRIPT = eagle.app.v6.ld
20 |
21 | # we create two different files for uploading into the flash
22 | # these are the names and options to generate them
23 | FW_1 = 0x00000
24 | FW_2 = 0x40000
25 |
26 | FLAVOR ?= release
27 |
28 |
29 | #############################################################
30 | # Select compile
31 | #
32 | ifeq ($(OS),Windows_NT)
33 | # WIN32
34 | # We are under windows.
35 | ifeq ($(XTENSA_CORE),lx106)
36 | # It is xcc
37 | AR = xt-ar
38 | CC = xt-xcc
39 | LD = xt-xcc
40 | NM = xt-nm
41 | CPP = xt-cpp
42 | OBJCOPY = xt-objcopy
43 | #MAKE = xt-make
44 | CCFLAGS += -Os --rename-section .text=.irom0.text --rename-section .literal=.irom0.literal
45 | else
46 | # It is gcc, may be cygwin
47 | # Can we use -fdata-sections?
48 | CCFLAGS += -Os -ffunction-sections -fno-jump-tables
49 | AR = xtensa-lx106-elf-ar
50 | CC = xtensa-lx106-elf-gcc
51 | LD = xtensa-lx106-elf-gcc
52 | NM = xtensa-lx106-elf-nm
53 | CPP = xtensa-lx106-elf-cpp
54 | OBJCOPY = xtensa-lx106-elf-objcopy
55 | endif
56 | ESPPORT ?= com1
57 | SDK_BASE ?= c:/Espressif/ESP8266_SDK
58 | ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
59 | # ->AMD64
60 | endif
61 | ifeq ($(PROCESSOR_ARCHITECTURE),x86)
62 | # ->IA32
63 | endif
64 | else
65 | # We are under other system, may be Linux. Assume using gcc.
66 | # Can we use -fdata-sections?
67 | ESPPORT ?= /dev/ttyUSB0
68 | SDK_BASE ?= /opt/esp-open-sdk/sdk
69 |
70 | CCFLAGS += -Os -ffunction-sections -fno-jump-tables
71 | AR = xtensa-lx106-elf-ar
72 | CC = xtensa-lx106-elf-gcc
73 | LD = xtensa-lx106-elf-gcc
74 | NM = xtensa-lx106-elf-nm
75 | CPP = xtensa-lx106-elf-cpp
76 | OBJCOPY = xtensa-lx106-elf-objcopy
77 | UNAME_S := $(shell uname -s)
78 |
79 | ifeq ($(UNAME_S),Linux)
80 | # LINUX
81 | endif
82 | ifeq ($(UNAME_S),Darwin)
83 | # OSX
84 | endif
85 | UNAME_P := $(shell uname -p)
86 | ifeq ($(UNAME_P),x86_64)
87 | # ->AMD64
88 | endif
89 | ifneq ($(filter %86,$(UNAME_P)),)
90 | # ->IA32
91 | endif
92 | ifneq ($(filter arm%,$(UNAME_P)),)
93 | # ->ARM
94 | endif
95 | endif
96 | #############################################################
97 |
98 |
99 | # which modules (subdirectories) of the project to include in compiling
100 | MODULES = driver mqtt user modules roomba
101 | EXTRA_INCDIR = include $(SDK_BASE)/include include/driver
102 |
103 | # libraries used in this project, mainly provided by the SDK
104 | LIBS = c gcc hal phy pp net80211 lwip wpa main ssl
105 |
106 | # compiler flags using during compilation of source files
107 | CFLAGS = -Os -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH
108 |
109 | # linker flags used to generate the main object file
110 | LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
111 |
112 | ifeq ($(FLAVOR),debug)
113 | CFLAGS += -g -O0
114 | LDFLAGS += -g -O0
115 | endif
116 |
117 | ifeq ($(FLAVOR),release)
118 | CFLAGS += -g -O2
119 | LDFLAGS += -g -O2
120 | endif
121 |
122 |
123 |
124 | # various paths from the SDK used in this project
125 | SDK_LIBDIR = lib
126 | SDK_LDDIR = ld
127 | SDK_INCDIR = include include/json
128 |
129 | ####
130 | #### no user configurable options below here
131 | ####
132 | FW_TOOL ?= $(ESPTOOL)
133 | SRC_DIR := $(MODULES)
134 | BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES))
135 |
136 | SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR))
137 | SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR))
138 |
139 | SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
140 | OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC))
141 | LIBS := $(addprefix -l,$(LIBS))
142 | APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a)
143 | TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out)
144 |
145 | LD_SCRIPT := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT))
146 |
147 | INCDIR := $(addprefix -I,$(SRC_DIR))
148 | EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR))
149 | MODULE_INCDIR := $(addsuffix /include,$(INCDIR))
150 |
151 | FW_FILE_1 := $(addprefix $(FW_BASE)/,$(FW_1).bin)
152 | FW_FILE_2 := $(addprefix $(FW_BASE)/,$(FW_2).bin)
153 | BLANKER := $(SDK_BASE)/bin/blank.bin
154 |
155 | V ?= $(VERBOSE)
156 | ifeq ("$(V)","1")
157 | Q :=
158 | vecho := @true
159 | else
160 | Q := @
161 | vecho := @echo
162 | endif
163 |
164 | vpath %.c $(SRC_DIR)
165 |
166 | define compile-objects
167 | $1/%.o: %.c
168 | $(vecho) "CC $$<"
169 | $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@
170 | endef
171 |
172 | .PHONY: all checkdirs clean
173 |
174 | all: checkdirs $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2)
175 |
176 | $(FW_FILE_1): $(TARGET_OUT)
177 | $(vecho) "FW $@"
178 | $(ESPTOOL) elf2image $< -o $(FW_BASE)/
179 |
180 | $(FW_FILE_2): $(TARGET_OUT)
181 | $(vecho) "FW $@"
182 | $(ESPTOOL) elf2image $< -o $(FW_BASE)/
183 |
184 | $(TARGET_OUT): $(APP_AR)
185 | $(vecho) "LD $@"
186 | $(Q) $(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@
187 |
188 | $(APP_AR): $(OBJ)
189 | $(vecho) "AR $@"
190 | $(Q) $(AR) cru $@ $^
191 |
192 | checkdirs: $(BUILD_DIR) $(FW_BASE)
193 |
194 | $(BUILD_DIR):
195 | $(Q) mkdir -p $@
196 |
197 | firmware:
198 | $(Q) mkdir -p $@
199 |
200 | flash: $(FW_FILE_1) $(FW_FILE_2)
201 | $(ESPTOOL) -p $(ESPPORT) write_flash $(FW_1) $(FW_FILE_1) 0x3C000 $(BLANKER) $(FW_2) $(FW_FILE_2)
202 |
203 | test: flash
204 | screen $(ESPPORT) 115200
205 |
206 | rebuild: clean all
207 |
208 | clean:
209 | $(Q) rm -f $(APP_AR)
210 | $(Q) rm -f $(TARGET_OUT)
211 | $(Q) rm -rf $(BUILD_DIR)
212 | $(Q) rm -rf $(BUILD_BASE)
213 | $(Q) rm -f $(FW_FILE_1)
214 | $(Q) rm -f $(FW_FILE_2)
215 | $(Q) rm -rf $(FW_BASE)
216 |
217 | $(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))
218 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **esp_mqtt**
2 | ==========
3 | 
4 |
5 | This is MQTT client library for ESP8266, port from: [MQTT client library for Contiki](https://github.com/esar/contiki-mqtt) (thanks)
6 |
7 |
8 |
9 | **Features:**
10 |
11 | * Support subscribing, publishing, authentication, will messages, keep alive pings and all 3 QoS levels (it should be a fully functional client).
12 | * Support multiple connection (to multiple hosts).
13 | * Support SSL connection (max 1024 bit key size)
14 | * Easy to setup and use
15 |
16 | **Compile:**
17 |
18 | Make sure to add PYTHON PATH and compile PATH to Eclipse environment variable if using Eclipse
19 |
20 | for Windows:
21 |
22 | ```bash
23 | git clone https://github.com/tuanpmt/esp_mqtt
24 | cd esp_mqtt
25 | #clean
26 | mingw32-make clean
27 | #make
28 | mingw32-make SDK_BASE="c:/Espressif/ESP8266_SDK" FLAVOR="release" all
29 | #flash
30 | mingw32-make ESPPORT="COM1" flash
31 | ```
32 |
33 | for Mac or Linux:
34 |
35 | ```bash
36 | git clone https://github.com/tuanpmt/esp_mqtt
37 | cd esp_mqtt
38 | #clean
39 | make clean
40 | #make
41 | make SDK_BASE="/opt/Espressif/ESP8266_SDK" FLAVOR="release" all
42 | #flash
43 | make ESPPORT="/dev/ttyUSB0" flash
44 | ```
45 |
46 | **Usage**
47 | ```c
48 | #include "ets_sys.h"
49 | #include "driver/uart.h"
50 | #include "osapi.h"
51 | #include "mqtt.h"
52 | #include "wifi.h"
53 | #include "config.h"
54 | #include "debug.h"
55 | #include "gpio.h"
56 | #include "user_interface.h"
57 | #include "mem.h"
58 |
59 | MQTT_Client mqttClient;
60 |
61 | void wifiConnectCb(uint8_t status)
62 | {
63 | if(status == STATION_GOT_IP){
64 | MQTT_Connect(&mqttClient);
65 | } else {
66 | MQTT_Disconnect(&mqttClient);
67 | }
68 | }
69 | void mqttConnectedCb(uint32_t *args)
70 | {
71 | MQTT_Client* client = (MQTT_Client*)args;
72 | INFO("MQTT: Connected\r\n");
73 | MQTT_Subscribe(client, "/mqtt/topic/0", 0);
74 | MQTT_Subscribe(client, "/mqtt/topic/1", 1);
75 | MQTT_Subscribe(client, "/mqtt/topic/2", 2);
76 |
77 | MQTT_Publish(client, "/mqtt/topic/0", "hello0", 6, 0, 0);
78 | MQTT_Publish(client, "/mqtt/topic/1", "hello1", 6, 1, 0);
79 | MQTT_Publish(client, "/mqtt/topic/2", "hello2", 6, 2, 0);
80 |
81 | }
82 |
83 | void mqttDisconnectedCb(uint32_t *args)
84 | {
85 | MQTT_Client* client = (MQTT_Client*)args;
86 | INFO("MQTT: Disconnected\r\n");
87 | }
88 |
89 | void mqttPublishedCb(uint32_t *args)
90 | {
91 | MQTT_Client* client = (MQTT_Client*)args;
92 | INFO("MQTT: Published\r\n");
93 | }
94 |
95 | void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)
96 | {
97 | char *topicBuf = (char*)os_zalloc(topic_len+1),
98 | *dataBuf = (char*)os_zalloc(data_len+1);
99 |
100 | MQTT_Client* client = (MQTT_Client*)args;
101 |
102 | os_memcpy(topicBuf, topic, topic_len);
103 | topicBuf[topic_len] = 0;
104 |
105 | os_memcpy(dataBuf, data, data_len);
106 | dataBuf[data_len] = 0;
107 |
108 | INFO("Receive topic: %s, data: %s \r\n", topicBuf, dataBuf);
109 | os_free(topicBuf);
110 | os_free(dataBuf);
111 | }
112 |
113 |
114 | void user_init(void)
115 | {
116 | uart_init(BIT_RATE_115200, BIT_RATE_115200);
117 | os_delay_us(1000000);
118 |
119 | CFG_Load();
120 |
121 | MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.security);
122 | //MQTT_InitConnection(&mqttClient, "192.168.11.122", 1880, 0);
123 |
124 | MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1);
125 | //MQTT_InitClient(&mqttClient, "client_id", "user", "pass", 120, 1);
126 |
127 | MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
128 | MQTT_OnConnected(&mqttClient, mqttConnectedCb);
129 | MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
130 | MQTT_OnPublished(&mqttClient, mqttPublishedCb);
131 | MQTT_OnData(&mqttClient, mqttDataCb);
132 |
133 | WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb);
134 |
135 | INFO("\r\nSystem started ...\r\n");
136 | }
137 |
138 | ```
139 |
140 | **Publish message and Subscribe**
141 |
142 | ```c
143 | /* TRUE if success */
144 | BOOL MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos);
145 |
146 | BOOL MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain);
147 |
148 | ```
149 |
150 | **Already support LWT: (Last Will and Testament)**
151 |
152 | ```c
153 |
154 | /* Broker will publish a message with qos = 0, retain = 0, data = "offline" to topic "/lwt" if client don't send keepalive packet */
155 | MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
156 |
157 | ```
158 |
159 | #Default configuration
160 |
161 | See: **include/user_config.h**
162 |
163 | If you want to load new default configurations, just change the value of CFG_HOLDER in **include/user_config.h**
164 |
165 | **Define protocol name in include/user_config.h**
166 |
167 | ```c
168 | #define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/
169 | //PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/
170 | ```
171 |
172 | In the Makefile, it will erase section hold the user configuration at 0x3C000
173 |
174 | ```bash
175 | flash: firmware/0x00000.bin firmware/0x40000.bin
176 | $(PYTHON) $(ESPTOOL) -p $(ESPPORT) write_flash 0x00000 firmware/0x00000.bin 0x3C000 $(BLANKER) 0x40000 firmware/0x40000.bin
177 | ```
178 | The BLANKER is the blank.bin file you find in your SDKs bin folder.
179 |
180 | **Create SSL Self sign**
181 |
182 | ```
183 | openssl req -x509 -newkey rsa:1024 -keyout key.pem -out cert.pem -days XXX
184 | ```
185 |
186 | **SSL Mqtt broker for test**
187 |
188 | ```javascript
189 | var mosca = require('mosca')
190 | var SECURE_KEY = __dirname + '/key.pem';
191 | var SECURE_CERT = __dirname + '/cert.pem';
192 | var ascoltatore = {
193 | //using ascoltatore
194 | type: 'mongo',
195 | url: 'mongodb://localhost:27017/mqtt',
196 | pubsubCollection: 'ascoltatori',
197 | mongo: {}
198 | };
199 |
200 | var moscaSettings = {
201 | port: 1880,
202 | stats: false,
203 | backend: ascoltatore,
204 | persistence: {
205 | factory: mosca.persistence.Mongo,
206 | url: 'mongodb://localhost:27017/mqtt'
207 | },
208 | secure : {
209 | keyPath: SECURE_KEY,
210 | certPath: SECURE_CERT,
211 | port: 1883
212 | }
213 | };
214 |
215 | var server = new mosca.Server(moscaSettings);
216 | server.on('ready', setup);
217 |
218 | server.on('clientConnected', function(client) {
219 | console.log('client connected', client.id);
220 | });
221 |
222 | // fired when a message is received
223 | server.on('published', function(packet, client) {
224 | console.log('Published', packet.payload);
225 | });
226 |
227 | // fired when the mqtt server is ready
228 | function setup() {
229 | console.log('Mosca server is up and running')
230 | }
231 | ```
232 |
233 | **Example projects using esp_mqtt:**
234 | - [https://github.com/eadf/esp_mqtt_lcd](https://github.com/eadf/esp_mqtt_lcd)
235 |
236 | **Limited:**
237 | - Not fully supported retransmit for QoS1 and QoS2
238 |
239 | **Status:** *Pre release.*
240 |
241 | [https://github.com/tuanpmt/esp_mqtt/releases](https://github.com/tuanpmt/esp_mqtt/releases)
242 |
243 | [MQTT Broker for test](https://github.com/mcollina/mosca)
244 |
245 | [MQTT Client for test](https://chrome.google.com/webstore/detail/mqttlens/hemojaaeigabkbcookmlgmdigohjobjm?hl=en)
246 |
247 | **Contributing:**
248 |
249 | ***Feel free to contribute to the project in any way you like!***
250 |
251 | **Requried:**
252 |
253 | SDK esp_iot_sdk_v0.9.4_14_12_19 or higher
254 |
255 | **Authors:**
256 | [Tuan PM](https://twitter.com/TuanPMT)
257 |
258 | **Donations**
259 |
260 | Invite me to a coffee
261 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JR9RVLFC4GE6J)
262 |
263 |
264 | **LICENSE - "MIT License"**
265 |
266 | Copyright (c) 2014-2015 Tuan PM, https://twitter.com/TuanPMT
267 |
268 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
269 |
270 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
271 |
272 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
273 |
--------------------------------------------------------------------------------
/driver/Makefile:
--------------------------------------------------------------------------------
1 |
2 | #############################################################
3 | # Required variables for each makefile
4 | # Discard this section from all parent makefiles
5 | # Expected variables (with automatic defaults):
6 | # CSRCS (all "C" files in the dir)
7 | # SUBDIRS (all subdirs with a Makefile)
8 | # GEN_LIBS - list of libs to be generated ()
9 | # GEN_IMAGES - list of images to be generated ()
10 | # COMPONENTS_xxx - a list of libs/objs in the form
11 | # subdir/lib to be extracted and rolled up into
12 | # a generated lib/image xxx.a ()
13 | #
14 | ifndef PDIR
15 | GEN_LIBS = libdriver.a
16 | endif
17 |
18 |
19 | #############################################################
20 | # Configuration i.e. compile options etc.
21 | # Target specific stuff (defines etc.) goes in here!
22 | # Generally values applying to a tree are captured in the
23 | # makefile at its root level - these are then overridden
24 | # for a subtree within the makefile rooted therein
25 | #
26 | #DEFINES +=
27 |
28 | #############################################################
29 | # Recursion Magic - Don't touch this!!
30 | #
31 | # Each subtree potentially has an include directory
32 | # corresponding to the common APIs applicable to modules
33 | # rooted at that subtree. Accordingly, the INCLUDE PATH
34 | # of a module can only contain the include directories up
35 | # its parent path, and not its siblings
36 | #
37 | # Required for each makefile to inherit from the parent
38 | #
39 |
40 | INCLUDES := $(INCLUDES) -I $(PDIR)include
41 | INCLUDES += -I ./
42 | PDIR := ../$(PDIR)
43 | sinclude $(PDIR)Makefile
44 |
45 |
--------------------------------------------------------------------------------
/driver/uart.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2013-2014 Espressif Systems (Wuxi)
3 | *
4 | * FileName: uart.c
5 | *
6 | * Description: Two UART mode configration and interrupt handler.
7 | * Check your hardware connection while use this mode.
8 | *
9 | * Modification history:
10 | * 2014/3/12, v1.0 create this file.
11 | *******************************************************************************/
12 | #include "ets_sys.h"
13 | #include "osapi.h"
14 | #include "driver/uart.h"
15 | #include "osapi.h"
16 | #include "driver/uart_register.h"
17 | //#include "ssc.h"
18 |
19 |
20 | // UartDev is defined and initialized in rom code.
21 | extern UartDevice UartDev;
22 | //extern os_event_t at_recvTaskQueue[at_recvTaskQueueLen];
23 |
24 | LOCAL void uart0_rx_intr_handler(void *para);
25 |
26 | /******************************************************************************
27 | * FunctionName : uart_config
28 | * Description : Internal used function
29 | * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
30 | * UART1 just used for debug output
31 | * Parameters : uart_no, use UART0 or UART1 defined ahead
32 | * Returns : NONE
33 | *******************************************************************************/
34 | LOCAL void ICACHE_FLASH_ATTR
35 | uart_config(uint8 uart_no)
36 | {
37 | if (uart_no == UART1)
38 | {
39 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
40 | }
41 | else
42 | {
43 | /* rcv_buff size if 0x100 */
44 | ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
45 | PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
46 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
47 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
48 | }
49 |
50 | uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
51 |
52 | WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
53 | | UartDev.parity
54 | | (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
55 | | (UartDev.data_bits << UART_BIT_NUM_S));
56 |
57 | //clear rx and tx fifo,not ready
58 | SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
59 | CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
60 |
61 | //set rx fifo trigger
62 | // WRITE_PERI_REG(UART_CONF1(uart_no),
63 | // ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
64 | // ((96 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) |
65 | // UART_RX_FLOW_EN);
66 | if (uart_no == UART0)
67 | {
68 | //set rx fifo trigger
69 | WRITE_PERI_REG(UART_CONF1(uart_no),
70 | ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
71 | ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
72 | UART_RX_FLOW_EN |
73 | (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
74 | UART_RX_TOUT_EN);
75 | SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
76 | UART_FRM_ERR_INT_ENA);
77 | }
78 | else
79 | {
80 | WRITE_PERI_REG(UART_CONF1(uart_no),
81 | ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
82 | }
83 |
84 | //clear all interrupt
85 | WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
86 | //enable rx_interrupt
87 | SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
88 | }
89 |
90 | /******************************************************************************
91 | * FunctionName : uart1_tx_one_char
92 | * Description : Internal used function
93 | * Use uart1 interface to transfer one char
94 | * Parameters : uint8 TxChar - character to tx
95 | * Returns : OK
96 | *******************************************************************************/
97 | LOCAL STATUS
98 | uart_tx_one_char(uint8 uart, uint8 TxChar)
99 | {
100 | while (true)
101 | {
102 | uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
104 | break;
105 | }
106 | }
107 |
108 | WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
109 | return OK;
110 | }
111 |
112 | /******************************************************************************
113 | * FunctionName : uart1_write_char
114 | * Description : Internal used function
115 | * Do some special deal while tx char is '\r' or '\n'
116 | * Parameters : char c - character to tx
117 | * Returns : NONE
118 | *******************************************************************************/
119 | void ICACHE_FLASH_ATTR
120 | uart1_write_char(char c)
121 | {
122 | if (c == '\n')
123 | {
124 | uart_tx_one_char(UART1, '\r');
125 | uart_tx_one_char(UART1, '\n');
126 | }
127 | else if (c == '\r')
128 | {
129 | }
130 | else
131 | {
132 | uart_tx_one_char(UART1, c);
133 | }
134 | }
135 |
136 | void ICACHE_FLASH_ATTR
137 | uart0_write_char(char c)
138 | {
139 | if (c == '\n')
140 | {
141 | uart_tx_one_char(UART0, '\r');
142 | uart_tx_one_char(UART0, '\n');
143 | }
144 | else if (c == '\r')
145 | {
146 | }
147 | else
148 | {
149 | uart_tx_one_char(UART0, c);
150 | }
151 | }
152 | /******************************************************************************
153 | * FunctionName : uart0_tx_buffer
154 | * Description : use uart0 to transfer buffer
155 | * Parameters : uint8 *buf - point to send buffer
156 | * uint16 len - buffer len
157 | * Returns :
158 | *******************************************************************************/
159 | void ICACHE_FLASH_ATTR
160 | uart0_tx_buffer(uint8 *buf, uint16 len)
161 | {
162 | uint16 i;
163 |
164 | for (i = 0; i < len; i++)
165 | {
166 | uart_tx_one_char(UART0, buf[i]);
167 | }
168 | }
169 |
170 | /******************************************************************************
171 | * FunctionName : uart0_sendStr
172 | * Description : use uart0 to transfer buffer
173 | * Parameters : uint8 *buf - point to send buffer
174 | * uint16 len - buffer len
175 | * Returns :
176 | *******************************************************************************/
177 | void ICACHE_FLASH_ATTR
178 | uart0_sendStr(const char *str)
179 | {
180 | while(*str)
181 | {
182 | uart_tx_one_char(UART0, *str++);
183 | }
184 | }
185 |
186 | /******************************************************************************
187 | * FunctionName : uart0_rx_intr_handler
188 | * Description : Internal used function
189 | * UART0 interrupt handler, add self handle code inside
190 | * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
191 | * Returns : NONE
192 | *******************************************************************************/
193 | //extern void at_recvTask(void);
194 |
195 | LOCAL void
196 | uart0_rx_intr_handler(void *para)
197 | {
198 | /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
199 | * uart1 and uart0 respectively
200 | */
201 | // RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para;
202 | uint8 RcvChar;
203 | uint8 uart_no = UART0;//UartDev.buff_uart_no;
204 |
205 | // if (UART_RXFIFO_FULL_INT_ST != (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
206 | // {
207 | // return;
208 | // }
209 | // if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
210 | // {
211 | //// at_recvTask();
212 | // RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
213 | // system_os_post(at_recvTaskPrio, NULL, RcvChar);
214 | // WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
215 | // }
216 | if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST))
217 | {
218 | os_printf("FRM_ERR\r\n");
219 | WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
220 | }
221 |
222 | if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
223 | {
224 | // os_printf("fifo full\r\n");
225 | ETS_UART_INTR_DISABLE();/////////
226 |
227 | //system_os_post(at_recvTaskPrio, 0, 0);
228 |
229 | // WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
230 | // while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
231 | // {
232 | //// at_recvTask();
233 | // RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
234 | // system_os_post(at_recvTaskPrio, NULL, RcvChar);
235 | // }
236 | }
237 | else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST))
238 | {
239 | ETS_UART_INTR_DISABLE();/////////
240 |
241 | //system_os_post(at_recvTaskPrio, 0, 0);
242 |
243 | // WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_TOUT_INT_CLR);
244 | //// os_printf("rx time over\r\n");
245 | // while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
246 | // {
247 | //// os_printf("process recv\r\n");
248 | //// at_recvTask();
249 | // RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
250 | // system_os_post(at_recvTaskPrio, NULL, RcvChar);
251 | // }
252 | }
253 |
254 | // WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
255 |
256 | // if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
257 | // {
258 | // RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
259 | // at_recvTask();
260 | // *(pRxBuff->pWritePos) = RcvChar;
261 |
262 | // system_os_post(at_recvTaskPrio, NULL, RcvChar);
263 |
264 | // //insert here for get one command line from uart
265 | // if (RcvChar == '\r')
266 | // {
267 | // pRxBuff->BuffState = WRITE_OVER;
268 | // }
269 | //
270 | // pRxBuff->pWritePos++;
271 | //
272 | // if (pRxBuff->pWritePos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE))
273 | // {
274 | // // overflow ...we may need more error handle here.
275 | // pRxBuff->pWritePos = pRxBuff->pRcvMsgBuff ;
276 | // }
277 | // }
278 | }
279 |
280 | /******************************************************************************
281 | * FunctionName : uart_init
282 | * Description : user interface for init uart
283 | * Parameters : UartBautRate uart0_br - uart0 bautrate
284 | * UartBautRate uart1_br - uart1 bautrate
285 | * Returns : NONE
286 | *******************************************************************************/
287 | void ICACHE_FLASH_ATTR
288 | uart_init(UartBautRate uart0_br, UartBautRate uart1_br)
289 | {
290 | // rom use 74880 baut_rate, here reinitialize
291 | UartDev.baut_rate = uart0_br;
292 | uart_config(UART0);
293 | UartDev.baut_rate = uart1_br;
294 | uart_config(UART1);
295 | ETS_UART_INTR_ENABLE();
296 |
297 | // install uart1 putc callback
298 | os_install_putc1((void *)uart0_write_char);
299 | }
300 |
301 | void ICACHE_FLASH_ATTR
302 | uart_reattach()
303 | {
304 | uart_init(BIT_RATE_74880, BIT_RATE_74880);
305 | // ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff));
306 | // ETS_UART_INTR_ENABLE();
307 | }
308 |
--------------------------------------------------------------------------------
/include/driver/uart.h:
--------------------------------------------------------------------------------
1 | #ifndef UART_APP_H
2 | #define UART_APP_H
3 |
4 | #include "uart_register.h"
5 | #include "eagle_soc.h"
6 | #include "c_types.h"
7 |
8 | #define RX_BUFF_SIZE 256
9 | #define TX_BUFF_SIZE 100
10 | #define UART0 0
11 | #define UART1 1
12 |
13 | typedef enum {
14 | FIVE_BITS = 0x0,
15 | SIX_BITS = 0x1,
16 | SEVEN_BITS = 0x2,
17 | EIGHT_BITS = 0x3
18 | } UartBitsNum4Char;
19 |
20 | typedef enum {
21 | ONE_STOP_BIT = 0,
22 | ONE_HALF_STOP_BIT = BIT2,
23 | TWO_STOP_BIT = BIT2
24 | } UartStopBitsNum;
25 |
26 | typedef enum {
27 | NONE_BITS = 0,
28 | ODD_BITS = 0,
29 | EVEN_BITS = BIT4
30 | } UartParityMode;
31 |
32 | typedef enum {
33 | STICK_PARITY_DIS = 0,
34 | STICK_PARITY_EN = BIT3 | BIT5
35 | } UartExistParity;
36 |
37 | typedef enum {
38 | BIT_RATE_9600 = 9600,
39 | BIT_RATE_19200 = 19200,
40 | BIT_RATE_38400 = 38400,
41 | BIT_RATE_57600 = 57600,
42 | BIT_RATE_74880 = 74880,
43 | BIT_RATE_115200 = 115200,
44 | BIT_RATE_230400 = 230400,
45 | BIT_RATE_256000 = 256000,
46 | BIT_RATE_460800 = 460800,
47 | BIT_RATE_921600 = 921600
48 | } UartBautRate;
49 |
50 | typedef enum {
51 | NONE_CTRL,
52 | HARDWARE_CTRL,
53 | XON_XOFF_CTRL
54 | } UartFlowCtrl;
55 |
56 | typedef enum {
57 | EMPTY,
58 | UNDER_WRITE,
59 | WRITE_OVER
60 | } RcvMsgBuffState;
61 |
62 | typedef struct {
63 | uint32 RcvBuffSize;
64 | uint8 *pRcvMsgBuff;
65 | uint8 *pWritePos;
66 | uint8 *pReadPos;
67 | uint8 TrigLvl; //JLU: may need to pad
68 | RcvMsgBuffState BuffState;
69 | } RcvMsgBuff;
70 |
71 | typedef struct {
72 | uint32 TrxBuffSize;
73 | uint8 *pTrxBuff;
74 | } TrxMsgBuff;
75 |
76 | typedef enum {
77 | BAUD_RATE_DET,
78 | WAIT_SYNC_FRM,
79 | SRCH_MSG_HEAD,
80 | RCV_MSG_BODY,
81 | RCV_ESC_CHAR,
82 | } RcvMsgState;
83 |
84 | typedef struct {
85 | UartBautRate baut_rate;
86 | UartBitsNum4Char data_bits;
87 | UartExistParity exist_parity;
88 | UartParityMode parity; // chip size in byte
89 | UartStopBitsNum stop_bits;
90 | UartFlowCtrl flow_ctrl;
91 | RcvMsgBuff rcv_buff;
92 | TrxMsgBuff trx_buff;
93 | RcvMsgState rcv_state;
94 | int received;
95 | int buff_uart_no; //indicate which uart use tx/rx buffer
96 | } UartDevice;
97 |
98 | void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
99 | void uart0_sendStr(const char *str);
100 | #endif
101 |
102 |
--------------------------------------------------------------------------------
/include/driver/uart_register.h:
--------------------------------------------------------------------------------
1 | //Generated at 2012-07-03 18:44:06
2 | /*
3 | * Copyright (c) 2010 - 2011 Espressif System
4 | *
5 | */
6 |
7 | #ifndef UART_REGISTER_H_INCLUDED
8 | #define UART_REGISTER_H_INCLUDED
9 | #define REG_UART_BASE( i ) (0x60000000+(i)*0xf00)
10 | //version value:32'h062000
11 |
12 | #define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0)
13 | #define UART_RXFIFO_RD_BYTE 0x000000FF
14 | #define UART_RXFIFO_RD_BYTE_S 0
15 |
16 | #define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4)
17 | #define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
18 | #define UART_BRK_DET_INT_RAW (BIT(7))
19 | #define UART_CTS_CHG_INT_RAW (BIT(6))
20 | #define UART_DSR_CHG_INT_RAW (BIT(5))
21 | #define UART_RXFIFO_OVF_INT_RAW (BIT(4))
22 | #define UART_FRM_ERR_INT_RAW (BIT(3))
23 | #define UART_PARITY_ERR_INT_RAW (BIT(2))
24 | #define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
25 | #define UART_RXFIFO_FULL_INT_RAW (BIT(0))
26 |
27 | #define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8)
28 | #define UART_RXFIFO_TOUT_INT_ST (BIT(8))
29 | #define UART_BRK_DET_INT_ST (BIT(7))
30 | #define UART_CTS_CHG_INT_ST (BIT(6))
31 | #define UART_DSR_CHG_INT_ST (BIT(5))
32 | #define UART_RXFIFO_OVF_INT_ST (BIT(4))
33 | #define UART_FRM_ERR_INT_ST (BIT(3))
34 | #define UART_PARITY_ERR_INT_ST (BIT(2))
35 | #define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
36 | #define UART_RXFIFO_FULL_INT_ST (BIT(0))
37 |
38 | #define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC)
39 | #define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
40 | #define UART_BRK_DET_INT_ENA (BIT(7))
41 | #define UART_CTS_CHG_INT_ENA (BIT(6))
42 | #define UART_DSR_CHG_INT_ENA (BIT(5))
43 | #define UART_RXFIFO_OVF_INT_ENA (BIT(4))
44 | #define UART_FRM_ERR_INT_ENA (BIT(3))
45 | #define UART_PARITY_ERR_INT_ENA (BIT(2))
46 | #define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
47 | #define UART_RXFIFO_FULL_INT_ENA (BIT(0))
48 |
49 | #define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10)
50 | #define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
51 | #define UART_BRK_DET_INT_CLR (BIT(7))
52 | #define UART_CTS_CHG_INT_CLR (BIT(6))
53 | #define UART_DSR_CHG_INT_CLR (BIT(5))
54 | #define UART_RXFIFO_OVF_INT_CLR (BIT(4))
55 | #define UART_FRM_ERR_INT_CLR (BIT(3))
56 | #define UART_PARITY_ERR_INT_CLR (BIT(2))
57 | #define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
58 | #define UART_RXFIFO_FULL_INT_CLR (BIT(0))
59 |
60 | #define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14)
61 | #define UART_CLKDIV_CNT 0x000FFFFF
62 | #define UART_CLKDIV_S 0
63 |
64 | #define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18)
65 | #define UART_GLITCH_FILT 0x000000FF
66 | #define UART_GLITCH_FILT_S 8
67 | #define UART_AUTOBAUD_EN (BIT(0))
68 |
69 | #define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C)
70 | #define UART_TXD (BIT(31))
71 | #define UART_RTSN (BIT(30))
72 | #define UART_DTRN (BIT(29))
73 | #define UART_TXFIFO_CNT 0x000000FF
74 | #define UART_TXFIFO_CNT_S 16
75 | #define UART_RXD (BIT(15))
76 | #define UART_CTSN (BIT(14))
77 | #define UART_DSRN (BIT(13))
78 | #define UART_RXFIFO_CNT 0x000000FF
79 | #define UART_RXFIFO_CNT_S 0
80 |
81 | #define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20)
82 | #define UART_TXFIFO_RST (BIT(18))
83 | #define UART_RXFIFO_RST (BIT(17))
84 | #define UART_IRDA_EN (BIT(16))
85 | #define UART_TX_FLOW_EN (BIT(15))
86 | #define UART_LOOPBACK (BIT(14))
87 | #define UART_IRDA_RX_INV (BIT(13))
88 | #define UART_IRDA_TX_INV (BIT(12))
89 | #define UART_IRDA_WCTL (BIT(11))
90 | #define UART_IRDA_TX_EN (BIT(10))
91 | #define UART_IRDA_DPLX (BIT(9))
92 | #define UART_TXD_BRK (BIT(8))
93 | #define UART_SW_DTR (BIT(7))
94 | #define UART_SW_RTS (BIT(6))
95 | #define UART_STOP_BIT_NUM 0x00000003
96 | #define UART_STOP_BIT_NUM_S 4
97 | #define UART_BIT_NUM 0x00000003
98 | #define UART_BIT_NUM_S 2
99 | #define UART_PARITY_EN (BIT(1))
100 | #define UART_PARITY (BIT(0))
101 |
102 | #define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24)
103 | #define UART_RX_TOUT_EN (BIT(31))
104 | #define UART_RX_TOUT_THRHD 0x0000007F
105 | #define UART_RX_TOUT_THRHD_S 24
106 | #define UART_RX_FLOW_EN (BIT(23))
107 | #define UART_RX_FLOW_THRHD 0x0000007F
108 | #define UART_RX_FLOW_THRHD_S 16
109 | #define UART_TXFIFO_EMPTY_THRHD 0x0000007F
110 | #define UART_TXFIFO_EMPTY_THRHD_S 8
111 | #define UART_RXFIFO_FULL_THRHD 0x0000007F
112 | #define UART_RXFIFO_FULL_THRHD_S 0
113 |
114 | #define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28)
115 | #define UART_LOWPULSE_MIN_CNT 0x000FFFFF
116 | #define UART_LOWPULSE_MIN_CNT_S 0
117 |
118 | #define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C)
119 | #define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
120 | #define UART_HIGHPULSE_MIN_CNT_S 0
121 |
122 | #define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30)
123 | #define UART_PULSE_NUM_CNT 0x0003FF
124 | #define UART_PULSE_NUM_CNT_S 0
125 |
126 | #define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78)
127 | #define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C)
128 | #endif // UART_REGISTER_H_INCLUDED
129 |
--------------------------------------------------------------------------------
/include/user_config.h:
--------------------------------------------------------------------------------
1 | #ifndef _USER_CONFIG_H_
2 | #define _USER_CONFIG_H_
3 |
4 | #define CFG_HOLDER 0x00FF55A4 /* Change this value to load default configurations */
5 | #define CFG_LOCATION 0x3C /* Please don't change or if you know what you doing */
6 | #define CLIENT_SSL_ENABLE
7 |
8 | /*DEFAULT CONFIGURATIONS*/
9 |
10 | #define MQTT_HOST "192.168.1.10" //or "mqtt.yourdomain.com"
11 | #define MQTT_PORT 1883
12 | #define MQTT_BUF_SIZE 1024
13 | #define MQTT_KEEPALIVE 120 /*second*/
14 |
15 | #define MQTT_CLIENT_ID "DVES_%08X"
16 | #define MQTT_USER "DVES_USER"
17 | #define MQTT_PASS "DVES_PASS"
18 |
19 | #define STA_SSID "PiT"
20 | #define STA_PASS "geenidee"
21 | #define STA_TYPE AUTH_WPA2_PSK
22 |
23 | #define MQTT_RECONNECT_TIMEOUT 5 /*second*/
24 |
25 | #define DEFAULT_SECURITY 0
26 | #define QUEUE_BUFFER_SIZE 2048
27 |
28 | #define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/
29 | //PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/
30 | #endif
31 |
--------------------------------------------------------------------------------
/modules/Makefile:
--------------------------------------------------------------------------------
1 |
2 | #############################################################
3 | # Required variables for each makefile
4 | # Discard this section from all parent makefiles
5 | # Expected variables (with automatic defaults):
6 | # CSRCS (all "C" files in the dir)
7 | # SUBDIRS (all subdirs with a Makefile)
8 | # GEN_LIBS - list of libs to be generated ()
9 | # GEN_IMAGES - list of images to be generated ()
10 | # COMPONENTS_xxx - a list of libs/objs in the form
11 | # subdir/lib to be extracted and rolled up into
12 | # a generated lib/image xxx.a ()
13 | #
14 | ifndef PDIR
15 | GEN_LIBS = libmqtt.a
16 | endif
17 |
18 |
19 | #############################################################
20 | # Configuration i.e. compile options etc.
21 | # Target specific stuff (defines etc.) goes in here!
22 | # Generally values applying to a tree are captured in the
23 | # makefile at its root level - these are then overridden
24 | # for a subtree within the makefile rooted therein
25 | #
26 | #DEFINES +=
27 |
28 | #############################################################
29 | # Recursion Magic - Don't touch this!!
30 | #
31 | # Each subtree potentially has an include directory
32 | # corresponding to the common APIs applicable to modules
33 | # rooted at that subtree. Accordingly, the INCLUDE PATH
34 | # of a module can only contain the include directories up
35 | # its parent path, and not its siblings
36 | #
37 | # Required for each makefile to inherit from the parent
38 | #
39 |
40 | INCLUDES := $(INCLUDES) -I $(PDIR)include
41 | INCLUDES += -I ./
42 | PDIR := ../$(PDIR)
43 | sinclude $(PDIR)Makefile
44 |
45 |
--------------------------------------------------------------------------------
/modules/config.c:
--------------------------------------------------------------------------------
1 | /*
2 | /* config.c
3 | *
4 | * Copyright (c) 2014-2015, Tuan PM
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions are met:
9 | *
10 | * * Redistributions of source code must retain the above copyright notice,
11 | * this list of conditions and the following disclaimer.
12 | * * Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * * Neither the name of Redis nor the names of its contributors may be used
16 | * to endorse or promote products derived from this software without
17 | * specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 | #include "ets_sys.h"
32 | #include "os_type.h"
33 | #include "mem.h"
34 | #include "osapi.h"
35 | #include "user_interface.h"
36 |
37 | #include "mqtt.h"
38 | #include "config.h"
39 | #include "user_config.h"
40 | #include "debug.h"
41 |
42 | SYSCFG sysCfg;
43 | SAVE_FLAG saveFlag;
44 |
45 | void ICACHE_FLASH_ATTR
46 | CFG_Save()
47 | {
48 | spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
49 | (uint32 *)&saveFlag, sizeof(SAVE_FLAG));
50 |
51 | if (saveFlag.flag == 0) {
52 | spi_flash_erase_sector(CFG_LOCATION + 1);
53 | spi_flash_write((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE,
54 | (uint32 *)&sysCfg, sizeof(SYSCFG));
55 | saveFlag.flag = 1;
56 | spi_flash_erase_sector(CFG_LOCATION + 3);
57 | spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
58 | (uint32 *)&saveFlag, sizeof(SAVE_FLAG));
59 | } else {
60 | spi_flash_erase_sector(CFG_LOCATION + 0);
61 | spi_flash_write((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE,
62 | (uint32 *)&sysCfg, sizeof(SYSCFG));
63 | saveFlag.flag = 0;
64 | spi_flash_erase_sector(CFG_LOCATION + 3);
65 | spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
66 | (uint32 *)&saveFlag, sizeof(SAVE_FLAG));
67 | }
68 | }
69 |
70 | void ICACHE_FLASH_ATTR
71 | CFG_Load()
72 | {
73 |
74 | INFO("\r\nload ...\r\n");
75 | spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,
76 | (uint32 *)&saveFlag, sizeof(SAVE_FLAG));
77 | if (saveFlag.flag == 0) {
78 | spi_flash_read((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE,
79 | (uint32 *)&sysCfg, sizeof(SYSCFG));
80 | } else {
81 | spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE,
82 | (uint32 *)&sysCfg, sizeof(SYSCFG));
83 | }
84 | if(sysCfg.cfg_holder != CFG_HOLDER){
85 | os_memset(&sysCfg, 0x00, sizeof sysCfg);
86 |
87 |
88 | sysCfg.cfg_holder = CFG_HOLDER;
89 |
90 | os_sprintf(sysCfg.sta_ssid, "%s", STA_SSID);
91 | os_sprintf(sysCfg.sta_pwd, "%s", STA_PASS);
92 | sysCfg.sta_type = STA_TYPE;
93 |
94 | os_sprintf(sysCfg.device_id, MQTT_CLIENT_ID, system_get_chip_id());
95 | os_sprintf(sysCfg.mqtt_host, "%s", MQTT_HOST);
96 | sysCfg.mqtt_port = MQTT_PORT;
97 | os_sprintf(sysCfg.mqtt_user, "%s", MQTT_USER);
98 | os_sprintf(sysCfg.mqtt_pass, "%s", MQTT_PASS);
99 |
100 | sysCfg.security = DEFAULT_SECURITY; /* default non ssl */
101 |
102 | sysCfg.mqtt_keepalive = MQTT_KEEPALIVE;
103 |
104 | INFO(" default configuration\r\n");
105 |
106 | CFG_Save();
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/modules/include/config.h:
--------------------------------------------------------------------------------
1 | /* config.h
2 | *
3 | * Copyright (c) 2014-2015, Tuan PM
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | #ifndef USER_CONFIG_H_
32 | #define USER_CONFIG_H_
33 | #include "os_type.h"
34 | #include "user_config.h"
35 | typedef struct{
36 | uint32_t cfg_holder;
37 | uint8_t device_id[16];
38 |
39 | uint8_t sta_ssid[64];
40 | uint8_t sta_pwd[64];
41 | uint32_t sta_type;
42 |
43 | uint8_t mqtt_host[64];
44 | uint32_t mqtt_port;
45 | uint8_t mqtt_user[32];
46 | uint8_t mqtt_pass[32];
47 | uint32_t mqtt_keepalive;
48 | uint8_t security;
49 | } SYSCFG;
50 |
51 | typedef struct {
52 | uint8 flag;
53 | uint8 pad[3];
54 | } SAVE_FLAG;
55 |
56 | void ICACHE_FLASH_ATTR CFG_Save();
57 | void ICACHE_FLASH_ATTR CFG_Load();
58 |
59 | extern SYSCFG sysCfg;
60 |
61 | #endif /* USER_CONFIG_H_ */
62 |
--------------------------------------------------------------------------------
/modules/include/wifi.h:
--------------------------------------------------------------------------------
1 | /*
2 | * wifi.h
3 | *
4 | * Created on: Dec 30, 2014
5 | * Author: Minh
6 | */
7 |
8 | #ifndef USER_WIFI_H_
9 | #define USER_WIFI_H_
10 | #include "os_type.h"
11 | typedef void (*WifiCallback)(uint8_t);
12 | void ICACHE_FLASH_ATTR WIFI_Connect(uint8_t* ssid, uint8_t* pass, WifiCallback cb);
13 |
14 |
15 | #endif /* USER_WIFI_H_ */
16 |
--------------------------------------------------------------------------------
/modules/wifi.c:
--------------------------------------------------------------------------------
1 | /*
2 | * wifi.c
3 | *
4 | * Created on: Dec 30, 2014
5 | * Author: Minh
6 | */
7 | #include "wifi.h"
8 | #include "user_interface.h"
9 | #include "osapi.h"
10 | #include "espconn.h"
11 | #include "os_type.h"
12 | #include "mem.h"
13 | #include "mqtt_msg.h"
14 | #include "debug.h"
15 | #include "user_config.h"
16 | #include "config.h"
17 |
18 | static ETSTimer WiFiLinker;
19 | WifiCallback wifiCb = NULL;
20 | static uint8_t wifiStatus = STATION_IDLE, lastWifiStatus = STATION_IDLE;
21 | static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg)
22 | {
23 | struct ip_info ipConfig;
24 |
25 | os_timer_disarm(&WiFiLinker);
26 | wifi_get_ip_info(STATION_IF, &ipConfig);
27 | wifiStatus = wifi_station_get_connect_status();
28 | if (wifiStatus == STATION_GOT_IP && ipConfig.ip.addr != 0)
29 | {
30 |
31 | os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
32 | os_timer_arm(&WiFiLinker, 2000, 0);
33 |
34 |
35 | }
36 | else
37 | {
38 | if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD)
39 | {
40 |
41 | INFO("STATION_WRONG_PASSWORD\r\n");
42 | wifi_station_connect();
43 |
44 |
45 | }
46 | else if(wifi_station_get_connect_status() == STATION_NO_AP_FOUND)
47 | {
48 |
49 | INFO("STATION_NO_AP_FOUND\r\n");
50 | wifi_station_connect();
51 |
52 |
53 | }
54 | else if(wifi_station_get_connect_status() == STATION_CONNECT_FAIL)
55 | {
56 |
57 | INFO("STATION_CONNECT_FAIL\r\n");
58 | wifi_station_connect();
59 |
60 | }
61 | else
62 | {
63 | INFO("STATION_IDLE\r\n");
64 | }
65 |
66 | os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
67 | os_timer_arm(&WiFiLinker, 500, 0);
68 | }
69 | if(wifiStatus != lastWifiStatus){
70 | lastWifiStatus = wifiStatus;
71 | if(wifiCb)
72 | wifiCb(wifiStatus);
73 | }
74 | }
75 |
76 | void ICACHE_FLASH_ATTR WIFI_Connect(uint8_t* ssid, uint8_t* pass, WifiCallback cb)
77 | {
78 | struct station_config stationConf;
79 |
80 | INFO("WIFI_INIT\r\n");
81 | wifi_set_opmode(STATION_MODE);
82 | wifi_station_set_auto_connect(FALSE);
83 | wifiCb = cb;
84 |
85 | os_memset(&stationConf, 0, sizeof(struct station_config));
86 |
87 | os_sprintf(stationConf.ssid, "%s", ssid);
88 | os_sprintf(stationConf.password, "%s", pass);
89 |
90 | wifi_station_set_config(&stationConf);
91 |
92 | os_timer_disarm(&WiFiLinker);
93 | os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL);
94 | os_timer_arm(&WiFiLinker, 1000, 0);
95 |
96 | wifi_station_set_auto_connect(TRUE);
97 | wifi_station_connect();
98 | }
99 |
100 |
--------------------------------------------------------------------------------
/mqtt/Makefile:
--------------------------------------------------------------------------------
1 |
2 | #############################################################
3 | # Required variables for each makefile
4 | # Discard this section from all parent makefiles
5 | # Expected variables (with automatic defaults):
6 | # CSRCS (all "C" files in the dir)
7 | # SUBDIRS (all subdirs with a Makefile)
8 | # GEN_LIBS - list of libs to be generated ()
9 | # GEN_IMAGES - list of images to be generated ()
10 | # COMPONENTS_xxx - a list of libs/objs in the form
11 | # subdir/lib to be extracted and rolled up into
12 | # a generated lib/image xxx.a ()
13 | #
14 | ifndef PDIR
15 | GEN_LIBS = libmqtt.a
16 | endif
17 |
18 |
19 | #############################################################
20 | # Configuration i.e. compile options etc.
21 | # Target specific stuff (defines etc.) goes in here!
22 | # Generally values applying to a tree are captured in the
23 | # makefile at its root level - these are then overridden
24 | # for a subtree within the makefile rooted therein
25 | #
26 | #DEFINES +=
27 |
28 | #############################################################
29 | # Recursion Magic - Don't touch this!!
30 | #
31 | # Each subtree potentially has an include directory
32 | # corresponding to the common APIs applicable to modules
33 | # rooted at that subtree. Accordingly, the INCLUDE PATH
34 | # of a module can only contain the include directories up
35 | # its parent path, and not its siblings
36 | #
37 | # Required for each makefile to inherit from the parent
38 | #
39 |
40 | INCLUDES := $(INCLUDES) -I $(PDIR)include
41 | INCLUDES += -I ./
42 | PDIR := ../$(PDIR)
43 | sinclude $(PDIR)Makefile
44 |
45 |
--------------------------------------------------------------------------------
/mqtt/include/debug.h:
--------------------------------------------------------------------------------
1 | /*
2 | * debug.h
3 | *
4 | * Created on: Dec 4, 2014
5 | * Author: Minh
6 | */
7 |
8 | #ifndef USER_DEBUG_H_
9 | #define USER_DEBUG_H_
10 |
11 | #ifndef INFO
12 | #define INFO os_printf
13 | #endif
14 |
15 | #endif /* USER_DEBUG_H_ */
16 |
--------------------------------------------------------------------------------
/mqtt/include/mqtt.h:
--------------------------------------------------------------------------------
1 | /* mqtt.h
2 | *
3 | * Copyright (c) 2014-2015, Tuan PM
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 | #ifndef USER_AT_MQTT_H_
31 | #define USER_AT_MQTT_H_
32 | #include "mqtt_msg.h"
33 | #include "user_interface.h"
34 |
35 | #include "queue.h"
36 | typedef struct mqtt_event_data_t
37 | {
38 | uint8_t type;
39 | const char* topic;
40 | const char* data;
41 | uint16_t topic_length;
42 | uint16_t data_length;
43 | uint16_t data_offset;
44 | } mqtt_event_data_t;
45 |
46 | typedef struct mqtt_state_t
47 | {
48 | uint16_t port;
49 | int auto_reconnect;
50 | mqtt_connect_info_t* connect_info;
51 | uint8_t* in_buffer;
52 | uint8_t* out_buffer;
53 | int in_buffer_length;
54 | int out_buffer_length;
55 | uint16_t message_length;
56 | uint16_t message_length_read;
57 | mqtt_message_t* outbound_message;
58 | mqtt_connection_t mqtt_connection;
59 | uint16_t pending_msg_id;
60 | int pending_msg_type;
61 | int pending_publish_qos;
62 | } mqtt_state_t;
63 |
64 | typedef enum {
65 | WIFI_INIT,
66 | WIFI_CONNECTING,
67 | WIFI_CONNECTING_ERROR,
68 | WIFI_CONNECTED,
69 | DNS_RESOLVE,
70 | TCP_DISCONNECTED,
71 | TCP_RECONNECT_REQ,
72 | TCP_RECONNECT,
73 | TCP_CONNECTING,
74 | TCP_CONNECTING_ERROR,
75 | TCP_CONNECTED,
76 | MQTT_CONNECT_SEND,
77 | MQTT_CONNECT_SENDING,
78 | MQTT_SUBSCIBE_SEND,
79 | MQTT_SUBSCIBE_SENDING,
80 | MQTT_DATA,
81 | MQTT_PUBLISH_RECV,
82 | MQTT_PUBLISHING
83 | } tConnState;
84 |
85 | typedef void (*MqttCallback)(uint32_t *args);
86 | typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh);
87 |
88 | typedef struct {
89 | struct espconn *pCon;
90 | uint8_t security;
91 | uint8_t* host;
92 | uint32_t port;
93 | ip_addr_t ip;
94 | mqtt_state_t mqtt_state;
95 | mqtt_connect_info_t connect_info;
96 | MqttCallback connectedCb;
97 | MqttCallback disconnectedCb;
98 | MqttCallback publishedCb;
99 | MqttDataCallback dataCb;
100 | ETSTimer mqttTimer;
101 | uint32_t keepAliveTick;
102 | uint32_t reconnectTick;
103 | uint32_t sendTimeout;
104 | tConnState connState;
105 | QUEUE msgQueue;
106 | void* user_data;
107 | } MQTT_Client;
108 |
109 | #define SEC_NONSSL 0
110 | #define SEC_SSL 1
111 |
112 | #define MQTT_FLAG_CONNECTED 1
113 | #define MQTT_FLAG_READY 2
114 | #define MQTT_FLAG_EXIT 4
115 |
116 | #define MQTT_EVENT_TYPE_NONE 0
117 | #define MQTT_EVENT_TYPE_CONNECTED 1
118 | #define MQTT_EVENT_TYPE_DISCONNECTED 2
119 | #define MQTT_EVENT_TYPE_SUBSCRIBED 3
120 | #define MQTT_EVENT_TYPE_UNSUBSCRIBED 4
121 | #define MQTT_EVENT_TYPE_PUBLISH 5
122 | #define MQTT_EVENT_TYPE_PUBLISHED 6
123 | #define MQTT_EVENT_TYPE_EXITED 7
124 | #define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8
125 |
126 | void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security);
127 | void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession);
128 | void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain);
129 | void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb);
130 | void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb);
131 | void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb);
132 | void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb);
133 | BOOL ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos);
134 | void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient);
135 | void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient);
136 | BOOL ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain);
137 |
138 | #endif /* USER_AT_MQTT_H_ */
139 |
--------------------------------------------------------------------------------
/mqtt/include/mqtt_msg.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: mqtt_msg.h
3 | * Author: Minh Tuan
4 | *
5 | * Created on July 12, 2014, 1:05 PM
6 | */
7 |
8 | #ifndef MQTT_MSG_H
9 | #define MQTT_MSG_H
10 | #include "c_types.h"
11 | #ifdef __cplusplus
12 | extern "C" {
13 | #endif
14 |
15 | /*
16 | * Copyright (c) 2014, Stephen Robinson
17 | * All rights reserved.
18 | *
19 | * Redistribution and use in source and binary forms, with or without
20 | * modification, are permitted provided that the following conditions
21 | * are met:
22 | *
23 | * 1. Redistributions of source code must retain the above copyright
24 | * notice, this list of conditions and the following disclaimer.
25 | * 2. Redistributions in binary form must reproduce the above copyright
26 | * notice, this list of conditions and the following disclaimer in the
27 | * documentation and/or other materials provided with the distribution.
28 | * 3. Neither the name of the copyright holder nor the names of its
29 | * contributors may be used to endorse or promote products derived
30 | * from this software without specific prior written permission.
31 | *
32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 | * POSSIBILITY OF SUCH DAMAGE.
43 | *
44 | */
45 | /* 7 6 5 4 3 2 1 0*/
46 | /*| --- Message Type---- | DUP Flag | QoS Level | Retain |
47 | /* Remaining Length */
48 |
49 |
50 | enum mqtt_message_type
51 | {
52 | MQTT_MSG_TYPE_CONNECT = 1,
53 | MQTT_MSG_TYPE_CONNACK = 2,
54 | MQTT_MSG_TYPE_PUBLISH = 3,
55 | MQTT_MSG_TYPE_PUBACK = 4,
56 | MQTT_MSG_TYPE_PUBREC = 5,
57 | MQTT_MSG_TYPE_PUBREL = 6,
58 | MQTT_MSG_TYPE_PUBCOMP = 7,
59 | MQTT_MSG_TYPE_SUBSCRIBE = 8,
60 | MQTT_MSG_TYPE_SUBACK = 9,
61 | MQTT_MSG_TYPE_UNSUBSCRIBE = 10,
62 | MQTT_MSG_TYPE_UNSUBACK = 11,
63 | MQTT_MSG_TYPE_PINGREQ = 12,
64 | MQTT_MSG_TYPE_PINGRESP = 13,
65 | MQTT_MSG_TYPE_DISCONNECT = 14
66 | };
67 |
68 | typedef struct mqtt_message
69 | {
70 | uint8_t* data;
71 | uint16_t length;
72 |
73 | } mqtt_message_t;
74 |
75 | typedef struct mqtt_connection
76 | {
77 | mqtt_message_t message;
78 |
79 | uint16_t message_id;
80 | uint8_t* buffer;
81 | uint16_t buffer_length;
82 |
83 | } mqtt_connection_t;
84 |
85 | typedef struct mqtt_connect_info
86 | {
87 | char* client_id;
88 | char* username;
89 | char* password;
90 | char* will_topic;
91 | char* will_message;
92 | int keepalive;
93 | int will_qos;
94 | int will_retain;
95 | int clean_session;
96 |
97 | } mqtt_connect_info_t;
98 |
99 |
100 | static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
101 | static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
102 | static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
103 | static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
104 |
105 | void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
106 | int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length);
107 | const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
108 | const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
109 | uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length);
110 |
111 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
112 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
113 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);
114 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id);
115 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id);
116 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id);
117 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id);
118 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id);
119 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection);
120 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection);
121 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection);
122 |
123 |
124 | #ifdef __cplusplus
125 | }
126 | #endif
127 |
128 | #endif /* MQTT_MSG_H */
129 |
130 |
--------------------------------------------------------------------------------
/mqtt/include/proto.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: proto.h
3 | * Author: ThuHien
4 | *
5 | * Created on November 23, 2012, 8:57 AM
6 | */
7 |
8 | #ifndef _PROTO_H_
9 | #define _PROTO_H_
10 | #include
11 | #include "typedef.h"
12 | #include "ringbuf.h"
13 |
14 | typedef void(PROTO_PARSE_CALLBACK)();
15 |
16 | typedef struct{
17 | U8 *buf;
18 | U16 bufSize;
19 | U16 dataLen;
20 | U8 isEsc;
21 | U8 isBegin;
22 | PROTO_PARSE_CALLBACK* callback;
23 | }PROTO_PARSER;
24 |
25 | I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize);
26 | I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len);
27 | I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize);
28 | I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len);
29 | I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value);
30 | I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen);
31 | #endif
32 |
33 |
--------------------------------------------------------------------------------
/mqtt/include/queue.h:
--------------------------------------------------------------------------------
1 | /* str_queue.h --
2 | *
3 | * Copyright (c) 2014-2015, Tuan PM
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | #ifndef USER_QUEUE_H_
32 | #define USER_QUEUE_H_
33 | #include "os_type.h"
34 | #include "ringbuf.h"
35 | typedef struct {
36 | uint8_t *buf;
37 | RINGBUF rb;
38 | } QUEUE;
39 |
40 | void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize);
41 | int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len);
42 | int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen);
43 | BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue);
44 | #endif /* USER_QUEUE_H_ */
45 |
--------------------------------------------------------------------------------
/mqtt/include/ringbuf.h:
--------------------------------------------------------------------------------
1 | #ifndef _RING_BUF_H_
2 | #define _RING_BUF_H_
3 |
4 | #include
5 | #include
6 | #include "typedef.h"
7 |
8 | typedef struct{
9 | U8* p_o; /**< Original pointer */
10 | U8* volatile p_r; /**< Read pointer */
11 | U8* volatile p_w; /**< Write pointer */
12 | volatile I32 fill_cnt; /**< Number of filled slots */
13 | I32 size; /**< Buffer size */
14 | }RINGBUF;
15 |
16 | I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size);
17 | I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c);
18 | I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c);
19 | #endif
20 |
--------------------------------------------------------------------------------
/mqtt/include/typedef.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * Standard Types definition
4 | */
5 |
6 | #ifndef _TYPE_DEF_H_
7 | #define _TYPE_DEF_H_
8 |
9 | typedef char I8;
10 | typedef unsigned char U8;
11 | typedef short I16;
12 | typedef unsigned short U16;
13 | typedef long I32;
14 | typedef unsigned long U32;
15 | typedef unsigned long long U64;
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/mqtt/include/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef _UTILS_H_
2 | #define _UTILS_H_
3 |
4 | #include "c_types.h"
5 |
6 | uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s);
7 | uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip);
8 | uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str);
9 | #endif
10 |
--------------------------------------------------------------------------------
/mqtt/mqtt.c:
--------------------------------------------------------------------------------
1 | /* mqtt.c
2 | * Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
3 | *
4 | * Copyright (c) 2014-2015, Tuan PM
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions are met:
9 | *
10 | * * Redistributions of source code must retain the above copyright notice,
11 | * this list of conditions and the following disclaimer.
12 | * * Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * * Neither the name of Redis nor the names of its contributors may be used
16 | * to endorse or promote products derived from this software without
17 | * specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include "user_interface.h"
33 | #include "osapi.h"
34 | #include "espconn.h"
35 | #include "os_type.h"
36 | #include "mem.h"
37 | #include "mqtt_msg.h"
38 | #include "debug.h"
39 | #include "user_config.h"
40 | #include "mqtt.h"
41 | #include "queue.h"
42 |
43 | #define MQTT_TASK_PRIO 0
44 | #define MQTT_TASK_QUEUE_SIZE 1
45 | #define MQTT_SEND_TIMOUT 5
46 |
47 | #ifndef QUEUE_BUFFER_SIZE
48 | #define QUEUE_BUFFER_SIZE 2048
49 | #endif
50 |
51 | unsigned char *default_certificate;
52 | unsigned int default_certificate_len = 0;
53 | unsigned char *default_private_key;
54 | unsigned int default_private_key_len = 0;
55 |
56 | os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE];
57 |
58 | LOCAL void ICACHE_FLASH_ATTR
59 | mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
60 | {
61 | struct espconn *pConn = (struct espconn *)arg;
62 | MQTT_Client* client = (MQTT_Client *)pConn->reverse;
63 |
64 |
65 | if(ipaddr == NULL)
66 | {
67 | INFO("DNS: Found, but got no ip, try to reconnect\r\n");
68 | client->connState = TCP_RECONNECT_REQ;
69 | return;
70 | }
71 |
72 | INFO("DNS: found ip %d.%d.%d.%d\n",
73 | *((uint8 *) &ipaddr->addr),
74 | *((uint8 *) &ipaddr->addr + 1),
75 | *((uint8 *) &ipaddr->addr + 2),
76 | *((uint8 *) &ipaddr->addr + 3));
77 |
78 | if(client->ip.addr == 0 && ipaddr->addr != 0)
79 | {
80 | os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
81 | if(client->security){
82 | espconn_secure_connect(client->pCon);
83 | }
84 | else {
85 | espconn_connect(client->pCon);
86 | }
87 |
88 | client->connState = TCP_CONNECTING;
89 | INFO("TCP: connecting...\r\n");
90 | }
91 |
92 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
93 | }
94 |
95 |
96 |
97 | LOCAL void ICACHE_FLASH_ATTR
98 | deliver_publish(MQTT_Client* client, uint8_t* message, int length)
99 | {
100 | mqtt_event_data_t event_data;
101 |
102 | event_data.topic_length = length;
103 | event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length);
104 | event_data.data_length = length;
105 | event_data.data = mqtt_get_publish_data(message, &event_data.data_length);
106 |
107 | if(client->dataCb)
108 | client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length);
109 |
110 | }
111 |
112 |
113 | /**
114 | * @brief Client received callback function.
115 | * @param arg: contain the ip link information
116 | * @param pdata: received data
117 | * @param len: the lenght of received data
118 | * @retval None
119 | */
120 | void ICACHE_FLASH_ATTR
121 | mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len)
122 | {
123 | uint8_t msg_type;
124 | uint8_t msg_qos;
125 | uint16_t msg_id;
126 |
127 | struct espconn *pCon = (struct espconn*)arg;
128 | MQTT_Client *client = (MQTT_Client *)pCon->reverse;
129 |
130 | READPACKET:
131 | INFO("TCP: data received %d bytes\r\n", len);
132 | if(len < MQTT_BUF_SIZE && len > 0){
133 | os_memcpy(client->mqtt_state.in_buffer, pdata, len);
134 |
135 | msg_type = mqtt_get_type(client->mqtt_state.in_buffer);
136 | msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer);
137 | msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);
138 | switch(client->connState){
139 | case MQTT_CONNECT_SENDING:
140 | if(msg_type == MQTT_MSG_TYPE_CONNACK){
141 | if(client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT){
142 | INFO("MQTT: Invalid packet\r\n");
143 | if(client->security){
144 | espconn_secure_disconnect(client->pCon);
145 | }
146 | else {
147 | espconn_disconnect(client->pCon);
148 | }
149 | } else {
150 | INFO("MQTT: Connected to %s:%d\r\n", client->host, client->port);
151 | client->connState = MQTT_DATA;
152 | if(client->connectedCb)
153 | client->connectedCb((uint32_t*)client);
154 | }
155 |
156 | }
157 | break;
158 | case MQTT_DATA:
159 | client->mqtt_state.message_length_read = len;
160 | client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
161 |
162 |
163 | switch(msg_type)
164 | {
165 |
166 | case MQTT_MSG_TYPE_SUBACK:
167 | if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
168 | INFO("MQTT: Subscribe successful\r\n");
169 | break;
170 | case MQTT_MSG_TYPE_UNSUBACK:
171 | if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
172 | INFO("MQTT: UnSubscribe successful\r\n");
173 | break;
174 | case MQTT_MSG_TYPE_PUBLISH:
175 | if(msg_qos == 1)
176 | client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id);
177 | else if(msg_qos == 2)
178 | client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id);
179 | if(msg_qos == 1 || msg_qos == 2){
180 | INFO("MQTT: Queue response QoS: %d\r\n", msg_qos);
181 | if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
182 | INFO("MQTT: Queue full\r\n");
183 | }
184 | }
185 |
186 | deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
187 | break;
188 | case MQTT_MSG_TYPE_PUBACK:
189 | if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){
190 | INFO("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\r\n");
191 | }
192 |
193 | break;
194 | case MQTT_MSG_TYPE_PUBREC:
195 | client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id);
196 | if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
197 | INFO("MQTT: Queue full\r\n");
198 | }
199 | break;
200 | case MQTT_MSG_TYPE_PUBREL:
201 | client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id);
202 | if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
203 | INFO("MQTT: Queue full\r\n");
204 | }
205 | break;
206 | case MQTT_MSG_TYPE_PUBCOMP:
207 | if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){
208 | INFO("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\r\n");
209 | }
210 | break;
211 | case MQTT_MSG_TYPE_PINGREQ:
212 | client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection);
213 | if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
214 | INFO("MQTT: Queue full\r\n");
215 | }
216 | break;
217 | case MQTT_MSG_TYPE_PINGRESP:
218 | // Ignore
219 | break;
220 | }
221 | // NOTE: this is done down here and not in the switch case above
222 | // because the PSOCK_READBUF_LEN() won't work inside a switch
223 | // statement due to the way protothreads resume.
224 | if(msg_type == MQTT_MSG_TYPE_PUBLISH)
225 | {
226 | len = client->mqtt_state.message_length_read;
227 |
228 | if(client->mqtt_state.message_length < client->mqtt_state.message_length_read)
229 | {
230 | //client->connState = MQTT_PUBLISH_RECV;
231 | //Not Implement yet
232 | len -= client->mqtt_state.message_length;
233 | pdata += client->mqtt_state.message_length;
234 |
235 | INFO("Get another published message\r\n");
236 | goto READPACKET;
237 | }
238 |
239 | }
240 | break;
241 | }
242 | } else {
243 | INFO("ERROR: Message too long\r\n");
244 | }
245 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
246 | }
247 |
248 | /**
249 | * @brief Client send over callback function.
250 | * @param arg: contain the ip link information
251 | * @retval None
252 | */
253 | void ICACHE_FLASH_ATTR
254 | mqtt_tcpclient_sent_cb(void *arg)
255 | {
256 | struct espconn *pCon = (struct espconn *)arg;
257 | MQTT_Client* client = (MQTT_Client *)pCon->reverse;
258 | INFO("TCP: Sent\r\n");
259 | client->sendTimeout = 0;
260 | if(client->connState == MQTT_DATA && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH){
261 | if(client->publishedCb)
262 | client->publishedCb((uint32_t*)client);
263 | }
264 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
265 | }
266 |
267 | void ICACHE_FLASH_ATTR mqtt_timer(void *arg)
268 | {
269 | MQTT_Client* client = (MQTT_Client*)arg;
270 |
271 | if(client->connState == MQTT_DATA){
272 | client->keepAliveTick ++;
273 | if(client->keepAliveTick > client->mqtt_state.connect_info->keepalive){
274 |
275 | INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port);
276 | client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
277 | client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ;
278 | client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
279 | client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
280 |
281 |
282 | client->sendTimeout = MQTT_SEND_TIMOUT;
283 | INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
284 | if(client->security){
285 | espconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
286 | }
287 | else{
288 | espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
289 | }
290 |
291 | client->mqtt_state.outbound_message = NULL;
292 |
293 | client->keepAliveTick = 0;
294 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
295 | }
296 |
297 | } else if(client->connState == TCP_RECONNECT_REQ){
298 | client->reconnectTick ++;
299 | if(client->reconnectTick > MQTT_RECONNECT_TIMEOUT) {
300 | client->reconnectTick = 0;
301 | client->connState = TCP_RECONNECT;
302 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
303 | }
304 | }
305 | if(client->sendTimeout > 0)
306 | client->sendTimeout --;
307 | }
308 |
309 | void ICACHE_FLASH_ATTR
310 | mqtt_tcpclient_discon_cb(void *arg)
311 | {
312 |
313 | struct espconn *pespconn = (struct espconn *)arg;
314 | MQTT_Client* client = (MQTT_Client *)pespconn->reverse;
315 | INFO("TCP: Disconnected callback\r\n");
316 | client->connState = TCP_RECONNECT_REQ;
317 | if(client->disconnectedCb)
318 | client->disconnectedCb((uint32_t*)client);
319 |
320 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
321 | }
322 |
323 |
324 |
325 | /**
326 | * @brief Tcp client connect success callback function.
327 | * @param arg: contain the ip link information
328 | * @retval None
329 | */
330 | void ICACHE_FLASH_ATTR
331 | mqtt_tcpclient_connect_cb(void *arg)
332 | {
333 | struct espconn *pCon = (struct espconn *)arg;
334 | MQTT_Client* client = (MQTT_Client *)pCon->reverse;
335 |
336 | espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb);
337 | espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);////////
338 | espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);///////
339 | INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port);
340 |
341 | mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length);
342 | client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info);
343 | client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
344 | client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
345 |
346 |
347 | client->sendTimeout = MQTT_SEND_TIMOUT;
348 | INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
349 | if(client->security){
350 | espconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
351 | }
352 | else{
353 | espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
354 | }
355 |
356 | client->mqtt_state.outbound_message = NULL;
357 | client->connState = MQTT_CONNECT_SENDING;
358 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
359 | }
360 |
361 | /**
362 | * @brief Tcp client connect repeat callback function.
363 | * @param arg: contain the ip link information
364 | * @retval None
365 | */
366 | void ICACHE_FLASH_ATTR
367 | mqtt_tcpclient_recon_cb(void *arg, sint8 errType)
368 | {
369 | struct espconn *pCon = (struct espconn *)arg;
370 | MQTT_Client* client = (MQTT_Client *)pCon->reverse;
371 |
372 | INFO("TCP: Reconnect to %s:%d\r\n", client->host, client->port);
373 |
374 | client->connState = TCP_RECONNECT_REQ;
375 |
376 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
377 |
378 | }
379 |
380 | /**
381 | * @brief MQTT publish function.
382 | * @param client: MQTT_Client reference
383 | * @param topic: string topic will publish to
384 | * @param data: buffer data send point to
385 | * @param data_length: length of data
386 | * @param qos: qos
387 | * @param retain: retain
388 | * @retval TRUE if success queue
389 | */
390 | BOOL ICACHE_FLASH_ATTR
391 | MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain)
392 | {
393 | uint8_t dataBuffer[MQTT_BUF_SIZE];
394 | uint16_t dataLen;
395 | client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection,
396 | topic, data, data_length,
397 | qos, retain,
398 | &client->mqtt_state.pending_msg_id);
399 | if(client->mqtt_state.outbound_message->length == 0){
400 | INFO("MQTT: Queuing publish failed\r\n");
401 | return FALSE;
402 | }
403 | INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size);
404 | while(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
405 | INFO("MQTT: Queue full\r\n");
406 | if(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
407 | INFO("MQTT: Serious buffer error\r\n");
408 | return FALSE;
409 | }
410 | }
411 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
412 | return TRUE;
413 | }
414 |
415 | /**
416 | * @brief MQTT subscibe function.
417 | * @param client: MQTT_Client reference
418 | * @param topic: string topic will subscribe
419 | * @param qos: qos
420 | * @retval TRUE if success queue
421 | */
422 | BOOL ICACHE_FLASH_ATTR
423 | MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos)
424 | {
425 | uint8_t dataBuffer[MQTT_BUF_SIZE];
426 | uint16_t dataLen;
427 |
428 | client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection,
429 | topic, 0,
430 | &client->mqtt_state.pending_msg_id);
431 | INFO("MQTT: queue subscribe, topic\"%s\", id: %d\r\n",topic, client->mqtt_state.pending_msg_id);
432 | while(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){
433 | INFO("MQTT: Queue full\r\n");
434 | if(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
435 | INFO("MQTT: Serious buffer error\r\n");
436 | return FALSE;
437 | }
438 | }
439 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
440 | return TRUE;
441 | }
442 |
443 | void ICACHE_FLASH_ATTR
444 | MQTT_Task(os_event_t *e)
445 | {
446 | MQTT_Client* client = (MQTT_Client*)e->par;
447 | uint8_t dataBuffer[MQTT_BUF_SIZE];
448 | uint16_t dataLen;
449 | if(e->par == 0)
450 | return;
451 | switch(client->connState){
452 |
453 | case TCP_RECONNECT_REQ:
454 | break;
455 | case TCP_RECONNECT:
456 | MQTT_Connect(client);
457 | INFO("TCP: Reconnect to: %s:%d\r\n", client->host, client->port);
458 | client->connState = TCP_CONNECTING;
459 | break;
460 | case MQTT_DATA:
461 | if(QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) {
462 | break;
463 | }
464 | if(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0){
465 | client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer);
466 | client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen);
467 |
468 |
469 | client->sendTimeout = MQTT_SEND_TIMOUT;
470 | INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
471 | if(client->security){
472 | espconn_secure_sent(client->pCon, dataBuffer, dataLen);
473 | }
474 | else{
475 | espconn_sent(client->pCon, dataBuffer, dataLen);
476 | }
477 |
478 | client->mqtt_state.outbound_message = NULL;
479 | break;
480 | }
481 | break;
482 | }
483 | }
484 |
485 | /**
486 | * @brief MQTT initialization connection function
487 | * @param client: MQTT_Client reference
488 | * @param host: Domain or IP string
489 | * @param port: Port to connect
490 | * @param security: 1 for ssl, 0 for none
491 | * @retval None
492 | */
493 | void ICACHE_FLASH_ATTR
494 | MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security)
495 | {
496 | uint32_t temp;
497 | INFO("MQTT_InitConnection\r\n");
498 | os_memset(mqttClient, 0, sizeof(MQTT_Client));
499 | temp = os_strlen(host);
500 | mqttClient->host = (uint8_t*)os_zalloc(temp + 1);
501 | os_strcpy(mqttClient->host, host);
502 | mqttClient->host[temp] = 0;
503 | mqttClient->port = port;
504 | mqttClient->security = security;
505 |
506 | }
507 |
508 | /**
509 | * @brief MQTT initialization mqtt client function
510 | * @param client: MQTT_Client reference
511 | * @param clientid: MQTT client id
512 | * @param client_user:MQTT client user
513 | * @param client_pass:MQTT client password
514 | * @param client_pass:MQTT keep alive timer, in second
515 | * @retval None
516 | */
517 | void ICACHE_FLASH_ATTR
518 | MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession)
519 | {
520 | uint32_t temp;
521 | INFO("MQTT_InitClient\r\n");
522 |
523 | os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t));
524 |
525 | temp = os_strlen(client_id);
526 | mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1);
527 | os_strcpy(mqttClient->connect_info.client_id, client_id);
528 | mqttClient->connect_info.client_id[temp] = 0;
529 |
530 | temp = os_strlen(client_user);
531 | mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1);
532 | os_strcpy(mqttClient->connect_info.username, client_user);
533 | mqttClient->connect_info.username[temp] = 0;
534 |
535 | temp = os_strlen(client_pass);
536 | mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1);
537 | os_strcpy(mqttClient->connect_info.password, client_pass);
538 | mqttClient->connect_info.password[temp] = 0;
539 |
540 |
541 | mqttClient->connect_info.keepalive = keepAliveTime;
542 | mqttClient->connect_info.clean_session = cleanSession;
543 |
544 | mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
545 | mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE;
546 | mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
547 | mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE;
548 | mqttClient->mqtt_state.connect_info = &mqttClient->connect_info;
549 |
550 | mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length);
551 |
552 | QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE);
553 |
554 | system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE);
555 | system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
556 | }
557 | void ICACHE_FLASH_ATTR
558 | MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain)
559 | {
560 | uint32_t temp;
561 | temp = os_strlen(will_topic);
562 | mqttClient->connect_info.will_topic = (uint8_t*)os_zalloc(temp + 1);
563 | os_strcpy(mqttClient->connect_info.will_topic, will_topic);
564 | mqttClient->connect_info.will_topic[temp] = 0;
565 |
566 | temp = os_strlen(will_msg);
567 | mqttClient->connect_info.will_message = (uint8_t*)os_zalloc(temp + 1);
568 | os_strcpy(mqttClient->connect_info.will_message, will_msg);
569 | mqttClient->connect_info.will_message[temp] = 0;
570 |
571 |
572 | mqttClient->connect_info.will_qos = will_qos;
573 | mqttClient->connect_info.will_retain = will_retain;
574 | }
575 | /**
576 | * @brief Begin connect to MQTT broker
577 | * @param client: MQTT_Client reference
578 | * @retval None
579 | */
580 | void ICACHE_FLASH_ATTR
581 | MQTT_Connect(MQTT_Client *mqttClient)
582 | {
583 | MQTT_Disconnect(mqttClient);
584 | mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
585 | mqttClient->pCon->type = ESPCONN_TCP;
586 | mqttClient->pCon->state = ESPCONN_NONE;
587 | mqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
588 | mqttClient->pCon->proto.tcp->local_port = espconn_port();
589 | mqttClient->pCon->proto.tcp->remote_port = mqttClient->port;
590 | mqttClient->pCon->reverse = mqttClient;
591 | espconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb);
592 | espconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb);
593 |
594 | mqttClient->keepAliveTick = 0;
595 | mqttClient->reconnectTick = 0;
596 |
597 |
598 | os_timer_disarm(&mqttClient->mqttTimer);
599 | os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient);
600 | os_timer_arm(&mqttClient->mqttTimer, 1000, 1);
601 |
602 | if(UTILS_StrToIP(mqttClient->host, &mqttClient->pCon->proto.tcp->remote_ip)) {
603 | INFO("TCP: Connect to ip %s:%d\r\n", mqttClient->host, mqttClient->port);
604 | if(mqttClient->security){
605 | espconn_secure_connect(mqttClient->pCon);
606 | }
607 | else {
608 | espconn_connect(mqttClient->pCon);
609 | }
610 | }
611 | else {
612 | INFO("TCP: Connect to domain %s:%d\r\n", mqttClient->host, mqttClient->port);
613 | espconn_gethostbyname(mqttClient->pCon, mqttClient->host, &mqttClient->ip, mqtt_dns_found);
614 | }
615 | mqttClient->connState = TCP_CONNECTING;
616 | }
617 |
618 | void ICACHE_FLASH_ATTR
619 | MQTT_Disconnect(MQTT_Client *mqttClient)
620 | {
621 | if(mqttClient->pCon){
622 | INFO("Free memory\r\n");
623 | if(mqttClient->pCon->proto.tcp)
624 | os_free(mqttClient->pCon->proto.tcp);
625 | os_free(mqttClient->pCon);
626 | mqttClient->pCon = NULL;
627 | }
628 |
629 | os_timer_disarm(&mqttClient->mqttTimer);
630 | }
631 | void ICACHE_FLASH_ATTR
632 | MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb)
633 | {
634 | mqttClient->connectedCb = connectedCb;
635 | }
636 |
637 | void ICACHE_FLASH_ATTR
638 | MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb)
639 | {
640 | mqttClient->disconnectedCb = disconnectedCb;
641 | }
642 |
643 | void ICACHE_FLASH_ATTR
644 | MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb)
645 | {
646 | mqttClient->dataCb = dataCb;
647 | }
648 |
649 | void ICACHE_FLASH_ATTR
650 | MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb)
651 | {
652 | mqttClient->publishedCb = publishedCb;
653 | }
654 |
--------------------------------------------------------------------------------
/mqtt/mqtt_msg.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Stephen Robinson
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | *
9 | * 1. Redistributions of source code must retain the above copyright
10 | * notice, this list of conditions and the following disclaimer.
11 | * 2. Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * 3. Neither the name of the copyright holder nor the names of its
15 | * contributors may be used to endorse or promote products derived
16 | * from this software without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | *
30 | */
31 |
32 | #include
33 | #include "mqtt_msg.h"
34 | #include "user_config.h"
35 | #define MQTT_MAX_FIXED_HEADER_SIZE 3
36 |
37 | enum mqtt_connect_flag
38 | {
39 | MQTT_CONNECT_FLAG_USERNAME = 1 << 7,
40 | MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,
41 | MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,
42 | MQTT_CONNECT_FLAG_WILL = 1 << 2,
43 | MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1
44 | };
45 |
46 | struct __attribute((__packed__)) mqtt_connect_variable_header
47 | {
48 | uint8_t lengthMsb;
49 | uint8_t lengthLsb;
50 | #if defined(PROTOCOL_NAMEv31)
51 | uint8_t magic[6];
52 | #elif defined(PROTOCOL_NAMEv311)
53 | uint8_t magic[4];
54 | #else
55 | #error "Please define protocol name"
56 | #endif
57 | uint8_t version;
58 | uint8_t flags;
59 | uint8_t keepaliveMsb;
60 | uint8_t keepaliveLsb;
61 | };
62 |
63 | static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len)
64 | {
65 | if(connection->message.length + len + 2 > connection->buffer_length)
66 | return -1;
67 |
68 | connection->buffer[connection->message.length++] = len >> 8;
69 | connection->buffer[connection->message.length++] = len & 0xff;
70 | memcpy(connection->buffer + connection->message.length, string, len);
71 | connection->message.length += len;
72 |
73 | return len + 2;
74 | }
75 |
76 | static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id)
77 | {
78 | // If message_id is zero then we should assign one, otherwise
79 | // we'll use the one supplied by the caller
80 | while(message_id == 0)
81 | message_id = ++connection->message_id;
82 |
83 | if(connection->message.length + 2 > connection->buffer_length)
84 | return 0;
85 |
86 | connection->buffer[connection->message.length++] = message_id >> 8;
87 | connection->buffer[connection->message.length++] = message_id & 0xff;
88 |
89 | return message_id;
90 | }
91 |
92 | static int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection)
93 | {
94 | connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE;
95 | return MQTT_MAX_FIXED_HEADER_SIZE;
96 | }
97 |
98 | static mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection)
99 | {
100 | connection->message.data = connection->buffer;
101 | connection->message.length = 0;
102 | return &connection->message;
103 | }
104 |
105 | static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain)
106 | {
107 | int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;
108 |
109 | if(remaining_length > 127)
110 | {
111 | connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
112 | connection->buffer[1] = 0x80 | (remaining_length % 128);
113 | connection->buffer[2] = remaining_length / 128;
114 | connection->message.length = remaining_length + 3;
115 | connection->message.data = connection->buffer;
116 | }
117 | else
118 | {
119 | connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
120 | connection->buffer[2] = remaining_length;
121 | connection->message.length = remaining_length + 2;
122 | connection->message.data = connection->buffer + 1;
123 | }
124 |
125 | return &connection->message;
126 | }
127 |
128 | void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length)
129 | {
130 | memset(connection, 0, sizeof(connection));
131 | connection->buffer = buffer;
132 | connection->buffer_length = buffer_length;
133 | }
134 |
135 | int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length)
136 | {
137 | int i;
138 | int totlen = 0;
139 |
140 | for(i = 1; i < length; ++i)
141 | {
142 | totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
143 | if((buffer[i] & 0x80) == 0)
144 | {
145 | ++i;
146 | break;
147 | }
148 | }
149 | totlen += i;
150 |
151 | return totlen;
152 | }
153 |
154 | const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
155 | {
156 | int i;
157 | int totlen = 0;
158 | int topiclen;
159 |
160 | for(i = 1; i < *length; ++i)
161 | {
162 | totlen += (buffer[i] & 0x7f) << (7 * (i -1));
163 | if((buffer[i] & 0x80) == 0)
164 | {
165 | ++i;
166 | break;
167 | }
168 | }
169 | totlen += i;
170 |
171 | if(i + 2 >= *length)
172 | return NULL;
173 | topiclen = buffer[i++] << 8;
174 | topiclen |= buffer[i++];
175 |
176 | if(i + topiclen > *length)
177 | return NULL;
178 |
179 | *length = topiclen;
180 | return (const char*)(buffer + i);
181 | }
182 |
183 | const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
184 | {
185 | int i;
186 | int totlen = 0;
187 | int topiclen;
188 |
189 | for(i = 1; i < *length; ++i)
190 | {
191 | totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
192 | if((buffer[i] & 0x80) == 0)
193 | {
194 | ++i;
195 | break;
196 | }
197 | }
198 | totlen += i;
199 |
200 | if(i + 2 >= *length)
201 | return NULL;
202 | topiclen = buffer[i++] << 8;
203 | topiclen |= buffer[i++];
204 |
205 | if(i + topiclen >= *length){
206 | *length = 0;
207 | return NULL;
208 | }
209 | i += topiclen;
210 |
211 | if(mqtt_get_qos(buffer) > 0)
212 | {
213 | if(i + 2 >= *length)
214 | return NULL;
215 | i += 2;
216 | }
217 |
218 | if(totlen < i)
219 | return NULL;
220 |
221 | if(totlen <= *length)
222 | *length = totlen - i;
223 | else
224 | *length = *length - i;
225 | return (const char*)(buffer + i);
226 | }
227 |
228 | uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length)
229 | {
230 | if(length < 1)
231 | return 0;
232 |
233 | switch(mqtt_get_type(buffer))
234 | {
235 | case MQTT_MSG_TYPE_PUBLISH:
236 | {
237 | int i;
238 | int topiclen;
239 |
240 | for(i = 1; i < length; ++i)
241 | {
242 | if((buffer[i] & 0x80) == 0)
243 | {
244 | ++i;
245 | break;
246 | }
247 | }
248 |
249 | if(i + 2 >= length)
250 | return 0;
251 | topiclen = buffer[i++] << 8;
252 | topiclen |= buffer[i++];
253 |
254 | if(i + topiclen >= length)
255 | return 0;
256 | i += topiclen;
257 |
258 | if(mqtt_get_qos(buffer) > 0)
259 | {
260 | if(i + 2 >= length)
261 | return 0;
262 | //i += 2;
263 | } else {
264 | return 0;
265 | }
266 |
267 | return (buffer[i] << 8) | buffer[i + 1];
268 | }
269 | case MQTT_MSG_TYPE_PUBACK:
270 | case MQTT_MSG_TYPE_PUBREC:
271 | case MQTT_MSG_TYPE_PUBREL:
272 | case MQTT_MSG_TYPE_PUBCOMP:
273 | case MQTT_MSG_TYPE_SUBACK:
274 | case MQTT_MSG_TYPE_UNSUBACK:
275 | case MQTT_MSG_TYPE_SUBSCRIBE:
276 | {
277 | // This requires the remaining length to be encoded in 1 byte,
278 | // which it should be.
279 | if(length >= 4 && (buffer[1] & 0x80) == 0)
280 | return (buffer[2] << 8) | buffer[3];
281 | else
282 | return 0;
283 | }
284 |
285 | default:
286 | return 0;
287 | }
288 | }
289 |
290 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info)
291 | {
292 | struct mqtt_connect_variable_header* variable_header;
293 |
294 | init_message(connection);
295 |
296 | if(connection->message.length + sizeof(*variable_header) > connection->buffer_length)
297 | return fail_message(connection);
298 | variable_header = (void*)(connection->buffer + connection->message.length);
299 | connection->message.length += sizeof(*variable_header);
300 |
301 | variable_header->lengthMsb = 0;
302 | #if defined(PROTOCOL_NAMEv31)
303 | variable_header->lengthLsb = 6;
304 | memcpy(variable_header->magic, "MQIsdp", 6);
305 | variable_header->version = 3;
306 | #elif defined(PROTOCOL_NAMEv311)
307 | variable_header->lengthLsb = 4;
308 | memcpy(variable_header->magic, "MQTT", 4);
309 | variable_header->version = 4;
310 | #else
311 | #error "Please define protocol name"
312 | #endif
313 |
314 | variable_header->flags = 0;
315 | variable_header->keepaliveMsb = info->keepalive >> 8;
316 | variable_header->keepaliveLsb = info->keepalive & 0xff;
317 |
318 | if(info->clean_session)
319 | variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;
320 |
321 | if(info->client_id != NULL && info->client_id[0] != '\0')
322 | {
323 | if(append_string(connection, info->client_id, strlen(info->client_id)) < 0)
324 | return fail_message(connection);
325 | }
326 | else
327 | return fail_message(connection);
328 |
329 | if(info->will_topic != NULL && info->will_topic[0] != '\0')
330 | {
331 | if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0)
332 | return fail_message(connection);
333 |
334 | if(append_string(connection, info->will_message, strlen(info->will_message)) < 0)
335 | return fail_message(connection);
336 |
337 | variable_header->flags |= MQTT_CONNECT_FLAG_WILL;
338 | if(info->will_retain)
339 | variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;
340 | variable_header->flags |= (info->will_qos & 3) << 3;
341 | }
342 |
343 | if(info->username != NULL && info->username[0] != '\0')
344 | {
345 | if(append_string(connection, info->username, strlen(info->username)) < 0)
346 | return fail_message(connection);
347 |
348 | variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;
349 | }
350 |
351 | if(info->password != NULL && info->password[0] != '\0')
352 | {
353 | if(append_string(connection, info->password, strlen(info->password)) < 0)
354 | return fail_message(connection);
355 |
356 | variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;
357 | }
358 |
359 | return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);
360 | }
361 |
362 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id)
363 | {
364 | init_message(connection);
365 |
366 | if(topic == NULL || topic[0] == '\0')
367 | return fail_message(connection);
368 |
369 | if(append_string(connection, topic, strlen(topic)) < 0)
370 | return fail_message(connection);
371 |
372 | if(qos > 0)
373 | {
374 | if((*message_id = append_message_id(connection, 0)) == 0)
375 | return fail_message(connection);
376 | }
377 | else
378 | *message_id = 0;
379 |
380 | if(connection->message.length + data_length > connection->buffer_length)
381 | return fail_message(connection);
382 | memcpy(connection->buffer + connection->message.length, data, data_length);
383 | connection->message.length += data_length;
384 |
385 | return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
386 | }
387 |
388 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)
389 | {
390 | init_message(connection);
391 | if(append_message_id(connection, message_id) == 0)
392 | return fail_message(connection);
393 | return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);
394 | }
395 |
396 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id)
397 | {
398 | init_message(connection);
399 | if(append_message_id(connection, message_id) == 0)
400 | return fail_message(connection);
401 | return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);
402 | }
403 |
404 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id)
405 | {
406 | init_message(connection);
407 | if(append_message_id(connection, message_id) == 0)
408 | return fail_message(connection);
409 | return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);
410 | }
411 |
412 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id)
413 | {
414 | init_message(connection);
415 | if(append_message_id(connection, message_id) == 0)
416 | return fail_message(connection);
417 | return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
418 | }
419 |
420 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)
421 | {
422 | init_message(connection);
423 |
424 | if(topic == NULL || topic[0] == '\0')
425 | return fail_message(connection);
426 |
427 | if((*message_id = append_message_id(connection, 0)) == 0)
428 | return fail_message(connection);
429 |
430 | if(append_string(connection, topic, strlen(topic)) < 0)
431 | return fail_message(connection);
432 |
433 | if(connection->message.length + 1 > connection->buffer_length)
434 | return fail_message(connection);
435 | connection->buffer[connection->message.length++] = qos;
436 |
437 | return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
438 | }
439 |
440 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
441 | {
442 | init_message(connection);
443 |
444 | if(topic == NULL || topic[0] == '\0')
445 | return fail_message(connection);
446 |
447 | if((*message_id = append_message_id(connection, 0)) == 0)
448 | return fail_message(connection);
449 |
450 | if(append_string(connection, topic, strlen(topic)) < 0)
451 | return fail_message(connection);
452 |
453 | return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0);
454 | }
455 |
456 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection)
457 | {
458 | init_message(connection);
459 | return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);
460 | }
461 |
462 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection)
463 | {
464 | init_message(connection);
465 | return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);
466 | }
467 |
468 | mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection)
469 | {
470 | init_message(connection);
471 | return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);
472 | }
473 |
--------------------------------------------------------------------------------
/mqtt/proto.c:
--------------------------------------------------------------------------------
1 | #include "proto.h"
2 | #include "ringbuf.h"
3 | I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize)
4 | {
5 | parser->buf = buf;
6 | parser->bufSize = bufSize;
7 | parser->dataLen = 0;
8 | parser->callback = completeCallback;
9 | parser->isEsc = 0;
10 | return 0;
11 | }
12 |
13 | I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value)
14 | {
15 | switch(value){
16 | case 0x7D:
17 | parser->isEsc = 1;
18 | break;
19 |
20 | case 0x7E:
21 | parser->dataLen = 0;
22 | parser->isEsc = 0;
23 | parser->isBegin = 1;
24 | break;
25 |
26 | case 0x7F:
27 | if (parser->callback != NULL)
28 | parser->callback();
29 | parser->isBegin = 0;
30 | return 0;
31 | break;
32 |
33 | default:
34 | if(parser->isBegin == 0) break;
35 |
36 | if(parser->isEsc){
37 | value ^= 0x20;
38 | parser->isEsc = 0;
39 | }
40 |
41 | if(parser->dataLen < parser->bufSize)
42 | parser->buf[parser->dataLen++] = value;
43 |
44 | break;
45 | }
46 | return -1;
47 | }
48 |
49 | I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len)
50 | {
51 | while(len--)
52 | PROTO_ParseByte(parser, *buf++);
53 |
54 | return 0;
55 | }
56 | I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, U8 *bufOut, U16* len, U16 maxBufLen)
57 | {
58 | U8 c;
59 |
60 | PROTO_PARSER proto;
61 | PROTO_Init(&proto, NULL, bufOut, maxBufLen);
62 | while(RINGBUF_Get(rb, &c) == 0){
63 | if(PROTO_ParseByte(&proto, c) == 0){
64 | *len = proto.dataLen;
65 | return 0;
66 | }
67 | }
68 | return -1;
69 | }
70 | I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize)
71 | {
72 | U16 i = 2;
73 | U16 len = *(U16*) packet;
74 |
75 | if (bufSize < 1) return -1;
76 |
77 | *buf++ = 0x7E;
78 | bufSize--;
79 |
80 | while (len--) {
81 | switch (*packet) {
82 | case 0x7D:
83 | case 0x7E:
84 | case 0x7F:
85 | if (bufSize < 2) return -1;
86 | *buf++ = 0x7D;
87 | *buf++ = *packet++ ^ 0x20;
88 | i += 2;
89 | bufSize -= 2;
90 | break;
91 | default:
92 | if (bufSize < 1) return -1;
93 | *buf++ = *packet++;
94 | i++;
95 | bufSize--;
96 | break;
97 | }
98 | }
99 |
100 | if (bufSize < 1) return -1;
101 | *buf++ = 0x7F;
102 |
103 | return i;
104 | }
105 |
106 | I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len)
107 | {
108 | U16 i = 2;
109 | if(RINGBUF_Put(rb, 0x7E) == -1) return -1;
110 | while (len--) {
111 | switch (*packet) {
112 | case 0x7D:
113 | case 0x7E:
114 | case 0x7F:
115 | if(RINGBUF_Put(rb, 0x7D) == -1) return -1;
116 | if(RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1;
117 | i += 2;
118 | break;
119 | default:
120 | if(RINGBUF_Put(rb, *packet++) == -1) return -1;
121 | i++;
122 | break;
123 | }
124 | }
125 | if(RINGBUF_Put(rb, 0x7F) == -1) return -1;
126 |
127 | return i;
128 | }
129 |
130 |
--------------------------------------------------------------------------------
/mqtt/queue.c:
--------------------------------------------------------------------------------
1 | /* str_queue.c
2 | *
3 | * Copyright (c) 2014-2015, Tuan PM
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 | #include "queue.h"
31 |
32 | #include "user_interface.h"
33 | #include "osapi.h"
34 | #include "os_type.h"
35 | #include "mem.h"
36 | #include "proto.h"
37 | void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize)
38 | {
39 | queue->buf = (uint8_t*)os_zalloc(bufferSize);
40 | RINGBUF_Init(&queue->rb, queue->buf, bufferSize);
41 | }
42 | int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len)
43 | {
44 | return PROTO_AddRb(&queue->rb, buffer, len);
45 | }
46 | int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen)
47 | {
48 |
49 | return PROTO_ParseRb(&queue->rb, buffer, len, maxLen);
50 | }
51 |
52 | BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue)
53 | {
54 | if(queue->rb.fill_cnt<=0)
55 | return TRUE;
56 | return FALSE;
57 | }
58 |
--------------------------------------------------------------------------------
/mqtt/ringbuf.c:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * Ring Buffer library
4 | */
5 |
6 | #include "ringbuf.h"
7 |
8 |
9 | /**
10 | * \brief init a RINGBUF object
11 | * \param r pointer to a RINGBUF object
12 | * \param buf pointer to a byte array
13 | * \param size size of buf
14 | * \return 0 if successfull, otherwise failed
15 | */
16 | I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size)
17 | {
18 | if(r == NULL || buf == NULL || size < 2) return -1;
19 |
20 | r->p_o = r->p_r = r->p_w = buf;
21 | r->fill_cnt = 0;
22 | r->size = size;
23 |
24 | return 0;
25 | }
26 | /**
27 | * \brief put a character into ring buffer
28 | * \param r pointer to a ringbuf object
29 | * \param c character to be put
30 | * \return 0 if successfull, otherwise failed
31 | */
32 | I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c)
33 | {
34 | if(r->fill_cnt>=r->size)return -1; // ring buffer is full, this should be atomic operation
35 |
36 |
37 | r->fill_cnt++; // increase filled slots count, this should be atomic operation
38 |
39 |
40 | *r->p_w++ = c; // put character into buffer
41 |
42 | if(r->p_w >= r->p_o + r->size) // rollback if write pointer go pass
43 | r->p_w = r->p_o; // the physical boundary
44 |
45 | return 0;
46 | }
47 | /**
48 | * \brief get a character from ring buffer
49 | * \param r pointer to a ringbuf object
50 | * \param c read character
51 | * \return 0 if successfull, otherwise failed
52 | */
53 | I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c)
54 | {
55 | if(r->fill_cnt<=0)return -1; // ring buffer is empty, this should be atomic operation
56 |
57 |
58 | r->fill_cnt--; // decrease filled slots count
59 |
60 |
61 | *c = *r->p_r++; // get the character out
62 |
63 | if(r->p_r >= r->p_o + r->size) // rollback if write pointer go pass
64 | r->p_r = r->p_o; // the physical boundary
65 |
66 | return 0;
67 | }
68 |
--------------------------------------------------------------------------------
/mqtt/utils.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Tuan PM
3 | * Email: tuanpm@live.com
4 | *
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | * 2. Redistributions in binary form must reproduce the above copyright
14 | * notice, this list of conditions and the following disclaimer in the
15 | * documentation and/or other materials provided with the distribution.
16 | * 3. Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived
18 | * from this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 | * POSSIBILITY OF SUCH DAMAGE.
31 | *
32 | */
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include "utils.h"
39 |
40 |
41 | uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str)
42 | {
43 | uint8_t segs = 0; /* Segment count. */
44 | uint8_t chcnt = 0; /* Character count within segment. */
45 | uint8_t accum = 0; /* Accumulator for segment. */
46 | /* Catch NULL pointer. */
47 | if (str == 0)
48 | return 0;
49 | /* Process every character in string. */
50 |
51 | while (*str != '\0') {
52 | /* Segment changeover. */
53 |
54 | if (*str == '.') {
55 | /* Must have some digits in segment. */
56 | if (chcnt == 0)
57 | return 0;
58 | /* Limit number of segments. */
59 | if (++segs == 4)
60 | return 0;
61 | /* Reset segment values and restart loop. */
62 | chcnt = accum = 0;
63 | str++;
64 | continue;
65 | }
66 |
67 | /* Check numeric. */
68 | if ((*str < '0') || (*str > '9'))
69 | return 0;
70 |
71 | /* Accumulate and check segment. */
72 |
73 | if ((accum = accum * 10 + *str - '0') > 255)
74 | return 0;
75 | /* Advance other segment specific stuff and continue loop. */
76 |
77 | chcnt++;
78 | str++;
79 | }
80 |
81 | /* Check enough segments and enough characters in last segment. */
82 |
83 | if (segs != 3)
84 | return 0;
85 | if (chcnt == 0)
86 | return 0;
87 | /* Address okay. */
88 |
89 | return 1;
90 | }
91 | uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip)
92 | {
93 |
94 | /* The count of the number of bytes processed. */
95 | int i;
96 | /* A pointer to the next digit to process. */
97 | const char * start;
98 |
99 | start = str;
100 | for (i = 0; i < 4; i++) {
101 | /* The digit being processed. */
102 | char c;
103 | /* The value of this byte. */
104 | int n = 0;
105 | while (1) {
106 | c = * start;
107 | start++;
108 | if (c >= '0' && c <= '9') {
109 | n *= 10;
110 | n += c - '0';
111 | }
112 | /* We insist on stopping at "." if we are still parsing
113 | the first, second, or third numbers. If we have reached
114 | the end of the numbers, we will allow any character. */
115 | else if ((i < 3 && c == '.') || i == 3) {
116 | break;
117 | }
118 | else {
119 | return 0;
120 | }
121 | }
122 | if (n >= 256) {
123 | return 0;
124 | }
125 | ((uint8_t*)ip)[i] = n;
126 | }
127 | return 1;
128 |
129 | }
130 | uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s)
131 | {
132 | uint32_t value = 0, digit;
133 | int8_t c;
134 |
135 | while((c = *s++)){
136 | if('0' <= c && c <= '9')
137 | digit = c - '0';
138 | else if('A' <= c && c <= 'F')
139 | digit = c - 'A' + 10;
140 | else if('a' <= c && c<= 'f')
141 | digit = c - 'a' + 10;
142 | else break;
143 |
144 | value = (value << 4) | digit;
145 | }
146 |
147 | return value;
148 | }
149 |
150 |
--------------------------------------------------------------------------------
/roomba/mqtt_commands.h:
--------------------------------------------------------------------------------
1 | /*
2 | * mqtt_commands.h
3 | *
4 | * Created on: Jul 22, 2015
5 | * Author: marcok
6 | */
7 |
8 | #ifndef MQTT_COMMANDS_H_
9 | #define MQTT_COMMANDS_H_
10 |
11 | #define MQTT_ROOMBA_CMD_TOPIC "pit/roomba/cmd"
12 | #define MQTT_ROOMBA_STATUS_TOPIC "pit/roomba/state"
13 |
14 | #define MQTT_ROOMBA_CMD_WAKEUP "wakeup"
15 | #define MQTT_ROOMBA_CMD_SLEEP "sleep"
16 | #define MQTT_ROOMBA_CMD_DOCK "dock"
17 | #define MQTT_ROOMBA_CMD_CLEAN "clean"
18 | #define MQTT_ROOMBA_CMD_SPOT_CLEAN "spot_clean"
19 | #define MQTT_ROOMBA_CMD_MOTORS "motors"
20 | #define MQTT_ROOMBA_CMD_PLAY_SONG "play"
21 |
22 | #endif /* MQTT_COMMANDS_H_ */
23 |
--------------------------------------------------------------------------------
/roomba/roomba.c:
--------------------------------------------------------------------------------
1 | /*
2 | * roomba.c
3 | *
4 | * Created on: Jul 22, 2015
5 | * Author: marcok
6 | */
7 |
8 | #include "osapi.h"
9 |
10 | #include "roomba_opcodes.h"
11 | #include "roomba.h"
12 | #include "uart.h"
13 |
14 | void roomba_send_command(char command){
15 | uart_tx_one_char(command);
16 | os_delay_us(1000);
17 | }
18 |
19 | void roomba_startup(void) {
20 | os_printf("startup");
21 | roomba_send_command(START);
22 | roomba_send_command(SAFE);
23 |
24 | os_delay_us(30000);
25 | }
26 |
27 | void roomba_wakeup(void) {
28 | unsigned char j;
29 |
30 | // Wakeup roomba
31 | roomba_startup();
32 | gpio_output_set(0, ROOMBA_WAKEUP_PIN, ROOMBA_WAKEUP_PIN, 0); // ESP01 io2 Low
33 |
34 | for (j = 0; j < 50; j++) // 0,5 Sekunden
35 | {
36 | //feedwdt();
37 | os_delay_us(10000); // 10ms
38 | }
39 | gpio_output_set(ROOMBA_WAKEUP_PIN, 0, ROOMBA_WAKEUP_PIN, 0); // ESP01 io2 High
40 |
41 | for (j = 0; j < 100; j++) // 1 Sekunde
42 | {
43 | //feedwdt();
44 | os_delay_us(10000); //10ms
45 | }
46 | roomba_startup();
47 | }
48 |
49 | void roomba_dock(void) {
50 | roomba_startup();
51 | roomba_send_command(DOCK);
52 | }
53 |
54 | void roomba_clean(void) {
55 | roomba_startup();
56 | roomba_send_command(CLEAN);
57 | }
58 |
59 | void roomba_spot_clean(void){
60 | roomba_startup();
61 | roomba_send_command(SPOT);
62 | }
63 |
64 | void roomba_sleep(void) {
65 | roomba_startup();
66 | roomba_send_command(POWER);
67 | }
68 |
69 | #if 0
70 | void roomba_motors(char * data){
71 | roomba_startup();
72 | roomba_send_command(MOTORS);
73 | roomba_send_command(data);
74 | }
75 |
76 | void roomba_go_forward(void) {
77 | roomba_drive(speed, 0x8000);
78 | }
79 |
80 | void roomba_go_backward(void) {
81 | roomba_drive(-speed, 0x8000);
82 | }
83 |
84 | void roomba_spin_right(void) {
85 | roomba_drive(speed, 0xffff);
86 | }
87 |
88 | void roomba_spin_left(void) {
89 | roomba_drive(speed, 1);
90 | }
91 |
92 | void roomba_stop(void) {
93 | roomba_drive(0, 0);
94 | }
95 |
96 | void roomba_drive(unsigned int velocity, unsigned int radius) {
97 | roomba_startup();
98 | uart_tx_one_char(DRIVE);
99 | uart_tx_one_char(velocity / 256);
100 | uart_tx_one_char(velocity);
101 | uart_tx_one_char(radius / 256);
102 | uart_tx_one_char(radius);
103 | }
104 | #endif
105 |
106 | void roomba_program_songs(){
107 | roomba_startup();
108 |
109 | roomba_send_command(SONG); //define a song
110 | roomba_send_command(SONG_GENERAL_LEE); //at position 0
111 | roomba_send_command(12); //song is 12 notes long
112 |
113 | roomba_send_command(64);
114 | roomba_send_command(8);
115 | roomba_send_command(62);
116 | roomba_send_command(8);
117 |
118 | roomba_send_command(60);
119 | roomba_send_command(32);
120 | roomba_send_command(60);
121 | roomba_send_command(32);
122 | roomba_send_command(60);
123 | roomba_send_command(16);
124 | roomba_send_command(61);
125 | roomba_send_command(16);
126 | roomba_send_command(62);
127 | roomba_send_command(16);
128 | roomba_send_command(63);
129 | roomba_send_command(16);
130 |
131 | roomba_send_command(64);
132 | roomba_send_command(32);
133 | roomba_send_command(64);
134 | roomba_send_command(32);
135 | roomba_send_command(64);
136 | roomba_send_command(32);
137 | roomba_send_command(62);
138 | roomba_send_command(32);
139 | }
140 |
141 | void roomba_play_dixie_song(){
142 | roomba_startup();
143 |
144 | roomba_send_command(PLAY); //play song
145 | roomba_send_command(SONG_GENERAL_LEE); //song
146 | }
147 |
--------------------------------------------------------------------------------
/roomba/roomba.h:
--------------------------------------------------------------------------------
1 | #ifndef ROOMBA_H
2 | #define ROOMBA_H
3 |
4 | #include "eagle_soc.h"
5 |
6 | #define ROOMBA_WAKEUP_PIN BIT2
7 |
8 | void roomba_startup(void);
9 | void roomba_wakeup(void);
10 | void roomba_dock(void);
11 | void roomba_clean(void);
12 | void roomba_sleep(void);
13 | void roomba_motors(char *);
14 | void roomba_play_dixie_song(void);
15 | void roomba_program_songs(void);
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/roomba/roomba_opcodes.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: roomba.h
3 | * Author: admin
4 | *
5 | * Created on 13 November 2014, 07:47
6 | */
7 |
8 | #ifndef ROOMBA_OPCODES_H
9 | #define ROOMBA_OPCODES_H
10 |
11 | // Roomba ROI opcodes
12 | #define START 128 // 0
13 | #define BAUD 129 // 1
14 | //#define CONTROL 130 // 0 DEPRECATED!
15 | #define SAFE 131 // 0
16 | #define FULL 132 // 0
17 | #define POWER 133 // 0
18 | #define SPOT 134 // 0
19 | #define CLEAN 135 // 0
20 | #define MAX 136 // 0
21 | #define DRIVE 137 // 4
22 | #define MOTORS 138 // 1
23 | #define LEDS 139 // 3
24 | #define SONG 140 // 2N+2
25 | #define PLAY 141 // 1
26 | #define SENSORS 142 // 1
27 | #define DOCK 143 // 0
28 | #define PWMMOTORS 144 // 3
29 | #define DRIVEWHEELS 145 // 4
30 | #define DRIVEPWM 146 // 4
31 | #define STREAM 148 // N+1
32 | #define QUERYLIST 149 // N+1
33 | #define STOPSTARTSTREAM 150 // 1
34 | #define SCRIPT 152
35 | #define PLAYSCRIPT 153
36 | #define SCHEDULINGLEDS 162 // 2
37 | #define DIGITLEDSRAW 163 // 4
38 | #define DIGITLEDSASCII 164 // 4
39 | #define BUTTONSCMD 165 // 1
40 | #define SCHEDULE 167 // n
41 | #define SETDAYTIME 168 // 3
42 |
43 | // own opcodes
44 | /*
45 | #define WAKEUP 200 // DD Signal auf low
46 | #define goDistanceForward 201 // 2 distance in cm 16 Bit
47 | #define goDistanceBackward 202 // 2 distance in cm 16 Bit
48 | #define turnRight 203 // 2 degrees 16Bit
49 | #define turnLeft 204 // 2 degrees 16Bit
50 | #define mySTOP 205
51 | #define myDOCK 206
52 | #define myCLEAN 207
53 | #define myReset 210
54 | #define mySong 211
55 | */
56 | #define SONG_GENERAL_LEE 0 //sound the general lee horn!
57 |
58 | // Sensors
59 | #define SENSORS_ALL 0
60 | #define SENSORS_PHYSICAL 1
61 | #define SENSORS_INTERNAL 2
62 | #define SENSORS_POWER 3
63 |
64 | // speed
65 | #define default_speed 200
66 |
67 |
68 | // offsets into sensor_bytes data
69 | #define SENSORS_ALL_BUMPSWHEELDROPS 0
70 | #define SENSORS_ALL_WALL 1
71 | #define SENSORS_ALL_CLIFFLEFT 2
72 | #define SENSORS_ALL_CLIFFFRONTLEFT 3
73 | #define SENSORS_ALL_CLIFFFRONTRIGHT 4
74 | #define SENSORS_ALL_CLIFFRIGHT 5
75 | #define SENSORS_ALL_VIRTUALWALL 6
76 | #define SENSORS_ALL_MOTOROVERCURRENTS 7
77 | #define SENSORS_ALL_DIRTLEFT 8
78 | #define SENSORS_ALL_DIRTRIGHT 9
79 | #define SENSORS_ALL_REMOTEOPCODE 10
80 | #define SENSORS_ALL_BUTTONS 11
81 | #define SENSORS_ALL_DISTANCE_HI 12
82 | #define SENSORS_ALL_DISTANCE_LO 13
83 | #define SENSORS_ALL_ANGLE_HI 14
84 | #define SENSORS_ALL_ANGLE_LO 15
85 | #define SENSORS_ALL_CHARGINGSTATE 16
86 | #define SENSORS_ALL_VOLTAGE_HI 17
87 | #define SENSORS_ALL_VOLTAGE_LO 18
88 | #define SENSORS_ALL_CURRENT_HI 19
89 | #define SENSORS_ALL_CURRENT_LO 20
90 | #define SENSORS_ALL_TEMPERATURE 21
91 | #define SENSORS_ALL_CHARGE_HI 22
92 | #define SENSORS_ALL_CHARGE_LO 23
93 | #define SENSORS_ALL_CAPACITY_HI 24
94 | #define SENSORS_ALL_CAPACITY_LO 25
95 |
96 | #define SENSORS_POWER_CHARGINGSTATE 0
97 | #define SENSORS_POWER_VOLTAGE_HI 1
98 | #define SENSORS_POWER_VOLTAGE_LO 2
99 | #define SENSORS_POWER_CURRENT_HI 3
100 | #define SENSORS_POWER_CURRENT_LO 4
101 | #define SENSORS_POWER_TEMPERATURE 5
102 | #define SENSORS_POWER_CHARGE_HI 6
103 | #define SENSORS_POWER_CHARGE_LO 7
104 | #define SENSORS_POWER_CAPACITY_HI 8
105 | #define SENSORS_POWER_CAPACITY_LO 9
106 |
107 | // bitmasks for various thingems
108 | #define WHEELDROP_MASK 0x1C
109 | #define BUMP_MASK 0x03
110 | #define BUMPRIGHT_MASK 0x01
111 | #define BUMPLEFT_MASK 0x02
112 | #define WHEELDROPRIGHT_MASK 0x04
113 | #define WHEELDROPLEFT_MASK 0x08
114 | #define WHEELDROPCENT_MASK 0x10
115 |
116 | #define MOVERDRIVELEFT_MASK 0x10
117 | #define MOVERDRIVERIGHT_MASK 0x08
118 | #define MOVERMAINBRUSH_MASK 0x04
119 | #define MOVERVACUUM_MASK 0x02
120 | #define MOVERSIDEBRUSH_MASK 0x01
121 |
122 | #define POWERBUTTON_MASK 0x08
123 | #define SPOTBUTTON_MASK 0x04
124 | #define CLEANBUTTON_MASK 0x02
125 | #define MAXBUTTON_MASK 0x01
126 |
127 | #endif /* ROOMBA_H */
128 |
129 |
--------------------------------------------------------------------------------
/tools/.gitattributes:
--------------------------------------------------------------------------------
1 | # Enforce Unix newlines
2 | *.css text eol=lf
3 | *.html text eol=lf
4 | *.js text eol=lf
5 | *.json text eol=lf
6 | *.less text eol=lf
7 | *.md text eol=lf
8 | *.svg text eol=lf
9 | *.yml text eol=lf
10 | *.py text eol=lf
11 | *.sh text eol=lf
12 |
--------------------------------------------------------------------------------
/tools/esptool.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # ESP8266 ROM Bootloader Utility
4 | # https://github.com/themadinventor/esptool
5 | #
6 | # Copyright (C) 2014 Fredrik Ahlberg
7 | #
8 | # This program is free software; you can redistribute it and/or modify it under
9 | # the terms of the GNU General Public License as published by the Free Software
10 | # Foundation; either version 2 of the License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful, but WITHOUT
13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License along with
17 | # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
18 | # Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 |
20 | import sys
21 | import struct
22 | import serial
23 | import math
24 | import time
25 | import argparse
26 | import os
27 | import subprocess
28 |
29 | class ESPROM:
30 |
31 | # These are the currently known commands supported by the ROM
32 | ESP_FLASH_BEGIN = 0x02
33 | ESP_FLASH_DATA = 0x03
34 | ESP_FLASH_END = 0x04
35 | ESP_MEM_BEGIN = 0x05
36 | ESP_MEM_END = 0x06
37 | ESP_MEM_DATA = 0x07
38 | ESP_SYNC = 0x08
39 | ESP_WRITE_REG = 0x09
40 | ESP_READ_REG = 0x0a
41 |
42 | # Maximum block sized for RAM and Flash writes, respectively.
43 | ESP_RAM_BLOCK = 0x1800
44 | ESP_FLASH_BLOCK = 0x100
45 |
46 | # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want.
47 | ESP_ROM_BAUD = 115200
48 |
49 | # First byte of the application image
50 | ESP_IMAGE_MAGIC = 0xe9
51 |
52 | # Initial state for the checksum routine
53 | ESP_CHECKSUM_MAGIC = 0xef
54 |
55 | # OTP ROM addresses
56 | ESP_OTP_MAC0 = 0x3ff00050
57 | ESP_OTP_MAC1 = 0x3ff00054
58 |
59 | def __init__(self, port = 0, baud = ESP_ROM_BAUD):
60 | self._port = serial.Serial(port, baud)
61 |
62 | """ Read bytes from the serial port while performing SLIP unescaping """
63 | def read(self, length = 1):
64 | b = ''
65 | while len(b) < length:
66 | c = self._port.read(1)
67 | if c == '\xdb':
68 | c = self._port.read(1)
69 | if c == '\xdc':
70 | b = b + '\xc0'
71 | elif c == '\xdd':
72 | b = b + '\xdb'
73 | else:
74 | raise Exception('Invalid SLIP escape')
75 | else:
76 | b = b + c
77 | return b
78 |
79 | """ Write bytes to the serial port while performing SLIP escaping """
80 | def write(self, packet):
81 | buf = '\xc0'
82 | for b in packet:
83 | if b == '\xc0':
84 | buf += '\xdb\xdc'
85 | elif b == '\xdb':
86 | buf += '\xdb\xdd'
87 | else:
88 | buf += b
89 | buf += '\xc0'
90 | self._port.write(buf)
91 |
92 | """ Calculate checksum of a blob, as it is defined by the ROM """
93 | @staticmethod
94 | def checksum(data, state = ESP_CHECKSUM_MAGIC):
95 | for b in data:
96 | state ^= ord(b)
97 | return state
98 |
99 | """ Send a request and read the response """
100 | def command(self, op = None, data = None, chk = 0):
101 | if op:
102 | # Construct and send request
103 | pkt = struct.pack(' 16:
225 | raise Exception('Invalid firmware image')
226 |
227 | for i in xrange(segments):
228 | (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536:
230 | raise Exception('Suspicious segment %x,%d' % (offset, size))
231 | self.segments.append((offset, size, f.read(size)))
232 |
233 | # Skip the padding. The checksum is stored in the last byte so that the
234 | # file is a multiple of 16 bytes.
235 | align = 15-(f.tell() % 16)
236 | f.seek(align, 1)
237 |
238 | self.checksum = ord(f.read(1))
239 |
240 | def add_segment(self, addr, data):
241 | # Data should be aligned on word boundary
242 | l = len(data)
243 | if l % 4:
244 | data += b"\x00" * (4 - l % 4)
245 | self.segments.append((addr, len(data), data))
246 |
247 | def save(self, filename):
248 | f = file(filename, 'wb')
249 | f.write(struct.pack(' 0:
397 | esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq)
398 | data = data[esp.ESP_RAM_BLOCK:]
399 | seq += 1
400 | print 'done!'
401 |
402 | print 'All segments done, executing at %08x' % image.entrypoint
403 | esp.mem_finish(image.entrypoint)
404 |
405 | elif args.operation == 'read_mem':
406 | print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))
407 |
408 | elif args.operation == 'write_mem':
409 | esp.write_reg(args.address, args.value, args.mask, 0)
410 | print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)
411 |
412 | elif args.operation == 'dump_mem':
413 | f = file(args.filename, 'wb')
414 | for i in xrange(args.size/4):
415 | d = esp.read_reg(args.address+(i*4))
416 | f.write(struct.pack(' 0:
434 | print '\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks),
435 | sys.stdout.flush()
436 | block = image[0:esp.ESP_FLASH_BLOCK]
437 | block = block + '\xe0' * (esp.ESP_FLASH_BLOCK-len(block))
438 | esp.flash_block(block, seq)
439 | image = image[esp.ESP_FLASH_BLOCK:]
440 | seq += 1
441 | print
442 | print '\nLeaving...'
443 | esp.flash_finish(False)
444 |
445 | elif args.operation == 'run':
446 | esp.run()
447 |
448 | elif args.operation == 'image_info':
449 | image = ESPFirmwareImage(args.filename)
450 | print ('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set'
451 | print '%d segments' % len(image.segments)
452 | print
453 | checksum = ESPROM.ESP_CHECKSUM_MAGIC
454 | for (idx, (offset, size, data)) in enumerate(image.segments):
455 | print 'Segment %d: %5d bytes at %08x' % (idx+1, size, offset)
456 | checksum = ESPROM.checksum(data, checksum)
457 | print
458 | print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!')
459 |
460 | elif args.operation == 'make_image':
461 | image = ESPFirmwareImage()
462 | if len(args.segfile) == 0:
463 | raise Exception('No segments specified')
464 | if len(args.segfile) != len(args.segaddr):
465 | raise Exception('Number of specified files does not match number of specified addresses')
466 | for (seg, addr) in zip(args.segfile, args.segaddr):
467 | data = file(seg, 'rb').read()
468 | image.add_segment(addr, data)
469 | image.entrypoint = args.entrypoint
470 | image.save(args.output)
471 |
472 | elif args.operation == 'elf2image':
473 | if args.output is None:
474 | args.output = args.input + '-'
475 | e = ELFFile(args.input)
476 | image = ESPFirmwareImage()
477 | image.entrypoint = e.get_symbol_addr("call_user_start")
478 | for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")):
479 | data = e.load_section(section)
480 | image.add_segment(e.get_symbol_addr(start), data)
481 | image.save(args.output + "0x00000.bin")
482 | data = e.load_section(".irom0.text")
483 | off = e.get_symbol_addr("_irom0_text_start") - 0x40200000
484 | assert off >= 0
485 | f = open(args.output + "0x%05x.bin" % off, "wb")
486 | f.write(data)
487 | f.close()
488 |
489 | elif args.operation == 'read_mac':
490 | mac0 = esp.read_reg(esp.ESP_OTP_MAC0)
491 | mac1 = esp.read_reg(esp.ESP_OTP_MAC1)
492 | print 'MAC: 18:fe:34:%02x:%02x:%02x' % ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
493 |
--------------------------------------------------------------------------------
/tools/makefile.sh:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Generate the certificates and keys for encrypt.
4 | #
5 |
6 | # set default cert for use in the client
7 | xxd -i client.cer | sed -e \
8 | "s/client_cer/default_certificate/" > cert.h
9 | # set default key for use in the server
10 | xxd -i server.key_1024 | sed -e \
11 | "s/server_key_1024/default_private_key/" > private_key.h
12 |
--------------------------------------------------------------------------------
/user/Makefile:
--------------------------------------------------------------------------------
1 |
2 | #############################################################
3 | # Required variables for each makefile
4 | # Discard this section from all parent makefiles
5 | # Expected variables (with automatic defaults):
6 | # CSRCS (all "C" files in the dir)
7 | # SUBDIRS (all subdirs with a Makefile)
8 | # GEN_LIBS - list of libs to be generated ()
9 | # GEN_IMAGES - list of images to be generated ()
10 | # COMPONENTS_xxx - a list of libs/objs in the form
11 | # subdir/lib to be extracted and rolled up into
12 | # a generated lib/image xxx.a ()
13 | #
14 | ifndef PDIR
15 | GEN_LIBS = libuser.a
16 | endif
17 |
18 |
19 | #############################################################
20 | # Configuration i.e. compile options etc.
21 | # Target specific stuff (defines etc.) goes in here!
22 | # Generally values applying to a tree are captured in the
23 | # makefile at its root level - these are then overridden
24 | # for a subtree within the makefile rooted therein
25 | #
26 | #DEFINES +=
27 |
28 | #############################################################
29 | # Recursion Magic - Don't touch this!!
30 | #
31 | # Each subtree potentially has an include directory
32 | # corresponding to the common APIs applicable to modules
33 | # rooted at that subtree. Accordingly, the INCLUDE PATH
34 | # of a module can only contain the include directories up
35 | # its parent path, and not its siblings
36 | #
37 | # Required for each makefile to inherit from the parent
38 | #
39 |
40 | INCLUDES := $(INCLUDES) -I $(PDIR)include
41 | INCLUDES += -I ./
42 | PDIR := ../$(PDIR)
43 | sinclude $(PDIR)Makefile
44 |
45 |
--------------------------------------------------------------------------------
/user/user_main.c:
--------------------------------------------------------------------------------
1 | /* main.c -- MQTT client example
2 | *
3 | * Copyright (c) 2014-2015, Tuan PM
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 | #include "ets_sys.h"
31 | #include "driver/uart.h"
32 | #include "osapi.h"
33 | #include "mqtt.h"
34 | #include "wifi.h"
35 | #include "config.h"
36 | #include "debug.h"
37 | #include "gpio.h"
38 | #include "user_interface.h"
39 | #include "mem.h"
40 | #include "eagle_soc.h"
41 | //#include "stdio.h"
42 |
43 | #include "roomba.h"
44 | #include "mqtt_commands.h"
45 |
46 | #define DEVICE_ID "123"
47 | #define DEVICE_NAME "roomba_woonkamer"
48 |
49 |
50 | MQTT_Client mqttClient;
51 |
52 | void ICACHE_FLASH_ATTR publish_roomba_status(MQTT_Client* client, char * message){
53 | MQTT_Publish(client, MQTT_ROOMBA_STATUS_TOPIC, message, strlen(message), 0, 0);
54 | }
55 |
56 | void ICACHE_FLASH_ATTR mqtt_advertise(MQTT_Client* client){
57 | struct ip_info ipconfig;
58 | wifi_get_ip_info(STATION_IF, &ipconfig);
59 |
60 | //assemble advertise string
61 | char advertise_str[] = "advertise 123 huiskamer 192.168.1.101";
62 |
63 | //sprintf(advertise_str, "advertise %s %s %s", DEVICE_ID, DEVICE_NAME, ipconfig.ip);
64 |
65 | MQTT_Publish(client, MQTT_ROOMBA_STATUS_TOPIC, advertise_str, strlen(advertise_str), 0, 0);
66 |
67 | }
68 |
69 | void ICACHE_FLASH_ATTR wifiConnectCb(uint8_t status)
70 | {
71 | if(status == STATION_GOT_IP){
72 | MQTT_Connect(&mqttClient);
73 | } else {
74 | MQTT_Disconnect(&mqttClient);
75 | }
76 | }
77 | void ICACHE_FLASH_ATTR mqttConnectedCb(uint32_t *args)
78 | {
79 | MQTT_Client* client = (MQTT_Client*)args;
80 | INFO("MQTT: Connected\r\n");
81 |
82 | MQTT_Subscribe(client, MQTT_ROOMBA_CMD_TOPIC, 0);
83 |
84 | mqtt_advertise(client);
85 | }
86 |
87 | void mqttDisconnectedCb(uint32_t *args)
88 | {
89 | MQTT_Client* client = (MQTT_Client*)args;
90 | INFO("MQTT: Disconnected\r\n");
91 | }
92 |
93 | void mqttPublishedCb(uint32_t *args)
94 | {
95 | MQTT_Client* client = (MQTT_Client*)args;
96 | INFO("MQTT: Published\r\n");
97 | }
98 |
99 | bool strEquals(const char *str, const char *match)
100 | {
101 | return (strcmp(str, match) == 0);
102 |
103 | }
104 |
105 | bool strStartsWith(const char *str, const char *pre)
106 | {
107 | size_t lenpre = strlen(pre),
108 | lenstr = strlen(str);
109 | return lenstr < lenpre ? false : strncmp(pre, str, lenpre) == 0;
110 | }
111 |
112 | void get_command(char * buff, char ** command)
113 | {
114 | char *p = buff;
115 |
116 | while( p != NULL ){
117 | p = strchr(p, ' ');
118 |
119 | if( p != NULL){
120 | // Found the delimiter, get next char
121 | p++;
122 | *command = p;
123 | break;
124 | }else{
125 | p++;
126 | }
127 | }
128 | }
129 |
130 |
131 | void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)
132 | {
133 | char *topicBuf = (char*)os_zalloc(topic_len+1);
134 | char *dataBuf = (char*)os_zalloc(data_len+1);
135 |
136 | MQTT_Client* client = (MQTT_Client*)args;
137 |
138 | os_memcpy(topicBuf, topic, topic_len);
139 | topicBuf[topic_len] = 0;
140 |
141 | os_memcpy(dataBuf, data, data_len);
142 | dataBuf[data_len] = 0;
143 |
144 | INFO("Receive topic: %s, data: %s \r\n", topicBuf, dataBuf);
145 |
146 | if(strEquals(topicBuf, MQTT_ROOMBA_CMD_TOPIC)){
147 | //compare the first token with known commands
148 | if(strEquals(dataBuf, MQTT_ROOMBA_CMD_WAKEUP)){
149 | roomba_wakeup();
150 | }else if(strEquals(dataBuf, MQTT_ROOMBA_CMD_CLEAN)){
151 | roomba_clean();
152 | publish_roomba_status(client, "cleaning");
153 | }else if(strEquals(dataBuf, MQTT_ROOMBA_CMD_SPOT_CLEAN)){
154 | roomba_spot_clean();
155 | publish_roomba_status(client, "spot_cleaning");
156 | }else if(strEquals(dataBuf, MQTT_ROOMBA_CMD_DOCK)){
157 | roomba_dock();
158 | publish_roomba_status(client, "docked");
159 | //todo when are we docked??
160 | }else if(strEquals(dataBuf, MQTT_ROOMBA_CMD_SLEEP)){
161 | roomba_sleep();
162 | publish_roomba_status(client, "sleeping");
163 | }else if(strStartsWith(dataBuf, MQTT_ROOMBA_CMD_PLAY_SONG)){
164 | //make sure the songs are programmed
165 | roomba_program_songs();
166 |
167 | roomba_play_dixie_song();
168 | }else{
169 | os_printf("Unknown command received: %s at topic %s\n", dataBuf, topicBuf);
170 | }
171 | }
172 |
173 | os_free(topicBuf);
174 | os_free(dataBuf);
175 | }
176 |
177 |
178 | void user_init(void)
179 | {
180 | system_set_os_print(0);
181 |
182 | uart_init(BIT_RATE_115200, BIT_RATE_115200);
183 | os_delay_us(1000000);
184 |
185 | CFG_Load();
186 |
187 | // Initialize the GPIO subsystem.
188 | gpio_init();
189 |
190 | //Set GPIO2 to output mode
191 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
192 | //Set GPIO2 high
193 | gpio_output_set(ROOMBA_WAKEUP_PIN, 0, ROOMBA_WAKEUP_PIN, 0);
194 |
195 | MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.security);
196 | //MQTT_InitConnection(&mqttClient, "192.168.11.122", 1880, 0);
197 |
198 | MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1);
199 | //MQTT_InitClient(&mqttClient, "client_id", "user", "pass", 120, 1);
200 |
201 | MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
202 | MQTT_OnConnected(&mqttClient, mqttConnectedCb);
203 | MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
204 | MQTT_OnPublished(&mqttClient, mqttPublishedCb);
205 | MQTT_OnData(&mqttClient, mqttDataCb);
206 |
207 | WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb);
208 |
209 | INFO("\r\nSystem started ...\r\n");
210 | }
211 |
--------------------------------------------------------------------------------