├── .github
└── issue_template.md
├── .gitignore
├── .travis.yml
├── LICENSE.md
├── README.md
├── examples
├── MAX30100_Debug
│ └── MAX30100_Debug.ino
├── MAX30100_Minimal
│ └── MAX30100_Minimal.ino
├── MAX30100_RawData
│ └── MAX30100_RawData.ino
└── MAX30100_Tester
│ └── MAX30100_Tester.ino
├── extras
├── arduino-wiring.pdf
├── block-diagram.png
├── recorder
│ ├── README.md
│ ├── beat_analysis.ipynb
│ ├── recorder.py
│ ├── requirements.txt
│ ├── sampling_analysis.ipynb
│ └── test.out.sample
└── rolling_graph
│ ├── README.md
│ └── rolling_graph.pde
├── library.json
├── library.properties
└── src
├── CircularBuffer.h
├── CircularBuffer.tpp
├── MAX30100.cpp
├── MAX30100.h
├── MAX30100_BeatDetector.cpp
├── MAX30100_BeatDetector.h
├── MAX30100_Filters.h
├── MAX30100_PulseOximeter.cpp
├── MAX30100_PulseOximeter.h
├── MAX30100_Registers.h
├── MAX30100_SpO2Calculator.cpp
└── MAX30100_SpO2Calculator.h
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 | ### Troubleshooting checklist
2 |
3 | - [ ] I read the README (on master) thoroughly
4 | - [ ] I ran the MAX30100_Tester and I'm going to paste the output down below
5 | - [ ] I filled in all the details of my setup down below
6 |
7 | ### Description of the issue
8 |
9 | ### Output from MAX30100_Tester example
10 |
11 | ### Details of my setup
12 |
13 | * Arduino hardware:
14 | * MAX30100 breakout:
15 | * Arduino framework version:
16 | * MAX30100 library version:
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .pioenvs
2 | .clang_complete
3 | .gcc-flags.json
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "2.7"
4 |
5 | sudo: false
6 | cache:
7 | directories:
8 | - "~/.platformio"
9 |
10 | env:
11 | - PLATFORMIO_CI_SRC=examples/MAX30100_Minimal
12 | - PLATFORMIO_CI_SRC=examples/MAX30100_Debug
13 |
14 | install:
15 | - pip install -U platformio
16 |
17 | script:
18 | - platformio ci --lib="." --board=uno
19 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Arduino-MAX30100
2 |
3 | [](https://travis-ci.org/oxullo/Arduino-MAX30100)
4 |
5 | Arduino library for the Maxim Integrated MAX30100 oximetry / heart rate sensor.
6 |
7 | 
8 |
9 | ## Disclaimer
10 |
11 | The library is offered only for educational purposes and it is not meant for medical uses.
12 | Use it at your sole risk.
13 |
14 | ## Notes
15 |
16 | Maxim integrated stopped the production of the MAX30100 in favor of MAX30101 and MAX30102.
17 | Therefore this library won't be seeing any further improvement, besides fixes.
18 |
19 | *IMPORTANT: when submitting issues, make sure to fill ALL the fields indicated in the template text of the issue. The issue will be marked as invalid and closed immediately otherwise.*
20 |
21 | ## Hardware
22 |
23 | This library has been tested with the MikroElektronika Heart rate click daughterboard:
24 |
25 | http://www.mikroe.com/click/heart-rate/
26 |
27 | along with an Arduino UNO r3. Any Arduino supporting the Wire library should work.
28 |
29 | The only required connection to the sensor is the I2C bus (SDA, SCL lines, pulled up).
30 |
31 | An example which shows a possible way to wire up the sensor is shown in
32 | [extras/arduino-wiring.pdf](extras/arduino-wiring.pdf)
33 |
34 | Note: The schematics above shows also how to wire up the interrupt line, which is
35 | currently not used by the library.
36 |
37 | ### Pull-ups
38 |
39 | Since the I2C interface is clocked at 400kHz, make sure that the SDA/SCL lines are pulled
40 | up by 4,7kOhm or less resistors.
41 |
42 | ## Architecture
43 |
44 | The library offers a low-level driver class, MAX30100.
45 | This component allows for low level communication with the device.
46 |
47 | A rather simple but working implementation of the heart rate and SpO2 calculation
48 | can be found in the PulseOximeter class.
49 |
50 | This high level class sets up the sensor and data processing pipelines in order to
51 | offer a very simple interface to the data:
52 |
53 | * Sampling frequency set to 100Hz
54 | * 1600uS pulse width, full sampling 16bit dynamic
55 | * IR LED current set to 50mA
56 | * Heart-rate + SpO2 mode
57 |
58 | The PulseOximeter class is not optimised for battery-based projects.
59 |
60 | ## Examples
61 |
62 | The included examples show how to use the PulseOximeter class:
63 |
64 | * MAX30100_Minimal: a minimal example that dumps human-readable results via serial
65 | * MAX30100_Debug: used in conjunction with the Processing pde "rolling_graph" (extras folder), to show the sampled data at various processing stages
66 | * MAX30100_RawData: demonstrates how to access raw data from the sensor
67 | * MAX30100_Tester: this sketch helps to find out potential issues with the sensor
68 |
69 | ## Troubleshooting
70 |
71 | Run the MAX30100_Tester example to inspect the state of your rig.
72 | When run with a properly connected sensor, it should print:
73 |
74 | ```
75 | Initializing MAX30100..Success
76 | Enabling HR/SPO2 mode..done.
77 | Configuring LEDs biases to 50mA..done.
78 | Lowering the current to 7.6mA..done.
79 | Shutting down..done.
80 | Resuming normal operation..done.
81 | Sampling die temperature..done, temp=24.94C
82 | All test pass. Press any key to go into sampling loop mode
83 | ```
84 |
85 | Pressing any key, a data stream with the raw values from the photodiode sampling red
86 | and infrared is presented.
87 | With no finger on the sensor, both values should be close to zero and jump up when
88 | a finger is positioned on top of the sensor.
89 |
90 |
91 | Typical issues when attempting to run the examples:
92 |
93 | ### I2C error or garbage data
94 |
95 | In particular when the tester fails with:
96 |
97 | ```
98 | Initializing MAX30100..FAILED: I2C error
99 | ```
100 |
101 | This is likely to be caused by an improper pullup setup for the I2C lines.
102 | Make sure to use 4,7kOhm resistors, checking if the breakout board in use is equipped
103 | with pullups.
104 |
105 | ### Logic level compatibility
106 |
107 | If you're using a 5V-based microcontroller but the sensor breakout board pulls SDA and SCL up
108 | to 3.3V, you should ensure that its inputs are compatible with the 3.3V logic levels.
109 | An original Atmel ATMega328p considers anything above 3V as HIGH, so it might work well without
110 | level shifting hardware.
111 |
112 | Since the MAX30100 I2C pins maximum ratings aren't bound to Vdd, a cheap option to avoid
113 | level shifting is to simply pull SDA and SCL up to 5V instead of 3.3V.
114 |
115 | ### Sketchy beat frequency readouts
116 |
117 | The beat detector uses the IR LED to track the heartbeat. The IR LED is biased
118 | by default at 50mA on all examples, excluding the Tester (which sets it to 7.6mA).
119 | This value is somehow critical and it must be experimented with.
120 |
121 | The current can be adjusted using PulseOximeter::setIRLedCurrent().
122 | Check the _MAX30100_Minimal_ example.
123 |
124 | ### Advanced debugging
125 |
126 | Two tools are available for further inspection and error reporting:
127 |
128 | * extras/recorder: a python script that records a session that can be then analysed with the provided collection of jupyter notebooks
129 | * extras/rolling_graph: to be used in conjunction with _MAX30100_Debug_ example, it provides a visual feedback of the LED tracking and heartbeat detector
130 |
131 | Both tools have additional information on the README.md in their respective directories.
132 |
133 | ## Tested devices
134 |
135 | * Arduino UNO r3, Mikroelektronika Heart rate click (https://shop.mikroe.com/heart-rate-click)
136 |
137 | This combination works without level shifting devices at 400kHz I2C clock rate.
138 |
139 | * Arduino UNO r3, MAX30100 custom board with 4.7kOhm pullups to 5V to SDA, SCL, INT
140 |
141 | As above, working at 400kHz
142 |
143 | * Sparkfun Arduino Pro 328p 8MHz 3.3V, Mikroelektronika Heart rate click
144 |
145 | Even if this combination works (MAX30100 communication), the slower clock speed fails to deliver
146 | the required performance deadlines for a 100Hz sampling.
147 |
148 | ## Troubled breakouts
149 |
150 | This breakout board: http://www.sunrom.com/m/5337
151 |
152 | Has pullups on the Vdd (1.8V) line. To make it work, the three 4k7 pullups must be
153 | desoldered and external 4.7k pullups to Vcc of the MCU must be added.
154 |
--------------------------------------------------------------------------------
/examples/MAX30100_Debug/MAX30100_Debug.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | // This example must be used in conjunction with the Processing sketch located
20 | // in extras/rolling_graph
21 |
22 | #include
23 | #include "MAX30100_PulseOximeter.h"
24 |
25 | #define REPORTING_PERIOD_MS 1000
26 |
27 | // PulseOximeter is the higher level interface to the sensor
28 | // it offers:
29 | // * beat detection reporting
30 | // * heart rate calculation
31 | // * SpO2 (oxidation level) calculation
32 | PulseOximeter pox;
33 |
34 | uint32_t tsLastReport = 0;
35 |
36 | // Callback (registered below) fired when a pulse is detected
37 | void onBeatDetected()
38 | {
39 | Serial.println("B:1");
40 | }
41 |
42 | void setup()
43 | {
44 | Serial.begin(115200);
45 |
46 | // Initialize the PulseOximeter instance and register a beat-detected callback
47 | // The parameter passed to the begin() method changes the samples flow that
48 | // the library spews to the serial.
49 | // Options:
50 | // * PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT : filtered samples and beat detection threshold
51 | // * PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES : sampled values coming from the sensor, with no processing
52 | // * PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES : sampled values after the DC removal filter
53 |
54 | // Initialize the PulseOximeter instance
55 | // Failures are generally due to an improper I2C wiring, missing power supply
56 | // or wrong target chip
57 | if (!pox.begin(PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT)) {
58 | Serial.println("ERROR: Failed to initialize pulse oximeter");
59 | for(;;);
60 | }
61 |
62 | pox.setOnBeatDetectedCallback(onBeatDetected);
63 | }
64 |
65 | void loop()
66 | {
67 | // Make sure to call update as fast as possible
68 | pox.update();
69 |
70 | // Asynchronously dump heart rate and oxidation levels to the serial
71 | // For both, a value of 0 means "invalid"
72 | if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
73 | Serial.print("H:");
74 | Serial.println(pox.getHeartRate());
75 |
76 | Serial.print("O:");
77 | Serial.println(pox.getSpO2());
78 |
79 | tsLastReport = millis();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/examples/MAX30100_Minimal/MAX30100_Minimal.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include "MAX30100_PulseOximeter.h"
21 |
22 | #define REPORTING_PERIOD_MS 1000
23 |
24 | // PulseOximeter is the higher level interface to the sensor
25 | // it offers:
26 | // * beat detection reporting
27 | // * heart rate calculation
28 | // * SpO2 (oxidation level) calculation
29 | PulseOximeter pox;
30 |
31 | uint32_t tsLastReport = 0;
32 |
33 | // Callback (registered below) fired when a pulse is detected
34 | void onBeatDetected()
35 | {
36 | Serial.println("Beat!");
37 | }
38 |
39 | void setup()
40 | {
41 | Serial.begin(115200);
42 |
43 | Serial.print("Initializing pulse oximeter..");
44 |
45 | // Initialize the PulseOximeter instance
46 | // Failures are generally due to an improper I2C wiring, missing power supply
47 | // or wrong target chip
48 | if (!pox.begin()) {
49 | Serial.println("FAILED");
50 | for(;;);
51 | } else {
52 | Serial.println("SUCCESS");
53 | }
54 |
55 | // The default current for the IR LED is 50mA and it could be changed
56 | // by uncommenting the following line. Check MAX30100_Registers.h for all the
57 | // available options.
58 | // pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
59 |
60 | // Register a callback for the beat detection
61 | pox.setOnBeatDetectedCallback(onBeatDetected);
62 | }
63 |
64 | void loop()
65 | {
66 | // Make sure to call update as fast as possible
67 | pox.update();
68 |
69 | // Asynchronously dump heart rate and oxidation levels to the serial
70 | // For both, a value of 0 means "invalid"
71 | if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
72 | Serial.print("Heart rate:");
73 | Serial.print(pox.getHeartRate());
74 | Serial.print("bpm / SpO2:");
75 | Serial.print(pox.getSpO2());
76 | Serial.println("%");
77 |
78 | tsLastReport = millis();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/examples/MAX30100_RawData/MAX30100_RawData.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | // The example shows how to retrieve raw values from the sensor
20 | // experimenting with the most relevant configuration parameters.
21 | // Use the "Serial Plotter" app from arduino IDE 1.6.7+ to plot the output
22 |
23 | #include
24 | #include "MAX30100.h"
25 |
26 | // Sampling is tightly related to the dynamic range of the ADC.
27 | // refer to the datasheet for further info
28 | #define SAMPLING_RATE MAX30100_SAMPRATE_100HZ
29 |
30 | // The LEDs currents must be set to a level that avoids clipping and maximises the
31 | // dynamic range
32 | #define IR_LED_CURRENT MAX30100_LED_CURR_50MA
33 | #define RED_LED_CURRENT MAX30100_LED_CURR_27_1MA
34 |
35 | // The pulse width of the LEDs driving determines the resolution of
36 | // the ADC (which is a Sigma-Delta).
37 | // set HIGHRES_MODE to true only when setting PULSE_WIDTH to MAX30100_SPC_PW_1600US_16BITS
38 | #define PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS
39 | #define HIGHRES_MODE true
40 |
41 |
42 | // Instantiate a MAX30100 sensor class
43 | MAX30100 sensor;
44 |
45 | void setup()
46 | {
47 | Serial.begin(115200);
48 |
49 | Serial.print("Initializing MAX30100..");
50 |
51 | // Initialize the sensor
52 | // Failures are generally due to an improper I2C wiring, missing power supply
53 | // or wrong target chip
54 | if (!sensor.begin()) {
55 | Serial.println("FAILED");
56 | for(;;);
57 | } else {
58 | Serial.println("SUCCESS");
59 | }
60 |
61 | // Set up the wanted parameters
62 | sensor.setMode(MAX30100_MODE_SPO2_HR);
63 | sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT);
64 | sensor.setLedsPulseWidth(PULSE_WIDTH);
65 | sensor.setSamplingRate(SAMPLING_RATE);
66 | sensor.setHighresModeEnabled(HIGHRES_MODE);
67 | }
68 |
69 | void loop()
70 | {
71 | uint16_t ir, red;
72 |
73 | sensor.update();
74 |
75 | while (sensor.getRawValues(&ir, &red)) {
76 | Serial.print(ir);
77 | Serial.print('\t');
78 | Serial.println(red);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/examples/MAX30100_Tester/MAX30100_Tester.ino:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2017 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | // This example can be used to test connectivity and operation of the sensor
20 | // check the README file on the repo's root for a troubleshooting guide in case
21 | // any of the tests running fail
22 |
23 | #include
24 | #include "MAX30100.h"
25 |
26 | MAX30100 sensor;
27 |
28 | void setup()
29 | {
30 | Serial.begin(115200);
31 |
32 | Serial.print("Initializing MAX30100..");
33 |
34 | if (!sensor.begin()) {
35 | Serial.print("FAILED: ");
36 |
37 | uint8_t partId = sensor.getPartId();
38 | if (partId == 0xff) {
39 | Serial.println("I2C error");
40 | } else {
41 | Serial.print("wrong part ID 0x");
42 | Serial.print(partId, HEX);
43 | Serial.print(" (expected: 0x");
44 | Serial.println(EXPECTED_PART_ID, HEX);
45 | }
46 | // Stop here
47 | for(;;);
48 | } else {
49 | Serial.println("Success");
50 | }
51 |
52 | Serial.print("Enabling HR/SPO2 mode..");
53 | sensor.setMode(MAX30100_MODE_SPO2_HR);
54 | Serial.println("done.");
55 |
56 | Serial.print("Configuring LEDs biases to 50mA..");
57 | sensor.setLedsCurrent(MAX30100_LED_CURR_50MA, MAX30100_LED_CURR_50MA);
58 | Serial.println("done.");
59 |
60 | delay(1000);
61 |
62 | Serial.print("Lowering the current to 7.6mA..");
63 | sensor.setLedsCurrent(MAX30100_LED_CURR_7_6MA, MAX30100_LED_CURR_7_6MA);
64 | Serial.println("done.");
65 |
66 | delay(1000);
67 |
68 | Serial.print("Shutting down..");
69 | sensor.shutdown();
70 | Serial.println("done.");
71 |
72 | delay(1000);
73 |
74 | Serial.print("Resuming normal operation..");
75 | sensor.resume();
76 | delay(500);
77 | Serial.println("done.");
78 |
79 | uint32_t tsTempSampStart = millis();
80 | Serial.print("Sampling die temperature..");
81 | sensor.startTemperatureSampling();
82 | while(!sensor.isTemperatureReady()) {
83 | if (millis() - tsTempSampStart > 1000) {
84 | Serial.println("ERROR: timeout");
85 | // Stop here
86 | for(;;);
87 | }
88 | }
89 |
90 | float temperature = sensor.retrieveTemperature();
91 | Serial.print("done, temp=");
92 | Serial.print(temperature);
93 | Serial.println("C");
94 |
95 | if (temperature < 5) {
96 | Serial.println("WARNING: Temperature probe reported an odd value");
97 | } else {
98 | Serial.println("All test pass.");
99 | }
100 |
101 | Serial.println();
102 | Serial.println("Press any key to go into sampling loop mode");
103 | while (!Serial.available());
104 |
105 | sensor.resetFifo();
106 | }
107 |
108 | void loop()
109 | {
110 | uint16_t ir, red;
111 |
112 | sensor.update();
113 |
114 | while (sensor.getRawValues(&ir, &red)) {
115 | Serial.print("IR=");
116 | Serial.print(ir);
117 | Serial.print(" RED=");
118 | Serial.println(red);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/extras/arduino-wiring.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxullo/Arduino-MAX30100/5754dfe2cfd882b91d5db748d78c4a6ad4cab0d1/extras/arduino-wiring.pdf
--------------------------------------------------------------------------------
/extras/block-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oxullo/Arduino-MAX30100/5754dfe2cfd882b91d5db748d78c4a6ad4cab0d1/extras/block-diagram.png
--------------------------------------------------------------------------------
/extras/recorder/README.md:
--------------------------------------------------------------------------------
1 | # Session recorder
2 |
3 | This tool pipes a raw session from the sensor into a file for further analysis.
4 |
5 | ## Requirements
6 |
7 | The recorder and the analysis notebook require python and analysis libraries.
8 | Virtualenv is warmly suggested.
9 |
10 | * Flash the example firmware MAX30100_RawData to the microcontroller board
11 | * Install the required libraries
12 | $ virtualenv max30100env
13 | $ source max30100env/bin/activate
14 | $ pip install -Ur requirements.txt
15 | * Ensure the board is connected
16 |
17 | ## Record a session
18 |
19 | Recording a session might be useful as a valuable debugging file when posting issues.
20 | It can be done via command line interface:
21 |
22 | $ ./recorder.py --samples 1000 /dev/ttyACM0 test.out
23 |
24 | the command above records at least 1000 samples of data from the serial device /dev/ttyACM0 to file test.out.
25 |
26 | Each system might expose the microcontroller with different device paths.
27 |
28 | ## Run a beat analysis
29 |
30 | Fire up a jupyter kernel and follow the instruction on the notebook:
31 |
32 | $ jupyter notebook beat_analysis.ipynb
33 |
34 | ## Use the provided sample data
35 |
36 | A sample data file is provided to allow comparisons: test.out.sample
37 | It can be opened from the provided notebooks by either copying it to test.out or by altering
38 | the pd.read_csv() function exposes in each notebook.
39 |
40 | The sample file shows an undisturbed 2000-samples worth of data that exposes an uncompensated
41 | temperature drift.
42 |
--------------------------------------------------------------------------------
/extras/recorder/recorder.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import print_function
5 |
6 | import time
7 | import threading
8 | import Queue
9 | import argparse
10 | import logging
11 | import serial
12 |
13 | #
14 | # Data logger
15 | # to be used in conjunction with the MAX30100_RawData example
16 | #
17 |
18 |
19 | logger = logging.getLogger(__name__)
20 |
21 |
22 | class SerialStreamer(threading.Thread):
23 | DEFAULT_SPEED = 115200
24 | DEFAULT_HOLDOFF = 3
25 | DEFAULT_TIMEOUT = .1
26 |
27 | def __init__(self, port, holdoff=DEFAULT_HOLDOFF, speed=DEFAULT_SPEED):
28 | super(SerialStreamer, self).__init__()
29 | self._s = serial.Serial(port, speed, timeout=.5)
30 | self._q = Queue.Queue()
31 | self._holdoff = holdoff
32 | self._time_started = 0
33 |
34 | def run(self):
35 | logger.info('Starting streamer thread, delaying acquisition by %.2fs' % self._holdoff)
36 | self._isRunning = True
37 |
38 | tstarted = time.time()
39 |
40 | while time.time() - tstarted < self._holdoff and self._isRunning:
41 | self._s.readline()
42 |
43 | logger.info('Started acquisition')
44 | self._time_started = time.time()
45 |
46 | while self._isRunning:
47 | self._poll()
48 |
49 | def stop(self):
50 | logger.info('Stopping streamer thread')
51 | self._isRunning = False
52 | self.join()
53 |
54 | def get_samples(self):
55 | samples = []
56 | while not self._q.empty():
57 | samples.append(self._q.get())
58 |
59 | return samples
60 |
61 | def _poll(self):
62 | line = self._s.readline().strip()
63 | if line:
64 | spl = line.split('\t')
65 |
66 | if len(spl) != 2:
67 | logger.warning('Ignoring line: %s' % line)
68 | else:
69 | try:
70 | a, b = [int(v) for v in spl]
71 | except Exception, e:
72 | logger.exception(e)
73 | else:
74 | self._q.put((self._get_time_offs(), a, b))
75 |
76 | def _get_time_offs(self):
77 | return int((time.time() - self._time_started) * 1000.0)
78 |
79 |
80 | def parse_args():
81 | parser = argparse.ArgumentParser()
82 | parser.add_argument('port', help='Serial port of the device')
83 | parser.add_argument('outfile', help='Output recording file')
84 | parser.add_argument('--holdoff', type=float, default=SerialStreamer.DEFAULT_HOLDOFF,
85 | help='Seconds to wait after connection before starting '
86 | 'acquisition')
87 | parser.add_argument('--debug', action='store_true', help='Be verbose')
88 | parser.add_argument('--samples', type=int, default=0,
89 | help='Define the number of samples to be fetched, 0 to infinite')
90 |
91 | return parser.parse_args()
92 |
93 | def gather(streamer, fp, maxsamples):
94 | samples_count = 0
95 |
96 | while True:
97 | samples = streamer.get_samples()
98 | samples_count += len(samples)
99 |
100 | for sample in samples:
101 | fp.write('%d\t%d\t%d\n' % sample)
102 | logger.info('Gathered %d/%d/%d samples' % (len(samples), samples_count, maxsamples))
103 |
104 | if samples_count > maxsamples:
105 | logging.info('Acquired %d samples (requested: %d), stopping' %
106 | (samples_count, maxsamples))
107 | return
108 |
109 | time.sleep(1)
110 |
111 | def run(port, outfile, holdoff, debug, samples):
112 |
113 | if debug:
114 | level = logging.DEBUG
115 | else:
116 | level = logging.INFO
117 |
118 | logging.basicConfig(level=level)
119 |
120 | streamer = SerialStreamer(port, holdoff)
121 | streamer.start()
122 |
123 | fp = open(outfile, 'w')
124 |
125 | fp.write('timestamp\tir_level\tred_level\n')
126 |
127 | try:
128 | gather(streamer, fp, samples)
129 | except KeyboardInterrupt:
130 | logger.info('Terminating')
131 | finally:
132 | fp.close()
133 | streamer.stop()
134 |
135 | def cli_run():
136 | args = parse_args()
137 |
138 | run(args.port, args.outfile, args.holdoff, args.debug, args.samples)
139 |
140 | if __name__ == '__main__':
141 | cli_run()
142 |
--------------------------------------------------------------------------------
/extras/recorder/requirements.txt:
--------------------------------------------------------------------------------
1 | pyserial
2 | pandas
3 | numpy
4 | scipy
5 | matplotlib
6 | jupyter
7 |
--------------------------------------------------------------------------------
/extras/recorder/sampling_analysis.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Sampling time analysis scratchpad\n",
8 | "\n",
9 | "Attempts to analyse the sampling time based on the timestamps associated during acquisition.\n",
10 | "Acquisition timestamps are susceptible to jitter and using the RawData example does not account for filtering overhead."
11 | ]
12 | },
13 | {
14 | "cell_type": "code",
15 | "execution_count": 1,
16 | "metadata": {
17 | "collapsed": true
18 | },
19 | "outputs": [],
20 | "source": [
21 | "%matplotlib inline\n",
22 | "from matplotlib import pyplot as plt\n",
23 | "import pandas as pd\n",
24 | "from scipy import signal\n",
25 | "import numpy as np\n",
26 | "import recorder"
27 | ]
28 | },
29 | {
30 | "cell_type": "code",
31 | "execution_count": 2,
32 | "metadata": {
33 | "collapsed": true
34 | },
35 | "outputs": [],
36 | "source": [
37 | "%load_ext autoreload\n",
38 | "%autoreload 2"
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "execution_count": 3,
44 | "metadata": {
45 | "collapsed": false
46 | },
47 | "outputs": [
48 | {
49 | "name": "stderr",
50 | "output_type": "stream",
51 | "text": [
52 | "INFO:recorder:Starting streamer thread, delaying acquisition by 5.00s\n",
53 | "INFO:recorder:Gathered 0 samples\n",
54 | "INFO:recorder:Gathered 0 samples\n",
55 | "INFO:recorder:Gathered 0 samples\n",
56 | "INFO:recorder:Gathered 0 samples\n",
57 | "INFO:recorder:Gathered 0 samples\n",
58 | "INFO:recorder:Started acquisition\n",
59 | "INFO:recorder:Gathered 1 samples\n",
60 | "INFO:recorder:Gathered 98 samples\n",
61 | "INFO:recorder:Gathered 196 samples\n",
62 | "INFO:recorder:Gathered 294 samples\n",
63 | "INFO:root:Acquired 294 samples (requested: 200), stopping\n",
64 | "INFO:recorder:Stopping streamer thread\n"
65 | ]
66 | }
67 | ],
68 | "source": [
69 | "# Record 200 samples worth of data, delaying acquisition by 5 seconds\n",
70 | "# this can be done also using the command line interface of recorder.py\n",
71 | "recorder.run(port='/dev/ttyACM0', outfile='test.out', holdoff=5, debug=False, samples=200)"
72 | ]
73 | },
74 | {
75 | "cell_type": "code",
76 | "execution_count": 4,
77 | "metadata": {
78 | "collapsed": true
79 | },
80 | "outputs": [],
81 | "source": [
82 | "# Read from the recorded session\n",
83 | "df = pd.read_csv('test.out', delimiter='\\t', index_col=0)"
84 | ]
85 | },
86 | {
87 | "cell_type": "code",
88 | "execution_count": 5,
89 | "metadata": {
90 | "collapsed": true
91 | },
92 | "outputs": [],
93 | "source": [
94 | "df_ts = pd.DataFrame(df.index)\n",
95 | "df_ts_diffs = df_ts.diff()"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": 6,
101 | "metadata": {
102 | "collapsed": false
103 | },
104 | "outputs": [
105 | {
106 | "data": {
107 | "text/plain": [
108 | ""
109 | ]
110 | },
111 | "execution_count": 6,
112 | "metadata": {},
113 | "output_type": "execute_result"
114 | },
115 | {
116 | "data": {
117 | "image/png": "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\nV3D22WczOjrKKaecwmte8xoOZzcogOPfvffee7n88suZnJxk586dvP3tbwfggQce4LLLLmPbtm2c\ncsopvOc971n3/dtuu42BgQE++clP8ta3vpVTTjmFiYkJXvziF/Pggw9Wui+zs8WKbaVKez2M2A2e\n5nvSSWrTlNj4653SYnZpJ5e+G7zsZS/jnnvu4ZZbbuF973sfJ5xwAkIITjzxxLbx+9e//vWccsop\nXH/99dxxxx18+MMfZnJykttvv50zzjiDP/7jP+aLX/wi73rXu3ja057G5Zdffvy7/+2//Tc+/vGP\nc+WVV/LGN76Rffv28f73v5+77rqLb33rWwwODnLw4EEuvfRSdu7cyR/8wR8wOTnJz372M/7u7/4O\ngBNPPJEPfvCDXHXVVbz0pS/lpS99KQC/8Au/AMBXv/pV9u3bx5VXXsnJJ5/MD3/4Qz70oQ/xH//x\nH3z7298+fi2a32/91m9x7rnnctNNN/H3f//3vPOd72T79u186EMf4pJLLuGmm27i5ptv5vd///e5\n6KKLePazn73u93jnO9/JwMAAb3nLWzhw4AC7d+/mBS94AXfddRebN28udV9mZmB8vEDxHSml13/A\n+YC88847ZUIx/M3fSAlSPvCAev3sZ31fkVvcfrvi/f3vS7l1q5TvepfvK3KL/fsV/899TsqnP13K\nq67yfUXusWWLlO9+t5Qvf7mUL3iB32u58847ZT+PZe9617vkwMCAvO+++9a9f+aZZ8orrrji+N8f\n/ehHpRBCvvCFL1x33DOf+Uw5MDAgr7766uPvra6uytNOO03+0i/90vH3/vmf/1kKIeQtt9yy7vtf\n+cpXpBBC7tmzR0op5ec+9zk5MDAg9+7d2/aaDx06JIUQ8rrrrtvw2cLCwob3brnlFjkwMCC/+c1v\nHn/v2muvlUII+Xu/93sbrntwcFC+KzPwTE9Py7GxsXW/xze+8Q0phJCnnXaanJ+fP/7+pz71KSmE\nkO9///vbXr+UnfvVm94k5eMfrz4Hzpdd7G1S+D2MmRkYGlLLkvTfMUHzjTWGGzt/XYdC83/gAd9X\nVAxHj8KPfmS3jSc9CcbG7LbRCkKIDUv1Lr74Yu644w6uuOKK4+8NDAxw4YUXsnfv3uPvffrTn2Zy\ncpJLLrmExx577Pj7T3/605mYmODrX/86r3jFK5icnERKya233srTnvY0hoaKmbOsql5cXGRubo6L\n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\n",
118 | "text/plain": [
119 | ""
120 | ]
121 | },
122 | "metadata": {},
123 | "output_type": "display_data"
124 | }
125 | ],
126 | "source": [
127 | "df_ts_diffs[10:40].plot()"
128 | ]
129 | },
130 | {
131 | "cell_type": "code",
132 | "execution_count": 7,
133 | "metadata": {
134 | "collapsed": false
135 | },
136 | "outputs": [
137 | {
138 | "data": {
139 | "text/plain": [
140 | "array([[]], dtype=object)"
141 | ]
142 | },
143 | "execution_count": 7,
144 | "metadata": {},
145 | "output_type": "execute_result"
146 | },
147 | {
148 | "data": {
149 | "image/png": "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\nxBsAAAAASUVORK5CYII=\n",
150 | "text/plain": [
151 | ""
152 | ]
153 | },
154 | "metadata": {},
155 | "output_type": "display_data"
156 | }
157 | ],
158 | "source": [
159 | "df_ts_diffs.hist()"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "execution_count": null,
165 | "metadata": {
166 | "collapsed": true
167 | },
168 | "outputs": [],
169 | "source": []
170 | }
171 | ],
172 | "metadata": {
173 | "kernelspec": {
174 | "display_name": "Python 2",
175 | "language": "python",
176 | "name": "python2"
177 | },
178 | "language_info": {
179 | "codemirror_mode": {
180 | "name": "ipython",
181 | "version": 2
182 | },
183 | "file_extension": ".py",
184 | "mimetype": "text/x-python",
185 | "name": "python",
186 | "nbconvert_exporter": "python",
187 | "pygments_lexer": "ipython2",
188 | "version": "2.7.12"
189 | }
190 | },
191 | "nbformat": 4,
192 | "nbformat_minor": 2
193 | }
194 |
--------------------------------------------------------------------------------
/extras/recorder/test.out.sample:
--------------------------------------------------------------------------------
1 | timestamp ir_level red_level
2 | 7 40164 39722
3 | 19 40172 39728
4 | 27 40156 39724
5 | 39 40166 39724
6 | 47 40153 39729
7 | 60 40169 39723
8 | 68 40154 39727
9 | 80 40165 39711
10 | 88 40186 39725
11 | 101 40180 39737
12 | 109 40190 39716
13 | 121 40206 39731
14 | 129 40207 39726
15 | 142 40201 39721
16 | 150 40205 39721
17 | 162 40193 39680
18 | 170 40139 39675
19 | 183 40090 39656
20 | 191 40040 39606
21 | 203 39945 39581
22 | 211 39870 39543
23 | 223 39785 39512
24 | 232 39690 39475
25 | 244 39625 39422
26 | 252 39559 39406
27 | 264 39490 39362
28 | 273 39446 39349
29 | 285 39405 39316
30 | 297 39376 39326
31 | 305 39364 39313
32 | 317 39336 39287
33 | 326 39313 39274
34 | 338 39294 39278
35 | 346 39295 39265
36 | 358 39294 39273
37 | 367 39296 39249
38 | 379 39282 39258
39 | 387 39269 39268
40 | 399 39271 39262
41 | 408 39276 39245
42 | 420 39295 39256
43 | 428 39295 39253
44 | 440 39319 39270
45 | 449 39316 39265
46 | 461 39322 39270
47 | 469 39322 39270
48 | 481 39348 39282
49 | 490 39336 39268
50 | 502 39352 39269
51 | 510 39358 39257
52 | 522 39357 39263
53 | 531 39359 39260
54 | 543 39354 39259
55 | 551 39364 39258
56 | 563 39370 39275
57 | 572 39370 39258
58 | 584 39358 39267
59 | 592 39344 39248
60 | 604 39343 39246
61 | 613 39331 39255
62 | 625 39338 39245
63 | 633 39323 39258
64 | 645 39324 39260
65 | 654 39334 39243
66 | 666 39334 39229
67 | 674 39338 39247
68 | 686 39338 39238
69 | 695 39351 39231
70 | 707 39373 39231
71 | 715 39375 39255
72 | 727 39379 39249
73 | 735 39388 39246
74 | 748 39395 39246
75 | 756 39414 39251
76 | 768 39416 39264
77 | 776 39445 39264
78 | 789 39434 39283
79 | 797 39441 39253
80 | 809 39460 39252
81 | 817 39473 39269
82 | 830 39475 39269
83 | 838 39480 39270
84 | 850 39491 39261
85 | 858 39492 39277
86 | 871 39499 39277
87 | 879 39499 39284
88 | 891 39498 39271
89 | 899 39515 39257
90 | 912 39523 39292
91 | 920 39528 39286
92 | 932 39531 39282
93 | 940 39534 39284
94 | 953 39548 39290
95 | 961 39554 39276
96 | 973 39548 39293
97 | 981 39564 39291
98 | 994 39586 39285
99 | 1002 39584 39302
100 | 1014 39609 39295
101 | 1022 39608 39288
102 | 1034 39611 39291
103 | 1043 39589 39282
104 | 1055 39559 39252
105 | 1063 39525 39231
106 | 1075 39475 39194
107 | 1084 39400 39154
108 | 1096 39319 39128
109 | 1104 39238 39097
110 | 1117 39155 39043
111 | 1125 39074 39014
112 | 1137 39009 38966
113 | 1145 38959 38965
114 | 1157 38897 38950
115 | 1166 38860 38908
116 | 1178 38824 38905
117 | 1186 38787 38881
118 | 1198 38770 38884
119 | 1206 38760 38868
120 | 1219 38742 38858
121 | 1227 38725 38850
122 | 1239 38711 38834
123 | 1247 38708 38836
124 | 1260 38710 38825
125 | 1268 38698 38818
126 | 1280 38683 38824
127 | 1288 38680 38836
128 | 1301 38658 38844
129 | 1309 38674 38839
130 | 1321 38685 38836
131 | 1329 38703 38841
132 | 1342 38708 38837
133 | 1350 38730 38838
134 | 1362 38732 38844
135 | 1370 38749 38873
136 | 1383 38745 38855
137 | 1391 38734 38862
138 | 1403 38740 38839
139 | 1411 38754 38839
140 | 1424 38755 38844
141 | 1432 38743 38834
142 | 1444 38756 38822
143 | 1452 38751 38831
144 | 1465 38739 38828
145 | 1473 38740 38820
146 | 1485 38742 38814
147 | 1493 38737 38818
148 | 1505 38727 38826
149 | 1514 38734 38815
150 | 1526 38742 38812
151 | 1534 38730 38823
152 | 1546 38752 38821
153 | 1555 38759 38830
154 | 1567 38775 38806
155 | 1575 38777 38832
156 | 1588 38778 38828
157 | 1596 38796 38817
158 | 1608 38793 38818
159 | 1616 38812 38839
160 | 1628 38822 38843
161 | 1637 38853 38847
162 | 1649 38844 38841
163 | 1657 38866 38852
164 | 1669 38879 38861
165 | 1678 38885 38854
166 | 1690 38891 38867
167 | 1698 38910 38848
168 | 1710 38907 38880
169 | 1718 38929 38847
170 | 1731 38941 38870
171 | 1739 38953 38870
172 | 1751 38966 38875
173 | 1759 38976 38874
174 | 1772 38985 38883
175 | 1780 38996 38878
176 | 1792 38993 38886
177 | 1804 39009 38867
178 | 1813 39018 38888
179 | 1825 39021 38897
180 | 1833 39025 38897
181 | 1845 39044 38881
182 | 1854 39038 38884
183 | 1866 39054 38888
184 | 1874 39056 38884
185 | 1886 39070 38894
186 | 1895 39099 38914
187 | 1907 39088 38907
188 | 1915 39098 38913
189 | 1927 39095 38908
190 | 1936 39098 38910
191 | 1948 39114 38897
192 | 1956 39085 38906
193 | 1968 39072 38897
194 | 1977 39002 38867
195 | 1989 38952 38833
196 | 1997 38875 38795
197 | 2009 38801 38742
198 | 2017 38686 38716
199 | 2030 38597 38654
200 | 2038 38488 38623
201 | 2050 38394 38576
202 | 2058 38321 38535
203 | 2071 38240 38498
204 | 2079 38174 38485
205 | 2091 38114 38451
206 | 2099 38096 38427
207 | 2112 38047 38427
208 | 2120 38013 38418
209 | 2132 37994 38398
210 | 2140 37991 38391
211 | 2152 37976 38401
212 | 2161 37966 38390
213 | 2173 37944 38374
214 | 2181 37954 38369
215 | 2193 37931 38380
216 | 2202 37934 38356
217 | 2214 37927 38365
218 | 2222 37947 38373
219 | 2234 37974 38381
220 | 2243 37994 38381
221 | 2255 38001 38393
222 | 2263 38037 38399
223 | 2275 38072 38412
224 | 2284 38101 38424
225 | 2296 38115 38432
226 | 2304 38141 38432
227 | 2316 38142 38442
228 | 2325 38160 38450
229 | 2337 38183 38454
230 | 2345 38170 38453
231 | 2357 38176 38455
232 | 2366 38176 38451
233 | 2378 38185 38452
234 | 2386 38188 38440
235 | 2398 38185 38449
236 | 2407 38173 38439
237 | 2419 38172 38434
238 | 2427 38173 38439
239 | 2439 38193 38449
240 | 2448 38194 38442
241 | 2460 38201 38462
242 | 2468 38218 38453
243 | 2480 38222 38453
244 | 2488 38247 38469
245 | 2501 38261 38469
246 | 2509 38286 38476
247 | 2521 38276 38481
248 | 2529 38298 38480
249 | 2542 38321 38481
250 | 2550 38343 38489
251 | 2562 38354 38508
252 | 2570 38354 38525
253 | 2583 38372 38508
254 | 2591 38386 38503
255 | 2603 38387 38515
256 | 2611 38408 38522
257 | 2624 38418 38536
258 | 2632 38442 38547
259 | 2644 38461 38545
260 | 2652 38468 38534
261 | 2664 38478 38548
262 | 2673 38496 38559
263 | 2685 38516 38559
264 | 2693 38539 38572
265 | 2706 38538 38573
266 | 2714 38536 38572
267 | 2726 38555 38591
268 | 2734 38553 38578
269 | 2747 38589 38577
270 | 2755 38605 38581
271 | 2767 38604 38575
272 | 2775 38625 38590
273 | 2787 38625 38601
274 | 2796 38638 38606
275 | 2808 38657 38596
276 | 2816 38665 38599
277 | 2828 38656 38616
278 | 2837 38678 38614
279 | 2849 38720 38611
280 | 2857 38710 38634
281 | 2869 38734 38631
282 | 2878 38738 38638
283 | 2890 38732 38639
284 | 2898 38739 38616
285 | 2910 38729 38618
286 | 2919 38701 38592
287 | 2931 38650 38545
288 | 2939 38591 38530
289 | 2951 38536 38477
290 | 2960 38446 38447
291 | 2972 38377 38407
292 | 2980 38323 38379
293 | 2992 38250 38360
294 | 3000 38204 38333
295 | 3013 38166 38319
296 | 3021 38128 38306
297 | 3033 38102 38293
298 | 3041 38084 38290
299 | 3054 38067 38265
300 | 3062 38041 38246
301 | 3074 38014 38240
302 | 3082 38016 38243
303 | 3095 38010 38234
304 | 3103 37989 38215
305 | 3115 37982 38223
306 | 3123 37991 38219
307 | 3136 37989 38217
308 | 3144 37978 38233
309 | 3156 37988 38218
310 | 3164 37997 38226
311 | 3177 38022 38226
312 | 3185 38033 38235
313 | 3197 38035 38241
314 | 3205 38065 38263
315 | 3218 38073 38258
316 | 3226 38089 38270
317 | 3238 38095 38270
318 | 3246 38105 38281
319 | 3259 38123 38270
320 | 3267 38125 38279
321 | 3279 38138 38262
322 | 3287 38133 38268
323 | 3299 38133 38269
324 | 3308 38122 38267
325 | 3320 38127 38268
326 | 3328 38108 38253
327 | 3340 38109 38259
328 | 3352 38125 38237
329 | 3361 38125 38249
330 | 3373 38117 38249
331 | 3381 38147 38255
332 | 3393 38140 38256
333 | 3402 38169 38267
334 | 3414 38164 38252
335 | 3422 38173 38265
336 | 3434 38198 38258
337 | 3443 38193 38268
338 | 3455 38216 38257
339 | 3463 38237 38277
340 | 3475 38250 38292
341 | 3484 38258 38297
342 | 3496 38254 38306
343 | 3504 38284 38304
344 | 3516 38309 38307
345 | 3525 38303 38303
346 | 3537 38326 38319
347 | 3545 38329 38319
348 | 3557 38349 38324
349 | 3566 38380 38326
350 | 3578 38366 38330
351 | 3586 38372 38331
352 | 3598 38390 38349
353 | 3607 38405 38347
354 | 3619 38403 38357
355 | 3627 38426 38341
356 | 3639 38418 38344
357 | 3648 38451 38342
358 | 3660 38458 38354
359 | 3668 38466 38362
360 | 3680 38492 38359
361 | 3689 38491 38369
362 | 3701 38502 38361
363 | 3709 38513 38369
364 | 3721 38530 38363
365 | 3729 38545 38391
366 | 3742 38551 38389
367 | 3750 38555 38390
368 | 3762 38571 38381
369 | 3770 38586 38393
370 | 3782 38600 38392
371 | 3791 38610 38395
372 | 3803 38624 38388
373 | 3811 38643 38398
374 | 3823 38654 38412
375 | 3832 38646 38411
376 | 3844 38655 38417
377 | 3852 38684 38422
378 | 3865 38694 38415
379 | 3873 38688 38429
380 | 3885 38697 38404
381 | 3893 38684 38403
382 | 3905 38657 38373
383 | 3914 38616 38362
384 | 3926 38545 38327
385 | 3934 38482 38293
386 | 3947 38430 38259
387 | 3955 38355 38232
388 | 3967 38286 38207
389 | 3975 38235 38162
390 | 3987 38198 38135
391 | 3996 38151 38129
392 | 4008 38129 38114
393 | 4016 38114 38107
394 | 4028 38085 38111
395 | 4037 38081 38084
396 | 4049 38065 38088
397 | 4057 38054 38081
398 | 4069 38033 38073
399 | 4078 38031 38063
400 | 4090 38023 38068
401 | 4098 38027 38075
402 | 4110 38017 38047
403 | 4119 38009 38064
404 | 4131 38015 38063
405 | 4139 38021 38054
406 | 4151 38030 38067
407 | 4160 38037 38071
408 | 4172 38044 38068
409 | 4180 38089 38092
410 | 4192 38089 38080
411 | 4201 38099 38082
412 | 4213 38120 38091
413 | 4221 38143 38093
414 | 4233 38132 38102
415 | 4242 38137 38102
416 | 4254 38126 38078
417 | 4262 38133 38081
418 | 4274 38145 38100
419 | 4282 38136 38083
420 | 4295 38130 38085
421 | 4303 38125 38068
422 | 4315 38121 38079
423 | 4323 38123 38074
424 | 4336 38113 38067
425 | 4344 38142 38071
426 | 4356 38137 38075
427 | 4364 38135 38073
428 | 4377 38142 38061
429 | 4385 38162 38072
430 | 4397 38151 38071
431 | 4405 38175 38070
432 | 4418 38201 38070
433 | 4426 38210 38072
434 | 4438 38217 38086
435 | 4446 38227 38100
436 | 4458 38242 38090
437 | 4467 38266 38072
438 | 4479 38275 38093
439 | 4487 38272 38111
440 | 4500 38289 38105
441 | 4508 38298 38106
442 | 4520 38305 38114
443 | 4528 38322 38108
444 | 4541 38332 38123
445 | 4549 38341 38114
446 | 4561 38363 38130
447 | 4569 38367 38121
448 | 4581 38370 38131
449 | 4590 38380 38134
450 | 4602 38393 38137
451 | 4610 38395 38152
452 | 4622 38404 38147
453 | 4631 38403 38145
454 | 4643 38416 38133
455 | 4651 38417 38141
456 | 4663 38431 38144
457 | 4672 38428 38156
458 | 4684 38418 38150
459 | 4692 38434 38150
460 | 4704 38447 38156
461 | 4713 38450 38143
462 | 4725 38463 38157
463 | 4733 38463 38145
464 | 4745 38476 38177
465 | 4754 38497 38171
466 | 4766 38503 38166
467 | 4774 38513 38168
468 | 4786 38518 38167
469 | 4794 38524 38184
470 | 4807 38512 38165
471 | 4815 38481 38131
472 | 4827 38459 38117
473 | 4835 38415 38094
474 | 4848 38357 38065
475 | 4856 38304 38037
476 | 4868 38231 37999
477 | 4876 38160 37978
478 | 4889 38123 37949
479 | 4897 38058 37926
480 | 4909 38021 37916
481 | 4917 37980 37904
482 | 4929 37948 37881
483 | 4938 37934 37860
484 | 4950 37924 37863
485 | 4958 37908 37861
486 | 4971 37896 37842
487 | 4979 37897 37837
488 | 4991 37866 37843
489 | 4999 37862 37831
490 | 5012 37854 37833
491 | 5020 37829 37823
492 | 5032 37838 37823
493 | 5040 37837 37828
494 | 5052 37837 37808
495 | 5061 37850 37825
496 | 5073 37845 37819
497 | 5081 37856 37821
498 | 5093 37884 37825
499 | 5102 37886 37835
500 | 5114 37897 37831
501 | 5122 37903 37844
502 | 5134 37913 37848
503 | 5143 37932 37851
504 | 5155 37931 37854
505 | 5163 37913 37852
506 | 5175 37926 37841
507 | 5184 37913 37842
508 | 5196 37925 37846
509 | 5208 37903 37844
510 | 5216 37892 37813
511 | 5228 37896 37828
512 | 5237 37894 37826
513 | 5249 37906 37819
514 | 5257 37910 37819
515 | 5269 37924 37815
516 | 5278 37924 37815
517 | 5290 37941 37830
518 | 5298 37957 37834
519 | 5310 37982 37842
520 | 5319 37996 37840
521 | 5331 38011 37845
522 | 5339 38025 37855
523 | 5351 38029 37857
524 | 5360 38034 37865
525 | 5372 38059 37850
526 | 5380 38074 37861
527 | 5392 38083 37856
528 | 5401 38097 37857
529 | 5413 38107 37862
530 | 5421 38117 37852
531 | 5433 38138 37865
532 | 5442 38162 37884
533 | 5454 38164 37866
534 | 5462 38179 37880
535 | 5474 38196 37883
536 | 5483 38202 37896
537 | 5495 38213 37876
538 | 5503 38237 37901
539 | 5515 38242 37912
540 | 5524 38260 37909
541 | 5536 38264 37925
542 | 5544 38278 37931
543 | 5556 38302 37912
544 | 5564 38304 37922
545 | 5577 38322 37933
546 | 5585 38330 37944
547 | 5597 38349 37923
548 | 5605 38349 37943
549 | 5618 38362 37927
550 | 5626 38358 37935
551 | 5638 38372 37945
552 | 5646 38386 37946
553 | 5659 38399 37957
554 | 5667 38417 37949
555 | 5679 38433 37960
556 | 5687 38445 37967
557 | 5699 38438 37965
558 | 5708 38463 37979
559 | 5720 38462 37977
560 | 5728 38479 37979
561 | 5740 38477 37975
562 | 5749 38490 37974
563 | 5761 38513 37981
564 | 5769 38516 37978
565 | 5781 38541 37979
566 | 5790 38539 37971
567 | 5802 38552 37989
568 | 5810 38554 37993
569 | 5822 38562 37982
570 | 5831 38535 37961
571 | 5843 38502 37936
572 | 5851 38447 37894
573 | 5863 38387 37879
574 | 5872 38328 37839
575 | 5884 38275 37809
576 | 5892 38208 37778
577 | 5904 38151 37767
578 | 5913 38116 37738
579 | 5925 38068 37696
580 | 5933 38029 37694
581 | 5945 37997 37681
582 | 5954 37971 37682
583 | 5966 37951 37661
584 | 5974 37928 37642
585 | 5986 37915 37651
586 | 5995 37907 37641
587 | 6007 37896 37640
588 | 6015 37875 37619
589 | 6028 37877 37627
590 | 6035 37840 37614
591 | 6048 37830 37603
592 | 6056 37819 37606
593 | 6068 37825 37610
594 | 6076 37821 37609
595 | 6089 37832 37613
596 | 6097 37830 37605
597 | 6109 37833 37603
598 | 6117 37847 37620
599 | 6130 37851 37604
600 | 6138 37870 37611
601 | 6150 37886 37620
602 | 6158 37894 37622
603 | 6171 37889 37604
604 | 6179 37897 37623
605 | 6191 37899 37626
606 | 6199 37876 37622
607 | 6212 37880 37615
608 | 6220 37894 37615
609 | 6232 37890 37603
610 | 6240 37880 37605
611 | 6253 37880 37603
612 | 6261 37868 37612
613 | 6273 37848 37610
614 | 6281 37858 37605
615 | 6294 37871 37601
616 | 6302 37874 37605
617 | 6314 37875 37603
618 | 6322 37891 37608
619 | 6334 37873 37609
620 | 6343 37889 37612
621 | 6355 37902 37613
622 | 6363 37894 37618
623 | 6375 37911 37609
624 | 6384 37908 37604
625 | 6396 37916 37599
626 | 6404 37931 37626
627 | 6416 37933 37622
628 | 6425 37952 37621
629 | 6437 37959 37627
630 | 6445 37976 37627
631 | 6457 37962 37632
632 | 6466 37966 37651
633 | 6478 37975 37647
634 | 6486 37993 37643
635 | 6498 37993 37654
636 | 6507 38001 37641
637 | 6519 38016 37649
638 | 6527 38020 37641
639 | 6539 38020 37651
640 | 6547 38022 37651
641 | 6560 38032 37654
642 | 6568 38036 37648
643 | 6580 38051 37653
644 | 6588 38050 37665
645 | 6601 38063 37651
646 | 6609 38061 37656
647 | 6621 38065 37667
648 | 6629 38090 37671
649 | 6642 38086 37663
650 | 6650 38109 37680
651 | 6662 38105 37683
652 | 6670 38114 37677
653 | 6683 38110 37693
654 | 6691 38123 37683
655 | 6703 38122 37672
656 | 6711 38143 37678
657 | 6724 38136 37697
658 | 6732 38143 37687
659 | 6744 38151 37677
660 | 6752 38171 37698
661 | 6765 38164 37711
662 | 6777 38165 37707
663 | 6785 38190 37705
664 | 6797 38191 37702
665 | 6806 38203 37708
666 | 6817 38202 37702
667 | 6826 38200 37701
668 | 6838 38224 37710
669 | 6846 38214 37720
670 | 6858 38227 37711
671 | 6867 38223 37725
672 | 6879 38246 37713
673 | 6887 38242 37736
674 | 6899 38247 37722
675 | 6908 38260 37727
676 | 6920 38272 37739
677 | 6928 38266 37726
678 | 6940 38245 37709
679 | 6949 38221 37704
680 | 6961 38177 37667
681 | 6969 38111 37640
682 | 6981 38045 37618
683 | 6990 37960 37582
684 | 7002 37920 37538
685 | 7010 37851 37508
686 | 7022 37795 37480
687 | 7032 37751 37451
688 | 7043 37697 37445
689 | 7051 37674 37438
690 | 7063 37629 37406
691 | 7072 37625 37420
692 | 7084 37584 37396
693 | 7092 37570 37399
694 | 7104 37554 37386
695 | 7113 37541 37374
696 | 7125 37520 37362
697 | 7133 37519 37370
698 | 7145 37509 37343
699 | 7154 37494 37346
700 | 7166 37479 37348
701 | 7174 37487 37326
702 | 7186 37487 37316
703 | 7195 37478 37331
704 | 7207 37484 37334
705 | 7215 37487 37346
706 | 7227 37513 37349
707 | 7235 37535 37354
708 | 7248 37530 37357
709 | 7256 37551 37377
710 | 7268 37558 37371
711 | 7277 37566 37399
712 | 7289 37574 37353
713 | 7297 37563 37376
714 | 7309 37575 37372
715 | 7317 37582 37372
716 | 7330 37549 37356
717 | 7338 37559 37362
718 | 7350 37557 37358
719 | 7358 37553 37354
720 | 7371 37555 37363
721 | 7379 37554 37332
722 | 7391 37561 37343
723 | 7399 37553 37340
724 | 7412 37555 37338
725 | 7420 37536 37346
726 | 7432 37544 37345
727 | 7440 37559 37340
728 | 7453 37559 37350
729 | 7461 37560 37344
730 | 7473 37563 37352
731 | 7481 37563 37366
732 | 7493 37576 37365
733 | 7502 37591 37358
734 | 7514 37593 37365
735 | 7522 37611 37370
736 | 7534 37605 37367
737 | 7543 37627 37368
738 | 7555 37627 37364
739 | 7563 37655 37386
740 | 7575 37649 37385
741 | 7584 37668 37380
742 | 7596 37668 37397
743 | 7604 37687 37372
744 | 7616 37694 37397
745 | 7625 37717 37394
746 | 7637 37724 37408
747 | 7645 37715 37412
748 | 7657 37740 37422
749 | 7666 37738 37431
750 | 7678 37754 37430
751 | 7686 37769 37438
752 | 7698 37784 37439
753 | 7707 37793 37453
754 | 7719 37793 37452
755 | 7727 37810 37436
756 | 7739 37814 37440
757 | 7748 37831 37439
758 | 7760 37830 37442
759 | 7768 37842 37459
760 | 7780 37869 37462
761 | 7788 37858 37468
762 | 7801 37883 37464
763 | 7809 37873 37461
764 | 7821 37887 37466
765 | 7829 37900 37476
766 | 7842 37912 37480
767 | 7850 37909 37466
768 | 7862 37922 37482
769 | 7870 37932 37491
770 | 7883 37944 37481
771 | 7891 37960 37479
772 | 7903 37991 37488
773 | 7911 37983 37498
774 | 7924 37977 37504
775 | 7932 37994 37497
776 | 7944 38017 37512
777 | 7952 38017 37507
778 | 7965 38049 37530
779 | 7973 38032 37526
780 | 7985 38053 37520
781 | 7993 38059 37505
782 | 8006 38059 37518
783 | 8014 38057 37502
784 | 8026 38014 37513
785 | 8036 37961 37474
786 | 8046 37919 37439
787 | 8055 37837 37424
788 | 8067 37777 37381
789 | 8075 37685 37338
790 | 8087 37625 37307
791 | 8096 37535 37280
792 | 8108 37490 37268
793 | 8116 37437 37226
794 | 8128 37381 37206
795 | 8137 37375 37196
796 | 8149 37345 37192
797 | 8157 37322 37194
798 | 8169 37309 37159
799 | 8178 37279 37163
800 | 8190 37279 37164
801 | 8198 37258 37161
802 | 8210 37258 37156
803 | 8219 37258 37152
804 | 8231 37227 37134
805 | 8239 37226 37151
806 | 8251 37229 37143
807 | 8260 37232 37139
808 | 8272 37241 37150
809 | 8280 37248 37152
810 | 8292 37254 37157
811 | 8300 37264 37141
812 | 8313 37271 37165
813 | 8321 37282 37173
814 | 8333 37300 37170
815 | 8341 37301 37173
816 | 8354 37303 37178
817 | 8362 37322 37200
818 | 8374 37312 37183
819 | 8382 37307 37175
820 | 8395 37296 37184
821 | 8403 37302 37182
822 | 8415 37303 37163
823 | 8423 37289 37172
824 | 8436 37278 37173
825 | 8444 37275 37182
826 | 8456 37276 37175
827 | 8464 37259 37175
828 | 8477 37262 37166
829 | 8489 37274 37152
830 | 8497 37265 37172
831 | 8509 37263 37158
832 | 8518 37271 37149
833 | 8530 37264 37164
834 | 8538 37275 37148
835 | 8550 37273 37165
836 | 8559 37279 37170
837 | 8571 37284 37155
838 | 8579 37287 37161
839 | 8591 37299 37154
840 | 8600 37305 37179
841 | 8611 37300 37182
842 | 8620 37316 37188
843 | 8632 37325 37192
844 | 8640 37360 37192
845 | 8652 37369 37208
846 | 8661 37366 37198
847 | 8673 37390 37211
848 | 8681 37384 37210
849 | 8693 37387 37214
850 | 8702 37403 37230
851 | 8714 37418 37227
852 | 8722 37424 37220
853 | 8734 37428 37237
854 | 8743 37456 37231
855 | 8755 37470 37231
856 | 8763 37465 37237
857 | 8775 37478 37230
858 | 8784 37496 37249
859 | 8796 37489 37260
860 | 8804 37506 37264
861 | 8816 37518 37263
862 | 8825 37531 37271
863 | 8837 37536 37278
864 | 8845 37544 37291
865 | 8857 37551 37281
866 | 8866 37554 37267
867 | 8878 37552 37268
868 | 8886 37581 37274
869 | 8898 37576 37296
870 | 8907 37591 37290
871 | 8919 37581 37296
872 | 8927 37599 37299
873 | 8939 37611 37311
874 | 8948 37627 37298
875 | 8960 37650 37312
876 | 8968 37641 37322
877 | 8980 37655 37332
878 | 8989 37664 37330
879 | 9001 37675 37317
880 | 9009 37643 37303
881 | 9021 37613 37269
882 | 9030 37569 37242
883 | 9042 37505 37213
884 | 9050 37440 37170
885 | 9062 37344 37137
886 | 9070 37277 37117
887 | 9083 37207 37090
888 | 9091 37127 37056
889 | 9103 37086 37034
890 | 9111 37033 37013
891 | 9124 37002 37003
892 | 9132 36974 36983
893 | 9144 36953 36968
894 | 9152 36954 36972
895 | 9165 36924 36957
896 | 9173 36900 36962
897 | 9185 36903 36948
898 | 9193 36902 36956
899 | 9206 36885 36955
900 | 9214 36881 36939
901 | 9226 36877 36941
902 | 9234 36863 36942
903 | 9247 36840 36948
904 | 9255 36857 36948
905 | 9267 36857 36954
906 | 9275 36855 36945
907 | 9287 36879 36950
908 | 9296 36891 36968
909 | 9308 36919 36972
910 | 9316 36931 36973
911 | 9329 36940 36991
912 | 9337 36959 36996
913 | 9349 36967 36991
914 | 9357 36983 36995
915 | 9369 36995 37008
916 | 9378 36996 36998
917 | 9390 37015 36993
918 | 9398 37012 37011
919 | 9410 37020 37007
920 | 9419 37007 36991
921 | 9431 37006 37008
922 | 9439 37012 37008
923 | 9451 37003 37019
924 | 9460 37016 37002
925 | 9472 37039 37013
926 | 9480 37024 36994
927 | 9492 37033 36996
928 | 9500 37020 36996
929 | 9513 37044 37007
930 | 9521 37050 37024
931 | 9533 37052 37019
932 | 9542 37056 37020
933 | 9554 37073 37018
934 | 9562 37067 37020
935 | 9574 37084 37027
936 | 9582 37099 37027
937 | 9595 37102 37045
938 | 9603 37116 37030
939 | 9615 37119 37044
940 | 9623 37126 37034
941 | 9636 37150 37064
942 | 9644 37150 37071
943 | 9656 37166 37060
944 | 9664 37170 37068
945 | 9677 37180 37065
946 | 9685 37195 37069
947 | 9697 37203 37049
948 | 9705 37204 37094
949 | 9718 37226 37070
950 | 9726 37229 37090
951 | 9738 37251 37095
952 | 9746 37257 37102
953 | 9759 37272 37101
954 | 9767 37292 37108
955 | 9779 37293 37098
956 | 9787 37306 37126
957 | 9799 37317 37112
958 | 9808 37313 37120
959 | 9820 37333 37141
960 | 9828 37338 37141
961 | 9840 37349 37119
962 | 9849 37367 37133
963 | 9861 37382 37142
964 | 9869 37399 37156
965 | 9881 37401 37141
966 | 9890 37416 37159
967 | 9902 37407 37159
968 | 9910 37421 37173
969 | 9922 37412 37163
970 | 9931 37443 37161
971 | 9943 37440 37173
972 | 9955 37442 37178
973 | 9963 37468 37180
974 | 9975 37487 37177
975 | 9984 37495 37162
976 | 9996 37493 37194
977 | 10004 37496 37179
978 | 10016 37467 37163
979 | 10025 37445 37135
980 | 10037 37404 37112
981 | 10045 37333 37089
982 | 10057 37255 37051
983 | 10066 37162 37006
984 | 10078 37071 36973
985 | 10086 36976 36911
986 | 10098 36905 36864
987 | 10107 36842 36870
988 | 10119 36724 36822
989 | 10127 36679 36804
990 | 10139 36661 36785
991 | 10148 36643 36767
992 | 10160 36620 36776
993 | 10168 36588 36766
994 | 10180 36575 36766
995 | 10189 36554 36756
996 | 10201 36536 36751
997 | 10209 36541 36729
998 | 10221 36533 36730
999 | 10230 36520 36734
1000 | 10242 36509 36723
1001 | 10250 36505 36721
1002 | 10262 36511 36733
1003 | 10270 36509 36732
1004 | 10283 36525 36752
1005 | 10291 36527 36761
1006 | 10303 36559 36766
1007 | 10311 36581 36780
1008 | 10324 36608 36774
1009 | 10332 36618 36790
1010 | 10344 36639 36791
1011 | 10353 36655 36792
1012 | 10365 36657 36820
1013 | 10373 36648 36800
1014 | 10385 36654 36798
1015 | 10393 36657 36786
1016 | 10406 36655 36796
1017 | 10414 36654 36787
1018 | 10426 36659 36794
1019 | 10434 36646 36803
1020 | 10447 36643 36793
1021 | 10455 36636 36804
1022 | 10467 36636 36778
1023 | 10475 36629 36787
1024 | 10488 36619 36777
1025 | 10496 36648 36780
1026 | 10508 36639 36782
1027 | 10516 36638 36782
1028 | 10528 36644 36791
1029 | 10537 36649 36791
1030 | 10549 36661 36798
1031 | 10557 36668 36791
1032 | 10569 36673 36810
1033 | 10578 36690 36810
1034 | 10590 36706 36818
1035 | 10598 36695 36819
1036 | 10610 36729 36811
1037 | 10619 36728 36823
1038 | 10631 36736 36829
1039 | 10639 36761 36828
1040 | 10651 36762 36828
1041 | 10660 36771 36843
1042 | 10672 36796 36849
1043 | 10680 36807 36869
1044 | 10692 36807 36844
1045 | 10701 36821 36863
1046 | 10713 36835 36864
1047 | 10721 36832 36865
1048 | 10733 36859 36879
1049 | 10742 36860 36877
1050 | 10754 36872 36887
1051 | 10762 36891 36890
1052 | 10774 36925 36894
1053 | 10782 36918 36908
1054 | 10795 36938 36899
1055 | 10803 36949 36922
1056 | 10815 36967 36918
1057 | 10823 36977 36920
1058 | 10836 36988 36931
1059 | 10844 37013 36933
1060 | 10856 37012 36949
1061 | 10864 37021 36945
1062 | 10877 37042 36956
1063 | 10885 37053 36955
1064 | 10897 37080 36951
1065 | 10905 37068 36958
1066 | 10918 37092 36962
1067 | 10926 37109 36984
1068 | 10938 37123 36984
1069 | 10946 37164 36989
1070 | 10959 37163 36994
1071 | 10967 37175 37004
1072 | 10979 37179 37022
1073 | 10987 37194 37013
1074 | 11000 37200 37012
1075 | 11008 37175 37013
1076 | 11020 37161 36982
1077 | 11028 37123 36965
1078 | 11041 37060 36911
1079 | 11049 37007 36907
1080 | 11061 36900 36848
1081 | 11069 36844 36823
1082 | 11082 36752 36773
1083 | 11090 36663 36749
1084 | 11102 36609 36708
1085 | 11110 36534 36694
1086 | 11122 36495 36671
1087 | 11131 36463 36653
1088 | 11143 36446 36636
1089 | 11151 36416 36631
1090 | 11163 36394 36625
1091 | 11172 36386 36611
1092 | 11184 36387 36623
1093 | 11192 36371 36610
1094 | 11204 36364 36602
1095 | 11213 36366 36603
1096 | 11225 36326 36586
1097 | 11233 36318 36587
1098 | 11245 36331 36589
1099 | 11253 36337 36585
1100 | 11266 36355 36614
1101 | 11274 36357 36605
1102 | 11286 36375 36623
1103 | 11294 36398 36621
1104 | 11307 36415 36639
1105 | 11315 36431 36647
1106 | 11327 36458 36649
1107 | 11335 36476 36678
1108 | 11348 36497 36668
1109 | 11356 36495 36680
1110 | 11368 36520 36683
1111 | 11380 36495 36688
1112 | 11389 36501 36667
1113 | 11401 36506 36669
1114 | 11409 36493 36682
1115 | 11421 36504 36668
1116 | 11430 36489 36673
1117 | 11442 36501 36670
1118 | 11450 36495 36672
1119 | 11462 36500 36667
1120 | 11471 36487 36663
1121 | 11483 36488 36672
1122 | 11491 36495 36672
1123 | 11503 36515 36675
1124 | 11512 36524 36675
1125 | 11524 36529 36680
1126 | 11532 36531 36684
1127 | 11544 36541 36686
1128 | 11552 36555 36690
1129 | 11565 36565 36700
1130 | 11573 36585 36700
1131 | 11585 36602 36723
1132 | 11593 36621 36710
1133 | 11606 36636 36725
1134 | 11614 36646 36734
1135 | 11626 36640 36737
1136 | 11635 36666 36758
1137 | 11647 36688 36748
1138 | 11655 36688 36742
1139 | 11667 36708 36747
1140 | 11675 36702 36762
1141 | 11687 36728 36755
1142 | 11696 36740 36766
1143 | 11708 36754 36768
1144 | 11716 36768 36763
1145 | 11728 36757 36788
1146 | 11737 36773 36798
1147 | 11749 36774 36771
1148 | 11757 36787 36809
1149 | 11769 36797 36808
1150 | 11778 36817 36814
1151 | 11790 36815 36821
1152 | 11798 36818 36804
1153 | 11810 36829 36818
1154 | 11819 36848 36816
1155 | 11831 36862 36829
1156 | 11839 36870 36832
1157 | 11851 36865 36826
1158 | 11860 36872 36829
1159 | 11872 36898 36820
1160 | 11880 36903 36837
1161 | 11892 36919 36837
1162 | 11901 36919 36847
1163 | 11913 36927 36842
1164 | 11921 36936 36861
1165 | 11933 36939 36870
1166 | 11942 36955 36865
1167 | 11954 36982 36874
1168 | 11962 36947 36836
1169 | 11974 36934 36827
1170 | 11983 36889 36806
1171 | 11995 36819 36775
1172 | 12003 36748 36743
1173 | 12015 36670 36696
1174 | 12024 36584 36663
1175 | 12036 36504 36622
1176 | 12044 36427 36599
1177 | 12056 36367 36564
1178 | 12065 36324 36546
1179 | 12077 36294 36534
1180 | 12085 36278 36527
1181 | 12097 36227 36521
1182 | 12106 36234 36516
1183 | 12118 36193 36511
1184 | 12126 36195 36479
1185 | 12138 36176 36490
1186 | 12146 36163 36489
1187 | 12159 36174 36487
1188 | 12167 36173 36487
1189 | 12179 36161 36474
1190 | 12187 36167 36473
1191 | 12200 36151 36471
1192 | 12208 36146 36483
1193 | 12220 36168 36498
1194 | 12228 36167 36485
1195 | 12241 36185 36497
1196 | 12249 36215 36500
1197 | 12261 36249 36532
1198 | 12269 36266 36525
1199 | 12282 36303 36552
1200 | 12290 36307 36557
1201 | 12302 36342 36549
1202 | 12310 36342 36571
1203 | 12323 36344 36559
1204 | 12331 36354 36554
1205 | 12343 36358 36561
1206 | 12351 36353 36562
1207 | 12363 36344 36549
1208 | 12372 36347 36572
1209 | 12384 36351 36563
1210 | 12392 36348 36565
1211 | 12404 36347 36567
1212 | 12413 36351 36570
1213 | 12425 36351 36580
1214 | 12433 36354 36567
1215 | 12445 36370 36572
1216 | 12454 36384 36572
1217 | 12466 36389 36585
1218 | 12474 36389 36582
1219 | 12486 36406 36591
1220 | 12495 36425 36603
1221 | 12507 36438 36603
1222 | 12515 36454 36614
1223 | 12527 36476 36605
1224 | 12535 36484 36611
1225 | 12548 36500 36628
1226 | 12556 36499 36648
1227 | 12568 36531 36645
1228 | 12576 36545 36642
1229 | 12589 36554 36658
1230 | 12597 36569 36655
1231 | 12609 36578 36659
1232 | 12617 36594 36663
1233 | 12630 36613 36679
1234 | 12638 36622 36693
1235 | 12650 36633 36688
1236 | 12658 36651 36698
1237 | 12671 36667 36707
1238 | 12679 36690 36722
1239 | 12691 36703 36712
1240 | 12699 36736 36713
1241 | 12712 36733 36730
1242 | 12720 36756 36744
1243 | 12732 36781 36755
1244 | 12740 36800 36751
1245 | 12753 36803 36754
1246 | 12761 36807 36758
1247 | 12773 36842 36742
1248 | 12785 36859 36746
1249 | 12794 36840 36776
1250 | 12806 36869 36787
1251 | 12814 36885 36785
1252 | 12826 36891 36793
1253 | 12834 36910 36807
1254 | 12847 36913 36811
1255 | 12855 36935 36795
1256 | 12867 36948 36815
1257 | 12875 36958 36814
1258 | 12888 36966 36812
1259 | 12896 36971 36839
1260 | 12908 36998 36831
1261 | 12916 37011 36842
1262 | 12928 37037 36844
1263 | 12937 37022 36833
1264 | 12949 37052 36867
1265 | 12957 37061 36859
1266 | 12969 37069 36872
1267 | 12978 37092 36858
1268 | 12990 37096 36855
1269 | 12998 37092 36875
1270 | 13010 37061 36854
1271 | 13019 37025 36840
1272 | 13031 36972 36799
1273 | 13039 36882 36772
1274 | 13052 36805 36709
1275 | 13060 36740 36674
1276 | 13072 36564 36608
1277 | 13080 36502 36567
1278 | 13092 36438 36535
1279 | 13101 36389 36519
1280 | 13113 36358 36505
1281 | 13121 36345 36503
1282 | 13133 36322 36494
1283 | 13142 36298 36487
1284 | 13154 36284 36482
1285 | 13162 36273 36478
1286 | 13174 36256 36472
1287 | 13183 36245 36471
1288 | 13195 36221 36447
1289 | 13203 36223 36452
1290 | 13215 36225 36447
1291 | 13224 36206 36452
1292 | 13236 36208 36452
1293 | 13244 36200 36452
1294 | 13256 36210 36450
1295 | 13265 36208 36448
1296 | 13277 36217 36461
1297 | 13285 36236 36467
1298 | 13297 36270 36469
1299 | 13306 36281 36483
1300 | 13318 36291 36500
1301 | 13326 36336 36517
1302 | 13338 36332 36499
1303 | 13346 36348 36506
1304 | 13359 36347 36521
1305 | 13367 36352 36518
1306 | 13379 36350 36509
1307 | 13387 36348 36496
1308 | 13400 36341 36512
1309 | 13408 36342 36508
1310 | 13420 36332 36489
1311 | 13428 36325 36493
1312 | 13441 36317 36488
1313 | 13449 36344 36481
1314 | 13461 36315 36492
1315 | 13469 36335 36502
1316 | 13482 36337 36500
1317 | 13490 36347 36504
1318 | 13502 36369 36490
1319 | 13510 36377 36513
1320 | 13523 36375 36525
1321 | 13531 36379 36522
1322 | 13543 36402 36530
1323 | 13551 36409 36546
1324 | 13564 36444 36558
1325 | 13572 36433 36541
1326 | 13584 36446 36560
1327 | 13592 36468 36572
1328 | 13605 36483 36579
1329 | 13613 36498 36562
1330 | 13625 36511 36578
1331 | 13633 36527 36579
1332 | 13645 36560 36599
1333 | 13654 36565 36603
1334 | 13666 36579 36608
1335 | 13674 36597 36612
1336 | 13686 36601 36616
1337 | 13695 36606 36624
1338 | 13707 36635 36627
1339 | 13715 36645 36635
1340 | 13727 36670 36649
1341 | 13736 36676 36656
1342 | 13748 36697 36652
1343 | 13756 36711 36674
1344 | 13768 36721 36681
1345 | 13777 36737 36665
1346 | 13789 36747 36693
1347 | 13797 36769 36684
1348 | 13809 36808 36700
1349 | 13817 36821 36704
1350 | 13830 36833 36707
1351 | 13838 36853 36715
1352 | 13850 36867 36730
1353 | 13858 36891 36738
1354 | 13871 36887 36740
1355 | 13879 36903 36736
1356 | 13891 36908 36748
1357 | 13899 36929 36763
1358 | 13912 36934 36772
1359 | 13920 36940 36763
1360 | 13932 36946 36758
1361 | 13940 36948 36778
1362 | 13953 36961 36772
1363 | 13961 36981 36777
1364 | 13973 36963 36791
1365 | 13981 36998 36788
1366 | 13994 37011 36785
1367 | 14002 37014 36785
1368 | 14014 37024 36786
1369 | 14022 37032 36818
1370 | 14035 37044 36817
1371 | 14043 37055 36819
1372 | 14055 37064 36811
1373 | 14063 37067 36823
1374 | 14076 37089 36820
1375 | 14084 37078 36787
1376 | 14096 37050 36783
1377 | 14104 37008 36775
1378 | 14116 36949 36739
1379 | 14125 36884 36688
1380 | 14137 36792 36656
1381 | 14145 36703 36588
1382 | 14157 36603 36560
1383 | 14166 36521 36519
1384 | 14178 36394 36472
1385 | 14186 36339 36443
1386 | 14198 36296 36450
1387 | 14207 36276 36429
1388 | 14219 36264 36434
1389 | 14231 36237 36395
1390 | 14239 36236 36406
1391 | 14251 36219 36398
1392 | 14260 36200 36401
1393 | 14272 36184 36379
1394 | 14280 36192 36386
1395 | 14292 36182 36366
1396 | 14301 36172 36378
1397 | 14313 36172 36365
1398 | 14321 36155 36374
1399 | 14333 36171 36380
1400 | 14342 36174 36391
1401 | 14354 36190 36402
1402 | 14362 36225 36404
1403 | 14374 36235 36422
1404 | 14383 36266 36426
1405 | 14395 36285 36444
1406 | 14403 36297 36461
1407 | 14415 36327 36458
1408 | 14424 36329 36458
1409 | 14436 36355 36465
1410 | 14444 36363 36480
1411 | 14456 36366 36464
1412 | 14465 36357 36457
1413 | 14477 36358 36463
1414 | 14485 36355 36462
1415 | 14497 36362 36458
1416 | 14506 36353 36468
1417 | 14518 36336 36451
1418 | 14526 36338 36444
1419 | 14538 36336 36462
1420 | 14547 36346 36461
1421 | 14559 36367 36465
1422 | 14567 36365 36468
1423 | 14579 36369 36464
1424 | 14588 36402 36460
1425 | 14600 36395 36479
1426 | 14608 36415 36480
1427 | 14620 36418 36492
1428 | 14628 36430 36497
1429 | 14641 36434 36488
1430 | 14649 36445 36490
1431 | 14661 36466 36490
1432 | 14669 36458 36505
1433 | 14682 36483 36497
1434 | 14690 36495 36512
1435 | 14702 36507 36514
1436 | 14710 36517 36520
1437 | 14723 36524 36519
1438 | 14731 36551 36526
1439 | 14743 36550 36549
1440 | 14751 36559 36526
1441 | 14764 36579 36544
1442 | 14772 36579 36551
1443 | 14784 36615 36544
1444 | 14792 36602 36556
1445 | 14805 36631 36558
1446 | 14813 36624 36553
1447 | 14825 36621 36564
1448 | 14833 36644 36578
1449 | 14846 36634 36577
1450 | 14854 36655 36575
1451 | 14866 36677 36588
1452 | 14874 36681 36594
1453 | 14886 36685 36586
1454 | 14895 36696 36598
1455 | 14907 36695 36595
1456 | 14915 36710 36603
1457 | 14927 36727 36623
1458 | 14936 36741 36613
1459 | 14948 36747 36614
1460 | 14956 36771 36621
1461 | 14968 36776 36634
1462 | 14977 36794 36629
1463 | 14989 36810 36641
1464 | 14997 36826 36646
1465 | 15009 36828 36646
1466 | 15018 36844 36669
1467 | 15030 36860 36675
1468 | 15038 36879 36668
1469 | 15050 36882 36689
1470 | 15059 36907 36673
1471 | 15071 36901 36691
1472 | 15079 36896 36653
1473 | 15091 36878 36665
1474 | 15100 36819 36626
1475 | 15112 36761 36586
1476 | 15120 36690 36546
1477 | 15132 36606 36515
1478 | 15140 36514 36489
1479 | 15153 36449 36437
1480 | 15161 36353 36406
1481 | 15173 36293 36374
1482 | 15181 36253 36369
1483 | 15194 36205 36344
1484 | 15202 36177 36327
1485 | 15214 36148 36321
1486 | 15222 36129 36311
1487 | 15235 36118 36319
1488 | 15243 36118 36308
1489 | 15255 36104 36297
1490 | 15263 36099 36284
1491 | 15276 36093 36308
1492 | 15284 36084 36284
1493 | 15296 36084 36290
1494 | 15304 36086 36290
1495 | 15317 36084 36309
1496 | 15325 36109 36313
1497 | 15337 36118 36306
1498 | 15345 36141 36333
1499 | 15358 36180 36320
1500 | 15366 36209 36346
1501 | 15378 36228 36370
1502 | 15386 36250 36374
1503 | 15398 36278 36386
1504 | 15407 36294 36371
1505 | 15419 36291 36377
1506 | 15427 36297 36395
1507 | 15439 36318 36388
1508 | 15448 36310 36402
1509 | 15460 36325 36407
1510 | 15468 36338 36400
1511 | 15480 36334 36401
1512 | 15489 36333 36405
1513 | 15501 36345 36400
1514 | 15509 36324 36391
1515 | 15521 36340 36391
1516 | 15530 36347 36389
1517 | 15542 36331 36394
1518 | 15550 36335 36394
1519 | 15562 36332 36388
1520 | 15571 36353 36403
1521 | 15583 36388 36401
1522 | 15591 36362 36410
1523 | 15603 36390 36403
1524 | 15611 36398 36421
1525 | 15624 36406 36420
1526 | 15636 36415 36412
1527 | 15644 36441 36427
1528 | 15656 36474 36453
1529 | 15665 36488 36441
1530 | 15677 36502 36452
1531 | 15685 36532 36459
1532 | 15697 36533 36474
1533 | 15706 36542 36474
1534 | 15718 36556 36466
1535 | 15726 36563 36479
1536 | 15738 36566 36478
1537 | 15747 36577 36493
1538 | 15759 36604 36496
1539 | 15767 36615 36499
1540 | 15779 36615 36503
1541 | 15788 36637 36499
1542 | 15800 36644 36510
1543 | 15808 36653 36523
1544 | 15820 36651 36533
1545 | 15829 36681 36537
1546 | 15841 36696 36542
1547 | 15849 36703 36544
1548 | 15861 36733 36546
1549 | 15869 36739 36561
1550 | 15882 36768 36559
1551 | 15890 36777 36565
1552 | 15902 36791 36575
1553 | 15910 36794 36579
1554 | 15923 36799 36589
1555 | 15931 36812 36586
1556 | 15943 36832 36598
1557 | 15951 36853 36613
1558 | 15964 36859 36617
1559 | 15972 36864 36617
1560 | 15984 36865 36624
1561 | 15992 36878 36633
1562 | 16005 36905 36621
1563 | 16013 36911 36629
1564 | 16025 36920 36646
1565 | 16033 36948 36659
1566 | 16045 36950 36656
1567 | 16054 36969 36653
1568 | 16066 36973 36657
1569 | 16074 36970 36672
1570 | 16087 36986 36676
1571 | 16095 37000 36674
1572 | 16107 36989 36677
1573 | 16115 37002 36666
1574 | 16128 36969 36654
1575 | 16136 36950 36642
1576 | 16148 36885 36617
1577 | 16156 36824 36567
1578 | 16168 36727 36518
1579 | 16177 36633 36471
1580 | 16189 36526 36417
1581 | 16197 36446 36386
1582 | 16209 36350 36348
1583 | 16218 36288 36324
1584 | 16230 36226 36296
1585 | 16238 36194 36278
1586 | 16250 36140 36275
1587 | 16259 36122 36264
1588 | 16271 36097 36237
1589 | 16279 36081 36234
1590 | 16291 36062 36244
1591 | 16300 36041 36226
1592 | 16312 36054 36228
1593 | 16320 36046 36203
1594 | 16332 36023 36209
1595 | 16341 36012 36225
1596 | 16353 36014 36203
1597 | 16361 36011 36204
1598 | 16373 36006 36212
1599 | 16381 36015 36222
1600 | 16394 36039 36221
1601 | 16402 36075 36246
1602 | 16414 36097 36251
1603 | 16422 36110 36261
1604 | 16435 36153 36282
1605 | 16443 36171 36300
1606 | 16455 36201 36302
1607 | 16463 36210 36281
1608 | 16476 36209 36310
1609 | 16484 36220 36314
1610 | 16496 36240 36304
1611 | 16504 36246 36313
1612 | 16517 36245 36299
1613 | 16525 36244 36292
1614 | 16537 36253 36306
1615 | 16545 36227 36310
1616 | 16558 36242 36299
1617 | 16566 36223 36302
1618 | 16578 36221 36314
1619 | 16586 36233 36304
1620 | 16599 36226 36309
1621 | 16607 36245 36319
1622 | 16619 36257 36320
1623 | 16627 36263 36329
1624 | 16640 36265 36326
1625 | 16648 36278 36311
1626 | 16660 36293 36331
1627 | 16668 36297 36339
1628 | 16680 36313 36340
1629 | 16689 36326 36357
1630 | 16701 36327 36346
1631 | 16709 36345 36341
1632 | 16721 36354 36353
1633 | 16730 36373 36361
1634 | 16742 36379 36351
1635 | 16750 36419 36376
1636 | 16762 36432 36385
1637 | 16771 36435 36381
1638 | 16783 36455 36406
1639 | 16791 36456 36407
1640 | 16803 36470 36415
1641 | 16812 36479 36417
1642 | 16824 36498 36408
1643 | 16832 36517 36429
1644 | 16844 36529 36410
1645 | 16852 36538 36440
1646 | 16865 36540 36441
1647 | 16873 36555 36443
1648 | 16885 36573 36452
1649 | 16893 36582 36459
1650 | 16906 36587 36469
1651 | 16914 36593 36467
1652 | 16926 36602 36464
1653 | 16934 36609 36469
1654 | 16947 36628 36472
1655 | 16955 36639 36481
1656 | 16967 36655 36476
1657 | 16975 36654 36489
1658 | 16988 36672 36496
1659 | 17000 36680 36491
1660 | 17008 36688 36491
1661 | 17020 36700 36508
1662 | 17029 36695 36487
1663 | 17041 36710 36510
1664 | 17049 36714 36521
1665 | 17061 36732 36514
1666 | 17070 36741 36509
1667 | 17082 36746 36527
1668 | 17090 36749 36527
1669 | 17102 36763 36535
1670 | 17111 36776 36538
1671 | 17123 36802 36531
1672 | 17131 36813 36545
1673 | 17143 36809 36542
1674 | 17152 36815 36543
1675 | 17164 36843 36571
1676 | 17172 36848 36564
1677 | 17184 36854 36563
1678 | 17192 36860 36549
1679 | 17205 36801 36534
1680 | 17213 36771 36503
1681 | 17225 36708 36480
1682 | 17233 36617 36423
1683 | 17246 36507 36378
1684 | 17254 36412 36338
1685 | 17266 36346 36298
1686 | 17274 36238 36258
1687 | 17286 36153 36226
1688 | 17295 36082 36192
1689 | 17307 36034 36182
1690 | 17315 36006 36157
1691 | 17327 35949 36154
1692 | 17336 35944 36143
1693 | 17348 35912 36122
1694 | 17356 35896 36127
1695 | 17368 35890 36125
1696 | 17377 35868 36110
1697 | 17389 35848 36101
1698 | 17397 35862 36096
1699 | 17409 35841 36107
1700 | 17418 35836 36098
1701 | 17430 35840 36099
1702 | 17438 35838 36083
1703 | 17450 35833 36097
1704 | 17459 35842 36113
1705 | 17471 35855 36115
1706 | 17479 35871 36128
1707 | 17491 35938 36152
1708 | 17500 35962 36177
1709 | 17512 35989 36197
1710 | 17520 36022 36193
1711 | 17532 36041 36207
1712 | 17541 36064 36218
1713 | 17553 36084 36213
1714 | 17561 36101 36221
1715 | 17573 36104 36237
1716 | 17582 36110 36229
1717 | 17594 36120 36224
1718 | 17602 36118 36231
1719 | 17614 36126 36234
1720 | 17623 36121 36236
1721 | 17635 36120 36229
1722 | 17643 36125 36233
1723 | 17655 36127 36233
1724 | 17663 36131 36231
1725 | 17676 36118 36233
1726 | 17684 36132 36241
1727 | 17696 36147 36237
1728 | 17704 36151 36228
1729 | 17717 36166 36241
1730 | 17725 36189 36243
1731 | 17737 36212 36239
1732 | 17745 36222 36258
1733 | 17758 36212 36246
1734 | 17766 36233 36272
1735 | 17778 36252 36269
1736 | 17786 36261 36273
1737 | 17799 36294 36296
1738 | 17807 36299 36281
1739 | 17819 36327 36315
1740 | 17827 36340 36311
1741 | 17840 36352 36329
1742 | 17848 36357 36314
1743 | 17860 36368 36328
1744 | 17868 36393 36330
1745 | 17881 36410 36355
1746 | 17889 36432 36350
1747 | 17901 36439 36350
1748 | 17909 36458 36361
1749 | 17922 36473 36368
1750 | 17930 36482 36369
1751 | 17942 36494 36375
1752 | 17950 36512 36378
1753 | 17962 36519 36401
1754 | 17971 36530 36398
1755 | 17983 36545 36406
1756 | 17991 36565 36404
1757 | 18003 36596 36411
1758 | 18012 36605 36423
1759 | 18024 36589 36427
1760 | 18032 36614 36434
1761 | 18044 36612 36438
1762 | 18053 36615 36427
1763 | 18065 36646 36434
1764 | 18073 36641 36437
1765 | 18085 36649 36440
1766 | 18094 36661 36447
1767 | 18106 36674 36456
1768 | 18114 36702 36470
1769 | 18126 36709 36462
1770 | 18135 36727 36466
1771 | 18147 36754 36475
1772 | 18155 36748 36487
1773 | 18167 36756 36483
1774 | 18175 36751 36467
1775 | 18188 36739 36459
1776 | 18196 36688 36432
1777 | 18208 36620 36407
1778 | 18216 36541 36360
1779 | 18229 36340 36254
1780 | 18237 36223 36239
1781 | 18249 36148 36189
1782 | 18257 36064 36161
1783 | 18270 36000 36114
1784 | 18278 35939 36088
1785 | 18290 35897 36079
1786 | 18298 35857 36058
1787 | 18311 35833 36063
1788 | 18319 35818 36056
1789 | 18331 35809 36060
1790 | 18339 35798 36039
1791 | 18352 35792 36051
1792 | 18360 35772 36033
1793 | 18372 35777 36044
1794 | 18380 35769 36024
1795 | 18393 35764 36041
1796 | 18401 35764 36025
1797 | 18413 35762 36024
1798 | 18425 35776 36043
1799 | 18434 35801 36055
1800 | 18445 35822 36073
1801 | 18454 35838 36078
1802 | 18466 35871 36082
1803 | 18474 35880 36097
1804 | 18486 35912 36105
1805 | 18495 35942 36114
1806 | 18507 35960 36116
1807 | 18515 35975 36140
1808 | 18527 35986 36125
1809 | 18536 35982 36132
1810 | 18548 35993 36123
1811 | 18556 35985 36131
1812 | 18568 35979 36130
1813 | 18577 35977 36126
1814 | 18589 35967 36134
1815 | 18597 35955 36101
1816 | 18609 35956 36116
1817 | 18618 35941 36111
1818 | 18630 35953 36116
1819 | 18638 35971 36130
1820 | 18650 35959 36114
1821 | 18659 35964 36102
1822 | 18671 35969 36120
1823 | 18679 35976 36111
1824 | 18691 35983 36112
1825 | 18700 35990 36103
1826 | 18712 36011 36119
1827 | 18720 36018 36131
1828 | 18732 36041 36146
1829 | 18741 36039 36143
1830 | 18753 36051 36149
1831 | 18761 36068 36152
1832 | 18773 36074 36165
1833 | 18782 36085 36171
1834 | 18794 36093 36173
1835 | 18802 36117 36181
1836 | 18814 36134 36190
1837 | 18823 36145 36200
1838 | 18835 36160 36192
1839 | 18843 36170 36211
1840 | 18855 36171 36212
1841 | 18864 36193 36209
1842 | 18876 36208 36216
1843 | 18884 36222 36219
1844 | 18896 36246 36226
1845 | 18905 36255 36226
1846 | 18917 36249 36244
1847 | 18925 36270 36238
1848 | 18937 36281 36251
1849 | 18945 36298 36262
1850 | 18958 36309 36274
1851 | 18966 36319 36273
1852 | 18978 36320 36280
1853 | 18986 36329 36278
1854 | 18999 36346 36275
1855 | 19007 36357 36278
1856 | 19019 36377 36285
1857 | 19027 36380 36295
1858 | 19040 36394 36280
1859 | 19048 36412 36281
1860 | 19060 36434 36313
1861 | 19068 36423 36301
1862 | 19081 36420 36288
1863 | 19089 36400 36280
1864 | 19101 36344 36248
1865 | 19109 36276 36209
1866 | 19122 36185 36171
1867 | 19130 36074 36114
1868 | 19142 35969 36073
1869 | 19150 35870 36021
1870 | 19163 35775 35977
1871 | 19171 35683 35952
1872 | 19183 35623 35918
1873 | 19191 35570 35904
1874 | 19204 35534 35882
1875 | 19212 35505 35867
1876 | 19224 35470 35855
1877 | 19232 35451 35860
1878 | 19244 35450 35850
1879 | 19253 35429 35846
1880 | 19265 35420 35850
1881 | 19273 35432 35848
1882 | 19285 35426 35846
1883 | 19294 35409 35843
1884 | 19306 35404 35842
1885 | 19314 35383 35832
1886 | 19326 35415 35842
1887 | 19335 35441 35862
1888 | 19347 35447 35869
1889 | 19355 35486 35877
1890 | 19367 35522 35901
1891 | 19376 35549 35923
1892 | 19388 35586 35923
1893 | 19396 35612 35933
1894 | 19408 35650 35946
1895 | 19417 35667 35963
1896 | 19429 35672 35952
1897 | 19437 35694 35958
1898 | 19449 35709 35975
1899 | 19457 35713 35985
1900 | 19470 35709 35976
1901 | 19478 35716 35979
1902 | 19490 35696 35976
1903 | 19498 35701 35985
1904 | 19511 35698 35958
1905 | 19519 35692 35971
1906 | 19531 35714 35979
1907 | 19539 35696 35971
1908 | 19552 35718 35975
1909 | 19560 35695 35966
1910 | 19572 35711 35971
1911 | 19580 35709 35974
1912 | 19593 35720 35978
1913 | 19601 35746 35992
1914 | 19613 35745 35990
1915 | 19621 35754 36010
1916 | 19634 35786 36005
1917 | 19642 35795 36007
1918 | 19654 35799 36011
1919 | 19662 35814 36013
1920 | 19675 35837 36030
1921 | 19683 35855 36048
1922 | 19695 35869 36055
1923 | 19703 35892 36061
1924 | 19716 35911 36064
1925 | 19724 35906 36073
1926 | 19736 35933 36079
1927 | 19744 35937 36084
1928 | 19756 35965 36097
1929 | 19765 35979 36086
1930 | 19777 35989 36098
1931 | 19785 36005 36103
1932 | 19797 36023 36109
1933 | 19806 36042 36104
1934 | 19818 36045 36123
1935 | 19826 36062 36122
1936 | 19838 36058 36139
1937 | 19847 36084 36130
1938 | 19859 36085 36139
1939 | 19871 36112 36147
1940 | 19879 36127 36159
1941 | 19891 36129 36159
1942 | 19900 36139 36164
1943 | 19912 36157 36163
1944 | 19920 36175 36159
1945 | 19932 36167 36169
1946 | 19941 36168 36172
1947 | 19953 36203 36184
1948 | 19961 36209 36181
1949 | 19973 36204 36187
1950 | 19982 36232 36196
1951 | 19994 36238 36207
1952 | 20002 36245 36207
1953 | 20014 36267 36223
1954 | 20023 36276 36215
1955 | 20035 36271 36217
1956 | 20043 36278 36217
1957 | 20055 36271 36202
1958 | 20064 36283 36220
1959 | 20076 36237 36201
1960 | 20084 36189 36168
1961 | 20096 36120 36119
1962 | 20105 35994 36072
1963 | 20117 35899 36023
1964 | 20125 35775 35966
1965 | 20137 35649 35902
1966 | 20146 35540 35850
1967 | 20158 35461 35816
1968 | 20166 35368 35781
1969 | 20178 35317 35753
1970 | 20187 35259 35732
1971 | 20199 35222 35718
1972 | 20207 35192 35701
1973 | 20219 35180 35691
1974 | 20227 35149 35703
1975 | 20240 35130 35694
1976 | 20248 35124 35673
1977 | 20260 35136 35680
1978 | 20268 35111 35675
1979 | 20281 35092 35650
1980 | 20289 35099 35672
1981 | 20301 35098 35662
1982 | 20309 35091 35673
1983 | 20322 35100 35661
1984 | 20330 35105 35680
1985 | 20342 35124 35694
1986 | 20350 35142 35696
1987 | 20362 35189 35709
1988 | 20371 35216 35739
1989 | 20383 35235 35743
1990 | 20391 35263 35742
1991 | 20403 35285 35756
1992 | 20412 35308 35770
1993 | 20424 35334 35799
1994 | 20432 35369 35796
1995 | 20444 35370 35802
1996 | 20453 35389 35803
1997 | 20465 35391 35788
1998 | 20473 35385 35800
1999 | 20485 35382 35785
2000 | 20494 35369 35783
2001 | 20506 35358 35779
2002 | 20514 35375 35788
2003 | 20526 35373 35787
2004 | 20535 35363 35798
2005 | 20547 35396 35792
2006 | 20555 35415 35794
2007 | 20567 35433 35800
2008 | 20576 35430 35810
2009 | 20588 35443 35808
2010 | 20596 35468 35833
2011 | 20608 35470 35828
2012 | 20617 35489 35825
2013 | 20629 35513 35852
2014 | 20637 35543 35856
2015 | 20649 35561 35877
2016 | 20658 35590 35868
2017 | 20670 35599 35891
2018 | 20678 35629 35889
2019 | 20690 35645 35891
2020 | 20699 35660 35898
2021 | 20711 35683 35919
2022 | 20719 35693 35914
2023 | 20731 35710 35929
2024 | 20739 35706 35941
2025 | 20752 35712 35926
2026 | 20760 35734 35945
2027 | 20772 35751 35943
2028 | 20780 35759 35957
2029 | 20793 35775 35970
2030 | 20801 35782 35976
2031 | 20813 35792 35972
2032 | 20821 35797 35983
2033 | 20834 35822 35987
2034 | 20842 35819 35983
2035 | 20854 35831 35992
2036 | 20862 35849 35992
2037 | 20875 35838 36004
2038 | 20883 35863 35994
2039 | 20895 35866 36012
2040 | 20903 35874 36011
2041 | 20916 35881 36013
2042 | 20924 35891 36019
2043 | 20936 35901 36018
2044 | 20944 35912 36031
2045 | 20957 35920 36018
2046 | 20965 35930 36043
2047 | 20977 35936 36038
2048 | 20985 35951 36039
2049 | 20998 35964 36027
2050 | 21006 35978 36047
2051 | 21018 35987 36043
2052 | 21026 36004 36051
2053 | 21038 36010 36059
2054 | 21047 36031 36061
2055 | 21059 36031 36069
2056 | 21067 36040 36080
2057 |
--------------------------------------------------------------------------------
/extras/rolling_graph/README.md:
--------------------------------------------------------------------------------
1 | # Rolling graph
2 |
3 | Graphs the filtered data from the sensor and overlays the beat detector stage, allowing
4 | a visual inspection of the beat detection algorithm.
5 |
6 | ## Requirements
7 |
8 | * Processing 3+ (http://www.processing.org)
9 | * Flash the example MAX30100_Debug to the target microcontroller
10 |
11 | ## Usage
12 |
13 | * Start processing and open the file rolling_graph.pde
14 | * If under linux or windows, adjust the line in order to match the serial port the microcontroller is connected to (eg: COM2, /dev/ttyUSB0). Under OSX the port should be autodetected.
15 | final String serialPort = "/dev/ttyACM0";
16 | * Run the sketch
17 |
18 | ## Interpreting the screen
19 |
20 | Data coming from the sensor are plotted continuously. Legend for the time series:
21 |
22 | * Black graph (ch 0): infrared channel response level (the beat detector uses the IR channel)
23 | * Red graph (ch 1): beat detector threshold
24 |
25 | On the top left corner the following realtime values are printed:
26 |
27 | * channels 0 and 1 current, max and min values
28 | * computed heart rate
29 | * computed SpO2
30 |
31 | A typical working session would show a fairly regular black graph. Each peak of the black graph
32 | should be intercepted by the red graph. When this happens, the screen flashes red to signify
33 | that the beat detector is counting beats.
34 |
35 | If the red graph misses often one or more black peak, try to adjust the power of the IR LED.
36 |
--------------------------------------------------------------------------------
/extras/rolling_graph/rolling_graph.pde:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | // Grapher helper for the Arduino MAX30100 library
20 |
21 | import processing.serial.*;
22 |
23 | // NOTE: when using PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES
24 | // set this to -1 to enable the auto range mode
25 | final int ABSMAX = 800;
26 | // Adjust to the serial port. Under OSX, UNO platforms and alike are auto-detected.
27 | final String serialPort = "/dev/tty.usbmodemFD13131";
28 |
29 |
30 | final int WIDTH = 1200;
31 | final int HEIGHT = 600;
32 | final int CHANNELS = 2;
33 | final color[] colors = {color(0, 0, 0), color(255, 0, 0), color(0, 255, 0), color(0, 0, 255)};
34 |
35 |
36 | float[][] series = new float[CHANNELS][WIDTH];
37 | float heartRate = 0;
38 | int spO2 = 0;
39 | int redLedCurrentIndex = 0;
40 | boolean beatDetected = false;
41 | int ptr = 0;
42 |
43 | Serial myPort;
44 |
45 | void settings()
46 | {
47 | size(WIDTH, HEIGHT);
48 | }
49 |
50 | void setup ()
51 | {
52 | String attemptPort = serialPort;
53 |
54 | for (int i=0 ; i < Serial.list().length ; ++i) {
55 | String port = Serial.list()[i];
56 | if (port.matches(".+tty\\.usbmodem.+")) {
57 | attemptPort = port;
58 | break;
59 | }
60 | }
61 |
62 | println("Opening port " + attemptPort);
63 |
64 | myPort = new Serial(this, attemptPort, 115200);
65 |
66 | stroke(0);
67 | fill(0);
68 | textSize(8);
69 | }
70 |
71 | void draw ()
72 | {
73 | if (beatDetected) {
74 | background(255, 200, 200);
75 | beatDetected = false;
76 | } else {
77 | background(255);
78 | }
79 |
80 | stroke(30);
81 |
82 | line(0, height/2, width, height/2);
83 |
84 | float maxv=0, minv;
85 | for (int s=0 ; s < CHANNELS ; ++s) {
86 | float[] samples = series[s];
87 | maxv = max(maxv, abs(max(samples)), abs(min(samples)));
88 | if (ABSMAX != -1) {
89 | maxv = min(maxv, ABSMAX);
90 | }
91 | }
92 |
93 | // Avoids map() errors
94 | if (maxv == 0) {
95 | maxv = 1;
96 | }
97 | minv = -maxv;
98 |
99 | for (int s=0 ; s < CHANNELS ; ++s) {
100 | stroke(colors[s]);
101 |
102 | float[] samples = series[s];
103 | float seriesMax = max(samples);
104 |
105 | text("ch " + s + " cur:" + samples[ptr] + " max:" + seriesMax + " min:" + min(samples), 0, 8 + 10 * s);
106 |
107 | boolean maxDisplayed = false;
108 | for (int i = 0 ; i < WIDTH ; ++i) {
109 | if (i > 0) {
110 | float ipy = HEIGHT - map(samples[i-1], minv, maxv, 0, HEIGHT);
111 | float iy = HEIGHT - map(samples[i], minv, maxv, 0, HEIGHT);
112 |
113 | if (abs(samples[i] - seriesMax) < 0.001 && !maxDisplayed) {
114 | text("v=" + samples[i], i, iy);
115 | maxDisplayed = true;
116 | }
117 |
118 | line(i - 1, ipy, i, iy);
119 | }
120 | }
121 | }
122 |
123 | text("Rate: " + heartRate, 200, 8);
124 | text("SpO2: " + spO2 + "%", 200, 18);
125 | text("RLI: " + redLedCurrentIndex, 200, 28);
126 | }
127 |
128 | void serialEvent (Serial myPort)
129 | {
130 | String sLine = myPort.readStringUntil('\n');
131 |
132 | if (sLine == null) {
133 | return;
134 | }
135 |
136 | if (sLine.substring(0, 2).equals("R:")) {
137 | String[] sValues = split(sLine.substring(2), ',');
138 |
139 | for (int i=0 ; i < sValues.length ; ++i) {
140 | float sample = float(sValues[i]);
141 |
142 | if (Float.isNaN(sample)) {
143 | continue;
144 | }
145 |
146 | series[i][ptr] = sample;
147 | }
148 |
149 | ptr = (ptr + 1) % WIDTH;
150 | } else if (sLine.substring(0, 2).equals("H:")) {
151 | heartRate = float(sLine.substring(2));
152 | } else if (sLine.substring(0, 2).equals("B:")) {
153 | beatDetected = true;
154 | } else if (sLine.substring(0, 2).equals("C:")) {
155 | println(sLine);
156 | } else if (sLine.substring(0, 2).equals("O:")) {
157 | spO2 = int(float(sLine.substring(2)));
158 | } else if (sLine.substring(0, 2).equals("I:")) {
159 | redLedCurrentIndex = int(float(sLine.substring(2)));
160 | }
161 | }
--------------------------------------------------------------------------------
/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "MAX30100lib",
3 | "keywords": "pulse,oximetry,spo2,max30100,sensor,i2c",
4 | "description": "Maxim-IC MAX30100 heart-rate sensor driver and pulse-oximetry components",
5 | "authors":
6 | {
7 | "name": "OXullo Intersecans",
8 | "email": "x@brainrapers.org",
9 | "url": "https://github.com/oxullo/",
10 | "maintainer": true
11 | },
12 | "repository":
13 | {
14 | "type": "git",
15 | "url": "https://github.com/oxullo/Arduino-MAX30100"
16 | },
17 | "version": "1.2.1",
18 | "frameworks": "arduino",
19 | "platforms": "atmelavr"
20 | }
21 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=MAX30100lib
2 | version=1.2.1
3 | author=OXullo Intersecans
4 | maintainer=OXullo Intersecans
5 | sentence=Maxim-IC MAX30100 heart-rate sensor driver and pulse-oximetry components
6 | paragraph=This library exposes most of the features of the MAX30100 and offers a modular approach to calculate pulse rate and SpO2
7 | category=Sensors
8 | url=https://github.com/oxullo/Arduino-MAX30100
9 | architectures=*
10 |
--------------------------------------------------------------------------------
/src/CircularBuffer.h:
--------------------------------------------------------------------------------
1 | /*
2 | CircularBuffer.h - Circular buffer library for Arduino.
3 | Copyright (c) 2017 Roberto Lo Giacco.
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU Lesser General Public License as
7 | published by the Free Software Foundation, either version 3 of the
8 | License, or (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 | #ifndef __CIRCULAR_BUFFER__
19 | #define __CIRCULAR_BUFFER__
20 | #include
21 |
22 | #ifndef CIRCULAR_BUFFER_XS
23 | #define __CB_ST__ uint16_t
24 | #else
25 | #define __CB_ST__ uint8_t
26 | #endif
27 |
28 | #ifdef CIRCULAR_BUFFER_DEBUG
29 | #include
30 | #endif
31 |
32 | template class CircularBuffer {
33 | public:
34 |
35 | CircularBuffer();
36 |
37 | ~CircularBuffer();
38 |
39 | /**
40 | * Adds an element to the beginning of buffer: the operation returns `false` if the addition caused overwriting an existing element.
41 | */
42 | bool unshift(T value);
43 |
44 | /**
45 | * Adds an element to the end of buffer: the operation returns `false` if the addition caused overwriting an existing element.
46 | */
47 | bool push(T value);
48 |
49 | /**
50 | * Removes an element from the beginning of the buffer.
51 | */
52 | T shift();
53 |
54 | /**
55 | * Removes an element from the end of the buffer.
56 | */
57 | T pop();
58 |
59 | /**
60 | * Returns the element at the beginning of the buffer.
61 | */
62 | T inline first();
63 |
64 | /**
65 | * Returns the element at the end of the buffer.
66 | */
67 | T inline last();
68 |
69 | /**
70 | * Array-like access to buffer
71 | */
72 | T operator [] (__CB_ST__ index);
73 |
74 | /**
75 | * Returns how many elements are actually stored in the buffer.
76 | */
77 | __CB_ST__ inline size();
78 |
79 | /**
80 | * Returns how many elements can be safely pushed into the buffer.
81 | */
82 | __CB_ST__ inline available();
83 |
84 | /**
85 | * Returns how many elements can be potentially stored into the buffer.
86 | */
87 | __CB_ST__ inline capacity();
88 |
89 | /**
90 | * Returns `true` if no elements can be removed from the buffer.
91 | */
92 | bool inline isEmpty();
93 |
94 | /**
95 | * Returns `true` if no elements can be added to the buffer without overwriting existing elements.
96 | */
97 | bool inline isFull();
98 |
99 | /**
100 | * Resets the buffer to a clean status, dropping any reference to current elements
101 | * and making all buffer positions available again.
102 | */
103 | void inline clear();
104 |
105 | #ifdef CIRCULAR_BUFFER_DEBUG
106 | void inline debug(Print* out);
107 | void inline debugFn(Print* out, void (*printFunction)(Print*, T));
108 | #endif
109 |
110 | private:
111 | T buffer[S];
112 | T *head;
113 | T *tail;
114 | uint16_t count;
115 | };
116 |
117 | #include "CircularBuffer.tpp"
118 | #endif
119 |
--------------------------------------------------------------------------------
/src/CircularBuffer.tpp:
--------------------------------------------------------------------------------
1 | /*
2 | CircularBuffer.tpp - Circular buffer library for Arduino.
3 | Copyright (c) 2017 Roberto Lo Giacco.
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU Lesser General Public License as
7 | published by the Free Software Foundation, either version 3 of the
8 | License, or (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
21 | template
22 | CircularBuffer::CircularBuffer() :
23 | head(buffer), tail(buffer), count(0) {
24 | }
25 |
26 | template
27 | CircularBuffer::~CircularBuffer() {
28 | }
29 |
30 | template
31 | bool CircularBuffer::unshift(T value) {
32 | if (head == buffer) {
33 | head = buffer + S;
34 | }
35 | *--head = value;
36 | if (count == S) {
37 | if (tail-- == buffer) {
38 | tail = buffer + S - 1;
39 | }
40 | return false;
41 | } else {
42 | if (count++ == 0) {
43 | tail = head;
44 | }
45 | return true;
46 | }
47 | }
48 |
49 | template
50 | bool CircularBuffer::push(T value) {
51 | if (++tail == buffer + S) {
52 | tail = buffer;
53 | }
54 | *tail = value;
55 | if (count == S) {
56 | if (++head == buffer + S) {
57 | head = buffer;
58 | }
59 | return false;
60 | } else {
61 | if (count++ == 0) {
62 | head = tail;
63 | }
64 | return true;
65 | }
66 | }
67 |
68 | template
69 | T CircularBuffer::shift() {
70 | void(* crash) (void) = 0;
71 | if (count <= 0) crash();
72 | T result = *head++;
73 | if (head >= buffer + S) {
74 | head = buffer;
75 | }
76 | count--;
77 | return result;
78 | }
79 |
80 | template
81 | T CircularBuffer::pop() {
82 | void(* crash) (void) = 0;
83 | if (count <= 0) crash();
84 | T result = *tail--;
85 | if (tail < buffer) {
86 | tail = buffer + S - 1;
87 | }
88 | count--;
89 | return result;
90 | }
91 |
92 | template
93 | T inline CircularBuffer::first() {
94 | return *head;
95 | }
96 |
97 | template
98 | T inline CircularBuffer::last() {
99 | return *tail;
100 | }
101 |
102 | template
103 | T CircularBuffer::operator [](__CB_ST__ index) {
104 | return *(buffer + ((head - buffer + index) % S));
105 | }
106 |
107 | template
108 | __CB_ST__ inline CircularBuffer::size() {
109 | return count;
110 | }
111 |
112 | template
113 | __CB_ST__ inline CircularBuffer::available() {
114 | return S - count;
115 | }
116 |
117 | template
118 | __CB_ST__ inline CircularBuffer::capacity() {
119 | return S;
120 | }
121 |
122 | template
123 | bool inline CircularBuffer::isEmpty() {
124 | return count == 0;
125 | }
126 |
127 | template
128 | bool inline CircularBuffer::isFull() {
129 | return count == S;
130 | }
131 |
132 | template
133 | void inline CircularBuffer::clear() {
134 | memset(buffer, 0, sizeof(buffer));
135 | head = tail = buffer;
136 | count = 0;
137 | }
138 |
139 | #ifdef CIRCULAR_BUFFER_DEBUG
140 | template
141 | void inline CircularBuffer::debug(Print* out) {
142 | for (__CB_ST__ i = 0; i < S; i++) {
143 | int hex = (int)buffer + i;
144 | out->print(hex, HEX);
145 | out->print(" ");
146 | out->print(*(buffer + i));
147 | if (head == buffer + i) {
148 | out->print(" head");
149 | }
150 | if (tail == buffer + i) {
151 | out->print(" tail");
152 | }
153 | out->println();
154 | }
155 | }
156 |
157 | template
158 | void inline CircularBuffer::debugFn(Print* out, void (*printFunction)(Print*, T)) {
159 | for (__CB_ST__ i = 0; i < S; i++) {
160 | int hex = (int)buffer + i;
161 | out->print(hex, HEX);
162 | out->print(" ");
163 | printFunction(out, *(buffer + i));
164 | if (head == buffer + i) {
165 | out->print(" head");
166 | }
167 | if (tail == buffer + i) {
168 | out->print(" tail");
169 | }
170 | out->println();
171 | }
172 | }
173 | #endif
--------------------------------------------------------------------------------
/src/MAX30100.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
21 | #include "MAX30100.h"
22 |
23 | MAX30100::MAX30100()
24 | {
25 | }
26 |
27 | bool MAX30100::begin()
28 | {
29 | Wire.begin();
30 | Wire.setClock(I2C_BUS_SPEED);
31 |
32 | if (getPartId() != EXPECTED_PART_ID) {
33 | return false;
34 | }
35 |
36 | setMode(DEFAULT_MODE);
37 | setLedsPulseWidth(DEFAULT_PULSE_WIDTH);
38 | setSamplingRate(DEFAULT_SAMPLING_RATE);
39 | setLedsCurrent(DEFAULT_IR_LED_CURRENT, DEFAULT_RED_LED_CURRENT);
40 | setHighresModeEnabled(true);
41 |
42 | return true;
43 | }
44 |
45 | void MAX30100::setMode(Mode mode)
46 | {
47 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, mode);
48 | }
49 |
50 | void MAX30100::setLedsPulseWidth(LEDPulseWidth ledPulseWidth)
51 | {
52 | uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION);
53 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xfc) | ledPulseWidth);
54 | }
55 |
56 | void MAX30100::setSamplingRate(SamplingRate samplingRate)
57 | {
58 | uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION);
59 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xe3) | (samplingRate << 2));
60 | }
61 |
62 | void MAX30100::setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent)
63 | {
64 | writeRegister(MAX30100_REG_LED_CONFIGURATION, redLedCurrent << 4 | irLedCurrent);
65 | }
66 |
67 | void MAX30100::setHighresModeEnabled(bool enabled)
68 | {
69 | uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION);
70 | if (enabled) {
71 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous | MAX30100_SPC_SPO2_HI_RES_EN);
72 | } else {
73 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous & ~MAX30100_SPC_SPO2_HI_RES_EN);
74 | }
75 | }
76 |
77 | void MAX30100::update()
78 | {
79 | readFifoData();
80 | }
81 |
82 | bool MAX30100::getRawValues(uint16_t *ir, uint16_t *red)
83 | {
84 | if (!readoutsBuffer.isEmpty()) {
85 | SensorReadout readout = readoutsBuffer.pop();
86 |
87 | *ir = readout.ir;
88 | *red = readout.red;
89 |
90 | return true;
91 | } else {
92 | return false;
93 | }
94 | }
95 |
96 | void MAX30100::resetFifo()
97 | {
98 | writeRegister(MAX30100_REG_FIFO_WRITE_POINTER, 0);
99 | writeRegister(MAX30100_REG_FIFO_READ_POINTER, 0);
100 | writeRegister(MAX30100_REG_FIFO_OVERFLOW_COUNTER, 0);
101 | }
102 |
103 | uint8_t MAX30100::readRegister(uint8_t address)
104 | {
105 | Wire.beginTransmission(MAX30100_I2C_ADDRESS);
106 | Wire.write(address);
107 | Wire.endTransmission(false);
108 | Wire.requestFrom(MAX30100_I2C_ADDRESS, 1);
109 |
110 | return Wire.read();
111 | }
112 |
113 | void MAX30100::writeRegister(uint8_t address, uint8_t data)
114 | {
115 | Wire.beginTransmission(MAX30100_I2C_ADDRESS);
116 | Wire.write(address);
117 | Wire.write(data);
118 | Wire.endTransmission();
119 | }
120 |
121 | void MAX30100::burstRead(uint8_t baseAddress, uint8_t *buffer, uint8_t length)
122 | {
123 | Wire.beginTransmission(MAX30100_I2C_ADDRESS);
124 | Wire.write(baseAddress);
125 | Wire.endTransmission(false);
126 | Wire.requestFrom((uint8_t)MAX30100_I2C_ADDRESS, length);
127 |
128 | uint8_t idx = 0;
129 | while (Wire.available()) {
130 | buffer[idx++] = Wire.read();
131 | }
132 | }
133 |
134 | void MAX30100::readFifoData()
135 | {
136 | uint8_t buffer[MAX30100_FIFO_DEPTH*4];
137 | uint8_t toRead;
138 |
139 | toRead = (readRegister(MAX30100_REG_FIFO_WRITE_POINTER) - readRegister(MAX30100_REG_FIFO_READ_POINTER)) & (MAX30100_FIFO_DEPTH-1);
140 |
141 | if (toRead) {
142 | burstRead(MAX30100_REG_FIFO_DATA, buffer, 4 * toRead);
143 |
144 | for (uint8_t i=0 ; i < toRead ; ++i) {
145 | // Warning: the values are always left-aligned
146 | readoutsBuffer.push({
147 | .ir=(uint16_t)((buffer[i*4] << 8) | buffer[i*4 + 1]),
148 | .red=(uint16_t)((buffer[i*4 + 2] << 8) | buffer[i*4 + 3])});
149 | }
150 | }
151 | }
152 |
153 | void MAX30100::startTemperatureSampling()
154 | {
155 | uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION);
156 | modeConfig |= MAX30100_MC_TEMP_EN;
157 |
158 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig);
159 | }
160 |
161 | bool MAX30100::isTemperatureReady()
162 | {
163 | return !(readRegister(MAX30100_REG_MODE_CONFIGURATION) & MAX30100_MC_TEMP_EN);
164 | }
165 |
166 | float MAX30100::retrieveTemperature()
167 | {
168 | int8_t tempInteger = readRegister(MAX30100_REG_TEMPERATURE_DATA_INT);
169 | float tempFrac = readRegister(MAX30100_REG_TEMPERATURE_DATA_FRAC);
170 |
171 | return tempFrac * 0.0625 + tempInteger;
172 | }
173 |
174 | void MAX30100::shutdown()
175 | {
176 | uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION);
177 | modeConfig |= MAX30100_MC_SHDN;
178 |
179 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig);
180 | }
181 |
182 | void MAX30100::resume()
183 | {
184 | uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION);
185 | modeConfig &= ~MAX30100_MC_SHDN;
186 |
187 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig);
188 | }
189 |
190 | uint8_t MAX30100::getPartId()
191 | {
192 | return readRegister(0xff);
193 | }
194 |
--------------------------------------------------------------------------------
/src/MAX30100.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifndef MAX30100_H
20 | #define MAX30100_H
21 |
22 | #include
23 |
24 | #define CIRCULAR_BUFFER_XS
25 | #include "CircularBuffer.h"
26 | #include "MAX30100_Registers.h"
27 |
28 | #define DEFAULT_MODE MAX30100_MODE_HRONLY
29 | #define DEFAULT_SAMPLING_RATE MAX30100_SAMPRATE_100HZ
30 | #define DEFAULT_PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS
31 | #define DEFAULT_RED_LED_CURRENT MAX30100_LED_CURR_50MA
32 | #define DEFAULT_IR_LED_CURRENT MAX30100_LED_CURR_50MA
33 | #define EXPECTED_PART_ID 0x11
34 | #define RINGBUFFER_SIZE 16
35 |
36 | #define I2C_BUS_SPEED 400000UL
37 |
38 | typedef struct {
39 | uint16_t ir;
40 | uint16_t red;
41 | } SensorReadout;
42 |
43 | class MAX30100 {
44 | public:
45 | MAX30100();
46 | bool begin();
47 | void setMode(Mode mode);
48 | void setLedsPulseWidth(LEDPulseWidth ledPulseWidth);
49 | void setSamplingRate(SamplingRate samplingRate);
50 | void setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent);
51 | void setHighresModeEnabled(bool enabled);
52 | void update();
53 | bool getRawValues(uint16_t *ir, uint16_t *red);
54 | void resetFifo();
55 | void startTemperatureSampling();
56 | bool isTemperatureReady();
57 | float retrieveTemperature();
58 | void shutdown();
59 | void resume();
60 | uint8_t getPartId();
61 |
62 | private:
63 | CircularBuffer readoutsBuffer;
64 |
65 | uint8_t readRegister(uint8_t address);
66 | void writeRegister(uint8_t address, uint8_t data);
67 | void burstRead(uint8_t baseAddress, uint8_t *buffer, uint8_t length);
68 | void readFifoData();
69 | };
70 |
71 | #endif
72 |
--------------------------------------------------------------------------------
/src/MAX30100_BeatDetector.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
21 | #include "MAX30100_BeatDetector.h"
22 |
23 | #ifndef min
24 | #define min(a,b) \
25 | ({ __typeof__ (a) _a = (a); \
26 | __typeof__ (b) _b = (b); \
27 | _a < _b ? _a : _b; })
28 | #endif
29 |
30 | BeatDetector::BeatDetector() :
31 | state(BEATDETECTOR_STATE_INIT),
32 | threshold(BEATDETECTOR_MIN_THRESHOLD),
33 | beatPeriod(0),
34 | lastMaxValue(0),
35 | tsLastBeat(0)
36 | {
37 | }
38 |
39 | bool BeatDetector::addSample(float sample)
40 | {
41 | return checkForBeat(sample);
42 | }
43 |
44 | float BeatDetector::getRate()
45 | {
46 | if (beatPeriod != 0) {
47 | return 1 / beatPeriod * 1000 * 60;
48 | } else {
49 | return 0;
50 | }
51 | }
52 |
53 | float BeatDetector::getCurrentThreshold()
54 | {
55 | return threshold;
56 | }
57 |
58 | bool BeatDetector::checkForBeat(float sample)
59 | {
60 | bool beatDetected = false;
61 |
62 | switch (state) {
63 | case BEATDETECTOR_STATE_INIT:
64 | if (millis() > BEATDETECTOR_INIT_HOLDOFF) {
65 | state = BEATDETECTOR_STATE_WAITING;
66 | }
67 | break;
68 |
69 | case BEATDETECTOR_STATE_WAITING:
70 | if (sample > threshold) {
71 | threshold = min(sample, BEATDETECTOR_MAX_THRESHOLD);
72 | state = BEATDETECTOR_STATE_FOLLOWING_SLOPE;
73 | }
74 |
75 | // Tracking lost, resetting
76 | if (millis() - tsLastBeat > BEATDETECTOR_INVALID_READOUT_DELAY) {
77 | beatPeriod = 0;
78 | lastMaxValue = 0;
79 | }
80 |
81 | decreaseThreshold();
82 | break;
83 |
84 | case BEATDETECTOR_STATE_FOLLOWING_SLOPE:
85 | if (sample < threshold) {
86 | state = BEATDETECTOR_STATE_MAYBE_DETECTED;
87 | } else {
88 | threshold = min(sample, BEATDETECTOR_MAX_THRESHOLD);
89 | }
90 | break;
91 |
92 | case BEATDETECTOR_STATE_MAYBE_DETECTED:
93 | if (sample + BEATDETECTOR_STEP_RESILIENCY < threshold) {
94 | // Found a beat
95 | beatDetected = true;
96 | lastMaxValue = sample;
97 | state = BEATDETECTOR_STATE_MASKING;
98 | float delta = millis() - tsLastBeat;
99 | if (delta) {
100 | beatPeriod = BEATDETECTOR_BPFILTER_ALPHA * delta +
101 | (1 - BEATDETECTOR_BPFILTER_ALPHA) * beatPeriod;
102 | }
103 |
104 | tsLastBeat = millis();
105 | } else {
106 | state = BEATDETECTOR_STATE_FOLLOWING_SLOPE;
107 | }
108 | break;
109 |
110 | case BEATDETECTOR_STATE_MASKING:
111 | if (millis() - tsLastBeat > BEATDETECTOR_MASKING_HOLDOFF) {
112 | state = BEATDETECTOR_STATE_WAITING;
113 | }
114 | decreaseThreshold();
115 | break;
116 | }
117 |
118 | return beatDetected;
119 | }
120 |
121 | void BeatDetector::decreaseThreshold()
122 | {
123 | // When a valid beat rate readout is present, target the
124 | if (lastMaxValue > 0 && beatPeriod > 0) {
125 | threshold -= lastMaxValue * (1 - BEATDETECTOR_THRESHOLD_FALLOFF_TARGET) /
126 | (beatPeriod / BEATDETECTOR_SAMPLES_PERIOD);
127 | } else {
128 | // Asymptotic decay
129 | threshold *= BEATDETECTOR_THRESHOLD_DECAY_FACTOR;
130 | }
131 |
132 | if (threshold < BEATDETECTOR_MIN_THRESHOLD) {
133 | threshold = BEATDETECTOR_MIN_THRESHOLD;
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/MAX30100_BeatDetector.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifndef MAX30100_BEATDETECTOR_H
20 | #define MAX30100_BEATDETECTOR_H
21 |
22 | #include
23 |
24 | #define BEATDETECTOR_INIT_HOLDOFF 2000 // in ms, how long to wait before counting
25 | #define BEATDETECTOR_MASKING_HOLDOFF 200 // in ms, non-retriggerable window after beat detection
26 | #define BEATDETECTOR_BPFILTER_ALPHA 0.6 // EMA factor for the beat period value
27 | #define BEATDETECTOR_MIN_THRESHOLD 20 // minimum threshold (filtered) value
28 | #define BEATDETECTOR_MAX_THRESHOLD 800 // maximum threshold (filtered) value
29 | #define BEATDETECTOR_STEP_RESILIENCY 30 // maximum negative jump that triggers the beat edge
30 | #define BEATDETECTOR_THRESHOLD_FALLOFF_TARGET 0.3 // thr chasing factor of the max value when beat
31 | #define BEATDETECTOR_THRESHOLD_DECAY_FACTOR 0.99 // thr chasing factor when no beat
32 | #define BEATDETECTOR_INVALID_READOUT_DELAY 2000 // in ms, no-beat time to cause a reset
33 | #define BEATDETECTOR_SAMPLES_PERIOD 10 // in ms, 1/Fs
34 |
35 |
36 | typedef enum BeatDetectorState {
37 | BEATDETECTOR_STATE_INIT,
38 | BEATDETECTOR_STATE_WAITING,
39 | BEATDETECTOR_STATE_FOLLOWING_SLOPE,
40 | BEATDETECTOR_STATE_MAYBE_DETECTED,
41 | BEATDETECTOR_STATE_MASKING
42 | } BeatDetectorState;
43 |
44 |
45 | class BeatDetector
46 | {
47 | public:
48 | BeatDetector();
49 | bool addSample(float sample);
50 | float getRate();
51 | float getCurrentThreshold();
52 |
53 | private:
54 | bool checkForBeat(float value);
55 | void decreaseThreshold();
56 |
57 | BeatDetectorState state;
58 | float threshold;
59 | float beatPeriod;
60 | float lastMaxValue;
61 | uint32_t tsLastBeat;
62 | };
63 |
64 | #endif
65 |
--------------------------------------------------------------------------------
/src/MAX30100_Filters.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifndef MAX30100_FILTERS_H
20 | #define MAX30100_FILTERS_H
21 |
22 | // http://www.schwietering.com/jayduino/filtuino/
23 | // Low pass butterworth filter order=1 alpha1=0.1
24 | // Fs=100Hz, Fc=6Hz
25 | class FilterBuLp1
26 | {
27 | public:
28 | FilterBuLp1()
29 | {
30 | v[0]=0.0;
31 | }
32 | private:
33 | float v[2];
34 | public:
35 | float step(float x) //class II
36 | {
37 | v[0] = v[1];
38 | v[1] = (2.452372752527856026e-1 * x)
39 | + (0.50952544949442879485 * v[0]);
40 | return
41 | (v[0] + v[1]);
42 | }
43 | };
44 |
45 | // http://sam-koblenski.blogspot.de/2015/11/everyday-dsp-for-programmers-dc-and.html
46 | class DCRemover
47 | {
48 | public:
49 | DCRemover() : alpha(0), dcw(0)
50 | {
51 | }
52 | DCRemover(float alpha_) : alpha(alpha_), dcw(0)
53 | {
54 | }
55 |
56 | float step(float x)
57 | {
58 | float olddcw = dcw;
59 | dcw = (float)x + alpha * dcw;
60 |
61 | return dcw - olddcw;
62 | }
63 |
64 | float getDCW()
65 | {
66 | return dcw;
67 | }
68 |
69 | private:
70 | float alpha;
71 | float dcw;
72 | };
73 |
74 | #endif
75 |
--------------------------------------------------------------------------------
/src/MAX30100_PulseOximeter.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
21 | #include "MAX30100_PulseOximeter.h"
22 |
23 |
24 | PulseOximeter::PulseOximeter() :
25 | state(PULSEOXIMETER_STATE_INIT),
26 | tsFirstBeatDetected(0),
27 | tsLastBeatDetected(0),
28 | tsLastBiasCheck(0),
29 | tsLastCurrentAdjustment(0),
30 | redLedCurrentIndex((uint8_t)RED_LED_CURRENT_START),
31 | irLedCurrent(DEFAULT_IR_LED_CURRENT),
32 | onBeatDetected(NULL)
33 | {
34 | }
35 |
36 | bool PulseOximeter::begin(PulseOximeterDebuggingMode debuggingMode_)
37 | {
38 | debuggingMode = debuggingMode_;
39 |
40 | bool ready = hrm.begin();
41 |
42 | if (!ready) {
43 | if (debuggingMode != PULSEOXIMETER_DEBUGGINGMODE_NONE) {
44 | Serial.println("Failed to initialize the HRM sensor");
45 | }
46 | return false;
47 | }
48 |
49 | hrm.setMode(MAX30100_MODE_SPO2_HR);
50 | hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex);
51 |
52 | irDCRemover = DCRemover(DC_REMOVER_ALPHA);
53 | redDCRemover = DCRemover(DC_REMOVER_ALPHA);
54 |
55 | state = PULSEOXIMETER_STATE_IDLE;
56 |
57 | return true;
58 | }
59 |
60 | void PulseOximeter::update()
61 | {
62 | hrm.update();
63 |
64 | checkSample();
65 | checkCurrentBias();
66 | }
67 |
68 | float PulseOximeter::getHeartRate()
69 | {
70 | return beatDetector.getRate();
71 | }
72 |
73 | uint8_t PulseOximeter::getSpO2()
74 | {
75 | return spO2calculator.getSpO2();
76 | }
77 |
78 | uint8_t PulseOximeter::getRedLedCurrentBias()
79 | {
80 | return redLedCurrentIndex;
81 | }
82 |
83 | void PulseOximeter::setOnBeatDetectedCallback(void (*cb)())
84 | {
85 | onBeatDetected = cb;
86 | }
87 |
88 | void PulseOximeter::setIRLedCurrent(LEDCurrent irLedNewCurrent)
89 | {
90 | irLedCurrent = irLedNewCurrent;
91 | hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex);
92 | }
93 |
94 | void PulseOximeter::shutdown()
95 | {
96 | hrm.shutdown();
97 | }
98 |
99 | void PulseOximeter::resume()
100 | {
101 | hrm.resume();
102 | }
103 |
104 | void PulseOximeter::checkSample()
105 | {
106 | uint16_t rawIRValue, rawRedValue;
107 |
108 | // Dequeue all available samples, they're properly timed by the HRM
109 | while (hrm.getRawValues(&rawIRValue, &rawRedValue)) {
110 | float irACValue = irDCRemover.step(rawIRValue);
111 | float redACValue = redDCRemover.step(rawRedValue);
112 |
113 | // The signal fed to the beat detector is mirrored since the cleanest monotonic spike is below zero
114 | float filteredPulseValue = lpf.step(-irACValue);
115 | bool beatDetected = beatDetector.addSample(filteredPulseValue);
116 |
117 | if (beatDetector.getRate() > 0) {
118 | state = PULSEOXIMETER_STATE_DETECTING;
119 | spO2calculator.update(irACValue, redACValue, beatDetected);
120 | } else if (state == PULSEOXIMETER_STATE_DETECTING) {
121 | state = PULSEOXIMETER_STATE_IDLE;
122 | spO2calculator.reset();
123 | }
124 |
125 | switch (debuggingMode) {
126 | case PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES:
127 | Serial.print("R:");
128 | Serial.print(rawIRValue);
129 | Serial.print(",");
130 | Serial.println(rawRedValue);
131 | break;
132 |
133 | case PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES:
134 | Serial.print("R:");
135 | Serial.print(irACValue);
136 | Serial.print(",");
137 | Serial.println(redACValue);
138 | break;
139 |
140 | case PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT:
141 | Serial.print("R:");
142 | Serial.print(filteredPulseValue);
143 | Serial.print(",");
144 | Serial.println(beatDetector.getCurrentThreshold());
145 | break;
146 |
147 | default:
148 | break;
149 | }
150 |
151 | if (beatDetected && onBeatDetected) {
152 | onBeatDetected();
153 | }
154 | }
155 | }
156 |
157 | void PulseOximeter::checkCurrentBias()
158 | {
159 | // Follower that adjusts the red led current in order to have comparable DC baselines between
160 | // red and IR leds. The numbers are really magic: the less possible to avoid oscillations
161 | if (millis() - tsLastBiasCheck > CURRENT_ADJUSTMENT_PERIOD_MS) {
162 | bool changed = false;
163 | if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedCurrentIndex < MAX30100_LED_CURR_50MA) {
164 | ++redLedCurrentIndex;
165 | changed = true;
166 | } else if (redDCRemover.getDCW() - irDCRemover.getDCW() > 70000 && redLedCurrentIndex > 0) {
167 | --redLedCurrentIndex;
168 | changed = true;
169 | }
170 |
171 | if (changed) {
172 | hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex);
173 | tsLastCurrentAdjustment = millis();
174 |
175 | if (debuggingMode != PULSEOXIMETER_DEBUGGINGMODE_NONE) {
176 | Serial.print("I:");
177 | Serial.println(redLedCurrentIndex);
178 | }
179 | }
180 |
181 | tsLastBiasCheck = millis();
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/MAX30100_PulseOximeter.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifndef MAX30100_PULSEOXIMETER_H
20 | #define MAX30100_PULSEOXIMETER_H
21 |
22 | #define SAMPLING_FREQUENCY 100
23 | #define CURRENT_ADJUSTMENT_PERIOD_MS 500
24 | #define DEFAULT_IR_LED_CURRENT MAX30100_LED_CURR_50MA
25 | #define RED_LED_CURRENT_START MAX30100_LED_CURR_27_1MA
26 | #define DC_REMOVER_ALPHA 0.95
27 |
28 | #include
29 |
30 | #include "MAX30100.h"
31 | #include "MAX30100_BeatDetector.h"
32 | #include "MAX30100_Filters.h"
33 | #include "MAX30100_SpO2Calculator.h"
34 |
35 | typedef enum PulseOximeterState {
36 | PULSEOXIMETER_STATE_INIT,
37 | PULSEOXIMETER_STATE_IDLE,
38 | PULSEOXIMETER_STATE_DETECTING
39 | } PulseOximeterState;
40 |
41 | typedef enum PulseOximeterDebuggingMode {
42 | PULSEOXIMETER_DEBUGGINGMODE_NONE,
43 | PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES,
44 | PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES,
45 | PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT
46 | } PulseOximeterDebuggingMode;
47 |
48 |
49 | class PulseOximeter {
50 | public:
51 | PulseOximeter();
52 |
53 | bool begin(PulseOximeterDebuggingMode debuggingMode_=PULSEOXIMETER_DEBUGGINGMODE_NONE);
54 | void update();
55 | float getHeartRate();
56 | uint8_t getSpO2();
57 | uint8_t getRedLedCurrentBias();
58 | void setOnBeatDetectedCallback(void (*cb)());
59 | void setIRLedCurrent(LEDCurrent irLedCurrent);
60 | void shutdown();
61 | void resume();
62 |
63 | private:
64 | void checkSample();
65 | void checkCurrentBias();
66 |
67 | PulseOximeterState state;
68 | PulseOximeterDebuggingMode debuggingMode;
69 | uint32_t tsFirstBeatDetected;
70 | uint32_t tsLastBeatDetected;
71 | uint32_t tsLastBiasCheck;
72 | uint32_t tsLastCurrentAdjustment;
73 | BeatDetector beatDetector;
74 | DCRemover irDCRemover;
75 | DCRemover redDCRemover;
76 | FilterBuLp1 lpf;
77 | uint8_t redLedCurrentIndex;
78 | LEDCurrent irLedCurrent;
79 | SpO2Calculator spO2calculator;
80 | MAX30100 hrm;
81 |
82 | void (*onBeatDetected)();
83 | };
84 | #endif
85 |
--------------------------------------------------------------------------------
/src/MAX30100_Registers.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifndef MAX30100_REGISTERS_H
20 | #define MAX30100_REGISTERS_H
21 |
22 | #define MAX30100_I2C_ADDRESS 0x57
23 |
24 | // Interrupt status register (RO)
25 | #define MAX30100_REG_INTERRUPT_STATUS 0x00
26 | #define MAX30100_IS_PWR_RDY (1 << 0)
27 | #define MAX30100_IS_SPO2_RDY (1 << 4)
28 | #define MAX30100_IS_HR_RDY (1 << 5)
29 | #define MAX30100_IS_TEMP_RDY (1 << 6)
30 | #define MAX30100_IS_A_FULL (1 << 7)
31 |
32 | // Interrupt enable register
33 | #define MAX30100_REG_INTERRUPT_ENABLE 0x01
34 | #define MAX30100_IE_ENB_SPO2_RDY (1 << 4)
35 | #define MAX30100_IE_ENB_HR_RDY (1 << 5)
36 | #define MAX30100_IE_ENB_TEMP_RDY (1 << 6)
37 | #define MAX30100_IE_ENB_A_FULL (1 << 7)
38 |
39 | // FIFO control and data registers
40 | #define MAX30100_REG_FIFO_WRITE_POINTER 0x02
41 | #define MAX30100_REG_FIFO_OVERFLOW_COUNTER 0x03
42 | #define MAX30100_REG_FIFO_READ_POINTER 0x04
43 | #define MAX30100_REG_FIFO_DATA 0x05 // Burst read does not autoincrement addr
44 |
45 | // Mode Configuration register
46 | #define MAX30100_REG_MODE_CONFIGURATION 0x06
47 | #define MAX30100_MC_TEMP_EN (1 << 3)
48 | #define MAX30100_MC_RESET (1 << 6)
49 | #define MAX30100_MC_SHDN (1 << 7)
50 | typedef enum Mode {
51 | MAX30100_MODE_HRONLY = 0x02,
52 | MAX30100_MODE_SPO2_HR = 0x03
53 | } Mode;
54 |
55 | // SpO2 Configuration register
56 | // Check tables 8 and 9, p19 of the MAX30100 datasheet to see the permissible
57 | // combinations of sampling rates and pulse widths
58 | #define MAX30100_REG_SPO2_CONFIGURATION 0x07
59 | #define MAX30100_SPC_SPO2_HI_RES_EN (1 << 6)
60 | typedef enum SamplingRate {
61 | MAX30100_SAMPRATE_50HZ = 0x00,
62 | MAX30100_SAMPRATE_100HZ = 0x01,
63 | MAX30100_SAMPRATE_167HZ = 0x02,
64 | MAX30100_SAMPRATE_200HZ = 0x03,
65 | MAX30100_SAMPRATE_400HZ = 0x04,
66 | MAX30100_SAMPRATE_600HZ = 0x05,
67 | MAX30100_SAMPRATE_800HZ = 0x06,
68 | MAX30100_SAMPRATE_1000HZ = 0x07
69 | } SamplingRate;
70 |
71 | typedef enum LEDPulseWidth {
72 | MAX30100_SPC_PW_200US_13BITS = 0x00,
73 | MAX30100_SPC_PW_400US_14BITS = 0x01,
74 | MAX30100_SPC_PW_800US_15BITS = 0x02,
75 | MAX30100_SPC_PW_1600US_16BITS = 0x03
76 | } LEDPulseWidth;
77 |
78 | // LED Configuration register
79 | #define MAX30100_REG_LED_CONFIGURATION 0x09
80 | typedef enum LEDCurrent {
81 | MAX30100_LED_CURR_0MA = 0x00,
82 | MAX30100_LED_CURR_4_4MA = 0x01,
83 | MAX30100_LED_CURR_7_6MA = 0x02,
84 | MAX30100_LED_CURR_11MA = 0x03,
85 | MAX30100_LED_CURR_14_2MA = 0x04,
86 | MAX30100_LED_CURR_17_4MA = 0x05,
87 | MAX30100_LED_CURR_20_8MA = 0x06,
88 | MAX30100_LED_CURR_24MA = 0x07,
89 | MAX30100_LED_CURR_27_1MA = 0x08,
90 | MAX30100_LED_CURR_30_6MA = 0x09,
91 | MAX30100_LED_CURR_33_8MA = 0x0a,
92 | MAX30100_LED_CURR_37MA = 0x0b,
93 | MAX30100_LED_CURR_40_2MA = 0x0c,
94 | MAX30100_LED_CURR_43_6MA = 0x0d,
95 | MAX30100_LED_CURR_46_8MA = 0x0e,
96 | MAX30100_LED_CURR_50MA = 0x0f
97 | } LEDCurrent;
98 |
99 | // Temperature integer part register
100 | #define MAX30100_REG_TEMPERATURE_DATA_INT 0x16
101 | // Temperature fractional part register
102 | #define MAX30100_REG_TEMPERATURE_DATA_FRAC 0x17
103 |
104 | // Revision ID register (RO)
105 | #define MAX30100_REG_REVISION_ID 0xfe
106 | // Part ID register
107 | #define MAX30100_REG_PART_ID 0xff
108 |
109 | #define MAX30100_FIFO_DEPTH 0x10
110 |
111 | #endif
112 |
--------------------------------------------------------------------------------
/src/MAX30100_SpO2Calculator.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
21 | #include "MAX30100_SpO2Calculator.h"
22 |
23 | // SaO2 Look-up Table
24 | // http://www.ti.com/lit/an/slaa274b/slaa274b.pdf
25 | const uint8_t SpO2Calculator::spO2LUT[43] = {100,100,100,100,99,99,99,99,99,99,98,98,98,98,
26 | 98,97,97,97,97,97,97,96,96,96,96,96,96,95,95,
27 | 95,95,95,95,94,94,94,94,94,93,93,93,93,93};
28 |
29 | SpO2Calculator::SpO2Calculator() :
30 | irACValueSqSum(0),
31 | redACValueSqSum(0),
32 | beatsDetectedNum(0),
33 | samplesRecorded(0),
34 | spO2(0)
35 | {
36 | }
37 |
38 | void SpO2Calculator::update(float irACValue, float redACValue, bool beatDetected)
39 | {
40 | irACValueSqSum += irACValue * irACValue;
41 | redACValueSqSum += redACValue * redACValue;
42 | ++samplesRecorded;
43 |
44 | if (beatDetected) {
45 | ++beatsDetectedNum;
46 | if (beatsDetectedNum == CALCULATE_EVERY_N_BEATS) {
47 | float acSqRatio = 100.0 * log(redACValueSqSum/samplesRecorded) / log(irACValueSqSum/samplesRecorded);
48 | uint8_t index = 0;
49 |
50 | if (acSqRatio > 66) {
51 | index = (uint8_t)acSqRatio - 66;
52 | } else if (acSqRatio > 50) {
53 | index = (uint8_t)acSqRatio - 50;
54 | }
55 | reset();
56 |
57 | spO2 = spO2LUT[index];
58 | }
59 | }
60 | }
61 |
62 | void SpO2Calculator::reset()
63 | {
64 | samplesRecorded = 0;
65 | redACValueSqSum = 0;
66 | irACValueSqSum = 0;
67 | beatsDetectedNum = 0;
68 | spO2 = 0;
69 | }
70 |
71 | uint8_t SpO2Calculator::getSpO2()
72 | {
73 | return spO2;
74 | }
75 |
--------------------------------------------------------------------------------
/src/MAX30100_SpO2Calculator.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library
3 | Copyright (C) 2016 OXullo Intersecans
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | #ifndef MAX30100_SPO2CALCULATOR_H
20 | #define MAX30100_SPO2CALCULATOR_H
21 |
22 | #include
23 |
24 | #define CALCULATE_EVERY_N_BEATS 3
25 |
26 | class SpO2Calculator {
27 | public:
28 | SpO2Calculator();
29 |
30 | void update(float irACValue, float redACValue, bool beatDetected);
31 | void reset();
32 | uint8_t getSpO2();
33 |
34 | private:
35 | static const uint8_t spO2LUT[43];
36 |
37 | float irACValueSqSum;
38 | float redACValueSqSum;
39 | uint8_t beatsDetectedNum;
40 | uint32_t samplesRecorded;
41 | uint8_t spO2;
42 | };
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------