diff --git a/.gitignore b/.gitignore
index c6cbe562a4..692e056954 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.iml
+wear/wear.iml
.gradle
/local.properties
/.idea/workspace.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5d19981032..fbb68289f4 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -37,7 +37,7 @@
-
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000000..dbbe355815
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/app/build.gradle b/app/build.gradle
index 74f1b69f37..21b5236a26 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -57,48 +57,42 @@ android {
}
}
productFlavors {
- flavorDimensions "standard", "wear"
- full {
- dimension "standard"
- buildConfigField "boolean", "APS", "true"
- buildConfigField "boolean", "PUMPDRIVERS", "true"
- buildConfigField "boolean", "CLOSEDLOOP", "true"
+ flavorDimensions "standard", "limits", "wear"
+ adult {
+ dimension "limits"
buildConfigField "int", "MAXBOLUS", "17"
}
- fullteenage {
- dimension "standard"
- buildConfigField "boolean", "APS", "true"
- buildConfigField "boolean", "PUMPDRIVERS", "true"
- buildConfigField "boolean", "CLOSEDLOOP", "true"
+ teenage {
+ dimension "limits"
buildConfigField "int", "MAXBOLUS", "10"
}
- fullchild {
+ child {
+ dimension "limits"
+ buildConfigField "int", "MAXBOLUS", "5"
+ }
+ full {
dimension "standard"
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "true"
- buildConfigField "int", "MAXBOLUS", "5"
}
- danarcontrol {
+ pumpcontrol {
dimension "standard"
buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "false"
- buildConfigField "int", "MAXBOLUS", "17"
}
careportal {
dimension "standard"
buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
- buildConfigField "int", "MAXBOLUS", "17"
}
openloop {
dimension "standard"
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "CLOSEDLOOP", "false"
- buildConfigField "int", "MAXBOLUS", "17"
}
wear {
dimension "wear"
@@ -126,7 +120,9 @@ dependencies {
compile 'com.squareup:otto:1.3.7'
compile 'com.j256.ormlite:ormlite-core:4.46'
compile 'com.j256.ormlite:ormlite-android:4.46'
- compile 'com.github.tony19:logback-android-classic:1.1.1-4'
+ compile('com.github.tony19:logback-android-classic:1.1.1-6') {
+ exclude group: 'com.google.android', module: 'android'
+ }
compile 'org.slf4j:slf4j-api:1.7.12'
compile 'com.jjoe64:graphview:4.0.1'
compile 'com.eclipsesource.j2v8:j2v8:3.1.6@aar'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b186abbbed..f6e693e611 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -35,6 +35,7 @@
+
@@ -80,6 +81,10 @@
android:name=".plugins.DanaR.Services.ExecutionService"
android:enabled="true"
android:exported="false" />
+
@@ -91,4 +96,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java
index 851ecdb39c..62bdc6eb1a 100644
--- a/app/src/main/java/info/nightscout/androidaps/Config.java
+++ b/app/src/main/java/info/nightscout/androidaps/Config.java
@@ -15,7 +15,7 @@ public class Config {
public static final boolean SMSCOMMUNICATORENABLED = true;
public static final boolean DANAR = true && BuildConfig.PUMPDRIVERS;
- public static final boolean MM640G = false && BuildConfig.PUMPDRIVERS;
+ public static final boolean DANARKOREAN = true && BuildConfig.PUMPDRIVERS;
public static final boolean detailedLog = true;
public static final boolean logFunctionCalls = true;
diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
index faf0c259fe..2bd72f178b 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
@@ -39,8 +39,6 @@ import info.nightscout.utils.LocaleHelper;
public class MainActivity extends AppCompatActivity {
private static Logger log = LoggerFactory.getLogger(MainActivity.class);
- private static KeepAliveReceiver keepAliveReceiver;
-
static final int CASE_STORAGE = 0x1;
static final int CASE_SMS = 0x2;
@@ -77,11 +75,7 @@ public class MainActivity extends AppCompatActivity {
// no action
}
- if (keepAliveReceiver == null) {
- keepAliveReceiver = new KeepAliveReceiver();
- startService(new Intent(this, ExecutionService.class));
- keepAliveReceiver.setAlarm(this);
- }
+
setUpTabs(false);
}
@@ -90,12 +84,17 @@ public class MainActivity extends AppCompatActivity {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String lang = SP.getString("language", "en");
LocaleHelper.setLocale(getApplicationContext(), lang);
- recreate();
- try { // activity may be destroyed
- setUpTabs(ev.isSwitchToLast());
- } catch (IllegalStateException e) {
- e.printStackTrace();
- }
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ recreate();
+ try { // activity may be destroyed
+ setUpTabs(ev.isSwitchToLast());
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
+ }
+ });
}
private void setUpTabs(boolean switchToLast) {
@@ -164,8 +163,7 @@ public class MainActivity extends AppCompatActivity {
// break;
case R.id.nav_exit:
log.debug("Exiting");
- keepAliveReceiver.cancelAlarm(this);
-
+ MainApp.instance().stopKeepAliveService();
MainApp.bus().post(new EventAppExit());
MainApp.closeDbHelper();
finish();
diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java
index b2f46cddb8..e2e7eabd89 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainApp.java
+++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java
@@ -1,6 +1,7 @@
package info.nightscout.androidaps;
import android.app.Application;
+import android.content.Intent;
import android.content.res.Resources;
import android.support.annotation.Nullable;
@@ -22,9 +23,10 @@ import info.nightscout.androidaps.plugins.CircadianPercentageProfile.CircadianPe
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRFragment;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanFragment;
import info.nightscout.androidaps.plugins.Loop.LoopFragment;
-import info.nightscout.androidaps.plugins.MM640g.MM640gFragment;
-import info.nightscout.androidaps.plugins.NSProfileViewer.NSProfileViewerFragment;
+import info.nightscout.androidaps.plugins.MDI.MDIFragment;
+import info.nightscout.androidaps.plugins.NSProfile.NSProfileFragment;
import info.nightscout.androidaps.plugins.Objectives.ObjectivesFragment;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAFragment;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
@@ -37,11 +39,13 @@ import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpFragment;
import info.nightscout.androidaps.plugins.Wear.WearFragment;
+import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import io.fabric.sdk.android.Fabric;
public class MainApp extends Application {
private static Logger log = LoggerFactory.getLogger(MainApp.class);
+ private static KeepAliveReceiver keepAliveReceiver;
private static Bus sBus;
private static MainApp sInstance;
@@ -70,12 +74,13 @@ public class MainApp extends Application {
pluginsList.add(OverviewFragment.getPlugin());
pluginsList.add(ActionsFragment.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRFragment.getPlugin());
- if (Config.MM640G) pluginsList.add(MM640gFragment.getPlugin());
+ if (Config.DANARKOREAN) pluginsList.add(DanaRKoreanFragment.getPlugin());
if (Config.CAREPORTALENABLED) pluginsList.add(CareportalFragment.getPlugin());
+ pluginsList.add(MDIFragment.getPlugin());
pluginsList.add(VirtualPumpFragment.getPlugin());
if (Config.LOOPENABLED) pluginsList.add(LoopFragment.getPlugin());
if (Config.OPENAPSMAENABLED) pluginsList.add(OpenAPSMAFragment.getPlugin());
- pluginsList.add(NSProfileViewerFragment.getPlugin());
+ pluginsList.add(NSProfileFragment.getPlugin());
pluginsList.add(SimpleProfileFragment.getPlugin());
pluginsList.add(CircadianPercentageProfileFragment.getPlugin());
pluginsList.add(TreatmentsFragment.getPlugin());
@@ -94,6 +99,26 @@ public class MainApp extends Application {
MainApp.getConfigBuilder().initialize();
}
MainApp.getConfigBuilder().uploadAppStart();
+
+ startKeepAliveService();
+ }
+
+ private void startKeepAliveService() {
+ if (keepAliveReceiver == null) {
+ keepAliveReceiver = new KeepAliveReceiver();
+ if (Config.DANAR) {
+ startService(new Intent(this, info.nightscout.androidaps.plugins.DanaR.Services.ExecutionService.class));
+ startService(new Intent(this, info.nightscout.androidaps.plugins.DanaRKorean.Services.ExecutionService.class));
+ }
+ keepAliveReceiver.setAlarm(this);
+ }
+ }
+
+
+
+ public void stopKeepAliveService(){
+ if(keepAliveReceiver!=null)
+ keepAliveReceiver.cancelAlarm(this);
}
public static Bus bus() {
@@ -172,4 +197,4 @@ public class MainApp extends Application {
super.onTerminate();
sDatabaseHelper.close();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java
index 0934e68ec3..f6edcdd827 100644
--- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java
@@ -17,6 +17,7 @@ import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.DanaR.BluetoothDevicePreference;
import info.nightscout.androidaps.plugins.DanaR.DanaRFragment;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
import info.nightscout.utils.LocaleHelper;
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
@@ -89,13 +90,12 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResource(R.xml.pref_nightscout);
if (Config.DANAR) {
DanaRPlugin danaRPlugin = (DanaRPlugin) MainApp.getSpecificPlugin(DanaRPlugin.class);
- if (danaRPlugin.isEnabled(PluginBase.PUMP)) {
+ DanaRKoreanPlugin danaRKoreanPlugin = (DanaRKoreanPlugin) MainApp.getSpecificPlugin(DanaRKoreanPlugin.class);
+ if (danaRPlugin.isEnabled(PluginBase.PUMP) || danaRKoreanPlugin.isEnabled(PluginBase.PUMP)) {
addPreferencesFromResource(R.xml.pref_danar);
addPreferencesFromResource(R.xml.pref_danarprofile);
}
}
- if (Config.MM640G)
- addPreferencesFromResource(R.xml.pref_mm640g);
if (Config.SMSCOMMUNICATORENABLED)
addPreferencesFromResource(R.xml.pref_smscommunicator);
addPreferencesFromResource(R.xml.pref_others);
diff --git a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java
index c38724d6bd..95a6b81b68 100644
--- a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java
+++ b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java
@@ -22,9 +22,6 @@ import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
@@ -36,10 +33,11 @@ import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventTreatmentChange;
+import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.History.DanaRNSHistorySync;
-import info.nightscout.androidaps.plugins.NSProfileViewer.NSProfileViewerPlugin;
+import info.nightscout.androidaps.plugins.NSProfile.NSProfilePlugin;
import info.nightscout.androidaps.plugins.Objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
@@ -76,7 +74,7 @@ public class DataService extends IntentService {
nsClientEnabled = true;
}
- boolean isNSProfile = ConfigBuilderPlugin.getActiveProfile().getClass().equals(NSProfileViewerPlugin.class);
+ boolean isNSProfile = ConfigBuilderPlugin.getActiveProfile().getClass().equals(NSProfilePlugin.class);
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean nsUploadOnly = SP.getBoolean("ns_upload_only", false);
@@ -95,12 +93,11 @@ public class DataService extends IntentService {
// Objectives 0
ObjectivesPlugin.bgIsAvailableInNS = true;
ObjectivesPlugin.saveProgress();
- } else if (isNSProfile && Intents.ACTION_NEW_PROFILE.equals(action)){
- // always handle Profili if NSProfile is enabled without looking at nsUploadOnly
+ } else if (isNSProfile && Intents.ACTION_NEW_PROFILE.equals(action)) {
+ // always handle Profile if NSProfile is enabled without looking at nsUploadOnly
handleNewDataFromNSClient(intent);
} else if (!nsUploadOnly &&
- (Intents.ACTION_NEW_PROFILE.equals(action) ||
- Intents.ACTION_NEW_TREATMENT.equals(action) ||
+ (Intents.ACTION_NEW_TREATMENT.equals(action) ||
Intents.ACTION_CHANGED_TREATMENT.equals(action) ||
Intents.ACTION_REMOVED_TREATMENT.equals(action) ||
Intents.ACTION_NEW_STATUS.equals(action) ||
@@ -152,7 +149,7 @@ public class DataService extends IntentService {
BgReading bgReading = new BgReading();
bgReading.value = bundle.getDouble(Intents.EXTRA_BG_ESTIMATE);
- bgReading.slope = bundle.getDouble(Intents.EXTRA_BG_SLOPE);
+ bgReading.direction = bundle.getString(Intents.EXTRA_BG_SLOPE_NAME);
bgReading.battery_level = bundle.getInt(Intents.EXTRA_SENSOR_BATTERY);
bgReading.timeIndex = bundle.getLong(Intents.EXTRA_TIMESTAMP);
bgReading.raw = bundle.getDouble(Intents.EXTRA_RAW);
@@ -248,21 +245,24 @@ public class DataService extends IntentService {
String activeProfile = bundles.getString("activeprofile");
String profile = bundles.getString("profile");
NSProfile nsProfile = new NSProfile(new JSONObject(profile), activeProfile);
- if (MainApp.getConfigBuilder() == null) {
- log.error("Config builder not ready on receive profile");
- return;
- }
+ MainApp.bus().post(new EventNewBasalProfile(nsProfile));
+
PumpInterface pump = MainApp.getConfigBuilder();
if (pump != null) {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- if (SP.getBoolean("syncprofiletopump", false))
- pump.setNewBasalProfile(nsProfile);
+ if (SP.getBoolean("syncprofiletopump", false)) {
+ if (pump.setNewBasalProfile(nsProfile) == PumpInterface.SUCCESS) {
+ SmsCommunicatorPlugin smsCommunicatorPlugin = (SmsCommunicatorPlugin) MainApp.getSpecificPlugin(SmsCommunicatorPlugin.class);
+ if (smsCommunicatorPlugin != null && smsCommunicatorPlugin.isEnabled(PluginBase.GENERAL)) {
+ smsCommunicatorPlugin.sendNotificationToAllNumbers(MainApp.sResources.getString(R.string.profile_set_ok));
+ }
+ }
+ }
} else {
log.error("No active pump selected");
}
if (Config.logIncommingData)
log.debug("Received profile: " + activeProfile + " " + profile);
- MainApp.bus().post(new EventNewBasalProfile(nsProfile));
} catch (JSONException e) {
e.printStackTrace();
}
@@ -419,7 +419,8 @@ public class DataService extends IntentService {
if (trJson.has("eventType")) {
treatment.mealBolus = true;
if (trJson.get("eventType").equals("Correction Bolus")) treatment.mealBolus = false;
- if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0) treatment.mealBolus = false;
+ if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0)
+ treatment.mealBolus = false;
}
treatment.setTimeIndex(treatment.getTimeIndex());
try {
@@ -469,7 +470,8 @@ public class DataService extends IntentService {
if (trJson.has("eventType")) {
treatment.mealBolus = true;
if (trJson.get("eventType").equals("Correction Bolus")) treatment.mealBolus = false;
- if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0) treatment.mealBolus = false;
+ if (trJson.get("eventType").equals("Bolus Wizard") && treatment.carbs <= 0)
+ treatment.mealBolus = false;
}
treatment.setTimeIndex(treatment.getTimeIndex());
try {
diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
index 267f8f886d..6dcf282e6c 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
@@ -32,7 +32,7 @@ public class BgReading implements DataPointInterface {
public double value;
@DatabaseField
- public double slope;
+ public String direction;
@DatabaseField
public double raw;
@@ -48,6 +48,7 @@ public class BgReading implements DataPointInterface {
timeIndex = sgv.getMills();
value = sgv.getMgdl();
raw = sgv.getFiltered();
+ direction = sgv.getDirection();
}
public Double valueToUnits(String units) {
@@ -62,13 +63,48 @@ public class BgReading implements DataPointInterface {
else return DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL);
}
+ public String directionToSymbol() {
+ String symbol = "";
+ if (direction.compareTo("DoubleDown") == 0) {
+ symbol = "\u21ca";
+ } else if (direction.compareTo("SingleDown") == 0) {
+ symbol = "\u2193";
+ } else if (direction.compareTo("FortyFiveDown") == 0) {
+ symbol = "\u2198";
+ } else if (direction.compareTo("Flat") == 0) {
+ symbol = "\u2192";
+ } else if (direction.compareTo("FortyFiveUp") == 0) {
+ symbol = "\u2197";
+ } else if (direction.compareTo("SingleUp") == 0) {
+ symbol = "\u2191";
+ } else if (direction.compareTo("DoubleUp") == 0) {
+ symbol = "\u21c8";
+ } else if (isSlopeNameInvalid(direction)) {
+ symbol = "??";
+ }
+ return symbol;
+ }
+
+ public static boolean isSlopeNameInvalid(String direction) {
+ if (direction.compareTo("NOT_COMPUTABLE") == 0 ||
+ direction.compareTo("NOT COMPUTABLE") == 0 ||
+ direction.compareTo("OUT_OF_RANGE") == 0 ||
+ direction.compareTo("OUT OF RANGE") == 0 ||
+ direction.compareTo("NONE") == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
@Override
public String toString() {
return "BgReading{" +
"timeIndex=" + timeIndex +
", date=" + new Date(timeIndex) +
", value=" + value +
- ", slope=" + slope +
+ ", direction=" + direction +
", raw=" + raw +
", battery_level=" + battery_level +
'}';
diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
index 4717f6e237..fccb964394 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
@@ -40,7 +40,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_TREATMENTS = "Treatments";
public static final String DATABASE_DANARHISTORY = "DanaRHistory";
- private static final int DATABASE_VERSION = 4;
+ private static final int DATABASE_VERSION = 5;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -196,8 +196,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("timeIndex", true);
Where where = queryBuilder.where();
- where.ge("timeIndex", mills);
- queryBuilder.where().gt("value", 38);
+ where.ge("timeIndex", mills).and().gt("value", 38);
PreparedQuery preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.java b/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.java
new file mode 100644
index 0000000000..e9a9ce511d
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.java
@@ -0,0 +1,8 @@
+package info.nightscout.androidaps.events;
+
+/**
+ * Created by mike on 13.12.2016.
+ */
+
+public class EventInitializationChanged {
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
new file mode 100644
index 0000000000..78a111d468
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
@@ -0,0 +1,38 @@
+package info.nightscout.androidaps.interfaces;
+
+/**
+ * Created by mike on 08.12.2016.
+ */
+
+public class PumpDescription {
+ public static final int NONE = 0;
+ public static final int PERCENT = 1;
+ public static final int ABSOLUTE = 2;
+ public static final int EXTENDED = 4;
+
+ public boolean isBolusCapable = true;
+ public double bolusStep = 0.1d;
+
+ public boolean isExtendedBolusCapable = true;
+ public double extendedBolusStep = 0.1d;
+
+ public boolean isTempBasalCapable = true;
+ public int lowTempBasalStyle = PERCENT;
+ public int highTempBasalStyle = PERCENT;
+ public double maxHighTempPercent = 200;
+ public double maxHighTempAbsolute = 0; // zero = no limit
+ public double lowTempPercentStep = 10;
+ public double lowTempAbsoluteStep = 0.05d;
+ public int lowTempPercentDuration = 30;
+ public int lowTempAbsoluteDuration = 30;
+ public double highTempPercentStep = 10;
+ public double highTempAbsoluteStep = 0.05d;
+ public int highTempPercentDuration = 30;
+ public int highTempAbsoluteDuration = 30;
+
+ public boolean isSetBasalProfileCapable = true;
+ public double basalStep = 0.01d;
+ public double basalMinimumRate = 0.04d;
+
+ public boolean isRefillingCapable = false;
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java
index 2b413fbe43..cde760fc28 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java
@@ -22,7 +22,11 @@ public interface PumpInterface {
boolean isExtendedBoluslInProgress();
// Upload to pump new basal profile
- void setNewBasalProfile(NSProfile profile);
+ int SUCCESS = 0;
+ int FAILED = 1;
+ int NOT_NEEDED = 2;
+ int setNewBasalProfile(NSProfile profile);
+ boolean isThisProfileSet(NSProfile profile);
double getBaseBasalRate(); // base basal rate, not temp basal
double getTempBasalAbsoluteRate();
@@ -42,4 +46,6 @@ public interface PumpInterface {
// Status to be passed to NS
JSONObject getJSONStatus();
String deviceID();
+
+ PumpDescription getPumpDescription();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java
index f263adcc99..88643752ee 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java
@@ -1,14 +1,21 @@
package info.nightscout.androidaps.plugins.Actions;
+import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Button;
+import com.squareup.otto.Subscribe;
+
+import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.events.EventInitializationChanged;
+import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.FragmentBase;
import info.nightscout.androidaps.plugins.Actions.dialogs.FillDialog;
import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
@@ -22,10 +29,16 @@ import info.nightscout.androidaps.plugins.Actions.dialogs.NewTempBasalDialog;
public class ActionsFragment extends Fragment implements FragmentBase, View.OnClickListener {
static ActionsPlugin actionsPlugin = new ActionsPlugin();
+
static public ActionsPlugin getPlugin() {
return actionsPlugin;
}
+ Button profileSwitch;
+ Button extendedBolus;
+ Button tempBasal;
+ Button fill;
+
public ActionsFragment() {
}
@@ -35,14 +48,69 @@ public class ActionsFragment extends Fragment implements FragmentBase, View.OnCl
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.actions_fragment, container, false);
- view.findViewById(R.id.actions_profileswitch).setOnClickListener(this);
- view.findViewById(R.id.actions_extendedbolus).setOnClickListener(this);
- view.findViewById(R.id.actions_settempbasal).setOnClickListener(this);
- view.findViewById(R.id.actions_fill).setOnClickListener(this);
+ profileSwitch = (Button) view.findViewById(R.id.actions_profileswitch);
+ extendedBolus = (Button) view.findViewById(R.id.actions_extendedbolus);
+ tempBasal = (Button) view.findViewById(R.id.actions_settempbasal);
+ fill = (Button) view.findViewById(R.id.actions_fill);
+ profileSwitch.setOnClickListener(this);
+ extendedBolus.setOnClickListener(this);
+ tempBasal.setOnClickListener(this);
+ fill.setOnClickListener(this);
+
+ updateGUIIfVisible();
return view;
}
+ @Override
+ public void onPause() {
+ super.onPause();
+ MainApp.bus().unregister(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ MainApp.bus().register(this);
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventInitializationChanged ev) {
+ updateGUIIfVisible();
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventRefreshGui ev) {
+ updateGUIIfVisible();
+ }
+
+ void updateGUIIfVisible() {
+ Activity activity = getActivity();
+ if (activity != null)
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!MainApp.getConfigBuilder().getPumpDescription().isSetBasalProfileCapable || !MainApp.getConfigBuilder().isInitialized())
+ profileSwitch.setVisibility(View.GONE);
+ else
+ profileSwitch.setVisibility(View.VISIBLE);
+ if (!MainApp.getConfigBuilder().getPumpDescription().isExtendedBolusCapable || !MainApp.getConfigBuilder().isInitialized())
+ extendedBolus.setVisibility(View.GONE);
+ else
+ extendedBolus.setVisibility(View.VISIBLE);
+ if (!MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable || !MainApp.getConfigBuilder().isInitialized())
+ tempBasal.setVisibility(View.GONE);
+ else
+ tempBasal.setVisibility(View.VISIBLE);
+ if (!MainApp.getConfigBuilder().getPumpDescription().isRefillingCapable || !MainApp.getConfigBuilder().isInitialized())
+ fill.setVisibility(View.GONE);
+ else
+ fill.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+
+
@Override
public void onClick(View view) {
FragmentManager manager = getFragmentManager();
@@ -57,11 +125,11 @@ public class ActionsFragment extends Fragment implements FragmentBase, View.OnCl
case R.id.actions_extendedbolus:
NewExtendedBolusDialog newExtendedDialog = new NewExtendedBolusDialog();
newExtendedDialog.show(manager, "NewExtendedDialog");
- break;
+ break;
case R.id.actions_settempbasal:
NewTempBasalDialog newTempDialog = new NewTempBasalDialog();
newTempDialog.show(manager, "NewTempDialog");
- break;
+ break;
case R.id.actions_fill:
FillDialog fillDialog = new FillDialog();
fillDialog.show(manager, "FillDialog");
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsPlugin.java
index d591f67556..df283bac13 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsPlugin.java
@@ -30,12 +30,12 @@ public class ActionsPlugin implements PluginBase {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == GENERAL && fragmentVisible;
}
@Override
@@ -45,12 +45,12 @@ public class ActionsPlugin implements PluginBase {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java
index 047dd3e7c5..05245bd0b1 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java
@@ -16,9 +16,12 @@ import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialo
public class CareportalFragment extends Fragment implements FragmentBase, View.OnClickListener {
- static CareportalPlugin careportalPlugin = new CareportalPlugin();
+ static CareportalPlugin careportalPlugin;
static public CareportalPlugin getPlugin() {
+ if (careportalPlugin == null) {
+ careportalPlugin = new CareportalPlugin();
+ }
return careportalPlugin;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalPlugin.java
index adc9ae0d4f..87f9f0f817 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalPlugin.java
@@ -26,12 +26,12 @@ public class CareportalPlugin implements PluginBase {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == GENERAL && fragmentVisible;
}
@Override
@@ -41,12 +41,12 @@ public class CareportalPlugin implements PluginBase {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java
index 1011caf40a..43b383f33a 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java
@@ -541,7 +541,6 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
builder.setMessage(confirmText);
builder.setPositiveButton(getContext().getString(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
if (options.executeProfileSwitch) {
if (data.has("profile")) {
sHandler.post(new Runnable() {
@@ -559,12 +558,15 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} else {
log.error("No active pump selected");
}
+ ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
+ } else {
+ ConfigBuilderPlugin.uploadCareportalEntryToNS(data);
}
}
});
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/CircadianPercentageProfile/CircadianPercentageProfilePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/CircadianPercentageProfile/CircadianPercentageProfilePlugin.java
index 094ae157c8..274e1a941d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/CircadianPercentageProfile/CircadianPercentageProfilePlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/CircadianPercentageProfile/CircadianPercentageProfilePlugin.java
@@ -69,12 +69,12 @@ public class CircadianPercentageProfilePlugin implements PluginBase, ProfileInte
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == PROFILE && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == PROFILE && fragmentVisible;
}
@Override
@@ -84,12 +84,12 @@ public class CircadianPercentageProfilePlugin implements PluginBase, ProfileInte
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == PROFILE) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == PROFILE) this.fragmentVisible = fragmentVisible;
}
void storeSettings() {
@@ -265,7 +265,7 @@ public class CircadianPercentageProfilePlugin implements PluginBase, ProfileInte
if (percentage < MIN_PERCENTAGE || percentage > MAX_PERCENTAGE){
String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Percentage");
log.error(msg);
- OpenAPSMAPlugin.sendErrorToNSClient(msg);
+ MainApp.getConfigBuilder().uploadError(msg);
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
percentage = Math.max(percentage, MIN_PERCENTAGE);
percentage = Math.min(percentage, MAX_PERCENTAGE);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java
index 70a526f1a2..e15f97d5fb 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java
@@ -1,16 +1,10 @@
package info.nightscout.androidaps.plugins.ConfigBuilder;
-import android.app.Activity;
import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
-import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -21,6 +15,7 @@ import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
+
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventRefreshGui;
@@ -31,9 +26,8 @@ import info.nightscout.androidaps.interfaces.FragmentBase;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.interfaces.TempBasalsInterface;
-import info.nightscout.androidaps.interfaces.TreatmentsInterface;
-import info.nightscout.androidaps.plugins.Loop.LoopFragment;
+import info.nightscout.androidaps.plugins.NSProfile.NSProfilePlugin;
+import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpPlugin;
public class ConfigBuilderFragment extends Fragment implements FragmentBase {
@@ -93,7 +87,8 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
nsclientVerView.setText(ConfigBuilderPlugin.nsClientVersionName);
nightscoutVerView.setText(ConfigBuilderPlugin.nightscoutVersionName);
if (ConfigBuilderPlugin.nsClientVersionCode < 117) nsclientVerView.setTextColor(Color.RED);
- if (ConfigBuilderPlugin.nightscoutVersionCode < 900) nightscoutVerView.setTextColor(Color.RED);
+ if (ConfigBuilderPlugin.nightscoutVersionCode < 900)
+ nightscoutVerView.setTextColor(Color.RED);
setViews();
return view;
}
@@ -179,6 +174,7 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
onEnabledCategoryChanged(plugin, type);
configBuilderPlugin.storeSettings();
MainApp.bus().post(new EventRefreshGui(true));
+ getPlugin().logPluginStatus();
}
});
@@ -189,6 +185,7 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
plugin.setFragmentVisible(type, cb.isChecked());
configBuilderPlugin.storeSettings();
MainApp.bus().post(new EventRefreshGui(true));
+ getPlugin().logPluginStatus();
}
});
} else {
@@ -208,11 +205,13 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
holder.checkboxVisible.setEnabled(false);
}
- int type = plugin.getType();
- // Force enabled if there is only one plugin
+ // Hide enabled control and force enabled plugin if there is only one plugin available
if (type == PluginBase.PUMP || type == PluginBase.TREATMENT || type == PluginBase.TEMPBASAL || type == PluginBase.PROFILE)
- if (pluginList.size() < 2)
+ if (pluginList.size() < 2) {
holder.checkboxEnabled.setEnabled(false);
+ plugin.setFragmentEnabled(type, true);
+ getPlugin().storeSettings();
+ }
// Constraints cannot be disabled
if (type == PluginBase.CONSTRAINTS)
@@ -228,6 +227,16 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
}
}
+ // Disable profile control for pump profiles if pump is not enabled
+ if (type == PluginBase.PROFILE) {
+ if (PumpInterface.class.isAssignableFrom(plugin.getClass())) {
+ if (!plugin.isEnabled(PluginBase.PUMP)) {
+ holder.checkboxEnabled.setEnabled(false);
+ holder.checkboxEnabled.setChecked(false);
+ }
+ }
+ }
+
return convertView;
}
@@ -235,9 +244,8 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
}
void onEnabledCategoryChanged(PluginBase changedPlugin, int type) {
- int category = changedPlugin.getType();
ArrayList pluginsInCategory = null;
- switch (category) {
+ switch (type) {
// Multiple selection allowed
case PluginBase.GENERAL:
case PluginBase.CONSTRAINTS:
@@ -256,7 +264,7 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
case PluginBase.TEMPBASAL:
case PluginBase.TREATMENT:
case PluginBase.PUMP:
- pluginsInCategory = MainApp.getSpecificPluginsList(category);
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(PumpInterface.class);
break;
}
if (pluginsInCategory != null) {
@@ -271,7 +279,12 @@ public class ConfigBuilderFragment extends Fragment implements FragmentBase {
}
}
} else { // enable first plugin in list
- pluginsInCategory.get(0).setFragmentEnabled(type, true);
+ if (type == PluginBase.PUMP)
+ MainApp.getSpecificPlugin(VirtualPumpPlugin.class).setFragmentEnabled(type, true);
+ else if (type == PluginBase.PROFILE)
+ MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentEnabled(type, true);
+ else
+ pluginsInCategory.get(0).setFragmentEnabled(type, true);
}
setViews();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java
index 00d6beafcf..ccbec0581f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java
@@ -35,6 +35,7 @@ import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
+import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.TempBasalsInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
@@ -45,6 +46,10 @@ import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.DetermineBasalResult;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Actions.dialogs.NewExtendedBolusDialog;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.client.data.DbLogger;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
@@ -97,12 +102,12 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
@Override
public boolean isEnabled(int type) {
- return true;
+ return type == GENERAL && true;
}
@Override
public boolean isVisibleInTabs(int type) {
- return true;
+ return type == GENERAL && true;
}
@Override
@@ -191,6 +196,22 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
return activeLoop;
}
+ public void logPluginStatus() {
+ for (PluginBase p : pluginList) {
+ log.debug(p.getName() + ":" +
+ (p.isEnabled(1) ? " GENERAL" : "") +
+ (p.isEnabled(2) ? " TREATMENT" : "") +
+ (p.isEnabled(3) ? " TEMPBASAL" : "") +
+ (p.isEnabled(4) ? " PROFILE" : "") +
+ (p.isEnabled(5) ? " APS" : "") +
+ (p.isEnabled(6) ? " PUMP" : "") +
+ (p.isEnabled(7) ? " CONSTRAINTS" : "") +
+ (p.isEnabled(8) ? " LOOP" : "") +
+ (p.isEnabled(9) ? " BGSOURCE" : "")
+ );
+ }
+ }
+
private void verifySelectionInCategories() {
ArrayList pluginsInCategory;
@@ -314,8 +335,31 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
}
@Override
- public void setNewBasalProfile(NSProfile profile) {
- activePump.setNewBasalProfile(profile);
+ public int setNewBasalProfile(NSProfile profile) {
+ // Compare with pump limits
+ NSProfile.BasalValue[] basalValues = profile.getBasalValues();
+
+ for (int index = 0; index < basalValues.length; index++) {
+ if (basalValues[index].value < getPumpDescription().basalMinimumRate) {
+ Notification notification = new Notification(Notification.BASAL_VALUE_BELOW_MINIMUM, MainApp.sResources.getString(R.string.basalvaluebelowminimum), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ return FAILED;
+ }
+ }
+
+ MainApp.bus().post(new EventDismissNotification(Notification.BASAL_VALUE_BELOW_MINIMUM));
+
+ if (isThisProfileSet(profile)) {
+ log.debug("Correct profile already set");
+ return NOT_NEEDED;
+ } else {
+ return activePump.setNewBasalProfile(profile);
+ }
+ }
+
+ @Override
+ public boolean isThisProfileSet(NSProfile profile) {
+ return activePump.isThisProfileSet(profile);
}
@Override
@@ -594,6 +638,21 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain
else return "Unknown";
}
+ @Override
+ public PumpDescription getPumpDescription() {
+ if (activePump != null)
+ return activePump.getPumpDescription();
+ else {
+ PumpDescription emptyDescription = new PumpDescription();
+ emptyDescription.isBolusCapable = false;
+ emptyDescription.isExtendedBolusCapable = false;
+ emptyDescription.isSetBasalProfileCapable = false;
+ emptyDescription.isTempBasalCapable = false;
+ emptyDescription.isRefillingCapable = false;
+ return emptyDescription;
+ }
+ }
+
/**
* Constraints interface
**/
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java
index 3595193ce1..4ec54cb37e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java
@@ -38,9 +38,12 @@ import info.nightscout.utils.SetWarnColor;
public class DanaRFragment extends Fragment implements FragmentBase {
private static Logger log = LoggerFactory.getLogger(DanaRFragment.class);
- private static DanaRPlugin danaRPlugin = new DanaRPlugin();
+ private static DanaRPlugin danaRPlugin;
public static DanaRPlugin getPlugin() {
+ if(danaRPlugin==null){
+ danaRPlugin = new DanaRPlugin();
+ }
return danaRPlugin;
}
@@ -204,20 +207,20 @@ public class DanaRFragment extends Fragment implements FragmentBase {
Long agoMsec = new Date().getTime() - DanaRPlugin.getDanaRPump().lastBolusTime.getTime();
double agoHours = agoMsec / 60d / 60d / 1000d;
if (agoHours < 6) // max 6h back
- lastBolusView.setText(formatTime.format(DanaRPlugin.getDanaRPump().lastBolusTime) + " (" + DecimalFormatter.to1Decimal(agoHours) + " " + getString(R.string.hoursago) + ") " + DecimalFormatter.to2Decimal(danaRPlugin.getDanaRPump().lastBolusAmount) + " U");
+ lastBolusView.setText(formatTime.format(DanaRPlugin.getDanaRPump().lastBolusTime) + " (" + DecimalFormatter.to1Decimal(agoHours) + " " + getString(R.string.hoursago) + ") " + DecimalFormatter.to2Decimal(getPlugin().getDanaRPump().lastBolusAmount) + " U");
else lastBolusView.setText("");
}
dailyUnitsView.setText(DecimalFormatter.to0Decimal(DanaRPlugin.getDanaRPump().dailyTotalUnits) + " / " + DanaRPlugin.getDanaRPump().maxDailyTotalUnits + " U");
SetWarnColor.setColor(dailyUnitsView, DanaRPlugin.getDanaRPump().dailyTotalUnits, DanaRPlugin.getDanaRPump().maxDailyTotalUnits * 0.75d, DanaRPlugin.getDanaRPump().maxDailyTotalUnits * 0.9d);
- basaBasalRateView.setText("( " + (DanaRPlugin.getDanaRPump().activeProfile + 1) + " ) " + DecimalFormatter.to2Decimal(danaRPlugin.getBaseBasalRate()) + " U/h");
- if (danaRPlugin.isRealTempBasalInProgress()) {
- tempBasalView.setText(danaRPlugin.getRealTempBasal().toString());
+ basaBasalRateView.setText("( " + (DanaRPlugin.getDanaRPump().activeProfile + 1) + " ) " + DecimalFormatter.to2Decimal(getPlugin().getBaseBasalRate()) + " U/h");
+ if (getPlugin().isRealTempBasalInProgress()) {
+ tempBasalView.setText(getPlugin().getRealTempBasal().toString());
} else {
tempBasalView.setText("");
}
- if (danaRPlugin.isExtendedBoluslInProgress()) {
- extendedBolusView.setText(danaRPlugin.getExtendedBolus().toString());
+ if (getPlugin().isExtendedBoluslInProgress()) {
+ extendedBolusView.setText(getPlugin().getExtendedBolus().toString());
} else {
extendedBolusView.setText("");
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java
index 5501319e99..99f318c5a1 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java
@@ -16,7 +16,6 @@ import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.text.DateFormat;
import java.util.Date;
import java.util.Objects;
@@ -33,14 +32,18 @@ import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
+import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.DanaR.Services.ExecutionService;
+import info.nightscout.androidaps.plugins.NSProfile.NSProfilePlugin;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
-import info.nightscout.utils.ToastUtils;
/**
* Created by mike on 05.08.2016.
@@ -63,6 +66,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
private static DanaRPump sDanaRPump = new DanaRPump();
private static boolean useExtendedBoluses = false;
+ private static PumpDescription pumpDescription = new PumpDescription();
+
public static DanaRPump getDanaRPump() {
return sDanaRPump;
}
@@ -75,6 +80,32 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
Intent intent = new Intent(context, ExecutionService.class);
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
MainApp.bus().register(this);
+
+ pumpDescription.isBolusCapable = true; // TODO: use description in setTempBasalAbsolute
+ pumpDescription.bolusStep = 0.05d;
+
+ pumpDescription.isExtendedBolusCapable = true;
+ pumpDescription.extendedBolusStep = 0.1d;
+
+ pumpDescription.isTempBasalCapable = true;
+ pumpDescription.lowTempBasalStyle = PumpDescription.PERCENT;
+ pumpDescription.highTempBasalStyle = useExtendedBoluses ? PumpDescription.EXTENDED : PumpDescription.PERCENT;
+ pumpDescription.maxHighTempPercent = 200;
+ pumpDescription.maxHighTempAbsolute = 0;
+ pumpDescription.lowTempPercentStep = 10;
+ pumpDescription.lowTempAbsoluteStep = 0;
+ pumpDescription.lowTempPercentDuration = 60;
+ pumpDescription.lowTempAbsoluteDuration = 60;
+ pumpDescription.highTempPercentStep = 10;
+ pumpDescription.highTempAbsoluteStep = 0.05d;
+ pumpDescription.highTempPercentDuration = 60;
+ pumpDescription.highTempAbsoluteDuration = 30;
+
+ pumpDescription.isSetBasalProfileCapable = true;
+ pumpDescription.basalStep = 0.01d;
+ pumpDescription.basalMinimumRate = 0.04d;
+
+ pumpDescription.isRefillingCapable = true;
}
ServiceConnection mConnection = new ServiceConnection() {
@@ -99,11 +130,16 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
@Subscribe
public void onStatusEvent(final EventPreferenceChange s) {
- boolean previousValue = useExtendedBoluses;
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
- useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false);
- if (useExtendedBoluses != previousValue && isExtendedBoluslInProgress()) {
- sExecutionService.extendedBolusStop();
+ if (isEnabled(PUMP)) {
+ boolean previousValue = useExtendedBoluses;
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+ useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false);
+
+ pumpDescription.highTempBasalStyle = useExtendedBoluses ? PumpDescription.EXTENDED : PumpDescription.PERCENT;
+
+ if (useExtendedBoluses != previousValue && isExtendedBoluslInProgress()) {
+ sExecutionService.extendedBolusStop();
+ }
}
}
@@ -140,8 +176,17 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- if (type == PluginBase.PROFILE) this.fragmentProfileEnabled = fragmentEnabled;
- else if (type == PluginBase.PUMP) this.fragmentPumpEnabled = fragmentEnabled;
+ if (type == PluginBase.PROFILE)
+ this.fragmentProfileEnabled = fragmentEnabled;
+ else if (type == PluginBase.PUMP)
+ this.fragmentPumpEnabled = fragmentEnabled;
+ // if pump profile was enabled need to switch to another too
+ if (type == PluginBase.PUMP && !fragmentEnabled && this.fragmentProfileEnabled) {
+ setFragmentEnabled(PluginBase.PROFILE, false);
+ setFragmentVisible(PluginBase.PROFILE, false);
+ MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentEnabled(PluginBase.PROFILE, true);
+ MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentVisible(PluginBase.PROFILE, true);
+ }
}
@Override
@@ -152,7 +197,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
@Override
public boolean isInitialized() {
- return getDanaRPump().lastConnection.getTime() > 0;
+ return getDanaRPump().lastConnection.getTime() > 0 && getDanaRPump().isExtendedBolusEnabled;
}
// Pump interface
@@ -173,13 +218,46 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
}
@Override
- public void setNewBasalProfile(NSProfile profile) {
+ public int setNewBasalProfile(NSProfile profile) {
if (sExecutionService == null) {
log.error("setNewBasalProfile sExecutionService is null");
- return;
+ return FAILED;
}
- if (!sExecutionService.updateBasalsInPump(profile))
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.failedupdatebasalprofile));
+ if (!isInitialized()) {
+ log.error("setNewBasalProfile not initialized");
+ Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ return FAILED;
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
+ }
+ if (!sExecutionService.updateBasalsInPump(profile)) {
+ Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ return FAILED;
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
+ MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
+ return SUCCESS;
+ }
+ }
+
+ @Override
+ public boolean isThisProfileSet(NSProfile profile) {
+ if (!isInitialized())
+ return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
+ DanaRPump pump = getDanaRPump();
+ int basalValues = pump.basal48Enable ? 48 : 24;
+ int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
+ for (int h = 0; h < basalValues; h++) {
+ Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
+ Double profileValue = profile.getBasal(h * basalIncrement);
+ if (!pumpValue.equals(profileValue)) {
+ log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
+ return false;
+ }
+ }
+ return true;
}
@Override
@@ -585,6 +663,10 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
return sExecutionService != null && sExecutionService.isConnecting();
}
+ public static void doDisconnect(String from) {
+ if (sExecutionService != null) sExecutionService.disconnect(from);
+ }
+
@Override
public JSONObject getJSONStatus() {
if (getDanaRPump().lastConnection.getTime() + 5 * 60 * 1000L < new Date().getTime()) {
@@ -611,7 +693,8 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
extended.put("BaseBasalRate", getBaseBasalRate());
try {
extended.put("ActiveProfile", MainApp.getConfigBuilder().getActiveProfile().getProfile().getActiveProfile());
- } catch (Exception e) {}
+ } catch (Exception e) {
+ }
pump.put("battery", battery);
pump.put("status", status);
@@ -629,6 +712,11 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf
return getDanaRPump().serialNumber;
}
+ @Override
+ public PumpDescription getPumpDescription() {
+ return pumpDescription;
+ }
+
/**
* Constraint interface
*/
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPump.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPump.java
index f1e2a91f87..535b80a296 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPump.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPump.java
@@ -22,6 +22,11 @@ public class DanaRPump {
public static final int UNITS_MGDL = 0;
public static final int UNITS_MMOL = 1;
+ public static final int DELIVERY_PRIME = 0x01;
+ public static final int DELIVERY_STEP_BOLUS = 0x02;
+ public static final int DELIVERY_BASAL = 0x04;
+ public static final int DELIVERY_EXT_BOLUS = 0x08;
+
public static final String PROFILE_PREFIX = "DanaR-";
public Date lastConnection = new Date(0);
@@ -35,12 +40,25 @@ public class DanaRPump {
public int password = -1;
public Date pumpTime = new Date(0);
+ public static final int DOMESTIC_MODEL = 0x01;
+ public static final int EXPORT_MODEL = 0x03;
+ public int model;
+ public int protocol;
+ public int productCode;
+
+ public boolean isConfigUD;
+ public boolean isExtendedBolusEnabled;
+
+
// Status
public boolean pumpSuspended;
public boolean calculatorEnabled;
public double dailyTotalUnits;
public int maxDailyTotalUnits;
+ public double bolusStep;
+ public double basalStep;
+
public double iob;
public double reservoirRemainingUnits;
@@ -58,6 +76,7 @@ public class DanaRPump {
public int tempBasalTotalSec;
public Date tempBasalStart;
+ public boolean isDualBolusInProgress;
public boolean isExtendedInProgress;
public int extendedBolusMinutes;
public double extendedBolusAmount;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/Services/ExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/Services/ExecutionService.java
index e9151a53c3..66acc7292e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/Services/ExecutionService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/Services/ExecutionService.java
@@ -30,6 +30,7 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventAppExit;
+import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
@@ -58,8 +59,10 @@ import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStart;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStop;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStart;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTime;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingActiveProfile;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingBasal;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingMeal;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingGlucose;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingMaxValues;
import info.nightscout.androidaps.plugins.DanaR.comm.MsgSettingProfileRatios;
@@ -174,6 +177,11 @@ public class ExecutionService extends Service {
return connectionInProgress;
}
+ public void disconnect(String from) {
+ if (mSerialIOThread != null)
+ mSerialIOThread.disconnect(from);
+ }
+
public void connect(String from) {
if (danaRPump.password != -1 && danaRPump.password != SafeParse.stringToInt(SP.getString("danar_password", "-1"))) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
@@ -270,11 +278,11 @@ public class ExecutionService extends Service {
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
+ mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); // TODO: show it somewhere
mSerialIOThread.sendMessage(tempStatusMsg); // do this before statusBasic because here is temp duration
mSerialIOThread.sendMessage(exStatusMsg);
mSerialIOThread.sendMessage(statusMsg);
mSerialIOThread.sendMessage(statusBasicMsg);
- mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); // TODO: show it somewhere
if (danaRPump.isNewPump) {
mSerialIOThread.sendMessage(new MsgCheckValue());
@@ -303,10 +311,10 @@ public class ExecutionService extends Service {
}
Date now = new Date();
- if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime()) {
+ if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !((DanaRPlugin)MainApp.getSpecificPlugin(DanaRPlugin.class)).isInitialized()) {
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
- //0x3203
+ mSerialIOThread.sendMessage(new MsgSettingMeal());
mSerialIOThread.sendMessage(new MsgSettingBasal());
//0x3201
mSerialIOThread.sendMessage(new MsgSettingMaxValues());
@@ -315,11 +323,13 @@ public class ExecutionService extends Service {
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
+ mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
danaRPump.lastSettingsRead = now;
}
danaRPump.lastConnection = now;
MainApp.bus().post(new EventDanaRNewStatus());
+ MainApp.bus().post(new EventInitializationChanged());
} catch (Exception e) {
e.printStackTrace();
}
@@ -361,8 +371,8 @@ public class ExecutionService extends Service {
public boolean bolus(Double amount, int carbs, Treatment t) {
bolusingTreatment = t;
MsgBolusStart start = new MsgBolusStart(amount);
- MsgBolusProgress progress = new MsgBolusProgress(MainApp.bus(), amount, t);
- MsgBolusStop stop = new MsgBolusStop(MainApp.bus(), amount, t);
+ MsgBolusProgress progress = new MsgBolusProgress(amount, t); // initialize static variables
+ MsgBolusStop stop = new MsgBolusStop(amount, t);
connect("bolus");
if (!isConnected()) return false;
@@ -381,6 +391,11 @@ public class ExecutionService extends Service {
}
while (!stop.stopped && !start.failed) {
waitMsec(100);
+ if (progress.lastReceive != 0 && (new Date().getTime() - progress.lastReceive) > 5 * 1000L) { // if i didn't receive status for more than 5 sec expecting broken comm
+ stop.stopped = true;
+ stop.forced = true;
+ log.debug("Communication stopped");
+ }
}
waitMsec(300);
bolusingTreatment = null;
@@ -466,6 +481,7 @@ public class ExecutionService extends Service {
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
+ danaRPump.lastSettingsRead = new Date(0); // force read full settings
getPumpStatus();
return true;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageBase.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageBase.java
index 3fc4093119..1d97a02ba1 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageBase.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageBase.java
@@ -51,6 +51,15 @@ public class MessageBase {
AddParamByte((byte) (date.get(Calendar.MINUTE)));
}
+ public void AddParamDateTime(Date date) {
+ AddParamByte((byte) (date.getSeconds()));
+ AddParamByte((byte) (date.getMinutes()));
+ AddParamByte((byte) (date.getHours()));
+ AddParamByte((byte) (date.getDate()));
+ AddParamByte((byte) (date.getMonth() + 1));
+ AddParamByte((byte) (date.getYear() - 100));
+ }
+
public byte[] getRawMessageBytes() {
this.buffer[0] = (byte) 0x7E;
this.buffer[1] = (byte) 0x7E;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageHashTable.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageHashTable.java
index 5081bf81d6..221f7855e9 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageHashTable.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageHashTable.java
@@ -33,7 +33,7 @@ public class MessageHashTable {
put(new MsgSetTempBasalStop()); // 0x0403 CMD_PUMPSET_EXERCISE_STOP
put(new MsgSetExtendedBolusStop()); // 0x0406 CMD_PUMPSET_EXPANS_INS_STOP
put(new MsgSetExtendedBolusStart()); // 0x0407 CMD_PUMPSET_EXPANS_INS_S
- put(new MsgError()); // 0x0601 CMD_PUMPOWAY_SYSTEM_STATUS
+ put(new MsgError()); // 0x0601 CMD_PUMPOWAY_SYSTEM_STATUS
put(new MsgPCCommStart()); // 0x3001 CMD_CONNECT
put(new MsgPCCommStop()); // 0x3002 CMD_DISCONNECT
put(new MsgHistoryBolus()); // 0x3101 CMD_HISTORY_MEAL_INS
@@ -47,6 +47,7 @@ public class MessageHashTable {
put(new MsgHistoryBasalHour()); // 0x310A CMD_HISTORY_BASAL_HOUR
put(new MsgHistoryDone()); // 0x31F1 CMD_HISTORY_DONT_USED
put(new MsgSettingBasal()); // 0x3202 CMD_SETTING_V_BASAL_INS_I
+ put(new MsgSettingMeal()); // 0x3203 CMD_SETTING_V_MEAL_SETTING_I
put(new MsgSettingProfileRatios()); // 0x3204 CMD_SETTING_V_CCC_I
put(new MsgSettingMaxValues()); // 0x3205 CMD_SETTING_V_MAX_VALUE_I
put(new MsgSettingBasalProfileAll()); // 0x3206 CMD_SETTING_V_BASAL_PROFILE_ALL
@@ -56,6 +57,7 @@ public class MessageHashTable {
put(new MsgSettingUserOptions()); // 0x320B CMD_SETTING_V_USER_OPTIONS
put(new MsgSettingActiveProfile()); // 0x320C CMD_SETTING_V_PROFILE_NUMBER
put(new MsgSettingProfileRatiosAll()); // 0x320D CMD_SETTING_V_CIR_CF_VALUE
+ put(new MsgSetSingleBasalProfile()); // 0x3302 CMD_SETTING_BASAL_INS_S
put(new MsgSetBasalProfile()); // 0x3306 CMD_SETTING_BASAL_PROFILE_S
put(new MsgSetActivateBasalProfile()); // 0x330C CMD_SETTING_PROFILE_NUMBER_S
put(new MsgHistoryAllDone()); // 0x41F1 CMD_HISTORY_ALL_DONE
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageOriginalNames.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageOriginalNames.java
index 66f4ac71bf..5aba354812 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageOriginalNames.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MessageOriginalNames.java
@@ -62,7 +62,7 @@ public class MessageOriginalNames {
messageNames.put(0x320d, "CMD_SETTING_V_CIR_CF_VALUE");
messageNames.put(0x3301, "CMD_SETTING_MEAL_INS_S");
- messageNames.put(0x3302, "CMD_SETTING_Based_INS_S");
+ messageNames.put(0x3302, "CMD_SETTING_BASAL_INS_S");
messageNames.put(0x3303, "CMD_SETTING_MEAL_SETTING_S");
messageNames.put(0x3304, "CMD_SETTING_CCC_S");
messageNames.put(0x3305, "CMD_SETTING_MAX_VALUE_S");
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusProgress.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusProgress.java
index a5b7e68818..aa8a77f7bf 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusProgress.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusProgress.java
@@ -5,6 +5,8 @@ import com.squareup.otto.Bus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Date;
+
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
@@ -13,27 +15,28 @@ import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProg
public class MsgBolusProgress extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgBolusProgress.class);
- private static Bus bus = null;
private static Treatment t;
private static double amount;
+ public static long lastReceive = 0;
public int progress = -1;
public MsgBolusProgress() {
SetCommand(0x0202);
}
- public MsgBolusProgress(Bus bus, double amount, Treatment t) {
+ public MsgBolusProgress(double amount, Treatment t) {
this();
this.amount = amount;
this.t = t;
- this.bus = bus;
+ lastReceive = 0;
}
@Override
public void handleMessage(byte[] bytes) {
progress = intFromBuff(bytes, 0, 2);
+ lastReceive = new Date().getTime();
Double done = (amount * 100 - progress) / 100d;
t.insulin = done;
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
@@ -45,6 +48,6 @@ public class MsgBolusProgress extends MessageBase {
log.debug("Bolus remaining: " + progress + " delivered: " + done);
}
- bus.post(bolusingEvent);
+ MainApp.bus().post(bolusingEvent);
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStart.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStart.java
index faa66237f6..bf6af2841b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStart.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStart.java
@@ -23,6 +23,9 @@ public class MsgBolusStart extends MessageBase {
if (amount > BuildConfig.MAXBOLUS) amount = BuildConfig.MAXBOLUS;
AddParamInt((int) (amount * 100));
+
+ if (Config.logDanaMessageDetail)
+ log.debug("Bolus start : " + amount);
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStop.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStop.java
index f6c21adc78..68de53d50b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStop.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgBolusStop.java
@@ -14,7 +14,6 @@ public class MsgBolusStop extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgBolusStop.class);
private static Treatment t;
private static Double amount;
- private static Bus bus = null;
public static boolean stopped = false;
public static boolean forced = false;
@@ -24,9 +23,8 @@ public class MsgBolusStop extends MessageBase {
stopped = false;
}
- public MsgBolusStop(Bus bus, Double amount, Treatment t) {
+ public MsgBolusStop(Double amount, Treatment t) {
this();
- this.bus = bus;
this.t = t;
this.amount = amount;
forced = false;
@@ -43,6 +41,6 @@ public class MsgBolusStop extends MessageBase {
} else {
bolusingEvent.status = MainApp.sResources.getString(R.string.overview_bolusprogress_stoped);
}
- bus.post(bolusingEvent);
+ MainApp.bus().post(bolusingEvent);
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgCheckValue.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgCheckValue.java
index 954342a8a7..775de6eb29 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgCheckValue.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgCheckValue.java
@@ -4,6 +4,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
+import info.nightscout.utils.ToastUtils;
/**
* Created by mike on 30.06.2016.
@@ -17,15 +22,22 @@ public class MsgCheckValue extends MessageBase {
@Override
public void handleMessage(byte[] bytes) {
- int a = intFromBuff(bytes, 0, 1);
- int b = intFromBuff(bytes, 1, 1);
- if (a != 3 || b <= 0) {
- // another message will follow
- } else {
+ DanaRPump pump = DanaRPlugin.getDanaRPump();
+ pump.model = intFromBuff(bytes, 0, 1);
+ pump.protocol = intFromBuff(bytes, 1, 1);
+ pump.productCode = intFromBuff(bytes, 2, 1);
+ if (pump.model != DanaRPump.EXPORT_MODEL) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumpdriverselected), R.raw.error);
+ ((DanaRPlugin) MainApp.getSpecificPlugin(DanaRPlugin.class)).doDisconnect("Wrong Model");
+ log.debug("Wrong model selected");
+ }
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Model: " + String.format("%02X ", pump.model));
+ log.debug("Protocol: " + String.format("%02X ", pump.protocol));
+ log.debug("Product Code: " + String.format("%02X ", pump.productCode));
}
- if (Config.logDanaMessageDetail)
- log.debug("Response: " + String.format("%02X ", a) + String.format("%02X ", b));
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgError.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgError.java
index 020256d1c7..c416a8baad 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgError.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgError.java
@@ -31,10 +31,6 @@ public class MsgError extends MessageBase {
break;
case 5: // Occlusion
errorString = MainApp.sResources.getString(R.string.occlusion);
- EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
- MsgBolusStop.stopped = true;
- bolusingEvent.status = errorString;
- MainApp.bus().post(bolusingEvent);
break;
case 7: // Low Battery
errorString = MainApp.sResources.getString(R.string.lowbattery);
@@ -43,6 +39,13 @@ public class MsgError extends MessageBase {
errorString = MainApp.sResources.getString(R.string.batterydischarged);
break;
}
+
+ if (errorCode < 8) { // bolus delivering stopped
+ EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
+ MsgBolusStop.stopped = true;
+ bolusingEvent.status = errorString;
+ MainApp.bus().post(bolusingEvent);
+ }
if (Config.logDanaMessageDetail)
log.debug("Error detected: " + errorString);
MainApp.getConfigBuilder().uploadError(errorString);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBasic.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBasic.java
index 33a95554f7..6303391d4a 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBasic.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBasic.java
@@ -3,6 +3,10 @@ package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
+
public class MsgInitConnStatusBasic extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusBasic.class);
@@ -12,25 +16,51 @@ public class MsgInitConnStatusBasic extends MessageBase {
@Override
public void handleMessage(byte[] bytes) {
- int a = intFromBuff(bytes, 0, 1);
- int b = intFromBuff(bytes, 1, 1);
- int c = intFromBuff(bytes, 2, 1);
- int d = intFromBuff(bytes, 3, 1);
- int e = intFromBuff(bytes, 4, 1);
- int f = intFromBuff(bytes, 5, 1);
- int g = intFromBuff(bytes, 6, 1);
- int h = intFromBuff(bytes, 7, 1);
- int i = intFromBuff(bytes, 8, 1);
- int j = intFromBuff(bytes, 9, 1);
- int k = intFromBuff(bytes, 10, 1);
- int l = intFromBuff(bytes, 11, 1);
- int m = intFromBuff(bytes, 12, 1);
- int n = intFromBuff(bytes, 13, 1);
- int o;
+ if (bytes.length - 10 < 21) {
+ return;
+ }
+ DanaRPump pump = DanaRPlugin.getDanaRPump();
+ pump.pumpSuspended = intFromBuff(bytes, 0, 1) == 1;
+ pump.calculatorEnabled = intFromBuff(bytes, 1, 1) == 1;
+ pump.dailyTotalUnits = intFromBuff(bytes, 2, 3) / 750d;
+ pump.maxDailyTotalUnits = intFromBuff(bytes, 5, 2) / 100;
+ pump.reservoirRemainingUnits = intFromBuff(bytes, 7, 3) / 750d;
+ pump.bolusBlocked = intFromBuff(bytes, 10, 1) == 1;
+ pump.currentBasal = intFromBuff(bytes, 11, 2) / 100d;
+ pump.tempBasalPercent = intFromBuff(bytes, 13, 1);
+ pump.isExtendedInProgress = intFromBuff(bytes, 14, 1) == 1;
+ pump.isTempBasalInProgress = intFromBuff(bytes, 15, 1) == 1;
+ int statusBasalUDOption = intFromBuff(bytes, 16, 1);
+ pump.isDualBolusInProgress = intFromBuff(bytes, 17, 1) == 1;
+ double extendedBolusRate = intFromBuff(bytes, 18, 2) / 100d;
+ pump.batteryRemaining = intFromBuff(bytes, 20, 1);
try {
- o = intFromBuff(bytes, 21, 1);
- } catch (Exception ex) {
- o = 0;
+ int bolusConfig = intFromBuff(bytes, 21, 1);
+ boolean deliveryPrime = (bolusConfig & DanaRPump.DELIVERY_PRIME) != 0;
+ boolean deliveryStepBolus = (bolusConfig & DanaRPump.DELIVERY_STEP_BOLUS) != 0;
+ boolean deliveryBasal = (bolusConfig & DanaRPump.DELIVERY_BASAL) != 0;
+ boolean deliveryExtBolus = (bolusConfig & DanaRPump.DELIVERY_EXT_BOLUS) != 0;
+ log.debug("Delivery prime: " + deliveryPrime);
+ log.debug("Delivery step bolus: " + deliveryStepBolus);
+ log.debug("Delivery basal: " + deliveryBasal);
+ log.debug("Delivery ext bolus: " + deliveryExtBolus);
+ } catch (Exception e) {
+ }
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Pump suspended: " + pump.pumpSuspended);
+ log.debug("Calculator enabled: " + pump.calculatorEnabled);
+ log.debug("Daily total units: " + pump.dailyTotalUnits);
+ log.debug("Max daily total units: " + pump.maxDailyTotalUnits);
+ log.debug("Reservoir remaining units: " + pump.reservoirRemainingUnits);
+ log.debug("Bolus blocked: " + pump.bolusBlocked);
+ log.debug("Current basal: " + pump.currentBasal);
+ log.debug("Current temp basal percent: " + pump.tempBasalPercent);
+ log.debug("Is extended bolus running: " + pump.isExtendedInProgress);
+ log.debug("statusBasalUDOption: " + statusBasalUDOption);
+ log.debug("Is dual bolus running: " + pump.isDualBolusInProgress);
+ log.debug("Extended bolus rate: " + extendedBolusRate);
+ log.debug("Battery remaining: " + pump.batteryRemaining);
}
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBolus.java
index 3a3ce99349..36705c49ec 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBolus.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusBolus.java
@@ -3,6 +3,15 @@ package info.nightscout.androidaps.plugins.DanaR.comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+
/**
* Created by mike on 28.05.2016.
*/
@@ -15,10 +24,28 @@ public class MsgInitConnStatusBolus extends MessageBase {
@Override
public void handleMessage(byte[] bytes) {
- int a1 = intFromBuff(bytes, 0, 1);
- int a2 = intFromBuff(bytes, 1, 1);
- int c = intFromBuff(bytes, 8, 2);
- int d = c / 100;
- int e = intFromBuff(bytes, 10, 2);
+ if (bytes.length - 10 > 12) {
+ return;
+ }
+ DanaRPump pump = DanaRPlugin.getDanaRPump();
+ int bolusConfig = intFromBuff(bytes, 0, 1);
+ pump.isExtendedBolusEnabled = (bolusConfig & 0x01) != 0;
+
+ pump.bolusStep = intFromBuff(bytes, 1, 1) / 100d;
+ pump.maxBolus = intFromBuff(bytes, 2, 2) / 100d;
+ //int bolusRate = intFromBuff(bytes, 4, 8);
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Is Extended bolus enabled: " + pump.isExtendedBolusEnabled);
+ log.debug("Bolus increment: " + pump.bolusStep);
+ log.debug("Bolus max: " + pump.maxBolus);
+ }
+
+ if (!pump.isExtendedBolusEnabled) {
+ Notification notification = new Notification(Notification.EXTENDED_BOLUS_DISABLED, MainApp.sResources.getString(R.string.danar_enableextendedbolus), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.EXTENDED_BOLUS_DISABLED));
+ }
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusOption.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusOption.java
index b8049c23ee..2b424a949b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusOption.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusOption.java
@@ -18,15 +18,15 @@ public class MsgInitConnStatusOption extends MessageBase {
@Override
public void handleMessage(byte[] bytes) {
- int a = intFromBuff(bytes, 0, 1);
- int b = intFromBuff(bytes, 1, 1);
- int c = intFromBuff(bytes, 2, 1);
- int d = intFromBuff(bytes, 3, 1);
- int e = intFromBuff(bytes, 4, 1);
- int f = intFromBuff(bytes, 5, 1);
- int g = intFromBuff(bytes, 6, 1);
- int h = intFromBuff(bytes, 7, 1);
- int i = intFromBuff(bytes, 8, 1);
+ int status1224Clock = intFromBuff(bytes, 0, 1);
+ int isStatusButtonScroll = intFromBuff(bytes, 1, 1);
+ int soundVibration = intFromBuff(bytes, 2, 1);
+ int glucoseUnit = intFromBuff(bytes, 3, 1);
+ int lcdTimeout = intFromBuff(bytes, 4, 1);
+ int backlightgTimeout = intFromBuff(bytes, 5, 1);
+ int languageOption = intFromBuff(bytes, 6, 1);
+ int lowReservoirAlarmBoundary = intFromBuff(bytes, 7, 1);
+ //int none = intFromBuff(bytes, 8, 1);
if (bytes.length >= 21) {
DanaRPlugin.getDanaRPump().password = intFromBuff(bytes, 9, 2) ^ 0x3463;
if (Config.logDanaMessageDetail)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusTime.java
index 7e6b1a7652..d1d5652f4d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusTime.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgInitConnStatusTime.java
@@ -6,6 +6,14 @@ import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.events.EventRefreshGui;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.utils.ToastUtils;
public class MsgInitConnStatusTime extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusTime.class);
@@ -16,9 +24,32 @@ public class MsgInitConnStatusTime extends MessageBase {
@Override
public void handleMessage(byte[] bytes) {
- Date time = dateTimeSecFromBuff(bytes, 0);
+ if (bytes.length - 10 > 7) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(),MainApp.sResources.getString(R.string.wrongpumpdriverselected), R.raw.error);
+ ((DanaRPlugin) MainApp.getSpecificPlugin(DanaRPlugin.class)).doDisconnect("Wrong Model");
+ log.debug("Wrong model selected. Switching to Korean DanaR");
+ ((DanaRKoreanPlugin)MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).setFragmentEnabled(PluginBase.PUMP, true);
+ ((DanaRKoreanPlugin)MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).setFragmentVisible(PluginBase.PUMP, true);
+ ((DanaRPlugin)MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentEnabled(PluginBase.PUMP, false);
+ ((DanaRPlugin)MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentVisible(PluginBase.PUMP, false);
- if (Config.logDanaMessageDetail)
+ //If profile coming from pump, switch it as well
+ if(MainApp.getSpecificPlugin(DanaRPlugin.class).isEnabled(PluginBase.PROFILE)){
+ (MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentEnabled(PluginBase.PROFILE, false);
+ (MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).setFragmentEnabled(PluginBase.PROFILE, true);
+ }
+
+ MainApp.getConfigBuilder().storeSettings();
+ MainApp.bus().post(new EventRefreshGui(false));
+ return;
+ }
+
+ Date time = dateTimeSecFromBuff(bytes, 0);
+ int versionCode = intFromBuff(bytes, 6, 1);
+
+ if (Config.logDanaMessageDetail) {
log.debug("Pump time: " + time);
+ log.debug("Version code: " + versionCode);
+ }
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetBasalProfile.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetBasalProfile.java
index 97eb3844da..9acd5ec824 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetBasalProfile.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetBasalProfile.java
@@ -4,6 +4,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
public class MsgSetBasalProfile extends MessageBase {
private static Logger log = LoggerFactory.getLogger(MsgSetBasalProfile.class);
@@ -29,9 +33,13 @@ public class MsgSetBasalProfile extends MessageBase {
if (result != 1) {
failed = true;
log.debug("Set basal profile result: " + result + " FAILED!!!");
+ Notification reportFail = new Notification(Notification.PROFILE_SET_FAILED, MainApp.sResources.getString(R.string.profile_set_failed), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(reportFail));
} else {
if (Config.logDanaMessageDetail)
log.debug("Set basal profile result: " + result);
+ Notification reportOK = new Notification(Notification.PROFILE_SET_OK, MainApp.sResources.getString(R.string.profile_set_ok), Notification.INFO, 60);
+ MainApp.bus().post(new EventNewNotification(reportOK));
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetSingleBasalProfile.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetSingleBasalProfile.java
new file mode 100644
index 0000000000..4e57712b04
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetSingleBasalProfile.java
@@ -0,0 +1,48 @@
+package info.nightscout.androidaps.plugins.DanaR.comm;
+
+import com.j256.ormlite.stmt.query.Not;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+
+public class MsgSetSingleBasalProfile extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSetSingleBasalProfile.class);
+
+ public MsgSetSingleBasalProfile() {
+ SetCommand(0x3302);
+ }
+
+ // index 0-3
+ public MsgSetSingleBasalProfile(double[] values) {
+ this();
+ for (Integer i = 0; i < 24; i++) {
+ AddParamInt((int) (values[i] * 100));
+ }
+ if (Config.logDanaMessageDetail)
+ log.debug("Set basal profile");
+ }
+
+ @Override
+ public void handleMessage(byte[] bytes) {
+ int result = intFromBuff(bytes, 0, 1);
+ if (result != 1) {
+ failed = true;
+ log.debug("Set basal profile result: " + result + " FAILED!!!");
+ Notification reportFail = new Notification(Notification.PROFILE_SET_FAILED, MainApp.sResources.getString(R.string.profile_set_failed), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(reportFail));
+ } else {
+ if (Config.logDanaMessageDetail)
+ log.debug("Set basal profile result: " + result);
+ Notification reportOK = new Notification(Notification.PROFILE_SET_OK, MainApp.sResources.getString(R.string.profile_set_ok), Notification.INFO, 60);
+ MainApp.bus().post(new EventNewNotification(reportOK));
+ }
+ }
+
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetTime.java
new file mode 100644
index 0000000000..827958608c
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSetTime.java
@@ -0,0 +1,28 @@
+package info.nightscout.androidaps.plugins.DanaR.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+import info.nightscout.androidaps.Config;
+
+/**
+ * Created by mike on 09.12.2016.
+ */
+
+public class MsgSetTime extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSetTime.class);
+
+ public MsgSetTime(Date time) {
+ SetCommand(0x330a);
+ AddParamDateTime(time);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ int result = intFromBuff(bytes, 0, 1);
+
+ if (Config.logDanaMessageDetail)
+ log.debug("Result: " + result);
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSettingMeal.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSettingMeal.java
new file mode 100644
index 0000000000..a588479869
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSettingMeal.java
@@ -0,0 +1,40 @@
+package info.nightscout.androidaps.plugins.DanaR.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
+
+/**
+ * Created by mike on 13.12.2016.
+ */
+
+public class MsgSettingMeal extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingMeal.class);
+
+ public MsgSettingMeal() {
+ SetCommand(0x3203);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRPump pump = DanaRPlugin.getDanaRPump();
+ pump.basalStep = intFromBuff(bytes, 0, 1) / 100d;
+ pump.bolusStep = intFromBuff(bytes, 1, 1) / 100d;
+ boolean bolusEnabled = intFromBuff(bytes, 2, 1) == 1;
+ int melodyTime = intFromBuff(bytes, 3, 1);
+ int blockTime = intFromBuff(bytes, 4, 1);
+ pump.isConfigUD = intFromBuff(bytes, 5, 1) == 1;
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Basal step: " + pump.basalStep);
+ log.debug("Bolus step: " + pump.bolusStep);
+ log.debug("Bolus enabled: " + bolusEnabled);
+ log.debug("Melody time: " + melodyTime);
+ log.debug("Block time: " + blockTime);
+ log.debug("Is Config U/d: " + pump.isConfigUD);
+ }
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSettingShippingInfo.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSettingShippingInfo.java
index 81b1a11eb6..9b71f0060b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSettingShippingInfo.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgSettingShippingInfo.java
@@ -7,6 +7,7 @@ import java.util.Date;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
/**
* Created by mike on 05.07.2016.
@@ -19,17 +20,18 @@ public class MsgSettingShippingInfo extends MessageBase {
}
public void handleMessage(byte[] bytes) {
- DanaRPlugin.getDanaRPump().serialNumber = stringFromBuff(bytes, 0, 10);
- DanaRPlugin.getDanaRPump().shippingDate = dateFromBuff(bytes, 10);
- DanaRPlugin.getDanaRPump().shippingCountry = asciiStringFromBuff(bytes, 13, 3);
- if (DanaRPlugin.getDanaRPump().shippingDate.getTime() > new Date(116, 4, 1).getTime()) {
- DanaRPlugin.getDanaRPump().isNewPump = true;
+ DanaRPump pump = DanaRPlugin.getDanaRPump();
+ pump.serialNumber = stringFromBuff(bytes, 0, 10);
+ pump.shippingDate = dateFromBuff(bytes, 10);
+ pump.shippingCountry = asciiStringFromBuff(bytes, 13, 3);
+ if (pump.shippingDate.getTime() > new Date(116, 4, 1).getTime()) {
+ pump.isNewPump = true;
} else
- DanaRPlugin.getDanaRPump().isNewPump = false;
+ pump.isNewPump = false;
if (Config.logDanaMessageDetail) {
- log.debug("Serial number: " + DanaRPlugin.getDanaRPump().serialNumber);
- log.debug("Shipping date: " + DanaRPlugin.getDanaRPump().shippingDate);
- log.debug("Shipping country: " + DanaRPlugin.getDanaRPump().shippingCountry);
+ log.debug("Serial number: " + pump.serialNumber);
+ log.debug("Shipping date: " + pump.shippingDate);
+ log.debug("Shipping country: " + pump.shippingCountry);
}
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgStatusBasic.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgStatusBasic.java
index 5422c4318b..d79dd6aea8 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgStatusBasic.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/comm/MsgStatusBasic.java
@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
public class MsgStatusBasic extends MessageBase {
@@ -15,41 +16,31 @@ public class MsgStatusBasic extends MessageBase {
}
public void handleMessage(byte[] bytes) {
- boolean pumpSuspended = intFromBuff(bytes, 0, 1) == 1;
- boolean calculatorEnabled = intFromBuff(bytes, 1, 1) == 1;
- double dailyTotalUnits = intFromBuff(bytes, 2, 3) / 750d;
- int maxDailyTotalUnits = intFromBuff(bytes, 5, 2) / 100;
- double reservoirRemainingUnits = intFromBuff(bytes, 7, 3) / 750d;
- boolean bolusBlocked = intFromBuff(bytes, 10, 1) == 1;
- double currentBasal = intFromBuff(bytes, 11, 2) / 100d;
- int tempBasalPercent = intFromBuff(bytes, 13, 1);
- boolean isExtendedInProgress = intFromBuff(bytes, 14, 1) == 1;
- boolean isTempBasalInProgress = intFromBuff(bytes, 15, 1) == 1;
- int batteryRemaining = intFromBuff(bytes, 20, 1);
+ DanaRPump pump = DanaRPlugin.getDanaRPump();
- DanaRPlugin.getDanaRPump().pumpSuspended = pumpSuspended;
- DanaRPlugin.getDanaRPump().calculatorEnabled = calculatorEnabled;
- DanaRPlugin.getDanaRPump().dailyTotalUnits = dailyTotalUnits;
- DanaRPlugin.getDanaRPump().maxDailyTotalUnits = maxDailyTotalUnits;
- DanaRPlugin.getDanaRPump().reservoirRemainingUnits = reservoirRemainingUnits;
- DanaRPlugin.getDanaRPump().bolusBlocked = bolusBlocked;
- DanaRPlugin.getDanaRPump().currentBasal = currentBasal;
- DanaRPlugin.getDanaRPump().tempBasalPercent = tempBasalPercent;
- DanaRPlugin.getDanaRPump().isExtendedInProgress = isExtendedInProgress;
- DanaRPlugin.getDanaRPump().isTempBasalInProgress = isTempBasalInProgress;
- DanaRPlugin.getDanaRPump().batteryRemaining = batteryRemaining;
+ pump.pumpSuspended = intFromBuff(bytes, 0, 1) == 1;
+ pump.calculatorEnabled = intFromBuff(bytes, 1, 1) == 1;
+ pump.dailyTotalUnits = intFromBuff(bytes, 2, 3) / 750d;
+ pump.maxDailyTotalUnits = intFromBuff(bytes, 5, 2) / 100;
+ pump.reservoirRemainingUnits = intFromBuff(bytes, 7, 3) / 750d;
+ pump.bolusBlocked = intFromBuff(bytes, 10, 1) == 1;
+ pump.currentBasal = intFromBuff(bytes, 11, 2) / 100d;
+ pump.tempBasalPercent = intFromBuff(bytes, 13, 1);
+ pump.isExtendedInProgress = intFromBuff(bytes, 14, 1) == 1;
+ pump.isTempBasalInProgress = intFromBuff(bytes, 15, 1) == 1;
+ pump.batteryRemaining = intFromBuff(bytes, 20, 1);
if (Config.logDanaMessageDetail) {
- log.debug("Pump suspended: " + pumpSuspended);
- log.debug("Calculator enabled: " + calculatorEnabled);
- log.debug("Daily total units: " + dailyTotalUnits);
- log.debug("Max daily total units: " + maxDailyTotalUnits);
- log.debug("Reservoir remaining units: " + reservoirRemainingUnits);
- log.debug("Bolus blocked: " + bolusBlocked);
- log.debug("Current basal: " + currentBasal);
- log.debug("Current temp basal percent: " + tempBasalPercent);
- log.debug("Is extended bolus running: " + isExtendedInProgress);
- log.debug("Is temp basal running: " + isTempBasalInProgress);
+ log.debug("Pump suspended: " + pump.pumpSuspended);
+ log.debug("Calculator enabled: " + pump.calculatorEnabled);
+ log.debug("Daily total units: " + pump.dailyTotalUnits);
+ log.debug("Max daily total units: " + pump.maxDailyTotalUnits);
+ log.debug("Reservoir remaining units: " + pump.reservoirRemainingUnits);
+ log.debug("Bolus blocked: " + pump.bolusBlocked);
+ log.debug("Current basal: " + pump.currentBasal);
+ log.debug("Current temp basal percent: " + pump.tempBasalPercent);
+ log.debug("Is extended bolus running: " + pump.isExtendedInProgress);
+ log.debug("Is temp basal running: " + pump.isTempBasalInProgress);
}
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanFragment.java
new file mode 100644
index 0000000000..77e320c3a9
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanFragment.java
@@ -0,0 +1,234 @@
+package info.nightscout.androidaps.plugins.DanaRKorean;
+
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.squareup.otto.Subscribe;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.events.EventPreferenceChange;
+import info.nightscout.androidaps.events.EventTempBasalChange;
+import info.nightscout.androidaps.interfaces.FragmentBase;
+import info.nightscout.androidaps.plugins.DanaR.Dialogs.ProfileViewDialog;
+import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus;
+import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRNewStatus;
+import info.nightscout.androidaps.plugins.DanaRKorean.History.DanaRHistoryActivity;
+import info.nightscout.utils.DecimalFormatter;
+import info.nightscout.utils.SetWarnColor;
+
+public class DanaRKoreanFragment extends Fragment implements FragmentBase {
+ private static Logger log = LoggerFactory.getLogger(DanaRKoreanFragment.class);
+
+ private static DanaRKoreanPlugin danaRKoreanPlugin = new DanaRKoreanPlugin();
+
+ public static DanaRKoreanPlugin getPlugin() {
+ return danaRKoreanPlugin;
+ }
+
+ private static Handler sHandler;
+ private static HandlerThread sHandlerThread;
+
+ private Handler loopHandler = new Handler();
+ private Runnable refreshLoop = null;
+
+ TextView lastConnectionView;
+ TextView btConnectionView;
+ TextView lastBolusView;
+ TextView dailyUnitsView;
+ TextView basaBasalRateView;
+ TextView tempBasalView;
+ TextView extendedBolusView;
+ TextView batteryView;
+ TextView reservoirView;
+ TextView iobView;
+ Button viewProfileButton;
+ Button historyButton;
+
+ public DanaRKoreanFragment() {
+ if (sHandlerThread == null) {
+ sHandlerThread = new HandlerThread(DanaRKoreanFragment.class.getSimpleName());
+ sHandlerThread.start();
+ sHandler = new Handler(sHandlerThread.getLooper());
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (refreshLoop == null) {
+ refreshLoop = new Runnable() {
+ @Override
+ public void run() {
+ updateGUI();
+ loopHandler.postDelayed(refreshLoop, 60 * 1000L);
+ }
+ };
+ loopHandler.postDelayed(refreshLoop, 60 * 1000L);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.danar_fragment, container, false);
+ btConnectionView = (TextView) view.findViewById(R.id.danar_btconnection);
+ lastConnectionView = (TextView) view.findViewById(R.id.danar_lastconnection);
+ lastBolusView = (TextView) view.findViewById(R.id.danar_lastbolus);
+ dailyUnitsView = (TextView) view.findViewById(R.id.danar_dailyunits);
+ basaBasalRateView = (TextView) view.findViewById(R.id.danar_basabasalrate);
+ tempBasalView = (TextView) view.findViewById(R.id.danar_tempbasal);
+ extendedBolusView = (TextView) view.findViewById(R.id.danar_extendedbolus);
+ batteryView = (TextView) view.findViewById(R.id.danar_battery);
+ reservoirView = (TextView) view.findViewById(R.id.danar_reservoir);
+ iobView = (TextView) view.findViewById(R.id.danar_iob);
+ viewProfileButton = (Button) view.findViewById(R.id.danar_viewprofile);
+ historyButton = (Button) view.findViewById(R.id.danar_history);
+
+ viewProfileButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FragmentManager manager = getFragmentManager();
+ ProfileViewDialog profileViewDialog = new ProfileViewDialog();
+ profileViewDialog.show(manager, "ProfileViewDialog");
+ }
+ });
+
+ historyButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
+ }
+ });
+
+ btConnectionView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ sHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ DanaRKoreanPlugin.sExecutionService.connect("Connect request from GUI");
+ }
+ }
+ );
+ }
+ });
+
+ updateGUI();
+ return view;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ MainApp.bus().unregister(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ MainApp.bus().register(this);
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventDanaRConnectionStatus c) {
+ Activity activity = getActivity();
+ if (activity != null) {
+ activity.runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (c.sStatus == EventDanaRConnectionStatus.CONNECTING)
+ btConnectionView.setText("{fa-bluetooth-b spin} " + c.sSecondsElapsed + "s");
+ else if (c.sStatus == EventDanaRConnectionStatus.CONNECTED)
+ btConnectionView.setText("{fa-bluetooth}");
+ else
+ btConnectionView.setText("{fa-bluetooth-b}");
+ }
+ }
+ );
+ }
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventDanaRNewStatus s) {
+ updateGUI();
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventTempBasalChange s) {
+ updateGUI();
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventPreferenceChange s) {
+ updateGUI();
+ }
+
+ // GUI functions
+ private void updateGUI() {
+ final DateFormat formatTime = DateFormat.getTimeInstance(DateFormat.SHORT);
+
+ Activity activity = getActivity();
+ if (activity != null && basaBasalRateView != null)
+ activity.runOnUiThread(new Runnable() {
+ @SuppressLint("SetTextI18n")
+ @Override
+ public void run() {
+
+ if (DanaRKoreanPlugin.getDanaRPump().lastConnection.getTime() != 0) {
+ Long agoMsec = new Date().getTime() - DanaRKoreanPlugin.getDanaRPump().lastConnection.getTime();
+ int agoMin = (int) (agoMsec / 60d / 1000d);
+ lastConnectionView.setText(formatTime.format(DanaRKoreanPlugin.getDanaRPump().lastConnection) + " (" + agoMin + " " + MainApp.sResources.getString(R.string.minago) + ")");
+ SetWarnColor.setColor(lastConnectionView, agoMin, 16d, 31d);
+ }
+// if (DanaRKoreanPlugin.getDanaRPump().lastBolusTime.getTime() != 0) {
+// Long agoMsec = new Date().getTime() - DanaRKoreanPlugin.getDanaRPump().lastBolusTime.getTime();
+// double agoHours = agoMsec / 60d / 60d / 1000d;
+// if (agoHours < 6) // max 6h back
+// lastBolusView.setText(formatTime.format(DanaRKoreanPlugin.getDanaRPump().lastBolusTime) + " (" + DecimalFormatter.to1Decimal(agoHours) + " " + getString(R.string.hoursago) + ") " + DecimalFormatter.to2Decimal(danaRKoreanPlugin.getDanaRPump().lastBolusAmount) + " U");
+// else lastBolusView.setText("");
+// }
+
+ dailyUnitsView.setText(DecimalFormatter.to0Decimal(DanaRKoreanPlugin.getDanaRPump().dailyTotalUnits) + " / " + DanaRKoreanPlugin.getDanaRPump().maxDailyTotalUnits + " U");
+ SetWarnColor.setColor(dailyUnitsView, DanaRKoreanPlugin.getDanaRPump().dailyTotalUnits, DanaRKoreanPlugin.getDanaRPump().maxDailyTotalUnits * 0.75d, DanaRKoreanPlugin.getDanaRPump().maxDailyTotalUnits * 0.9d);
+ basaBasalRateView.setText("( " + (DanaRKoreanPlugin.getDanaRPump().activeProfile + 1) + " ) " + DecimalFormatter.to2Decimal(danaRKoreanPlugin.getBaseBasalRate()) + " U/h");
+ if (danaRKoreanPlugin.isRealTempBasalInProgress()) {
+ tempBasalView.setText(danaRKoreanPlugin.getRealTempBasal().toString());
+ } else {
+ tempBasalView.setText("");
+ }
+ if (danaRKoreanPlugin.isExtendedBoluslInProgress()) {
+ extendedBolusView.setText(danaRKoreanPlugin.getExtendedBolus().toString());
+ } else {
+ extendedBolusView.setText("");
+ }
+ reservoirView.setText(DecimalFormatter.to0Decimal(DanaRKoreanPlugin.getDanaRPump().reservoirRemainingUnits) + " / 300 U");
+ SetWarnColor.setColorInverse(reservoirView, DanaRKoreanPlugin.getDanaRPump().reservoirRemainingUnits, 50d, 20d);
+ batteryView.setText("{fa-battery-" + (DanaRKoreanPlugin.getDanaRPump().batteryRemaining / 25) + "}");
+ SetWarnColor.setColorInverse(batteryView, DanaRKoreanPlugin.getDanaRPump().batteryRemaining, 51d, 26d);
+ iobView.setText(DanaRKoreanPlugin.getDanaRPump().iob + " U");
+ }
+ });
+
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPlugin.java
new file mode 100644
index 0000000000..e4a3d06959
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPlugin.java
@@ -0,0 +1,826 @@
+package info.nightscout.androidaps.plugins.DanaRKorean;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
+
+import com.squareup.otto.Subscribe;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.Objects;
+
+import info.nightscout.androidaps.BuildConfig;
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.Constants;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.db.TempBasal;
+import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.events.EventAppExit;
+import info.nightscout.androidaps.events.EventPreferenceChange;
+import info.nightscout.androidaps.interfaces.ConstraintsInterface;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.ProfileInterface;
+import info.nightscout.androidaps.interfaces.PumpDescription;
+import info.nightscout.androidaps.interfaces.PumpInterface;
+import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.Services.ExecutionService;
+import info.nightscout.androidaps.plugins.NSProfile.NSProfilePlugin;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+import info.nightscout.client.data.NSProfile;
+import info.nightscout.utils.DateUtil;
+import info.nightscout.utils.DecimalFormatter;
+import info.nightscout.utils.Round;
+
+/**
+ * Created by mike on 05.08.2016.
+ */
+public class DanaRKoreanPlugin implements PluginBase, PumpInterface, ConstraintsInterface, ProfileInterface {
+ private static Logger log = LoggerFactory.getLogger(DanaRKoreanPlugin.class);
+
+ @Override
+ public String getFragmentClass() {
+ return DanaRKoreanFragment.class.getName();
+ }
+
+ static boolean fragmentPumpEnabled = true;
+ static boolean fragmentProfileEnabled = true;
+ static boolean fragmentPumpVisible = true;
+
+ public static ExecutionService sExecutionService;
+
+
+ private static DanaRKoreanPump sDanaRKoreanPump = new DanaRKoreanPump();
+ private static boolean useExtendedBoluses = false;
+
+ private PumpDescription pumpDescription = new PumpDescription();
+
+ public static DanaRKoreanPump getDanaRPump() {
+ return sDanaRKoreanPump;
+ }
+
+ public DanaRKoreanPlugin() {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+ useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false);
+
+ Context context = MainApp.instance().getApplicationContext();
+ Intent intent = new Intent(context, ExecutionService.class);
+ context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ MainApp.bus().register(this);
+
+ pumpDescription.isBolusCapable = true; // TODO: use description in setTempBasalAbsolute
+ pumpDescription.bolusStep = 0.1d;
+
+ pumpDescription.isExtendedBolusCapable = true;
+ pumpDescription.extendedBolusStep = 0.1d;
+
+ pumpDescription.isTempBasalCapable = true;
+ pumpDescription.lowTempBasalStyle = PumpDescription.PERCENT;
+ pumpDescription.highTempBasalStyle = useExtendedBoluses ? PumpDescription.EXTENDED : PumpDescription.PERCENT;
+ pumpDescription.maxHighTempPercent = 200;
+ pumpDescription.maxHighTempAbsolute = 0;
+ pumpDescription.lowTempPercentStep = 10;
+ pumpDescription.lowTempAbsoluteStep = 0;
+ pumpDescription.lowTempPercentDuration = 60;
+ pumpDescription.lowTempAbsoluteDuration = 60;
+ pumpDescription.highTempPercentStep = 10;
+ pumpDescription.highTempAbsoluteStep = 0.05d;
+ pumpDescription.highTempPercentDuration = 60;
+ pumpDescription.highTempAbsoluteDuration = 30;
+
+ pumpDescription.isSetBasalProfileCapable = true;
+ pumpDescription.basalStep = 0.01d;
+ pumpDescription.basalMinimumRate = 0.1d;
+
+ pumpDescription.isRefillingCapable = true;
+ }
+
+ ServiceConnection mConnection = new ServiceConnection() {
+
+ public void onServiceDisconnected(ComponentName name) {
+ log.debug("Service is disconnected");
+ sExecutionService = null;
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ log.debug("Service is connected");
+ ExecutionService.LocalBinder mLocalBinder = (ExecutionService.LocalBinder) service;
+ sExecutionService = mLocalBinder.getServiceInstance();
+ }
+ };
+
+ @SuppressWarnings("UnusedParameters")
+ @Subscribe
+ public void onStatusEvent(final EventAppExit e) {
+ MainApp.instance().getApplicationContext().unbindService(mConnection);
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventPreferenceChange s) {
+ if (isEnabled(PUMP)) {
+ boolean previousValue = useExtendedBoluses;
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+ useExtendedBoluses = sharedPreferences.getBoolean("danar_useextended", false);
+
+ pumpDescription.highTempBasalStyle = useExtendedBoluses ? PumpDescription.EXTENDED : PumpDescription.PERCENT;
+
+ if (useExtendedBoluses != previousValue && isExtendedBoluslInProgress()) {
+ sExecutionService.extendedBolusStop();
+ }
+ }
+ }
+
+ // Plugin base interface
+ @Override
+ public int getType() {
+ return PluginBase.PUMP;
+ }
+
+ @Override
+ public String getName() {
+ return MainApp.instance().getString(R.string.danarkoreanpump);
+ }
+
+ @Override
+ public boolean isEnabled(int type) {
+ if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled;
+ else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
+ else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
+ return false;
+ }
+
+ @Override
+ public boolean isVisibleInTabs(int type) {
+ if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
+ else if (type == PluginBase.PUMP) return fragmentPumpVisible;
+ return false;
+ }
+
+ @Override
+ public boolean canBeHidden(int type) {
+ return true;
+ }
+
+ @Override
+ public void setFragmentEnabled(int type, boolean fragmentEnabled) {
+ if (type == PluginBase.PROFILE)
+ this.fragmentProfileEnabled = fragmentEnabled;
+ else if (type == PluginBase.PUMP)
+ this.fragmentPumpEnabled = fragmentEnabled;
+ // if pump profile was enabled need to switch to another too
+ if (type == PluginBase.PUMP && !fragmentEnabled && this.fragmentProfileEnabled) {
+ setFragmentEnabled(PluginBase.PROFILE, false);
+ setFragmentVisible(PluginBase.PROFILE, false);
+ MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentEnabled(PluginBase.PROFILE, true);
+ MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentVisible(PluginBase.PROFILE, true);
+ }
+ }
+
+ @Override
+ public void setFragmentVisible(int type, boolean fragmentVisible) {
+ if (type == PluginBase.PUMP)
+ this.fragmentPumpVisible = fragmentVisible;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return getDanaRPump().lastConnection.getTime() > 0 && !getDanaRPump().isConfigUD && !getDanaRPump().isEasyModeEnabled && getDanaRPump().isExtendedBolusEnabled;
+ }
+
+ // Pump interface
+ @Override
+ public boolean isTempBasalInProgress() {
+ if (getRealTempBasal() != null) return true;
+ if (getExtendedBolus() != null && useExtendedBoluses) return true;
+ return false;
+ }
+
+ public boolean isRealTempBasalInProgress() {
+ return getRealTempBasal() != null; //TODO: crosscheck here
+ }
+
+ @Override
+ public boolean isExtendedBoluslInProgress() {
+ return getExtendedBolus() != null; //TODO: crosscheck here
+ }
+
+ @Override
+ public int setNewBasalProfile(NSProfile profile) {
+ if (sExecutionService == null) {
+ log.error("setNewBasalProfile sExecutionService is null");
+ return FAILED;
+ }
+ if (!isInitialized()) {
+ log.error("setNewBasalProfile not initialized");
+ Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ return FAILED;
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
+ }
+ if (!sExecutionService.updateBasalsInPump(profile)) {
+ Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ return FAILED;
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
+ MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
+ return SUCCESS;
+ }
+ }
+
+ @Override
+ public boolean isThisProfileSet(NSProfile profile) {
+ if (!isInitialized())
+ return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS
+ DanaRKoreanPump pump = getDanaRPump();
+ int basalValues = pump.basal48Enable ? 48 : 24;
+ int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
+ for (int h = 0; h < basalValues; h++) {
+ Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
+ Double profileValue = profile.getBasal(h * basalIncrement);
+ if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
+ log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public double getBaseBasalRate() {
+ return getDanaRPump().currentBasal;
+ }
+
+ @Override
+ public double getTempBasalAbsoluteRate() {
+ if (isRealTempBasalInProgress()) {
+ if (getRealTempBasal().isAbsolute) {
+ return getRealTempBasal().absolute;
+ } else {
+ Double baseRate = getBaseBasalRate();
+ Double tempRate = baseRate * (getRealTempBasal().percent / 100d);
+ return tempRate;
+ }
+ }
+ if (isExtendedBoluslInProgress() && useExtendedBoluses) {
+ return getBaseBasalRate() + getExtendedBolus().absolute;
+ }
+ return 0;
+ }
+
+ @Override
+ public double getTempBasalRemainingMinutes() {
+ if (isRealTempBasalInProgress())
+ return getRealTempBasal().getPlannedRemainingMinutes();
+ if (isExtendedBoluslInProgress() && useExtendedBoluses)
+ return getExtendedBolus().getPlannedRemainingMinutes();
+ return 0;
+ }
+
+ @Override
+ public TempBasal getTempBasal() {
+ if (isRealTempBasalInProgress())
+ return getRealTempBasal();
+ if (isExtendedBoluslInProgress() && useExtendedBoluses)
+ return getExtendedBolus();
+ return null;
+ }
+
+ public TempBasal getTempBasal(Date time) {
+ TempBasal temp = MainApp.getConfigBuilder().getActiveTempBasals().getTempBasal(time);
+ if (temp != null) return temp;
+ if (useExtendedBoluses)
+ return MainApp.getConfigBuilder().getActiveTempBasals().getExtendedBolus(time);
+ return null;
+ }
+
+ public TempBasal getRealTempBasal() {
+ return MainApp.getConfigBuilder().getActiveTempBasals().getTempBasal(new Date());
+ }
+
+ @Override
+ public TempBasal getExtendedBolus() {
+ return MainApp.getConfigBuilder().getActiveTempBasals().getExtendedBolus(new Date());
+ }
+
+ @Override
+ public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context) {
+ ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
+ insulin = configBuilderPlugin.applyBolusConstraints(insulin);
+ if (insulin > 0 || carbs > 0) {
+ Treatment t = new Treatment();
+ boolean connectionOK = false;
+ if (insulin > 0 || carbs > 0) connectionOK = sExecutionService.bolus(insulin, carbs, t);
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = connectionOK;
+ result.bolusDelivered = t.insulin;
+ result.carbsDelivered = carbs;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ if (Config.logPumpActions)
+ log.debug("deliverTreatment: OK. Asked: " + insulin + " Delivered: " + result.bolusDelivered);
+ return result;
+ } else {
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = false;
+ result.bolusDelivered = 0d;
+ result.carbsDelivered = 0;
+ result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
+ log.error("deliverTreatment: Invalid input");
+ return result;
+ }
+ }
+
+ @Override
+ public void stopBolusDelivering() {
+ if (sExecutionService == null) {
+ log.error("stopBolusDelivering sExecutionService is null");
+ return;
+ }
+ sExecutionService.bolusStop();
+ }
+
+ // This is called from APS
+ @Override
+ public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
+ // Recheck pump status if older than 30 min
+ if (getDanaRPump().lastConnection.getTime() + 30 * 60 * 1000L < new Date().getTime()) {
+ doConnect("setTempBasalAbsolute old data");
+ }
+
+ PumpEnactResult result = new PumpEnactResult();
+
+ ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
+ absoluteRate = configBuilderPlugin.applyBasalConstraints(absoluteRate);
+
+ final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d;
+ final boolean doLowTemp = absoluteRate < getBaseBasalRate();
+ final boolean doHighTemp = absoluteRate > getBaseBasalRate() && !useExtendedBoluses;
+ final boolean doExtendedTemp = absoluteRate > getBaseBasalRate() && useExtendedBoluses;
+
+ if (doTempOff) {
+ // If extended in progress
+ if (isExtendedBoluslInProgress() && useExtendedBoluses) {
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Stopping extended bolus (doTempOff)");
+ return cancelExtendedBolus();
+ }
+ // If temp in progress
+ if (isRealTempBasalInProgress()) {
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Stopping temp basal (doTempOff)");
+ return cancelRealTempBasal();
+ }
+ result.success = true;
+ result.enacted = false;
+ result.percent = 100;
+ result.isPercent = true;
+ result.isTempCancel = true;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: doTempOff OK");
+ return result;
+ }
+
+ if (doLowTemp || doHighTemp) {
+ Integer percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
+ if (percentRate < 100) percentRate = Round.ceilTo((double) percentRate, 10d).intValue();
+ else percentRate = Round.floorTo((double) percentRate, 10d).intValue();
+ if (percentRate > 200) {
+ percentRate = 200;
+ }
+ // If extended in progress
+ if (isExtendedBoluslInProgress() && useExtendedBoluses) {
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Stopping extended bolus (doLowTemp || doHighTemp)");
+ result = cancelExtendedBolus();
+ if (!result.success) {
+ log.error("setTempBasalAbsolute: Failed to stop previous extended bolus (doLowTemp || doHighTemp)");
+ return result;
+ }
+ }
+ // Check if some temp is already in progress
+ if (isRealTempBasalInProgress()) {
+ // Correct basal already set ?
+ if (getRealTempBasal().percent == percentRate) {
+ result.success = true;
+ result.percent = percentRate;
+ result.absolute = getTempBasalAbsoluteRate();
+ result.enacted = false;
+ result.duration = ((Double) getTempBasalRemainingMinutes()).intValue();
+ result.isPercent = true;
+ result.isTempCancel = false;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)");
+ return result;
+ } else {
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Stopping temp basal (doLowTemp || doHighTemp)");
+ result = cancelRealTempBasal();
+ // Check for proper result
+ if (!result.success) {
+ log.error("setTempBasalAbsolute: Failed to stop previous temp basal (doLowTemp || doHighTemp)");
+ return result;
+ }
+ }
+ }
+ // Convert duration from minutes to hours
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)");
+ return setTempBasalPercent(percentRate, durationInMinutes);
+ }
+ if (doExtendedTemp) {
+ // Check if some temp is already in progress
+ if (isRealTempBasalInProgress()) {
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Stopping temp basal (doExtendedTemp)");
+ result = cancelRealTempBasal();
+ // Check for proper result
+ if (!result.success) {
+ log.error("setTempBasalAbsolute: Failed to stop previous temp basal (doExtendedTemp)");
+ return result;
+ }
+ }
+
+ // Calculate # of halfHours from minutes
+ Integer durationInHalfHours = Math.max(durationInMinutes / 30, 1);
+ // We keep current basal running so need to sub current basal
+ Double extendedRateToSet = absoluteRate - getBaseBasalRate();
+ extendedRateToSet = configBuilderPlugin.applyBasalConstraints(extendedRateToSet);
+ // needs to be rounded to 0.1
+ extendedRateToSet = Round.roundTo(extendedRateToSet, 0.1d);
+
+ // What is current rate of extended bolusing in u/h?
+ if (Config.logPumpActions) {
+ log.debug("setTempBasalAbsolute: Extended bolus in progress: " + isExtendedBoluslInProgress() + " rate: " + getDanaRPump().extendedBolusAbsoluteRate + "U/h duration remaining: " + getDanaRPump().extendedBolusRemainingMinutes + "min");
+ log.debug("setTempBasalAbsolute: Rate to set: " + extendedRateToSet + "U/h");
+ }
+
+ // Compare with extended rate in progress
+ if (Math.abs(getDanaRPump().extendedBolusAbsoluteRate - extendedRateToSet) < 0.02D) { // Allow some rounding diff
+ // correct extended already set
+ result.success = true;
+ result.absolute = getDanaRPump().extendedBolusAbsoluteRate;
+ result.enacted = false;
+ result.duration = getDanaRPump().extendedBolusRemainingMinutes;
+ result.isPercent = false;
+ result.isTempCancel = false;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Correct extended already set");
+ return result;
+ }
+
+ // Now set new extended, no need to to stop previous (if running) because it's replaced
+ Double extendedAmount = extendedRateToSet / 2 * durationInHalfHours;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Setting extended: " + extendedAmount + "U halfhours: " + durationInHalfHours);
+ result = setExtendedBolus(extendedAmount, durationInMinutes);
+ if (!result.success) {
+ log.error("setTempBasalAbsolute: Failed to set extended bolus");
+ return result;
+ }
+ if (Config.logPumpActions)
+ log.debug("setTempBasalAbsolute: Extended bolus set ok");
+ result.absolute = result.absolute + getBaseBasalRate();
+ return result;
+ }
+ // We should never end here
+ log.error("setTempBasalAbsolute: Internal error");
+ result.success = false;
+ result.comment = "Internal error";
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) {
+ PumpEnactResult result = new PumpEnactResult();
+ ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
+ percent = configBuilderPlugin.applyBasalConstraints(percent);
+ if (percent < 0) {
+ result.isTempCancel = false;
+ result.enacted = false;
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_invalidinput);
+ log.error("setTempBasalPercent: Invalid input");
+ return result;
+ }
+ if (percent > 200) percent = 200;
+ if (getDanaRPump().isTempBasalInProgress && getDanaRPump().tempBasalPercent == percent) {
+ result.enacted = false;
+ result.success = true;
+ result.isTempCancel = false;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.duration = getDanaRPump().tempBasalRemainingMin;
+ result.percent = getDanaRPump().tempBasalPercent;
+ result.isPercent = true;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalPercent: Correct value already set");
+ return result;
+ }
+ int durationInHours = Math.max(durationInMinutes / 60, 1);
+ boolean connectionOK = sExecutionService.tempBasal(percent, durationInHours);
+ if (connectionOK && getDanaRPump().isTempBasalInProgress && getDanaRPump().tempBasalPercent == percent) {
+ result.enacted = true;
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.isTempCancel = false;
+ result.duration = getDanaRPump().tempBasalRemainingMin;
+ result.percent = getDanaRPump().tempBasalPercent;
+ result.isPercent = true;
+ if (Config.logPumpActions)
+ log.debug("setTempBasalPercent: OK");
+ return result;
+ }
+ result.enacted = false;
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
+ log.error("setTempBasalPercent: Failed to set temp basal");
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
+ ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder();
+ insulin = configBuilderPlugin.applyBolusConstraints(insulin);
+ // needs to be rounded to 0.1
+ insulin = Round.roundTo(insulin, 0.1d);
+
+ PumpEnactResult result = new PumpEnactResult();
+ if (getDanaRPump().isExtendedInProgress && Math.abs(getDanaRPump().extendedBolusAmount - insulin) < 0.1d) {
+ result.enacted = false;
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.duration = getDanaRPump().extendedBolusRemainingMinutes;
+ result.absolute = getDanaRPump().extendedBolusAbsoluteRate;
+ result.isPercent = false;
+ result.isTempCancel = false;
+ if (Config.logPumpActions)
+ log.debug("setExtendedBolus: Correct extended bolus already set");
+ return result;
+ }
+ int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
+ boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
+ if (connectionOK && getDanaRPump().isExtendedInProgress && Math.abs(getDanaRPump().extendedBolusAmount - insulin) < 0.1d) {
+ result.enacted = true;
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.isTempCancel = false;
+ result.duration = getDanaRPump().extendedBolusRemainingMinutes;
+ result.absolute = getDanaRPump().extendedBolusAbsoluteRate;
+ result.bolusDelivered = getDanaRPump().extendedBolusAmount;
+ result.isPercent = false;
+ if (Config.logPumpActions)
+ log.debug("setExtendedBolus: OK");
+ return result;
+ }
+ result.enacted = false;
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
+ log.error("setExtendedBolus: Failed to extended bolus");
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult cancelTempBasal() {
+ if (isRealTempBasalInProgress())
+ return cancelRealTempBasal();
+ if (isExtendedBoluslInProgress())
+ return cancelExtendedBolus();
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = true;
+ result.enacted = false;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ result.isTempCancel = true;
+ return result;
+ }
+
+ public PumpEnactResult cancelRealTempBasal() {
+ PumpEnactResult result = new PumpEnactResult();
+ if (getDanaRPump().isTempBasalInProgress) {
+ sExecutionService.tempBasalStop();
+ result.enacted = true;
+ result.isTempCancel = true;
+ }
+ if (!getDanaRPump().isTempBasalInProgress) {
+ result.success = true;
+ result.isTempCancel = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ if (Config.logPumpActions)
+ log.debug("cancelRealTempBasal: OK");
+ return result;
+ } else {
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
+ result.isTempCancel = true;
+ log.error("cancelRealTempBasal: Failed to cancel temp basal");
+ return result;
+ }
+ }
+
+ @Override
+ public PumpEnactResult cancelExtendedBolus() {
+ PumpEnactResult result = new PumpEnactResult();
+ if (getDanaRPump().isExtendedInProgress) {
+ sExecutionService.extendedBolusStop();
+ result.enacted = true;
+ result.isTempCancel = true;
+ }
+ if (!getDanaRPump().isExtendedInProgress) {
+ result.success = true;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ if (Config.logPumpActions)
+ log.debug("cancelExtendedBolus: OK");
+ return result;
+ } else {
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly);
+ log.error("cancelExtendedBolus: Failed to cancel extended bolus");
+ return result;
+ }
+ }
+
+ public static void doConnect(String from) {
+ if (sExecutionService != null) sExecutionService.connect(from);
+ }
+
+ public static boolean isConnected() {
+ return sExecutionService != null && sExecutionService.isConnected();
+ }
+
+ public static boolean isConnecting() {
+ return sExecutionService != null && sExecutionService.isConnecting();
+ }
+
+ public static void doDisconnect(String from) {
+ if (sExecutionService != null) sExecutionService.disconnect(from);
+ }
+
+ @Override
+ public JSONObject getJSONStatus() {
+ if (getDanaRPump().lastConnection.getTime() + 5 * 60 * 1000L < new Date().getTime()) {
+ return null;
+ }
+ JSONObject pump = new JSONObject();
+ JSONObject battery = new JSONObject();
+ JSONObject status = new JSONObject();
+ JSONObject extended = new JSONObject();
+ try {
+ battery.put("percent", getDanaRPump().batteryRemaining);
+ status.put("status", "normal");
+ status.put("timestamp", DateUtil.toISOString(getDanaRPump().lastConnection));
+ extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
+ extended.put("PumpIOB", getDanaRPump().iob);
+// extended.put("LastBolus", getDanaRPump().lastBolusTime.toLocaleString());
+// extended.put("LastBolusAmount", getDanaRPump().lastBolusAmount);
+ if (isTempBasalInProgress()) {
+ extended.put("TempBasalAbsoluteRate", getTempBasalAbsoluteRate());
+ extended.put("TempBasalStart", getTempBasal().timeStart.toLocaleString());
+ extended.put("TempBasalRemaining", getTempBasal().getPlannedRemainingMinutes());
+ extended.put("IsExtended", getTempBasal().isExtended);
+ }
+ extended.put("BaseBasalRate", getBaseBasalRate());
+ try {
+ extended.put("ActiveProfile", MainApp.getConfigBuilder().getActiveProfile().getProfile().getActiveProfile());
+ } catch (Exception e) {
+ }
+
+ pump.put("battery", battery);
+ pump.put("status", status);
+ pump.put("extended", extended);
+ pump.put("reservoir", (int) getDanaRPump().reservoirRemainingUnits);
+ pump.put("clock", DateUtil.toISOString(new Date()));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return pump;
+ }
+
+ @Override
+ public String deviceID() {
+ return getDanaRPump().serialNumber;
+ }
+
+ @Override
+ public PumpDescription getPumpDescription() {
+ return pumpDescription;
+ }
+
+ /**
+ * Constraint interface
+ */
+
+ @Override
+ public boolean isLoopEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isClosedModeEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isAutosensModeEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isAMAModeEnabled() {
+ return true;
+ }
+
+ @SuppressWarnings("PointlessBooleanExpression")
+ @Override
+ public Double applyBasalConstraints(Double absoluteRate) {
+ double origAbsoluteRate = absoluteRate;
+ if (getDanaRPump() != null) {
+ if (absoluteRate > getDanaRPump().maxBasal) {
+ absoluteRate = getDanaRPump().maxBasal;
+ if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
+ log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h");
+ }
+ }
+ return absoluteRate;
+ }
+
+ @SuppressWarnings("PointlessBooleanExpression")
+ @Override
+ public Integer applyBasalConstraints(Integer percentRate) {
+ Integer origPercentRate = percentRate;
+ if (percentRate < 0) percentRate = 0;
+ if (percentRate > 200) percentRate = 200;
+ if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
+ log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%");
+ return percentRate;
+ }
+
+ @SuppressWarnings("PointlessBooleanExpression")
+ @Override
+ public Double applyBolusConstraints(Double insulin) {
+ double origInsulin = insulin;
+ if (getDanaRPump() != null) {
+ if (insulin > getDanaRPump().maxBolus) {
+ insulin = getDanaRPump().maxBolus;
+ if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit)
+ log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U");
+ }
+ }
+ return insulin;
+ }
+
+ @Override
+ public Integer applyCarbsConstraints(Integer carbs) {
+ return carbs;
+ }
+
+ @Override
+ public Double applyMaxIOBConstraints(Double maxIob) {
+ return maxIob;
+ }
+
+ @Nullable
+ @Override
+ public NSProfile getProfile() {
+ DanaRKoreanPump pump = getDanaRPump();
+ if (pump.lastSettingsRead.getTime() == 0)
+ return null; // no info now
+ return pump.createConvertedProfile();
+ }
+
+ // Reply for sms communicator
+ public String shortStatus() {
+ String ret = "";
+ if (getDanaRPump().lastConnection.getTime() != 0) {
+ Long agoMsec = new Date().getTime() - getDanaRPump().lastConnection.getTime();
+ int agoMin = (int) (agoMsec / 60d / 1000d);
+ ret += "LastConn: " + agoMin + " minago\n";
+ }
+// if (getDanaRPump().lastBolusTime.getTime() != 0) {
+// ret += "LastBolus: " + DecimalFormatter.to2Decimal(getDanaRPump().lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", getDanaRPump().lastBolusTime) + "\n";
+// }
+ if (isRealTempBasalInProgress()) {
+ ret += "Temp: " + getRealTempBasal().toString() + "\n";
+ }
+ if (isExtendedBoluslInProgress()) {
+ ret += "Extended: " + getExtendedBolus().toString() + "\n";
+ }
+ ret += "IOB: " + getDanaRPump().iob + "U\n";
+ ret += "Reserv: " + DecimalFormatter.to0Decimal(getDanaRPump().reservoirRemainingUnits) + "U\n";
+ ret += "Batt: " + getDanaRPump().batteryRemaining + "\n";
+ return ret;
+ }
+ // TODO: daily total constraint
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPump.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPump.java
new file mode 100644
index 0000000000..16ac0e2507
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPump.java
@@ -0,0 +1,172 @@
+package info.nightscout.androidaps.plugins.DanaRKorean;
+
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.text.DecimalFormat;
+import java.util.Date;
+
+import info.nightscout.androidaps.Constants;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.client.data.NSProfile;
+import info.nightscout.utils.SafeParse;
+
+/**
+ * Created by mike on 04.07.2016.
+ */
+public class DanaRKoreanPump {
+ public static final int UNITS_MGDL = 0;
+ public static final int UNITS_MMOL = 1;
+
+ public static final int DELIVERY_PRIME = 0x01;
+ public static final int DELIVERY_STEP_BOLUS = 0x02;
+ public static final int DELIVERY_BASAL = 0x04;
+ public static final int DELIVERY_EXT_BOLUS = 0x08;
+
+ public static final String PROFILE_PREFIX = "DanaR-";
+
+ public Date lastConnection = new Date(0);
+ public Date lastSettingsRead = new Date(0);
+
+ // Info
+ public String serialNumber = "";
+ public Date shippingDate = new Date(0);
+ public String shippingCountry = "";
+ public boolean isNewPump = false;
+ public int password = -1;
+ public Date pumpTime = new Date(0);
+
+ public static final int DOMESTIC_MODEL = 0x01;
+ public static final int EXPORT_MODEL = 0x03;
+ public int model;
+ public int protocol;
+ public int productCode;
+
+ public boolean isConfigUD;
+ public boolean isExtendedBolusEnabled;
+ public boolean isEasyModeEnabled;
+
+ // Status
+ public double dailyTotalUnits;
+ public int maxDailyTotalUnits;
+
+ public double bolusStep;
+ public double basalStep;
+
+ public double iob;
+
+ public double reservoirRemainingUnits;
+ public int batteryRemaining;
+
+ public double currentBasal;
+
+ public boolean isTempBasalInProgress;
+ public int tempBasalPercent;
+ public int tempBasalRemainingMin;
+ public int tempBasalTotalSec;
+ public Date tempBasalStart;
+
+ public boolean isExtendedInProgress;
+ public int extendedBolusMinutes;
+ public double extendedBolusAmount;
+ public double extendedBolusAbsoluteRate;
+ public int extendedBolusSoFarInMinutes;
+ public Date extendedBolusStart;
+ public int extendedBolusRemainingMinutes;
+
+ // Profile
+ public int units;
+ public int easyBasalMode;
+ public boolean basal48Enable = false;
+ public int currentCIR;
+ public double currentCF;
+ public double currentAI;
+ public double currentTarget;
+ public int currentAIDR;
+
+ public int morningCIR;
+ public double morningCF;
+ public int afternoonCIR;
+ public double afternoonCF;
+ public int eveningCIR;
+ public double eveningCF;
+ public int nightCIR;
+ public double nightCF;
+
+
+ public int activeProfile = 0;
+ public double[][] pumpProfiles = null;
+
+ //Limits
+ public double maxBolus;
+ public double maxBasal;
+
+ public NSProfile createConvertedProfile() {
+ JSONObject json = new JSONObject();
+ JSONObject store = new JSONObject();
+ JSONObject profile = new JSONObject();
+
+// Morning / 6:00–10:59
+// Afternoon / 11:00–16:59
+// Evening / 17:00–21:59
+// Night / 22:00–5:59
+
+ SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+ double dia = SafeParse.stringToDouble(SP.getString("danarprofile_dia", "3"));
+ double car = SafeParse.stringToDouble(SP.getString("danarprofile_car", "20"));
+
+ try {
+ json.put("defaultProfile", PROFILE_PREFIX + (activeProfile + 1));
+ json.put("store", store);
+ profile.put("dia", dia);
+
+ JSONArray carbratios = new JSONArray();
+ carbratios.put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", nightCIR));
+ carbratios.put(new JSONObject().put("time", "06:00").put("timeAsSeconds", 6 * 3600).put("value", morningCIR));
+ carbratios.put(new JSONObject().put("time", "11:00").put("timeAsSeconds", 11 * 3600).put("value", afternoonCIR));
+ carbratios.put(new JSONObject().put("time", "14:00").put("timeAsSeconds", 17 * 3600).put("value", eveningCIR));
+ carbratios.put(new JSONObject().put("time", "22:00").put("timeAsSeconds", 22 * 3600).put("value", nightCIR));
+ profile.put("carbratio", carbratios);
+
+ profile.put("carbs_hr", car);
+
+ JSONArray sens = new JSONArray();
+ sens.put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", nightCF));
+ sens.put(new JSONObject().put("time", "06:00").put("timeAsSeconds", 6 * 3600).put("value", morningCF));
+ sens.put(new JSONObject().put("time", "11:00").put("timeAsSeconds", 11 * 3600).put("value", afternoonCF));
+ sens.put(new JSONObject().put("time", "17:00").put("timeAsSeconds", 17 * 3600).put("value", eveningCF));
+ sens.put(new JSONObject().put("time", "22:00").put("timeAsSeconds", 22 * 3600).put("value", nightCF));
+ profile.put("sens", sens);
+
+ JSONArray basals = new JSONArray();
+ int basalValues = basal48Enable ? 48 : 24;
+ int basalIncrement = basal48Enable ? 30 * 60 : 60 * 60;
+ for (int h = 0; h < basalValues; h++) {
+ String time;
+ DecimalFormat df = new DecimalFormat("00");
+ if (basal48Enable) {
+ time = df.format((long) h / 2) + ":" + df.format(30 * (h % 2));
+ } else {
+ time = df.format(h) + ":00";
+ }
+ basals.put(new JSONObject().put("time", time).put("timeAsSeconds", h * basalIncrement).put("value", pumpProfiles[activeProfile][h]));
+ }
+ profile.put("basal", basals);
+
+ profile.put("target_low", new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", currentTarget)));
+ profile.put("target_high", new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", currentTarget)));
+ profile.put("units", units == UNITS_MGDL ? Constants.MGDL : Constants.MMOL);
+ store.put(PROFILE_PREFIX + (activeProfile + 1), profile);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ return null;
+ }
+ return new NSProfile(json, PROFILE_PREFIX + (activeProfile + 1));
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/History/DanaRHistoryActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/History/DanaRHistoryActivity.java
new file mode 100644
index 0000000000..1b2f8165cf
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/History/DanaRHistoryActivity.java
@@ -0,0 +1,460 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.History;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.support.v7.widget.CardView;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.stmt.PreparedQuery;
+import com.j256.ormlite.stmt.QueryBuilder;
+import com.j256.ormlite.stmt.Where;
+import com.squareup.otto.Subscribe;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import info.nightscout.androidaps.Constants;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.db.DanaRHistoryRecord;
+import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.DanaR.History.DanaRNSHistorySync;
+import info.nightscout.androidaps.plugins.DanaR.comm.RecordTypes;
+import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus;
+import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRSyncStatus;
+import info.nightscout.androidaps.plugins.DanaRKorean.Services.ExecutionService;
+import info.nightscout.client.data.NSProfile;
+import info.nightscout.utils.DecimalFormatter;
+import info.nightscout.utils.ToastUtils;
+
+public class DanaRHistoryActivity extends Activity {
+ private static Logger log = LoggerFactory.getLogger(DanaRHistoryActivity.class);
+
+ private boolean mBounded;
+ private static ExecutionService mExecutionService;
+
+ private Handler mHandler;
+ private static HandlerThread mHandlerThread;
+
+ static NSProfile profile = null;
+
+ Spinner historyTypeSpinner;
+ TextView statusView;
+ Button reloadButton;
+ Button syncButton;
+ RecyclerView recyclerView;
+ LinearLayoutManager llm;
+
+ static byte showingType = RecordTypes.RECORD_TYPE_ALARM;
+ List historyList = new ArrayList<>();
+
+ public static class TypeList {
+ public byte type;
+ String name;
+
+ public TypeList(byte type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ public DanaRHistoryActivity() {
+ super();
+ mHandlerThread = new HandlerThread(DanaRHistoryActivity.class.getSimpleName());
+ mHandlerThread.start();
+ this.mHandler = new Handler(mHandlerThread.getLooper());
+ }
+
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ Intent intent = new Intent(this, ExecutionService.class);
+ bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ MainApp.bus().register(this);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ MainApp.bus().unregister(this);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (mBounded) {
+ unbindService(mConnection);
+ mBounded = false;
+ }
+ }
+
+ ServiceConnection mConnection = new ServiceConnection() {
+
+ public void onServiceDisconnected(ComponentName name) {
+ log.debug("Service is disconnected");
+ mBounded = false;
+ mExecutionService = null;
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ log.debug("Service is connected");
+ mBounded = true;
+ ExecutionService.LocalBinder mLocalBinder = (ExecutionService.LocalBinder) service;
+ mExecutionService = mLocalBinder.getServiceInstance();
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.danar_historyactivity);
+
+ historyTypeSpinner = (Spinner) findViewById(R.id.danar_historytype);
+ statusView = (TextView) findViewById(R.id.danar_historystatus);
+ reloadButton = (Button) findViewById(R.id.danar_historyreload);
+ syncButton = (Button) findViewById(R.id.danar_historysync);
+ recyclerView = (RecyclerView) findViewById(R.id.danar_history_recyclerview);
+
+ recyclerView.setHasFixedSize(true);
+ llm = new LinearLayoutManager(this);
+ recyclerView.setLayoutManager(llm);
+
+ RecyclerViewAdapter adapter = new RecyclerViewAdapter(historyList);
+ recyclerView.setAdapter(adapter);
+
+ statusView.setVisibility(View.GONE);
+
+ // Types
+
+ ArrayList typeList = new ArrayList<>();
+ typeList.add(new TypeList(RecordTypes.RECORD_TYPE_ALARM, getString(R.string.danar_history_alarm)));
+ typeList.add(new TypeList(RecordTypes.RECORD_TYPE_BASALHOUR, getString(R.string.danar_history_basalhours)));
+ typeList.add(new TypeList(RecordTypes.RECORD_TYPE_BOLUS, getString(R.string.danar_history_bolus)));
+ typeList.add(new TypeList(RecordTypes.RECORD_TYPE_CARBO, getString(R.string.danar_history_carbohydrates)));
+ typeList.add(new TypeList(RecordTypes.RECORD_TYPE_DAILY, getString(R.string.danar_history_dailyinsulin)));
+ typeList.add(new TypeList(RecordTypes.RECORD_TYPE_GLUCOSE, getString(R.string.danar_history_glucose)));
+
+ ArrayAdapter spinnerAdapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item, typeList);
+ spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ historyTypeSpinner.setAdapter(spinnerAdapter);
+
+ reloadButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mExecutionService.isConnected() || mExecutionService.isConnecting()) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.pumpbusy));
+ return;
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ TypeList selected = (TypeList) historyTypeSpinner.getSelectedItem();
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ reloadButton.setVisibility(View.GONE);
+ syncButton.setVisibility(View.GONE);
+ statusView.setVisibility(View.VISIBLE);
+ }
+ });
+ clearCardView();
+ mExecutionService.loadHistory(selected.type);
+ loadDataFromDB(selected.type);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ reloadButton.setVisibility(View.VISIBLE);
+ syncButton.setVisibility(View.VISIBLE);
+ statusView.setVisibility(View.GONE);
+ }
+ });
+ }
+ });
+ }
+ });
+
+ syncButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ reloadButton.setVisibility(View.GONE);
+ syncButton.setVisibility(View.GONE);
+ statusView.setVisibility(View.VISIBLE);
+ }
+ });
+ DanaRNSHistorySync sync = new DanaRNSHistorySync(historyList);
+ sync.sync(DanaRNSHistorySync.SYNC_ALL);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ reloadButton.setVisibility(View.VISIBLE);
+ syncButton.setVisibility(View.VISIBLE);
+ statusView.setVisibility(View.GONE);
+ }
+ });
+ }
+ });
+ }
+ });
+
+ historyTypeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ TypeList selected = (TypeList) historyTypeSpinner.getSelectedItem();
+ loadDataFromDB(selected.type);
+ showingType = selected.type;
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ clearCardView();
+ }
+ });
+ profile = ConfigBuilderPlugin.getActiveProfile().getProfile();
+ if (profile == null) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.noprofile));
+ finish();
+ }
+ }
+
+ public static class RecyclerViewAdapter extends RecyclerView.Adapter {
+
+ List historyList;
+
+ RecyclerViewAdapter(List historyList) {
+ this.historyList = historyList;
+ }
+
+ @Override
+ public HistoryViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+ View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.danar_history_item, viewGroup, false);
+ return new HistoryViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(HistoryViewHolder holder, int position) {
+ DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
+ DanaRHistoryRecord record = historyList.get(position);
+ holder.time.setText(df.format(new Date(record.getRecordDate())));
+ holder.value.setText(DecimalFormatter.to2Decimal(record.getRecordValue()));
+ holder.stringvalue.setText(record.getStringRecordValue());
+ holder.bolustype.setText(record.getBolusType());
+ holder.duration.setText(DecimalFormatter.to0Decimal(record.getRecordDuration()));
+ holder.alarm.setText(record.getRecordAlarm());
+ switch (showingType) {
+ case RecordTypes.RECORD_TYPE_ALARM:
+ holder.time.setVisibility(View.VISIBLE);
+ holder.value.setVisibility(View.VISIBLE);
+ holder.stringvalue.setVisibility(View.GONE);
+ holder.bolustype.setVisibility(View.GONE);
+ holder.duration.setVisibility(View.GONE);
+ holder.dailybasal.setVisibility(View.GONE);
+ holder.dailybolus.setVisibility(View.GONE);
+ holder.dailytotal.setVisibility(View.GONE);
+ holder.alarm.setVisibility(View.VISIBLE);
+ break;
+ case RecordTypes.RECORD_TYPE_BOLUS:
+ holder.time.setVisibility(View.VISIBLE);
+ holder.value.setVisibility(View.VISIBLE);
+ holder.stringvalue.setVisibility(View.GONE);
+ holder.bolustype.setVisibility(View.VISIBLE);
+ holder.duration.setVisibility(View.VISIBLE);
+ holder.dailybasal.setVisibility(View.GONE);
+ holder.dailybolus.setVisibility(View.GONE);
+ holder.dailytotal.setVisibility(View.GONE);
+ holder.alarm.setVisibility(View.GONE);
+ break;
+ case RecordTypes.RECORD_TYPE_DAILY:
+ df = DateFormat.getDateInstance(DateFormat.SHORT);
+ holder.dailybasal.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBasal()) + "U");
+ holder.dailybolus.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBolus()) + "U");
+ holder.dailytotal.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBolus()+ record.getRecordDailyBasal()) + "U");
+ holder.time.setText(df.format(new Date(record.getRecordDate())));
+ holder.time.setVisibility(View.VISIBLE);
+ holder.value.setVisibility(View.GONE);
+ holder.stringvalue.setVisibility(View.GONE);
+ holder.bolustype.setVisibility(View.GONE);
+ holder.duration.setVisibility(View.GONE);
+ holder.dailybasal.setVisibility(View.VISIBLE);
+ holder.dailybolus.setVisibility(View.VISIBLE);
+ holder.dailytotal.setVisibility(View.VISIBLE);
+ holder.alarm.setVisibility(View.GONE);
+ break;
+ case RecordTypes.RECORD_TYPE_GLUCOSE:
+ holder.value.setText(NSProfile.toUnitsString(record.getRecordValue(), record.getRecordValue() * Constants.MGDL_TO_MMOLL, profile.getUnits()));
+ // rest is the same
+ case RecordTypes.RECORD_TYPE_CARBO:
+ case RecordTypes.RECORD_TYPE_BASALHOUR:
+ case RecordTypes.RECORD_TYPE_ERROR:
+ case RecordTypes.RECORD_TYPE_PRIME:
+ case RecordTypes.RECORD_TYPE_REFILL:
+ case RecordTypes.RECORD_TYPE_TB:
+ holder.time.setVisibility(View.VISIBLE);
+ holder.value.setVisibility(View.VISIBLE);
+ holder.stringvalue.setVisibility(View.GONE);
+ holder.bolustype.setVisibility(View.GONE);
+ holder.duration.setVisibility(View.GONE);
+ holder.dailybasal.setVisibility(View.GONE);
+ holder.dailybolus.setVisibility(View.GONE);
+ holder.dailytotal.setVisibility(View.GONE);
+ holder.alarm.setVisibility(View.GONE);
+ break;
+ case RecordTypes.RECORD_TYPE_SUSPEND:
+ holder.time.setVisibility(View.VISIBLE);
+ holder.value.setVisibility(View.GONE);
+ holder.stringvalue.setVisibility(View.VISIBLE);
+ holder.bolustype.setVisibility(View.GONE);
+ holder.duration.setVisibility(View.GONE);
+ holder.dailybasal.setVisibility(View.GONE);
+ holder.dailybolus.setVisibility(View.GONE);
+ holder.dailytotal.setVisibility(View.GONE);
+ holder.alarm.setVisibility(View.GONE);
+ break;
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return historyList.size();
+ }
+
+ @Override
+ public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+ super.onAttachedToRecyclerView(recyclerView);
+ }
+
+ public static class HistoryViewHolder extends RecyclerView.ViewHolder {
+ CardView cv;
+ TextView time;
+ TextView value;
+ TextView bolustype;
+ TextView stringvalue;
+ TextView duration;
+ TextView dailybasal;
+ TextView dailybolus;
+ TextView dailytotal;
+ TextView alarm;
+
+ HistoryViewHolder(View itemView) {
+ super(itemView);
+ cv = (CardView) itemView.findViewById(R.id.danar_history_cardview);
+ time = (TextView) itemView.findViewById(R.id.danar_history_time);
+ value = (TextView) itemView.findViewById(R.id.danar_history_value);
+ bolustype = (TextView) itemView.findViewById(R.id.danar_history_bolustype);
+ stringvalue = (TextView) itemView.findViewById(R.id.danar_history_stringvalue);
+ duration = (TextView) itemView.findViewById(R.id.danar_history_duration);
+ dailybasal = (TextView) itemView.findViewById(R.id.danar_history_dailybasal);
+ dailybolus = (TextView) itemView.findViewById(R.id.danar_history_dailybolus);
+ dailytotal = (TextView) itemView.findViewById(R.id.danar_history_dailytotal);
+ alarm = (TextView) itemView.findViewById(R.id.danar_history_alarm);
+ }
+ }
+ }
+
+ private void loadDataFromDB(byte type) {
+ try {
+ Dao dao = MainApp.getDbHelper().getDaoDanaRHistory();
+ QueryBuilder queryBuilder = dao.queryBuilder();
+ queryBuilder.orderBy("recordDate", false);
+ Where where = queryBuilder.where();
+ where.eq("recordCode", type);
+ queryBuilder.limit(200L);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ historyList = dao.query(preparedQuery);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ historyList = new ArrayList<>();
+ }
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ recyclerView.swapAdapter(new RecyclerViewAdapter(historyList), false);
+ }
+ });
+ }
+
+ private void clearCardView() {
+ historyList = new ArrayList<>();
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ recyclerView.swapAdapter(new RecyclerViewAdapter(historyList), false);
+ }
+ });
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventDanaRSyncStatus s) {
+ log.debug("EventDanaRSyncStatus: " + s.message);
+ runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ statusView.setText(s.message);
+ }
+ });
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventDanaRConnectionStatus c) {
+ runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (c.sStatus == EventDanaRConnectionStatus.CONNECTING) {
+ statusView.setText(String.format(getString(R.string.danar_history_connectingfor), c.sSecondsElapsed));
+ log.debug("EventDanaRConnectionStatus: " + "Connecting for " + c.sSecondsElapsed + "s");
+ } else if (c.sStatus == EventDanaRConnectionStatus.CONNECTED) {
+ statusView.setText(MainApp.sResources.getString(R.string.connected));
+ log.debug("EventDanaRConnectionStatus: Connected");
+ } else {
+ statusView.setText(MainApp.sResources.getString(R.string.disconnected));
+ log.debug("EventDanaRConnectionStatus: Disconnected");
+ }
+ }
+ }
+ );
+ }
+
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/SerialIOThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/SerialIOThread.java
new file mode 100644
index 0000000000..ed53de2815
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/SerialIOThread.java
@@ -0,0 +1,224 @@
+package info.nightscout.androidaps.plugins.DanaRKorean;
+
+import android.bluetooth.BluetoothSocket;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MessageHashTable;
+import info.nightscout.utils.CRC;
+
+/**
+ * Created by mike on 17.07.2016.
+ */
+public class SerialIOThread extends Thread {
+ private static Logger log = LoggerFactory.getLogger(SerialIOThread.class);
+
+ private InputStream mInputStream = null;
+ private OutputStream mOutputStream = null;
+ private BluetoothSocket mRfCommSocket;
+
+ private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
+ private static ScheduledFuture> scheduledDisconnection = null;
+
+ private boolean mKeepRunning = true;
+ private byte[] mReadBuff = new byte[0];
+
+ MessageBase processedMessage;
+
+ public SerialIOThread(BluetoothSocket rfcommSocket) {
+ super(SerialIOThread.class.toString());
+
+ mRfCommSocket = rfcommSocket;
+ try {
+ mOutputStream = mRfCommSocket.getOutputStream();
+ mInputStream = mRfCommSocket.getInputStream();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ this.start();
+ }
+
+ @Override
+ public final void run() {
+ try {
+ while (mKeepRunning) {
+ int availableBytes = mInputStream.available();
+ // Ask for 1024 byte (or more if available)
+ byte[] newData = new byte[Math.max(1024, availableBytes)];
+ int gotBytes = mInputStream.read(newData);
+ // When we are here there is some new data available
+ appendToBuffer(newData, gotBytes);
+
+ // process all messages we already got
+ while (mReadBuff.length > 3) { // 3rd byte is packet size. continue only if we an determine packet size
+ byte[] extractedBuff = cutMessageFromBuffer();
+ if (extractedBuff == null) break; // message is not complete in buffer (wrong packet calls disconnection)
+
+ int command = (extractedBuff[5] & 0xFF) | ((extractedBuff[4] << 8) & 0xFF00);
+
+ MessageBase message;
+ if (processedMessage != null && processedMessage.getCommand() == command) {
+ message = processedMessage;
+ } else {
+ // get it from hash table
+ message = MessageHashTable.findMessage(command);
+ }
+
+ if (Config.logDanaMessageDetail)
+ log.debug("<<<<< " + message.getMessageName() + " " + message.toHexString(extractedBuff));
+
+ // process the message content
+ message.received = true;
+ message.handleMessage(extractedBuff);
+ synchronized (message) {
+ message.notify();
+ }
+ scheduleDisconnection();
+ }
+ }
+ } catch (Exception e) {
+ if (Config.logDanaSerialEngine && e.getMessage().indexOf("bt socket closed") < 0)
+ log.error("Thread exception: ", e);
+ mKeepRunning = false;
+ }
+ disconnect("EndOfLoop");
+ }
+
+ void appendToBuffer(byte[] newData, int gotBytes) {
+ // add newData to mReadBuff
+ byte[] newReadBuff = new byte[mReadBuff.length + gotBytes];
+ System.arraycopy(mReadBuff, 0, newReadBuff, 0, mReadBuff.length);
+ System.arraycopy(newData, 0, newReadBuff, mReadBuff.length, gotBytes);
+ mReadBuff = newReadBuff;
+ }
+
+ byte[] cutMessageFromBuffer() {
+ if (mReadBuff[0] == (byte) 0x7E && mReadBuff[1] == (byte) 0x7E) {
+ int length = (mReadBuff[2] & 0xFF) + 7;
+ // Check if we have enough data
+ if (mReadBuff.length < length) {
+ return null;
+ }
+ if (mReadBuff[length - 2] != (byte) 0x2E || mReadBuff[length - 1] != (byte) 0x2E) {
+ log.error("wrong packet lenght=" + length + " data " + MessageBase.toHexString(mReadBuff));
+ disconnect("wrong packet");
+ return null;
+ }
+
+ short crc = CRC.getCrc16(mReadBuff, 3, length - 7);
+ byte crcByte0 = (byte) (crc >> 8 & 0xFF);
+ byte crcByte1 = (byte) (crc & 0xFF);
+
+ byte crcByte0received = mReadBuff[length - 4];
+ byte crcByte1received = mReadBuff[length - 3];
+
+ if (crcByte0 != crcByte0received || crcByte1 != crcByte1received) {
+ log.error("CRC Error" + String.format("%02x ", crcByte0) + String.format("%02x ", crcByte1) + String.format("%02x ", crcByte0received) + String.format("%02x ", crcByte1received));
+ disconnect("crc error");
+ return null;
+ }
+ // Packet is verified here. extract data
+ byte[] extractedBuff = new byte[length];
+ System.arraycopy(mReadBuff, 0, extractedBuff, 0, length);
+ // remove extracted data from read buffer
+ byte[] unprocessedData = new byte[mReadBuff.length - length];
+ System.arraycopy(mReadBuff, length, unprocessedData, 0, unprocessedData.length);
+ mReadBuff = unprocessedData;
+ return extractedBuff;
+ } else {
+ log.error("Wrong beginning of packet len=" + mReadBuff.length + " " + MessageBase.toHexString(mReadBuff));
+ disconnect("Wrong beginning of packet");
+ return null;
+ }
+ }
+
+ public synchronized void sendMessage(MessageBase message) {
+ if (!mRfCommSocket.isConnected()) {
+ log.error("Socket not connected on sendMessage");
+ return;
+ }
+ processedMessage = message;
+
+ byte[] messageBytes = message.getRawMessageBytes();
+ if (Config.logDanaSerialEngine)
+ log.debug(">>>>> " + message.getMessageName() + " " + message.toHexString(messageBytes));
+
+ try {
+ mOutputStream.write(messageBytes);
+ } catch (Exception e) {
+ log.error("sendMessage write exception: ", e);
+ e.printStackTrace();
+ }
+
+ synchronized (message) {
+ try {
+ message.wait(5000);
+ } catch (InterruptedException e) {
+ log.error("sendMessage InterruptedException", e);
+ e.printStackTrace();
+ }
+ }
+
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ }
+ if (!message.received) {
+ log.warn("Reply not received " + message.getMessageName());
+ }
+ scheduleDisconnection();
+ }
+
+ public void scheduleDisconnection() {
+ class DisconnectRunnable implements Runnable {
+ public void run() {
+ disconnect("scheduleDisconnection");
+ scheduledDisconnection = null;
+ }
+ }
+ // prepare task for execution in 5 sec
+ // cancel waiting task to prevent sending multiple disconnections
+ if (scheduledDisconnection != null)
+ scheduledDisconnection.cancel(false);
+ Runnable task = new DisconnectRunnable();
+ final int sec = 5;
+ scheduledDisconnection = worker.schedule(task, sec, TimeUnit.SECONDS);
+ }
+
+ public void disconnect(String reason) {
+ mKeepRunning = false;
+ try {
+ mInputStream.close();
+ } catch (Exception e) {
+ if (Config.logDanaSerialEngine) log.debug(e.getMessage());
+ }
+ try {
+ mOutputStream.close();
+ } catch (Exception e) {
+ if (Config.logDanaSerialEngine) log.debug(e.getMessage());
+ }
+ try {
+ mRfCommSocket.close();
+ } catch (Exception e) {
+ if (Config.logDanaSerialEngine) log.debug(e.getMessage());
+ }
+ try {
+ System.runFinalization();
+ } catch (Exception e) {
+ if (Config.logDanaSerialEngine) log.debug(e.getMessage());
+ }
+ if (Config.logDanaSerialEngine) log.debug("Disconnected: " + reason);
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/Services/ExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/Services/ExecutionService.java
new file mode 100644
index 0000000000..29c001cc4c
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/Services/ExecutionService.java
@@ -0,0 +1,496 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.Services;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.preference.PreferenceManager;
+
+import com.squareup.otto.Subscribe;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Set;
+import java.util.UUID;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.events.EventAppExit;
+import info.nightscout.androidaps.events.EventInitializationChanged;
+import info.nightscout.androidaps.events.EventPreferenceChange;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusProgress;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryAlarm;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryBasalHour;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryBolus;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryCarbo;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryDailyInsulin;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryDone;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryError;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryGlucose;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryRefill;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistorySuspend;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgPCCommStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgPCCommStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetCarbsEntry;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetSingleBasalProfile;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTime;
+import info.nightscout.androidaps.plugins.DanaR.comm.RecordTypes;
+import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRBolusStart;
+import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus;
+import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRNewStatus;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+import info.nightscout.androidaps.plugins.DanaRKorean.SerialIOThread;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgCheckValue;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgSettingBasal;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgSettingGlucose;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgSettingMaxValues;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgSettingMeal;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgSettingProfileRatios;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgSettingPumpTime;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgSettingShippingInfo;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgStatusBasic;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgStatusBolusExtended;
+import info.nightscout.androidaps.plugins.DanaRKorean.comm.MsgStatusTempBasal;
+import info.nightscout.client.data.NSProfile;
+import info.nightscout.utils.SafeParse;
+import info.nightscout.utils.ToastUtils;
+
+public class ExecutionService extends Service {
+ private static Logger log = LoggerFactory.getLogger(ExecutionService.class);
+
+ private SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+ private String devName;
+
+ private SerialIOThread mSerialIOThread;
+ private BluetoothSocket mRfcommSocket;
+ private BluetoothDevice mBTDevice;
+
+ private PowerManager.WakeLock mWakeLock;
+ private IBinder mBinder = new LocalBinder();
+
+ private DanaRKoreanPump danaRKoreanPump;
+ private Treatment bolusingTreatment = null;
+
+ private static Boolean connectionInProgress = false;
+ private static final Object connectionLock = new Object();
+
+ private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
+
+ private BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ String action = intent.getAction();
+ if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
+ log.debug("Device has disconnected " + device.getName());//Device has disconnected
+ if (mBTDevice != null && mBTDevice.getName().equals(device.getName())) {
+ if (mSerialIOThread != null) {
+ mSerialIOThread.disconnect("BT disconnection broadcast");
+ }
+ MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.DISCONNECTED, 0));
+ }
+ }
+ }
+ };
+
+ public ExecutionService() {
+ registerBus();
+ MainApp.instance().getApplicationContext().registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
+ danaRKoreanPump = DanaRKoreanPlugin.getDanaRPump();
+
+ PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExecutionService");
+ }
+
+ public class LocalBinder extends Binder {
+ public ExecutionService getServiceInstance() {
+ return ExecutionService.this;
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+
+ return START_STICKY;
+ }
+
+ private void registerBus() {
+ try {
+ MainApp.bus().unregister(this);
+ } catch (RuntimeException x) {
+ // Ignore
+ }
+ MainApp.bus().register(this);
+ }
+
+ @Subscribe
+ public void onStatusEvent(EventAppExit event) {
+ if (Config.logFunctionCalls)
+ log.debug("EventAppExit received");
+
+ if (mSerialIOThread != null)
+ mSerialIOThread.disconnect("Application exit");
+
+ MainApp.instance().getApplicationContext().unregisterReceiver(receiver);
+
+ stopSelf();
+ if (Config.logFunctionCalls)
+ log.debug("EventAppExit finished");
+ }
+
+ public boolean isConnected() {
+ return mRfcommSocket != null && mRfcommSocket.isConnected();
+ }
+
+ public boolean isConnecting() {
+ return connectionInProgress;
+ }
+
+ public void disconnect(String from) {
+ if (mSerialIOThread != null)
+ mSerialIOThread.disconnect(from);
+ }
+
+ public void connect(String from) {
+ if (danaRKoreanPump.password != -1 && danaRKoreanPump.password != SafeParse.stringToInt(SP.getString("danar_password", "-1"))) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.wrongpumppassword), R.raw.error);
+ return;
+ }
+ while (isConnected() || isConnecting()) {
+ if (Config.logDanaBTComm)
+ log.debug("already connected/connecting from: " + from);
+ waitMsec(3000);
+ }
+ final long maxConnectionTime = 5 * 60 * 1000L; // 5 min
+ synchronized (connectionLock) {
+ //log.debug("entering connection while loop");
+ connectionInProgress = true;
+ mWakeLock.acquire();
+ getBTSocketForSelectedPump();
+ if (mRfcommSocket == null || mBTDevice == null)
+ return; // Device not found
+ long startTime = new Date().getTime();
+ while (!isConnected() && startTime + maxConnectionTime >= new Date().getTime()) {
+ long secondsElapsed = (new Date().getTime() - startTime) / 1000L;
+ MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.CONNECTING, (int) secondsElapsed));
+ if (Config.logDanaBTComm)
+ log.debug("connect waiting " + secondsElapsed + "sec from: " + from);
+ try {
+ mRfcommSocket.connect();
+ } catch (IOException e) {
+ //e.printStackTrace();
+ if (e.getMessage().contains("socket closed")) {
+ e.printStackTrace();
+ break;
+ }
+ }
+ waitMsec(1000);
+
+ if (isConnected()) {
+ if (mSerialIOThread != null) {
+ mSerialIOThread.disconnect("Recreate SerialIOThread");
+ }
+ mSerialIOThread = new SerialIOThread(mRfcommSocket);
+ MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.CONNECTED, 0));
+ if (!getPumpStatus()) {
+ mSerialIOThread.disconnect("getPumpStatus failed");
+ waitMsec(3000);
+ }
+ }
+ }
+ if (!isConnected()) {
+ MainApp.bus().post(new EventDanaRConnectionStatus(EventDanaRConnectionStatus.DISCONNECTED, 0));
+ log.error("Pump connection timed out");
+ }
+ connectionInProgress = false;
+ mWakeLock.release();
+ }
+ }
+
+ private void getBTSocketForSelectedPump() {
+ devName = SP.getString("danar_bt_name", "");
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ if (bluetoothAdapter != null) {
+ Set bondedDevices = bluetoothAdapter.getBondedDevices();
+
+ for (BluetoothDevice device : bondedDevices) {
+ if (devName.equals(device.getName())) {
+ mBTDevice = device;
+ try {
+ mRfcommSocket = mBTDevice.createRfcommSocketToServiceRecord(SPP_UUID);
+ } catch (IOException e) {
+ log.error("Error creating socket: ", e);
+ }
+ break;
+ }
+ }
+ } else {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.nobtadapter));
+ }
+ if (mBTDevice == null) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.devicenotfound));
+ }
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventPreferenceChange pch) {
+ if (mSerialIOThread != null)
+ mSerialIOThread.disconnect("EventPreferenceChange");
+ }
+
+ private boolean getPumpStatus() {
+ try {
+ //MsgStatus statusMsg = new MsgStatus();
+ MsgStatusBasic statusBasicMsg = new MsgStatusBasic();
+ MsgStatusTempBasal tempStatusMsg = new MsgStatusTempBasal();
+ MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
+
+
+ mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); // TODO: show it somewhere
+ mSerialIOThread.sendMessage(tempStatusMsg); // do this before statusBasic because here is temp duration
+ mSerialIOThread.sendMessage(exStatusMsg);
+ //mSerialIOThread.sendMessage(statusMsg);
+ mSerialIOThread.sendMessage(statusBasicMsg);
+
+ mSerialIOThread.sendMessage(new MsgCheckValue());
+
+// if (!statusMsg.received) {
+// mSerialIOThread.sendMessage(statusMsg);
+// }
+ if (!statusBasicMsg.received) {
+ mSerialIOThread.sendMessage(statusBasicMsg);
+ }
+ if (!tempStatusMsg.received) {
+ // Load of status of current basal rate failed, give one more try
+ mSerialIOThread.sendMessage(tempStatusMsg);
+ }
+ if (!exStatusMsg.received) {
+ // Load of status of current extended bolus failed, give one more try
+ mSerialIOThread.sendMessage(exStatusMsg);
+ }
+
+ // Check we have really current status of pump
+ if (/*!statusMsg.received || */!statusBasicMsg.received || !tempStatusMsg.received || !exStatusMsg.received) {
+ waitMsec(10 * 1000);
+ log.debug("getPumpStatus failed");
+ return false;
+ }
+
+ Date now = new Date();
+ if (danaRKoreanPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !((DanaRKoreanPlugin)MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).isInitialized()) {
+ mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
+ mSerialIOThread.sendMessage(new MsgSettingMeal());
+ mSerialIOThread.sendMessage(new MsgSettingBasal());
+ //0x3201
+ mSerialIOThread.sendMessage(new MsgSettingMaxValues());
+ mSerialIOThread.sendMessage(new MsgSettingGlucose());
+ mSerialIOThread.sendMessage(new MsgSettingPumpTime());
+ mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
+ mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
+ danaRKoreanPump.lastSettingsRead = now;
+ }
+
+ danaRKoreanPump.lastConnection = now;
+ MainApp.bus().post(new EventDanaRNewStatus());
+ MainApp.bus().post(new EventInitializationChanged());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+
+ public boolean tempBasal(int percent, int durationInHours) {
+ connect("tempBasal");
+ if (!isConnected()) return false;
+ mSerialIOThread.sendMessage(new MsgSetTempBasalStart(percent, durationInHours));
+ mSerialIOThread.sendMessage(new MsgStatusTempBasal());
+ return true;
+ }
+
+ public boolean tempBasalStop() {
+ connect("tempBasalStop");
+ if (!isConnected()) return false;
+ mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
+ mSerialIOThread.sendMessage(new MsgStatusTempBasal());
+ return true;
+ }
+
+ public boolean extendedBolus(double insulin, int durationInHalfHours) {
+ connect("extendedBolus");
+ if (!isConnected()) return false;
+ mSerialIOThread.sendMessage(new MsgSetExtendedBolusStart(insulin, (byte) (durationInHalfHours & 0xFF)));
+ mSerialIOThread.sendMessage(new MsgStatusBolusExtended());
+ return true;
+ }
+
+ public boolean extendedBolusStop() {
+ connect("extendedBolusStop");
+ if (!isConnected()) return false;
+ mSerialIOThread.sendMessage(new MsgSetExtendedBolusStop());
+ mSerialIOThread.sendMessage(new MsgStatusBolusExtended());
+ return true;
+ }
+
+ public boolean bolus(Double amount, int carbs, Treatment t) {
+ bolusingTreatment = t;
+ MsgBolusStart start = new MsgBolusStart(amount);
+ MsgBolusProgress progress = new MsgBolusProgress(amount, t); // initialize static variables
+ MsgBolusStop stop = new MsgBolusStop(amount, t);
+
+ connect("bolus");
+ if (!isConnected()) return false;
+
+ if (carbs > 0) {
+ Calendar time = Calendar.getInstance();
+ mSerialIOThread.sendMessage(new MsgSetCarbsEntry(time, carbs));
+ }
+ MainApp.bus().post(new EventDanaRBolusStart());
+
+ if (!stop.stopped) {
+ mSerialIOThread.sendMessage(start);
+ } else {
+ t.insulin = 0d;
+ return false;
+ }
+ while (!stop.stopped && !start.failed) {
+ waitMsec(100);
+ if (progress.lastReceive != 0 && (new Date().getTime() - progress.lastReceive) > 5 * 1000L) { // if i didn't receive status for more than 5 sec expecting broken comm
+ stop.stopped = true;
+ stop.forced = true;
+ log.debug("Communication stopped");
+ }
+ }
+ waitMsec(300);
+ bolusingTreatment = null;
+ getPumpStatus();
+ return true;
+ }
+
+ public void bolusStop() {
+ if (Config.logDanaBTComm)
+ log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin));
+ MsgBolusStop stop = new MsgBolusStop();
+ stop.forced = true;
+ if (isConnected()) {
+ mSerialIOThread.sendMessage(stop);
+ while (!stop.stopped) {
+ mSerialIOThread.sendMessage(stop);
+ waitMsec(200);
+ }
+ } else {
+ stop.stopped = true;
+ }
+ }
+
+ public boolean carbsEntry(int amount) {
+ connect("carbsEntry");
+ if (!isConnected()) return false;
+ Calendar time = Calendar.getInstance();
+ MsgSetCarbsEntry msg = new MsgSetCarbsEntry(time, amount);
+ mSerialIOThread.sendMessage(msg);
+ return true;
+ }
+
+ public boolean loadHistory(byte type) {
+ connect("loadHistory");
+ if (!isConnected()) return false;
+ MessageBase msg = null;
+ switch (type) {
+ case RecordTypes.RECORD_TYPE_ALARM:
+ msg = new MsgHistoryAlarm();
+ break;
+ case RecordTypes.RECORD_TYPE_BASALHOUR:
+ msg = new MsgHistoryBasalHour();
+ break;
+ case RecordTypes.RECORD_TYPE_BOLUS:
+ msg = new MsgHistoryBolus();
+ break;
+ case RecordTypes.RECORD_TYPE_CARBO:
+ msg = new MsgHistoryCarbo();
+ break;
+ case RecordTypes.RECORD_TYPE_DAILY:
+ msg = new MsgHistoryDailyInsulin();
+ break;
+ case RecordTypes.RECORD_TYPE_ERROR:
+ msg = new MsgHistoryError();
+ break;
+ case RecordTypes.RECORD_TYPE_GLUCOSE:
+ msg = new MsgHistoryGlucose();
+ break;
+ case RecordTypes.RECORD_TYPE_REFILL:
+ msg = new MsgHistoryRefill();
+ break;
+ case RecordTypes.RECORD_TYPE_SUSPEND:
+ msg = new MsgHistorySuspend();
+ break;
+ }
+ MsgHistoryDone done = new MsgHistoryDone();
+ mSerialIOThread.sendMessage(new MsgPCCommStart());
+ waitMsec(400);
+ mSerialIOThread.sendMessage(msg);
+ while (!done.received && mRfcommSocket.isConnected()) {
+ waitMsec(100);
+ }
+ waitMsec(200);
+ mSerialIOThread.sendMessage(new MsgPCCommStop());
+ return true;
+ }
+
+ public boolean updateBasalsInPump(final NSProfile profile) {
+ connect("updateBasalsInPump");
+ if (!isConnected()) return false;
+ double[] basal = buildDanaRProfileRecord(profile);
+ MsgSetSingleBasalProfile msgSet = new MsgSetSingleBasalProfile(basal);
+ mSerialIOThread.sendMessage(msgSet);
+ danaRKoreanPump.lastSettingsRead = new Date(0); // force read full settings
+ getPumpStatus();
+ return true;
+ }
+
+ private double[] buildDanaRProfileRecord(NSProfile nsProfile) {
+ double[] record = new double[24];
+ for (Integer hour = 0; hour < 24; hour++) {
+ double value = nsProfile.getBasal(hour * 60 * 60);
+ if (Config.logDanaMessageDetail)
+ log.debug("NS basal value for " + hour + ":00 is " + value);
+ record[hour] = value;
+ }
+ return record;
+ }
+
+ private void waitMsec(long msecs) {
+ try {
+ Thread.sleep(msecs);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MessageHashTable.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MessageHashTable.java
new file mode 100644
index 0000000000..084ad11074
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MessageHashTable.java
@@ -0,0 +1,95 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusProgress;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgBolusStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgError;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryAlarm;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryAll;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryBolus;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryCarbo;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryDailyInsulin;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryGlucose;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryNew;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgHistoryNewDone;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgPCCommStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgPCCommStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetCarbsEntry;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetExtendedBolusStop;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetSingleBasalProfile;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStart;
+import info.nightscout.androidaps.plugins.DanaR.comm.MsgSetTempBasalStop;
+
+/**
+ * Created by mike on 28.05.2016.
+ */
+public class MessageHashTable {
+ private static Logger log = LoggerFactory.getLogger(MessageHashTable.class);
+
+ public static HashMap messages = null;
+
+ static {
+ if (messages == null) {
+ messages = new HashMap();
+ put(new MsgBolusStop()); // 0x0101 CMD_MEALINS_STOP
+ put(new MsgBolusStart()); // 0x0102 CMD_MEALINS_START_DATA
+ put(new MsgBolusProgress()); // 0x0202 CMD_PUMP_THIS_REMAINDER_MEAL_INS
+ put(new MsgStatusProfile()); // 0x0204 CMD_PUMP_CALCULATION_SETTING
+ put(new MsgStatusTempBasal()); // 0x0205 CMD_PUMP_EXERCISE_MODE
+ put(new MsgStatusBolusExtended()); // 0x0207 CMD_PUMP_EXPANS_INS_I
+ put(new MsgStatusBasic()); // 0x020A CMD_PUMP_INITVIEW_I
+ put(new MsgStatus()); // 0x020B CMD_PUMP_STATUS
+ put(new MsgInitConnStatusTime()); // 0x0301 CMD_PUMPINIT_TIME_INFO
+ put(new MsgInitConnStatusBolus()); // 0x0302 CMD_PUMPINIT_BOLUS_INFO
+ put(new MsgInitConnStatusBasic()); // 0x0303 CMD_PUMPINIT_INIT_INFO
+ put(new MsgSetTempBasalStart()); // 0x0401 CMD_PUMPSET_EXERCISE_S
+ put(new MsgSetCarbsEntry()); // 0x0402 CMD_PUMPSET_HIS_S
+ put(new MsgSetTempBasalStop()); // 0x0403 CMD_PUMPSET_EXERCISE_STOP
+ put(new MsgSetExtendedBolusStop()); // 0x0406 CMD_PUMPSET_EXPANS_INS_STOP
+ put(new MsgSetExtendedBolusStart()); // 0x0407 CMD_PUMPSET_EXPANS_INS_S
+ put(new MsgError()); // 0x0601 CMD_PUMPOWAY_SYSTEM_STATUS
+ put(new MsgPCCommStart()); // 0x3001 CMD_CONNECT
+ put(new MsgPCCommStop()); // 0x3002 CMD_DISCONNECT
+ put(new MsgHistoryBolus()); // 0x3101 CMD_HISTORY_MEAL_INS
+ put(new MsgHistoryDailyInsulin()); // 0x3102 CMD_HISTORY_DAY_INS
+ put(new MsgHistoryGlucose()); // 0x3104 CMD_HISTORY_GLUCOSE
+ put(new MsgHistoryAlarm()); // 0x3105 CMD_HISTORY_ALARM
+ put(new MsgHistoryCarbo()); // 0x3107 CMD_HISTORY_CARBOHY
+ put(new MsgSettingBasal()); // 0x3202 CMD_SETTING_V_BASAL_INS_I
+ put(new MsgSettingMeal()); // 0x3203 CMD_SETTING_V_MEAL_SETTING_I
+ put(new MsgSettingProfileRatios()); // 0x3204 CMD_SETTING_V_CCC_I
+ put(new MsgSettingMaxValues()); // 0x3205 CMD_SETTING_V_MAX_VALUE_I
+ put(new MsgSettingBasalProfileAll()); // 0x3206 CMD_SETTING_V_BASAL_PROFILE_ALL
+ put(new MsgSettingShippingInfo()); // 0x3207 CMD_SETTING_V_SHIPPING_I
+ put(new MsgSettingGlucose()); // 0x3209 CMD_SETTING_V_GLUCOSEandEASY
+ put(new MsgSettingPumpTime()); // 0x320A CMD_SETTING_V_TIME_I
+ put(new MsgSetSingleBasalProfile()); // 0x3302 CMD_SETTING_BASAL_INS_S
+ put(new MsgHistoryAll()); // 0x41F2 CMD_HISTORY_ALL
+ put(new MsgHistoryNewDone()); // 0x42F1 CMD_HISTORY_NEW_DONE
+ put(new MsgHistoryNew()); // 0x42F2 CMD_HISTORY_NEW
+ put(new MsgCheckValue()); // 0xF0F1 CMD_PUMP_CHECK_VALUE
+ }
+ }
+
+ public static void put(MessageBase message) {
+ int command = message.getCommand();
+ //String name = MessageOriginalNames.getName(command);
+ messages.put(command, message);
+ //log.debug(String.format("%04x ", command) + " " + name);
+ }
+
+ public static MessageBase findMessage(Integer command) {
+ if (messages.containsKey(command)) {
+ return messages.get(command);
+ } else {
+ return new MessageBase();
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgCheckValue.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgCheckValue.java
new file mode 100644
index 0000000000..0a9ea6f2aa
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgCheckValue.java
@@ -0,0 +1,44 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+import info.nightscout.utils.ToastUtils;
+
+/**
+ * Created by mike on 30.06.2016.
+ */
+public class MsgCheckValue extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgCheckValue.class);
+
+ public MsgCheckValue() {
+ SetCommand(0xF0F1);
+ }
+
+ @Override
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump();
+
+ pump.model = intFromBuff(bytes, 0, 1);
+ pump.protocol = intFromBuff(bytes, 1, 1);
+ pump.productCode = intFromBuff(bytes, 2, 1);
+ if (pump.model != DanaRKoreanPump.DOMESTIC_MODEL) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(),MainApp.sResources.getString(R.string.wrongpumpdriverselected), R.raw.error);
+ ((DanaRKoreanPlugin)MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).doDisconnect("Wrong Model");
+ log.debug("Wrong model selected");
+ }
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Model: " + String.format("%02X ", pump.model));
+ log.debug("Protocol: " + String.format("%02X ", pump.protocol));
+ log.debug("Product Code: " + String.format("%02X ", pump.productCode));
+ }
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBasic.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBasic.java
new file mode 100644
index 0000000000..39f45d7843
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBasic.java
@@ -0,0 +1,49 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+
+public class MsgInitConnStatusBasic extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusBasic.class);
+
+ public MsgInitConnStatusBasic() {
+ SetCommand(0x0303);
+ }
+
+ @Override
+ public void handleMessage(byte[] bytes) {
+ if (bytes.length - 10 > 6) {
+ return;
+ }
+ DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump();
+ int isStatusSuspendOn = intFromBuff(bytes, 0, 1);
+ int isUtilityEnable = intFromBuff(bytes, 1, 1);
+ pump.isEasyModeEnabled = intFromBuff(bytes, 2, 1) == 1;
+ int easyUIMode = intFromBuff(bytes, 3, 1);
+ pump.password = intFromBuff(bytes, 4, 2) ^ 0x3463;
+ if (Config.logDanaMessageDetail) {
+ log.debug("isStatusSuspendOn: " + isStatusSuspendOn);
+ log.debug("isUtilityEnable: " + isUtilityEnable);
+ log.debug("Is EasyUI Enabled: " + pump.isEasyModeEnabled);
+ log.debug("easyUIMode: " + easyUIMode);
+ log.debug("Pump password: " + pump.password);
+ }
+
+ if (pump.isEasyModeEnabled) {
+ Notification notification = new Notification(Notification.EASYMODE_ENABLED, MainApp.sResources.getString(R.string.danar_disableeasymode), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.EASYMODE_ENABLED));
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBolus.java
new file mode 100644
index 0000000000..b391fe11e3
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBolus.java
@@ -0,0 +1,54 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+
+/**
+ * Created by mike on 28.05.2016.
+ */
+public class MsgInitConnStatusBolus extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusBolus.class);
+
+ public MsgInitConnStatusBolus() {
+ SetCommand(0x0302);
+ }
+
+ @Override
+ public void handleMessage(byte[] bytes) {
+ if (bytes.length - 10 < 13) {
+ return;
+ }
+ DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump();
+ int bolusConfig = intFromBuff(bytes, 0, 1);
+ pump.isExtendedBolusEnabled = (bolusConfig & 0x01) != 0;
+
+ pump.bolusStep = intFromBuff(bytes, 1, 1) / 100d;
+ pump.maxBolus = intFromBuff(bytes, 2, 2) / 100d;
+ //int bolusRate = intFromBuff(bytes, 4, 8);
+ int deliveryStatus = intFromBuff(bytes, 12, 1);
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Is Extended bolus enabled: " + pump.isExtendedBolusEnabled);
+ log.debug("Bolus increment: " + pump.bolusStep);
+ log.debug("Bolus max: " + pump.maxBolus);
+ log.debug("Delivery status: " + deliveryStatus);
+ }
+
+ if (!pump.isExtendedBolusEnabled) {
+ Notification notification = new Notification(Notification.EXTENDED_BOLUS_DISABLED, MainApp.sResources.getString(R.string.danar_enableextendedbolus), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.EXTENDED_BOLUS_DISABLED));
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusTime.java
new file mode 100644
index 0000000000..5e904a493b
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusTime.java
@@ -0,0 +1,62 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.events.EventRefreshGui;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.utils.ToastUtils;
+
+public class MsgInitConnStatusTime extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgInitConnStatusTime.class);
+
+ public MsgInitConnStatusTime() {
+ SetCommand(0x0301);
+ }
+
+ @Override
+ public void handleMessage(byte[] bytes) {
+
+ if (bytes.length - 10 < 10) {
+ ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(),MainApp.sResources.getString(R.string.wrongpumpdriverselected), R.raw.error);
+ ((DanaRKoreanPlugin)MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).doDisconnect("Wrong Model");
+ log.debug("Wrong model selected. Switching to export DanaR");
+ ((DanaRKoreanPlugin)MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).setFragmentEnabled(PluginBase.PUMP, false);
+ ((DanaRKoreanPlugin)MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).setFragmentVisible(PluginBase.PUMP, false);
+ ((DanaRPlugin)MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentEnabled(PluginBase.PUMP, true);
+ ((DanaRPlugin)MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentVisible(PluginBase.PUMP, true);
+
+ //If profile coming from pump, switch it as well
+ if(MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isEnabled(PluginBase.PROFILE)){
+ (MainApp.getSpecificPlugin(DanaRKoreanPlugin.class)).setFragmentEnabled(PluginBase.PROFILE, false);
+ (MainApp.getSpecificPlugin(DanaRPlugin.class)).setFragmentEnabled(PluginBase.PROFILE, true);
+ }
+
+ MainApp.getConfigBuilder().storeSettings();
+ MainApp.bus().post(new EventRefreshGui(false));
+ return;
+ }
+
+ Date time = dateTimeSecFromBuff(bytes, 0);
+ int versionCode1 = intFromBuff(bytes, 6, 1);
+ int versionCode2 = intFromBuff(bytes, 7, 1);
+ int versionCode3 = intFromBuff(bytes, 8, 1);
+ int versionCode4 = intFromBuff(bytes, 9, 1);
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Pump time: " + time);
+ log.debug("Version code1: " + versionCode1);
+ log.debug("Version code2: " + versionCode2);
+ log.debug("Version code3: " + versionCode3);
+ log.debug("Version code4: " + versionCode4);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingBasal.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingBasal.java
new file mode 100644
index 0000000000..e6ac4b9003
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingBasal.java
@@ -0,0 +1,36 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+/**
+ * Created by mike on 05.07.2016.
+ */
+public class MsgSettingBasal extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingBasal.class);
+
+ public MsgSettingBasal() {
+ SetCommand(0x3202);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump();
+ if (pump.pumpProfiles == null) pump.pumpProfiles = new double[4][];
+ pump.pumpProfiles[pump.activeProfile] = new double[24];
+ for (int index = 0; index < 24; index++) {
+ int basal = intFromBuff(bytes, 2 * index, 2);
+ if (basal < 10) basal = 0;
+ pump.pumpProfiles[pump.activeProfile][index] = basal / 100d;
+ }
+
+ if (Config.logDanaMessageDetail)
+ for (int index = 0; index < 24; index++) {
+ log.debug("Basal " + String.format("%02d", index) + "h: " + DanaRKoreanPlugin.getDanaRPump().pumpProfiles[DanaRKoreanPlugin.getDanaRPump().activeProfile][index]);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingBasalProfileAll.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingBasalProfileAll.java
new file mode 100644
index 0000000000..9397ed86c6
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingBasalProfileAll.java
@@ -0,0 +1,73 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+
+/**
+ * Created by mike on 05.07.2016.
+ *
+ *
+ * THIS IS BROKEN IN PUMP... SENDING ONLY 1 PROFILE
+ */
+public class MsgSettingBasalProfileAll extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingBasalProfileAll.class);
+
+ public MsgSettingBasalProfileAll() {
+ SetCommand(0x3206);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump();
+ if (DanaRKoreanPlugin.getDanaRPump().basal48Enable) {
+ pump.pumpProfiles = new double[4][];
+ for (int profile = 0; profile < 4; profile++) {
+ int position = intFromBuff(bytes, 107 * profile, 1);
+ pump.pumpProfiles[position] = new double[48];
+ for (int index = 0; index < 48; index++) {
+ int basal = intFromBuff(bytes, 107 * profile + 2 * index + 1, 2);
+ if (basal < 10) basal = 0;
+ pump.pumpProfiles[position][index] = basal / 100 / 24d; // in units/day
+ }
+ }
+ } else {
+ pump.pumpProfiles = new double[4][];
+ for (int profile = 0; profile < 4; profile++) {
+ int position = intFromBuff(bytes, 49 * profile, 1);
+ log.debug("position " + position);
+ pump.pumpProfiles[position] = new double[24];
+ for (int index = 0; index < 24; index++) {
+ int basal = intFromBuff(bytes, 59 * profile + 2 * index + 1, 2);
+ if (basal < 10) basal = 0;
+ log.debug("position " + position + " index " + index);
+ pump.pumpProfiles[position][index] = basal / 100 / 24d; // in units/day
+ }
+ }
+ }
+
+ if (Config.logDanaMessageDetail) {
+ if (DanaRKoreanPlugin.getDanaRPump().basal48Enable) {
+ for (int profile = 0; profile < 4; profile++) {
+ for (int index = 0; index < 24; index++) {
+ log.debug("Basal profile " + profile + ": " + String.format("%02d", index) + "h: " + DanaRKoreanPlugin.getDanaRPump().pumpProfiles[profile][index]);
+ }
+ }
+ } else {
+ for (int profile = 0; profile < 4; profile++) {
+ for (int index = 0; index < 48; index++) {
+ log.debug("Basal profile " + profile + ": " +
+ String.format("%02d", (index / 2)) +
+ ":" + String.format("%02d", (index % 2) * 30) + " : " +
+ DanaRKoreanPlugin.getDanaRPump().pumpProfiles[profile][index]);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingGlucose.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingGlucose.java
new file mode 100644
index 0000000000..8ebc972495
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingGlucose.java
@@ -0,0 +1,30 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+/**
+ * Created by mike on 05.07.2016.
+ */
+public class MsgSettingGlucose extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingGlucose.class);
+
+ public MsgSettingGlucose() {
+ SetCommand(0x3209);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPlugin.getDanaRPump().units = intFromBuff(bytes, 0, 1);
+ DanaRKoreanPlugin.getDanaRPump().easyBasalMode = intFromBuff(bytes, 1, 1);
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Pump units: " + (DanaRKoreanPlugin.getDanaRPump().units == DanaRKoreanPump.UNITS_MGDL ? "MGDL" : "MMOL"));
+ log.debug("Easy basal mode: " + DanaRKoreanPlugin.getDanaRPump().easyBasalMode);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingMaxValues.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingMaxValues.java
new file mode 100644
index 0000000000..428881e715
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingMaxValues.java
@@ -0,0 +1,33 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+
+
+/**
+ * Created by mike on 05.07.2016.
+ */
+public class MsgSettingMaxValues extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingMaxValues.class);
+
+ public MsgSettingMaxValues() {
+ SetCommand(0x3205);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPlugin.getDanaRPump().maxBolus = intFromBuff(bytes, 0, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().maxBasal = intFromBuff(bytes, 2, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().maxDailyTotalUnits = intFromBuff(bytes, 4, 2) / 100;
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Max bolus: " + DanaRKoreanPlugin.getDanaRPump().maxBolus);
+ log.debug("Max basal: " + DanaRKoreanPlugin.getDanaRPump().maxBasal);
+ log.debug("Total daily max units: " + DanaRKoreanPlugin.getDanaRPump().maxDailyTotalUnits);
+ }
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingMeal.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingMeal.java
new file mode 100644
index 0000000000..488cf3becf
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingMeal.java
@@ -0,0 +1,55 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaR.DanaRPump;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+import info.nightscout.androidaps.plugins.Overview.Notification;
+import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
+
+/**
+ * Created by mike on 13.12.2016.
+ */
+
+public class MsgSettingMeal extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingMeal.class);
+
+ public MsgSettingMeal() {
+ SetCommand(0x3203);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump();
+ pump.basalStep = intFromBuff(bytes, 0, 1) / 100d;
+ pump.bolusStep = intFromBuff(bytes, 1, 1) / 100d;
+ boolean bolusEnabled = intFromBuff(bytes, 2, 1) == 1;
+ int melodyTime = intFromBuff(bytes, 3, 1);
+ int blockTime = intFromBuff(bytes, 4, 1);
+ pump.isConfigUD = intFromBuff(bytes, 5, 1) == 1;
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Basal step: " + pump.basalStep);
+ log.debug("Bolus step: " + pump.bolusStep);
+ log.debug("Bolus enabled: " + bolusEnabled);
+ log.debug("Melody time: " + melodyTime);
+ log.debug("Block time: " + blockTime);
+ log.debug("Is Config U/d: " + pump.isConfigUD);
+ }
+
+ if (pump.isConfigUD) {
+ Notification notification = new Notification(Notification.UD_MODE_ENABLED, MainApp.sResources.getString(R.string.danar_switchtouhmode), Notification.URGENT);
+ MainApp.bus().post(new EventNewNotification(notification));
+ } else {
+ MainApp.bus().post(new EventDismissNotification(Notification.UD_MODE_ENABLED));
+ }
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingProfileRatios.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingProfileRatios.java
new file mode 100644
index 0000000000..e023c1bb5b
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingProfileRatios.java
@@ -0,0 +1,45 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+/**
+ * Created by mike on 05.07.2016.
+ */
+public class MsgSettingProfileRatios extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingProfileRatios.class);
+
+ public MsgSettingProfileRatios() {
+ SetCommand(0x3204);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ if (DanaRKoreanPlugin.getDanaRPump().units == DanaRKoreanPump.UNITS_MGDL) {
+ DanaRKoreanPlugin.getDanaRPump().currentCIR = intFromBuff(bytes, 0, 2);
+ DanaRKoreanPlugin.getDanaRPump().currentCF = intFromBuff(bytes, 2, 2);
+ DanaRKoreanPlugin.getDanaRPump().currentAI = intFromBuff(bytes, 4, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().currentTarget = intFromBuff(bytes, 6, 2);
+ DanaRKoreanPlugin.getDanaRPump().currentAIDR = intFromBuff(bytes, 8, 1);
+ } else {
+ DanaRKoreanPlugin.getDanaRPump().currentCIR = intFromBuff(bytes, 0, 2);
+ DanaRKoreanPlugin.getDanaRPump().currentCF = intFromBuff(bytes, 2, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().currentAI = intFromBuff(bytes, 4, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().currentTarget = intFromBuff(bytes, 6, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().currentAIDR = intFromBuff(bytes, 8, 1);
+ }
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Pump units (saved): " + (DanaRKoreanPlugin.getDanaRPump().units == DanaRKoreanPump.UNITS_MGDL ? "MGDL" : "MMOL"));
+ log.debug("Current pump CIR: " + DanaRKoreanPlugin.getDanaRPump().currentCIR);
+ log.debug("Current pump CF: " + DanaRKoreanPlugin.getDanaRPump().currentCF);
+ log.debug("Current pump AI: " + DanaRKoreanPlugin.getDanaRPump().currentAI);
+ log.debug("Current pump target: " + DanaRKoreanPlugin.getDanaRPump().currentTarget);
+ log.debug("Current pump AIDR: " + DanaRKoreanPlugin.getDanaRPump().currentAIDR);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingPumpTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingPumpTime.java
new file mode 100644
index 0000000000..359ffb924e
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingPumpTime.java
@@ -0,0 +1,35 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+
+public class MsgSettingPumpTime extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingPumpTime.class);
+
+ public MsgSettingPumpTime() {
+ SetCommand(0x320A);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ Date time =
+ new Date(
+ 100 + intFromBuff(bytes, 5, 1),
+ intFromBuff(bytes, 4, 1) - 1,
+ intFromBuff(bytes, 3, 1),
+ intFromBuff(bytes, 2, 1),
+ intFromBuff(bytes, 1, 1),
+ intFromBuff(bytes, 0, 1)
+ );
+
+ if (Config.logDanaMessageDetail)
+ log.debug("Pump time: " + time);
+
+ DanaRKoreanPlugin.getDanaRPump().pumpTime = time;
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingShippingInfo.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingShippingInfo.java
new file mode 100644
index 0000000000..4d10aef389
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgSettingShippingInfo.java
@@ -0,0 +1,39 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+/**
+ * Created by mike on 05.07.2016.
+ */
+public class MsgSettingShippingInfo extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgSettingShippingInfo.class);
+
+ public MsgSettingShippingInfo() {
+ SetCommand(0x3207);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump();
+ pump.serialNumber = stringFromBuff(bytes, 0, 10);
+ pump.shippingDate = dateFromBuff(bytes, 10);
+ pump.shippingCountry = asciiStringFromBuff(bytes, 13, 3);
+ if (pump.shippingDate.getTime() > new Date(116, 4, 1).getTime()) {
+ pump.isNewPump = true;
+ } else
+ pump.isNewPump = false;
+ if (Config.logDanaMessageDetail) {
+ log.debug("Serial number: " + pump.serialNumber);
+ log.debug("Shipping date: " + pump.shippingDate);
+ log.debug("Shipping country: " + pump.shippingCountry);
+ }
+ }
+}
+
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatus.java
new file mode 100644
index 0000000000..bb4adaa58e
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatus.java
@@ -0,0 +1,39 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+
+public class MsgStatus extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgStatus.class);
+
+ public MsgStatus() {
+ SetCommand(0x020B);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ DanaRKoreanPlugin.getDanaRPump().dailyTotalUnits = intFromBuff(bytes, 0, 3) / 750d;
+ DanaRKoreanPlugin.getDanaRPump().isExtendedInProgress = intFromBuff(bytes, 3, 1) == 1;
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusMinutes = intFromBuff(bytes, 4, 2);
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusAmount = intFromBuff(bytes, 6, 2) / 100d;
+ Double lastBolusAmount = intFromBuff(bytes, 13, 2) / 100d;
+// if (lastBolusAmount != 0d) {
+// DanaRKoreanPlugin.getDanaRPump().lastBolusTime = dateTimeFromBuff(bytes, 8);
+// DanaRKoreanPlugin.getDanaRPump().lastBolusAmount = lastBolusAmount;
+// }
+ DanaRKoreanPlugin.getDanaRPump().iob = intFromBuff(bytes, 15, 2) / 100d;
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Daily total: " + DanaRKoreanPlugin.getDanaRPump().dailyTotalUnits);
+ log.debug("Is extended bolus running: " + DanaRKoreanPlugin.getDanaRPump().isExtendedInProgress);
+ log.debug("Extended bolus min: " + DanaRKoreanPlugin.getDanaRPump().extendedBolusMinutes);
+ log.debug("Extended bolus amount: " + DanaRKoreanPlugin.getDanaRPump().extendedBolusAmount);
+// log.debug("Last bolus time: " + DanaRKoreanPlugin.getDanaRPump().lastBolusTime);
+// log.debug("Last bolus amount: " + DanaRKoreanPlugin.getDanaRPump().lastBolusAmount);
+ log.debug("IOB: " + DanaRKoreanPlugin.getDanaRPump().iob);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusBasic.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusBasic.java
new file mode 100644
index 0000000000..46a230b184
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusBasic.java
@@ -0,0 +1,38 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+
+
+public class MsgStatusBasic extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgStatusBasic.class);
+
+ public MsgStatusBasic() {
+ SetCommand(0x020A);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ double currentBasal = intFromBuff(bytes, 0, 2) / 100d;
+ int batteryRemaining = intFromBuff(bytes, 2, 1);
+ double reservoirRemainingUnits = intFromBuff(bytes, 3, 3) / 750d;
+ double dailyTotalUnits = intFromBuff(bytes, 6, 3) / 750d;
+ int maxDailyTotalUnits = intFromBuff(bytes, 9, 2) / 100;
+
+ DanaRKoreanPlugin.getDanaRPump().dailyTotalUnits = dailyTotalUnits;
+ DanaRKoreanPlugin.getDanaRPump().maxDailyTotalUnits = maxDailyTotalUnits;
+ DanaRKoreanPlugin.getDanaRPump().reservoirRemainingUnits = reservoirRemainingUnits;
+ DanaRKoreanPlugin.getDanaRPump().currentBasal = currentBasal;
+ DanaRKoreanPlugin.getDanaRPump().batteryRemaining = batteryRemaining;
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Daily total units: " + dailyTotalUnits);
+ log.debug("Max daily total units: " + maxDailyTotalUnits);
+ log.debug("Reservoir remaining units: " + reservoirRemainingUnits);
+ log.debug("Current basal: " + currentBasal);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusBolusExtended.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusBolusExtended.java
new file mode 100644
index 0000000000..1c740fd960
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusBolusExtended.java
@@ -0,0 +1,114 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import android.support.annotation.NonNull;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+import java.util.Date;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.db.TempBasal;
+import info.nightscout.androidaps.events.EventTempBasalChange;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+public class MsgStatusBolusExtended extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgStatusBolusExtended.class);
+
+ public MsgStatusBolusExtended() {
+ SetCommand(0x0207);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ boolean isExtendedInProgress = intFromBuff(bytes, 0, 1) == 1;
+ int extendedBolusHalfHours = intFromBuff(bytes, 1, 1);
+ int extendedBolusMinutes = extendedBolusHalfHours * 30;
+
+ double extendedBolusAmount = intFromBuff(bytes, 2, 2) / 100d;
+ int extendedBolusSoFarInSecs = intFromBuff(bytes, 4, 3);
+ int extendedBolusDeliveryPulse = intFromBuff(bytes, 7, 2);
+ int isEasyUIUserSleep = intFromBuff(bytes, 9, 1);
+
+ int extendedBolusSoFarInMinutes = extendedBolusSoFarInSecs / 60;
+ double extendedBolusAbsoluteRate = isExtendedInProgress ? extendedBolusAmount / extendedBolusMinutes * 60 : 0d;
+ Date extendedBolusStart = isExtendedInProgress ? getDateFromSecAgo(extendedBolusSoFarInSecs) : new Date(0);
+ int extendedBolusRemainingMinutes = extendedBolusMinutes - extendedBolusSoFarInMinutes;
+
+ DanaRKoreanPlugin.getDanaRPump().isExtendedInProgress = isExtendedInProgress;
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusMinutes = extendedBolusMinutes;
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusAmount = extendedBolusAmount;
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusSoFarInMinutes = extendedBolusSoFarInMinutes;
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusAbsoluteRate = extendedBolusAbsoluteRate;
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusStart = extendedBolusStart;
+ DanaRKoreanPlugin.getDanaRPump().extendedBolusRemainingMinutes = extendedBolusRemainingMinutes;
+
+ updateExtendedBolusInDB();
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Is extended bolus running: " + isExtendedInProgress);
+ log.debug("Extended bolus min: " + extendedBolusMinutes);
+ log.debug("Extended bolus amount: " + extendedBolusAmount);
+ log.debug("Extended bolus so far in minutes: " + extendedBolusSoFarInMinutes);
+ log.debug("Extended bolus absolute rate: " + extendedBolusAbsoluteRate);
+ log.debug("Extended bolus start: " + extendedBolusStart);
+ log.debug("Extended bolus remaining minutes: " + extendedBolusRemainingMinutes);
+ }
+ }
+
+ @NonNull
+ private Date getDateFromSecAgo(int tempBasalAgoSecs) {
+ return new Date((long) (Math.ceil(new Date().getTime() / 1000d) - tempBasalAgoSecs) * 1000);
+ }
+
+ public static void updateExtendedBolusInDB() {
+ DanaRKoreanPlugin DanaRKoreanPlugin = (DanaRKoreanPlugin) MainApp.getSpecificPlugin(DanaRKoreanPlugin.class);
+ DanaRKoreanPump danaRKoreanPump = DanaRKoreanPlugin.getDanaRPump();
+ Date now = new Date();
+
+ try {
+
+ if (DanaRKoreanPlugin.isExtendedBoluslInProgress()) {
+ TempBasal extendedBolus = DanaRKoreanPlugin.getExtendedBolus();
+ if (danaRKoreanPump.isExtendedInProgress) {
+ if (extendedBolus.absolute != danaRKoreanPump.extendedBolusAbsoluteRate) {
+ // Close current extended
+ extendedBolus.timeEnd = now;
+ MainApp.getDbHelper().getDaoTempBasals().update(extendedBolus);
+ // Create new
+ TempBasal newExtended = new TempBasal();
+ newExtended.timeStart = now;
+ newExtended.absolute = danaRKoreanPump.extendedBolusAbsoluteRate;
+ newExtended.isAbsolute = true;
+ newExtended.duration = danaRKoreanPump.extendedBolusMinutes;
+ newExtended.isExtended = true;
+ MainApp.getDbHelper().getDaoTempBasals().create(newExtended);
+ MainApp.bus().post(new EventTempBasalChange());
+ }
+ } else {
+ // Close curent temp basal
+ extendedBolus.timeEnd = now;
+ MainApp.getDbHelper().getDaoTempBasals().update(extendedBolus);
+ MainApp.bus().post(new EventTempBasalChange());
+ }
+ } else {
+ if (danaRKoreanPump.isExtendedInProgress) {
+ // Create new
+ TempBasal newExtended = new TempBasal();
+ newExtended.timeStart = now;
+ newExtended.absolute = danaRKoreanPump.extendedBolusAbsoluteRate;
+ newExtended.isAbsolute = true;
+ newExtended.duration = danaRKoreanPump.extendedBolusMinutes;
+ newExtended.isExtended = true;
+ MainApp.getDbHelper().getDaoTempBasals().create(newExtended);
+ MainApp.bus().post(new EventTempBasalChange());
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusProfile.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusProfile.java
new file mode 100644
index 0000000000..7af3260b3a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusProfile.java
@@ -0,0 +1,43 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+/**
+ * Created by mike on 05.07.2016.
+ */
+public class MsgStatusProfile extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgStatusProfile.class);
+
+ public MsgStatusProfile() {
+ SetCommand(0x0204);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ if (DanaRKoreanPlugin.getDanaRPump().units == DanaRKoreanPump.UNITS_MGDL) {
+ DanaRKoreanPlugin.getDanaRPump().currentCIR = intFromBuff(bytes, 0, 2);
+ DanaRKoreanPlugin.getDanaRPump().currentCF = intFromBuff(bytes, 2, 2);
+ DanaRKoreanPlugin.getDanaRPump().currentAI = intFromBuff(bytes, 4, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().currentTarget = intFromBuff(bytes, 6, 2);
+ } else {
+ DanaRKoreanPlugin.getDanaRPump().currentCIR = intFromBuff(bytes, 0, 2);
+ DanaRKoreanPlugin.getDanaRPump().currentCF = intFromBuff(bytes, 2, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().currentAI = intFromBuff(bytes, 4, 2) / 100d;
+ DanaRKoreanPlugin.getDanaRPump().currentTarget = intFromBuff(bytes, 6, 2) / 100d;
+ }
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Pump units (saved): " + (DanaRKoreanPlugin.getDanaRPump().units == DanaRKoreanPump.UNITS_MGDL ? "MGDL" : "MMOL"));
+ log.debug("Current pump CIR: " + DanaRKoreanPlugin.getDanaRPump().currentCIR);
+ log.debug("Current pump CF: " + DanaRKoreanPlugin.getDanaRPump().currentCF);
+ log.debug("Current pump AI: " + DanaRKoreanPlugin.getDanaRPump().currentAI);
+ log.debug("Current pump target: " + DanaRKoreanPlugin.getDanaRPump().currentTarget);
+ log.debug("Current pump AIDR: " + DanaRKoreanPlugin.getDanaRPump().currentAIDR);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusTempBasal.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusTempBasal.java
new file mode 100644
index 0000000000..4506bb944a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgStatusTempBasal.java
@@ -0,0 +1,103 @@
+package info.nightscout.androidaps.plugins.DanaRKorean.comm;
+
+import android.support.annotation.NonNull;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+import java.util.Date;
+
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.db.TempBasal;
+import info.nightscout.androidaps.events.EventTempBasalChange;
+import info.nightscout.androidaps.plugins.DanaR.comm.MessageBase;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPump;
+
+public class MsgStatusTempBasal extends MessageBase {
+ private static Logger log = LoggerFactory.getLogger(MsgStatusTempBasal.class);
+
+ public MsgStatusTempBasal() {
+ SetCommand(0x0205);
+ }
+
+ public void handleMessage(byte[] bytes) {
+ boolean isTempBasalInProgress = intFromBuff(bytes, 0, 1) == 1;
+ int tempBasalPercent = intFromBuff(bytes, 1, 1);
+ int tempBasalTotalSec = intFromBuff(bytes, 2, 1) * 60 * 60;
+ int tempBasalRunningSeconds = intFromBuff(bytes, 3, 3);
+ int tempBasalRemainingMin = (tempBasalTotalSec - tempBasalRunningSeconds) / 60;
+ Date tempBasalStart = isTempBasalInProgress ? getDateFromTempBasalSecAgo(tempBasalRunningSeconds) : new Date(0);
+
+ DanaRKoreanPlugin.getDanaRPump().isTempBasalInProgress = isTempBasalInProgress;
+ DanaRKoreanPlugin.getDanaRPump().tempBasalPercent = tempBasalPercent;
+ DanaRKoreanPlugin.getDanaRPump().tempBasalRemainingMin = tempBasalRemainingMin;
+ DanaRKoreanPlugin.getDanaRPump().tempBasalTotalSec = tempBasalTotalSec;
+ DanaRKoreanPlugin.getDanaRPump().tempBasalStart = tempBasalStart;
+
+ updateTempBasalInDB();
+
+ if (Config.logDanaMessageDetail) {
+ log.debug("Is temp basal running: " + isTempBasalInProgress);
+ log.debug("Current temp basal percent: " + tempBasalPercent);
+ log.debug("Current temp basal remaining min: " + tempBasalRemainingMin);
+ log.debug("Current temp basal total sec: " + tempBasalTotalSec);
+ log.debug("Current temp basal start: " + tempBasalStart);
+ }
+ }
+
+ @NonNull
+ private Date getDateFromTempBasalSecAgo(int tempBasalAgoSecs) {
+ return new Date((long) (Math.ceil(new Date().getTime() / 1000d) - tempBasalAgoSecs) * 1000);
+ }
+
+ public static void updateTempBasalInDB() {
+ DanaRKoreanPlugin DanaRKoreanPlugin = (DanaRKoreanPlugin) MainApp.getSpecificPlugin(DanaRKoreanPlugin.class);
+ DanaRKoreanPump danaRKoreanPump = DanaRKoreanPlugin.getDanaRPump();
+ Date now = new Date();
+
+ try {
+
+ if (DanaRKoreanPlugin.isRealTempBasalInProgress()) {
+ TempBasal tempBasal = DanaRKoreanPlugin.getRealTempBasal();
+ if (danaRKoreanPump.isTempBasalInProgress) {
+ if (tempBasal.percent != danaRKoreanPump.tempBasalPercent) {
+ // Close current temp basal
+ tempBasal.timeEnd = now;
+ MainApp.getDbHelper().getDaoTempBasals().update(tempBasal);
+ // Create new
+ TempBasal newTempBasal = new TempBasal();
+ newTempBasal.timeStart = now;
+ newTempBasal.percent = danaRKoreanPump.tempBasalPercent;
+ newTempBasal.isAbsolute = false;
+ newTempBasal.duration = danaRKoreanPump.tempBasalTotalSec / 60;
+ newTempBasal.isExtended = false;
+ MainApp.getDbHelper().getDaoTempBasals().create(newTempBasal);
+ MainApp.bus().post(new EventTempBasalChange());
+ }
+ } else {
+ // Close current temp basal
+ tempBasal.timeEnd = now;
+ MainApp.getDbHelper().getDaoTempBasals().update(tempBasal);
+ MainApp.bus().post(new EventTempBasalChange());
+ }
+ } else {
+ if (danaRKoreanPump.isTempBasalInProgress) {
+ // Create new
+ TempBasal newTempBasal = new TempBasal();
+ newTempBasal.timeStart = now;
+ newTempBasal.percent = danaRKoreanPump.tempBasalPercent;
+ newTempBasal.isAbsolute = false;
+ newTempBasal.duration = danaRKoreanPump.tempBasalTotalSec / 60;
+ newTempBasal.isExtended = false;
+ MainApp.getDbHelper().getDaoTempBasals().create(newTempBasal);
+ MainApp.bus().post(new EventTempBasalChange());
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java
index 329cc7e4d7..94676f8f3e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java
@@ -24,9 +24,12 @@ import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui;
public class LoopFragment extends Fragment implements View.OnClickListener, FragmentBase {
private static Logger log = LoggerFactory.getLogger(LoopFragment.class);
- private static LoopPlugin loopPlugin = new LoopPlugin();
+ private static LoopPlugin loopPlugin;
public static LoopPlugin getPlugin() {
+ if (loopPlugin == null){
+ loopPlugin = new LoopPlugin();
+ }
return loopPlugin;
}
@@ -73,7 +76,7 @@ public class LoopFragment extends Fragment implements View.OnClickListener, Frag
public void onClick(View view) {
switch (view.getId()) {
case R.id.loop_run:
- loopPlugin.invoke(true);
+ getPlugin().invoke(true);
break;
}
@@ -104,13 +107,13 @@ public class LoopFragment extends Fragment implements View.OnClickListener, Frag
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
- if (loopPlugin.lastRun != null) {
- requestView.setText(loopPlugin.lastRun.request != null ? loopPlugin.lastRun.request.toSpanned() : "");
- constraintsProcessedView.setText(loopPlugin.lastRun.constraintsProcessed != null ? loopPlugin.lastRun.constraintsProcessed.toSpanned() : "");
- setByPumpView.setText(loopPlugin.lastRun.setByPump != null ? loopPlugin.lastRun.setByPump.toSpanned() : "");
- sourceView.setText(loopPlugin.lastRun.source != null ? loopPlugin.lastRun.source : "");
- lastRunView.setText(loopPlugin.lastRun.lastAPSRun != null && loopPlugin.lastRun.lastAPSRun.getTime() != 0 ? loopPlugin.lastRun.lastAPSRun.toLocaleString() : "");
- lastEnactView.setText(loopPlugin.lastRun.lastEnact != null && loopPlugin.lastRun.lastEnact.getTime() != 0 ? loopPlugin.lastRun.lastEnact.toLocaleString() : "");
+ if (getPlugin().lastRun != null) {
+ requestView.setText(getPlugin().lastRun.request != null ? getPlugin().lastRun.request.toSpanned() : "");
+ constraintsProcessedView.setText(getPlugin().lastRun.constraintsProcessed != null ? getPlugin().lastRun.constraintsProcessed.toSpanned() : "");
+ setByPumpView.setText(getPlugin().lastRun.setByPump != null ? getPlugin().lastRun.setByPump.toSpanned() : "");
+ sourceView.setText(getPlugin().lastRun.source != null ? getPlugin().lastRun.source : "");
+ lastRunView.setText(getPlugin().lastRun.lastAPSRun != null && getPlugin().lastRun.lastAPSRun.getTime() != 0 ? getPlugin().lastRun.lastAPSRun.toLocaleString() : "");
+ lastEnactView.setText(getPlugin().lastRun.lastEnact != null && getPlugin().lastRun.lastEnact.getTime() != 0 ? getPlugin().lastRun.lastEnact.toLocaleString() : "");
}
}
});
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java
index 3051bf3138..d84bbb1017 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java
@@ -83,12 +83,12 @@ public class LoopPlugin implements PluginBase {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == LOOP && fragmentEnabled && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == LOOP && fragmentVisible && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
@Override
@@ -98,12 +98,12 @@ public class LoopPlugin implements PluginBase {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == LOOP) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == LOOP) this.fragmentVisible = fragmentVisible;
}
@Subscribe
@@ -128,7 +128,7 @@ public class LoopPlugin implements PluginBase {
final ConfigBuilderPlugin configBuilder = MainApp.getConfigBuilder();
APSResult result = null;
- if (configBuilder == null || !isEnabled(PluginBase.GENERAL))
+ if (configBuilder == null || !isEnabled(PluginBase.LOOP))
return;
// Check if pump info is loaded
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/MDI/MDIFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/MDI/MDIFragment.java
new file mode 100644
index 0000000000..a67f68dfb3
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/MDI/MDIFragment.java
@@ -0,0 +1,33 @@
+package info.nightscout.androidaps.plugins.MDI;
+
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.squareup.otto.Subscribe;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.interfaces.FragmentBase;
+import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpPlugin;
+import info.nightscout.androidaps.plugins.VirtualPump.events.EventVirtualPumpUpdateGui;
+
+public class MDIFragment extends Fragment implements FragmentBase {
+ private static Logger log = LoggerFactory.getLogger(MDIFragment.class);
+
+ private static MDIPlugin mdiPlugin = new MDIPlugin();
+
+ public static MDIPlugin getPlugin() {
+ return mdiPlugin;
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/MDI/MDIPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/MDI/MDIPlugin.java
new file mode 100644
index 0000000000..7676086de2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/MDI/MDIPlugin.java
@@ -0,0 +1,259 @@
+package info.nightscout.androidaps.plugins.MDI;
+
+import android.content.Context;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+import java.util.Date;
+
+import info.nightscout.androidaps.BuildConfig;
+import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.db.TempBasal;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.PumpDescription;
+import info.nightscout.androidaps.interfaces.PumpInterface;
+import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
+import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpFragment;
+import info.nightscout.androidaps.plugins.VirtualPump.events.EventVirtualPumpUpdateGui;
+import info.nightscout.client.data.NSProfile;
+import info.nightscout.utils.DateUtil;
+
+/**
+ * Created by mike on 05.08.2016.
+ */
+public class MDIPlugin implements PluginBase, PumpInterface {
+ private static Logger log = LoggerFactory.getLogger(MDIPlugin.class);
+
+ boolean fragmentEnabled = false;
+ boolean fragmentVisible = false;
+
+ PumpDescription pumpDescription = new PumpDescription();
+
+ public MDIPlugin() {
+ pumpDescription.isBolusCapable = true;
+ pumpDescription.bolusStep = 0.5d;
+
+ pumpDescription.isExtendedBolusCapable = false;
+ pumpDescription.extendedBolusStep = 0d;
+
+ pumpDescription.isTempBasalCapable = false;
+ pumpDescription.lowTempBasalStyle = PumpDescription.NONE;
+ pumpDescription.highTempBasalStyle = PumpDescription.NONE;
+ pumpDescription.maxHighTempPercent = 0;
+ pumpDescription.maxHighTempAbsolute = 0;
+ pumpDescription.lowTempPercentStep = 0;
+ pumpDescription.lowTempAbsoluteStep = 0;
+ pumpDescription.lowTempPercentDuration = 0;
+ pumpDescription.lowTempAbsoluteDuration = 0;
+ pumpDescription.highTempPercentStep = 0;
+ pumpDescription.highTempAbsoluteStep = 0d;
+ pumpDescription.highTempPercentDuration = 0;
+ pumpDescription.highTempAbsoluteDuration = 0;
+
+ pumpDescription.isSetBasalProfileCapable = true;
+ pumpDescription.basalStep = 0d;
+ pumpDescription.basalMinimumRate = 0d;
+
+ pumpDescription.isRefillingCapable = false;
+ }
+
+ @Override
+ public String getFragmentClass() {
+ return MDIFragment.class.getName();
+ }
+
+ @Override
+ public String getName() {
+ return MainApp.instance().getString(R.string.mdi);
+ }
+
+ @Override
+ public boolean isEnabled(int type) {
+ return type == PUMP && fragmentEnabled;
+ }
+
+ @Override
+ public boolean isVisibleInTabs(int type) {
+ return false;
+ }
+
+ @Override
+ public boolean canBeHidden(int type) {
+ return true;
+ }
+
+ @Override
+ public void setFragmentEnabled(int type, boolean fragmentEnabled) {
+ if (type == PUMP) this.fragmentEnabled = fragmentEnabled;
+ }
+
+ @Override
+ public void setFragmentVisible(int type, boolean fragmentVisible) {
+ if (type == PUMP) this.fragmentVisible = fragmentVisible;
+ }
+
+ @Override
+ public int getType() {
+ return PluginBase.PUMP;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return true;
+ }
+
+ @Override
+ public boolean isTempBasalInProgress() {
+ return false;
+ }
+
+ @Override
+ public boolean isExtendedBoluslInProgress() {
+ return false;
+ }
+
+ @Override
+ public int setNewBasalProfile(NSProfile profile) {
+ // Do nothing here. we are using MainApp.getConfigBuilder().getActiveProfile().getProfile();
+ return SUCCESS;
+ }
+
+ @Override
+ public boolean isThisProfileSet(NSProfile profile) {
+ return false;
+ }
+
+ @Override
+ public double getBaseBasalRate() {
+ return 0d;
+ }
+
+ @Override
+ public double getTempBasalAbsoluteRate() {
+ return 0;
+ }
+
+ @Override
+ public TempBasal getTempBasal() {
+ return null;
+ }
+
+ @Override
+ public TempBasal getExtendedBolus() {
+ return null;
+ }
+
+ @Override
+ public double getTempBasalRemainingMinutes() {
+ return 0d;
+ }
+
+ @Override
+ public TempBasal getTempBasal(Date time) {
+ return null;
+ }
+
+ @Override
+ public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context) {
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = true;
+ result.bolusDelivered = insulin;
+ result.carbsDelivered = carbs;
+ result.comment = MainApp.instance().getString(R.string.virtualpump_resultok);
+ return result;
+ }
+
+ @Override
+ public void stopBolusDelivering() {
+ }
+
+ @Override
+ public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.pumperror);
+ if (Config.logPumpComm)
+ log.debug("Setting temp basal absolute: " + result);
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) {
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.pumperror);
+ if (Config.logPumpComm)
+ log.debug("Settings temp basal percent: " + result);
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.pumperror);
+ if (Config.logPumpComm)
+ log.debug("Setting extended bolus: " + result);
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult cancelTempBasal() {
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.pumperror);
+ if (Config.logPumpComm)
+ log.debug("Cancel temp basal: " + result);
+ return result;
+ }
+
+ @Override
+ public PumpEnactResult cancelExtendedBolus() {
+ PumpEnactResult result = new PumpEnactResult();
+ result.success = false;
+ result.comment = MainApp.instance().getString(R.string.pumperror);
+ if (Config.logPumpComm)
+ log.debug("Canceling extended basal: " + result);
+ return result;
+ }
+
+ @Override
+ public JSONObject getJSONStatus() {
+ JSONObject pump = new JSONObject();
+ JSONObject status = new JSONObject();
+ JSONObject extended = new JSONObject();
+ try {
+ status.put("status", "normal");
+ extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
+ try {
+ extended.put("ActiveProfile", MainApp.getConfigBuilder().getActiveProfile().getProfile().getActiveProfile());
+ } catch (Exception e) {
+ }
+ status.put("timestamp", DateUtil.toISOString(new Date()));
+
+ pump.put("status", status);
+ pump.put("extended", extended);
+ pump.put("clock", DateUtil.toISOString(new Date()));
+ } catch (JSONException e) {
+ }
+ return pump;
+ }
+
+ @Override
+ public String deviceID() {
+ return "MDI";
+ }
+
+ @Override
+ public PumpDescription getPumpDescription() {
+ return pumpDescription;
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/MM640g/MM640gFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/MM640g/MM640gFragment.java
deleted file mode 100644
index a16774853e..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/MM640g/MM640gFragment.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package info.nightscout.androidaps.plugins.MM640g;
-
-
-import android.content.Context;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.squareup.otto.Subscribe;
-
-import org.json.JSONObject;
-
-import java.util.Date;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.PumpEnactResult;
-import info.nightscout.androidaps.db.TempBasal;
-import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.interfaces.BgSourceInterface;
-import info.nightscout.androidaps.interfaces.FragmentBase;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.client.data.NSProfile;
-
-public class MM640gFragment extends Fragment implements FragmentBase {
-
- private static MM640gPlugin mm640gPlugin = new MM640gPlugin();
-
- public static MM640gPlugin getPlugin() {
- return mm640gPlugin;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.mm640g_fragment, container, false);
- return view;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/MM640g/MM640gPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/MM640g/MM640gPlugin.java
deleted file mode 100644
index 7361054a3e..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/MM640g/MM640gPlugin.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package info.nightscout.androidaps.plugins.MM640g;
-
-import android.content.Context;
-
-import com.squareup.otto.Subscribe;
-
-import org.json.JSONObject;
-
-import java.util.Date;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.PumpEnactResult;
-import info.nightscout.androidaps.db.TempBasal;
-import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.interfaces.BgSourceInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.client.data.NSProfile;
-
-/**
- * Created by mike on 05.08.2016.
- */
-public class MM640gPlugin implements PluginBase, PumpInterface, BgSourceInterface {
-
- boolean fragmentPumpEnabled = false;
- boolean fragmentProfileEnabled = false;
- boolean fragmentBgSourceEnabled = false;
- boolean fragmentPumpVisible = true;
-
- @Override
- public String getFragmentClass() {
- return MM640gFragment.class.getName();
- }
-
- /**
- * Plugin base interface
- */
-
- @Override
- public int getType() {
- return PluginBase.PUMP;
- }
-
- @Override
- public String getName() {
- return MainApp.instance().getString(R.string.mm640g);
- }
-
- @Override
- public boolean isEnabled(int type) {
- if (type == PluginBase.PROFILE) return fragmentProfileEnabled;
- else if (type == PluginBase.BGSOURCE) return fragmentBgSourceEnabled;
- else if (type == PluginBase.PUMP) return fragmentPumpEnabled;
- else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled;
- return false;
- }
-
- @Override
- public boolean isVisibleInTabs(int type) {
- if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false;
- else if (type == PluginBase.PUMP) return fragmentPumpVisible;
- return false;
- }
-
- @Override
- public boolean canBeHidden(int type) {
- return true;
- }
-
- @Override
- public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- if (type == PluginBase.PROFILE) this.fragmentProfileEnabled = fragmentEnabled;
- if (type == PluginBase.BGSOURCE) this.fragmentBgSourceEnabled = fragmentEnabled;
- else if (type == PluginBase.PUMP) this.fragmentPumpEnabled = fragmentEnabled;
- }
-
- @Override
- public void setFragmentVisible(int type, boolean fragmentVisible) {
- if (type == PluginBase.PUMP)
- this.fragmentPumpVisible = fragmentVisible;
- }
-
- /**
- * Plugin communications
- */
-
- @Subscribe
- public void onStatusEvent(final EventPreferenceChange s) {
-
- }
-
- /**
- * Pump Interface
- */
-
- @Override
- public boolean isInitialized() {
- return false;
- }
-
- @Override
- public boolean isTempBasalInProgress() {
- return false;
- }
-
- @Override
- public boolean isExtendedBoluslInProgress() {
- return false;
- }
-
- @Override
- public void setNewBasalProfile(NSProfile profile) {
-
- }
-
- @Override
- public double getBaseBasalRate() {
- return 0;
- }
-
- @Override
- public double getTempBasalAbsoluteRate() {
- return 0;
- }
-
- @Override
- public double getTempBasalRemainingMinutes() {
- return 0;
- }
-
- @Override
- public TempBasal getTempBasal(Date time) {
- return null;
- }
-
- @Override
- public TempBasal getTempBasal() {
- return null;
- }
-
- @Override
- public TempBasal getExtendedBolus() {
- return null;
- }
-
- @Override
- public PumpEnactResult deliverTreatment(Double insulin, Integer carbs, Context context) {
- return new PumpEnactResult();
- }
-
- @Override
- public void stopBolusDelivering() {
-
- }
-
- @Override
- public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) {
- return new PumpEnactResult();
- }
-
- @Override
- public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) {
- return new PumpEnactResult();
- }
-
- @Override
- public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
- return new PumpEnactResult();
- }
-
- @Override
- public PumpEnactResult cancelTempBasal() {
- return new PumpEnactResult();
- }
-
- @Override
- public PumpEnactResult cancelExtendedBolus() {
- return new PumpEnactResult();
- }
-
- @Override
- public JSONObject getJSONStatus() {
- return new JSONObject();
- }
-
- @Override
- public String deviceID() {
- return "MM640G"; // TODO: probably serial goes here
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/NSProfileViewerFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/NSProfileFragment.java
similarity index 68%
rename from app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/NSProfileViewerFragment.java
rename to app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/NSProfileFragment.java
index 5ef13866d7..da54fcb27c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/NSProfileViewerFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/NSProfileFragment.java
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.NSProfileViewer;
+package info.nightscout.androidaps.plugins.NSProfile;
import android.app.Activity;
import android.os.Bundle;
@@ -13,14 +13,14 @@ import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.FragmentBase;
-import info.nightscout.androidaps.plugins.NSProfileViewer.events.EventNSProfileViewerUpdateGUI;
+import info.nightscout.androidaps.plugins.NSProfile.events.EventNSProfileUpdateGUI;
import info.nightscout.utils.DecimalFormatter;
-public class NSProfileViewerFragment extends Fragment implements FragmentBase {
- private static NSProfileViewerPlugin nsProfileViewerPlugin = new NSProfileViewerPlugin();
+public class NSProfileFragment extends Fragment implements FragmentBase {
+ private static NSProfilePlugin nsProfilePlugin = new NSProfilePlugin();
- public static NSProfileViewerPlugin getPlugin() {
- return nsProfileViewerPlugin;
+ public static NSProfilePlugin getPlugin() {
+ return nsProfilePlugin;
}
private static TextView noProfile;
@@ -63,7 +63,7 @@ public class NSProfileViewerFragment extends Fragment implements FragmentBase {
}
@Subscribe
- public void onStatusEvent(final EventNSProfileViewerUpdateGUI ev) {
+ public void onStatusEvent(final EventNSProfileUpdateGUI ev) {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(new Runnable() {
@@ -75,19 +75,19 @@ public class NSProfileViewerFragment extends Fragment implements FragmentBase {
}
private void updateGUI() {
- if (nsProfileViewerPlugin.profile == null) {
+ if (nsProfilePlugin.profile == null) {
noProfile.setVisibility(View.VISIBLE);
return;
} else {
noProfile.setVisibility(View.GONE);
}
- units.setText(nsProfileViewerPlugin.profile.getUnits());
- dia.setText(DecimalFormatter.to2Decimal(nsProfileViewerPlugin.profile.getDia()) + " h");
- activeProfile.setText(nsProfileViewerPlugin.profile.getActiveProfile());
- ic.setText(nsProfileViewerPlugin.profile.getIcList());
- isf.setText(nsProfileViewerPlugin.profile.getIsfList());
- basal.setText(nsProfileViewerPlugin.profile.getBasalList());
- target.setText(nsProfileViewerPlugin.profile.getTargetList());
+ units.setText(nsProfilePlugin.profile.getUnits());
+ dia.setText(DecimalFormatter.to2Decimal(nsProfilePlugin.profile.getDia()) + " h");
+ activeProfile.setText(nsProfilePlugin.profile.getActiveProfile());
+ ic.setText(nsProfilePlugin.profile.getIcList());
+ isf.setText(nsProfilePlugin.profile.getIsfList());
+ basal.setText(nsProfilePlugin.profile.getBasalList());
+ target.setText(nsProfilePlugin.profile.getTargetList());
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/NSProfileViewerPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/NSProfilePlugin.java
similarity index 85%
rename from app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/NSProfileViewerPlugin.java
rename to app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/NSProfilePlugin.java
index f957b46fce..8e522c3cae 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/NSProfileViewerPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/NSProfilePlugin.java
@@ -1,4 +1,4 @@
-package info.nightscout.androidaps.plugins.NSProfileViewer;
+package info.nightscout.androidaps.plugins.NSProfile;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -19,18 +19,18 @@ import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.ProfileInterface;
-import info.nightscout.androidaps.plugins.NSProfileViewer.events.EventNSProfileViewerUpdateGUI;
+import info.nightscout.androidaps.plugins.NSProfile.events.EventNSProfileUpdateGUI;
import info.nightscout.client.data.NSProfile;
/**
* Created by mike on 05.08.2016.
*/
-public class NSProfileViewerPlugin implements PluginBase, ProfileInterface {
- private static Logger log = LoggerFactory.getLogger(NSProfileViewerPlugin.class);
+public class NSProfilePlugin implements PluginBase, ProfileInterface {
+ private static Logger log = LoggerFactory.getLogger(NSProfilePlugin.class);
@Override
public String getFragmentClass() {
- return NSProfileViewerFragment.class.getName();
+ return NSProfileFragment.class.getName();
}
static boolean fragmentEnabled = true;
@@ -38,7 +38,7 @@ public class NSProfileViewerPlugin implements PluginBase, ProfileInterface {
static NSProfile profile = null;
- public NSProfileViewerPlugin() {
+ public NSProfilePlugin() {
MainApp.bus().register(this);
loadNSProfile();
@@ -51,12 +51,12 @@ public class NSProfileViewerPlugin implements PluginBase, ProfileInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == PROFILE && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == PROFILE && fragmentVisible;
}
@Override
@@ -66,12 +66,12 @@ public class NSProfileViewerPlugin implements PluginBase, ProfileInterface {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == PROFILE) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == PROFILE) this.fragmentVisible = fragmentVisible;
}
@Override
@@ -83,7 +83,7 @@ public class NSProfileViewerPlugin implements PluginBase, ProfileInterface {
public void onStatusEvent(final EventNewBasalProfile ev) {
profile = new NSProfile(ev.newNSProfile.getData(), ev.newNSProfile.getActiveProfile());
storeNSProfile();
- MainApp.bus().post(new EventNSProfileViewerUpdateGUI());
+ MainApp.bus().post(new EventNSProfileUpdateGUI());
}
private void storeNSProfile() {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/events/EventNSProfileUpdateGUI.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/events/EventNSProfileUpdateGUI.java
new file mode 100644
index 0000000000..df7fe40879
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSProfile/events/EventNSProfileUpdateGUI.java
@@ -0,0 +1,7 @@
+package info.nightscout.androidaps.plugins.NSProfile.events;
+
+/**
+ * Created by mike on 05.08.2016.
+ */
+public class EventNSProfileUpdateGUI {
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/events/EventNSProfileViewerUpdateGUI.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/events/EventNSProfileViewerUpdateGUI.java
deleted file mode 100644
index f84515eb56..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/NSProfileViewer/events/EventNSProfileViewerUpdateGUI.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package info.nightscout.androidaps.plugins.NSProfileViewer.events;
-
-/**
- * Created by mike on 05.08.2016.
- */
-public class EventNSProfileViewerUpdateGUI {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java
index a6b866fc77..2321d8a955 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java
@@ -29,9 +29,12 @@ import info.nightscout.androidaps.interfaces.FragmentBase;
public class ObjectivesFragment extends Fragment implements View.OnClickListener, FragmentBase {
private static Logger log = LoggerFactory.getLogger(ObjectivesFragment.class);
- private static ObjectivesPlugin objectivesPlugin = new ObjectivesPlugin();
+ private static ObjectivesPlugin objectivesPlugin;
public static ObjectivesPlugin getPlugin() {
+ if (objectivesPlugin == null) {
+ objectivesPlugin = new ObjectivesPlugin();
+ }
return objectivesPlugin;
}
@@ -67,7 +70,7 @@ public class ObjectivesFragment extends Fragment implements View.OnClickListener
@Override
public void onBindViewHolder(ObjectiveViewHolder holder, int position) {
ObjectivesPlugin.Objective o = objectives.get(position);
- ObjectivesPlugin.RequirementResult requirementsMet = objectivesPlugin.requirementsMet(position);
+ ObjectivesPlugin.RequirementResult requirementsMet = getPlugin().requirementsMet(position);
Context context = MainApp.instance().getApplicationContext();
holder.position.setText(String.valueOf(position + 1));
holder.objective.setText(o.objective);
@@ -91,7 +94,7 @@ public class ObjectivesFragment extends Fragment implements View.OnClickListener
holder.verifyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ObjectivesPlugin.Objective o = (ObjectivesPlugin.Objective) v.getTag();
- if (objectivesPlugin.requirementsMet(o.num).done || enableFake.isChecked()) {
+ if (getPlugin().requirementsMet(o.num).done || enableFake.isChecked()) {
o.accomplished = new Date();
updateGUI();
ObjectivesPlugin.saveProgress();
@@ -197,26 +200,26 @@ public class ObjectivesFragment extends Fragment implements View.OnClickListener
});
reset.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
- objectivesPlugin.initializeData();
- objectivesPlugin.saveProgress();
+ getPlugin().initializeData();
+ getPlugin().saveProgress();
updateGUI();
}
});
// Add correct translations to array after app is initialized
- objectivesPlugin.objectives.get(0).objective = MainApp.sResources.getString(R.string.objectives_0_objective);
- objectivesPlugin.objectives.get(1).objective = MainApp.sResources.getString(R.string.objectives_1_objective);
- objectivesPlugin.objectives.get(2).objective = MainApp.sResources.getString(R.string.objectives_2_objective);
- objectivesPlugin.objectives.get(3).objective = MainApp.sResources.getString(R.string.objectives_3_objective);
- objectivesPlugin.objectives.get(4).objective = MainApp.sResources.getString(R.string.objectives_4_objective);
- objectivesPlugin.objectives.get(5).objective = MainApp.sResources.getString(R.string.objectives_5_objective);
- objectivesPlugin.objectives.get(6).objective = MainApp.sResources.getString(R.string.objectives_6_objective);
- objectivesPlugin.objectives.get(0).gate = MainApp.sResources.getString(R.string.objectives_0_gate);
- objectivesPlugin.objectives.get(1).gate = MainApp.sResources.getString(R.string.objectives_1_gate);
- objectivesPlugin.objectives.get(2).gate = MainApp.sResources.getString(R.string.objectives_2_gate);
- objectivesPlugin.objectives.get(3).gate = MainApp.sResources.getString(R.string.objectives_3_gate);
- objectivesPlugin.objectives.get(4).gate = MainApp.sResources.getString(R.string.objectives_4_gate);
- objectivesPlugin.objectives.get(5).gate = MainApp.sResources.getString(R.string.objectives_5_gate);
+ getPlugin().objectives.get(0).objective = MainApp.sResources.getString(R.string.objectives_0_objective);
+ getPlugin().objectives.get(1).objective = MainApp.sResources.getString(R.string.objectives_1_objective);
+ getPlugin().objectives.get(2).objective = MainApp.sResources.getString(R.string.objectives_2_objective);
+ getPlugin().objectives.get(3).objective = MainApp.sResources.getString(R.string.objectives_3_objective);
+ getPlugin().objectives.get(4).objective = MainApp.sResources.getString(R.string.objectives_4_objective);
+ getPlugin().objectives.get(5).objective = MainApp.sResources.getString(R.string.objectives_5_objective);
+ getPlugin().objectives.get(6).objective = MainApp.sResources.getString(R.string.objectives_6_objective);
+ getPlugin().objectives.get(0).gate = MainApp.sResources.getString(R.string.objectives_0_gate);
+ getPlugin().objectives.get(1).gate = MainApp.sResources.getString(R.string.objectives_1_gate);
+ getPlugin().objectives.get(2).gate = MainApp.sResources.getString(R.string.objectives_2_gate);
+ getPlugin().objectives.get(3).gate = MainApp.sResources.getString(R.string.objectives_3_gate);
+ getPlugin().objectives.get(4).gate = MainApp.sResources.getString(R.string.objectives_4_gate);
+ getPlugin().objectives.get(5).gate = MainApp.sResources.getString(R.string.objectives_5_gate);
updateGUI();
return view;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java
index 89c319d2c1..f865165437 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java
@@ -51,13 +51,13 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
@Override
public boolean isEnabled(int type) {
- return true;
+ return type == CONSTRAINTS && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
@Override
public boolean isVisibleInTabs(int type) {
LoopPlugin loopPlugin = (LoopPlugin) MainApp.getSpecificPlugin(LoopPlugin.class);
- return fragmentVisible && loopPlugin != null && loopPlugin.isVisibleInTabs(type);
+ return type == CONSTRAINTS && fragmentVisible && loopPlugin != null && loopPlugin.isVisibleInTabs(LOOP);
}
@Override
@@ -71,7 +71,7 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == CONSTRAINTS) this.fragmentVisible = fragmentVisible;
}
public class Objective {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java
index f124b81a56..a3838d53a6 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java
@@ -24,9 +24,12 @@ import info.nightscout.utils.JSONFormatter;
public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, FragmentBase {
private static Logger log = LoggerFactory.getLogger(OpenAPSMAFragment.class);
- private static OpenAPSMAPlugin openAPSMAPlugin = new OpenAPSMAPlugin();
+ private static OpenAPSMAPlugin openAPSMAPlugin;
public static OpenAPSMAPlugin getPlugin() {
+ if(openAPSMAPlugin==null){
+ openAPSMAPlugin = new OpenAPSMAPlugin();
+ }
return openAPSMAPlugin;
}
@@ -64,7 +67,7 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
public void onClick(View view) {
switch (view.getId()) {
case R.id.openapsma_run:
- openAPSMAPlugin.invoke();
+ getPlugin().invoke();
break;
}
@@ -98,15 +101,15 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener,
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
- if (openAPSMAPlugin.lastAPSResult != null) {
- glucoseStatusView.setText(JSONFormatter.format(openAPSMAPlugin.lastDetermineBasalAdapterJS.getGlucoseStatusParam()));
- currentTempView.setText(JSONFormatter.format(openAPSMAPlugin.lastDetermineBasalAdapterJS.getCurrentTempParam()));
- iobDataView.setText(JSONFormatter.format(openAPSMAPlugin.lastDetermineBasalAdapterJS.getIobDataParam()));
- profileView.setText(JSONFormatter.format(openAPSMAPlugin.lastDetermineBasalAdapterJS.getProfileParam()));
- mealDataView.setText(JSONFormatter.format(openAPSMAPlugin.lastDetermineBasalAdapterJS.getMealDataParam()));
- resultView.setText(JSONFormatter.format(openAPSMAPlugin.lastAPSResult.json));
- requestView.setText(openAPSMAPlugin.lastAPSResult.toSpanned());
- lastRunView.setText(openAPSMAPlugin.lastAPSRun.toLocaleString());
+ if (getPlugin().lastAPSResult != null) {
+ glucoseStatusView.setText(JSONFormatter.format(getPlugin().lastDetermineBasalAdapterJS.getGlucoseStatusParam()));
+ currentTempView.setText(JSONFormatter.format(getPlugin().lastDetermineBasalAdapterJS.getCurrentTempParam()));
+ iobDataView.setText(JSONFormatter.format(getPlugin().lastDetermineBasalAdapterJS.getIobDataParam()));
+ profileView.setText(JSONFormatter.format(getPlugin().lastDetermineBasalAdapterJS.getProfileParam()));
+ mealDataView.setText(JSONFormatter.format(getPlugin().lastDetermineBasalAdapterJS.getMealDataParam()));
+ resultView.setText(JSONFormatter.format(getPlugin().lastAPSResult.json));
+ requestView.setText(getPlugin().lastAPSResult.toSpanned());
+ lastRunView.setText(getPlugin().lastAPSRun.toLocaleString());
}
}
});
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java
index 4e13e75d17..47ef05e08f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java
@@ -58,12 +58,12 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == APS && fragmentEnabled && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == APS && fragmentVisible && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
@Override
@@ -73,12 +73,12 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == APS) this.fragmentVisible = fragmentVisible;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == APS) this.fragmentEnabled = fragmentEnabled;
}
@Override
@@ -103,6 +103,7 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
@Override
public void invoke() {
+ lastAPSResult = null;
DetermineBasalAdapterJS determineBasalAdapterJS = null;
try {
determineBasalAdapterJS = new DetermineBasalAdapterJS(new ScriptReader(MainApp.instance().getBaseContext()));
@@ -234,7 +235,7 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
if (value < lowLimit || value > highLimit) {
String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), valueName);
log.error(msg);
- sendErrorToNSClient(msg);
+ MainApp.getConfigBuilder().uploadError(msg);
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error);
value = Math.max(value, lowLimit);
value = Math.min(value, highLimit);
@@ -242,26 +243,4 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface {
return value;
}
- public static void sendErrorToNSClient(String error) {
- Context context = MainApp.instance().getApplicationContext();
- Bundle bundle = new Bundle();
- bundle.putString("action", "dbAdd");
- bundle.putString("collection", "treatments");
- JSONObject data = new JSONObject();
- try {
- data.put("eventType", "Announcement");
- data.put("created_at", DateUtil.toISOString(new Date()));
- data.put("notes", error);
- data.put("isAnnouncement", true);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- bundle.putString("data", data.toString());
- Intent intent = new Intent(Intents.ACTION_DATABASE);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- context.sendBroadcast(intent);
- DbLogger.dbAdd(intent, data.toString(), OpenAPSMAPlugin.class);
- }
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java
index f255e4ca1e..60f7c48696 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java
@@ -380,7 +380,7 @@ public class WizardDialog extends DialogFragment implements OnClickListener {
correctionInsulin.setText(DecimalFormatter.to2Decimal(wizard.insulinFromCorrection) + "U");
calculatedTotalInsulin = wizard.calculatedTotalInsulin;
- if (calculatedTotalInsulin < 0) {
+ if (calculatedTotalInsulin <= 0) {
total.setText(getString(R.string.missing) + " " + DecimalFormatter.to0Decimal(wizard.carbsEquivalent) + "g");
totalInsulin.setText("");
} else {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java
index abf7858db4..38e954571b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java
@@ -12,9 +12,45 @@ public class Notification {
public static final int LOW = 2;
public static final int INFO = 3;
+ public static final int PROFILE_SET_FAILED = 0;
+ public static final int PROFILE_SET_OK = 1;
+ public static final int EASYMODE_ENABLED = 2;
+ public static final int EXTENDED_BOLUS_DISABLED = 3;
+ public static final int UD_MODE_ENABLED = 4;
+ public static final int PROFILE_NOT_SET_NOT_INITIALIZED = 5;
+ public static final int FAILED_UDPATE_PROFILE = 6;
+ public static final int BASAL_VALUE_BELOW_MINIMUM = 7;
+
public int id;
- Date date;
- String text;
- Date validTo = new Date(0);
- int level;
+ public Date date;
+ public String text;
+ public int level;
+ public Date validTo = new Date(0);
+
+ public Notification() {
+ }
+
+ public Notification(int id, Date date, String text, int level, Date validTo) {
+ this.id = id;
+ this.date = date;
+ this.text = text;
+ this.level = level;
+ this.validTo = validTo;
+ }
+
+ public Notification(int id, String text, int level, int validMinutes) {
+ this.id = id;
+ this.date = new Date();
+ this.text = text;
+ this.level = level;
+ this.validTo = new Date(new Date().getTime() + validMinutes * 60 * 1000L);
+ }
+
+ public Notification(int id, String text, int level) {
+ this.id = id;
+ this.date = new Date();
+ this.text = text;
+ this.level = level;
+ this.validTo = new Date(0);
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java
index 10c86ad2a2..b4cb02e914 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java
@@ -1,5 +1,8 @@
package info.nightscout.androidaps.plugins.Overview;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -12,6 +15,7 @@ import java.util.List;
*/
public class NotificationStore {
+ private static Logger log = LoggerFactory.getLogger(NotificationStore.class);
public List store = new ArrayList();
public NotificationStore() {
@@ -29,6 +33,7 @@ public class NotificationStore {
}
public void add(Notification n) {
+ log.info("Notification received: " + n.text);
for (int i = 0; i < store.size(); i++) {
if (get(i).id == n.id) {
get(i).date = n.date;
@@ -54,6 +59,7 @@ public class NotificationStore {
Notification n = get(i);
if (n.validTo.getTime() != 0 && n.validTo.getTime() < new Date().getTime()) {
store.remove(i);
+ i--;
}
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
index 7291c80bd8..62d68ebb23 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java
@@ -55,6 +55,7 @@ import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.db.Treatment;
+import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventPreferenceChange;
@@ -95,6 +96,7 @@ public class OverviewFragment extends Fragment {
}
TextView bgView;
+ TextView arrowView;
TextView timeAgoView;
TextView deltaView;
TextView runningTempView;
@@ -138,6 +140,7 @@ public class OverviewFragment extends Fragment {
View view = inflater.inflate(R.layout.overview_fragment, container, false);
bgView = (TextView) view.findViewById(R.id.overview_bg);
+ arrowView = (TextView) view.findViewById(R.id.overview_arrow);
timeAgoView = (TextView) view.findViewById(R.id.overview_timeago);
deltaView = (TextView) view.findViewById(R.id.overview_delta);
runningTempView = (TextView) view.findViewById(R.id.overview_runningtemp);
@@ -364,6 +367,11 @@ public class OverviewFragment extends Fragment {
updateGUIIfVisible();
}
+ @Subscribe
+ public void onStatusEvent(final EventInitializationChanged ev) {
+ updateGUIIfVisible();
+ }
+
@Subscribe
public void onStatusEvent(final EventPreferenceChange ev) {
updateGUIIfVisible();
@@ -442,7 +450,7 @@ public class OverviewFragment extends Fragment {
// open loop mode
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
- if (Config.APS) {
+ if (Config.APS && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable) {
apsModeView.setVisibility(View.VISIBLE);
apsModeView.setBackgroundResource(R.drawable.loopmodeborder);
apsModeView.setTextColor(Color.BLACK);
@@ -486,22 +494,22 @@ public class OverviewFragment extends Fragment {
apsModeView.setVisibility(View.GONE);
}
+ // **** Temp button ****
+ NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
+ PumpInterface pump = MainApp.getConfigBuilder();
+
boolean showAcceptButton = !MainApp.getConfigBuilder().isClosedModeEnabled(); // Open mode needed
showAcceptButton = showAcceptButton && finalLastRun != null && finalLastRun.lastAPSRun != null; // aps result must exist
showAcceptButton = showAcceptButton && (finalLastRun.lastOpenModeAccept == null || finalLastRun.lastOpenModeAccept.getTime() < finalLastRun.lastAPSRun.getTime()); // never accepted or before last result
showAcceptButton = showAcceptButton && finalLastRun.constraintsProcessed.changeRequested; // change is requested
- if (showAcceptButton) {
+ if (showAcceptButton && pump.isInitialized()) {
acceptTempLayout.setVisibility(View.VISIBLE);
acceptTempButton.setText(getContext().getString(R.string.setbasalquestion) + "\n" + finalLastRun.constraintsProcessed);
} else {
acceptTempLayout.setVisibility(View.GONE);
}
- // **** Temp button ****
- NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
- PumpInterface pump = MainApp.getConfigBuilder();
-
if (pump.isTempBasalInProgress()) {
TempBasal activeTemp = pump.getTempBasal();
cancelTempLayout.setVisibility(View.VISIBLE);
@@ -531,7 +539,7 @@ public class OverviewFragment extends Fragment {
});
activeProfileView.setLongClickable(true);
- if (profile == null) {
+ if (profile == null || !pump.isInitialized()) {
// disable all treatment buttons because we are not able to check constraints without profile
wizardButton.setVisibility(View.INVISIBLE);
treatmentButton.setVisibility(View.INVISIBLE);
@@ -545,7 +553,7 @@ public class OverviewFragment extends Fragment {
// QuickWizard button
QuickWizard.QuickWizardEntry quickWizardEntry = getPlugin().quickWizard.getActive();
- if (quickWizardEntry != null && lastBG != null) {
+ if (quickWizardEntry != null && lastBG != null && pump.isInitialized()) {
quickWizardLayout.setVisibility(View.VISIBLE);
String text = MainApp.sResources.getString(R.string.bolus) + ": " + quickWizardEntry.buttonText() + " " + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g";
BolusWizard wizard = new BolusWizard();
@@ -560,6 +568,7 @@ public class OverviewFragment extends Fragment {
// **** BG value ****
if (lastBG != null && bgView != null) {
bgView.setText(lastBG.valueToUnitsToString(profile.getUnits()));
+ arrowView.setText(lastBG.directionToSymbol());
DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
if (glucoseStatus != null)
deltaView.setText("Δ " + NSProfile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units);
@@ -677,6 +686,13 @@ public class OverviewFragment extends Fragment {
}
});
+ // set manual x bounds to have nice steps
+ bgGraph.getViewport().setMaxX(toTime);
+ bgGraph.getViewport().setMinX(fromTime);
+ bgGraph.getViewport().setXAxisBoundsManual(true);
+ bgGraph.getGridLabelRenderer().setLabelFormatter(new TimeAsXAxisLabelFormatter(getActivity(), "HH"));
+ bgGraph.getGridLabelRenderer().setNumHorizontalLabels(7); // only 7 because of the space
+
// **** BG graph ****
List bgReadingsArray = MainApp.getDbHelper().getDataFromTime(fromTime);
List inRangeArray = new ArrayList();
@@ -757,13 +773,6 @@ public class OverviewFragment extends Fragment {
seriesTreatments.setColor(Color.CYAN);
}
- // set manual x bounds to have nice steps
- bgGraph.getViewport().setMaxX(toTime);
- bgGraph.getViewport().setMinX(fromTime);
- bgGraph.getViewport().setXAxisBoundsManual(true);
- bgGraph.getGridLabelRenderer().setLabelFormatter(new TimeAsXAxisLabelFormatter(getActivity(), "HH"));
- bgGraph.getGridLabelRenderer().setNumHorizontalLabels(7); // only 7 because of the space
-
// set manual y bounds to have nice steps
bgGraph.getViewport().setMaxY(maxBgValue);
bgGraph.getViewport().setMinY(0);
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java
index 164238a57a..2dbc3332d0 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewPlugin.java
@@ -49,7 +49,7 @@ public class OverviewPlugin implements PluginBase {
@Override
public boolean isEnabled(int type) {
- return true;
+ return type == GENERAL;
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyPlugin.java
index 4003fedbdd..f501ae5a0e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyPlugin.java
@@ -40,7 +40,7 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
@Override
public boolean isEnabled(int type) {
- return true;
+ return type == CONSTRAINTS;
}
@Override
@@ -54,7 +54,7 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
}
@Override
- public void setFragmentEnabled(int tyep, boolean fragmentEnabled) {
+ public void setFragmentEnabled(int type, boolean fragmentEnabled) {
}
@@ -64,7 +64,7 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
@Override
public boolean isLoopEnabled() {
- return true;
+ return MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
/**
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java
index ef61949519..107629c97c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java
@@ -1,6 +1,7 @@
package info.nightscout.androidaps.plugins.SimpleProfile;
+import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
@@ -8,14 +9,22 @@ import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
+import com.squareup.otto.Subscribe;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.interfaces.FragmentBase;
+import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
+import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
+import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.utils.SafeParse;
public class SimpleProfileFragment extends Fragment implements FragmentBase {
@@ -36,6 +45,7 @@ public class SimpleProfileFragment extends Fragment implements FragmentBase {
EditText basalView;
EditText targetlowView;
EditText targethighView;
+ Button profileswitchButton;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -50,6 +60,9 @@ public class SimpleProfileFragment extends Fragment implements FragmentBase {
basalView = (EditText) layout.findViewById(R.id.simpleprofile_basalrate);
targetlowView = (EditText) layout.findViewById(R.id.simpleprofile_targetlow);
targethighView = (EditText) layout.findViewById(R.id.simpleprofile_targethigh);
+ profileswitchButton = (Button) layout.findViewById(R.id.simpleprofile_profileswitch);
+
+ onStatusEvent(null);
mgdlView.setChecked(simpleProfilePlugin.mgdl);
mmolView.setChecked(simpleProfilePlugin.mmol);
@@ -80,6 +93,17 @@ public class SimpleProfileFragment extends Fragment implements FragmentBase {
}
});
+ profileswitchButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
+ final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, false, false, false, true, false);
+ profileswitch.executeProfileSwitch = true;
+ newDialog.setOptions(profileswitch);
+ newDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
+ }
+ });
+
TextWatcher textWatch = new TextWatcher() {
@Override
@@ -115,4 +139,32 @@ public class SimpleProfileFragment extends Fragment implements FragmentBase {
return layout;
}
+ @Override
+ public void onPause() {
+ super.onPause();
+ MainApp.bus().unregister(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ MainApp.bus().register(this);
+ }
+
+ @Subscribe
+ public void onStatusEvent(final EventInitializationChanged e) {
+ Activity activity = getActivity();
+ if (activity != null)
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!MainApp.getConfigBuilder().isInitialized()) {
+ profileswitchButton.setVisibility(View.GONE);
+ } else {
+ profileswitchButton.setVisibility(View.VISIBLE);
+ }
+ }
+ });
+ }
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfilePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfilePlugin.java
index baa3da71f6..dbe6345927 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfilePlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfilePlugin.java
@@ -60,12 +60,12 @@ public class SimpleProfilePlugin implements PluginBase, ProfileInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == PROFILE && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == PROFILE && fragmentVisible;
}
@Override
@@ -75,12 +75,12 @@ public class SimpleProfilePlugin implements PluginBase, ProfileInterface {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == PROFILE) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == PROFILE) this.fragmentVisible = fragmentVisible;
}
public void storeSettings() {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorFragment.java
index 93383032d7..852562ddda 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorFragment.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorFragment.java
@@ -29,9 +29,13 @@ import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventSmsCommuni
public class SmsCommunicatorFragment extends Fragment {
private static Logger log = LoggerFactory.getLogger(SmsCommunicatorFragment.class);
- private static SmsCommunicatorPlugin smsCommunicatorPlugin = new SmsCommunicatorPlugin();
+ private static SmsCommunicatorPlugin smsCommunicatorPlugin;
public static SmsCommunicatorPlugin getPlugin() {
+
+ if(smsCommunicatorPlugin==null){
+ smsCommunicatorPlugin = new SmsCommunicatorPlugin();
+ }
return smsCommunicatorPlugin;
}
@@ -81,15 +85,15 @@ public class SmsCommunicatorFragment extends Fragment {
return (int) (object1.date.getTime() - object2.date.getTime());
}
}
- Collections.sort(smsCommunicatorPlugin.messages, new CustomComparator());
+ Collections.sort(getPlugin().messages, new CustomComparator());
int messagesToShow = 40;
- int start = Math.max(0, smsCommunicatorPlugin.messages.size() - messagesToShow);
+ int start = Math.max(0, getPlugin().messages.size() - messagesToShow);
DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
String logText = "";
- for (int x = start; x < smsCommunicatorPlugin.messages.size(); x++) {
- SmsCommunicatorPlugin.Sms sms = smsCommunicatorPlugin.messages.get(x);
+ for (int x = start; x < getPlugin().messages.size(); x++) {
+ SmsCommunicatorPlugin.Sms sms = getPlugin().messages.get(x);
if (sms.received) {
logText += df.format(sms.date) + " <<< " + (sms.processed ? "● " : "○ ") + sms.phoneNumber + " " + sms.text + "
";
} else if (sms.sent) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java
index 365027c012..f878b5676f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java
@@ -16,18 +16,26 @@ import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.StringTokenizer;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.db.BgReading;
+import info.nightscout.androidaps.db.DatabaseHelper;
+import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
+import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventSmsCommunicatorUpdateGui;
+import info.nightscout.client.data.NSProfile;
+import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SafeParse;
/**
@@ -41,6 +49,8 @@ public class SmsCommunicatorPlugin implements PluginBase {
final long CONFIRM_TIMEOUT = 5 * 60 * 1000L;
+ List allowedNumbers = new ArrayList();
+
public class Sms {
String phoneNumber;
String text;
@@ -67,6 +77,14 @@ public class SmsCommunicatorPlugin implements PluginBase {
sent = true;
}
+ public Sms(String phoneNumber, String text, Date date, String confirmCode) {
+ this.phoneNumber = phoneNumber;
+ this.text = text;
+ this.date = date;
+ this.confirmCode = confirmCode;
+ sent = true;
+ }
+
public String toString() {
return "SMS from " + phoneNumber + ": " + text;
}
@@ -81,6 +99,7 @@ public class SmsCommunicatorPlugin implements PluginBase {
public SmsCommunicatorPlugin() {
MainApp.bus().register(this);
+ processSettings(null);
}
@Override
@@ -100,12 +119,12 @@ public class SmsCommunicatorPlugin implements PluginBase {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == GENERAL && fragmentVisible;
}
@Override
@@ -115,12 +134,34 @@ public class SmsCommunicatorPlugin implements PluginBase {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- SmsCommunicatorPlugin.fragmentEnabled = fragmentEnabled;
+ if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- SmsCommunicatorPlugin.fragmentVisible = fragmentVisible;
+ if (type == GENERAL) this.fragmentVisible = fragmentVisible;
+ }
+
+ @Subscribe
+ public void processSettings(final EventPreferenceChange ev) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+ String settings = sharedPreferences.getString("smscommunicator_allowednumbers", "");
+
+ String pattern = ";";
+
+ String[] substrings = settings.split(pattern);
+ for (String number : substrings) {
+ String cleaned = number.replaceAll("\\s+", "");
+ allowedNumbers.add(cleaned);
+ log.debug("Found allowed number: " + cleaned);
+ }
+ }
+
+ boolean isAllowedNumber(String number) {
+ for (String num : allowedNumbers) {
+ if (num.equals(number)) return true;
+ }
+ return false;
}
@Subscribe
@@ -135,14 +176,13 @@ public class SmsCommunicatorPlugin implements PluginBase {
}
private void processSms(Sms receivedSms) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
+
if (!isEnabled(PluginBase.GENERAL)) {
log.debug("Ignoring SMS. Plugin disabled.");
return;
}
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
- String allowedNumbers = sharedPreferences.getString("smscommunicator_allowednumbers", "");
-
- if (!allowedNumbers.contains(receivedSms.phoneNumber)) {
+ if (!isAllowedNumber(receivedSms.phoneNumber)) {
log.debug("Ignoring SMS from: " + receivedSms.phoneNumber + ". Sender not allowed");
return;
}
@@ -156,10 +196,42 @@ public class SmsCommunicatorPlugin implements PluginBase {
Double amount = 0d;
Double tempBasal = 0d;
String passCode = "";
- Sms newSms = null;
if (splited.length > 0) {
switch (splited[0].toUpperCase()) {
+ case "BG":
+ BgReading actualBG = MainApp.getDbHelper().actualBg();
+ BgReading lastBG = MainApp.getDbHelper().lastBg();
+
+ NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile();
+ String units = profile.getUnits();
+
+ Long agoMsec = new Date().getTime() - lastBG.timeIndex;
+ int agoMin = (int) (agoMsec / 60d / 1000d);
+
+ if (actualBG != null) {
+ reply = MainApp.sResources.getString(R.string.actualbg) + " " + actualBG.valueToUnitsToString(units) + ", ";
+ } else if (lastBG != null) {
+ reply = MainApp.sResources.getString(R.string.lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + agoMin + MainApp.sResources.getString(R.string.minago) + ", ";
+ }
+ DatabaseHelper.GlucoseStatus glucoseStatus = MainApp.getDbHelper().getGlucoseStatusData();
+ if (glucoseStatus != null)
+ reply += MainApp.sResources.getString(R.string.delta) + ": " + NSProfile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", ";
+
+ MainApp.getConfigBuilder().getActiveTreatments().updateTotalIOB();
+ IobTotal bolusIob = MainApp.getConfigBuilder().getActiveTreatments().getLastCalculation().round();
+ if (bolusIob == null) bolusIob = new IobTotal();
+ MainApp.getConfigBuilder().getActiveTempBasals().updateTotalIOB();
+ IobTotal basalIob = MainApp.getConfigBuilder().getActiveTempBasals().getLastCalculation().round();
+ if (basalIob == null) basalIob = new IobTotal();
+
+ reply += MainApp.sResources.getString(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U ("
+ + MainApp.sResources.getString(R.string.bolus) + ": " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
+ + MainApp.sResources.getString(R.string.basal) + ": " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U)";
+
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
+ receivedSms.processed = true;
+ break;
case "LOOP":
switch (splited[1].toUpperCase()) {
case "STOP":
@@ -167,7 +239,7 @@ public class SmsCommunicatorPlugin implements PluginBase {
if (loopPlugin != null && loopPlugin.isEnabled(PluginBase.LOOP)) {
loopPlugin.setFragmentEnabled(PluginBase.LOOP, false);
reply = MainApp.sResources.getString(R.string.smscommunicator_loophasbeendisabled);
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
receivedSms.processed = true;
break;
@@ -176,7 +248,7 @@ public class SmsCommunicatorPlugin implements PluginBase {
if (loopPlugin != null && !loopPlugin.isEnabled(PluginBase.LOOP)) {
loopPlugin.setFragmentEnabled(PluginBase.LOOP, true);
reply = MainApp.sResources.getString(R.string.smscommunicator_loophasbeenenabled);
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
receivedSms.processed = true;
break;
@@ -188,7 +260,7 @@ public class SmsCommunicatorPlugin implements PluginBase {
} else {
reply = MainApp.sResources.getString(R.string.smscommunicator_loopisdisabled);
}
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
receivedSms.processed = true;
break;
@@ -202,7 +274,7 @@ public class SmsCommunicatorPlugin implements PluginBase {
MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient);
List q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(restartNSClient, 0);
reply = "TERATMENTS REFRESH " + q.size() + " receivers";
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
receivedSms.processed = true;
break;
}
@@ -214,16 +286,22 @@ public class SmsCommunicatorPlugin implements PluginBase {
MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient);
List q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(restartNSClient, 0);
reply = "NSCLIENT RESTART " + q.size() + " receivers";
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
receivedSms.processed = true;
break;
}
break;
case "DANAR":
DanaRPlugin danaRPlugin = (DanaRPlugin) MainApp.getSpecificPlugin(DanaRPlugin.class);
- if (danaRPlugin != null && danaRPlugin.isEnabled(PluginBase.PUMP))
+ if (danaRPlugin != null && danaRPlugin.isEnabled(PluginBase.PUMP)) {
reply = danaRPlugin.shortStatus();
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
+ }
+ DanaRKoreanPlugin danaRKoreanPlugin = (DanaRKoreanPlugin) MainApp.getSpecificPlugin(DanaRKoreanPlugin.class);
+ if (danaRKoreanPlugin != null && danaRKoreanPlugin.isEnabled(PluginBase.PUMP)) {
+ reply = danaRKoreanPlugin.shortStatus();
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
+ }
receivedSms.processed = true;
break;
case "BASAL":
@@ -234,13 +312,11 @@ public class SmsCommunicatorPlugin implements PluginBase {
passCode = generatePasscode();
reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_basalstopreplywithcode), passCode);
receivedSms.processed = true;
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
- newSms.confirmCode = passCode;
resetWaitingMessages();
- cancelTempBasalWaitingForConfirmation = newSms;
+ sendSMS(cancelTempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode));
} else {
reply = MainApp.sResources.getString(R.string.remotebasalnotallowed);
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
} else {
tempBasal = SafeParse.stringToDouble(splited[1]);
@@ -249,14 +325,12 @@ public class SmsCommunicatorPlugin implements PluginBase {
passCode = generatePasscode();
reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_basalreplywithcode), tempBasal, passCode);
receivedSms.processed = true;
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
- newSms.tempBasal = tempBasal;
- newSms.confirmCode = passCode;
resetWaitingMessages();
- tempBasalWaitingForConfirmation = newSms;
+ sendSMS(tempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode));
+ tempBasalWaitingForConfirmation.tempBasal = tempBasal;
} else {
reply = MainApp.sResources.getString(R.string.remotebasalnotallowed);
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
}
}
@@ -264,7 +338,7 @@ public class SmsCommunicatorPlugin implements PluginBase {
case "BOLUS":
if (new Date().getTime() - lastRemoteBolusTime.getTime() < Constants.remoteBolusMinDistance) {
reply = MainApp.sResources.getString(R.string.remotebolusnotallowed);
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
} else if (splited.length > 1) {
amount = SafeParse.stringToDouble(splited[1]);
amount = MainApp.getConfigBuilder().applyBolusConstraints(amount);
@@ -273,14 +347,12 @@ public class SmsCommunicatorPlugin implements PluginBase {
passCode = generatePasscode();
reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_bolusreplywithcode), amount, passCode);
receivedSms.processed = true;
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
- newSms.bolusRequested = amount;
- newSms.confirmCode = passCode;
resetWaitingMessages();
- bolusWaitingForConfirmation = newSms;
+ sendSMS(bolusWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode));
+ bolusWaitingForConfirmation.bolusRequested = amount;
} else {
reply = MainApp.sResources.getString(R.string.remotebolusnotallowed);
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
}
break;
@@ -296,11 +368,12 @@ public class SmsCommunicatorPlugin implements PluginBase {
reply = String.format(MainApp.sResources.getString(R.string.bolusdelivered), result.bolusDelivered);
if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus();
lastRemoteBolusTime = new Date();
+ sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date()));
} else {
reply = MainApp.sResources.getString(R.string.bolusfailed);
if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus();
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
}
} else if (tempBasalWaitingForConfirmation != null && !tempBasalWaitingForConfirmation.processed &&
tempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && new Date().getTime() - tempBasalWaitingForConfirmation.date.getTime() < CONFIRM_TIMEOUT) {
@@ -312,11 +385,12 @@ public class SmsCommunicatorPlugin implements PluginBase {
if (result.success) {
reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_tempbasalset), result.absolute, result.duration);
if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus();
+ sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date()));
} else {
reply = MainApp.sResources.getString(R.string.smscommunicator_tempbasalfailed);
if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus();
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
}
} else if (cancelTempBasalWaitingForConfirmation != null && !cancelTempBasalWaitingForConfirmation.processed &&
cancelTempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && new Date().getTime() - cancelTempBasalWaitingForConfirmation.date.getTime() < CONFIRM_TIMEOUT) {
@@ -328,30 +402,46 @@ public class SmsCommunicatorPlugin implements PluginBase {
if (result.success) {
reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_tempbasalcanceled));
if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus();
+ sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date()));
} else {
reply = MainApp.sResources.getString(R.string.smscommunicator_tempbasalcancelfailed);
if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus();
+ sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date()));
}
- newSms = new Sms(receivedSms.phoneNumber, reply, new Date());
}
} else {
- newSms = new Sms(receivedSms.phoneNumber, MainApp.sResources.getString(R.string.smscommunicator_unknowncommand), new Date());
+ sendSMS(new Sms(receivedSms.phoneNumber, MainApp.sResources.getString(R.string.smscommunicator_unknowncommand), new Date()));
}
resetWaitingMessages();
break;
}
}
- if (newSms != null) {
- SmsManager smsManager = SmsManager.getDefault();
- newSms.text = stripAccents(newSms.text);
- if (newSms.text.length() > 140) newSms.text = newSms.text.substring(0, 139);
- smsManager.sendTextMessage(newSms.phoneNumber, null, newSms.text, null, null);
- messages.add(newSms);
- }
MainApp.bus().post(new EventSmsCommunicatorUpdateGui());
}
+ public void sendNotificationToAllNumbers(String text) {
+ for (int i = 0; i < allowedNumbers.size(); i++) {
+ Sms sms = new Sms(allowedNumbers.get(i), text, new Date());
+ sendSMS(sms);
+ }
+ }
+
+ public void sendSMSToAllNumbers(Sms sms) {
+ for (int i = 0; i < allowedNumbers.size(); i++) {
+ sms.phoneNumber = allowedNumbers.get(i);
+ sendSMS(sms);
+ }
+ }
+
+ public void sendSMS(Sms sms) {
+ SmsManager smsManager = SmsManager.getDefault();
+ sms.text = stripAccents(sms.text);
+ if (sms.text.length() > 140) sms.text = sms.text.substring(0, 139);
+ smsManager.sendTextMessage(sms.phoneNumber, null, sms.text, null, null);
+ messages.add(sms);
+ }
+
private String generatePasscode() {
int startChar1 = 'A'; // on iphone 1st char is uppercase :)
String passCode = Character.toString((char) (startChar1 + Math.random() * ('z' - 'a' + 1)));
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java
index fa88a70803..f29acb293d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceNSClient/SourceNSClientPlugin.java
@@ -28,7 +28,7 @@ public class SourceNSClientPlugin implements PluginBase, BgSourceInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == BGSOURCE && fragmentEnabled;
}
@Override
@@ -43,7 +43,7 @@ public class SourceNSClientPlugin implements PluginBase, BgSourceInterface {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == BGSOURCE) this.fragmentEnabled = fragmentEnabled;
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java
index a2575d9291..f2318580ea 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceXdrip/SourceXdripPlugin.java
@@ -30,7 +30,7 @@ public class SourceXdripPlugin implements PluginBase, BgSourceInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == BGSOURCE && fragmentEnabled;
}
@Override
@@ -45,7 +45,7 @@ public class SourceXdripPlugin implements PluginBase, BgSourceInterface {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- SourceXdripPlugin.fragmentEnabled = fragmentEnabled;
+ if (type == BGSOURCE) this.fragmentEnabled = fragmentEnabled;
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java
index 8cd51bbd1b..87a73cb1df 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java
@@ -66,12 +66,12 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == TEMPBASAL && fragmentEnabled && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == TEMPBASAL && fragmentVisible && MainApp.getConfigBuilder().getPumpDescription().isTempBasalCapable;
}
@Override
@@ -81,12 +81,12 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == TEMPBASAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == TEMPBASAL) this.fragmentVisible = fragmentVisible;
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java
index 369ce9ddbb..d26b6d0b8c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsPlugin.java
@@ -49,12 +49,12 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == TREATMENT && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == TREATMENT && fragmentVisible;
}
@Override
@@ -64,12 +64,12 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == TREATMENT) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == TREATMENT) this.fragmentVisible = fragmentVisible;
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java
index 99508d2c7e..743b7b576a 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java
@@ -17,6 +17,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TempBasal;
import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.VirtualPump.events.EventVirtualPumpUpdateGui;
@@ -37,6 +38,36 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
boolean fragmentEnabled = true;
boolean fragmentVisible = true;
+ PumpDescription pumpDescription = new PumpDescription();
+
+ public VirtualPumpPlugin() {
+ pumpDescription.isBolusCapable = true;
+ pumpDescription.bolusStep = 1d;
+
+ pumpDescription.isExtendedBolusCapable = true;
+ pumpDescription.extendedBolusStep = 0.2d;
+
+ pumpDescription.isTempBasalCapable = true;
+ pumpDescription.lowTempBasalStyle = PumpDescription.ABSOLUTE | PumpDescription.PERCENT;
+ pumpDescription.highTempBasalStyle = PumpDescription.ABSOLUTE | PumpDescription.PERCENT;
+ pumpDescription.maxHighTempPercent = 600;
+ pumpDescription.maxHighTempAbsolute = 10;
+ pumpDescription.lowTempPercentStep = 5;
+ pumpDescription.lowTempAbsoluteStep = 0.1;
+ pumpDescription.lowTempPercentDuration = 30;
+ pumpDescription.lowTempAbsoluteDuration = 30;
+ pumpDescription.highTempPercentStep = 10;
+ pumpDescription.highTempAbsoluteStep = 0.05d;
+ pumpDescription.highTempPercentDuration = 30;
+ pumpDescription.highTempAbsoluteDuration = 30;
+
+ pumpDescription.isSetBasalProfileCapable = true;
+ pumpDescription.basalStep = 0.01d;
+ pumpDescription.basalMinimumRate = 0.04d;
+
+ pumpDescription.isRefillingCapable = false;
+ }
+
@Override
public String getFragmentClass() {
return VirtualPumpFragment.class.getName();
@@ -49,12 +80,12 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == PUMP && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == PUMP && fragmentVisible;
}
@Override
@@ -64,12 +95,12 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- this.fragmentEnabled = fragmentEnabled;
+ if (type == PUMP) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- this.fragmentVisible = fragmentVisible;
+ if (type == PUMP) this.fragmentVisible = fragmentVisible;
}
@Override
@@ -93,8 +124,14 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
}
@Override
- public void setNewBasalProfile(NSProfile profile) {
+ public int setNewBasalProfile(NSProfile profile) {
// Do nothing here. we are using MainApp.getConfigBuilder().getActiveProfile().getProfile();
+ return SUCCESS;
+ }
+
+ @Override
+ public boolean isThisProfileSet(NSProfile profile) {
+ return false;
}
@Override
@@ -367,4 +404,9 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface {
return "VirtualPump";
}
+ @Override
+ public PumpDescription getPumpDescription() {
+ return pumpDescription;
+ }
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java
index 4685d3b634..33ad54ee81 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java
@@ -28,7 +28,7 @@ public class WearPlugin implements PluginBase {
private static WatchUpdaterService watchUS;
private final Context ctx;
- WearPlugin(Context ctx){
+ WearPlugin(Context ctx) {
this.ctx = ctx;
MainApp.bus().register(this);
}
@@ -50,12 +50,12 @@ public class WearPlugin implements PluginBase {
@Override
public boolean isEnabled(int type) {
- return fragmentEnabled;
+ return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
- return fragmentVisible;
+ return type == GENERAL && fragmentVisible;
}
@Override
@@ -65,39 +65,41 @@ public class WearPlugin implements PluginBase {
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
- WearPlugin.fragmentEnabled = fragmentEnabled;
- if(watchUS!=null){
- watchUS.setSettings();
+ if (type == GENERAL) {
+ this.fragmentEnabled = fragmentEnabled;
+ if (watchUS != null) {
+ watchUS.setSettings();
+ }
}
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
- WearPlugin.fragmentVisible = fragmentVisible;
+ if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
- private void sendDataToWatch(boolean status, boolean basals, boolean bgValue){
+ private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) {
if (isEnabled(getType())) { //only start service when this plugin is enabled
- if(bgValue){
+ if (bgValue) {
ctx.startService(new Intent(ctx, WatchUpdaterService.class));
}
- if(basals){
+ if (basals) {
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BASALS));
}
- if(status){
+ if (status) {
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_STATUS));
}
}
}
- void resendDataToWatch(){
+ void resendDataToWatch() {
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_RESEND));
}
- void openSettings(){
+ void openSettings() {
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS));
}
@@ -132,11 +134,11 @@ public class WearPlugin implements PluginBase {
return fragmentEnabled;
}
- public static void registerWatchUpdaterService(WatchUpdaterService wus){
+ public static void registerWatchUpdaterService(WatchUpdaterService wus) {
watchUS = wus;
}
- public static void unRegisterWatchUpdaterService(){
+ public static void unRegisterWatchUpdaterService() {
watchUS = null;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java
index 1ab627fd33..0431c0e5d6 100644
--- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java
+++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java
@@ -27,6 +27,7 @@ import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.DanaR.DanaRFragment;
import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.DanaR.Services.ExecutionService;
+import info.nightscout.androidaps.plugins.DanaRKorean.DanaRKoreanPlugin;
import info.nightscout.utils.ToastUtils;
public class KeepAliveReceiver extends BroadcastReceiver {
@@ -51,6 +52,18 @@ public class KeepAliveReceiver extends BroadcastReceiver {
t.start();
}
}
+ final DanaRKoreanPlugin danaRKoreanPlugin = (DanaRKoreanPlugin) MainApp.getSpecificPlugin(DanaRKoreanPlugin.class);
+ if (danaRKoreanPlugin != null && Config.DANAR && danaRKoreanPlugin.isEnabled(PluginBase.PUMP)) {
+ if (danaRKoreanPlugin.getDanaRPump().lastConnection.getTime() + 30 * 60 * 1000L < new Date().getTime() && !danaRKoreanPlugin.isConnected() && !danaRKoreanPlugin.isConnecting()) {
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ danaRKoreanPlugin.doConnect("KeepAlive");
+ }
+ });
+ t.start();
+ }
+ }
wl.release();
}
diff --git a/app/src/main/java/info/nightscout/client/data/NSProfile.java b/app/src/main/java/info/nightscout/client/data/NSProfile.java
index c9a0c0723e..ec431e69a8 100644
--- a/app/src/main/java/info/nightscout/client/data/NSProfile.java
+++ b/app/src/main/java/info/nightscout/client/data/NSProfile.java
@@ -26,7 +26,18 @@ public class NSProfile {
public NSProfile(JSONObject json, String activeProfile) {
this.json = json;
- this.activeProfile = activeProfile;
+ this.activeProfile = null;
+ JSONObject store;
+ try {
+ store = json.getJSONObject("store");
+ if (activeProfile != null && store.has(activeProfile)) {
+ this.activeProfile = activeProfile;
+ } else {
+ log.error("Active profile not found in store");
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
}
public JSONObject getDefaultProfile() {
@@ -289,6 +300,34 @@ public class NSProfile {
return getBasalList(getDefaultProfile());
}
+ public class BasalValue {
+ public BasalValue(Integer timeAsSeconds, Double value) {
+ this.timeAsSeconds = timeAsSeconds;
+ this.value = value;
+ }
+
+ public Integer timeAsSeconds;
+ public Double value;
+ }
+
+ public BasalValue[] getBasalValues() {
+ try {
+ JSONArray array = getDefaultProfile().getJSONArray("basal");
+ BasalValue[] ret = new BasalValue[array.length()];
+
+ for (Integer index = 0; index < array.length(); index++) {
+ JSONObject o = array.getJSONObject(index);
+ Integer tas = o.getInt("timeAsSeconds");
+ Double value = o.getDouble("value");
+ ret[index] = new BasalValue(tas, value);
+ }
+ return ret;
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return new BasalValue[0];
+ }
+
public String getBasalList(JSONObject profile) {
if (profile != null) {
try {
@@ -346,7 +385,22 @@ public class NSProfile {
}
public String getActiveProfile() {
- return activeProfile;
+ if (activeProfile != null)
+ return activeProfile;
+ else {
+ try {
+ JSONObject store = json.getJSONObject("store");
+ String defaultProfileName = (String) json.get("defaultProfile");
+ if (store.has(defaultProfileName)) {
+ return defaultProfileName;
+ }
+ log.error("Default profile not found");
+ return null;
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ return null;
}
public void setActiveProfile(String newProfile) {
diff --git a/app/src/main/res/layout/mm640g_fragment.xml b/app/src/main/res/layout/mm640g_fragment.xml
deleted file mode 100644
index cf0c892dd0..0000000000
--- a/app/src/main/res/layout/mm640g_fragment.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/app/src/main/res/layout/nsprofileviewer_fragment.xml b/app/src/main/res/layout/nsprofileviewer_fragment.xml
index 64acddc172..df7b15a654 100644
--- a/app/src/main/res/layout/nsprofileviewer_fragment.xml
+++ b/app/src/main/res/layout/nsprofileviewer_fragment.xml
@@ -2,7 +2,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".plugins.NSProfileViewer.NSProfileViewerFragment">
+ tools:context=".plugins.NSProfile.NSProfileFragment">
+
+
-
-
-
-
-
-
+ android:layout_gravity="right"
+ android:layout_marginRight="10dp"
+ android:layout_weight="0.5"
+ android:background="@drawable/pillborder"
+ android:gravity="center_vertical|center_horizontal"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/colorProfileSwitchButton" />
+
+
+
+
+
+
+
+
+
+
+ android:textColor="@color/colorCancelTempButton" />
diff --git a/app/src/main/res/layout/overview_notification_item.xml b/app/src/main/res/layout/overview_notification_item.xml
index d29a21e9a9..1f10a9336e 100644
--- a/app/src/main/res/layout/overview_notification_item.xml
+++ b/app/src/main/res/layout/overview_notification_item.xml
@@ -33,7 +33,7 @@
android:text="Notification text" />
@@ -25,14 +25,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="2"
- android:text="mgdl" />
+ android:text="@string/mgdl" />
+ android:text="@string/mmol" />
@@ -43,7 +43,7 @@
+
+
+
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 4862916fa3..6ea117f09c 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -280,7 +280,6 @@
DE bolus
DS bolus
E bolus
- MM 640g
Настройка на визуализацията и наблюдението, а също и анализиране на базалните нужди и коефициенти
Стартиране в Open loop режим за няколко дни и ръчно прилагане на много временни базали
Стартиране на Open Loop
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index f97ca2d0e0..fa211d33b0 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -270,7 +270,6 @@
Nahrávám
Pumpa je zaneprázdněna
Špatné heslo k pumpě
- MM 640g
Heslo k pumpě
Okluze
Podáno
@@ -364,4 +363,15 @@
Čas v hodinách, o který bude bazál posunutý.
Jednotky:
Wear
+ Bazál:
+ Zakázat EasyUI režim v pumpě
+ Povolit kombo bolusy v pumpě
+ Změnit režim z U/d na U/h v pumpě
+ Korejská DanaR
+ Nastavení bazálního profilu selhalo
+ Bazální profil aktualizován
+ Pumpa není inicializována, profil nenastaven!
+ Vybrán špatný ovladač pumpy
+ Hodnota bazálu pod minimem. Nenastaveno!
+ Pera
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index c1a62ab6a9..b31207f125 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -214,7 +214,6 @@
Sensor
Finger
Sprache
- MM 640g
Prozent
Profil neuladen
Speichern
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index d9ba0086f0..c87ec9529e 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -236,7 +236,6 @@
Absoluto
Cancelar basal temporal
SMS Communicator
- MM 640g
Esperando resultado
Números de teléfono permitidos
XXXXXXXXXX +; + YYYYYYYYYY
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index aae109c8b6..2ce25cf7c4 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -238,7 +238,6 @@
Absolute
임시기초주입 취소하기
SMS 전송
- MM 640g
결과 기다리는 중
허가된 전화번호
+XXXXXXXXXX;+YYYYYYYYYY
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1543734b62..87b200db28 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -241,7 +241,6 @@
Absolute
Cancel temp basal
SMS Communicator
- MM 640g
Waiting for result
Allowed phone numbers
+XXXXXXXXXX;+YYYYYYYYYY
@@ -341,6 +340,7 @@
NS upload only. Not effective on SGV unless a local source like xDrip is selected. Not effective on Profiles while NS-Profiles is used.
Please deactivate "NS upload only" to use this feature.
Pump not initialized!
+ Pump not initialized, profile not set!
Prime/Fill
Please make sure the amount matches the specification of your infusion set!
Other
@@ -375,4 +375,16 @@
Low Battery
Pump Shutdown
Pump Battery Discharged
+ DanaR Korean
+ Wrong pump driver selected
+ Basal rate:
+ Setting of basal profile failed
+ Basal profile in pump updated
+ Disable EasyUI mode in pump
+ Enable extended boluses on pump
+ Change mode from U/d to U/h on pump
+ Basal value below minimum. Profile not set!
+ BG:
+ Last BG:
+ MDI
diff --git a/app/src/main/res/xml/pref_mm640g.xml b/app/src/main/res/xml/pref_mm640g.xml
deleted file mode 100644
index 60b7eaf24f..0000000000
--- a/app/src/main/res/xml/pref_mm640g.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/test/java/info/nightscout/androidaps/ExampleUnitTest.java b/app/src/test/java/info/nightscout/androidaps/ExampleUnitTest.java
deleted file mode 100644
index fb97638c7b..0000000000
--- a/app/src/test/java/info/nightscout/androidaps/ExampleUnitTest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package info.nightscout.androidaps;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * To work on unit tests, switch the Test Artifact in the Build Variants view.
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() throws Exception {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/wear/wear.iml b/wear/wear.iml
index f368e9add6..008bad09ce 100644
--- a/wear/wear.iml
+++ b/wear/wear.iml
@@ -43,13 +43,6 @@
-
-
-
-
-
-
-
@@ -58,6 +51,13 @@
+
+
+
+
+
+
+
@@ -66,14 +66,6 @@
-
-
-
-
-
-
-
-
@@ -82,6 +74,14 @@
+
+
+
+
+
+
+
+