Repository: StephenBlackWasAlreadyTaken/xDrip
Branch: master
Commit: bd43dad2b9cf
Files: 181
Total size: 717.9 KB
Directory structure:
gitextract_6jrc5dih/
├── .gitignore
├── DexDrip.iml
├── LICENSE
├── README.md
├── app/
│ ├── .gitignore
│ ├── app.iml
│ ├── build.gradle
│ ├── libs/
│ │ ├── ActiveAndroid.jar
│ │ ├── android-support-v4.jar
│ │ ├── hellocharts-library-1.1.jar
│ │ └── usb-serial-for-android-v010.jar
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── eveningoutpost/
│ │ └── dexdrip/
│ │ └── ApplicationTest.java
│ └── main/
│ ├── AndroidManifest.xml
│ ├── assets/
│ │ └── migrations/
│ │ ├── 10.sql
│ │ ├── 16.sql
│ │ ├── 17.sql
│ │ ├── 18.sql
│ │ ├── 19.sql
│ │ ├── 20.sql
│ │ ├── 21.sql
│ │ ├── 23.sql
│ │ ├── 24.sql
│ │ ├── 25.sql
│ │ └── 26.sql
│ ├── java/
│ │ └── com/
│ │ └── eveningoutpost/
│ │ └── dexdrip/
│ │ ├── AddCalibration.java
│ │ ├── AutoStart.java
│ │ ├── BluetoothScan.java
│ │ ├── CalibrationCheckInActivity.java
│ │ ├── CalibrationGraph.java
│ │ ├── CalibrationOverride.java
│ │ ├── DoubleCalibrationActivity.java
│ │ ├── FakeNumbers.java
│ │ ├── Home.java
│ │ ├── ImportedLibraries/
│ │ │ ├── dexcom/
│ │ │ │ ├── CRC16.java
│ │ │ │ ├── CRCFailRuntimeException.java
│ │ │ │ ├── Constants.java
│ │ │ │ ├── PacketBuilder.java
│ │ │ │ ├── ReadData.java
│ │ │ │ ├── ReadDataShare.java
│ │ │ │ ├── ReadPacket.java
│ │ │ │ ├── SyncingService.java
│ │ │ │ ├── Utils.java
│ │ │ │ └── records/
│ │ │ │ ├── CalRecord.java
│ │ │ │ ├── CalSubrecord.java
│ │ │ │ ├── EGVRecord.java
│ │ │ │ ├── GenericTimestampRecord.java
│ │ │ │ ├── GenericXMLRecord.java
│ │ │ │ ├── GlucoseDataSet.java
│ │ │ │ ├── MeterRecord.java
│ │ │ │ ├── PageHeader.java
│ │ │ │ └── SensorRecord.java
│ │ │ └── usbserial/
│ │ │ ├── BuildInfo.java
│ │ │ ├── driver/
│ │ │ │ ├── CdcAcmSerialDriver.java
│ │ │ │ ├── CommonUsbSerialPort.java
│ │ │ │ ├── Cp21xxSerialDriver.java
│ │ │ │ ├── FtdiSerialDriver.java
│ │ │ │ ├── ProbeTable.java
│ │ │ │ ├── ProlificSerialDriver.java
│ │ │ │ ├── UsbId.java
│ │ │ │ ├── UsbSerialDriver.java
│ │ │ │ ├── UsbSerialPort.java
│ │ │ │ ├── UsbSerialProber.java
│ │ │ │ └── UsbSerialRuntimeException.java
│ │ │ └── util/
│ │ │ ├── HexDump.java
│ │ │ └── SerialInputOutputManager.java
│ │ ├── Interfaces/
│ │ │ ├── BgReadingInterface.java
│ │ │ ├── CalibrationInterface.java
│ │ │ ├── SensorInterface.java
│ │ │ └── UserInterface.java
│ │ ├── LicenseAgreementActivity.java
│ │ ├── Models/
│ │ │ ├── ActiveBluetoothDevice.java
│ │ │ ├── BgReading.java
│ │ │ ├── Calibration.java
│ │ │ ├── CalibrationRequest.java
│ │ │ ├── TransmitterData.java
│ │ │ ├── User.java
│ │ │ └── UserNotification.java
│ │ ├── NavDrawerBuilder.java
│ │ ├── NavigationDrawerFragment.java
│ │ ├── Sensor.java
│ │ ├── Services/
│ │ │ ├── ComunicationHeader.java
│ │ │ ├── DexCollectionService.java
│ │ │ ├── DexShareCollectionService.java
│ │ │ ├── MongoWrapper.java
│ │ │ ├── SyncService.java
│ │ │ ├── TransmitterRawData.java
│ │ │ └── WixelReader.java
│ │ ├── SettingsActivity.java
│ │ ├── ShareModels/
│ │ │ ├── DexcomShareInterface.java
│ │ │ ├── Egv.java
│ │ │ ├── ShareAuthenticationBody.java
│ │ │ ├── ShareGlucose.java
│ │ │ ├── ShareRest.java
│ │ │ └── ShareUploadPayload.java
│ │ ├── ShareTest.java
│ │ ├── StartNewSensor.java
│ │ ├── StopSensor.java
│ │ ├── SystemStatus.java
│ │ ├── Tables/
│ │ │ ├── BgReadingTable.java
│ │ │ ├── CalibrationDataTable.java
│ │ │ └── SensorDataTable.java
│ │ ├── UsbConnectedActivity.java
│ │ ├── UtilityModels/
│ │ │ ├── BgGraphBuilder.java
│ │ │ ├── BgSendQueue.java
│ │ │ ├── CalibrationSendQueue.java
│ │ │ ├── CollectionServiceStarter.java
│ │ │ ├── Constants.java
│ │ │ ├── DexShareAttributes.java
│ │ │ ├── ForegroundServiceStarter.java
│ │ │ ├── HM10Attributes.java
│ │ │ ├── Intents.java
│ │ │ ├── MongoSendTask.java
│ │ │ ├── NightscoutUploader.java
│ │ │ ├── Notifications.java
│ │ │ ├── PebbleSync.java
│ │ │ ├── RedBearLabAttributes.java
│ │ │ ├── RestCalls.java
│ │ │ └── SensorSendQueue.java
│ │ ├── utils/
│ │ │ ├── DatabaseUtil.java
│ │ │ ├── FileUtils.java
│ │ │ ├── Preferences.java
│ │ │ └── ShareNotification.java
│ │ ├── widgetUpdateService.java
│ │ ├── xDripWidget.java
│ │ └── xdrip.java
│ └── res/
│ ├── layout/
│ │ ├── activity_add_calibration.xml
│ │ ├── activity_add_comparison.xml
│ │ ├── activity_bluetooth_scan.xml
│ │ ├── activity_calibration_check_in.xml
│ │ ├── activity_calibration_graph.xml
│ │ ├── activity_calibration_override.xml
│ │ ├── activity_double_calibration.xml
│ │ ├── activity_fake_numbers.xml
│ │ ├── activity_home.xml
│ │ ├── activity_license_agreement.xml
│ │ ├── activity_raw_data_table.xml
│ │ ├── activity_share_test.xml
│ │ ├── activity_start_new_sensor.xml
│ │ ├── activity_stop_sensor.xml
│ │ ├── activity_system_status.xml
│ │ ├── activity_usb_connected.xml
│ │ ├── fragment_navigation_drawer.xml
│ │ ├── listitem_device.xml
│ │ ├── raw_data_list.xml
│ │ ├── raw_data_list_item.xml
│ │ └── x_drip_widget.xml
│ ├── layout-xlarge/
│ │ └── activity_home.xml
│ ├── menu/
│ │ ├── global.xml
│ │ ├── menu_bluetooth_scan.xml
│ │ ├── menu_home.xml
│ │ ├── menu_share_test.xml
│ │ └── menu_system_status.xml
│ ├── values/
│ │ ├── arrays.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ ├── strings_activity_preferences.xml
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── dimens.xml
│ ├── values-v21/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ ├── device_filter.xml
│ ├── pref_advanced_settings.xml
│ ├── pref_data_source.xml
│ ├── pref_data_sync.xml
│ ├── pref_general.xml
│ ├── pref_headers.xml
│ ├── pref_license.xml
│ ├── pref_notifications.xml
│ └── x_drip_widget_info.xml
├── battle_of_the_dexes.md
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── hardware_setup.md
├── settings.gradle
├── xDrip-Experimental.iml
└── xDrip.iml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
#local
/local.properties
.idea/
/.idea/*
.idea/misc.xml
.idea/vcs.xml
*.idea*
*manifest-merger-debug-report.txt
*manifest-merger-release-report.txt
*.ds_store
*.DS_Store
*.swp
================================================
FILE: DexDrip.iml
================================================
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 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 General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is 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. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
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.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
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 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. Use with the GNU Affero General Public License.
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 Affero 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 special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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 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 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 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 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
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 GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: README.md
================================================
xDrip
=======
##### ** Please note this is __NOT__ a product created by or backed by Dexcom, you can check them out [here](http://dexcom.com/) **
#### Wirelessly with a Dexcom Share Receiver -- or -- Wireless xDrip bridge (No receiver!)
#### Click here for the [Main Project Page](http://stephenblackwasalreadytaken.github.io/xDrip/)
#### Access your Glucose levels from anywhere!
xDrip is ready to upload your glucose data to any [Nightscout](http://nightscout.github.io/) server for remote monitoring on just about any internet connected device!!
#### Want to learn more??
Jump on over to the [Wiki](https://github.com/StephenBlackWasAlreadyTaken/xDrip/wiki) for instructions and downloads!!
#### Stay Up to Date!
Follow me on twitter `@StephenIsTaken`, I will let everyone know when updates happen that you should definitely download! Updates will be rolling out fairly frequently as there is lots to do!!!
#### Want to help out?
AWESOME, let me know, put up some PRS, lets make it awesome!
#### Awesome Contributors:
(in no particular order, because they are all awesome)
* [@tzachi-dar](https://github.com/tzachi-dar)
* [@jstevensog](https://github.com/jstevensog)
* [@bhandfast](https://github.com/bhandfast)
* [@LorelaiL](https://github.com/LorelaiL)
* [@syntaxerr66](https://github.com/syntaxerr66)
* [@saercnap](https://github.com/saercnap)
* [@ktind](https://github.com/ktind)
* [Ly](http://youtu.be/YuxCUeJ9xAU)
* [Kev](http://circles-of-blue.winchcombe.org/)
* [NightScout](https://github.com/nightscout)
* Whoever else is supporting this and helping people out!!
***
***
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/app.iml
================================================
================================================
FILE: app/build.gradle
================================================
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
repositories {
maven { url 'https://maven.fabric.io/public' }
}
android {
compileSdkVersion 21
buildToolsVersion "20.0.0"
defaultConfig {
applicationId "com.eveningoutpost.dexdrip"
minSdkVersion 19
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'com.squareup.okhttp:mockwebserver:2.2.0'
compile 'com.squareup.okhttp:okhttp:2.2.0'
compile 'com.google.code.gson:gson:2.3'
compile 'org.mongodb:mongo-java-driver:2.10.1'
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.getpebble:pebblekit:2.6.0@aar'
compile 'io.reactivex:rxjava:1.0.0'
compile 'ch.acra:acra:4.5.0'
compile('com.crashlytics.sdk.android:crashlytics:2.2.3@aar') {
transitive = true;
}
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/stephenblack/adt-bundle-mac-x86_64-20140702 2/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/androidTest/java/com/eveningoutpost/dexdrip/ApplicationTest.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* Testing Fundamentals
*/
public class ApplicationTest extends ApplicationTestCase {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
FILE: app/src/main/assets/migrations/10.sql
================================================
ALTER TABLE Notifications ADD COLUMN calibration_alert BOOLEAN;
ALTER TABLE Notifications ADD COLUMN double_calibration_alert BOOLEAN;
ALTER TABLE Notifications ADD COLUMN extra_calibration_alert BOOLEAN;
================================================
FILE: app/src/main/assets/migrations/16.sql
================================================
ALTER TABLE CalibrationSendQueue ADD COLUMN mongo_success BOOLEAN;
ALTER TABLE BgSendQueue ADD COLUMN mongo_success BOOLEAN;
================================================
FILE: app/src/main/assets/migrations/17.sql
================================================
ALTER TABLE Calibration ADD COLUMN possible_bad BOOLEAN;
================================================
FILE: app/src/main/assets/migrations/18.sql
================================================
ALTER TABLE Calibration ADD COLUMN first_decay REAL;
ALTER TABLE Calibration ADD COLUMN second_decay REAL;
ALTER TABLE Calibration ADD COLUMN first_slope REAL;
ALTER TABLE Calibration ADD COLUMN second_slope REAL;
================================================
FILE: app/src/main/assets/migrations/19.sql
================================================
ALTER TABLE Calibration ADD COLUMN first_intercept REAL;
ALTER TABLE Calibration ADD COLUMN second_intercept REAL;
ALTER TABLE Calibration ADD COLUMN first_scale REAL;
ALTER TABLE Calibration ADD COLUMN second_scale REAL;
================================================
FILE: app/src/main/assets/migrations/20.sql
================================================
ALTER TABLE Calibration ADD COLUMN check_in BOOLEAN;
================================================
FILE: app/src/main/assets/migrations/21.sql
================================================
ALTER TABLE ActiveBluetoothDevice ADD COLUMN connected BOOLEAN;
================================================
FILE: app/src/main/assets/migrations/23.sql
================================================
ALTER TABLE BgReadings ADD COLUMN raw_calculated REAL;
================================================
FILE: app/src/main/assets/migrations/24.sql
================================================
ALTER TABLE BgReadings ADD COLUMN hide_slope BOOLEAN;
================================================
FILE: app/src/main/assets/migrations/25.sql
================================================
ALTER TABLE BgReadings ADD COLUMN noise TEXT;
================================================
FILE: app/src/main/assets/migrations/26.sql
================================================
ALTER TABLE BgReadings ADD COLUMN filtered_data REAL DEFAULT 0;
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/AddCalibration.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
public class AddCalibration extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
Button button;
private String menu_name = "Add Calibration";
private NavigationDrawerFragment mNavigationDrawerFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(CollectionServiceStarter.isBTShare(getApplicationContext())) {
Intent intent = new Intent(this, Home.class);
startActivity(intent);
finish();
}
setContentView(R.layout.activity_add_calibration);
addListenerOnButton();
}
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
public void addListenerOnButton() {
button = (Button) findViewById(R.id.save_calibration_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Sensor.isActive()) {
EditText value = (EditText) findViewById(R.id.bg_value);
String string_value = value.getText().toString();
if (!TextUtils.isEmpty(string_value)){
double calValue = Double.parseDouble(string_value);
Calibration calibration = Calibration.create(calValue, getApplicationContext());
Intent tableIntent = new Intent(v.getContext(), Home.class);
startActivity(tableIntent);
finish();
} else {
value.setError("Calibration Can Not be blank");
}
} else {
Log.w("CALERROR", "ERROR");
}
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/AutoStart.java
================================================
package com.eveningoutpost.dexdrip;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
/**
* Created by stephenblack on 11/3/14.
*/
public class AutoStart extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.w("DexDrip", "Service auto starter, starting!");
CollectionServiceStarter.newStart(context);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/BluetoothScan.java
================================================
package com.eveningoutpost.dexdrip;
import android.annotation.TargetApi;
import android.app.ListActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Services.DexCollectionService;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import java.util.ArrayList;
@TargetApi(android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
public class BluetoothScan extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "Scan for BT";
private NavigationDrawerFragment mNavigationDrawerFragment;
private final static String TAG = BluetoothScan.class.getSimpleName();
private static final long SCAN_PERIOD = 10000;
private boolean is_scanning;
private boolean has_bluetooth;
private Handler mHandler;
private LeDeviceListAdapter mLeDeviceListAdapter;
private ArrayList found_devices;
private BluetoothAdapter bluetooth_adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth_scan);
ListView lv = (ListView)findViewById(android.R.id.list);
final BluetoothManager bluetooth_manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetooth_adapter = bluetooth_manager.getAdapter();
mHandler = new Handler();
if (bluetooth_adapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_LONG).show();
has_bluetooth = false;
finish();
return;
} else {
has_bluetooth = true;
}
if(bluetooth_manager == null) {
Toast.makeText(this, "This device does not seem to support bluetooth", Toast.LENGTH_LONG).show();
} else {
if(!bluetooth_manager.getAdapter().isEnabled()) {
Toast.makeText(this, "Bluetooth is turned off on this device currently", Toast.LENGTH_LONG).show();
} else {
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){
Toast.makeText(this, "The android version of this device is not compatible with Bluetooth Low Energy", Toast.LENGTH_LONG).show();
}
}
}
mLeDeviceListAdapter = new LeDeviceListAdapter();
setListAdapter(mLeDeviceListAdapter);
}
@Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
mLeDeviceListAdapter.clear();
}
@Override
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_bluetooth_scan, menu);
if (!is_scanning) {
menu.findItem(R.id.menu_stop).setVisible(false);
menu.findItem(R.id.menu_scan).setVisible(true);
} else {
menu.findItem(R.id.menu_stop).setVisible(true);
menu.findItem(R.id.menu_scan).setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_scan:
scanLeDevice(true);
BluetoothManager bluetooth_manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
Toast.makeText(this, "Scanning", Toast.LENGTH_LONG).show();
if(bluetooth_manager == null) {
Toast.makeText(this, "This device does not seem to support bluetooth", Toast.LENGTH_LONG).show();
} else {
if(!bluetooth_manager.getAdapter().isEnabled()) {
Toast.makeText(this, "Bluetooth is turned off on this device currently", Toast.LENGTH_LONG).show();
} else {
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){
Toast.makeText(this, "The android version of this device is not compatible with Bluetooth Low Energy", Toast.LENGTH_LONG).show();
}
}
}
return true;
// case R.id.menu_stop:
// Intent tableIntent = new Intent(this, RawDataTable.class);
// startActivity(tableIntent);
// return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
is_scanning = false;
bluetooth_adapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
is_scanning = true;
bluetooth_adapter.startLeScan(mLeScanCallback);
} else {
is_scanning = false;
bluetooth_adapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Log.d(TAG, "Item Clicked");
final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);
if (device == null) return;
Toast.makeText(this, R.string.connecting_to_device, Toast.LENGTH_LONG).show();
ActiveBluetoothDevice btDevice = new Select().from(ActiveBluetoothDevice.class)
.orderBy("_ID desc")
.executeSingle();
if (btDevice == null) {
ActiveBluetoothDevice newBtDevice = new ActiveBluetoothDevice();
newBtDevice.name = device.getName();
newBtDevice.address = device.getAddress();
newBtDevice.save();
} else {
btDevice.name = device.getName();
btDevice.address = device.getAddress();
btDevice.save();
}
if (is_scanning) {
bluetooth_adapter.stopLeScan(mLeScanCallback);
is_scanning = false;
}
Intent intent = new Intent(this, Home.class);
CollectionServiceStarter.newStart(getApplicationContext());
startActivity(intent);
finish();
}
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList();
mInflator = BluetoothScan.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if(!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
@Override
public int getCount() {
return mLeDevices.size();
}
@Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.listitem_device, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(i);
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0)
viewHolder.deviceName.setText(deviceName);
else
viewHolder.deviceName.setText(R.string.unknown_device);
viewHolder.deviceAddress.setText(device.getAddress());
return view;
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/CalibrationCheckInActivity.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.eveningoutpost.dexdrip.Home;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.SyncingService;
import com.eveningoutpost.dexdrip.R;
import com.eveningoutpost.dexdrip.Sensor;
public class CalibrationCheckInActivity extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "Check in calibration";
private NavigationDrawerFragment mNavigationDrawerFragment;
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calibration_check_in);
addListenerOnButton();
}
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
public void addListenerOnButton() {
button = (Button) findViewById(R.id.check_in_calibrations);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Sensor.isActive()) {
SyncingService.startActionCalibrationCheckin(getApplicationContext());
Toast.makeText(getApplicationContext(), "Checked in all calibrations", Toast.LENGTH_LONG).show();
Intent tableIntent = new Intent(v.getContext(), Home.class);
startActivity(tableIntent);
finish();
} else {
Log.w("CANNOT CALIBRATE WITHOUT CURRENT SENSOR", "ERROR");
}
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/CalibrationGraph.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import com.eveningoutpost.dexdrip.Models.Calibration;
import java.util.ArrayList;
import java.util.List;
import lecho.lib.hellocharts.model.Axis;
import lecho.lib.hellocharts.model.Line;
import lecho.lib.hellocharts.model.LineChartData;
import lecho.lib.hellocharts.model.PointValue;
import lecho.lib.hellocharts.util.Utils;
import lecho.lib.hellocharts.view.LineChartView;
public class CalibrationGraph extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "Calibration Graph";
private NavigationDrawerFragment mNavigationDrawerFragment;
private LineChartView chart;
private LineChartData data;
public double start_x = 50;
public double end_x = 300;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calibration_graph);
}
@Override
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
setupCharts();
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
public void setupCharts() {
chart = (LineChartView) findViewById(R.id.chart);
List calibrations = Calibration.allForSensor();
List values = new ArrayList();
for (Calibration calibration : calibrations) {
values.add(new PointValue((float)calibration.estimate_raw_at_time_of_calibration, (float)calibration.bg));
}
Line line = new Line(values);
line.setColor(Utils.COLOR_BLUE);
line.setHasLines(false);
line.setPointRadius(2);
line.setHasPoints(true);
Calibration calibration = Calibration.last();
List lineValues = new ArrayList();
if(calibration != null) {
lineValues.add(new PointValue((float) start_x, (float) (start_x * calibration.slope + calibration.intercept)));
lineValues.add(new PointValue((float) end_x, (float) (end_x * calibration.slope + calibration.intercept)));
}
Line calibrationLine = new Line(lineValues);
calibrationLine.setColor(Utils.COLOR_RED);
calibrationLine.setHasLines(true);
calibrationLine.setHasPoints(false);
Axis axisX = new Axis();
Axis axisY = new Axis().setHasLines(true);
axisX.setName("Raw Value");
axisY.setName("BG");
List lines = new ArrayList();
lines.add(line);
lines.add(calibrationLine);
data = new LineChartData(lines);
data.setAxisXBottom(axisX);
data.setAxisYLeft(axisY);
chart.setLineChartData(data);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/CalibrationOverride.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
public class CalibrationOverride extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
Button button;
private String menu_name = "Override Calibration";
private NavigationDrawerFragment mNavigationDrawerFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(CollectionServiceStarter.isBTShare(getApplicationContext())) {
Intent intent = new Intent(this, Home.class);
startActivity(intent);
finish();
}
setContentView(R.layout.activity_calibration_override);
addListenerOnButton();
}
@Override
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
public void addListenerOnButton() {
button = (Button) findViewById(R.id.save_calibration_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Sensor.isActive()) {
EditText value = (EditText) findViewById(R.id.bg_value);
String string_value = value.getText().toString();
if (!TextUtils.isEmpty(string_value)){
double calValue = Double.parseDouble(string_value);
Calibration last_calibration = Calibration.last();
last_calibration.sensor_confidence = 0;
last_calibration.slope_confidence = 0;
last_calibration.save();
Calibration.create(calValue, getApplicationContext());
Intent tableIntent = new Intent(v.getContext(), Home.class);
startActivity(tableIntent);
finish();
} else {
value.setError("Calibration Can Not be blank");
}
} else {
Log.w("CANNOT CALIBRATE WITHOUT CURRENT SENSOR", "ERROR");
}
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/DoubleCalibrationActivity.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
public class DoubleCalibrationActivity extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
Button button;
private String menu_name = "Add Double Calibration";
private NavigationDrawerFragment mNavigationDrawerFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(CollectionServiceStarter.isBTShare(getApplicationContext())) {
Intent intent = new Intent(this, Home.class);
startActivity(intent);
finish();
}
setContentView(R.layout.activity_double_calibration);
addListenerOnButton();
}
@Override
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
public void addListenerOnButton() {
button = (Button) findViewById(R.id.save_calibration_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Sensor.isActive()) {
EditText value_1 = (EditText) findViewById(R.id.bg_value_1);
EditText value_2 = (EditText) findViewById(R.id.bg_value_2);
String string_value_1 = value_1.getText().toString();
String string_value_2 = value_2.getText().toString();
if (!TextUtils.isEmpty(string_value_1)){
if(!TextUtils.isEmpty(string_value_2)) {
double calValue_1 = Double.parseDouble(string_value_1);
double calValue_2 = Double.parseDouble(string_value_2);
Calibration.initialCalibration(calValue_1, calValue_2, getApplicationContext());
Intent tableIntent = new Intent(v.getContext(), Home.class);
startActivity(tableIntent);
finish();
} else {
value_2.setError("Calibration Can Not be blank");
}
} else {
value_1.setError("Calibration Can Not be blank");
}
} else {
Log.w("DoubleCalibration", "ERROR");
}
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/FakeNumbers.java
================================================
package com.eveningoutpost.dexdrip;
import java.util.Date;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TimePicker;
import com.eveningoutpost.dexdrip.Models.BgReading;
public class FakeNumbers extends Activity {
public Button button;
public DatePicker dp;
public TimePicker tp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fake_numbers);
button = (Button)findViewById(R.id.log);
addListenerOnButton();
}
public void addListenerOnButton() {
button = (Button)findViewById(R.id.log);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
EditText value = (EditText) findViewById(R.id.bg_value);
int intValue = Integer.parseInt(value.getText().toString());
BgReading bgReading = BgReading.create(intValue * 1000, getApplicationContext(), new Date().getTime());
Intent intent = new Intent(getApplicationContext(), Home.class);
startActivity(intent);
finish();
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Home.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Paint;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.Services.WixelReader;
import com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.Intents;
import com.eveningoutpost.dexdrip.UtilityModels.Notifications;
import com.eveningoutpost.dexdrip.utils.DatabaseUtil;
import com.eveningoutpost.dexdrip.utils.ShareNotification;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import lecho.lib.hellocharts.ViewportChangeListener;
import lecho.lib.hellocharts.gesture.ZoomType;
import lecho.lib.hellocharts.model.Viewport;
import lecho.lib.hellocharts.view.LineChartView;
import lecho.lib.hellocharts.view.PreviewLineChartView;
public class Home extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "xDrip";
private NavigationDrawerFragment mNavigationDrawerFragment;
private LineChartView chart;
private PreviewLineChartView previewChart;
SharedPreferences prefs;
Viewport tempViewport = new Viewport();
Viewport holdViewport = new Viewport();
public float left;
public float right;
public float top;
public float bottom;
public boolean updateStuff;
public boolean updatingPreviewViewport = false;
public boolean updatingChartViewport = false;
boolean isBTWixel;
boolean isBTShare;
boolean isWifiWixel;
public BgGraphBuilder bgGraphBuilder;
BroadcastReceiver _broadcastReceiver;
BroadcastReceiver newDataReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CollectionServiceStarter collectionServiceStarter = new CollectionServiceStarter(getApplicationContext());
collectionServiceStarter.start(getApplicationContext());
PreferenceManager.setDefaultValues(this, R.xml.pref_notifications, false);
PreferenceManager.setDefaultValues(this, R.xml.pref_data_source, false);
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
checkEula();
setContentView(R.layout.activity_home);
}
public void checkEula() {
boolean IUnderstand = prefs.getBoolean("I_understand", false);
if (!IUnderstand) {
Intent intent = new Intent(getApplicationContext(), LicenseAgreementActivity.class);
startActivity(intent);
finish();
}
}
@Override
protected void onResume(){
super.onResume();
checkEula();
_broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {
updateCurrentBgInfo();
}
}
};
newDataReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
holdViewport.set(0, 0, 0, 0);
setupCharts();
updateCurrentBgInfo();
}
};
registerReceiver(_broadcastReceiver, new IntentFilter(Intent.ACTION_TIME_TICK));
registerReceiver(newDataReceiver, new IntentFilter(Intents.ACTION_NEW_BG_ESTIMATE_NO_DATA));
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
holdViewport.set(0, 0, 0, 0);
setupCharts();
updateCurrentBgInfo();
}
public void setupCharts() {
bgGraphBuilder = new BgGraphBuilder(this);
updateStuff = false;
chart = (LineChartView) findViewById(R.id.chart);
chart.setZoomType(ZoomType.HORIZONTAL);
previewChart = (PreviewLineChartView) findViewById(R.id.chart_preview);
previewChart.setZoomType(ZoomType.HORIZONTAL);
chart.setLineChartData(bgGraphBuilder.lineData());
previewChart.setLineChartData(bgGraphBuilder.previewLineData());
updateStuff = true;
previewChart.setViewportCalculationEnabled(true);
chart.setViewportCalculationEnabled(true);
previewChart.setViewportChangeListener(new ViewportListener());
chart.setViewportChangeListener(new ChartViewPortListener());
setViewport();
}
private class ChartViewPortListener implements ViewportChangeListener {
@Override
public void onViewportChanged(Viewport newViewport) {
if (!updatingPreviewViewport) {
updatingChartViewport = true;
previewChart.setZoomType(ZoomType.HORIZONTAL);
previewChart.setCurrentViewport(newViewport, false);
updatingChartViewport = false;
}
}
}
private class ViewportListener implements ViewportChangeListener {
@Override
public void onViewportChanged(Viewport newViewport) {
if (!updatingChartViewport) {
updatingPreviewViewport = true;
chart.setZoomType(ZoomType.HORIZONTAL);
chart.setCurrentViewport(newViewport, false);
tempViewport = newViewport;
updatingPreviewViewport = false;
}
if (updateStuff == true) {
holdViewport.set(newViewport.left, newViewport.top, newViewport.right, newViewport.bottom);
}
}
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
public void setViewport() {
if (tempViewport.left == 0.0 || holdViewport.left == 0.0 || holdViewport.right >= (new Date().getTime())) {
previewChart.setCurrentViewport(bgGraphBuilder.advanceViewport(chart, previewChart), false);
} else {
previewChart.setCurrentViewport(holdViewport, false);
}
}
@Override
public void onPause() {
super.onPause();
if (_broadcastReceiver != null) {
unregisterReceiver(_broadcastReceiver);
}
if(newDataReceiver != null) {
unregisterReceiver(newDataReceiver);
}
}
public void updateCurrentBgInfo() {
final TextView currentBgValueText = (TextView) findViewById(R.id.currentBgValueRealTime);
final TextView notificationText = (TextView)findViewById(R.id.notices);
notificationText.setText("");
isBTWixel = CollectionServiceStarter.isBTWixel(getApplicationContext());
isBTShare = CollectionServiceStarter.isBTShare(getApplicationContext());
isWifiWixel = CollectionServiceStarter.isWifiWixel(getApplicationContext());
if(isBTShare) {
if((android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)) {
notificationText.setText("Unfortunately your android version does not support Bluetooth Low Energy");
} else {
String receiverSn = prefs.getString("share_key", "SM00000000").toUpperCase();
if (receiverSn.compareTo("SM00000000") == 0 || receiverSn.length() == 0) {
notificationText.setText("Please set your Dex Receiver Serial Number in App Settings");
} else {
if (receiverSn.length() < 10) {
notificationText.setText("Double Check Dex Receiver Serial Number, should be 10 characters, don't forget the letters");
} else {
if (ActiveBluetoothDevice.first() == null) {
notificationText.setText("Now pair with your Dexcom Share");
} else {
if (!Sensor.isActive()) {
notificationText.setText("Now choose start your sensor in your settings");
} else {
displayCurrentInfo();
}
}
}
}
}
}
if(isBTWixel) {
if ((android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)) {
notificationText.setText("Unfortunately your android version does not support Bluetooth Low Energy");
} else {
if (ActiveBluetoothDevice.first() == null) {
notificationText.setText("First pair with your BT device!");
} else {
if (Sensor.isActive() && (Sensor.currentSensor().started_at + (60000 * 60 * 2)) < new Date().getTime()) {
if (BgReading.latest(2).size() > 1) {
List calibrations = Calibration.latest(2);
if (calibrations.size() > 1) {
if (calibrations.get(0).possible_bad != null && calibrations.get(0).possible_bad == true && calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad != true) {
notificationText.setText("Possible bad calibration slope, please have a glass of water, wash hands, then recalibrate in a few!");
}
displayCurrentInfo();
} else {
notificationText.setText("Please enter two calibrations to get started!");
}
} else {
if(BgReading.latestUnCalculated(2).size() < 2) {
notificationText.setText("Please wait, need 2 readings from transmitter first.");
} else {
List calibrations = Calibration.latest(2);
if (calibrations.size() < 2) {
notificationText.setText("Please enter two calibrations to get started!");
}
}
}
} else if (Sensor.isActive() && ((Sensor.currentSensor().started_at + (60000 * 60 * 2))) >= new Date().getTime()) {
double waitTime = ((Sensor.currentSensor().started_at + (60000 * 60 * 2)) - (new Date().getTime())) / (60000);
notificationText.setText("Please wait while sensor warms up! (" + String.format("%.2f", waitTime) + " minutes)");
} else {
notificationText.setText("Now start your sensor");
}
}
}
}
if(isWifiWixel) {
if (!WixelReader.IsConfigured(getApplicationContext())) {
notificationText.setText("First configure your wifi wixel reader ip addresses");
} else {
if (Sensor.isActive() && (Sensor.currentSensor().started_at + (60000 * 60 * 2)) < new Date().getTime()) {
if (BgReading.latest(2).size() > 1) {
List calibrations = Calibration.latest(2);
if (calibrations.size() > 1) {
if (calibrations.get(0).possible_bad != null && calibrations.get(0).possible_bad == true && calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad != true) {
notificationText.setText("Possible bad calibration slope, please have a glass of water, wash hands, then recalibrate in a few!");
}
displayCurrentInfo();
} else {
notificationText.setText("Please enter two calibrations to get started!");
}
} else {
notificationText.setText("Please wait, need 2 readings from transmitter first.");
}
} else if (Sensor.isActive() && ((Sensor.currentSensor().started_at + (60000 * 60 * 2))) >= new Date().getTime()) {
double waitTime = ((Sensor.currentSensor().started_at + (60000 * 60 * 2)) - (new Date().getTime())) / (60000);
notificationText.setText("Please wait while sensor warms up! (" + String.format("%.2f", waitTime) + " minutes)");
} else {
notificationText.setText("Now start your sensor");
}
}
}
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
public void displayCurrentInfo() {
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(0);
final TextView currentBgValueText = (TextView)findViewById(R.id.currentBgValueRealTime);
final TextView notificationText = (TextView)findViewById(R.id.notices);
if ((currentBgValueText.getPaintFlags() & Paint.STRIKE_THRU_TEXT_FLAG) > 0) {
currentBgValueText.setPaintFlags(currentBgValueText.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
BgReading lastBgreading = BgReading.lastNoSenssor();
boolean predictive = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean("predictive_bg", false);
if(isBTShare) { predictive = false; }
if (lastBgreading != null) {
double estimate = 0;
if ((new Date().getTime()) - (60000 * 11) - lastBgreading.timestamp > 0) {
notificationText.setText("Signal Missed");
if(!predictive){
estimate=lastBgreading.calculated_value;
} else {
estimate = BgReading.estimated_bg(lastBgreading.timestamp + (6000 * 7));
}
currentBgValueText.setText(bgGraphBuilder.unitized_string(estimate));
currentBgValueText.setPaintFlags(currentBgValueText.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
if(!predictive){
estimate=lastBgreading.calculated_value;
String stringEstimate = bgGraphBuilder.unitized_string(estimate);
String slope_arrow = BgReading.slopeArrow((lastBgreading.calculated_value_slope * 60000));
if(lastBgreading.hide_slope) {
slope_arrow = "";
}
currentBgValueText.setText( stringEstimate + " " + slope_arrow);
} else {
estimate = BgReading.activePrediction();
String stringEstimate = bgGraphBuilder.unitized_string(estimate);
currentBgValueText.setText( stringEstimate + " " + BgReading.slopeArrow());
}
}
if(bgGraphBuilder.unitized(estimate) <= bgGraphBuilder.lowMark) {
currentBgValueText.setTextColor(Color.parseColor("#C30909"));
} else if(bgGraphBuilder.unitized(estimate) >= bgGraphBuilder.highMark) {
currentBgValueText.setTextColor(Color.parseColor("#FFBB33"));
} else {
currentBgValueText.setTextColor(Color.WHITE);
}
}
setupCharts();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_home, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_export_database) {
new AsyncTask() {
@Override
protected String doInBackground(Void... params) {
return DatabaseUtil.saveSql(getBaseContext());
}
@Override
protected void onPostExecute(String filename) {
super.onPostExecute(filename);
final Context ctx = getApplicationContext();
Toast.makeText(ctx, "Export stored at " + filename, Toast.LENGTH_SHORT).show();
final NotificationCompat.Builder n = new NotificationCompat.Builder(ctx);
n.setContentTitle("Export complete");
n.setContentText("Ready to be sent.");
n.setAutoCancel(true);
n.setSmallIcon(R.drawable.ic_action_communication_invert_colors_on);
ShareNotification.viewOrShare("application/octet-stream", Uri.fromFile(new File(filename)), n, ctx);
final NotificationManager manager = (NotificationManager) ctx.getSystemService(Service.NOTIFICATION_SERVICE);
manager.notify(Notifications.exportCompleteNotificationId, n.build());
}
}.execute();
return true;
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/CRC16.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CRC16 {
public static byte[] calculate(byte[] buff, int start, int end) {
int crcShort = 0;
for (int i = start; i < end; i++) {
crcShort = ((crcShort >>> 8) | (crcShort << 8) )& 0xffff;
crcShort ^= (buff[i] & 0xff);
crcShort ^= ((crcShort & 0xff) >> 4);
crcShort ^= (crcShort << 12) & 0xffff;
crcShort ^= ((crcShort & 0xFF) << 5) & 0xffff;
}
crcShort &= 0xffff;
return new byte[] {(byte) (crcShort & 0xff), (byte) ((crcShort >> 8) & 0xff)};
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/CRCFailRuntimeException.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CRCFailRuntimeException extends RuntimeException {
public CRCFailRuntimeException(String message){
super(message);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/Constants.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class Constants {
public final static int NULL = 0;
public final static int ACK = 1;
public final static int NAK = 2;
public final static int INVALID_COMMAND = 3;
public final static int INVALID_PARAM = 4;
public final static int INCOMPLETE_PACKET_RECEIVED = 5;
public final static int RECEIVER_ERROR = 6;
public final static int INVALID_MODE = 7;
public final static int PING = 10;
public final static int READ_FIRMWARE_HEADER = 11;
public final static int READ_DATABASE_PARTITION_INFO = 15;
public final static int READ_DATABASE_PAGE_RANGE = 16;
public final static int READ_DATABASE_PAGES = 17;
public final static int READ_DATABASE_PAGE_HEADER = 18;
public final static int READ_TRANSMITTER_ID = 25;
public final static int WRITE_TRANSMITTER_ID = 26;
public final static int READ_LANGUAGE = 27;
public final static int WRITE_LANGUAGE = 28;
public final static int READ_DISPLAY_TIME_OFFSET = 29;
public final static int WRITE_DISPLAY_TIME_OFFSET = 30;
public final static int READ_RTC = 31;
public final static int RESET_RECEIVER = 32;
public final static int READ_BATTERY_LEVEL = 33;
public final static int READ_SYSTEM_TIME = 34;
public final static int READ_SYSTEM_TIME_OFFSET = 35;
public final static int WRITE_SYSTEM_TIME = 36;
public final static int READ_GLUCOSE_UNIT = 37;
public final static int WRITE_GLUCOSE_UNIT = 38;
public final static int READ_BLINDED_MODE = 39;
public final static int WRITE_BLINDED_MODE = 40;
public final static int READ_CLOCK_MODE = 41;
public final static int WRITE_CLOCK_MODE = 42;
public final static int READ_DEVICE_MODE = 43;
public final static int ERASE_DATABASE = 45;
public final static int SHUTDOWN_RECEIVER = 46;
public final static int WRITE_PC_PARAMETERS = 47;
public final static int READ_BATTERY_STATE = 48;
public final static int READ_HARDWARE_BOARD_ID = 49;
public final static int READ_FIRMWARE_SETTINGS = 54;
public final static int READ_ENABLE_SETUP_WIZARD_FLAG = 55;
public final static int READ_SETUP_WIZARD_STATE = 57;
public final static int MAX_COMMAND = 59;
public final static int MAX_POSSIBLE_COMMAND = 255;
public final static int EGV_VALUE_MASK = 1023;
public final static int EGV_DISPLAY_ONLY_MASK = 32768;
public final static int EGV_TREND_ARROW_MASK = 15;
public final static int EGV_NOISE_MASK = 112;
public final static float MG_DL_TO_MMOL_L = 0.05556f;
public final static int CRC_LEN = 2;
public enum BATTERY_STATES {
NONE,
CHARGING,
NOT_CHARGING,
NTC_FAULT,
BAD_BATTERY
}
public enum RECORD_TYPES {
MANUFACTURING_DATA,
FIRMWARE_PARAMETER_DATA,
PC_SOFTWARE_PARAMETER,
SENSOR_DATA,
EGV_DATA,
CAL_SET,
DEVIATION,
INSERTION_TIME,
RECEIVER_LOG_DATA,
RECEIVER_ERROR_DATA,
METER_DATA,
USER_EVENT_DATA,
USER_SETTING_DATA,
MAX_VALUE
}
public enum TREND_ARROW_VALUES {
NONE(0),
DOUBLE_UP(1,"\u21C8", "DoubleUp"),
SINGLE_UP(2,"\u2191", "SingleUp"),
UP_45(3,"\u2197", "FortyFiveUp"),
FLAT(4,"\u2192", "Flat"),
DOWN_45(5,"\u2198", "FortyFiveDown"),
SINGLE_DOWN(6,"\u2193", "SingleDown"),
DOUBLE_DOWN(7,"\u21CA", "DoubleDown"),
NOT_COMPUTABLE(8, "", "NOT_COMPUTABLE"),
OUT_OF_RANGE(9, "", "OUT_OF_RANGE");
private String arrowSymbol;
private String trendName;
private int myID;
TREND_ARROW_VALUES(int id, String a, String t) {
myID=id;
arrowSymbol = a;
trendName = t;
}
TREND_ARROW_VALUES(int id) {
this(id,null, null);
}
public String Symbol() {
if (arrowSymbol == null) {
return "\u2194";
} else {
return arrowSymbol;
}
}
public String friendlyTrendName() {
if (trendName == null) {
return this.name().replace("_", " ");
} else {
return this.trendName;
}
}
public int getID(){
return myID;
}
}
public enum SPECIALBGVALUES_MGDL {
NONE("??0", 0),
SENSORNOTACTIVE("?SN", 1),
MINIMALLYEGVAB("??2", 2),
NOANTENNA("?NA", 3),
SENSOROUTOFCAL("?NC", 5),
COUNTSAB("?CD", 6),
ABSOLUTEAB("?AD", 9),
POWERAB("???", 10),
RFBADSTATUS("?RF", 12);
private String name;
private int val;
private SPECIALBGVALUES_MGDL(String s, int i){
name=s;
val=i;
}
public int getValue(){
return val;
}
public String toString(){
return name;
}
public static SPECIALBGVALUES_MGDL getEGVSpecialValue(int val){
for (SPECIALBGVALUES_MGDL e: values()){
if (e.getValue()==val)
return e;
}
return null;
}
public static boolean isSpecialValue(int val){
for (SPECIALBGVALUES_MGDL e: values()){
if (e.getValue()==val)
return true;
}
return false;
}
}
public enum InsertionState {
NONE,
REMOVED,
EXPIRED,
RESIDUAL_DEVIATION,
COUNTS_DEVIATION,
SECOND_SESSION,
OFF_TIME_LOSS,
STARTED,
BAD_TRANSMITTER,
MANUFACTURING_MODE,
MAX_VALUE
}
public enum NOISE {
NOISE_NONE(0),
CLEAN(1),
LIGHT(2),
MEDIUM(3),
HEAVY(4),
NOT_COMPUTED(5),
MAX(6);
private final int value;
private NOISE(int value) {
this.value = value;
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/PacketBuilder.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class PacketBuilder {
public static final int MAX_PAYLOAD = 1584;
public static final int MIN_LEN = 6;
public static final int MAX_LEN = MAX_PAYLOAD + MIN_LEN;
public static final byte SOF = 0x01;
public static final int OFFSET_SOF = 0;
public static final int OFFSET_LENGTH = 1;
public static final int OFFSET_NULL = 2;
public static final byte NULL = 0x00;
public static final int OFFSET_CMD = 3;
public static final int OFFSET_PAYLOAD = 4;
public static final int CRC_LEN = 2;
public static final int HEADER_LEN = 4;
public ArrayList packet;
public int command;
public ArrayList payload;
public PacketBuilder(int command) {
this.command = command;
}
public PacketBuilder(int command, ArrayList payload) {
this.command = command;
this.payload = payload;
}
public byte[] compose() {
packet = new ArrayList();
packet.add(OFFSET_SOF, SOF);
packet.add(OFFSET_LENGTH, getLength());
packet.add(OFFSET_NULL, NULL);
packet.add(OFFSET_CMD, (byte) command);
if (this.payload != null) { this.packet.addAll(OFFSET_PAYLOAD, this.payload); }
byte[] crc16 = CRC16.calculate(toBytes(), 0, this.packet.size());
this.packet.add(crc16[0]);
this.packet.add(crc16[1]);
Log.d("ShareTest", "About to start adding to Byte, size: " + this.packet.size());
return this.toBytes();
}
public List composeList() {
packet = new ArrayList();
packet.add(OFFSET_SOF, SOF);
packet.add(OFFSET_LENGTH, getLength());
packet.add(OFFSET_NULL, NULL);
packet.add(OFFSET_CMD, (byte) command);
if (this.payload != null) { this.packet.addAll(OFFSET_PAYLOAD, this.payload); }
byte[] crc16 = CRC16.calculate(toBytes(), 0, this.packet.size());
this.packet.add(crc16[0]);
this.packet.add(crc16[1]);
Log.d("ShareTest", "About to start adding to ByteList, size: " + this.packet.size());
return this.toBytesList();
}
private byte getLength() {
int packetSize = payload == null ? MIN_LEN : payload.size() + CRC_LEN + HEADER_LEN;
if (packetSize > MAX_LEN) {
throw new IndexOutOfBoundsException(packetSize + " bytes, but packet must between "
+ MIN_LEN + " and " + MAX_LEN + " bytes.");
}
return (byte) packetSize;
}
public byte[] toBytes() {
byte[] b = new byte[this.packet.size()];
for (int i = 0; i < this.packet.size(); i++) {
b[i] = this.packet.get(i).byteValue();
}
return b;
}
public List toBytesList() {
List byteMessages = new ArrayList();
double totalPacketSize = packet.size();
int messages =(int) Math.ceil(totalPacketSize/18);
for(int m = 0; m < messages; m++) {
int thisPacketSize;
if (m == messages - 1) {
thisPacketSize = ((this.packet.size()+2) % 18);
} else {
thisPacketSize = (20);
}
int offset = m * 18;
Log.d("ShareTest", "This packet size: " + thisPacketSize);
byte[] b = new byte[thisPacketSize];
b[0] = (byte) (m + 1);
b[1] = (byte) (messages);
for (int i = 2; i < thisPacketSize; i++) {
b[i] = packet.get(offset + i - 2).byteValue();
}
byteMessages.add(b);
}
return byteMessages;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/ReadData.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.CdcAcmSerialDriver;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GenericXMLRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.PageHeader;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialPort;
import org.w3c.dom.Element;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
public class ReadData {
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
private static final String TAG = ReadData.class.getSimpleName();
private static final int IO_TIMEOUT = 3000;
private static final int MIN_LEN = 256;
private UsbSerialDriver mSerialDevice;
protected final Object mReadBufferLock = new Object();
private UsbDeviceConnection mConnection;
private UsbDevice mDevice;
public ReadData(){}
public ReadData(UsbSerialDriver device) {
mSerialDevice = device;
}
public ReadData(UsbSerialDriver device, UsbDeviceConnection connection, UsbDevice usbDevice) {
mSerialDevice = device;
mConnection = connection;
mDevice = usbDevice;
try {
mSerialDevice.getPorts().get(0).open(connection);
} catch(IOException e) {
Log.w("FAILED WHILE", "trying to open");
}
// }
}
public EGVRecord[] getRecentEGVs() {
int recordType = Constants.RECORD_TYPES.EGV_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
return readDataBasePage(recordType, endPage);
}
public EGVRecord[] getRecentEGVsPages(int numOfRecentPages) {
if (numOfRecentPages < 1) {
throw new IllegalArgumentException("Number of pages must be greater than 1.");
}
Log.d(TAG, "Reading EGV page range...");
int recordType = Constants.RECORD_TYPES.EGV_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading " + numOfRecentPages + " EGV page(s)...");
numOfRecentPages = numOfRecentPages - 1;
EGVRecord[] allPages = new EGVRecord[0];
for (int i = Math.min(numOfRecentPages,endPage); i >= 0; i--) {
int nextPage = endPage - i;
Log.d(TAG, "Reading #" + i + " EGV pages (page number " + nextPage + ")");
EGVRecord[] ithEGVRecordPage = readDataBasePage(recordType, nextPage);
EGVRecord[] result = Arrays.copyOf(allPages, allPages.length + ithEGVRecordPage.length);
System.arraycopy(ithEGVRecordPage, 0, result, allPages.length, ithEGVRecordPage.length);
allPages = result;
}
Log.d(TAG, "Read complete of EGV pages.");
return allPages;
}
public long getTimeSinceEGVRecord(EGVRecord egvRecord) {
return readSystemTime() - egvRecord.getSystemTimeSeconds();
}
public MeterRecord[] getRecentMeterRecords() {
Log.d(TAG, "Reading Meter page...");
int recordType = Constants.RECORD_TYPES.METER_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
return readDataBasePage(recordType, endPage);
}
public SensorRecord[] getRecentSensorRecords(int numOfRecentPages) {
if (numOfRecentPages < 1) {
throw new IllegalArgumentException("Number of pages must be greater than 1.");
}
Log.d(TAG, "Reading Sensor page range...");
int recordType = Constants.RECORD_TYPES.SENSOR_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading " + numOfRecentPages + " Sensor page(s)...");
numOfRecentPages = numOfRecentPages - 1;
SensorRecord[] allPages = new SensorRecord[0];
for (int i = Math.min(numOfRecentPages,endPage); i >= 0; i--) {
int nextPage = endPage - i;
Log.d(TAG, "Reading #" + i + " Sensor pages (page number " + nextPage + ")");
SensorRecord[] ithSensorRecordPage = readDataBasePage(recordType, nextPage);
SensorRecord[] result = Arrays.copyOf(allPages, allPages.length + ithSensorRecordPage.length);
System.arraycopy(ithSensorRecordPage, 0, result, allPages.length, ithSensorRecordPage.length);
allPages = result;
}
Log.d(TAG, "Read complete of Sensor pages.");
return allPages;
}
public CalRecord[] getRecentCalRecords() {
Log.d(TAG, "Reading Cal Records page range...");
int recordType = Constants.RECORD_TYPES.CAL_SET.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading Cal Records page...");
return readDataBasePage(recordType, endPage);
}
public byte[] getRecentCalRecordsTest() {
Log.d(TAG, "Reading Cal Records page range...");
int recordType = Constants.RECORD_TYPES.CAL_SET.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading Cal Records page...");
return readDataBasePageTest(recordType, endPage);
}
public boolean ping() {
writeCommand(Constants.PING);
return read(MIN_LEN).getCommand() == Constants.ACK;
}
public int readBatteryLevel() {
Log.d(TAG, "Reading battery level...");
writeCommand(Constants.READ_BATTERY_LEVEL);
byte[] readData = read(MIN_LEN).getData();
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt();
}
public String readSerialNumber() {
int PAGE_OFFSET = 0;
byte[] readData = readDataBasePage(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), PAGE_OFFSET);
Element md = ParsePage(readData, Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal());
return md.getAttribute("SerialNumber");
}
public Date readDisplayTime() {
return Utils.receiverTimeToDate(readSystemTime() + readDisplayTimeOffset());
}
public long readSystemTime() {
Log.d(TAG, "Reading system time...");
writeCommand(Constants.READ_SYSTEM_TIME);
byte[] readData = read(MIN_LEN).getData();
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffff;
}
public int readDisplayTimeOffset() {
Log.d(TAG, "Reading display time offset...");
writeCommand(Constants.READ_DISPLAY_TIME_OFFSET);
byte[] readData = read(MIN_LEN).getData();
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffff;
}
private int readDataBasePageRange(int recordType) {
ArrayList payload = new ArrayList();
Log.d(TAG, "adding Payload");
payload.add((byte) recordType);
Log.d(TAG, "Sending write command");
writeCommand(Constants.READ_DATABASE_PAGE_RANGE, payload);
Log.d(TAG, "About to call getdata");
byte[] readData = read(MIN_LEN).getData();
Log.d(TAG, "Going to return");
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt(4);
}
private T readDataBasePage(int recordType, int page) {
byte numOfPages = 1;
if (page < 0){
throw new IllegalArgumentException("Invalid page requested:" + page);
}
ArrayList payload = new ArrayList();
payload.add((byte) recordType);
byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();
payload.add(pageInt[3]);
payload.add(pageInt[2]);
payload.add(pageInt[1]);
payload.add(pageInt[0]);
payload.add(numOfPages);
writeCommand(Constants.READ_DATABASE_PAGES, payload);
byte[] readData = read(2122).getData();
return ParsePage(readData, recordType);
}
private byte[] readDataBasePageTest(int recordType, int page) {
byte numOfPages = 1;
if (page < 0){
throw new IllegalArgumentException("Invalid page requested:" + page);
}
ArrayList payload = new ArrayList();
payload.add((byte) recordType);
byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();
payload.add(pageInt[3]);
payload.add(pageInt[2]);
payload.add(pageInt[1]);
payload.add(pageInt[0]);
payload.add(numOfPages);
return writeCommandTest(Constants.READ_DATABASE_PAGES, payload);
}
private void writeCommand(int command, ArrayList payload) {
byte[] packet = new PacketBuilder(command, payload).compose();
if (mSerialDevice != null) {
try {
// UsbInterface mDataInterface = mDevice.getInterface(1);
// UsbEndpoint mWriteEndpoint = mDataInterface.getEndpoint(0);
// mConnection.bulkTransfer(mWriteEndpoint, packet, packet.length, IO_TIMEOUT);
mSerialDevice.getPorts().get(0).write(packet, IO_TIMEOUT);
} catch (Exception e) {
Log.e(TAG, "Unable to write to serial device.", e);
}
}
}
private byte[] writeCommandTest(int command, ArrayList payload) {
byte[] packet = new PacketBuilder(command, payload).compose();
return packet;
}
private void writeCommand(int command) {
byte[] packet = new PacketBuilder(command).compose();
if (mSerialDevice != null) {
try {
// UsbInterface mDataInterface = mDevice.getInterface(1);
// UsbEndpoint mWriteEndpoint = mDataInterface.getEndpoint(0);
// mConnection.bulkTransfer(mWriteEndpoint, packet, packet.length, IO_TIMEOUT);
mSerialDevice.getPorts().get(0).write(packet, IO_TIMEOUT);
} catch (Exception e) {
Log.e(TAG, "Unable to write to serial device.", e);
}
}
}
private ReadPacket read(int numOfBytes) {
byte[] readData = new byte[numOfBytes];
int len = 0;
try {
// UsbInterface mDataInterface = mDevice.getInterface(1);
// UsbEndpoint mReadEndpoint = mDataInterface.getEndpoint(1);
// byte[] mReadBuffer;
// mReadBuffer = new byte[16 * 1024];
//
// int readAmt = Math.min(readData.length, mReadBuffer.length);
// synchronized (mReadBufferLock) {
//
//
// Log.d(TAG, "Read about to call bulk transfer.");
// if (len < 0) {
// // This sucks: we get -1 on timeout, not 0 as preferred.
// // We *should* use UsbRequest, except it has a bug/api oversight
// // where there is no way to determine the number of bytes read
// // in response :\ -- http://b.android.com/28023
// if (IO_TIMEOUT == Integer.MAX_VALUE) {
// // Hack: Special case "~infinite timeout" as an error.
// len = -1;
// }
// len = 0;
// }
//
//// System.arraycopy(mReadBuffer, 0, readData, 0, readAmt);
// }
// len = mConnection.bulkTransfer(mReadEndpoint, readData, readAmt, IO_TIMEOUT);
len = mSerialDevice.getPorts().get(0).read(readData, IO_TIMEOUT);
Log.d(TAG, "Read " + len + " byte(s) complete.");
// Add a 100ms delay for when multiple write/reads are occurring in series
Thread.sleep(100);
// TODO: this debug code to print data of the read, should be removed after
// finding the source of the reading issue
String bytes = "";
int readAmount = len;
for (int i = 0; i < readAmount; i++) bytes += String.format("%02x", readData[i]) + " ";
Log.d(TAG, "Read data: " + bytes);
////////////////////////////////////////////////////////////////////////////////////////
} catch (Exception e) {
Log.e(TAG, "Unable to read from serial device.", e);
}
byte[] data = Arrays.copyOfRange(readData, 0, len);
return new ReadPacket(data);
}
private T ParsePage(byte[] data, int recordType) {
int HEADER_LEN = 28;
PageHeader pageHeader=new PageHeader(data);
int NUM_REC_OFFSET = 4;
int numRec = data[NUM_REC_OFFSET];
int rec_len;
switch (Constants.RECORD_TYPES.values()[recordType]) {
case MANUFACTURING_DATA:
GenericXMLRecord xmlRecord = new GenericXMLRecord(Arrays.copyOfRange(data, HEADER_LEN, data.length - 1));
return (T) xmlRecord;
case SENSOR_DATA:
rec_len = 20;
SensorRecord[] sensorRecords = new SensorRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
sensorRecords[i] = new SensorRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) sensorRecords;
case EGV_DATA:
rec_len = 13;
EGVRecord[] egvRecords = new EGVRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
egvRecords[i] = new EGVRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) egvRecords;
case METER_DATA:
rec_len = 16;
MeterRecord[] meterRecords = new MeterRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
meterRecords[i] = new MeterRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) meterRecords;
case CAL_SET:
rec_len = 249;
if (pageHeader.getRevision()<=2) {
rec_len = 148;
}
CalRecord[] calRecords = new CalRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
calRecords[i] = new CalRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) calRecords;
default:
// Throw error "Database record not supported"
break;
}
return (T) null;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/ReadDataShare.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GenericXMLRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.PageHeader;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;
import com.eveningoutpost.dexdrip.Services.DexCollectionService;
import com.eveningoutpost.dexdrip.Services.DexShareCollectionService;
import com.eveningoutpost.dexdrip.ShareTest;
import org.w3c.dom.Element;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import rx.Observable;
import rx.functions.Action1;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class ReadDataShare {
byte[] accumulatedResponse;
private ShareTest mShareTest;
private DexShareCollectionService mCollectionService;
public ReadDataShare(ShareTest aShareTest){
mShareTest = aShareTest;
}
public ReadDataShare(DexShareCollectionService collectionService){
mCollectionService = collectionService;
}
public void getRecentEGVs(final Action1 recordListener) {
final int recordType = Constants.RECORD_TYPES.EGV_DATA.ordinal();
final Action1 fullPageListener = new Action1() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1 databasePageRangeCaller = new Action1() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getRecentMeterRecords(final Action1 recordListener) {
final int recordType = Constants.RECORD_TYPES.METER_DATA.ordinal();
final Action1 fullPageListener = new Action1() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1 databasePageRangeCaller = new Action1() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getRecentCalRecords(final Action1 recordListener) {
final int recordType = Constants.RECORD_TYPES.CAL_SET.ordinal();
final Action1 fullPageListener = new Action1() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1 databasePageRangeCaller = new Action1() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getRecentSensorRecords(final Action1 recordListener) {
final int recordType = Constants.RECORD_TYPES.SENSOR_DATA.ordinal();
final Action1 fullPageListener = new Action1() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1 databasePageRangeCaller = new Action1() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getTimeSinceEGVRecord(final EGVRecord egvRecord, final Action1 timeSinceEgvRecord) {
Action1 tempSystemTimeListener = new Action1() {
@Override
public void call(Long s) { Observable.just(s - egvRecord.getSystemTimeSeconds()).subscribe(timeSinceEgvRecord); }
};
readSystemTime(tempSystemTimeListener);
}
public void ping(final Action1 pingListener) {
Action1 pingReader = new Action1() {
@Override
public void call(byte[] s) { Observable.just(read(0, s).getCommand() == Constants.ACK).subscribe(pingListener); }
};
writeCommand(Constants.PING, pingReader);
}
public void readBatteryLevel(final Action1 batteryLevelListener) {
Action1 batteryLevelReader = new Action1() {
@Override //TODO: find out if this should be wrapped in read(s).getData();
public void call(byte[] s) { Observable.just(ByteBuffer.wrap(s).order(ByteOrder.LITTLE_ENDIAN).getInt()).subscribe(batteryLevelListener); }
};
writeCommand(Constants.READ_BATTERY_LEVEL, batteryLevelReader);
}
public void readSerialNumber(final Action1 serialNumberListener) {
final Action1 manufacturingDataListener = new Action1() {
@Override
public void call(byte[] s) {
Element el = ParsePage(s, Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal());
Observable.just(el.getAttribute("SerialNumber")).subscribe(serialNumberListener);
}
};
readDataBasePage(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), 0, manufacturingDataListener);
}
public void readDisplayTime(final Action1 displayTimeListener) {
Action1 tempSystemTimeListener = new Action1() {
@Override
public void call(Long s) {
final long systemTime = s;
Action1 tempSystemTimeListener = new Action1() {
@Override
public void call(Long s) {
Date dateDisplayTime = Utils.receiverTimeToDate(systemTime + s);
Observable.just(dateDisplayTime).subscribe(displayTimeListener); }
};
readDisplayTimeOffset(tempSystemTimeListener);
}
};
readSystemTime(tempSystemTimeListener);
}
public void readSystemTime(final Action1 systemTimeListener) {
Action1 systemTimeReader = new Action1() {
@Override
public void call(byte[] s) {
Observable.just(Utils.receiverTimeToDate(ByteBuffer.wrap(read(0,s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt()).getTime()).subscribe(systemTimeListener);
}
};
writeCommand(Constants.READ_SYSTEM_TIME, systemTimeReader);
}
public void readDisplayTimeOffset(final Action1 displayTimeOffsetListener) {
Action1 displayTimeOffsetReader = new Action1() {
@Override
public void call(byte[] s) { Observable.just((long) ByteBuffer.wrap(read(0,s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt()).subscribe(displayTimeOffsetListener); }
};
writeCommand(Constants.READ_DISPLAY_TIME_OFFSET, displayTimeOffsetReader);
}
private void readDataBasePageRange(int recordType, final Action1 databasePageRangeCaller) {
ArrayList payload = new ArrayList();
payload.add((byte) recordType);
final Action1 databasePageRangeListener = new Action1() {
@Override
public void call(byte[] s) {
Observable.just(ByteBuffer.wrap(new ReadPacket(s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt(4)).subscribe(databasePageRangeCaller);
}
};
writeCommand(Constants.READ_DATABASE_PAGE_RANGE, payload, databasePageRangeListener);
}
private T readDataBasePage(final int recordType, int page, final Action1 fullPageListener) {
byte numOfPages = 1;
if (page < 0){ throw new IllegalArgumentException("Invalid page requested:" + page); }
ArrayList payload = new ArrayList();
payload.add((byte) recordType);
byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();
payload.add(pageInt[3]);
payload.add(pageInt[2]);
payload.add(pageInt[1]);
payload.add(pageInt[0]);
payload.add(numOfPages);
accumulatedResponse = null;
final Action1 databasePageReader = new Action1() {
@Override
public void call(byte[] s) {
Log.d("ShareTest", "Database Page Reader received SIZE: " + s.length);
byte[] temp = s;
if (accumulatedResponse == null) {
accumulatedResponse = s;
} else {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(accumulatedResponse);
outputStream.write(temp);
accumulatedResponse = outputStream.toByteArray();
Log.d("ShareTest", "Combined Response length: " + accumulatedResponse.length);
} catch (Exception e) { e.printStackTrace(); }
}
if (temp.length < 20) { Observable.just(accumulatedResponse).subscribe(fullPageListener).unsubscribe(); }
}
};
writeCommand(Constants.READ_DATABASE_PAGES, payload, databasePageReader);
return null;
}
private void writeCommand(int command, ArrayList payload, Action1 responseListener) {
List packets = new PacketBuilder(command, payload).composeList();
if(mShareTest != null) { mShareTest.writeCommand(packets, 0, responseListener); }
else if (mCollectionService != null) { mCollectionService.writeCommand(packets, 0, responseListener); }
}
private void writeCommand(int command, Action1 responseListener) {
List packets = new PacketBuilder(command).composeList();
if(mShareTest != null) { mShareTest.writeCommand(packets, 0, responseListener); }
else if (mCollectionService != null) { mCollectionService.writeCommand(packets, 0, responseListener); }
}
private ReadPacket read(int numOfBytes, byte[] readPacket) {
return new ReadPacket(Arrays.copyOfRange(readPacket, 0, readPacket.length));
}
private T ParsePage(byte[] data, int recordType) { return ParsePage(data, recordType, null); }
private T ParsePage(byte[] data, int recordType, Action1 parsedPageReceiver) {
int HEADER_LEN = 28;
PageHeader pageHeader=new PageHeader(data);
int NUM_REC_OFFSET = 4;
int numRec = data[NUM_REC_OFFSET];
int rec_len;
switch (Constants.RECORD_TYPES.values()[recordType]) {
case MANUFACTURING_DATA:
GenericXMLRecord xmlRecord = new GenericXMLRecord(Arrays.copyOfRange(data, HEADER_LEN, data.length - 1));
if(parsedPageReceiver != null) {
Observable.just((T) xmlRecord).subscribe(parsedPageReceiver);
} else {
return (T) xmlRecord;
}
break;
case SENSOR_DATA:
rec_len = 20;
SensorRecord[] sensorRecords = new SensorRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
sensorRecords[i] = new SensorRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) sensorRecords).subscribe(parsedPageReceiver);
} else {
return (T) sensorRecords;
}
break;
case EGV_DATA:
rec_len = 13;
EGVRecord[] egvRecords = new EGVRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
egvRecords[i] = new EGVRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) egvRecords).subscribe(parsedPageReceiver);
} else {
return (T) egvRecords;
}
break;
case METER_DATA:
rec_len = 16;
MeterRecord[] meterRecords = new MeterRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
meterRecords[i] = new MeterRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) meterRecords).subscribe(parsedPageReceiver);
} else {
return (T) meterRecords;
}
break;
case CAL_SET:
rec_len = 249;
if (pageHeader.getRevision()<=2) { rec_len = 148; }
CalRecord[] calRecords = new CalRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
calRecords[i] = new CalRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) calRecords).subscribe(parsedPageReceiver);
} else {
return (T) calRecords;
}
break;
default:
break;
}
Observable.just((T) null).subscribe(parsedPageReceiver);
return (T) null;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/ReadPacket.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import java.util.Arrays;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class ReadPacket {
private int command;
private byte[] data;
private byte[] crc_calc;
private byte[] crc;
private int OFFSET_CMD = 3;
private int OFFSET_DATA = 4;
private int CRC_LEN = 2;
public ReadPacket(byte[] readPacket) {
this.command = readPacket[OFFSET_CMD];
this.data = Arrays.copyOfRange(readPacket, OFFSET_DATA, readPacket.length - CRC_LEN);
this.crc = Arrays.copyOfRange(readPacket, readPacket.length - CRC_LEN, readPacket.length);
this.crc_calc=CRC16.calculate(readPacket, 0, readPacket.length - 2);
if (!Arrays.equals(this.crc, this.crc_calc)) {
throw new CRCFailRuntimeException("CRC check failed: " + Utils.bytesToHex(this.crc) + " vs " + Utils.bytesToHex(this.crc_calc));
}
}
public int getCommand() {
return command;
}
public byte[] getData() {
return data;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/SyncingService.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import android.app.IntentService;
import android.bluetooth.BluetoothClass;
import android.content.Intent;
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.CdcAcmSerialDriver;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.ProbeTable;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialProber;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GlucoseDataSet;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.Models.Calibration;
import org.json.JSONArray;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
/**
* An {@link IntentService} subclass for handling asynchronous CGM Receiver downloads and cloud uploads
* requests in a service on a separate handler thread.
*/
public class SyncingService extends IntentService {
// Action for intent
private static final String ACTION_SYNC = "com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.action.SYNC";
private static final String ACTION_CALIBRATION_CHECKIN = "com.eveningoutpost.dexdrip.CalibrationCheckInActivity";
// Parameters for intent
private static final String SYNC_PERIOD = "com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.extra.SYNC_PERIOD";
// Response to broadcast to activity
public static final String RESPONSE_SGV = "mySGV";
public static final String RESPONSE_TREND = "myTrend";
public static final String RESPONSE_TIMESTAMP = "myTimestamp";
public static final String RESPONSE_NEXT_UPLOAD_TIME = "myUploadTime";
public static final String RESPONSE_UPLOAD_STATUS = "myUploadStatus";
public static final String RESPONSE_DISPLAY_TIME = "myDisplayTime";
public static final String RESPONSE_JSON = "myJSON";
public static final String RESPONSE_BAT = "myBatLvl";
private final String TAG = SyncingService.class.getSimpleName();
private Context mContext;
private UsbManager mUsbManager;
private UsbSerialDriver mSerialDevice;
private UsbDevice dexcom;
private UsbDeviceConnection mConnection;
// Constants
private final int TIME_SYNC_OFFSET = 10000;
public static final int MIN_SYNC_PAGES = 2;
public static final int GAP_SYNC_PAGES = 20;
/**
* Starts this service to perform action Single Sync with the given parameters. If
* the service is already performing a task this action will be queued.
*
* @see IntentService
*/
public static void startActionSingleSync(Context context, int numOfPages) {
Intent intent = new Intent(context, SyncingService.class);
intent.setAction(ACTION_SYNC);
intent.putExtra(SYNC_PERIOD, numOfPages);
context.startService(intent);
}
public static void startActionCalibrationCheckin(Context context) {
Intent intent = new Intent(context, SyncingService.class);
intent.setAction(ACTION_CALIBRATION_CHECKIN);
context.startService(intent);
}
public SyncingService() {
super("SyncingService");
}
@Override
protected void onHandleIntent(Intent intent) {
mContext = getApplicationContext();
if (intent != null) {
final String action = intent.getAction();
if (ACTION_SYNC.equals(action)) {
final int param1 = intent.getIntExtra(SYNC_PERIOD, 1);
handleActionSync(param1);
} else if (ACTION_CALIBRATION_CHECKIN.equals(action)) {
Log.w("CALIBRATION-CHECK-IN: ", "Beginning check in process");
performCalibrationCheckin();
}
}
}
/**
* Handle action Sync in the provided background thread with the provided
* parameters.
*/
private void performCalibrationCheckin(){
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NSDownload");
wl.acquire();
Log.w("CALIBRATION-CHECK-IN: ", "Wake Lock Acquired");
if (acquireSerialDevice()) {
try {
ReadData readData = new ReadData(mSerialDevice, mConnection, dexcom);
// ReadData readData = new ReadData(mSerialDevice);
CalRecord[] calRecords = readData.getRecentCalRecords();
Log.w("CALIBRATION-CHECK-IN: ", "Found "+ calRecords.length + " Records!");
save_most_recent_cal_record(calRecords);
} catch (Exception e) {
Log.wtf("Unhandled exception caught", e);
} finally {
// Close serial
try {
mSerialDevice.getPorts().get(0).close();
} catch (IOException e) {
Log.e(TAG, "Unable to close", e);
}
}
} else {
Log.w("CALIBRATION-CHECK-IN: ", "Failed to acquire serial device");
}
}
private void handleActionSync(int numOfPages) {
boolean broadcastSent = false;
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NSDownload");
wl.acquire();
if (acquireSerialDevice()) {
try {
ReadData readData = new ReadData(mSerialDevice);
// TODO: need to check if numOfPages if valid on ReadData side
EGVRecord[] recentRecords = readData.getRecentEGVsPages(numOfPages);
MeterRecord[] meterRecords = readData.getRecentMeterRecords();
// TODO: need to check if numOfPages if valid on ReadData side
SensorRecord[] sensorRecords = readData.getRecentSensorRecords(numOfPages);
GlucoseDataSet[] glucoseDataSets = Utils.mergeGlucoseDataRecords(recentRecords, sensorRecords);
// FIXME: This is a workaround for the new Dexcom AP which seems to have a new format
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
CalRecord[] calRecords = new CalRecord[1];
if (prefs.getBoolean("cloud_cal_data", false)) {
calRecords = readData.getRecentCalRecords();
}
long timeSinceLastRecord = readData.getTimeSinceEGVRecord(recentRecords[recentRecords.length - 1]);
// TODO: determine if the logic here is correct. I suspect it assumes the last record was less than 5
// minutes ago. If a reading is skipped and the device is plugged in then nextUploadTime will be
// set to a negative number. This situation will eventually correct itself.
long nextUploadTime = (1000 * 60 * 5) - (timeSinceLastRecord * (1000));
long displayTime = readData.readDisplayTime().getTime();
// FIXME: Device seems to flake out on battery level reads. Removing for now.
// int batLevel = readData.readBatteryLevel();
int batLevel = 100;
// convert into json for d3 plot
JSONArray array = new JSONArray();
for (int i = 0; i < recentRecords.length; i++) array.put(recentRecords[i].toJSON());
EGVRecord recentEGV = recentRecords[recentRecords.length - 1];
// broadcastSGVToUI(recentEGV, uploadStatus, nextUploadTime + TIME_SYNC_OFFSET,
// displayTime, array ,batLevel);
broadcastSent=true;
} catch (ArrayIndexOutOfBoundsException e) {
Log.wtf("Unable to read from the dexcom, maybe it will work next time", e);
} catch (NegativeArraySizeException e) {
Log.wtf("Negative array exception from receiver", e);
} catch (IndexOutOfBoundsException e) {
Log.wtf("IndexOutOfBounds exception from receiver", e);
} catch (CRCFailRuntimeException e){
// FIXME: may consider localizing this catch at a lower level (like ReadData) so that
// if the CRC check fails on one type of record we can capture the values if it
// doesn't fail on other types of records. This means we'd need to broadcast back
// partial results to the UI. Adding it to a lower level could make the ReadData class
// more difficult to maintain - needs discussion.
Log.wtf("CRC failed", e);
} catch (Exception e) {
Log.wtf("Unhandled exception caught", e);
} finally {
// Close serial
try {
mSerialDevice.getPorts().get(0).close();
} catch (IOException e) {
Log.e(TAG, "Unable to close", e);
}
}
}
// if (!broadcastSent) broadcastSGVToUI();
wl.release();
}
private void save_most_recent_cal_record(CalRecord[] calRecords) {
int size = calRecords.length;
Calibration.create(calRecords,getApplicationContext(), false, 0);
}
private boolean acquireSerialDevice() {
UsbDevice found_device = findDexcom();
if(mUsbManager == null) {
Log.w("CALIBRATION-CHECK-IN: ", "USB manager is null");
}
if( mUsbManager.hasPermission(dexcom)) { // the system is allowing us to poke around this device
ProbeTable customTable = new ProbeTable(); // From the USB library...
customTable.addProduct(0x22A3, 0x0047, CdcAcmSerialDriver.class); // ...Specify the Vendor ID and Product ID
UsbSerialProber prober = new UsbSerialProber(customTable); // Probe the device with the custom values
List drivers = prober.findAllDrivers(mUsbManager); // let's go through the list
Iterator foo = drivers.iterator(); // Invalid Return code
while (foo.hasNext()) { // let's loop through
UsbSerialDriver driver = foo.next(); // set fooDriver to the next available driver
if (driver != null) {
UsbDeviceConnection connection = mUsbManager.openDevice(driver.getDevice());
if (connection != null) {
mSerialDevice = driver;
mConnection = connection;
Log.w("CALIBRATION-CHECK-IN: ", "CONNECTEDDDD!!");
return true;
}
} else {
Log.w("CALIBRATION-CHECK-IN: ", "Driver was no good");
}
}
Log.w("CALIBRATION-CHECK-IN: ", "No usable drivers found");
} else {
Log.w("CALIBRATION-CHECK-IN: ", "You dont have permissions for that dexcom!!");
}
return false;
}
static public boolean isG4Connected(Context c){
UsbManager manager = (UsbManager) c.getSystemService(Context.USB_SERVICE);
HashMap deviceList = manager.getDeviceList();
Log.w("USB DEVICES = ", deviceList.toString());
Iterator deviceIterator = deviceList.values().iterator();
Log.w("USB DEVICES = ", String.valueOf(deviceList.size()));
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
if (device.getVendorId() == 8867 && device.getProductId() == 71
&& device.getDeviceClass() == 2 && device.getDeviceSubclass() ==0
&& device.getDeviceProtocol() == 0){
Log.w("CALIBRATION-CHECK-IN: ", "Dexcom Found!");
return true;
}
}
return false;
}
public UsbDevice findDexcom() {
Log.w("CALIBRATION-CHECK-IN: ", "Searching for dexcom");
mUsbManager = (UsbManager) getApplicationContext().getSystemService(Context.USB_SERVICE);
Log.w("USB MANAGER = ", mUsbManager.toString());
HashMap deviceList = mUsbManager.getDeviceList();
Log.w("USB DEVICES = ", deviceList.toString());
Iterator deviceIterator = deviceList.values().iterator();
Log.w("USB DEVICES = ", String.valueOf(deviceList.size()));
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
if (device.getVendorId() == 8867 && device.getProductId() == 71
&& device.getDeviceClass() == 2 && device.getDeviceSubclass() ==0
&& device.getDeviceProtocol() == 0){
dexcom = device;
Log.w("CALIBRATION-CHECK-IN: ", "Dexcom Found!");
return device;
} else {
Log.w("CALIBRATION-CHECK-IN: ", "that was not a dexcom (I dont think)");
}
}
return null;
}
private void broadcastSGVToUI(EGVRecord egvRecord, boolean uploadStatus,
long nextUploadTime, long displayTime,
JSONArray json, int batLvl) {
Log.d(TAG, "Current EGV: " + egvRecord.getBGValue());
Intent broadcastIntent = new Intent();
// broadcastIntent.setAction(MainActivity.CGMStatusReceiver.PROCESS_RESPONSE);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra(RESPONSE_SGV, egvRecord.getBGValue());
broadcastIntent.putExtra(RESPONSE_TREND, egvRecord.getTrend().getID());
broadcastIntent.putExtra(RESPONSE_TIMESTAMP, egvRecord.getDisplayTime().getTime());
broadcastIntent.putExtra(RESPONSE_NEXT_UPLOAD_TIME, nextUploadTime);
broadcastIntent.putExtra(RESPONSE_UPLOAD_STATUS, uploadStatus);
broadcastIntent.putExtra(RESPONSE_DISPLAY_TIME, displayTime);
if (json!=null)
broadcastIntent.putExtra(RESPONSE_JSON, json.toString());
broadcastIntent.putExtra(RESPONSE_BAT, batLvl);
sendBroadcast(broadcastIntent);
}
private void broadcastSGVToUI() {
EGVRecord record=new EGVRecord(-1, Constants.TREND_ARROW_VALUES.NONE,new Date(),new Date());
broadcastSGVToUI(record,false, (long) (1000 * 60 * 5) + TIME_SYNC_OFFSET, new Date().getTime(), null, 0);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/Utils.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GlucoseDataSet;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import java.util.Date;
import java.util.TimeZone;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class Utils {
public static Date receiverTimeToDate(long delta) {
int currentTZOffset = TimeZone.getDefault().getRawOffset();
long epochMS = 1230768000000L; // Jan 01, 2009 00:00 in UTC
long milliseconds = epochMS - currentTZOffset;
long timeAdd = milliseconds + (1000L * delta);
TimeZone tz = TimeZone.getDefault();
if (tz.inDaylightTime(new Date())) timeAdd = timeAdd - (1000 * 60 * 60);
return new Date(timeAdd);
}
public static String getTimeString(long timeDeltaMS) {
long minutes = (timeDeltaMS / 1000) / 60;
long hours = minutes / 60;
long days = hours / 24;
long weeks = days / 7;
minutes= minutes - hours * 60;
hours = hours - days * 24;
days= days - weeks * 7;
String timeAgoString = "";
if (weeks > 0) {
timeAgoString += weeks + " weeks ";
}
if (days > 0) {
timeAgoString += days + " days ";
}
if (hours > 0) {
timeAgoString += hours + " hours ";
}
if (minutes >= 0) {
timeAgoString += minutes + " min ";
}
return (timeAgoString.equals("") ? "--" : timeAgoString + "ago");
}
public static GlucoseDataSet[] mergeGlucoseDataRecords(EGVRecord[] egvRecords,
SensorRecord[] sensorRecords) {
int egvLength = egvRecords.length;
int sensorLength = sensorRecords.length;
int smallerLength = egvLength < sensorLength ? egvLength : sensorLength;
GlucoseDataSet[] glucoseDataSets = new GlucoseDataSet[smallerLength];
for (int i = 1; i <= smallerLength; i++) {
glucoseDataSets[smallerLength - i] = new GlucoseDataSet(egvRecords[egvLength - i], sensorRecords[sensorLength - i]);
}
return glucoseDataSets;
}
public static String bytesToHex(byte[] bytes) {
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[bytes.length * 3];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 3] = hexArray[v >>> 4];
hexChars[j * 3 + 1] = hexArray[v & 0x0F];
hexChars[j * 3 + 2] = " ".toCharArray()[0];
}
return new String(hexChars);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/CalRecord.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CalRecord extends GenericTimestampRecord {
private static final String TAG = CalRecord.class.getSimpleName();
private double slope;
private double intercept;
private double scale;
private int[] unk = new int[3];
private double decay;
private int numRecords;
private CalSubrecord[] calSubrecords = new CalSubrecord[12];
private int SUB_LEN = 17;
public CalRecord(byte[] packet) {
super(packet);
slope = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(8);
intercept = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(16);
scale = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(24);
unk[0] = packet[32];
unk[1] = packet[33];
unk[2] = packet[34];
decay = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(35);
numRecords = packet[43];
long displayTimeOffset = (getDisplayTime().getTime() - getSystemTime().getTime()) / (1000);
int start = 44;
for (int i = 0; i < numRecords; i++) {
Log.d("CalDebug","Loop #"+i);
byte[] temp = new byte[SUB_LEN];
System.arraycopy(packet, start, temp, 0, temp.length);
calSubrecords[i] = new CalSubrecord(temp, displayTimeOffset);
start += SUB_LEN;
}
Log.d("ShareTest", "slope: " + slope + " intercept: " + intercept);
}
public double getSlope() {
return slope;
}
public double getIntercept() {
return intercept;
}
public double getScale() {
return scale;
}
public int[] getUnk() {
return unk;
}
public double getDecay() {
return decay;
}
public int getNumRecords() {
return numRecords;
}
public CalSubrecord[] getCalSubrecords() {
return calSubrecords;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/CalSubrecord.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CalSubrecord {
private static final String TAG = CalSubrecord.class.getSimpleName();
private Date dateEntered;
private int calBGL;
private int calRaw;
private Date dateApplied;
private byte unk;
public CalSubrecord(byte[] packet, long displayTimeOffset) {
int delta = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt();
dateEntered = Utils.receiverTimeToDate(delta + displayTimeOffset);
calBGL = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4);
calRaw = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(8);
delta = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(12);
dateApplied = Utils.receiverTimeToDate(delta + displayTimeOffset);
unk = packet[16];
}
public Date getDateEntered() {
return dateEntered;
}
public int getCalBGL() {
return calBGL;
}
public int getCalRaw() {
return calRaw;
}
public Date getDateApplied() {
return dateApplied;
}
public byte getUnk() {
return unk;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/EGVRecord.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Constants;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class EGVRecord extends GenericTimestampRecord {
private int bGValue;
private int noise;
private Constants.TREND_ARROW_VALUES trend;
public EGVRecord(byte[] packet) {
// system_time (UInt), display_time (UInt), glucose (UShort), trend_arrow (Byte), crc (UShort))
super(packet);
bGValue = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8) & Constants.EGV_VALUE_MASK;
byte trendAndNoise = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).get(10);
int trendValue = trendAndNoise & Constants.EGV_TREND_ARROW_MASK;
byte noiseValue = (byte) ((trendAndNoise & Constants.EGV_NOISE_MASK) >> 4);
trend = Constants.TREND_ARROW_VALUES.values()[trendValue];
noise = noiseValue;
}
public EGVRecord(int bGValue,Constants.TREND_ARROW_VALUES trend,Date displayTime, Date systemTime){
super(displayTime, systemTime);
this.bGValue=bGValue;
this.trend=trend;
}
public String noiseValue() { return String.valueOf(noise); }
public int getBGValue() {
return bGValue;
}
public Constants.TREND_ARROW_VALUES getTrend() {
return trend;
}
public JSONObject toJSON() {
JSONObject obj = new JSONObject();
try {
obj.put("sgv", getBGValue());
obj.put("date", getDisplayTimeSeconds());
} catch (JSONException e) {
e.printStackTrace();
}
return obj;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/GenericTimestampRecord.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class GenericTimestampRecord {
protected final int OFFSET_SYS_TIME = 0;
protected final int OFFSET_DISPLAY_TIME = 4;
protected Date systemTime;
protected int systemTimeSeconds;
protected Date displayTime;
public GenericTimestampRecord(byte[] packet) {
systemTimeSeconds = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_SYS_TIME);
systemTime = Utils.receiverTimeToDate(systemTimeSeconds);
int dt = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_DISPLAY_TIME);
displayTime = Utils.receiverTimeToDate(dt);
}
public GenericTimestampRecord(Date displayTime, Date systemTime){
this.displayTime=displayTime;
this.systemTime=systemTime;
}
public Date getSystemTime() {
return systemTime;
}
public int getSystemTimeSeconds() {
return systemTimeSeconds;
}
public Date getDisplayTime() {
return displayTime;
}
public long getDisplayTimeSeconds() {
return displayTime.getTime();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/GenericXMLRecord.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import android.util.Log;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Arrays;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class GenericXMLRecord extends GenericTimestampRecord {
int XML_START = 8;
int XML_END = 241;
private final String TAG = GenericXMLRecord.class.getSimpleName();
private Element xmlElement;
public GenericXMLRecord(byte[] packet) {
super(packet);
Document document;
// TODO: it would be best if we could just remove /x00 characters and read till end
String xml = new String(Arrays.copyOfRange(packet, XML_START, XML_END));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
document = builder.parse(new InputSource(new StringReader(xml)));
xmlElement = document.getDocumentElement();
} catch (Exception e) {
Log.e(TAG, "Unable to build xml element", e);
}
}
// example: String sn = getXmlElement().getAttribute("SerialNumber");
public Element getXmlElement() {
return xmlElement;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/GlucoseDataSet.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Constants;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class GlucoseDataSet {
private Date systemTime;
private Date displayTime;
private int bGValue;
private Constants.TREND_ARROW_VALUES trend;
private long unfiltered;
private long filtered;
private int rssi;
public GlucoseDataSet(EGVRecord egvRecord, SensorRecord sensorRecord) {
// TODO check times match between record
systemTime = egvRecord.getSystemTime();
displayTime = egvRecord.getDisplayTime();
bGValue = egvRecord.getBGValue();
trend = egvRecord.getTrend();
unfiltered = sensorRecord.getUnfiltered();
filtered = sensorRecord.getFiltered();
rssi = sensorRecord.getRSSI();
}
public Date getSystemTime() {
return systemTime;
}
public Date getDisplayTime() {
return displayTime;
}
public int getBGValue() {
return bGValue;
}
public Constants.TREND_ARROW_VALUES getTrend() {
return trend;
}
public String getTrendSymbol() {
return trend.Symbol();
}
public long getUnfiltered() {
return unfiltered;
}
public long getFiltered() {
return filtered;
}
public int getRssi() {
return rssi;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/MeterRecord.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class MeterRecord extends GenericTimestampRecord {
private int meterBG;
private int meterTime;
public MeterRecord(byte[] packet) {
super(packet);
meterBG = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8);
meterTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(10);
}
public int getMeterBG() {
return meterBG;
}
public int getMeterTime() {
return meterTime;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/PageHeader.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.CRC16;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.CRCFailRuntimeException;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Constants;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class PageHeader {
protected final int HEADER_SIZE=28;
protected final int FIRSTRECORDINDEX_OFFSET=0;
protected final int NUMRECS_OFFSET=4;
protected final int RECTYPE_OFFSET=8;
protected final int REV_OFFSET=9;
protected final int PAGENUMBER_OFFSET=10;
protected final int RESERVED2_OFFSET=14;
protected final int RESERVED3_OFFSET=18;
protected final int RESERVED4_OFFSET=22;
protected int firstRecordIndex;
protected int numOfRecords;
protected Constants.RECORD_TYPES recordType;
protected byte revision;
protected int pageNumber;
protected int reserved2;
protected int reserved3;
protected int reserved4;
protected byte[] crc=new byte[2];
public PageHeader(byte[] packet) {
Log.d("ShareTest", "Header Packet Data Length: " + packet.length);
firstRecordIndex = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(FIRSTRECORDINDEX_OFFSET);
numOfRecords = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(NUMRECS_OFFSET);
recordType = Constants.RECORD_TYPES.values()[packet[RECTYPE_OFFSET]];
revision = packet[REV_OFFSET];
pageNumber = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(PAGENUMBER_OFFSET);
reserved2 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED2_OFFSET);
reserved3 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED3_OFFSET);
reserved4 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED4_OFFSET);
System.arraycopy(packet,HEADER_SIZE-Constants.CRC_LEN,crc,0,Constants.CRC_LEN);
byte[] crc_calc = CRC16.calculate(packet,0,HEADER_SIZE - Constants.CRC_LEN);
if (!Arrays.equals(this.crc, crc_calc)) {
throw new CRCFailRuntimeException("CRC check failed: " + Utils.bytesToHex(this.crc) + " vs " + Utils.bytesToHex(crc_calc));
}
}
public byte getRevision() {
return revision;
}
public Constants.RECORD_TYPES getRecordType() {
return recordType;
}
public int getFirstRecordIndex() {
return firstRecordIndex;
}
public int getNumOfRecords() {
return numOfRecords;
}
public int getPageNumber() {
return pageNumber;
}
public int getReserved2() {
return reserved2;
}
public int getReserved3() {
return reserved3;
}
public int getReserved4() {
return reserved4;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/dexcom/records/SensorRecord.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class SensorRecord extends GenericTimestampRecord {
private int unfiltered;
private int filtered;
private int rssi;
private int OFFSET_UNFILTERED = 8;
private int OFFSET_FILTERED = 12;
private int OFFSET_RSSI = 16;
public SensorRecord(byte[] packet) {
super(packet);
unfiltered = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_UNFILTERED);
filtered = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_FILTERED);
rssi = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(OFFSET_RSSI);
Log.d("ShareTest", "filtered: " + filtered + " unfiltered: " + unfiltered);
}
public long getUnfiltered() {
return unfiltered;
}
public long getFiltered() {
return filtered;
}
public int getRSSI() {
return rssi;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/BuildInfo.java
================================================
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial;
/**
* Static container of information about this library.
*/
public final class BuildInfo {
/**
* The current version of this library. Values are of the form
* "major.minor.micro[-suffix]". A suffix of "-pre" indicates a pre-release
* of the version preceeding it.
*/
public static final String VERSION = "0.2.0-pre";
private BuildInfo() {
throw new IllegalStateException("Non-instantiable class.");
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/CdcAcmSerialDriver.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.os.Build;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* USB CDC/ACM serial driver implementation.
*
* @author mike wakerly (opensource@hoho.com)
* @see Universal
* Serial Bus Class Definitions for Communication Devices, v1.1
*/
public class CdcAcmSerialDriver implements UsbSerialDriver {
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
public CdcAcmSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new CdcAcmSerialPort(device, 0);
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
@Override
public List getPorts() {
return Collections.singletonList(mPort);
}
class CdcAcmSerialPort extends CommonUsbSerialPort {
private final boolean mEnableAsyncReads;
private UsbInterface mControlInterface;
private UsbInterface mDataInterface;
private UsbEndpoint mControlEndpoint;
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
private boolean mRts = false;
private boolean mDtr = false;
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
private static final int GET_LINE_CODING = 0x21;
private static final int SET_CONTROL_LINE_STATE = 0x22;
private static final int SEND_BREAK = 0x23;
public CdcAcmSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
}
@Override
public UsbSerialDriver getDriver() {
return CdcAcmSerialDriver.this;
}
@Override
public void open(UsbDeviceConnection connection) throws IOException {
if (mConnection != null && false) {
throw new IOException("Already open");
}
mConnection = connection;
boolean opened = false;
try {
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
mControlInterface = mDevice.getInterface(0);
Log.d(TAG, "Control iface=" + mControlInterface);
// class should be USB_CLASS_COMM
if (!mConnection.claimInterface(mControlInterface, true)) {
throw new IOException("Could not claim control interface.");
}
mControlEndpoint = mControlInterface.getEndpoint(0);
Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection());
Log.d(TAG, "Claiming data interface.");
mDataInterface = mDevice.getInterface(1);
Log.d(TAG, "data iface=" + mDataInterface);
// class should be USB_CLASS_CDC_DATA
if (!mConnection.claimInterface(mDataInterface, true)) {
throw new IOException("Could not claim data interface.");
}
mReadEndpoint = mDataInterface.getEndpoint(1);
Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
mWriteEndpoint = mDataInterface.getEndpoint(0);
Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
if (mEnableAsyncReads) {
Log.d(TAG, "Async reads enabled");
} else {
Log.d(TAG, "Async reads disabled.");
}
opened = true;
} finally {
if (!opened) {
mConnection = null;
}
}
}
private int sendAcmControlMessage(int request, int value, byte[] buf) {
return mConnection.controlTransfer(
USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
}
@Override
public void close() throws IOException {
if (mConnection == null) {
throw new IOException("Already closed");
}
mConnection.close();
mConnection = null;
}
@Override
public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {return 0;}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
if (mEnableAsyncReads) {
final UsbRequest request = new UsbRequest();
try {
request.initialize(mConnection, mReadEndpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = mConnection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
} finally {
request.close();
}
}
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
if (timeoutMillis == Integer.MAX_VALUE) {
// Hack: Special case "~infinite timeout" as an error.
return -1;
}
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
return numBytesRead;
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
// TODO(mikey): Nearly identical to FtdiSerial write. Refactor.
int offset = 0;
while (offset < src.length) {
final int writeLength;
final int amtWritten;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
timeoutMillis);
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length);
}
Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
}
return offset;
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) {
byte stopBitsByte;
switch (stopBits) {
case STOPBITS_1: stopBitsByte = 0; break;
case STOPBITS_1_5: stopBitsByte = 1; break;
case STOPBITS_2: stopBitsByte = 2; break;
default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits);
}
byte parityBitesByte;
switch (parity) {
case PARITY_NONE: parityBitesByte = 0; break;
case PARITY_ODD: parityBitesByte = 1; break;
case PARITY_EVEN: parityBitesByte = 2; break;
case PARITY_MARK: parityBitesByte = 3; break;
case PARITY_SPACE: parityBitesByte = 4; break;
default: throw new IllegalArgumentException("Bad value for parity: " + parity);
}
byte[] msg = {
(byte) ( baudRate & 0xff),
(byte) ((baudRate >> 8 ) & 0xff),
(byte) ((baudRate >> 16) & 0xff),
(byte) ((baudRate >> 24) & 0xff),
stopBitsByte,
parityBitesByte,
(byte) dataBits};
sendAcmControlMessage(SET_LINE_CODING, 0, msg);
}
@Override
public boolean getCD() throws IOException {
return false; // TODO
}
@Override
public boolean getCTS() throws IOException {
return false; // TODO
}
@Override
public boolean getDSR() throws IOException {
return false; // TODO
}
@Override
public boolean getDTR() throws IOException {
return mDtr;
}
@Override
public void setDTR(boolean value) throws IOException {
mDtr = value;
setDtrRts();
}
@Override
public boolean getRI() throws IOException {
return false; // TODO
}
@Override
public boolean getRTS() throws IOException {
return mRts;
}
@Override
public void setRTS(boolean value) throws IOException {
mRts = value;
setDtrRts();
}
private void setDtrRts() {
int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
}
}
public static Map getSupportedDevices() {
final Map supportedDevices = new LinkedHashMap();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO),
new int[] {
UsbId.ARDUINO_UNO,
UsbId.ARDUINO_UNO_R3,
UsbId.ARDUINO_MEGA_2560,
UsbId.ARDUINO_MEGA_2560_R3,
UsbId.ARDUINO_SERIAL_ADAPTER,
UsbId.ARDUINO_SERIAL_ADAPTER_R3,
UsbId.ARDUINO_MEGA_ADK,
UsbId.ARDUINO_MEGA_ADK_R3,
UsbId.ARDUINO_LEONARDO,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH),
new int[] {
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL),
new int[] {
UsbId.ATMEL_LUFA_CDC_DEMO_APP,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS),
new int[] {
UsbId.LEAFLABS_MAPLE,
});
return supportedDevices;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/CommonUsbSerialPort.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import java.io.IOException;
/**
* A base class shared by several driver implementations.
*
* @author mike wakerly (opensource@hoho.com)
*/
abstract class CommonUsbSerialPort implements UsbSerialPort {
public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024;
public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
protected final UsbDevice mDevice;
protected final int mPortNumber;
// non-null when open()
protected UsbDeviceConnection mConnection = null;
protected final Object mReadBufferLock = new Object();
protected final Object mWriteBufferLock = new Object();
/** Internal read buffer. Guarded by {@link #mReadBufferLock}. */
protected byte[] mReadBuffer;
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
protected byte[] mWriteBuffer;
public CommonUsbSerialPort(UsbDevice device, int portNumber) {
mDevice = device;
mPortNumber = portNumber;
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
}
@Override
public String toString() {
return String.format("<%s device_name=%s device_id=%s port_number=%s>",
getClass().getSimpleName(), mDevice.getDeviceName(),
mDevice.getDeviceId(), mPortNumber);
}
/**
* Returns the currently-bound USB device.
*
* @return the device
*/
public final UsbDevice getDevice() {
return mDevice;
}
@Override
public int getPortNumber() {
return mPortNumber;
}
/**
* Returns the device serial number
* @return serial number
*/
@Override
public String getSerial() {
return mConnection.getSerial();
}
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for read operations. Most users should not need to change this.
*
* @param bufferSize the size in bytes
*/
public final void setReadBufferSize(int bufferSize) {
synchronized (mReadBufferLock) {
if (bufferSize == mReadBuffer.length) {
return;
}
mReadBuffer = new byte[bufferSize];
}
}
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for write operations. Most users should not need to change this.
*
* @param bufferSize the size in bytes
*/
public final void setWriteBufferSize(int bufferSize) {
synchronized (mWriteBufferLock) {
if (bufferSize == mWriteBuffer.length) {
return;
}
mWriteBuffer = new byte[bufferSize];
}
}
@Override
public abstract void open(UsbDeviceConnection connection) throws IOException;
@Override
public abstract void close() throws IOException;
@Override
public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException;
@Override
public abstract int write(final byte[] src, final int timeoutMillis) throws IOException;
@Override
public abstract void setParameters(
int baudRate, int dataBits, int stopBits, int parity) throws IOException;
@Override
public abstract boolean getCD() throws IOException;
@Override
public abstract boolean getCTS() throws IOException;
@Override
public abstract boolean getDSR() throws IOException;
@Override
public abstract boolean getDTR() throws IOException;
@Override
public abstract void setDTR(boolean value) throws IOException;
@Override
public abstract boolean getRI() throws IOException;
@Override
public abstract boolean getRTS() throws IOException;
@Override
public abstract void setRTS(boolean value) throws IOException;
@Override
public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException {
return !flushReadBuffers && !flushWriteBuffers;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/Cp21xxSerialDriver.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class Cp21xxSerialDriver implements UsbSerialDriver {
private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
public Cp21xxSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new Cp21xxSerialPort(mDevice, 0);
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
@Override
public List getPorts() {
return Collections.singletonList(mPort);
}
public class Cp21xxSerialPort extends CommonUsbSerialPort {
private static final int DEFAULT_BAUD_RATE = 9600;
private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
/*
* Configuration Request Types
*/
private static final int REQTYPE_HOST_TO_DEVICE = 0x41;
/*
* Configuration Request Codes
*/
private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00;
private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01;
private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03;
private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07;
private static final int SILABSER_SET_BAUDRATE = 0x1E;
private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12;
private static final int FLUSH_READ_CODE = 0x0a;
private static final int FLUSH_WRITE_CODE = 0x05;
/*
* SILABSER_IFC_ENABLE_REQUEST_CODE
*/
private static final int UART_ENABLE = 0x0001;
private static final int UART_DISABLE = 0x0000;
/*
* SILABSER_SET_BAUDDIV_REQUEST_CODE
*/
private static final int BAUD_RATE_GEN_FREQ = 0x384000;
/*
* SILABSER_SET_MHS_REQUEST_CODE
*/
private static final int MCR_DTR = 0x0001;
private static final int MCR_RTS = 0x0002;
private static final int MCR_ALL = 0x0003;
private static final int CONTROL_WRITE_DTR = 0x0100;
private static final int CONTROL_WRITE_RTS = 0x0200;
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
public Cp21xxSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
}
@Override
public UsbSerialDriver getDriver() {
return Cp21xxSerialDriver.this;
}
private int setConfigSingle(int request, int value) {
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value,
0, null, 0, USB_WRITE_TIMEOUT_MILLIS);
}
@Override
public void open(UsbDeviceConnection connection) throws IOException {
if (mConnection != null) {
throw new IOException("Already opened.");
}
mConnection = connection;
boolean opened = false;
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface usbIface = mDevice.getInterface(i);
if (mConnection.claimInterface(usbIface, true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
Log.d(TAG, "claimInterface " + i + " FAIL");
}
}
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
UsbEndpoint ep = dataIface.getEndpoint(i);
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
mReadEndpoint = ep;
} else {
mWriteEndpoint = ep;
}
}
}
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE);
setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, MCR_ALL | CONTROL_WRITE_DTR | CONTROL_WRITE_RTS);
setConfigSingle(SILABSER_SET_BAUDDIV_REQUEST_CODE, BAUD_RATE_GEN_FREQ / DEFAULT_BAUD_RATE);
// setParameters(DEFAULT_BAUD_RATE, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY);
opened = true;
} finally {
if (!opened) {
try {
close();
} catch (IOException e) {
// Ignore IOExceptions during close()
}
}
}
}
@Override
public void close() throws IOException {
if (mConnection == null) {
throw new IOException("Already closed");
}
try {
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
mConnection.close();
} finally {
mConnection = null;
}
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
return numBytesRead;
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
int offset = 0;
while (offset < src.length) {
final int writeLength;
final int amtWritten;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
timeoutMillis);
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length);
}
Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
}
return offset;
}
@Override
public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {
if (false) {
final UsbRequest request = new UsbRequest();
try {
request.initialize(connection, mReadEndpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = connection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
} finally {
request.close();
}
}
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = connection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
if (timeoutMillis == Integer.MAX_VALUE) {
// Hack: Special case "~infinite timeout" as an error.
return -1;
}
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
return numBytesRead;
}
private void setBaudRate(int baudRate) throws IOException {
byte[] data = new byte[] {
(byte) ( baudRate & 0xff),
(byte) ((baudRate >> 8 ) & 0xff),
(byte) ((baudRate >> 16) & 0xff),
(byte) ((baudRate >> 24) & 0xff)
};
int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,
0, 0, data, 4, USB_WRITE_TIMEOUT_MILLIS);
if (ret < 0) {
throw new IOException("Error setting baud rate.");
}
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
throws IOException {
setBaudRate(baudRate);
int configDataBits = 0;
switch (dataBits) {
case DATABITS_5:
configDataBits |= 0x0500;
break;
case DATABITS_6:
configDataBits |= 0x0600;
break;
case DATABITS_7:
configDataBits |= 0x0700;
break;
case DATABITS_8:
configDataBits |= 0x0800;
break;
default:
configDataBits |= 0x0800;
break;
}
switch (parity) {
case PARITY_ODD:
configDataBits |= 0x0010;
break;
case PARITY_EVEN:
configDataBits |= 0x0020;
break;
}
switch (stopBits) {
case STOPBITS_1:
configDataBits |= 0;
break;
case STOPBITS_2:
configDataBits |= 2;
break;
}
setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
}
@Override
public boolean getCD() throws IOException {
return false;
}
@Override
public boolean getCTS() throws IOException {
return false;
}
@Override
public boolean getDSR() throws IOException {
return false;
}
@Override
public boolean getDTR() throws IOException {
return true;
}
@Override
public void setDTR(boolean value) throws IOException {
}
@Override
public boolean getRI() throws IOException {
return false;
}
@Override
public boolean getRTS() throws IOException {
return true;
}
@Override
public void setRTS(boolean value) throws IOException {
}
@Override
public boolean purgeHwBuffers(boolean purgeReadBuffers,
boolean purgeWriteBuffers) throws IOException {
int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
| (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
if (value != 0) {
setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);
}
return true;
}
}
public static Map getSupportedDevices() {
final Map supportedDevices = new LinkedHashMap();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILABS),
new int[] {
UsbId.SILABS_CP2102,
UsbId.SILABS_CP2105,
UsbId.SILABS_CP2108,
UsbId.SILABS_CP2110
});
return supportedDevices;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/FtdiSerialDriver.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.util.HexDump;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* A {@link CommonUsbSerialPort} implementation for a variety of FTDI devices
*
* This driver is based on libftdi, and is
* copyright and subject to the following terms:
*
*
* Copyright (C) 2003 by Intra2net AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation;
*
* opensource@intra2net.com
* http://www.intra2net.com/en/developer/libftdi
*
*
*
*
* Some FTDI devices have not been tested; see later listing of supported and
* unsupported devices. Devices listed as "supported" support the following
* features:
*
*
Read and write of serial data (see
* {@link CommonUsbSerialPort#read(byte[], int)} and
* {@link CommonUsbSerialPort#write(byte[], int)}.
*
Setting serial line parameters (see
* {@link CommonUsbSerialPort#setParameters(int, int, int, int)}.
*
*
*
* Supported and tested devices:
*
*
{@value DeviceType#TYPE_R}
*
*
*
* Unsupported but possibly working devices (please contact the author with
* feedback or patches):
*
*
{@value DeviceType#TYPE_2232C}
*
{@value DeviceType#TYPE_2232H}
*
{@value DeviceType#TYPE_4232H}
*
{@value DeviceType#TYPE_AM}
*
{@value DeviceType#TYPE_BM}
*
*
*
* @author mike wakerly (opensource@hoho.com)
* @see USB Serial
* for Android project page
* @see FTDI Homepage
* @see libftdi
*/
public class FtdiSerialDriver implements UsbSerialDriver {
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
/**
* FTDI chip types.
*/
private static enum DeviceType {
TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H;
}
public FtdiSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new FtdiSerialPort(mDevice, 0);
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
@Override
public List getPorts() {
return Collections.singletonList(mPort);
}
private class FtdiSerialPort extends CommonUsbSerialPort {
public static final int USB_TYPE_STANDARD = 0x00 << 5;
public static final int USB_TYPE_CLASS = 0x00 << 5;
public static final int USB_TYPE_VENDOR = 0x00 << 5;
public static final int USB_TYPE_RESERVED = 0x00 << 5;
public static final int USB_RECIP_DEVICE = 0x00;
public static final int USB_RECIP_INTERFACE = 0x01;
public static final int USB_RECIP_ENDPOINT = 0x02;
public static final int USB_RECIP_OTHER = 0x03;
public static final int USB_ENDPOINT_IN = 0x80;
public static final int USB_ENDPOINT_OUT = 0x00;
public static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
public static final int USB_READ_TIMEOUT_MILLIS = 5000;
// From ftdi.h
/**
* Reset the port.
*/
private static final int SIO_RESET_REQUEST = 0;
/**
* Set the modem control register.
*/
private static final int SIO_MODEM_CTRL_REQUEST = 1;
/**
* Set flow control register.
*/
private static final int SIO_SET_FLOW_CTRL_REQUEST = 2;
/**
* Set baud rate.
*/
private static final int SIO_SET_BAUD_RATE_REQUEST = 3;
/**
* Set the data characteristics of the port.
*/
private static final int SIO_SET_DATA_REQUEST = 4;
private static final int SIO_RESET_SIO = 0;
private static final int SIO_RESET_PURGE_RX = 1;
private static final int SIO_RESET_PURGE_TX = 2;
public static final int FTDI_DEVICE_OUT_REQTYPE =
UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT;
public static final int FTDI_DEVICE_IN_REQTYPE =
UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN;
/**
* Length of the modem status header, transmitted with every read.
*/
private static final int MODEM_STATUS_HEADER_LENGTH = 2;
private final String TAG = FtdiSerialDriver.class.getSimpleName();
private DeviceType mType;
private int mInterface = 0; /* INTERFACE_ANY */
private int mMaxPacketSize = 64; // TODO(mikey): detect
/**
* Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
* since it gives no indication of number of bytes read. Set this to
* {@code true} on platforms where it is fixed.
*/
private static final boolean ENABLE_ASYNC_READS = false;
public FtdiSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
}
@Override
public UsbSerialDriver getDriver() {
return FtdiSerialDriver.this;
}
/**
* Filter FTDI status bytes from buffer
* @param src The source buffer (which contains status bytes)
* @param dest The destination buffer to write the status bytes into (can be src)
* @param totalBytesRead Number of bytes read to src
* @param maxPacketSize The USB endpoint max packet size
* @return The number of payload bytes
*/
private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) {
final int packetsCount = totalBytesRead / maxPacketSize + (totalBytesRead % maxPacketSize == 0 ? 0 : 1);
for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) {
final int count = (packetIdx == (packetsCount - 1))
? (totalBytesRead % maxPacketSize) - MODEM_STATUS_HEADER_LENGTH
: maxPacketSize - MODEM_STATUS_HEADER_LENGTH;
if (count > 0) {
System.arraycopy(src,
packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH,
dest,
packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH),
count);
}
}
return totalBytesRead - (packetsCount * 2);
}
public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {
if (false) {
final UsbRequest request = new UsbRequest();
try {
request.initialize(connection, null);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = connection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
} finally {
request.close();
}
}
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = connection.bulkTransfer(null, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
if (timeoutMillis == Integer.MAX_VALUE) {
// Hack: Special case "~infinite timeout" as an error.
return -1;
}
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
return numBytesRead;
}
public void reset() throws IOException {
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_SIO, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Reset failed: result=" + result);
}
// TODO(mikey): autodetect.
mType = DeviceType.TYPE_R;
}
@Override
public void open(UsbDeviceConnection connection) throws IOException {
if (mConnection != null) {
throw new IOException("Already open");
}
mConnection = connection;
boolean opened = false;
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
if (connection.claimInterface(mDevice.getInterface(i), true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
throw new IOException("Error claiming interface " + i);
}
}
reset();
opened = true;
} finally {
if (!opened) {
close();
mConnection = null;
}
}
}
@Override
public void close() throws IOException {
if (mConnection == null) {
throw new IOException("Already closed");
}
try {
mConnection.close();
} finally {
mConnection = null;
}
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);
if (ENABLE_ASYNC_READS) {
final int readAmt;
synchronized (mReadBufferLock) {
// mReadBuffer is only used for maximum read size.
readAmt = Math.min(dest.length, mReadBuffer.length);
}
final UsbRequest request = new UsbRequest();
request.initialize(mConnection, endpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, readAmt)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = mConnection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
if (payloadBytesRead > 0) {
Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return payloadBytesRead;
} else {
return 0;
}
} else {
final int totalBytesRead;
synchronized (mReadBufferLock) {
final int readAmt = Math.min(dest.length, mReadBuffer.length);
totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,
readAmt, timeoutMillis);
if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
}
return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize());
}
}
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(1);
int offset = 0;
while (offset < src.length) {
final int writeLength;
final int amtWritten;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength,
timeoutMillis);
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length);
}
Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
}
return offset;
}
private int setBaudRate(int baudRate) throws IOException {
long[] vals = convertBaudrate(baudRate);
long actualBaudrate = vals[0];
long index = vals[1];
long value = vals[2];
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index,
null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Setting baudrate failed: result=" + result);
}
return (int) actualBaudrate;
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
throws IOException {
setBaudRate(baudRate);
int config = dataBits;
switch (parity) {
case PARITY_NONE:
config |= (0x00 << 8);
break;
case PARITY_ODD:
config |= (0x01 << 8);
break;
case PARITY_EVEN:
config |= (0x02 << 8);
break;
case PARITY_MARK:
config |= (0x03 << 8);
break;
case PARITY_SPACE:
config |= (0x04 << 8);
break;
default:
throw new IllegalArgumentException("Unknown parity value: " + parity);
}
switch (stopBits) {
case STOPBITS_1:
config |= (0x00 << 11);
break;
case STOPBITS_1_5:
config |= (0x01 << 11);
break;
case STOPBITS_2:
config |= (0x02 << 11);
break;
default:
throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
}
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_DATA_REQUEST, config, 0 /* index */,
null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Setting parameters failed: result=" + result);
}
}
private long[] convertBaudrate(int baudrate) {
// TODO(mikey): Braindead transcription of libfti method. Clean up,
// using more idiomatic Java where possible.
int divisor = 24000000 / baudrate;
int bestDivisor = 0;
int bestBaud = 0;
int bestBaudDiff = 0;
int fracCode[] = {
0, 3, 2, 4, 1, 5, 6, 7
};
for (int i = 0; i < 2; i++) {
int tryDivisor = divisor + i;
int baudEstimate;
int baudDiff;
if (tryDivisor <= 8) {
// Round up to minimum supported divisor
tryDivisor = 8;
} else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) {
// BM doesn't support divisors 9 through 11 inclusive
tryDivisor = 12;
} else if (divisor < 16) {
// AM doesn't support divisors 9 through 15 inclusive
tryDivisor = 16;
} else {
if (mType == DeviceType.TYPE_AM) {
// TODO
} else {
if (tryDivisor > 0x1FFFF) {
// Round down to maximum supported divisor value (for
// BM)
tryDivisor = 0x1FFFF;
}
}
}
// Get estimated baud rate (to nearest integer)
baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor;
// Get absolute difference from requested baud rate
if (baudEstimate < baudrate) {
baudDiff = baudrate - baudEstimate;
} else {
baudDiff = baudEstimate - baudrate;
}
if (i == 0 || baudDiff < bestBaudDiff) {
// Closest to requested baud rate so far
bestDivisor = tryDivisor;
bestBaud = baudEstimate;
bestBaudDiff = baudDiff;
if (baudDiff == 0) {
// Spot on! No point trying
break;
}
}
}
// Encode the best divisor value
long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14);
// Deal with special cases for encoded value
if (encodedDivisor == 1) {
encodedDivisor = 0; // 3000000 baud
} else if (encodedDivisor == 0x4001) {
encodedDivisor = 1; // 2000000 baud (BM only)
}
// Split into "value" and "index" values
long value = encodedDivisor & 0xFFFF;
long index;
if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H
|| mType == DeviceType.TYPE_4232H) {
index = (encodedDivisor >> 8) & 0xffff;
index &= 0xFF00;
index |= 0 /* TODO mIndex */;
} else {
index = (encodedDivisor >> 16) & 0xffff;
}
// Return the nearest baud rate
return new long[] {
bestBaud, index, value
};
}
@Override
public boolean getCD() throws IOException {
return false;
}
@Override
public boolean getCTS() throws IOException {
return false;
}
@Override
public boolean getDSR() throws IOException {
return false;
}
@Override
public boolean getDTR() throws IOException {
return false;
}
@Override
public void setDTR(boolean value) throws IOException {
}
@Override
public boolean getRI() throws IOException {
return false;
}
@Override
public boolean getRTS() throws IOException {
return false;
}
@Override
public void setRTS(boolean value) throws IOException {
}
@Override
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
if (purgeReadBuffers) {
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_PURGE_RX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Flushing RX failed: result=" + result);
}
}
if (purgeWriteBuffers) {
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_PURGE_TX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Flushing RX failed: result=" + result);
}
}
return true;
}
}
public static Map getSupportedDevices() {
final Map supportedDevices = new LinkedHashMap();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),
new int[] {
UsbId.FTDI_FT232R,
UsbId.FTDI_FT231X,
});
return supportedDevices;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/ProbeTable.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.util.Pair;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Maps (vendor id, product id) pairs to the corresponding serial driver.
*
* @author mike wakerly (opensource@hoho.com)
*/
public class ProbeTable {
private final Map, Class extends UsbSerialDriver>> mProbeTable =
new LinkedHashMap, Class extends UsbSerialDriver>>();
/**
* Adds or updates a (vendor, product) pair in the table.
*
* @param vendorId the USB vendor id
* @param productId the USB product id
* @param driverClass the driver class responsible for this pair
* @return {@code this}, for chaining
*/
public ProbeTable addProduct(int vendorId, int productId,
Class extends UsbSerialDriver> driverClass) {
mProbeTable.put(Pair.create(vendorId, productId), driverClass);
return this;
}
/**
* Internal method to add all supported products from
* {@code getSupportedProducts} static method.
*
* @param driverClass
* @return
*/
@SuppressWarnings("unchecked")
ProbeTable addDriver(Class extends UsbSerialDriver> driverClass) {
final Method method;
try {
method = driverClass.getMethod("getSupportedDevices");
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
final Map devices;
try {
devices = (Map) method.invoke(null);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
for (Map.Entry entry : devices.entrySet()) {
final int vendorId = entry.getKey().intValue();
for (int productId : entry.getValue()) {
addProduct(vendorId, productId, driverClass);
}
}
return this;
}
/**
* Returns the driver for the given (vendor, product) pair, or {@code null}
* if no match.
*
* @param vendorId the USB vendor id
* @param productId the USB product id
* @return the driver class matching this pair, or {@code null}
*/
public Class extends UsbSerialDriver> findDriver(int vendorId, int productId) {
final Pair pair = Pair.create(vendorId, productId);
return mProbeTable.get(pair);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/ProlificSerialDriver.java
================================================
/* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
/*
* Ported to usb-serial-for-android
* by Felix Hädicke
*
* Based on the pyprolific driver written
* by Emmanuel Blot
* See https://github.com/eblot/pyftdi
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ProlificSerialDriver implements UsbSerialDriver {
private final String TAG = ProlificSerialDriver.class.getSimpleName();
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
public ProlificSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new ProlificSerialPort(mDevice, 0);
}
@Override
public List getPorts() {
return Collections.singletonList(mPort);
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
class ProlificSerialPort extends CommonUsbSerialPort {
private static final int USB_READ_TIMEOUT_MILLIS = 1000;
private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01;
private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01;
private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
| UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN
| UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT
| UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int WRITE_ENDPOINT = 0x02;
private static final int READ_ENDPOINT = 0x83;
private static final int INTERRUPT_ENDPOINT = 0x81;
private static final int FLUSH_RX_REQUEST = 0x08;
private static final int FLUSH_TX_REQUEST = 0x09;
private static final int SET_LINE_REQUEST = 0x20;
private static final int SET_CONTROL_REQUEST = 0x22;
private static final int CONTROL_DTR = 0x01;
private static final int CONTROL_RTS = 0x02;
private static final int STATUS_FLAG_CD = 0x01;
private static final int STATUS_FLAG_DSR = 0x02;
private static final int STATUS_FLAG_RI = 0x08;
private static final int STATUS_FLAG_CTS = 0x80;
private static final int STATUS_BUFFER_SIZE = 10;
private static final int STATUS_BYTE_IDX = 8;
private static final int DEVICE_TYPE_HX = 0;
private static final int DEVICE_TYPE_0 = 1;
private static final int DEVICE_TYPE_1 = 2;
private int mDeviceType = DEVICE_TYPE_HX;
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
private UsbEndpoint mInterruptEndpoint;
private int mControlLinesValue = 0;
private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1;
private int mStatus = 0;
private volatile Thread mReadStatusThread = null;
private final Object mReadStatusThreadLock = new Object();
boolean mStopReadStatusThread = false;
private IOException mReadStatusException = null;
public ProlificSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
}
@Override
public UsbSerialDriver getDriver() {
return ProlificSerialDriver.this;
}
private final byte[] inControlTransfer(int requestType, int request,
int value, int index, int length) throws IOException {
byte[] buffer = new byte[length];
int result = mConnection.controlTransfer(requestType, request, value,
index, buffer, length, USB_READ_TIMEOUT_MILLIS);
if (result != length) {
throw new IOException(
String.format("ControlTransfer with value 0x%x failed: %d",
value, result));
}
return buffer;
}
private final void outControlTransfer(int requestType, int request,
int value, int index, byte[] data) throws IOException {
int length = (data == null) ? 0 : data.length;
int result = mConnection.controlTransfer(requestType, request, value,
index, data, length, USB_WRITE_TIMEOUT_MILLIS);
if (result != length) {
throw new IOException(
String.format("ControlTransfer with value 0x%x failed: %d",
value, result));
}
}
public int read(byte[] dest, int timeoutMillis, UsbDeviceConnection connection) throws IOException {
if (false) {
final UsbRequest request = new UsbRequest();
try {
request.initialize(connection, mReadEndpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = connection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int nread = buf.position();
if (nread > 0) {
//Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread;
} else {
return 0;
}
} finally {
request.close();
}
}
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = connection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
if (timeoutMillis == Integer.MAX_VALUE) {
// Hack: Special case "~infinite timeout" as an error.
return -1;
}
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
return numBytesRead;
}
private final byte[] vendorIn(int value, int index, int length)
throws IOException {
return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE,
PROLIFIC_VENDOR_READ_REQUEST, value, index, length);
}
private final void vendorOut(int value, int index, byte[] data)
throws IOException {
outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE,
PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data);
}
private void resetDevice() throws IOException {
purgeHwBuffers(true, true);
}
private final void ctrlOut(int request, int value, int index, byte[] data)
throws IOException {
outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index,
data);
}
private void doBlackMagic() throws IOException {
vendorIn(0x8484, 0, 1);
vendorOut(0x0404, 0, null);
vendorIn(0x8484, 0, 1);
vendorIn(0x8383, 0, 1);
vendorIn(0x8484, 0, 1);
vendorOut(0x0404, 1, null);
vendorIn(0x8484, 0, 1);
vendorIn(0x8383, 0, 1);
vendorOut(0, 1, null);
vendorOut(1, 0, null);
vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null);
}
private void setControlLines(int newControlLinesValue) throws IOException {
ctrlOut(SET_CONTROL_REQUEST, newControlLinesValue, 0, null);
mControlLinesValue = newControlLinesValue;
}
private final void readStatusThreadFunction() {
try {
while (!mStopReadStatusThread) {
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint,
buffer,
STATUS_BUFFER_SIZE,
500);
if (readBytesCount > 0) {
if (readBytesCount == STATUS_BUFFER_SIZE) {
mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
} else {
throw new IOException(
String.format("Invalid CTS / DSR / CD / RI status buffer received, expected %d bytes, but received %d",
STATUS_BUFFER_SIZE,
readBytesCount));
}
}
}
} catch (IOException e) {
mReadStatusException = e;
}
}
private final int getStatus() throws IOException {
if ((mReadStatusThread == null) && (mReadStatusException == null)) {
synchronized (mReadStatusThreadLock) {
if (mReadStatusThread == null) {
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
int readBytes = mConnection.bulkTransfer(mInterruptEndpoint,
buffer,
STATUS_BUFFER_SIZE,
100);
if (readBytes != STATUS_BUFFER_SIZE) {
Log.w(TAG, "Could not read initial CTS / DSR / CD / RI status");
} else {
mStatus = buffer[STATUS_BYTE_IDX] & 0xff;
}
mReadStatusThread = new Thread(new Runnable() {
@Override
public void run() {
readStatusThreadFunction();
}
});
mReadStatusThread.setDaemon(true);
mReadStatusThread.start();
}
}
}
/* throw and clear an exception which occured in the status read thread */
IOException readStatusException = mReadStatusException;
if (mReadStatusException != null) {
mReadStatusException = null;
throw readStatusException;
}
return mStatus;
}
private final boolean testStatusFlag(int flag) throws IOException {
return ((getStatus() & flag) == flag);
}
@Override
public void open(UsbDeviceConnection connection) throws IOException {
if (mConnection != null) {
throw new IOException("Already open");
}
UsbInterface usbInterface = mDevice.getInterface(0);
if (!connection.claimInterface(usbInterface, true)) {
throw new IOException("Error claiming Prolific interface 0");
}
mConnection = connection;
boolean opened = false;
try {
for (int i = 0; i < usbInterface.getEndpointCount(); ++i) {
UsbEndpoint currentEndpoint = usbInterface.getEndpoint(i);
switch (currentEndpoint.getAddress()) {
case READ_ENDPOINT:
mReadEndpoint = currentEndpoint;
break;
case WRITE_ENDPOINT:
mWriteEndpoint = currentEndpoint;
break;
case INTERRUPT_ENDPOINT:
mInterruptEndpoint = currentEndpoint;
break;
}
}
if (mDevice.getDeviceClass() == 0x02) {
mDeviceType = DEVICE_TYPE_0;
} else {
try {
Method getRawDescriptorsMethod
= mConnection.getClass().getMethod("getRawDescriptors");
byte[] rawDescriptors
= (byte[]) getRawDescriptorsMethod.invoke(mConnection);
byte maxPacketSize0 = rawDescriptors[7];
if (maxPacketSize0 == 64) {
mDeviceType = DEVICE_TYPE_HX;
} else if ((mDevice.getDeviceClass() == 0x00)
|| (mDevice.getDeviceClass() == 0xff)) {
mDeviceType = DEVICE_TYPE_1;
} else {
Log.w(TAG, "Could not detect PL2303 subtype, "
+ "Assuming that it is a HX device");
mDeviceType = DEVICE_TYPE_HX;
}
} catch (NoSuchMethodException e) {
Log.w(TAG, "Method UsbDeviceConnection.getRawDescriptors, "
+ "required for PL2303 subtype detection, not "
+ "available! Assuming that it is a HX device");
mDeviceType = DEVICE_TYPE_HX;
} catch (Exception e) {
Log.e(TAG, "An unexpected exception occured while trying "
+ "to detect PL2303 subtype", e);
}
}
setControlLines(mControlLinesValue);
resetDevice();
doBlackMagic();
opened = true;
} finally {
if (!opened) {
mConnection = null;
connection.releaseInterface(usbInterface);
}
}
}
@Override
public void close() throws IOException {
if (mConnection == null) {
throw new IOException("Already closed");
}
try {
mStopReadStatusThread = true;
synchronized (mReadStatusThreadLock) {
if (mReadStatusThread != null) {
try {
mReadStatusThread.join();
} catch (Exception e) {
Log.w(TAG, "An error occured while waiting for status read thread", e);
}
}
}
resetDevice();
} finally {
try {
mConnection.releaseInterface(mDevice.getInterface(0));
} finally {
mConnection = null;
}
}
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer,
readAmt, timeoutMillis);
if (numBytesRead < 0) {
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
return numBytesRead;
}
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
int offset = 0;
while (offset < src.length) {
final int writeLength;
final int amtWritten;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(mWriteEndpoint,
writeBuffer, writeLength, timeoutMillis);
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length="
+ src.length);
}
offset += amtWritten;
}
return offset;
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits,
int parity) throws IOException {
if ((mBaudRate == baudRate) && (mDataBits == dataBits)
&& (mStopBits == stopBits) && (mParity == parity)) {
// Make sure no action is performed if there is nothing to change
return;
}
byte[] lineRequestData = new byte[7];
lineRequestData[0] = (byte) (baudRate & 0xff);
lineRequestData[1] = (byte) ((baudRate >> 8) & 0xff);
lineRequestData[2] = (byte) ((baudRate >> 16) & 0xff);
lineRequestData[3] = (byte) ((baudRate >> 24) & 0xff);
switch (stopBits) {
case STOPBITS_1:
lineRequestData[4] = 0;
break;
case STOPBITS_1_5:
lineRequestData[4] = 1;
break;
case STOPBITS_2:
lineRequestData[4] = 2;
break;
default:
throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
}
switch (parity) {
case PARITY_NONE:
lineRequestData[5] = 0;
break;
case PARITY_ODD:
lineRequestData[5] = 1;
break;
case PARITY_MARK:
lineRequestData[5] = 3;
break;
case PARITY_SPACE:
lineRequestData[5] = 4;
break;
default:
throw new IllegalArgumentException("Unknown parity value: " + parity);
}
lineRequestData[6] = (byte) dataBits;
ctrlOut(SET_LINE_REQUEST, 0, 0, lineRequestData);
resetDevice();
mBaudRate = baudRate;
mDataBits = dataBits;
mStopBits = stopBits;
mParity = parity;
}
@Override
public boolean getCD() throws IOException {
return testStatusFlag(STATUS_FLAG_CD);
}
@Override
public boolean getCTS() throws IOException {
return testStatusFlag(STATUS_FLAG_CTS);
}
@Override
public boolean getDSR() throws IOException {
return testStatusFlag(STATUS_FLAG_DSR);
}
@Override
public boolean getDTR() throws IOException {
return ((mControlLinesValue & CONTROL_DTR) == CONTROL_DTR);
}
@Override
public void setDTR(boolean value) throws IOException {
int newControlLinesValue;
if (value) {
newControlLinesValue = mControlLinesValue | CONTROL_DTR;
} else {
newControlLinesValue = mControlLinesValue & ~CONTROL_DTR;
}
setControlLines(newControlLinesValue);
}
@Override
public boolean getRI() throws IOException {
return testStatusFlag(STATUS_FLAG_RI);
}
@Override
public boolean getRTS() throws IOException {
return ((mControlLinesValue & CONTROL_RTS) == CONTROL_RTS);
}
@Override
public void setRTS(boolean value) throws IOException {
int newControlLinesValue;
if (value) {
newControlLinesValue = mControlLinesValue | CONTROL_RTS;
} else {
newControlLinesValue = mControlLinesValue & ~CONTROL_RTS;
}
setControlLines(newControlLinesValue);
}
@Override
public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException {
if (purgeReadBuffers) {
vendorOut(FLUSH_RX_REQUEST, 0, null);
}
if (purgeWriteBuffers) {
vendorOut(FLUSH_TX_REQUEST, 0, null);
}
return purgeReadBuffers || purgeWriteBuffers;
}
}
public static Map getSupportedDevices() {
final Map supportedDevices = new LinkedHashMap();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC),
new int[] { UsbId.PROLIFIC_PL2303, });
return supportedDevices;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbId.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
/**
* Registry of USB vendor/product ID constants.
*
* Culled from various sources; see
* usb.ids for one listing.
*
* @author mike wakerly (opensource@hoho.com)
*/
public final class UsbId {
public static final int VENDOR_FTDI = 0x0403;
public static final int FTDI_FT232R = 0x6001;
public static final int FTDI_FT231X = 0x6015;
public static final int VENDOR_ATMEL = 0x03EB;
public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;
public static final int VENDOR_ARDUINO = 0x2341;
public static final int ARDUINO_UNO = 0x0001;
public static final int ARDUINO_MEGA_2560 = 0x0010;
public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;
public static final int ARDUINO_MEGA_ADK = 0x003f;
public static final int ARDUINO_MEGA_2560_R3 = 0x0042;
public static final int ARDUINO_UNO_R3 = 0x0043;
public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;
public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
public static final int ARDUINO_LEONARDO = 0x8036;
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
public static final int VENDOR_LEAFLABS = 0x1eaf;
public static final int LEAFLABS_MAPLE = 0x0004;
public static final int VENDOR_SILABS = 0x10c4;
public static final int SILABS_CP2102 = 0xea60;
public static final int SILABS_CP2105 = 0xea70;
public static final int SILABS_CP2108 = 0xea71;
public static final int SILABS_CP2110 = 0xea80;
public static final int VENDOR_PROLIFIC = 0x067b;
public static final int PROLIFIC_PL2303 = 0x2303;
private UsbId() {
throw new IllegalAccessError("Non-instantiable class.");
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialDriver.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbDevice;
import java.util.List;
/**
*
* @author mike wakerly (opensource@hoho.com)
*/
public interface UsbSerialDriver {
/**
* Returns the raw {@link UsbDevice} backing this port.
*
* @return the device
*/
public UsbDevice getDevice();
/**
* Returns all available ports for this device. This list must have at least
* one entry.
*
* @return the ports
*/
public List getPorts();
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialPort.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import java.io.IOException;
/**
* Interface for a single serial port.
*
* @author mike wakerly (opensource@hoho.com)
*/
public interface UsbSerialPort {
/** 5 data bits. */
public static final int DATABITS_5 = 5;
/** 6 data bits. */
public static final int DATABITS_6 = 6;
/** 7 data bits. */
public static final int DATABITS_7 = 7;
/** 8 data bits. */
public static final int DATABITS_8 = 8;
/** No flow control. */
public static final int FLOWCONTROL_NONE = 0;
/** RTS/CTS input flow control. */
public static final int FLOWCONTROL_RTSCTS_IN = 1;
/** RTS/CTS output flow control. */
public static final int FLOWCONTROL_RTSCTS_OUT = 2;
/** XON/XOFF input flow control. */
public static final int FLOWCONTROL_XONXOFF_IN = 4;
/** XON/XOFF output flow control. */
public static final int FLOWCONTROL_XONXOFF_OUT = 8;
/** No parity. */
public static final int PARITY_NONE = 0;
/** Odd parity. */
public static final int PARITY_ODD = 1;
/** Even parity. */
public static final int PARITY_EVEN = 2;
/** Mark parity. */
public static final int PARITY_MARK = 3;
/** Space parity. */
public static final int PARITY_SPACE = 4;
/** 1 stop bit. */
public static final int STOPBITS_1 = 1;
/** 1.5 stop bits. */
public static final int STOPBITS_1_5 = 3;
/** 2 stop bits. */
public static final int STOPBITS_2 = 2;
public UsbSerialDriver getDriver();
/**
* Port number within driver.
*/
public int getPortNumber();
/**
* The serial number of the underlying UsbDeviceConnection, or {@code null}.
*/
public String getSerial();
/**
* Opens and initializes the port. Upon success, caller must ensure that
* {@link #close()} is eventually called.
*
* @param connection an open device connection, acquired with
* {@link UsbManager#openDevice(android.hardware.usb.UsbDevice)}
* @throws IOException on error opening or initializing the port.
*/
public void open(UsbDeviceConnection connection) throws IOException;
/**
* Closes the port.
*
* @throws IOException on error closing the port.
*/
public void close() throws IOException;
/**
* Reads as many bytes as possible into the destination buffer.
*
* @param dest the destination byte buffer
* @param timeoutMillis the timeout for reading
* @return the actual number of bytes read
* @throws IOException if an error occurred during reading
*/
public int read(final byte[] dest, final int timeoutMillis) throws IOException;
public int read(final byte[] dest, final int timeoutMillis, final UsbDeviceConnection connection) throws IOException;
/**
* Writes as many bytes as possible from the source buffer.
*
* @param src the source byte buffer
* @param timeoutMillis the timeout for writing
* @return the actual number of bytes written
* @throws IOException if an error occurred during writing
*/
public int write(final byte[] src, final int timeoutMillis) throws IOException;
/**
* Sets various serial port parameters.
*
* @param baudRate baud rate as an integer, for example {@code 115200}.
* @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6},
* {@link #DATABITS_7}, or {@link #DATABITS_8}.
* @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or
* {@link #STOPBITS_2}.
* @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD},
* {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or
* {@link #PARITY_SPACE}.
* @throws IOException on error setting the port parameters
*/
public void setParameters(
int baudRate, int dataBits, int stopBits, int parity) throws IOException;
/**
* Gets the CD (Carrier Detect) bit from the underlying UART.
*
* @return the current state, or {@code false} if not supported.
* @throws IOException if an error occurred during reading
*/
public boolean getCD() throws IOException;
/**
* Gets the CTS (Clear To Send) bit from the underlying UART.
*
* @return the current state, or {@code false} if not supported.
* @throws IOException if an error occurred during reading
*/
public boolean getCTS() throws IOException;
/**
* Gets the DSR (Data Set Ready) bit from the underlying UART.
*
* @return the current state, or {@code false} if not supported.
* @throws IOException if an error occurred during reading
*/
public boolean getDSR() throws IOException;
/**
* Gets the DTR (Data Terminal Ready) bit from the underlying UART.
*
* @return the current state, or {@code false} if not supported.
* @throws IOException if an error occurred during reading
*/
public boolean getDTR() throws IOException;
/**
* Sets the DTR (Data Terminal Ready) bit on the underlying UART, if
* supported.
*
* @param value the value to set
* @throws IOException if an error occurred during writing
*/
public void setDTR(boolean value) throws IOException;
/**
* Gets the RI (Ring Indicator) bit from the underlying UART.
*
* @return the current state, or {@code false} if not supported.
* @throws IOException if an error occurred during reading
*/
public boolean getRI() throws IOException;
/**
* Gets the RTS (Request To Send) bit from the underlying UART.
*
* @return the current state, or {@code false} if not supported.
* @throws IOException if an error occurred during reading
*/
public boolean getRTS() throws IOException;
/**
* Sets the RTS (Request To Send) bit on the underlying UART, if
* supported.
*
* @param value the value to set
* @throws IOException if an error occurred during writing
*/
public void setRTS(boolean value) throws IOException;
/**
* Flush non-transmitted output data and / or non-read input data
* @param flushRX {@code true} to flush non-transmitted output data
* @param flushTX {@code true} to flush non-read input data
* @return {@code true} if the operation was successful, or
* {@code false} if the operation is not supported by the driver or device
* @throws IOException if an error occurred during flush
*/
public boolean purgeHwBuffers(boolean flushRX, boolean flushTX) throws IOException;
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialProber.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author mike wakerly (opensource@hoho.com)
*/
public class UsbSerialProber {
private final ProbeTable mProbeTable;
public UsbSerialProber(ProbeTable probeTable) {
mProbeTable = probeTable;
}
public static UsbSerialProber getDefaultProber() {
return new UsbSerialProber(getDefaultProbeTable());
}
public static ProbeTable getDefaultProbeTable() {
final ProbeTable probeTable = new ProbeTable();
probeTable.addDriver(CdcAcmSerialDriver.class);
probeTable.addDriver(Cp21xxSerialDriver.class);
probeTable.addDriver(FtdiSerialDriver.class);
probeTable.addDriver(ProlificSerialDriver.class);
return probeTable;
}
/**
* Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers}
* from the currently-attached {@link UsbDevice} hierarchy. This method does
* not require permission from the Android USB system, since it does not
* open any of the devices.
*
* @param usbManager
* @return a list, possibly empty, of all compatible drivers
*/
public List findAllDrivers(final UsbManager usbManager) {
final List result = new ArrayList();
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
final UsbSerialDriver driver = probeDevice(usbDevice);
if (driver != null) {
result.add(driver);
}
}
return result;
}
/**
* Probes a single device for a compatible driver.
*
* @param usbDevice the usb device to probe
* @return a new {@link UsbSerialDriver} compatible with this device, or
* {@code null} if none available.
*/
public UsbSerialDriver probeDevice(final UsbDevice usbDevice) {
final int vendorId = usbDevice.getVendorId();
final int productId = usbDevice.getProductId();
final Class extends UsbSerialDriver> driverClass =
mProbeTable.findDriver(vendorId, productId);
if (driverClass != null) {
final UsbSerialDriver driver;
try {
final Constructor extends UsbSerialDriver> ctor =
driverClass.getConstructor(UsbDevice.class);
driver = ctor.newInstance(usbDevice);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return driver;
}
return null;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/driver/UsbSerialRuntimeException.java
================================================
/*
* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver;
/**
* Generic unchecked exception for the usbserial package.
*
* @author mike wakerly (opensource@hoho.com)
*/
@SuppressWarnings("serial")
public class UsbSerialRuntimeException extends RuntimeException {
public UsbSerialRuntimeException() {
super();
}
public UsbSerialRuntimeException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
}
public UsbSerialRuntimeException(String detailMessage) {
super(detailMessage);
}
public UsbSerialRuntimeException(Throwable throwable) {
super(throwable);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/util/HexDump.java
================================================
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.util;
/**
* Clone of Android's HexDump class, for use in debugging. Cosmetic changes
* only.
*/
public class HexDump {
private final static char[] HEX_DIGITS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
public static String dumpHexString(byte[] array) {
return dumpHexString(array, 0, array.length);
}
public static String dumpHexString(byte[] array, int offset, int length) {
StringBuilder result = new StringBuilder();
byte[] line = new byte[16];
int lineIndex = 0;
result.append("\n0x");
result.append(toHexString(offset));
for (int i = offset; i < offset + length; i++) {
if (lineIndex == 16) {
result.append(" ");
for (int j = 0; j < 16; j++) {
if (line[j] > ' ' && line[j] < '~') {
result.append(new String(line, j, 1));
} else {
result.append(".");
}
}
result.append("\n0x");
result.append(toHexString(i));
lineIndex = 0;
}
byte b = array[i];
result.append(" ");
result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
result.append(HEX_DIGITS[b & 0x0F]);
line[lineIndex++] = b;
}
if (lineIndex != 16) {
int count = (16 - lineIndex) * 3;
count++;
for (int i = 0; i < count; i++) {
result.append(" ");
}
for (int i = 0; i < lineIndex; i++) {
if (line[i] > ' ' && line[i] < '~') {
result.append(new String(line, i, 1));
} else {
result.append(".");
}
}
}
return result.toString();
}
public static String toHexString(byte b) {
return toHexString(toByteArray(b));
}
public static String toHexString(byte[] array) {
return toHexString(array, 0, array.length);
}
public static String toHexString(byte[] array, int offset, int length) {
char[] buf = new char[length * 2];
int bufIndex = 0;
for (int i = offset; i < offset + length; i++) {
byte b = array[i];
buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
}
return new String(buf);
}
public static String toHexString(int i) {
return toHexString(toByteArray(i));
}
public static String toHexString(short i) {
return toHexString(toByteArray(i));
}
public static byte[] toByteArray(byte b) {
byte[] array = new byte[1];
array[0] = b;
return array;
}
public static byte[] toByteArray(int i) {
byte[] array = new byte[4];
array[3] = (byte) (i & 0xFF);
array[2] = (byte) ((i >> 8) & 0xFF);
array[1] = (byte) ((i >> 16) & 0xFF);
array[0] = (byte) ((i >> 24) & 0xFF);
return array;
}
public static byte[] toByteArray(short i) {
byte[] array = new byte[2];
array[1] = (byte) (i & 0xFF);
array[0] = (byte) ((i >> 8) & 0xFF);
return array;
}
private static int toByte(char c) {
if (c >= '0' && c <= '9')
return (c - '0');
if (c >= 'A' && c <= 'F')
return (c - 'A' + 10);
if (c >= 'a' && c <= 'f')
return (c - 'a' + 10);
throw new RuntimeException("Invalid hex char '" + c + "'");
}
public static byte[] hexStringToByteArray(String hexString) {
int length = hexString.length();
byte[] buffer = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString
.charAt(i + 1)));
}
return buffer;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ImportedLibraries/usbserial/util/SerialInputOutputManager.java
================================================
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.util;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialPort;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Utility class which services a {@link UsbSerialPort} in its {@link #run()}
* method.
*
* @author mike wakerly (opensource@hoho.com)
*/
public class SerialInputOutputManager implements Runnable {
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
private static final boolean DEBUG = true;
private static final int READ_WAIT_MILLIS = 200;
private static final int BUFSIZ = 4096;
private final UsbSerialPort mDriver;
private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
// Synchronized by 'mWriteBuffer'
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
private enum State {
STOPPED,
RUNNING,
STOPPING
}
// Synchronized by 'this'
private State mState = State.STOPPED;
// Synchronized by 'this'
private Listener mListener;
public interface Listener {
/**
* Called when new incoming data is available.
*/
public void onNewData(byte[] data);
/**
* Called when {@link SerialInputOutputManager#run()} aborts due to an
* error.
*/
public void onRunError(Exception e);
}
/**
* Creates a new instance with no listener.
*/
public SerialInputOutputManager(UsbSerialPort driver) {
this(driver, null);
}
/**
* Creates a new instance with the provided listener.
*/
public SerialInputOutputManager(UsbSerialPort driver, Listener listener) {
mDriver = driver;
mListener = listener;
}
public synchronized void setListener(Listener listener) {
mListener = listener;
}
public synchronized Listener getListener() {
return mListener;
}
public void writeAsync(byte[] data) {
synchronized (mWriteBuffer) {
mWriteBuffer.put(data);
}
}
public synchronized void stop() {
if (getState() == State.RUNNING) {
Log.i(TAG, "Stop requested");
mState = State.STOPPING;
}
}
private synchronized State getState() {
return mState;
}
/**
* Continuously services the read and write buffers until {@link #stop()} is
* called, or until a driver exception is raised.
*
* NOTE(mikey): Uses inefficient read/write-with-timeout.
* TODO(mikey): Read asynchronously with {@link UsbRequest#queue(ByteBuffer, int)}
*/
@Override
public void run() {
synchronized (this) {
if (getState() != State.STOPPED) {
throw new IllegalStateException("Already running.");
}
mState = State.RUNNING;
}
Log.i(TAG, "Running ..");
try {
while (true) {
if (getState() != State.RUNNING) {
Log.i(TAG, "Stopping mState=" + getState());
break;
}
step();
}
} catch (Exception e) {
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
final Listener listener = getListener();
if (listener != null) {
listener.onRunError(e);
}
} finally {
synchronized (this) {
mState = State.STOPPED;
Log.i(TAG, "Stopped.");
}
}
}
private void step() throws IOException {
// Handle incoming data.
int len = mDriver.read(mReadBuffer.array(), READ_WAIT_MILLIS);
if (len > 0) {
if (DEBUG) Log.d(TAG, "Read data len=" + len);
final Listener listener = getListener();
if (listener != null) {
final byte[] data = new byte[len];
mReadBuffer.get(data, 0, len);
listener.onNewData(data);
}
mReadBuffer.clear();
}
// Handle outgoing data.
byte[] outBuff = null;
synchronized (mWriteBuffer) {
len = mWriteBuffer.position();
if (len > 0) {
outBuff = new byte[len];
mWriteBuffer.rewind();
mWriteBuffer.get(outBuff, 0, len);
mWriteBuffer.clear();
}
}
if (outBuff != null) {
if (DEBUG) {
Log.d(TAG, "Writing data len=" + len);
}
mDriver.write(outBuff, READ_WAIT_MILLIS);
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/BgReadingInterface.java
================================================
package com.eveningoutpost.dexdrip.Interfaces;
import com.eveningoutpost.dexdrip.Models.BgReading;
import retrofit.Callback;
import retrofit.http.Body;
import retrofit.http.POST;
import retrofit.http.PUT;
import retrofit.http.Path;
/**
* Created by stephenblack on 11/6/14.
*/
public interface BgReadingInterface {
@POST("/api/v1/users/{user_uuid}/BgReadings/new")
void createReading(@Path("user_uuid") String user_uuid, @Body BgReading bgReading, Callback callback);
@PUT("/api/v1/users/{user_uuid}/BgReading/{bgReading_uuid}")
void updateReading(@Path("user_uuid") String user_uuid, @Path("bgReading_uuid") String uuid, @Body BgReading bgReading, Callback callback);
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/CalibrationInterface.java
================================================
package com.eveningoutpost.dexdrip.Interfaces;
import com.eveningoutpost.dexdrip.Models.Calibration;
import retrofit.Callback;
import retrofit.http.Body;
import retrofit.http.POST;
import retrofit.http.Path;
/**
* Created by stephenblack on 11/7/14.
*/
public interface CalibrationInterface {
@POST("/api/v1/users/{user_uuid}/calibrations/new")
void createCalibration(@Path("user_uuid") String user_uuid, @Body Calibration calibration, Callback callback);
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/SensorInterface.java
================================================
package com.eveningoutpost.dexdrip.Interfaces;
import com.eveningoutpost.dexdrip.Sensor;
import retrofit.Callback;
import retrofit.http.Body;
import retrofit.http.POST;
import retrofit.http.Path;
/**
* Created by stephenblack on 11/7/14.
*/
public interface SensorInterface {
@POST("/api/v1/users/{user_uuid}/sensors/new")
void createSensor(@Path("user_uuid") String user_uuid, @Body Sensor sensor, Callback callback);
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Interfaces/UserInterface.java
================================================
package com.eveningoutpost.dexdrip.Interfaces;
import com.eveningoutpost.dexdrip.Models.User;
import retrofit.Callback;
import retrofit.http.Body;
import retrofit.http.POST;
/**
* Created by stephenblack on 11/10/14.
*/
public interface UserInterface {
@POST("/api/v1/sessions/new")
void authenticate(@Body User user, Callback callback);
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/LicenseAgreementActivity.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import com.eveningoutpost.dexdrip.Models.BgReading;
public class LicenseAgreementActivity extends Activity {
boolean IUnderstand;
CheckBox agreeCheckBox;
Button saveButton;
SharedPreferences prefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
IUnderstand = prefs.getBoolean("I_understand", false);
setContentView(R.layout.activity_license_agreement);
agreeCheckBox = (CheckBox)findViewById(R.id.agreeCheckBox);
agreeCheckBox.setChecked(IUnderstand);
saveButton = (Button)findViewById(R.id.saveButton);
addListenerOnButton();
}
public void addListenerOnButton() {
saveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
prefs.edit().putBoolean("I_understand", agreeCheckBox.isChecked()).apply();
Intent intent = new Intent(getApplicationContext(), Home.class);
startActivity(intent);
finish();
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Models/ActiveBluetoothDevice.java
================================================
package com.eveningoutpost.dexdrip.Models;
import android.provider.BaseColumns;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
/**
* Created by stephenblack on 11/3/14.
*/
@Table(name = "ActiveBluetoothDevice", id = BaseColumns._ID)
public class ActiveBluetoothDevice extends Model {
@Column(name = "name")
public String name;
@Column(name = "address")
public String address;
@Column(name = "connected")
public boolean connected;
public static ActiveBluetoothDevice first() {
return new Select()
.from(ActiveBluetoothDevice.class)
.orderBy("_ID asc")
.executeSingle();
}
public static void forget() {
ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();
if (activeBluetoothDevice != null) {
activeBluetoothDevice.delete();
}
}
public static void connected() {
ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();
if(activeBluetoothDevice != null) {
activeBluetoothDevice.connected = true;
activeBluetoothDevice.save();
}
}
public static void disconnected() {
ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();
if(activeBluetoothDevice != null) {
activeBluetoothDevice.connected = false;
activeBluetoothDevice.save();
}
}
public static boolean is_connected() {
ActiveBluetoothDevice activeBluetoothDevice = ActiveBluetoothDevice.first();
if(activeBluetoothDevice != null) {
return activeBluetoothDevice.connected;
}
return false;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Models/BgReading.java
================================================
package com.eveningoutpost.dexdrip.Models;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.provider.BaseColumns;
import android.util.Log;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalSubrecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.Sensor;
import com.eveningoutpost.dexdrip.Services.DexShareCollectionService;
import com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue;
import com.eveningoutpost.dexdrip.UtilityModels.Constants;
import com.eveningoutpost.dexdrip.UtilityModels.Notifications;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.internal.bind.DateTypeAdapter;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Table(name = "BgReadings", id = BaseColumns._ID)
public class BgReading extends Model {
private final static String TAG = BgReading.class.getSimpleName();
//TODO: Have these as adjustable settings!!
public final static double BESTOFFSET = (60000 * 0); // Assume readings are about x minutes off from actual!
@Column(name = "sensor", index = true)
public Sensor sensor;
@Column(name = "calibration", index = true)
public Calibration calibration;
@Expose
@Column(name = "timestamp", index = true)
public long timestamp;
@Expose
@Column(name = "time_since_sensor_started")
public double time_since_sensor_started;
@Expose
@Column(name = "raw_data")
public double raw_data;
@Expose
@Column(name = "filtered_data")
public double filtered_data;
@Expose
@Column(name = "age_adjusted_raw_value")
public double age_adjusted_raw_value;
@Expose
@Column(name = "calibration_flag")
public boolean calibration_flag;
@Expose
@Column(name = "calculated_value")
public double calculated_value;
@Expose
@Column(name = "calculated_value_slope")
public double calculated_value_slope;
@Expose
@Column(name = "a")
public double a;
@Expose
@Column(name = "b")
public double b;
@Expose
@Column(name = "c")
public double c;
@Expose
@Column(name = "ra")
public double ra;
@Expose
@Column(name = "rb")
public double rb;
@Expose
@Column(name = "rc")
public double rc;
@Expose
@Column(name = "uuid", index = true)
public String uuid;
@Expose
@Column(name = "calibration_uuid")
public String calibration_uuid;
@Expose
@Column(name = "sensor_uuid", index = true)
public String sensor_uuid;
@Column(name = "snyced")
public boolean synced;
@Column(name = "raw_calculated")
public double raw_calculated;
@Column(name = "hide_slope")
public boolean hide_slope;
@Column(name = "noise")
public String noise;
public double calculated_value_mmol() {
return mmolConvert(calculated_value);
}
public double mmolConvert(double mgdl) {
return mgdl * Constants.MGDL_TO_MMOLL;
}
public String displayValue(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String unit = prefs.getString("units", "mgdl");
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(0);
if (calculated_value >= 400) {
return "HIGH";
} else if (calculated_value >= 40) {
if(unit.compareTo("mgdl") == 0) {
df.setMaximumFractionDigits(0);
return df.format(calculated_value);
} else {
df.setMaximumFractionDigits(1);
return df.format(calculated_value_mmol());
}
} else {
return "LOW";
}
}
public static double activeSlope() {
BgReading bgReading = BgReading.lastNoSenssor();
double slope = (2 * bgReading.a * (new Date().getTime() + BESTOFFSET)) + bgReading.b;
Log.w(TAG, "ESTIMATE SLOPE" + slope);
return slope;
}
public static double activePrediction() {
BgReading bgReading = BgReading.lastNoSenssor();
if (bgReading != null) {
double currentTime = new Date().getTime();
if (currentTime >= bgReading.timestamp + (60000 * 7)) { currentTime = bgReading.timestamp + (60000 * 7); }
double time = currentTime + BESTOFFSET;
return ((bgReading.a * time * time) + (bgReading.b * time) + bgReading.c);
}
return 0;
}
//*******CLASS METHODS***********//
public static void create(EGVRecord[] egvRecords, long addativeOffset, Context context) {
for(EGVRecord egvRecord : egvRecords) { BgReading.create(egvRecord, addativeOffset, context); }
}
public static void create(SensorRecord[] sensorRecords, long addativeOffset, Context context) {
for(SensorRecord sensorRecord : sensorRecords) { BgReading.create(sensorRecord, addativeOffset, context); }
}
public static void create(SensorRecord sensorRecord, long addativeOffset, Context context) {
Log.w(TAG, "gonna make some sensor records: " + sensorRecord.getUnfiltered());
if(BgReading.is_new(sensorRecord, addativeOffset)) {
BgReading bgReading = new BgReading();
Sensor sensor = Sensor.currentSensor();
Calibration calibration = Calibration.getForTimestamp(sensorRecord.getSystemTime().getTime() + addativeOffset);
if(sensor != null && calibration != null) {
bgReading.sensor = sensor;
bgReading.sensor_uuid = sensor.uuid;
bgReading.calibration = calibration;
bgReading.calibration_uuid = calibration.uuid;
bgReading.raw_data = (sensorRecord.getUnfiltered() / 1000);
bgReading.filtered_data = (sensorRecord.getFiltered() / 1000);
bgReading.timestamp = sensorRecord.getSystemTime().getTime() + addativeOffset;
if(bgReading.timestamp > new Date().getTime()) { return; }
bgReading.uuid = UUID.randomUUID().toString();
bgReading.time_since_sensor_started = bgReading.timestamp - sensor.started_at;
bgReading.synced = false;
bgReading.calculateAgeAdjustedRawValue();
bgReading.save();
}
}
}
public static void create(EGVRecord egvRecord, long addativeOffset, Context context) {
BgReading bgReading = BgReading.getForTimestamp(egvRecord.getSystemTime().getTime() + addativeOffset);
Log.w(TAG, "Looking for BG reading to tag this thing to: " + egvRecord.getBGValue());
if(bgReading != null) {
bgReading.calculated_value = egvRecord.getBGValue();
if (egvRecord.getBGValue() <= 13) {
Calibration calibration = bgReading.calibration;
double firstAdjSlope = calibration.first_slope + (calibration.first_decay * (Math.ceil(new Date().getTime() - calibration.timestamp)/(1000 * 60 * 10)));
double calSlope = (calibration.first_scale / firstAdjSlope)*1000;
double calIntercept = ((calibration.first_scale * calibration.first_intercept) / firstAdjSlope)*-1;
bgReading.raw_calculated = (((calSlope * bgReading.raw_data) + calIntercept) - 5);
bgReading.noise = egvRecord.noiseValue();
}
Log.w(TAG, "NEW VALUE CALCULATED AT: " + bgReading.calculated_value);
bgReading.calculated_value_slope = bgReading.slopefromName(egvRecord.getTrend().friendlyTrendName());
if(egvRecord.getTrend().friendlyTrendName().compareTo("NOT_COMPUTABLE") == 0 || egvRecord.getTrend().friendlyTrendName().compareTo("OUT_OF_RANGE") == 0) {
bgReading.hide_slope = true;
}
bgReading.save();
bgReading.find_new_curve();
bgReading.find_new_raw_curve();
Notifications.notificationSetter(context);
BgSendQueue.addToQueue(bgReading, "create", context);
}
}
public static BgReading getForTimestamp(double timestamp) {
Sensor sensor = Sensor.currentSensor();
if(sensor != null) {
BgReading bgReading = new Select()
.from(BgReading.class)
.where("Sensor = ? ", sensor.getId())
.where("timestamp <= ?", (timestamp + (60*1000))) // 1 minute padding (should never be that far off, but why not)
.where("calculated_value = 0")
.where("raw_calculated = 0")
.orderBy("timestamp desc")
.executeSingle();
if(bgReading != null && Math.abs(bgReading.timestamp - timestamp) < (3*60*1000)) { //cool, so was it actually within 4 minutes of that bg reading?
Log.w(TAG, "Found a BG timestamp match");
return bgReading;
}
}
Log.w(TAG, "No luck finding a BG timestamp match");
return null;
}
public static boolean is_new(SensorRecord sensorRecord, long addativeOffset) {
double timestamp = sensorRecord.getSystemTime().getTime() + addativeOffset;
Sensor sensor = Sensor.currentSensor();
if(sensor != null) {
BgReading bgReading = new Select()
.from(BgReading.class)
.where("Sensor = ? ", sensor.getId())
.where("timestamp <= ?", (timestamp + (60*1000))) // 1 minute padding (should never be that far off, but why not)
.orderBy("timestamp desc")
.executeSingle();
if(bgReading != null && Math.abs(bgReading.timestamp - timestamp) < (3*60*1000)) { //cool, so was it actually within 4 minutes of that bg reading?
Log.w(TAG, "Old Reading");
return false;
}
}
Log.w(TAG, "New Reading");
return true;
}
public static BgReading create(double raw_data, Context context, Long timestamp) {
BgReading bgReading = new BgReading();
Sensor sensor = Sensor.currentSensor();
if (sensor != null) {
Calibration calibration = Calibration.last();
if (calibration == null) {
bgReading.sensor = sensor;
bgReading.sensor_uuid = sensor.uuid;
bgReading.raw_data = (raw_data / 1000);
bgReading.filtered_data = (raw_data / 1000);
bgReading.timestamp = timestamp;
bgReading.uuid = UUID.randomUUID().toString();
bgReading.time_since_sensor_started = bgReading.timestamp - sensor.started_at;
bgReading.synced = false;
bgReading.calibration_flag = false;
bgReading.calculateAgeAdjustedRawValue();
bgReading.save();
bgReading.perform_calculations();
} else {
bgReading.sensor = sensor;
bgReading.sensor_uuid = sensor.uuid;
bgReading.calibration = calibration;
bgReading.calibration_uuid = calibration.uuid;
bgReading.raw_data = (raw_data/1000);
bgReading.filtered_data = (raw_data/1000);
bgReading.timestamp = timestamp;
bgReading.uuid = UUID.randomUUID().toString();
bgReading.time_since_sensor_started = bgReading.timestamp - sensor.started_at;
bgReading.synced = false;
bgReading.calculateAgeAdjustedRawValue();
if(calibration.check_in) {
double firstAdjSlope = calibration.first_slope + (calibration.first_decay * (Math.ceil(new Date().getTime() - calibration.timestamp)/(1000 * 60 * 10)));
double calSlope = (calibration.first_scale / firstAdjSlope)*1000;
double calIntercept = ((calibration.first_scale * calibration.first_intercept) / firstAdjSlope)*-1;
bgReading.calculated_value = (((calSlope * bgReading.raw_data) + calIntercept) - 5);
} else {
BgReading lastBgReading = BgReading.last();
if (lastBgReading != null && lastBgReading.calibration != null) {
if (lastBgReading.calibration_flag == true && ((lastBgReading.timestamp + (60000 * 20)) > bgReading.timestamp) && ((lastBgReading.calibration.timestamp + (60000 * 20)) > bgReading.timestamp)) {
lastBgReading.calibration.rawValueOverride(BgReading.weightedAverageRaw(lastBgReading.timestamp, bgReading.timestamp, lastBgReading.calibration.timestamp, lastBgReading.age_adjusted_raw_value, bgReading.age_adjusted_raw_value), context);
}
}
bgReading.calculated_value = ((calibration.slope * bgReading.age_adjusted_raw_value) + calibration.intercept);
}
bgReading.calculated_value = Math.min(400, Math.max(40, bgReading.calculated_value));
Log.w(TAG, "NEW VALUE CALCULATED AT: " + bgReading.calculated_value);
bgReading.save();
bgReading.perform_calculations();
Notifications.notificationSetter(context);
BgSendQueue.addToQueue(bgReading, "create", context);
}
}
Log.w("BG GSON: ",bgReading.toS());
return bgReading;
}
public static String slopeArrow() {
double slope = (float) (BgReading.activeSlope() * 60000);
return slopeArrow(slope);
}
public static String slopeArrow(double slope) {
String arrow;
if (slope <= (-3.5)) {
arrow = "\u21ca";
} else if (slope <= (-2)) {
arrow = "\u2193";
} else if (slope <= (-1)) {
arrow = "\u2198";
} else if (slope <= (1)) {
arrow = "\u2192";
} else if (slope <= (2)) {
arrow = "\u2197";
} else if (slope <= (3.5)) {
arrow = "\u2191";
} else {
arrow = "\u21c8";
}
return arrow;
}
public String slopeName() {
double slope_by_minute = calculated_value_slope * 60000;
String arrow = "NONE";
if (slope_by_minute <= (-3.5)) {
arrow = "DoubleDown";
} else if (slope_by_minute <= (-2)) {
arrow = "SingleDown";
} else if (slope_by_minute <= (-1)) {
arrow = "FortyFiveDown";
} else if (slope_by_minute <= (1)) {
arrow = "Flat";
} else if (slope_by_minute <= (2)) {
arrow = "FortyFiveUp";
} else if (slope_by_minute <= (3.5)) {
arrow = "SingleUp";
} else if (slope_by_minute <= (40)) {
arrow = "DoubleUp";
}
if(hide_slope) {
arrow = "9";
}
return arrow;
}
public double slopefromName(String slope_name) {
double slope_by_minute = 0;
if (slope_name.compareTo("DoubleDown") == 0) {
slope_by_minute = -3.5;
} else if (slope_name.compareTo("SingleDown") == 0) {
slope_by_minute = -2;
} else if (slope_name.compareTo("FortyFiveDown") == 0) {
slope_by_minute = -1;
} else if (slope_name.compareTo("Flat") == 0) {
slope_by_minute = 0;
} else if (slope_name.compareTo("FortyFiveUp") == 0) {
slope_by_minute = 2;
} else if (slope_name.compareTo("SingleUp") == 0) {
slope_by_minute = 2;
} else if (slope_name.compareTo("DoubleUp") == 0) {
slope_by_minute = 4;
} else if (slope_name.compareTo("NOT_COMPUTABLE") == 0 || slope_name.compareTo("OUT_OF_RANGE") == 0) {
slope_by_minute = 0;
}
return slope_by_minute /60000;
}
public static BgReading last() {
Sensor sensor = Sensor.currentSensor();
if (sensor != null) {
return new Select()
.from(BgReading.class)
.where("Sensor = ? ", sensor.getId())
.where("calculated_value != 0")
.where("raw_data != 0")
.orderBy("timestamp desc")
.executeSingle();
}
return null;
}
public static List latest_by_size(int number) {
Sensor sensor = Sensor.currentSensor();
return new Select()
.from(BgReading.class)
.where("Sensor = ? ", sensor.getId())
.where("raw_data != 0")
.orderBy("timestamp desc")
.limit(number)
.execute();
}
public static BgReading lastNoSenssor() {
return new Select()
.from(BgReading.class)
.where("calculated_value != 0")
.where("raw_data != 0")
.orderBy("timestamp desc")
.executeSingle();
}
public static List latest(int number) {
Sensor sensor = Sensor.currentSensor();
if (sensor == null) { return null; }
return new Select()
.from(BgReading.class)
.where("Sensor = ? ", sensor.getId())
.where("calculated_value != 0")
.where("raw_data != 0")
.orderBy("timestamp desc")
.limit(number)
.execute();
}
public static List latestUnCalculated(int number) {
Sensor sensor = Sensor.currentSensor();
if (sensor == null) { return null; }
return new Select()
.from(BgReading.class)
.where("Sensor = ? ", sensor.getId())
.where("raw_data != 0")
.orderBy("timestamp desc")
.limit(number)
.execute();
}
public static List latestForGraph(int number, double startTime) {
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(1);
return new Select()
.from(BgReading.class)
.where("timestamp >= " + df.format(startTime))
.where("calculated_value != 0")
.where("raw_data != 0")
.orderBy("timestamp desc")
.limit(number)
.execute();
}
public static List last30Minutes() {
double timestamp = (new Date().getTime()) - (60000 * 30);
return new Select()
.from(BgReading.class)
.where("timestamp >= " + timestamp)
.where("calculated_value != 0")
.where("raw_data != 0")
.orderBy("timestamp desc")
.execute();
}
public static double estimated_bg(double timestamp) {
timestamp = timestamp + BESTOFFSET;
BgReading latest = BgReading.last();
if (latest == null) {
return 0;
} else {
return (latest.a * timestamp * timestamp) + (latest.b * timestamp) + latest.c;
}
}
public static double estimated_raw_bg(double timestamp) {
timestamp = timestamp + BESTOFFSET;
double estimate;
BgReading latest = BgReading.last();
if (latest == null) {
Log.w(TAG, "No data yet, assume perfect!");
estimate = 160;
} else {
estimate = (latest.ra * timestamp * timestamp) + (latest.rb * timestamp) + latest.rc;
}
Log.w(TAG, "ESTIMATE RAW BG" + estimate);
return estimate;
}
//*******INSTANCE METHODS***********//
public void perform_calculations() {
find_new_curve();
find_new_raw_curve();
find_slope();
}
public void find_slope() {
List last_2 = BgReading.latest(2);
if (last_2.size() == 2) {
BgReading second_latest = last_2.get(1);
double y1 = calculated_value;
double x1 = timestamp;
double y2 = second_latest.calculated_value;
double x2 = second_latest.timestamp;
if(y1 == y2) {
calculated_value_slope = 0;
} else {
calculated_value_slope = (y2 - y1)/(x2 - x1);
}
save();
} else if (last_2.size() == 1) {
calculated_value_slope = 0;
save();
} else {
Log.w(TAG, "NO BG? COULDNT FIND SLOPE!");
}
}
public void find_new_curve() {
List last_3 = BgReading.latest(3);
if (last_3.size() == 3) {
BgReading second_latest = last_3.get(1);
BgReading third_latest = last_3.get(2);
double y3 = calculated_value;
double x3 = timestamp;
double y2 = second_latest.calculated_value;
double x2 = second_latest.timestamp;
double y1 = third_latest.calculated_value;
double x1 = third_latest.timestamp;
a = y1/((x1-x2)*(x1-x3))+y2/((x2-x1)*(x2-x3))+y3/((x3-x1)*(x3-x2));
b = (-y1*(x2+x3)/((x1-x2)*(x1-x3))-y2*(x1+x3)/((x2-x1)*(x2-x3))-y3*(x1+x2)/((x3-x1)*(x3-x2)));
c = (y1*x2*x3/((x1-x2)*(x1-x3))+y2*x1*x3/((x2-x1)*(x2-x3))+y3*x1*x2/((x3-x1)*(x3-x2)));
Log.w(TAG, "BG PARABOLIC RATES: "+a+"x^2 + "+b+"x + "+c);
save();
} else if (last_3.size() == 2) {
Log.w(TAG, "Not enough data to calculate parabolic rates - assume Linear");
BgReading latest = last_3.get(0);
BgReading second_latest = last_3.get(1);
double y2 = latest.calculated_value;
double x2 = timestamp;
double y1 = second_latest.calculated_value;
double x1 = second_latest.timestamp;
if(y1 == y2) {
b = 0;
} else {
b = (y2 - y1)/(x2 - x1);
}
a = 0;
c = -1 * ((latest.b * x1) - y1);
Log.w(TAG, ""+latest.a+"x^2 + "+latest.b+"x + "+latest.c);
save();
} else {
Log.w(TAG, "Not enough data to calculate parabolic rates - assume static data");
a = 0;
b = 0;
c = calculated_value;
Log.w(TAG, ""+a+"x^2 + "+b+"x + "+c);
save();
}
}
public void calculateAgeAdjustedRawValue(){
double adjust_for = (86400000 * 1.9) - time_since_sensor_started;
if (adjust_for > 0) {
age_adjusted_raw_value = (((.45) * (adjust_for / (86400000 * 1.9))) * raw_data) + raw_data;
Log.w("RAW VALUE ADJUSTMENT: ", "FROM:" + raw_data + " TO: " + age_adjusted_raw_value);
} else {
age_adjusted_raw_value = raw_data;
}
}
public void find_new_raw_curve() {
List last_3 = BgReading.latest(3);
if (last_3.size() == 3) {
BgReading second_latest = last_3.get(1);
BgReading third_latest = last_3.get(2);
double y3 = age_adjusted_raw_value;
double x3 = timestamp;
double y2 = second_latest.age_adjusted_raw_value;
double x2 = second_latest.timestamp;
double y1 = third_latest.age_adjusted_raw_value;
double x1 = third_latest.timestamp;
ra = y1/((x1-x2)*(x1-x3))+y2/((x2-x1)*(x2-x3))+y3/((x3-x1)*(x3-x2));
rb = (-y1*(x2+x3)/((x1-x2)*(x1-x3))-y2*(x1+x3)/((x2-x1)*(x2-x3))-y3*(x1+x2)/((x3-x1)*(x3-x2)));
rc = (y1*x2*x3/((x1-x2)*(x1-x3))+y2*x1*x3/((x2-x1)*(x2-x3))+y3*x1*x2/((x3-x1)*(x3-x2)));
Log.w(TAG, "RAW PARABOLIC RATES: "+ra+"x^2 + "+rb+"x + "+rc);
save();
} else if (last_3.size() == 2) {
BgReading latest = last_3.get(0);
BgReading second_latest = last_3.get(1);
double y2 = latest.age_adjusted_raw_value;
double x2 = timestamp;
double y1 = second_latest.age_adjusted_raw_value;
double x1 = second_latest.timestamp;
if(y1 == y2) {
rb = 0;
} else {
rb = (y2 - y1)/(x2 - x1);
}
ra = 0;
rc = -1 * ((latest.rb * x1) - y1);
Log.w(TAG, "Not enough data to calculate parabolic rates - assume Linear data");
Log.w(TAG, "RAW PARABOLIC RATES: "+ra+"x^2 + "+rb+"x + "+rc);
save();
} else {
Log.w(TAG, "Not enough data to calculate parabolic rates - assume static data");
BgReading latest_entry = BgReading.lastNoSenssor();
ra = 0;
rb = 0;
rc = latest_entry.age_adjusted_raw_value;
save();
}
}
public static double weightedAverageRaw(double timeA, double timeB, double calibrationTime, double rawA, double rawB) {
double relativeSlope = (rawB - rawA)/(timeB - timeA);
double relativeIntercept = rawA - (relativeSlope * timeA);
return ((relativeSlope * calibrationTime) + relativeIntercept);
}
public String toS() {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.serializeSpecialFloatingPointValues()
.create();
return gson.toJson(this);
}
public String noiseValue() {
if(noise == null || noise.compareTo("") == 0) {
return "1";
} else {
return String.valueOf(noise);
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Models/Calibration.java
================================================
package com.eveningoutpost.dexdrip.Models;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.provider.BaseColumns;
import android.util.Log;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalSubrecord;
import com.eveningoutpost.dexdrip.Sensor;
import com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue;
import com.eveningoutpost.dexdrip.UtilityModels.CalibrationSendQueue;
import com.eveningoutpost.dexdrip.UtilityModels.Constants;
import com.eveningoutpost.dexdrip.UtilityModels.Notifications;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.internal.bind.DateTypeAdapter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
* Created by stephenblack on 10/29/14.
*/
@Table(name = "Calibration", id = BaseColumns._ID)
public class Calibration extends Model {
private final static String TAG = Calibration.class.getSimpleName();
@Expose
@Column(name = "timestamp", index = true)
public double timestamp;
@Expose
@Column(name = "sensor_age_at_time_of_estimation")
public double sensor_age_at_time_of_estimation;
@Column(name = "sensor", index = true)
public Sensor sensor;
@Expose
@Column(name = "bg")
public double bg;
@Expose
@Column(name = "raw_value")
public double raw_value;
//
// @Expose
// @Column(name = "filtered_value")
// public double filtered_value;
@Expose
@Column(name = "adjusted_raw_value")
public double adjusted_raw_value;
@Expose
@Column(name = "sensor_confidence")
public double sensor_confidence;
@Expose
@Column(name = "slope_confidence")
public double slope_confidence;
@Expose
@Column(name = "raw_timestamp")
public double raw_timestamp;
@Expose
@Column(name = "slope")
public double slope;
@Expose
@Column(name = "intercept")
public double intercept;
@Expose
@Column(name = "distance_from_estimate")
public double distance_from_estimate;
@Expose
@Column(name = "estimate_raw_at_time_of_calibration")
public double estimate_raw_at_time_of_calibration;
@Expose
@Column(name = "estimate_bg_at_time_of_calibration")
public double estimate_bg_at_time_of_calibration;
@Expose
@Column(name = "uuid", index = true)
public String uuid;
@Expose
@Column(name = "sensor_uuid", index = true)
public String sensor_uuid;
@Expose
@Column(name = "possible_bad")
public Boolean possible_bad;
@Expose
@Column(name = "check_in")
public boolean check_in;
@Expose
@Column(name = "first_decay")
public double first_decay;
@Expose
@Column(name = "second_decay")
public double second_decay;
@Expose
@Column(name = "first_slope")
public double first_slope;
@Expose
@Column(name = "second_slope")
public double second_slope;
@Expose
@Column(name = "first_intercept")
public double first_intercept;
@Expose
@Column(name = "second_intercept")
public double second_intercept;
@Expose
@Column(name = "first_scale")
public double first_scale;
@Expose
@Column(name = "second_scale")
public double second_scale;
public static void initialCalibration(double bg1, double bg2, Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String unit = prefs.getString("units", "mgdl");
if(unit.compareTo("mgdl") != 0 ) {
bg1 = bg1 * Constants.MMOLL_TO_MGDL;
bg2 = bg2 * Constants.MMOLL_TO_MGDL;
}
clear_all_existing_calibrations();
Calibration higherCalibration = new Calibration();
Calibration lowerCalibration = new Calibration();
Sensor sensor = Sensor.currentSensor();
List bgReadings = BgReading.latest_by_size(2);
BgReading bgReading1 = bgReadings.get(0);
BgReading bgReading2 = bgReadings.get(1);
BgReading highBgReading;
BgReading lowBgReading;
double higher_bg = Math.max(bg1, bg2);
double lower_bg = Math.min(bg1, bg2);
if (bgReading1.raw_data > bgReading2.raw_data) {
highBgReading = bgReading1;
lowBgReading = bgReading2;
} else {
highBgReading = bgReading2;
lowBgReading = bgReading1;
}
higherCalibration.bg = higher_bg;
higherCalibration.slope = 1;
higherCalibration.intercept = higher_bg;
higherCalibration.sensor = sensor;
higherCalibration.estimate_raw_at_time_of_calibration = highBgReading.age_adjusted_raw_value;
higherCalibration.adjusted_raw_value = highBgReading.age_adjusted_raw_value;
higherCalibration.raw_value = highBgReading.raw_data;
higherCalibration.raw_timestamp = highBgReading.timestamp;
higherCalibration.save();
highBgReading.calculated_value = higher_bg;
highBgReading.calibration_flag = true;
highBgReading.calibration = higherCalibration;
highBgReading.save();
higherCalibration.save();
lowerCalibration.bg = lower_bg;
lowerCalibration.slope = 1;
lowerCalibration.intercept = lower_bg;
lowerCalibration.sensor = sensor;
lowerCalibration.estimate_raw_at_time_of_calibration = lowBgReading.age_adjusted_raw_value;
lowerCalibration.adjusted_raw_value = lowBgReading.age_adjusted_raw_value;
lowerCalibration.raw_value = lowBgReading.raw_data;
lowerCalibration.raw_timestamp = lowBgReading.timestamp;
lowerCalibration.save();
lowBgReading.calculated_value = lower_bg;
lowBgReading.calibration_flag = true;
lowBgReading.calibration = lowerCalibration;
lowBgReading.save();
lowerCalibration.save();
highBgReading.find_new_curve();
highBgReading.find_new_raw_curve();
lowBgReading.find_new_curve();
lowBgReading.find_new_raw_curve();
List calibrations = new ArrayList();
calibrations.add(lowerCalibration);
calibrations.add(higherCalibration);
for(Calibration calibration : calibrations) {
calibration.timestamp = new Date().getTime();
calibration.sensor_uuid = sensor.uuid;
calibration.slope_confidence = .5;
calibration.distance_from_estimate = 0;
calibration.check_in = false;
calibration.sensor_confidence = ((-0.0018 * calibration.bg * calibration.bg) + (0.6657 * calibration.bg) + 36.7505) / 100;
calibration.sensor_age_at_time_of_estimation = calibration.timestamp - sensor.started_at;
calibration.uuid = UUID.randomUUID().toString();
calibration.save();
calculate_w_l_s();
CalibrationSendQueue.addToQueue(calibration, context);
}
adjustRecentBgReadings(5);
CalibrationRequest.createOffset(lowerCalibration.bg, 35);
Notifications.notificationSetter(context);
}
//Create Calibration Checkin
public static void create(CalRecord[] calRecords, long addativeOffset, Context context) { create(calRecords, context, false, addativeOffset); }
public static void create(CalRecord[] calRecords, Context context) { create(calRecords, context, false, 0); }
public static void create(CalRecord[] calRecords, Context context, boolean override, long addativeOffset) {
//TODO: Change calibration.last and other queries to order calibrations by timestamp rather than ID
Log.w("CALIBRATION-CHECK-IN: ", "Creating Calibration Record");
Sensor sensor = Sensor.currentSensor();
CalRecord firstCalRecord = calRecords[0];
CalRecord secondCalRecord = calRecords[0];
// CalRecord secondCalRecord = calRecords[calRecords.length - 1];
//TODO: Figgure out how the ratio between the two is determined
double calSlope = ((secondCalRecord.getScale() / secondCalRecord.getSlope()) + (3 * firstCalRecord.getScale() / firstCalRecord.getSlope())) * 250;
double calIntercept = (((secondCalRecord.getScale() * secondCalRecord.getIntercept()) / secondCalRecord.getSlope()) + ((3 * firstCalRecord.getScale() * firstCalRecord.getIntercept()) / firstCalRecord.getSlope())) / -4;
if (sensor != null) {
for(int i = 0; i < firstCalRecord.getCalSubrecords().length - 1; i++) {
if (((firstCalRecord.getCalSubrecords()[i] != null && Calibration.is_new(firstCalRecord.getCalSubrecords()[i], addativeOffset))) || (i == 0 && override)) {
CalSubrecord calSubrecord = firstCalRecord.getCalSubrecords()[i];
Calibration calibration = new Calibration();
calibration.bg = calSubrecord.getCalBGL();
calibration.timestamp = calSubrecord.getDateEntered().getTime() + addativeOffset;
if (calibration.timestamp > new Date().getTime()) {
Log.e(TAG, "ERROR - Calibration timestamp is from the future, wont save!");
return;
}
calibration.raw_value = calSubrecord.getCalRaw() / 1000;
calibration.slope = calSlope;
calibration.intercept = calIntercept;
calibration.sensor_confidence = ((-0.0018 * calibration.bg * calibration.bg) + (0.6657 * calibration.bg) + 36.7505) / 100;
if (calibration.sensor_confidence <= 0) {
calibration.sensor_confidence = 0;
}
calibration.slope_confidence = 0.8; //TODO: query backwards to find this value near the timestamp
calibration.estimate_raw_at_time_of_calibration = calSubrecord.getCalRaw() / 1000;
calibration.sensor = sensor;
calibration.sensor_age_at_time_of_estimation = calibration.timestamp - sensor.started_at;
calibration.uuid = UUID.randomUUID().toString();
calibration.sensor_uuid = sensor.uuid;
calibration.check_in = true;
calibration.first_decay = firstCalRecord.getDecay();
calibration.second_decay = secondCalRecord.getDecay();
calibration.first_slope = firstCalRecord.getSlope();
calibration.second_slope = secondCalRecord.getSlope();
calibration.first_scale = firstCalRecord.getScale();
calibration.second_scale = secondCalRecord.getScale();
calibration.first_intercept = firstCalRecord.getIntercept();
calibration.second_intercept = secondCalRecord.getIntercept();
calibration.save();
CalibrationSendQueue.addToQueue(calibration, context);
Calibration.requestCalibrationIfRangeTooNarrow();
}
}
if(firstCalRecord.getCalSubrecords()[0] != null && firstCalRecord.getCalSubrecords()[2] == null) {
if(Calibration.latest(2).size() == 1) {
Calibration.create(calRecords, context, true, 0);
}
}
Notifications.notificationSetter(context);
}
}
public static boolean is_new(CalSubrecord calSubrecord, long addativeOffset) {
Sensor sensor = Sensor.currentSensor();
Calibration calibration = new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("timestamp <= ?", calSubrecord.getDateEntered().getTime() + addativeOffset + (1000 * 60 * 2))
.orderBy("timestamp desc")
.executeSingle();
if(calibration != null && Math.abs(calibration.timestamp - (calSubrecord.getDateEntered().getTime() + addativeOffset)) < (4*60*1000)) {
Log.d("CAL CHECK IN ", "Already have that calibration!");
return false;
} else {
Log.d("CAL CHECK IN ", "Looks like a new calibration!");
return true;
}
}
public static Calibration getForTimestamp(double timestamp) {
Sensor sensor = Sensor.currentSensor();
return new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.where("timestamp < ?", timestamp)
.orderBy("timestamp desc")
.executeSingle();
}
public static Calibration create(double bg, Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String unit = prefs.getString("units", "mgdl");
if(unit.compareTo("mgdl") != 0 ) {
bg = bg * Constants.MMOLL_TO_MGDL;
}
CalibrationRequest.clearAll();
Calibration calibration = new Calibration();
Sensor sensor = Sensor.currentSensor();
if (sensor != null) {
BgReading bgReading = BgReading.last();
if (bgReading != null) {
calibration.sensor = sensor;
calibration.bg = bg;
calibration.check_in = false;
calibration.timestamp = new Date().getTime();
calibration.raw_value = bgReading.raw_data;
calibration.adjusted_raw_value = bgReading.age_adjusted_raw_value;
calibration.sensor_uuid = sensor.uuid;
calibration.slope_confidence = Math.min(Math.max(((4 - Math.abs((bgReading.calculated_value_slope) * 60000))/4), 0), 1);
double estimated_raw_bg = BgReading.estimated_raw_bg(new Date().getTime());
calibration.raw_timestamp = bgReading.timestamp;
if (Math.abs(estimated_raw_bg - bgReading.age_adjusted_raw_value) > 20) {
calibration.estimate_raw_at_time_of_calibration = bgReading.age_adjusted_raw_value;
} else {
calibration.estimate_raw_at_time_of_calibration = estimated_raw_bg;
}
calibration.distance_from_estimate = Math.abs(calibration.bg - bgReading.calculated_value);
calibration.sensor_confidence = Math.max(((-0.0018 * bg * bg) + (0.6657 * bg) + 36.7505) / 100, 0);
calibration.sensor_age_at_time_of_estimation = calibration.timestamp - sensor.started_at;
calibration.uuid = UUID.randomUUID().toString();
calibration.save();
bgReading.calibration = calibration;
bgReading.calibration_flag = true;
bgReading.save();
BgSendQueue.addToQueue(bgReading, "update", context);
calculate_w_l_s();
adjustRecentBgReadings();
CalibrationSendQueue.addToQueue(calibration, context);
Notifications.notificationSetter(context);
Calibration.requestCalibrationIfRangeTooNarrow();
}
} else {
Log.w("CALIBRATION", "No sensor, cant save!");
}
return Calibration.last();
}
public static List allForSensorInLastFiveDays() {
Sensor sensor = Sensor.currentSensor();
if (sensor == null) { return null; }
return new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.where("timestamp > ?", (new Date().getTime() - (60000 * 60 * 24 * 5)))
.orderBy("timestamp desc")
.execute();
}
public static void calculate_w_l_s() {
if (Sensor.isActive()) {
double l = 0;
double m = 0;
double n = 0;
double p = 0;
double q = 0;
double w;
List calibrations = allForSensorInLastFourDays(); //5 days was a bit much, dropped this to 4
if (calibrations.size() == 1) {
Calibration calibration = Calibration.last();
calibration.slope = 1;
calibration.intercept = calibration.bg - (calibration.raw_value * calibration.slope);
calibration.save();
} else {
for (Calibration calibration : calibrations) {
w = calibration.calculateWeight();
l += (w);
m += (w * calibration.estimate_raw_at_time_of_calibration);
n += (w * calibration.estimate_raw_at_time_of_calibration * calibration.estimate_raw_at_time_of_calibration);
p += (w * calibration.bg);
q += (w * calibration.estimate_raw_at_time_of_calibration * calibration.bg);
}
Calibration last_calibration = Calibration.last();
w = (last_calibration.calculateWeight() * (calibrations.size() * 0.14));
l += (w);
m += (w * last_calibration.estimate_raw_at_time_of_calibration);
n += (w * last_calibration.estimate_raw_at_time_of_calibration * last_calibration.estimate_raw_at_time_of_calibration);
p += (w * last_calibration.bg);
q += (w * last_calibration.estimate_raw_at_time_of_calibration * last_calibration.bg);
double d = (l * n) - (m * m);
Calibration calibration = Calibration.last();
calibration.intercept = ((n * p) - (m * q)) / d;
calibration.slope = ((l * q) - (m * p)) / d;
if ((calibrations.size() == 2 && calibration.slope < 0.95) || (calibration.slope < 0.85)) { // I have not seen a case where a value below 7.5 proved to be accurate but we should keep an eye on this
calibration.slope = calibration.slopeOOBHandler(0);
if(calibrations.size() > 2) { calibration.possible_bad = true; }
calibration.intercept = calibration.bg - (calibration.estimate_raw_at_time_of_calibration * calibration.slope);
CalibrationRequest.createOffset(calibration.bg, 25);
}
if ((calibrations.size() == 2 && calibration.slope > 1.3) || (calibration.slope > 1.4)) {
calibration.slope = calibration.slopeOOBHandler(1);
if(calibrations.size() > 2) { calibration.possible_bad = true; }
calibration.intercept = calibration.bg - (calibration.estimate_raw_at_time_of_calibration * calibration.slope);
CalibrationRequest.createOffset(calibration.bg, 25);
}
Log.d(TAG, "Calculated Calibration Slope: " + calibration.slope);
Log.d(TAG, "Calculated Calibration intercept: " + calibration.intercept);
calibration.save();
}
} else {
Log.w(TAG, "NO Current active sensor found!!");
}
}
private double slopeOOBHandler(int status) {
// If the last slope was reasonable and reasonably close, use that, otherwise use a slope that may be a little steep, but its best to play it safe when uncertain
List calibrations = Calibration.latest(3);
Calibration thisCalibration = calibrations.get(0);
if(status == 0) {
if (calibrations.size() == 3) {
if ((Math.abs(thisCalibration.bg - thisCalibration.estimate_bg_at_time_of_calibration) < 30) && (calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad == true)) {
return calibrations.get(1).slope;
} else {
return Math.max(((-0.048) * (thisCalibration.sensor_age_at_time_of_estimation / (60000 * 60 * 24))) + 1.1, 1.08);
}
} else if (calibrations.size() == 2) {
return Math.max(((-0.048) * (thisCalibration.sensor_age_at_time_of_estimation / (60000 * 60 * 24))) + 1.1, 1.15);
}
return 1;
} else {
if (calibrations.size() == 3) {
if ((Math.abs(thisCalibration.bg - thisCalibration.estimate_bg_at_time_of_calibration) < 30) && (calibrations.get(1).possible_bad != null && calibrations.get(1).possible_bad == true)) {
return calibrations.get(1).slope;
} else {
return 1.3;
}
} else if (calibrations.size() == 2) {
return 1.2;
}
}
return 1;
}
private static List calibrations_for_sensor(Sensor sensor) {
return new Select()
.from(Calibration.class)
.where("Sensor = ?", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.orderBy("timestamp desc")
.execute();
}
private double calculateWeight() {
double firstTimeStarted = Calibration.first().sensor_age_at_time_of_estimation;
double lastTimeStarted = Calibration.last().sensor_age_at_time_of_estimation;
double time_percentage = Math.min(((sensor_age_at_time_of_estimation - firstTimeStarted) / (lastTimeStarted - firstTimeStarted)) / (.85), 1);
time_percentage = (time_percentage + .01);
Log.w(TAG, "CALIBRATIONS TIME PERCENTAGE WEIGHT: " + time_percentage);
return Math.max((((((slope_confidence + sensor_confidence) * (time_percentage))) / 2) * 100), 1);
}
public static void adjustRecentBgReadings() {// This just adjust the last 30 bg readings transition from one calibration point to the next
adjustRecentBgReadings(30);
}
public static void adjustRecentBgReadings(int adjustCount) {
//TODO: add some handling around calibration overrides as they come out looking a bit funky
List calibrations = Calibration.latest(3);
List bgReadings = BgReading.latestUnCalculated(adjustCount);
if (calibrations.size() == 3) {
int denom = bgReadings.size();
Calibration latestCalibration = calibrations.get(0);
int i = 0;
for (BgReading bgReading : bgReadings) {
double oldYValue = bgReading.calculated_value;
double newYvalue = (bgReading.age_adjusted_raw_value * latestCalibration.slope) + latestCalibration.intercept;
bgReading.calculated_value = ((newYvalue * (denom - i)) + (oldYValue * ( i ))) / denom;
bgReading.save();
i += 1;
}
} else if (calibrations.size() == 2) {
Calibration latestCalibration = calibrations.get(0);
for (BgReading bgReading : bgReadings) {
double newYvalue = (bgReading.age_adjusted_raw_value * latestCalibration.slope) + latestCalibration.intercept;
bgReading.calculated_value = newYvalue;
bgReading.save();
}
}
bgReadings.get(0).find_new_raw_curve();
bgReadings.get(0).find_new_curve();
}
public void rawValueOverride(double rawValue, Context context) {
estimate_raw_at_time_of_calibration = rawValue;
save();
calculate_w_l_s();
CalibrationSendQueue.addToQueue(this, context);
}
public static void requestCalibrationIfRangeTooNarrow() {
double max = Calibration.max_recent();
double min = Calibration.min_recent();
if ((max - min) < 55) {
double avg = ((min + max) / 2);
double dist = max - avg;
CalibrationRequest.createOffset(avg, dist + 20);
}
}
public static void clear_all_existing_calibrations() {
CalibrationRequest.clearAll();
List pastCalibrations = Calibration.allForSensor();
if (pastCalibrations != null) {
for(Calibration calibration : pastCalibrations){
calibration.slope_confidence = 0;
calibration.sensor_confidence = 0;
calibration.save();
}
}
}
public String toS() {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.serializeSpecialFloatingPointValues()
.create();
return gson.toJson(this);
}
//COMMON SCOPES!
public static Calibration last() {
Sensor sensor = Sensor.currentSensor();
return new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.orderBy("timestamp desc")
.executeSingle();
}
public static Calibration first() {
Sensor sensor = Sensor.currentSensor();
return new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.orderBy("timestamp asc")
.executeSingle();
}
public static double max_recent() {
Sensor sensor = Sensor.currentSensor();
Calibration calibration = new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.where("timestamp > ?", (new Date().getTime() - (60000 * 60 * 24 * 4)))
.orderBy("bg desc")
.executeSingle();
if(calibration != null) {
return calibration.bg;
} else {
return 120;
}
}
public static double min_recent() {
Sensor sensor = Sensor.currentSensor();
Calibration calibration = new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.where("timestamp > ?", (new Date().getTime() - (60000 * 60 * 24 * 4)))
.orderBy("bg asc")
.executeSingle();
if(calibration != null) {
return calibration.bg;
} else {
return 100;
}
}
public static List latest(int number) {
Sensor sensor = Sensor.currentSensor();
if (sensor == null) { return null; }
return new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.orderBy("timestamp desc")
.limit(number)
.execute();
}
public static List allForSensor() {
Sensor sensor = Sensor.currentSensor();
if (sensor == null) { return null; }
return new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.orderBy("timestamp desc")
.execute();
}
public static List allForSensorInLastFourDays() {
Sensor sensor = Sensor.currentSensor();
if (sensor == null) { return null; }
return new Select()
.from(Calibration.class)
.where("Sensor = ? ", sensor.getId())
.where("slope_confidence != 0")
.where("sensor_confidence != 0")
.where("timestamp > ?", (new Date().getTime() - (60000 * 60 * 24 * 4)))
.orderBy("timestamp desc")
.execute();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Models/CalibrationRequest.java
================================================
package com.eveningoutpost.dexdrip.Models;
import android.provider.BaseColumns;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import java.util.List;
/**
* Created by stephenblack on 12/9/14.
*/
@Table(name = "CalibrationRequest", id = BaseColumns._ID)
public class CalibrationRequest extends Model {
private static final int max = 250;
private static final int min = 70;
@Column(name = "requestIfAbove")
public double requestIfAbove;
@Column(name = "requestIfBelow")
public double requestIfBelow;
public static void createRange(double low, double high) {
CalibrationRequest calibrationRequest = new CalibrationRequest();
calibrationRequest.requestIfAbove = low;
calibrationRequest.requestIfBelow = high;
calibrationRequest.save();
}
public static void createOffset(double center, double distance) {
CalibrationRequest calibrationRequest = new CalibrationRequest();
calibrationRequest.requestIfAbove = center + distance;
calibrationRequest.requestIfBelow = max;
calibrationRequest.save();
calibrationRequest.requestIfAbove = min;
calibrationRequest.requestIfBelow = center - distance;
calibrationRequest.save();
}
public static void clearAll(){
List calibrationRequests = new Select()
.from(CalibrationRequest.class)
.execute();
if (calibrationRequests.size() >=1) {
for (CalibrationRequest calibrationRequest : calibrationRequests) {
calibrationRequest.delete();
}
}
}
public static boolean shouldRequestCalibration(BgReading bgReading){
CalibrationRequest calibrationRequest = new Select()
.from(CalibrationRequest.class)
.where("requestIfAbove < ?", bgReading.calculated_value)
.where("requestIfBelow > ?", bgReading.calculated_value)
.executeSingle();
if (calibrationRequest != null && Math.abs(bgReading.calculated_value_slope * 60000) < 1.8) {
return true;
} else {
return false;
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Models/TransmitterData.java
================================================
package com.eveningoutpost.dexdrip.Models;
import android.provider.BaseColumns;
import android.util.Log;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import java.util.Date;
import java.util.UUID;
/**
* Created by stephenblack on 11/6/14.
*/
@Table(name = "TransmitterData", id = BaseColumns._ID)
public class TransmitterData extends Model {
private final static String TAG = BgReading.class.getSimpleName();
@Column(name = "timestamp", index = true)
public long timestamp;
@Column(name = "raw_data")
public double raw_data;
//
// @Column(name = "filtered_data")
// public double filtered_data;
@Column(name = "sensor_battery_level")
public int sensor_battery_level;
@Column(name = "uuid", index = true)
public String uuid;
public static TransmitterData create(byte[] buffer, int len, Long timestamp) {
StringBuilder data_string = new StringBuilder();
if (len < 6) { return null; };
for (int i = 0; i < len; ++i) {
data_string.append((char) buffer[i]);
}
String[] data = data_string.toString().split("\\s+");
randomDelay(100, 2000);
TransmitterData lastTransmitterData = TransmitterData.last();
if (lastTransmitterData != null && lastTransmitterData.raw_data == Integer.parseInt(data[0]) && Math.abs(lastTransmitterData.timestamp - timestamp) < (10000)) { //Stop allowing duplicate data, its bad!
return null;
}
TransmitterData transmitterData = new TransmitterData();
if(data.length > 1) {
transmitterData.sensor_battery_level = Integer.parseInt(data[1]);
}
if (Integer.parseInt(data[0]) < 1000) { return null; } // Sometimes the HM10 sends the battery level and readings in separate transmissions, filter out these incomplete packets!
transmitterData.raw_data = Integer.parseInt(data[0]);
transmitterData.timestamp = timestamp;
transmitterData.uuid = UUID.randomUUID().toString();
transmitterData.save();
return transmitterData;
}
public static TransmitterData create(int raw_data ,int sensor_battery_level, long timestamp) {
randomDelay(100, 2000);
TransmitterData lastTransmitterData = TransmitterData.last();
if (lastTransmitterData != null && lastTransmitterData.raw_data == raw_data && Math.abs(lastTransmitterData.timestamp - new Date().getTime()) < (10000)) { //Stop allowing duplicate data, its bad!
return null;
}
TransmitterData transmitterData = new TransmitterData();
transmitterData.sensor_battery_level = sensor_battery_level;
transmitterData.raw_data = raw_data ;
transmitterData.timestamp = timestamp;
transmitterData.uuid = UUID.randomUUID().toString();
transmitterData.save();
return transmitterData;
}
public static TransmitterData last() {
return new Select()
.from(TransmitterData.class)
.orderBy("_ID desc")
.executeSingle();
}
public static void randomDelay(float min, float max){
int random = (int)(max * Math.random() + min);
try {
Log.d("Sleeping ", "for " + random + "ms");
Thread.sleep(random);
} catch (InterruptedException e) {
Log.e("Random Delay ", "INTERUPTED");
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Models/User.java
================================================
package com.eveningoutpost.dexdrip.Models;
import android.provider.BaseColumns;
import android.util.Log;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.Interfaces.UserInterface;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.annotations.Expose;
import com.google.gson.internal.bind.DateTypeAdapter;
import java.util.Date;
import retrofit.Callback;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;
import retrofit.converter.GsonConverter;
/**
* Created by stephenblack on 11/7/14.
*/
@Table(name = "User", id = BaseColumns._ID)
public class User extends Model {
private static final String baseUrl = "http://10.0.2.2:3000";
public static Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.create();
@Expose
@Column(name = "email")
public String email;
@Expose
@Column(name = "password")
public String password;
@Expose
@Column(name = "token")
public String token;
@Expose
@Column(name = "token_expiration")
public double token_expiration;
@Expose
@Column(name = "uuid", index = true)
public String uuid;
public static User currentUser() {
User user = new Select()
.from(User.class)
.orderBy("_ID desc")
.limit(1)
.executeSingle();
return user;
}
//TODO: Add refresh token attempt instance method!!
public static void authenticate() {
final User user = User.currentUser();
userInterface().authenticate(user, new Callback() {
@Override
public void success(String gsonResponse, Response response) {
JsonObject jobj = new Gson().fromJson(gsonResponse, JsonObject.class);
user.token = jobj.get("token").getAsString();
user.token_expiration = jobj.get("expiration").getAsDouble();
user.save();
}
@Override
public void failure(RetrofitError error) {
Response response = error.getResponse();
Log.w("REST CALL ERROR:", "****************");
Log.w("REST CALL STATUS:", "" + response.getStatus());
Log.w("REST CALL REASON:", response.getReason());
}
}
);
}
public static UserInterface userInterface() {
RestAdapter adapter = adapterBuilder().build();
UserInterface userInterface =
adapter.create(UserInterface.class);
return userInterface();
}
public static RestAdapter.Builder adapterBuilder() {
RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();
adapterBuilder
.setEndpoint(baseUrl)
.setConverter(new GsonConverter(gson));
return adapterBuilder;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Models/UserNotification.java
================================================
package com.eveningoutpost.dexdrip.Models;
import android.provider.BaseColumns;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import java.util.Date;
/**
* Created by stephenblack on 11/29/14.
*/
@Table(name = "Notifications", id = BaseColumns._ID)
public class UserNotification extends Model {
@Column(name = "timestamp", index = true)
public double timestamp;
@Column(name = "message")
public String message;
@Column(name = "bg_alert")
public boolean bg_alert;
@Column(name = "calibration_alert")
public boolean calibration_alert;
@Column(name = "double_calibration_alert")
public boolean double_calibration_alert;
@Column(name = "extra_calibration_alert")
public boolean extra_calibration_alert;
public static UserNotification lastBgAlert() {
return new Select()
.from(UserNotification.class)
.where("bg_alert = ?", true)
.orderBy("_ID desc")
.executeSingle();
}
public static UserNotification lastCalibrationAlert() {
return new Select()
.from(UserNotification.class)
.where("calibration_alert = ?", true)
.orderBy("_ID desc")
.executeSingle();
}
public static UserNotification lastDoubleCalibrationAlert() {
return new Select()
.from(UserNotification.class)
.where("double_calibration_alert = ?", true)
.orderBy("_ID desc")
.executeSingle();
}
public static UserNotification lastExtraCalibrationAlert() {
return new Select()
.from(UserNotification.class)
.where("extra_calibration_alert = ?", true)
.orderBy("_ID desc")
.executeSingle();
}
public static UserNotification create(String message, String type) {
UserNotification userNotification = new UserNotification();
userNotification.timestamp = new Date().getTime();
userNotification.message = message;
if (type == "bg_alert") {
userNotification.bg_alert = true;
} else if (type == "calibration_alert") {
userNotification.calibration_alert = true;
} else if (type == "double_calibration_alert") {
userNotification.double_calibration_alert = true;
} else if (type == "extra_calibration_alert") {
userNotification.extra_calibration_alert = true;
}
userNotification.save();
return userNotification;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/NavDrawerBuilder.java
================================================
package com.eveningoutpost.dexdrip;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.Preference;
import android.preference.PreferenceManager;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.Tables.BgReadingTable;
import com.eveningoutpost.dexdrip.Tables.CalibrationDataTable;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.utils.Preferences;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created by stephenblack on 11/5/14.
*/
public class NavDrawerBuilder {
public final List last_two_calibrations = Calibration.latest(2);
public final List last_two_bgReadings = BgReading.latestUnCalculated(2);
public final List bGreadings_in_last_30_mins = BgReading.last30Minutes();
public final boolean is_active_sensor = Sensor.isActive();
public final double time_now = new Date().getTime();
public List nav_drawer_intents;
public List nav_drawer_options;
public Context context;
public NavDrawerBuilder(Context aContext) {
context = aContext;
this.nav_drawer_intents = nav_drawer_intents();
this.nav_drawer_options = nav_drawer_options();
}
private final List nav_drawer_options() {
List options = new ArrayList();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean IUnderstand = prefs.getBoolean("I_understand", false);
if(IUnderstand == false) {
options.add("Settings");
return options;
}
options.add("xDrip");
if(is_active_sensor) {
options.add("Calibration Graph");
}
options.add("BG Data Table");
options.add("Calibration Data Table");
// options.add("Sensor Data Table");
if(is_active_sensor) {
if(!CollectionServiceStarter.isBTShare(context)) {
if (last_two_bgReadings.size() > 1) {
if (last_two_calibrations.size() > 1) {
if (bGreadings_in_last_30_mins.size() >= 2) {
if (time_now - last_two_calibrations.get(0).timestamp < (1000 * 60 * 60)) { //Put steps in place to discourage over calibration
options.add("Override Calibration");
} else {
options.add("Add Calibration");
}
} else {
options.add("Cannot Calibrate right now");
}
if (last_two_calibrations.get(0).slope >= 1.4 || last_two_calibrations.get(0).slope <= 0.5) {
options.add("Add Double Calibration");
}
} else {
options.add("Add Double Calibration");
}
}
}
options.add("Stop Sensor");
} else { options.add("Start Sensor"); }
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
if(CollectionServiceStarter.isBTWixel(context) || CollectionServiceStarter.isBTShare(context)) {
options.add("Scan for BT");
}
}
options.add("System Status");
options.add("Settings");
// options.add("Fake Numbers");
// options.add("Add Double Calibration");
// options.add("Share Test");
return options;
}
private List nav_drawer_intents() {
List options = new ArrayList();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean IUnderstand = prefs.getBoolean("I_understand", false);
if(IUnderstand == false) {
options.add(new Intent(context, SettingsActivity.class));
return options;
}
options.add(new Intent(context, Home.class));
if(is_active_sensor) {
options.add(new Intent(context, CalibrationGraph.class));
}
options.add(new Intent(context, BgReadingTable.class));
options.add(new Intent(context, CalibrationDataTable.class));
// options.add(new Intent(context, SensorDataTable.class));
if(is_active_sensor) {
if(!CollectionServiceStarter.isBTShare(context)) {
if (last_two_bgReadings.size() > 1) {
if (last_two_calibrations.size() > 1) {
if (bGreadings_in_last_30_mins.size() >= 2) {
if (time_now - last_two_calibrations.get(0).timestamp < (1000 * 60 * 60)) { //Put steps in place to discourage over calibration
options.add(new Intent(context, CalibrationOverride.class));
} else {
options.add(new Intent(context, AddCalibration.class));
}
} else {
options.add(new Intent(context, Home.class));
}
if (last_two_calibrations.get(0).slope >= 1.4 || last_two_calibrations.get(0).slope <= 0.5) {
options.add(new Intent(context, DoubleCalibrationActivity.class));
}
} else {
options.add(new Intent(context, DoubleCalibrationActivity.class));
}
}
}
options.add(new Intent(context, StopSensor.class));
} else { options.add(new Intent(context, StartNewSensor.class)); }
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
if(CollectionServiceStarter.isBTWixel(context) || CollectionServiceStarter.isBTShare(context)) {
options.add(new Intent(context, BluetoothScan.class));
}
}
options.add(new Intent(context, SystemStatus.class));
// options.add(new Intent(context, SettingsActivity.class));
options.add(new Intent(context, Preferences.class));
// options.add(new Intent(context, FakeNumbers.class));
// options.add(new Intent(context, DoubleCalibrationActivity.class));
// options.add(new Intent(context, ShareTest.class));
return options;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/NavigationDrawerFragment.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.List;
public class NavigationDrawerFragment extends Fragment {
private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
private NavigationDrawerCallbacks mCallbacks;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private ListView mDrawerListView;
private View mFragmentContainerView;
private int mCurrentSelectedPosition = 0;
private boolean mFromSavedInstanceState;
private boolean mUserLearnedDrawer;
private String menu_name;
public NavDrawerBuilder navDrawerBuilder;
private int menu_position;
private List menu_option_list;
private List intent_list;
public NavigationDrawerFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
if (savedInstanceState != null) {
mCurrentSelectedPosition = 0;
mFromSavedInstanceState = true;
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mDrawerListView = (ListView) inflater.inflate(
R.layout.fragment_navigation_drawer, container, false);
mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
selectItem(position);
}
});
navDrawerBuilder = new NavDrawerBuilder(getActivity());
List menu_option_list = navDrawerBuilder.nav_drawer_options;
String[] menu_options = menu_option_list.toArray(new String[menu_option_list.size()]);
mDrawerListView.setAdapter(new ArrayAdapter(
getActionBar().getThemedContext(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
menu_options
));
return mDrawerListView;
}
public boolean isDrawerOpen() {
return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
}
public void setUp(int fragmentId, DrawerLayout drawerLayout, String current_activity, Context context) {
navDrawerBuilder = new NavDrawerBuilder(context);
menu_name = current_activity;
menu_option_list = navDrawerBuilder.nav_drawer_options;
String[] menu_options = menu_option_list.toArray(new String[menu_option_list.size()]);
menu_position = menu_option_list.indexOf(menu_name);
intent_list = navDrawerBuilder.nav_drawer_intents;
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
mCurrentSelectedPosition = menu_position;
mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
// mDrawerListView = (ListView) inflater.inflate(
// R.layout.fragment_navigation_drawer, container, false);
// mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
// @Override
// public void onItemClick(AdapterView> parent, View view, int position, long id) {
// selectItem(position);
// }
// });
// navDrawerBuilder = new NavDrawerBuilder();
// List menu_option_list = navDrawerBuilder.nav_drawer_options();
// String[] menu_options = menu_option_list.toArray(new String[menu_option_list.size()]);
mDrawerListView.setAdapter(new ArrayAdapter(
getActionBar().getThemedContext(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
menu_options
));
mDrawerToggle = new ActionBarDrawerToggle(
getActivity(),
mDrawerLayout,
R.drawable.ic_drawer,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
) {
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
}
getActivity().invalidateOptionsMenu();
}
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
}
if (!mUserLearnedDrawer) {
mUserLearnedDrawer = true;
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
}
getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
};
if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
mDrawerLayout.openDrawer(mFragmentContainerView);
}
mDrawerLayout.post(new Runnable() {
@Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
private void selectItem(int position) {
mCurrentSelectedPosition = position;
if (mDrawerListView != null) {
mDrawerListView.setItemChecked(position, true);
}
if (mDrawerLayout != null) {
mDrawerLayout.closeDrawer(mFragmentContainerView);
}
if (mCallbacks != null) {
mCallbacks.onNavigationDrawerItemSelected(position);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallbacks = (NavigationDrawerCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
}
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (mDrawerLayout != null && isDrawerOpen()) {
inflater.inflate(R.menu.global, menu);
showGlobalContextActionBar();
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void showGlobalContextActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(R.string.app_name);
}
private ActionBar getActionBar() {
return getActivity().getActionBar();
}
public static interface NavigationDrawerCallbacks {
void onNavigationDrawerItemSelected(int position);
}
public void swapContext(int position) {
if (position != menu_position) {
Intent[] intent_array = intent_list.toArray(new Intent[intent_list.size()]);
startActivity(intent_array[position]);
if(menu_position != 0) {
getActivity().finish();
}
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Sensor.java
================================================
package com.eveningoutpost.dexdrip;
import android.provider.BaseColumns;
import android.util.Log;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.UtilityModels.SensorSendQueue;
import java.util.UUID;
/**
* Created by stephenblack on 10/29/14.
*/
@Table(name = "Sensors", id = BaseColumns._ID)
public class Sensor extends Model {
// @Expose
@Column(name = "started_at", index = true)
public double started_at;
// @Expose
@Column(name = "stopped_at")
public double stopped_at;
// @Expose
@Column(name = "latest_battery_level")
public int latest_battery_level;
// @Expose
@Column(name = "uuid", index = true)
public String uuid;
public static Sensor create(double started_at) {
Sensor sensor = new Sensor();
sensor.started_at = started_at;
sensor.uuid = UUID.randomUUID().toString();
sensor.save();
SensorSendQueue.addToQueue(sensor);
Log.w("SENSOR MODEL:", sensor.toString());
return sensor;
}
public static Sensor currentSensor() {
Sensor sensor = new Select()
.from(Sensor.class)
.where("started_at != 0")
.where("stopped_at = 0")
.orderBy("_ID desc")
.limit(1)
.executeSingle();
return sensor;
}
public static boolean isActive() {
Sensor sensor = new Select()
.from(Sensor.class)
.where("started_at != 0")
.where("stopped_at = 0")
.orderBy("_ID desc")
.limit(1)
.executeSingle();
if(sensor == null) {
return false;
} else {
return true;
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Services/ComunicationHeader.java
================================================
package com.eveningoutpost.dexdrip.Services;
import java.io.Serializable;
import com.google.gson.annotations.Expose;
// This is a struct that is supsoed to tell the protocol version and is the first that the client is sending
// The complete protocol is:
// 1) the client connects
// 2) send this message.
// 3) the server will send numberOfRecords of type ???? that it has.
public class ComunicationHeader {
/**
*
*/
int version;
int numberOfRecords;
// String message;
// byte reserved[];
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Services/DexCollectionService.java
================================================
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.eveningoutpost.dexdrip.Services;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Sensor;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.HM10Attributes;
import com.eveningoutpost.dexdrip.Models.TransmitterData;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
@TargetApi(Build.VERSION_CODES.KITKAT)
public class DexCollectionService extends Service {
private final static String TAG = DexCollectionService.class.getSimpleName();
private String mDeviceName;
private String mDeviceAddress;
private boolean is_connected = false;
SharedPreferences prefs;
public DexCollectionService dexCollectionService;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private ForegroundServiceStarter foregroundServiceStarter;
private int mConnectionState = STATE_DISCONNECTED;
private BluetoothDevice device;
private Context mContext = null;
private static final int STATE_DISCONNECTED = BluetoothProfile.STATE_DISCONNECTED;
private static final int STATE_DISCONNECTING = BluetoothProfile.STATE_DISCONNECTING;
private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING;
private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED;
public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static UUID xDripDataService = UUID.fromString(HM10Attributes.HM_10_SERVICE);
public final static UUID xDripDataCharacteristic = UUID.fromString(HM10Attributes.HM_RX_TX);
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), this);
foregroundServiceStarter.start();
mContext = getApplicationContext();
dexCollectionService = this;
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
listenForChangeInSettings();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){
stopSelf();
return START_NOT_STICKY;
}
if (CollectionServiceStarter.isBTWixel(getApplicationContext())) {
setFailoverTimer();
} else {
stopSelf();
return START_NOT_STICKY;
}
attemptConnection();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
close();
foregroundServiceStarter.stop();
setRetryTimer();
Log.w(TAG, "SERVICE STOPPED");
}
public SharedPreferences.OnSharedPreferenceChangeListener prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if(key.compareTo("run_service_in_foreground") == 0) {
Log.e("FOREGROUND", "run_service_in_foreground changed!");
if (prefs.getBoolean("run_service_in_foreground", false)) {
foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), dexCollectionService);
foregroundServiceStarter.start();
Log.w(TAG, "Moving to foreground");
} else {
dexCollectionService.stopForeground(true);
Log.w(TAG, "Removing from foreground");
}
}
}
};
public void listenForChangeInSettings() {
prefs.registerOnSharedPreferenceChangeListener(prefListener);
}
public void setRetryTimer() {
if (CollectionServiceStarter.isBTWixel(getApplicationContext())) {
long retry_in = (1000 * 60 * 2);
Log.d(TAG, "Restarting in: " + (retry_in / (60 * 1000)) + " minutes");
Calendar calendar = Calendar.getInstance();
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
alarm.setExact(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexCollectionService.class), 0));
}
}
public void setFailoverTimer() { //Sometimes it gets stuck in limbo on 4.4, this should make it try again
if (CollectionServiceStarter.isBTWixel(getApplicationContext())) {
long retry_in = (1000 * 60 * 5);
Log.d(TAG, "Fallover Restarting in: " + (retry_in / (60 * 1000)) + " minutes");
Calendar calendar = Calendar.getInstance();
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexCollectionService.class), 0));
} else {
stopSelf();
}
}
public void attemptConnection() {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter != null) {
if (device != null) {
mConnectionState = STATE_DISCONNECTED;
for (BluetoothDevice bluetoothDevice : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {
if (bluetoothDevice.getAddress().compareTo(device.getAddress()) == 0) {
mConnectionState = STATE_CONNECTED;
}
}
}
Log.w(TAG, "Connection state: " + mConnectionState);
if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_DISCONNECTING) {
ActiveBluetoothDevice btDevice = ActiveBluetoothDevice.first();
if (btDevice != null) {
mDeviceName = btDevice.name;
mDeviceAddress = btDevice.address;
if (mBluetoothAdapter.isEnabled() && mBluetoothAdapter.getRemoteDevice(mDeviceAddress) != null) {
connect(mDeviceAddress);
return;
}
}
} else if (mConnectionState == STATE_CONNECTED) { //WOOO, we are good to go, nothing to do here!
Log.w(TAG, "Looks like we are already connected, going to read!");
return;
}
}
}
setRetryTimer();
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
ActiveBluetoothDevice.connected();
Log.w(TAG, "Connected to GATT server.");
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
ActiveBluetoothDevice.disconnected();
Log.w(TAG, "Disconnected from GATT server.");
setRetryTimer();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService gattService = mBluetoothGatt.getService(xDripDataService);
if (gattService != null) {
BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(xDripDataCharacteristic);
if (gattCharacteristic != null ) {
final int charaProp = gattCharacteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
} else {
Log.e(TAG, "characteristic " + gattCharacteristic.getUuid() + " doesn't have notify properties");
}
} else {
Log.e(TAG, "characteristic " + xDripDataCharacteristic + " not found");
}
} else {
Log.e(TAG, "service " + xDripDataCharacteristic + " not found");
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) { setSerialDataToTransmitterRawData(data, data.length); }
}
};
public boolean connect(final String address) {
Log.w(TAG, "going to connect to device at address" + address);
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
setRetryTimer();
return false;
}
if (mBluetoothGatt != null) {
Log.w(TAG, "BGatt isnt null, Closing.");
mBluetoothGatt.close();
mBluetoothGatt = null;
}
device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
setRetryTimer();
return false;
}
Log.w(TAG, "Trying to create a new connection.");
mBluetoothGatt = device.connectGatt(getApplicationContext(), true, mGattCallback);
mConnectionState = STATE_CONNECTING;
return true;
}
public void disconnect() {
if ( mBluetoothGatt == null) { return; }
mBluetoothGatt.disconnect();
Log.d(TAG, "Gatt Disconnect");
}
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
setRetryTimer();
mBluetoothGatt = null;
mConnectionState = STATE_DISCONNECTED;
}
public void setSerialDataToTransmitterRawData(byte[] buffer, int len) {
Log.w(TAG, "received some data!");
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"ReceivedReading");
wakeLock.acquire();
Long timestamp = new Date().getTime();
TransmitterData transmitterData = TransmitterData.create(buffer, len, timestamp);
if (transmitterData != null) {
Sensor sensor = Sensor.currentSensor();
if (sensor != null) {
sensor.latest_battery_level = transmitterData.sensor_battery_level;
sensor.save();
BgReading.create(transmitterData.raw_data, this, timestamp);
} else {
Log.w(TAG, "No Active Sensor, Data only stored in Transmitter Data");
}
}
wakeLock.release();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Services/DexShareCollectionService.java
================================================
package com.eveningoutpost.dexdrip.Services;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadDataShare;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.Sensor;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.DexShareAttributes;
import com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.HM10Attributes;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
import rx.Observable;
import rx.functions.Action1;
@TargetApi(Build.VERSION_CODES.KITKAT)
public class DexShareCollectionService extends Service {
private final static String TAG = DexShareCollectionService.class.getSimpleName();
private ForegroundServiceStarter foregroundServiceStarter;
private String mDeviceAddress;
private String mDeviceName;
private boolean is_connected = false;
private boolean reconnecting = false;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
private String mBluetoothDeviceAddress;
private int mConnectionState = STATE_DISCONNECTED;
private BluetoothDevice device;
private static final int STATE_DISCONNECTED = BluetoothProfile.STATE_DISCONNECTED;
private static final int STATE_DISCONNECTING = BluetoothProfile.STATE_DISCONNECTING;
private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING;
private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED;
private BluetoothGattService mShareService;
private BluetoothGattCharacteristic mAuthenticationCharacteristic;
private BluetoothGattCharacteristic mSendDataCharacteristic;
private BluetoothGattCharacteristic mReceiveDataCharacteristic;
private BluetoothGattCharacteristic mCommandCharacteristic;
private BluetoothGattCharacteristic mResponseCharacteristic;
private BluetoothGattCharacteristic mHeartBeatCharacteristic;
//Gatt Tasks
public final int GATT_NOTHING = 0;
public final int GATT_SETUP = 1;
public final int GATT_WRITING_COMMANDS = 2;
public final int GATT_READING_RESPONSE = 3;
public int successfulWrites;
//RXJAVA FUN
Action1 mDataResponseListener;
public int currentGattTask;
public int step;
public List writePackets;
public int recordType;
SharedPreferences prefs;
ReadDataShare readData;
public boolean state_authSucess = false;
public boolean state_authInProgress = false;
public boolean state_notifSetupSucess = false;
public boolean shouldDisconnect = false;
public boolean share2 = false;
public Service service;
@Override
public void onCreate() {
super.onCreate();
readData = new ReadDataShare(this);
service = this;
foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), service);
foregroundServiceStarter.start();
final IntentFilter bondintent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mPairReceiver, bondintent);
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
listenForChangeInSettings();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){
stopSelf();
return START_NOT_STICKY;
}
if (CollectionServiceStarter.isBTShare(getApplicationContext())) {
setFailoverTimer();
} else {
stopSelf();
return START_NOT_STICKY;
}
if (Sensor.currentSensor() == null) {
setRetryTimer();
return START_NOT_STICKY;
}
Log.w(TAG, "STARTING SERVICE");
attemptConnection();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
close();
setRetryTimer();
foregroundServiceStarter.stop();
unregisterReceiver(mPairReceiver);
Log.w(TAG, "SERVICE STOPPED");
}
public SharedPreferences.OnSharedPreferenceChangeListener prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if(key.compareTo("run_service_in_foreground") == 0) {
Log.e("FOREGROUND", "run_service_in_foreground changed!");
if (prefs.getBoolean("run_service_in_foreground", false)) {
foregroundServiceStarter = new ForegroundServiceStarter(getApplicationContext(), service);
foregroundServiceStarter.start();
Log.w(TAG, "Moving to foreground");
} else {
service.stopForeground(true);
Log.w(TAG, "Removing from foreground");
}
}
}
};
public void listenForChangeInSettings() {
prefs.registerOnSharedPreferenceChangeListener(prefListener);
}
public void setRetryTimer() {
if (CollectionServiceStarter.isBTShare(getApplicationContext())) {
BgReading bgReading = BgReading.last();
long retry_in;
if (bgReading != null) {
retry_in = Math.min(Math.max((1000 * 30), (1000 * 60 * 5) - (new Date().getTime() - bgReading.timestamp) - (1000 * 15)), (1000 * 60 * 5));
} else {
retry_in = (1000 * 20);
}
Log.d(TAG, "Restarting in: " + (retry_in / (60 * 1000)) + " minutes");
Calendar calendar = Calendar.getInstance();
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
alarm.setExact(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexShareCollectionService.class), 0));
}
}
public void setFailoverTimer() { //Sometimes it gets stuck in limbo on 4.4, this should make it try again
if (CollectionServiceStarter.isBTShare(getApplicationContext())) {
long retry_in = (1000 * 60 * 5);
Log.d(TAG, "Fallover Restarting in: " + (retry_in / (60 * 1000)) + " minutes");
Calendar calendar = Calendar.getInstance();
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, DexShareCollectionService.class), 0));
} else {
stopSelf();
}
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public void attemptConnection() {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
if (device != null) {
mConnectionState = STATE_DISCONNECTED;
for (BluetoothDevice bluetoothDevice : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {
if (bluetoothDevice.getAddress().compareTo(device.getAddress()) == 0) {
mConnectionState = STATE_CONNECTED;
}
}
}
Log.w(TAG, "Connection state: " + mConnectionState);
if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_DISCONNECTING) {
ActiveBluetoothDevice btDevice = ActiveBluetoothDevice.first();
if (btDevice != null) {
mDeviceName = btDevice.name;
mDeviceAddress = btDevice.address;
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter.isEnabled() && mBluetoothAdapter.getRemoteDevice(mDeviceAddress) != null) {
connect(mDeviceAddress);
return;
} else {
Log.w(TAG, "Bluetooth is disabled or BT device cant be found");
setRetryTimer();
return;
}
} else {
Log.w(TAG, "No bluetooth device to try and connect to");
setRetryTimer();
return;
}
} else if (mConnectionState == STATE_CONNECTED) {
Log.w(TAG, "Looks like we are already connected, going to read!");
attemptRead();
return;
} else {
setRetryTimer();
return;
}
} else {
setRetryTimer();
return;
}
}
public void attemptRead() {
Log.d(TAG, "Attempting to read data");
final Action1 systemTimeListener = new Action1() {
@Override
public void call(Long s) {
if (s != null) {
Log.d(TAG, "Made the full round trip, got " + s + " as the system time");
final long addativeSystemTimeOffset = new Date().getTime() - s;
final Action1 dislpayTimeListener = new Action1() {
@Override
public void call(Long s) {
if (s != null) {
Log.d(TAG, "Made the full round trip, got " + s + " as the display time offset");
final long addativeDisplayTimeOffset = addativeSystemTimeOffset - (s*1000);
Log.d(TAG, "Making " + addativeDisplayTimeOffset + " the the total time offset");
final Action1 evgRecordListener = new Action1() {
@Override
public void call(EGVRecord[] egvRecords) {
if (egvRecords != null) {
Log.d(TAG, "Made the full round trip, got " + egvRecords.length + " EVG Records");
BgReading.create(egvRecords, addativeSystemTimeOffset, getApplicationContext());
if (shouldDisconnect) {
stopSelf();
} else {
setRetryTimer();
}
}
}
};
final Action1 sensorRecordListener = new Action1() {
@Override
public void call(SensorRecord[] sensorRecords) {
if (sensorRecords != null) {
Log.d(TAG, "Made the full round trip, got " + sensorRecords.length + " Sensor Records");
BgReading.create(sensorRecords, addativeSystemTimeOffset, getApplicationContext());
readData.getRecentEGVs(evgRecordListener);
}
}
};
final Action1 calRecordListener = new Action1() {
@Override
public void call(CalRecord[] calRecords) {
if (calRecords != null) {
Log.d(TAG, "Made the full round trip, got " + calRecords.length + " Cal Records");
Calibration.create(calRecords, addativeDisplayTimeOffset, getApplicationContext());
readData.getRecentSensorRecords(sensorRecordListener);
}
}
};
readData.getRecentCalRecords(calRecordListener);
}
}
};
readData.readDisplayTimeOffset(dislpayTimeListener);
}
}
};
readData.readSystemTime(systemTimeListener);
}
public boolean connect(final String address) {
Log.w(TAG, "going to connect to device at address" + address);
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
setRetryTimer();
return false;
}
if (mBluetoothGatt != null) {
Log.w(TAG, "BGatt isnt null, Closing.");
mBluetoothGatt.close();
mBluetoothGatt = null;
}
for (BluetoothDevice bluetoothDevice : mBluetoothAdapter.getBondedDevices()) {
if (bluetoothDevice.getAddress().compareTo(address) == 0) {
Log.v(TAG, "Device found, already bonded, going to connect");
if(mBluetoothAdapter.getRemoteDevice(bluetoothDevice.getAddress()) != null) {
device = bluetoothDevice;
mBluetoothGatt = device.connectGatt(getApplicationContext(), false, mGattCallback);
return true;
}
}
}
device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
setRetryTimer();
return false;
}
Log.w(TAG, "Trying to create a new connection.");
mBluetoothGatt = device.connectGatt(getApplicationContext(), false, mGattCallback);
mConnectionState = STATE_CONNECTING;
return true;
}
public void authenticateConnection() {
Log.w(TAG, "Trying to auth");
String receiverSn = prefs.getString("share_key", "SM00000000").toUpperCase() + "000000";
if(receiverSn.compareTo("SM00000000000000") == 0) { // They havnt set their serial number, dont bond!
setRetryTimer();
return;
}
byte[] bondkey = (receiverSn).getBytes(StandardCharsets.US_ASCII);
if (mBluetoothGatt != null) {
if (mShareService != null) {
if(!share2) {
mAuthenticationCharacteristic = mShareService.getCharacteristic(DexShareAttributes.AuthenticationCode);
} else {
mAuthenticationCharacteristic = mShareService.getCharacteristic(DexShareAttributes.AuthenticationCode2);
}
if (mAuthenticationCharacteristic != null) {
Log.v(TAG, "Auth Characteristic found: " + mAuthenticationCharacteristic.toString());
if (mAuthenticationCharacteristic.setValue(bondkey)) {
mBluetoothGatt.writeCharacteristic(mAuthenticationCharacteristic);
} else {
setRetryTimer();
}
} else {
Log.w(TAG, "Authentication Characteristic IS NULL");
setRetryTimer();
}
} else {
Log.w(TAG, "CRADLE SERVICE IS NULL");
}
} else {
setRetryTimer();
}
}
public void assignCharacteristics() {
if(!share2) {
Log.d(TAG, "Setting #1 characteristics");
mSendDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageReceiver);
mReceiveDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageResponse);
mCommandCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Command);
mResponseCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Response);
mHeartBeatCharacteristic = mShareService.getCharacteristic(DexShareAttributes.HeartBeat);
} else {
Log.d(TAG, "Setting #1 characteristics");
mSendDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageReceiver2);
mReceiveDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageResponse2);
mCommandCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Command2);
mResponseCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Response2);
mHeartBeatCharacteristic = mShareService.getCharacteristic(DexShareAttributes.HeartBeat2);
}
}
public void setListeners(int listener_number) {
Log.w(TAG, "Setting Listener: #" + listener_number);
if (listener_number == 1) {
step = 2;
setCharacteristicIndication(mReceiveDataCharacteristic);
} else {
step = 3;
attemptRead();
}
}
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
setRetryTimer();
mBluetoothGatt = null;
mConnectionState = STATE_DISCONNECTED;
Log.w(TAG, "bt Disconnected");
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic) {
setCharacteristicNotification(characteristic, true);
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
Log.w(TAG, "Characteristic setting notification");
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));
Log.w(TAG, "Descriptor found: " + descriptor.getUuid());
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic) {
setCharacteristicIndication(characteristic, true);
}
public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic, boolean enabled) {
Log.w(TAG, "Characteristic setting indication");
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));
Log.w(TAG, "Descriptor found: " + descriptor.getUuid());
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
public void writeCommand(List packets, int aRecordType, Action1 dataResponseListener) {
mDataResponseListener = dataResponseListener;
successfulWrites = 0;
writePackets = packets;
recordType = aRecordType;
step = 0;
currentGattTask = GATT_WRITING_COMMANDS;
gattWritingStep();
}
public void clearGattTask() {
currentGattTask = GATT_NOTHING;
step = 0;
}
private void gattSetupStep() {
step = 1;
if(share2) { assignCharacteristics(); }
setListeners(1);
}
private void gattWritingStep() {
Log.d(TAG, "Writing command to the Gatt, step: " + step);
int index = step;
if (index <= (writePackets.size() - 1)) {
Log.d(TAG, "Writing: " + writePackets.get(index) + " index: " + index);
if(mSendDataCharacteristic != null && writePackets != null) {
mSendDataCharacteristic.setValue(writePackets.get(index));
if (mBluetoothGatt.writeCharacteristic(mSendDataCharacteristic)) {
Log.d(TAG, "Wrote Successfully");
}
}
} else {
Log.d(TAG, "Done Writing commands");
clearGattTask();
}
}
private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final BluetoothDevice bondDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (mBluetoothGatt != null && mBluetoothGatt.getDevice() != null && bondDevice != null) {
if (!bondDevice.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) {
Log.d(TAG, "Bond state wrong device");
return; // That wasnt a device we care about!!
}
}
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
if (state == BluetoothDevice.BOND_BONDED) {
Log.d(TAG, "CALLBACK RECIEVED Bonded");
authenticateConnection();
} else if (state == BluetoothDevice.BOND_NONE) {
Log.d(TAG, "CALLBACK RECIEVED: Not Bonded");
} else if (state == BluetoothDevice.BOND_BONDING) {
Log.d(TAG, "CALLBACK RECIEVED: Trying to bond");
}
}
}
};
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.w(TAG, "Gatt state change status: " + status + " new state: " + newState);
writeStatusConnectionFailures(status);
if (status == 133) {
Log.e(TAG, "Got the status 133 bug, GROSS!!");
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt = gatt;
device = mBluetoothGatt.getDevice();
mConnectionState = STATE_CONNECTED;
ActiveBluetoothDevice.connected();
Log.w(TAG, "Connected to GATT server.");
Log.w(TAG, "discovering services");
currentGattTask = GATT_SETUP;
if (!mBluetoothGatt.discoverServices()) {
Log.w(TAG, "discovering failed");
if(shouldDisconnect) {
stopSelf();
} else {
setRetryTimer();
}
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
ActiveBluetoothDevice.disconnected();
if(shouldDisconnect) {
stopSelf();
} else {
setRetryTimer();
}
Log.w(TAG, "Disconnected from GATT server.");
} else {
Log.w(TAG, "Gatt callback... strange state.");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(TAG, "services discovered " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
mShareService = mBluetoothGatt.getService(DexShareAttributes.CradleService);
if(mShareService == null) {
mShareService = mBluetoothGatt.getService(DexShareAttributes.CradleService2);
share2 = true;
} else {
share2 = false;
}
assignCharacteristics();
authenticateConnection();
gattSetupStep();
} else {
Log.w(TAG, "No Services Discovered!");
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.v(TAG, "Characteristic Read " + characteristic.getUuid());
if(mHeartBeatCharacteristic.getUuid().equals(characteristic.getUuid())) {
Log.v(TAG, "Characteristic Read " + characteristic.getUuid() + " " + characteristic.getValue());
setCharacteristicNotification(mHeartBeatCharacteristic);
}
mBluetoothGatt.readCharacteristic(mHeartBeatCharacteristic);
} else {
Log.e(TAG, "Characteristic failed to read");
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
UUID charUuid = characteristic.getUuid();
Log.d(TAG, "Characteristic Update Received: " + charUuid);
if (charUuid.compareTo(mReceiveDataCharacteristic.getUuid()) == 0) {
Log.d(TAG, "mCharReceiveData Update");
byte[] value = characteristic.getValue();
if (value != null) {
Observable.just(characteristic.getValue()).subscribe(mDataResponseListener);
}
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
Log.d(TAG, "Characteristic onDescriptorWrite ch " + characteristic.getUuid());
if(mHeartBeatCharacteristic.getUuid().equals(characteristic.getUuid())) {
state_notifSetupSucess = true;
setCharacteristicIndication(mReceiveDataCharacteristic);
}
if(mReceiveDataCharacteristic.getUuid().equals(characteristic.getUuid())) {
setCharacteristicIndication(mResponseCharacteristic);
}
if(mResponseCharacteristic.getUuid().equals(characteristic.getUuid())) {
attemptRead();
}
} else if ((status & BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) != 0 || (status & BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION) != 0) {
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
device = gatt.getDevice();
state_authInProgress = true;
bondDevice();
} else {
Log.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");
}
} else {
Log.e(TAG, "Unknown error writing descriptor");
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, "characteristic wrote " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "Wrote a characteristic successfully " + characteristic.getUuid());
if (mAuthenticationCharacteristic.getUuid().equals(characteristic.getUuid())) {
state_authSucess = true;
mBluetoothGatt.readCharacteristic(mHeartBeatCharacteristic);
}
} else if ((status & BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) != 0 || (status & BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION) != 0) {
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
device = gatt.getDevice();
state_authInProgress = true;
bondDevice();
} else {
Log.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");
}
} else {
Log.e(TAG, "Unknown error writing Characteristic");
}
}
};
public void bondDevice() {
final IntentFilter bondintent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mPairReceiver, bondintent);
if(!share2){ device.setPin("000000".getBytes()); }
device.createBond();
}
private void writeStatusConnectionFailures(int status) {
if(status != 0) {
Log.e(TAG, "ERRR: GATT_WRITE_NOT_PERMITTED " + (status & BluetoothGatt.GATT_WRITE_NOT_PERMITTED));
Log.e(TAG, "ERRR: GATT_INSUFFICIENT_AUTHENTICATION " + (status & BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION));
Log.e(TAG, "ERRR: GATT_REQUEST_NOT_SUPPORTED " + (status & BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED));
Log.e(TAG, "ERRR: GATT_INSUFFICIENT_ENCRYPTION " + (status & BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION));
Log.e(TAG, "ERRR: GATT_INVALID_OFFSET " + (status & BluetoothGatt.GATT_INVALID_OFFSET));
Log.e(TAG, "ERRR: GATT_FAILURE " + (status & BluetoothGatt.GATT_FAILURE));
Log.e(TAG, "ERRR: GATT_INVALID_ATTRIBUTE_LENGTH " + (status & BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH));
Log.e(TAG, "ERRR: GATT_READ_NOT_PERMITTED" + (status & BluetoothGatt.GATT_READ_NOT_PERMITTED));
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Services/MongoWrapper.java
================================================
package com.eveningoutpost.dexdrip.Services;
import java.io.IOException;
import java.net.UnknownHostException;
import android.util.Log;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.MongoClientURI;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class MongoWrapper {
MongoClient mongoClient_;
String dbUriStr_;
String dbName_;
String collection_;
String index_;
String machineName_;
private final static String TAG = WixelReader.class.getName();
public MongoWrapper(String dbUriStr, String collection, String index, String machineName) {
dbUriStr_ = dbUriStr;
// dbName is the last part of the string starting with /dbname
dbName_ = dbUriStr.substring(dbUriStr.lastIndexOf('/') + 1);
collection_ = collection;
index_ = index;
machineName_ = machineName;
}
// Unfortunately, this also throws other exceptions that are not documetned...
public DBCollection openMongoDb() throws UnknownHostException {
MongoClientURI dbUri = new MongoClientURI(dbUriStr_); //?? thros
mongoClient_ = new MongoClient(dbUri);
DB db = mongoClient_.getDB( dbName_ );
DBCollection coll = db.getCollection(collection_);
coll.createIndex(new BasicDBObject(index_, 1)); // create index on "i", ascending
return coll;
}
public void closeMongoDb() {
if(mongoClient_ != null) {
mongoClient_.close();
}
}
public boolean WriteDebugDataToMongo(String message)
{
String complete = machineName_ + " " + new Date().toLocaleString() + " " + message;
BasicDBObject doc = new BasicDBObject("DebugMessage", complete);
return WriteToMongo(doc);
}
public boolean WriteToMongo(TransmitterRawData trd)
{
BasicDBObject bdbo = trd.toDbObj(machineName_ + " " + new Date(trd.CaptureDateTime).toLocaleString());
return WriteToMongo(bdbo);
}
public boolean WriteToMongo(BasicDBObject bdbo)
{
DBCollection coll;
try {
coll = openMongoDb();
coll.insert(bdbo);
} catch (UnknownHostException e) {
Log.e(TAG, "WriteToMongo cought UnknownHostException! ",e);
return false;
} catch (MongoException e) {
Log.e(TAG, "WriteToMongo cought MongoException! ", e);
return false;
} catch (Exception e) {
Log.e(TAG, "WriteToMongo cought Exception! ", e);
closeMongoDb();
return false;
}
finally {
closeMongoDb();
}
return true;
}
// records will be marked by their timestamp
public List ReadFromMongo(int numberOfRecords) {
System.out.println( "Starting to read from mongodb");
List trd_list = new LinkedList();
DBCollection coll;
TransmitterRawData lastTrd = null;
try {
coll = openMongoDb();
BasicDBObject query = new BasicDBObject("RawValue", new BasicDBObject("$exists", true));
DBCursor cursor = coll.find(query);
cursor.sort(new BasicDBObject("CaptureDateTime", -1));
try {
while(cursor.hasNext() && trd_list.size() < numberOfRecords) {
//System.out.println(cursor.next());
Log.e(TAG, "Read an object from mongodb");
TransmitterRawData trd = new TransmitterRawData((BasicDBObject)cursor.next());
// Do our best to fix the relative time...
trd.RelativeTime = new Date().getTime() - trd.CaptureDateTime;
// since we are reading it from the db, it was uploaded...
trd.Uploaded = 1;
if(lastTrd == null) {
trd_list.add(0,trd);
lastTrd = trd;
System.out.println( trd.toTableString());
} else if(!WixelReader.almostEquals(lastTrd, trd)) {
lastTrd = trd;
trd_list.add(0,trd);
System.out.println( trd.toTableString());
}
}
} finally {
cursor.close();
}
} catch (UnknownHostException e) {
Log.e(TAG, "ReadFromMongo: cought UnknownHostException! ", e);
return null;
} catch (MongoException e) {
Log.e(TAG, "ReadFromMongo: cought MongoException! " , e);
return trd_list;
} catch (Exception e) {
Log.e(TAG, "ReadFromMongo: cought Exception! " , e);
closeMongoDb();
return null;
}finally {
closeMongoDb();
}
return trd_list;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Services/SyncService.java
================================================
package com.eveningoutpost.dexdrip.Services;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue;
import com.eveningoutpost.dexdrip.UtilityModels.CalibrationSendQueue;
import com.eveningoutpost.dexdrip.UtilityModels.MongoSendTask;
import com.eveningoutpost.dexdrip.UtilityModels.NightscoutUploader;
import com.eveningoutpost.dexdrip.UtilityModels.RestCalls;
import com.eveningoutpost.dexdrip.UtilityModels.SensorSendQueue;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class SyncService extends Service {
int mStartMode;
private Context mContext;
private Boolean enableRESTUpload;
private Boolean enableMongoUpload;
private SharedPreferences prefs;
@Override
public void onCreate() {
Log.w("SYNC SERVICE:", "STARTING SERVICE");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
attemptSend();
return START_STICKY;
}
@Override
public void onDestroy() {
setRetryTimer();
Log.w("SYNC SERVICE", "SERVICE STOPPED");
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public void attemptSend() {
mContext = getApplicationContext();
prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
enableRESTUpload = prefs.getBoolean("cloud_storage_api_enable", false);
enableMongoUpload = prefs.getBoolean("cloud_storage_mongodb_enable", false);
if (enableRESTUpload || enableMongoUpload) { syncToMogoDb(); }
if (false) {
for (SensorSendQueue job : SensorSendQueue.queue()) {
RestCalls.sendSensor(job);
}
for (CalibrationSendQueue job : CalibrationSendQueue.queue()) {
RestCalls.sendCalibration(job);
}
for (BgSendQueue job : BgSendQueue.queue()) {
RestCalls.sendBgReading(job);
}
}
setRetryTimer();
}
public void setRetryTimer() {
Calendar calendar = Calendar.getInstance();
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + (1000 * 30 * 5), PendingIntent.getService(this, 0, new Intent(this, SyncService.class), 0));
}
public void syncToMogoDb() {
MongoSendTask task = new MongoSendTask(getApplicationContext());
task.execute();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Services/TransmitterRawData.java
================================================
package com.eveningoutpost.dexdrip.Services;
import java.util.Date;
import com.mongodb.BasicDBObject;
/**
* Created by John Costik on 6/7/14.
*/
public class TransmitterRawData {
private long _id;
public String Id;
public int TransmissionId;
public String TransmitterId;
public int RawValue;
public int FilteredValue;
public int BatteryLife;
public int ReceivedSignalStrength;
public long CaptureDateTime;
public int Uploaded;
public int UploadAttempts;
public int UploaderBatteryLife;
// When sending set this value to the relative time...
// The time between the capture and now...
public long RelativeTime;
public int getTransmissionId() {
return TransmissionId;
}
public void setTransmissionId(int transmissionId) {
TransmissionId = transmissionId;
}
public int getUploaded() {
return Uploaded;
}
public void setUploaded(int uploaded) {
Uploaded = uploaded;
}
public int getUploadAttempts() {
return UploadAttempts;
}
public void setUploadAttempts(int uploadAttempts) {
UploadAttempts = uploadAttempts;
}
public int getUploaderBatteryLife() {
return UploaderBatteryLife;
}
public void setUploaderBatteryLife(int uploaderBatteryLife) {
UploaderBatteryLife = uploaderBatteryLife;
}
public int getBatteryLife() {
return BatteryLife;
}
public void setBatteryLife(int batteryLife) {
BatteryLife = batteryLife;
}
public int getReceivedSignalStrength() {
return ReceivedSignalStrength;
}
public void setReceivedSignalStrength(int receivedSignalStrength) {
ReceivedSignalStrength = receivedSignalStrength;
}
public String getTransmitterId() {
return TransmitterId;
}
public void setTransmitterId(String transmitterId) {
TransmitterId = transmitterId;
}
public int getRawValue() {
return RawValue;
}
public void setRawValue(int rawValue) {
RawValue = rawValue;
}
public int getFilteredValue() {
return FilteredValue;
}
public void setFilteredValue(int filteredValue) {
FilteredValue = filteredValue;
}
public long getCaptureDateTime() {
return CaptureDateTime;
}
public void setCaptureDateTime(long captureDateTime) {
CaptureDateTime = captureDateTime;
}
public long get_id() {
return _id;
}
public void set_id(long _id) {
this._id = _id;
}
private Long getRelativeTime() {
return RelativeTime;
}
public TransmitterRawData(){
}
/*
public TransmitterRawData(String id, String raw, String filter, String battery, String rssi, int uploaderBattery){
RawValue = Integer.parseInt(raw);
FilteredValue = Integer.parseInt(filter);
TransmitterId = id;
BatteryLife = Integer.parseInt(battery);
ReceivedSignalStrength = Integer.parseInt(rssi);
CaptureDateTime = new Date().getTime();
UploaderBatteryLife = uploaderBattery;
Uploaded = 0;
UploadAttempts = 1;
}
public TransmitterRawData(byte[] buffer, int len, Context context){
StringBuilder toParse = new StringBuilder();
for (int i = 0; i < len; ++i) {
toParse.append((char) buffer[i]);
}
String[] parsed = toParse.toString().split("\\s+");
RawValue = Integer.parseInt(parsed[1]);
FilteredValue = Integer.parseInt(parsed[2]);
TransmitterId = parsed[0];
BatteryLife = Integer.parseInt(parsed[3]);
ReceivedSignalStrength = Integer.parseInt(parsed[4]);
TransmissionId = Integer.parseInt(parsed[5]);
CaptureDateTime = new Date().getTime();
Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
UploaderBatteryLife = i.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
Uploaded = 0;
UploadAttempts = 1;
}
*/
public String toTableString()
{
String displayDt = new Date(getCaptureDateTime()).toLocaleString() + System.getProperty("line.separator");
String transmitterId = "Transmitter Id: " + getTransmitterId() + System.getProperty("line.separator");
String transmissionId = "Transmission Id: " + getTransmissionId() + System.getProperty("line.separator");
String rawVal = "Raw Value: " + getRawValue() + System.getProperty("line.separator");
String filterVal = "Filtered Value: " + getFilteredValue() + System.getProperty("line.separator");
String batteryVal = "Transmitter Battery: " + getBatteryLife() + " " + System.getProperty("line.separator");
String signalVal = "RSSI: " + getReceivedSignalStrength() + " " + System.getProperty("line.separator");
String uploadDeviceBatteryVal = "Uploader Battery: " + getUploaderBatteryLife() + " " + System.getProperty("line.separator");
String uploaded = "Uploaded: " + getUploaded() + " " + System.getProperty("line.separator");
String RelativeTime = "relateive time (seconds): " + getRelativeTime() / 1000 + " "+ System.getProperty("line.separator");
return displayDt + transmitterId + transmissionId + rawVal + filterVal + batteryVal + signalVal + uploadDeviceBatteryVal + uploaded + RelativeTime;
}
public BasicDBObject toDbObj(String DebugInfo) {
BasicDBObject doc = new BasicDBObject("TransmissionId", TransmissionId).
append("TransmitterId", TransmitterId).
append("RawValue", RawValue).
append("FilteredValue", FilteredValue).
append("BatteryLife", BatteryLife).
append("ReceivedSignalStrength", ReceivedSignalStrength).
append("CaptureDateTime", CaptureDateTime).
append("UploaderBatteryLife", UploaderBatteryLife).
append("DebugInfo", DebugInfo);
return doc;
}
public TransmitterRawData(BasicDBObject src) {
TransmissionId = src.getInt("TransmissionId");
TransmitterId = src.getString("TransmitterId");
RawValue = src.getInt("RawValue");
FilteredValue = src.getInt("FilteredValue");
BatteryLife = src.getInt("BatteryLife");
ReceivedSignalStrength = src.getInt("ReceivedSignalStrength");
CaptureDateTime = src.getLong("CaptureDateTime");
UploaderBatteryLife = src.getInt("UploaderBatteryLife");
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Services/WixelReader.java
================================================
package com.eveningoutpost.dexdrip.Services;
import java.io.IOException;
import java.util.Date;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.LinkedList;
import java.util.List;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.eveningoutpost.dexdrip.Sensor;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.TransmitterData;
public class WixelReader extends Thread {
private final static String TAG = WixelReader.class.getName();
private static WixelReader singleton;
public synchronized static WixelReader getInstance(Context ctx) {
if(singleton == null) {
singleton = new WixelReader(ctx);
}
return singleton;
}
private final Context mContext;
private volatile boolean mStop = false;
private static boolean sStarted = false;
public WixelReader(Context ctx) {
mContext = ctx.getApplicationContext();
}
public static void sStart(Context ctx) {
if(sStarted) {
return;
}
WixelReader theWixelReader = getInstance(ctx);
theWixelReader.start();
sStarted = true;
}
public static void sStop() {
if(!sStarted) {
return;
}
WixelReader theWixelReader = getInstance(null);
theWixelReader.Stop();
try {
theWixelReader.join();
} catch (InterruptedException e) {
Log.e(TAG, "cought InterruptedException, could not wait for the wixel thread to exit", e);
}
sStarted = false;
// A stopped thread can not start again, so we need to kill it and will start a new one
// on demand
singleton = null;
}
public static boolean IsConfigured(Context ctx) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
String recieversIpAddresses = prefs.getString("wifi_recievers_addresses", "");
if(recieversIpAddresses == null || recieversIpAddresses.equals("") ) {
return false;
}
return true;
}
public static boolean almostEquals( TransmitterRawData e1, TransmitterRawData e2)
{
if (e1 == null || e2==null) {
return false;
}
// relative time is in ms
if ((Math.abs(e1.CaptureDateTime - e2.CaptureDateTime) < 120 * 1000 ) &&
(e1.TransmissionId == e2.TransmissionId)) {
return true;
}
return false;
}
// last in the array, is first in time
public static List Merge2Lists(List list1 , List list2)
{
List merged = new LinkedList ();
while (true) {
if(list1.size() == 0 && list2.size() == 0) {
break;
}
if (list1.size() == 0) {
merged.addAll(list2);
break;
}
if (list2.size() == 0) {
merged.addAll(list1);
break;
}
if (almostEquals(list1.get(0), list2.get(0))) {
list2.remove(0);
merged.add(list1.remove(0));
continue;
}
if(list1.get(0).RelativeTime > list2.get(0).RelativeTime) {
merged.add(list1.remove(0));
} else {
merged.add(list2.remove(0));
}
}
return merged;
}
public static List MergeLists(List > allTransmitterRawData)
{
List MergedList;
MergedList = allTransmitterRawData.remove(0);
for (List it : allTransmitterRawData) {
MergedList = Merge2Lists(MergedList, it);
}
return MergedList;
}
public static List ReadHost(String hostAndIp, int numberOfRecords)
{
int port;
System.out.println("Reading From " + hostAndIp);
Log.i(TAG,"Reading From " + hostAndIp);
String []hosts = hostAndIp.split(":");
if(hosts.length != 2) {
System.out.println("Invalid hostAndIp " + hostAndIp);
Log.e(TAG, "Invalid hostAndIp " + hostAndIp);
return null;
}
try {
port = Integer.parseInt(hosts[1]);
} catch (NumberFormatException nfe) {
System.out.println("Invalid port " +hosts[1]);
Log.e(TAG, "Invalid hostAndIp " + hostAndIp, nfe);
return null;
}
if (port < 10 || port > 65536) {
System.out.println("Invalid port " +hosts[1]);
Log.e(TAG, "Invalid hostAndIp " + hostAndIp);
return null;
}
System.out.println("Reading from " + hosts[0] + " " + port);
List ret;
try {
ret = Read(hosts[0], port, numberOfRecords);
} catch(Exception e) {
// We had some error, need to move on...
System.out.println("read from host failed cought expation" + hostAndIp);
Log.e(TAG, "read from host failed " + hostAndIp, e);
return null;
}
return ret;
}
public static List ReadFromMongo(String dbury, int numberOfRecords)
{
Log.i(TAG,"Reading From " + dbury);
List tmpList;
// format is dburi/db/collection. We need to find the collection and strip it from the dburi.
int indexOfSlash = dbury.lastIndexOf('/');
if(indexOfSlash == -1) {
// We can not find a collection name
Log.e(TAG, "Error bad dburi. Did not find a collection name starting with / " + dbury);
// in order for the user to understand that there is a problem, we return null
return null;
}
String collection = dbury.substring(indexOfSlash + 1);
dbury = dbury.substring(0, indexOfSlash);
// Make sure that we have another /, since this is used in the constructor.
indexOfSlash = dbury.lastIndexOf('/');
if(indexOfSlash == -1) {
// We can not find a collection name
Log.e(TAG, "Error bad dburi. Did not find a collection name starting with / " + dbury);
// in order for the user to understand that there is a problem, we return null
return null;
}
MongoWrapper mt = new MongoWrapper(dbury, collection, "CaptureDateTime", "MachineNameNotUsed");
return mt.ReadFromMongo(numberOfRecords);
}
// format of string is ip1:port1,ip2:port2;
public static TransmitterRawData[] Read(String hostsNames, int numberOfRecords)
{
String []hosts = hostsNames.split(",");
if(hosts.length == 0) {
Log.e(TAG, "Error no hosts were found " + hostsNames);
return null;
}
List > allTransmitterRawData = new LinkedList >();
// go over all hosts and read data from them
for(String host : hosts) {
List tmpList;
if (host.startsWith("mongodb://")) {
tmpList = ReadFromMongo(host ,numberOfRecords);
} else {
tmpList = ReadHost(host, numberOfRecords);
}
if(tmpList != null && tmpList.size() > 0) {
allTransmitterRawData.add(tmpList);
}
}
// merge the information
if (allTransmitterRawData.size() == 0) {
System.out.println("Could not read anything from " + hostsNames);
Log.e(TAG, "Could not read anything from " + hostsNames);
return null;
}
List mergedData= MergeLists(allTransmitterRawData);
int retSize = Math.min(numberOfRecords, mergedData.size());
TransmitterRawData []trd_array = new TransmitterRawData[retSize];
mergedData.subList(mergedData.size() - retSize, mergedData.size()).toArray(trd_array);
System.out.println("Final Results========================================================================");
for (int i= 0; i < trd_array.length; i++) {
// System.out.println( trd_array[i].toTableString());
}
return trd_array;
}
public static List Read(String hostName,int port, int numberOfRecords)
{
List trd_list = new LinkedList();
try
{
Log.i(TAG, "Read called");
Gson gson = new GsonBuilder().create();
// An example of using gson.
ComunicationHeader ch = new ComunicationHeader();
ch.version = 1;
ch.numberOfRecords = numberOfRecords;
String flat = gson.toJson(ch);
ComunicationHeader ch2 = gson.fromJson(flat, ComunicationHeader.class);
System.out.println("Results code" + flat + ch2.version);
// Real client code
Socket MySocket = new Socket(hostName, port);
System.out.println("After the new socket \n");
MySocket.setSoTimeout(2000);
System.out.println("client connected... " );
PrintWriter out = new PrintWriter(MySocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(MySocket.getInputStream()));
out.println(flat);
while(true) {
String data = in.readLine();
if(data == null) {
System.out.println("recieved null exiting");
break;
}
if(data.equals("")) {
System.out.println("recieved \"\" exiting");
break;
}
//System.out.println( "data size " +data.length() + " data = "+ data);
TransmitterRawData trd = gson.fromJson(data, TransmitterRawData.class);
trd.CaptureDateTime = System.currentTimeMillis() - trd.RelativeTime;
trd_list.add(0,trd);
// System.out.println( trd.toTableString());
if(trd_list.size() == numberOfRecords) {
// We have the data we want, let's get out
break;
}
}
MySocket.close();
return trd_list;
}catch(SocketTimeoutException s) {
Log.e(TAG, "Socket timed out! ", s);
}
catch(IOException e) {
Log.e(TAG, "cought IOException! ", e);
}
return trd_list;
}
public void run()
{
Long LastReportedTime = new Date().getTime();
TransmitterRawData LastReportedReading = null;
Log.e(TAG, "Starting... LastReportedReading " + LastReportedReading);
try {
while (!mStop && !interrupted()) {
// try to read one object...
TransmitterRawData[] LastReadingArr = null;
if(WixelReader.IsConfigured(mContext)) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
String recieversIpAddresses = prefs.getString("wifi_recievers_addresses", "");
LastReadingArr = Read(recieversIpAddresses ,1);
}
if (LastReadingArr != null && LastReadingArr.length > 0) {
// Last in the array is the most updated reading we have.
TransmitterRawData LastReading = LastReadingArr[LastReadingArr.length -1];
//if (LastReading.CaptureDateTime > LastReportedReading + 5000) {
// Make sure we do not report packets from the far future...
if ((LastReading.CaptureDateTime > LastReportedTime ) &&
(!almostEquals(LastReading, LastReportedReading)) &&
LastReading.CaptureDateTime < new Date().getTime() + 12000) {
// We have a real new reading...
Log.e(TAG, "calling setSerialDataToTransmitterRawData " + LastReading.RawValue +
" LastReading.CaptureDateTime " + LastReading.CaptureDateTime + " " + LastReading.TransmissionId);
setSerialDataToTransmitterRawData(LastReading.RawValue , LastReading.BatteryLife, LastReading.CaptureDateTime);
LastReportedReading = LastReading;
LastReportedTime = LastReading.CaptureDateTime;
}
}
// let's sleep (right now for 30 seconds)
Thread.sleep(30000);
}
} catch (InterruptedException e) {
Log.e(TAG, "cought InterruptedException! ", e);
// time to get out...
}
}
// this function is only a test function. It is used to set many points fast in order to allow
// faster testing without real data.
public void runFake()
{
// let's start by faking numbers....
int i = 0;
int added = 5;
while (!mStop) {
try {
for (int j = 0 ; j < 3; j++) {
Thread.sleep(1000);
if(mStop ) {
// we were asked to leave, so do it....
return;
}
}
i+=added;
if (i==50) {
added = -5;
}
if (i==0) {
added = 5;
}
int fakedRaw = 150000 + i * 1000;
Log.e(TAG, "calling setSerialDataToTransmitterRawData " + fakedRaw);
setSerialDataToTransmitterRawData(fakedRaw, 100, new Date().getTime());
} catch (InterruptedException e) {
// time to get out...
Log.e(TAG, "cought InterruptedException! ", e);
break;
}
}
}
public void Stop()
{
mStop = true;
interrupt();
}
public void setSerialDataToTransmitterRawData(int raw_data ,int sensor_battery_leve, Long CaptureTime) {
TransmitterData transmitterData = TransmitterData.create(raw_data, sensor_battery_leve, CaptureTime);
if (transmitterData != null) {
Sensor sensor = Sensor.currentSensor();
if (sensor != null) {
BgReading bgReading = BgReading.create(transmitterData.raw_data, mContext, CaptureTime);
sensor.latest_battery_level = transmitterData.sensor_battery_level;
sensor.save();
} else {
Log.w(TAG, "No Active Sensor, Data only stored in Transmitter Data");
}
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/SettingsActivity.java
================================================
package com.eveningoutpost.dexdrip;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.RingtonePreference;
import android.text.TextUtils;
public class SettingsActivity extends PreferenceActivity {
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setupSimplePreferencesScreen();
}
private void setupSimplePreferencesScreen() {
addPreferencesFromResource(R.xml.pref_license);
PreferenceCategory fakeHeader = new PreferenceCategory(this);
getPreferenceScreen().addPreference(fakeHeader);
addPreferencesFromResource(R.xml.pref_general);
fakeHeader = new PreferenceCategory(this);
getPreferenceScreen().addPreference(fakeHeader);
addPreferencesFromResource(R.xml.pref_notifications);
fakeHeader = new PreferenceCategory(this);
getPreferenceScreen().addPreference(fakeHeader);
addPreferencesFromResource(R.xml.pref_data_source);
fakeHeader = new PreferenceCategory(this);
getPreferenceScreen().addPreference(fakeHeader);
addPreferencesFromResource(R.xml.pref_data_sync);
bindPreferenceSummaryToValue(findPreference("dex_collection_method"));
bindPreferenceSummaryToValue(findPreference("units"));
bindPreferenceSummaryToValue(findPreference("share_key"));
}
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (preference instanceof RingtonePreference) {
if (TextUtils.isEmpty(stringValue)) {
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
preference.setSummary(null);
} else {
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
preference.setSummary(stringValue);
}
return true;
}
};
private static void bindPreferenceSummaryToValue(Preference preference) {
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/DexcomShareInterface.java
================================================
package com.eveningoutpost.dexdrip.ShareModels;
import java.util.Map;
import retrofit.Callback;
import retrofit.client.Response;
import retrofit.http.Body;
import retrofit.http.POST;
import retrofit.http.QueryMap;
/**
* Created by stephenblack on 3/16/15.
*/
public interface DexcomShareInterface {
@POST("/Publisher/ReadPublisherLatestGlucoseValues")
ShareGlucose[] getShareBg(@QueryMap Map options);
@POST("/General/LoginPublisherAccountByName")
void getSessionId(@Body ShareAuthenticationBody body, Callback callback);
//Since this seems to respond with a string we need a callback that will parse the response body
//new String(((TypedByteArray) response.getBody()).getBytes());
@POST("/Publisher/IsRemoteMonitoringSessionActive")
void checkSessionActive(@QueryMap Map options, Callback callback);
// needs ?sessionId={YourSessionId}
// returns true or false
@POST("/Publisher/PostReceiverEgvRecords")
void uploadBGRecords(@QueryMap Map options, @Body ShareUploadPayload payload, Callback callback);
// needs ?sessionId={YourSessionId}
// body ShareUploadPayload
// status code
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/Egv.java
================================================
package com.eveningoutpost.dexdrip.ShareModels;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.google.gson.annotations.Expose;
/**
* Created by stephenblack on 3/19/15.
*/
public class Egv {
@Expose
public int Trend;
@Expose
public int Value;
@Expose
public String ST;
@Expose
public String DT;
public Egv(BgReading bg) {
this.Value = (int) bg.calculated_value;
this.DT = toDateString(bg.timestamp);
this.ST = toDateString(bg.timestamp);
this.Trend = slopeOrdinal(bg);
}
public String toDateString(double timestamp) {
long shortened = (long) Math.floor((timestamp/1000));
return "/Date(" + Long.toString(shortened*1000) + ")/";
}
public int slopeOrdinal(BgReading bg) {
double slope_by_minute = bg.calculated_value_slope * 60000;
int arrow = 0;
if (slope_by_minute <= (-3.5)) {
arrow = 7;
} else if (slope_by_minute <= (-2)) {
arrow = 6;
} else if (slope_by_minute <= (-1)) {
arrow = 5;
} else if (slope_by_minute <= (1)) {
arrow = 4;
} else if (slope_by_minute <= (2)) {
arrow = 3;
} else if (slope_by_minute <= (3.5)) {
arrow = 2;
} else {
arrow = 1;
}
if(bg.hide_slope) {
arrow = 9;
}
return arrow;
}
// {
//
// "Trend":4,
// "ST":"\/Date(1426783106000 - 1426754317000)\/",
// "DT":"\/Date(1426754317000)\/",
// "Value":97
// }
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareAuthenticationBody.java
================================================
package com.eveningoutpost.dexdrip.ShareModels;
import com.google.gson.annotations.Expose;
/**
* Created by stephenblack on 3/16/15.
*/
public class ShareAuthenticationBody {
@Expose
public String password;
@Expose
public String applicationId;
@Expose
public String accountName;
public ShareAuthenticationBody(String aPassword, String aAccountName) {
this.password = aPassword;
this.accountName = aAccountName;
this.applicationId = "d89443d2-327c-4a6f-89e5-496bbb0317db";
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareGlucose.java
================================================
package com.eveningoutpost.dexdrip.ShareModels;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.provider.BaseColumns;
import android.util.Log;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.google.gson.annotations.Expose;
/**
* Created by stephenblack on 3/16/15.
*/
@Table(name = "ShareGlucose", id = BaseColumns._ID)
public class ShareGlucose extends Model {
public Context mContext;
@Expose
@Column(name = "DT")
public String DT;
@Expose
@Column(name = "ST")
public String ST;
@Expose
@Column(name = "Trend")
public double Trend;
@Expose
@Column(name = "Value")
public double Value;
@Expose
@Column(name = "WT")
public String WT;
public void processShareData(Context context) {
Log.d("SHARE", "Share Data being processed!"); // TODO maybe set this up??
// mContext = context;
// Log.d("SHARE", "Timestamp before parsing: " + WT);
// Log.d("SHARE", "Timestamp before parsing: " + WT.replaceAll("[^\\d.]", ""));
//
// double timestamp = (Double.parseDouble(WT.replaceAll("[^\\d.]", "")));
// Log.d("SHARE", "Timestamp: " + timestamp);
// if (!Bg.alreadyExists(timestamp)) {
// Log.d("SHARE", "Data looks new!!");
// Bg bg = new Bg();
// bg.direction = slopeDirection();
// bg.battery = Integer.toString(getBatteryLevel());
// bg.bgdelta = calculateDelta(timestamp, Value);
// bg.datetime = timestamp;
// bg.sgv = Integer.toString((int) Value);
// bg.save();
// DataCollectionService.newDataArrived(mContext, true);
// Log.d("SHARE", "Share Data Processed Successfully!");
// } else {
// Log.d("SHARE", "A Bg Value similar to this timestamp already exists.");
// }
}
public String slopeDirection() {
switch((int) Trend) {
case 1:
return "DoubleUp";
case 2:
return "SingleUp";
case 3:
return "FortyFiveUp";
case 4:
return "Flat";
case 5:
return "FortyFiveDown";
case 6:
return "SingleDown";
case 7:
return "DoubleDown";
default:
return "";
}
}
public int getBatteryLevel() {
Intent batteryIntent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if(level == -1 || scale == -1) {
return 50;
}
return (int)(((float)level / (float)scale) * 100.0f);
}
public double calculateDelta(double timestamp, double currentValue) {
// Bg bg = Bg.mostRecentBefore(timestamp);
// if (bg != null && Math.abs(bg.datetime - timestamp) < (60*1000*15)) {
// return (bg.sgv_double() - currentValue);
// } else {
return 0;
// }
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareRest.java
================================================
package com.eveningoutpost.dexdrip.ShareModels;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.squareup.okhttp.OkHttpClient;
import java.security.cert.CertificateException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import retrofit.Callback;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.android.AndroidLog;
import retrofit.client.OkClient;
import retrofit.client.Response;
import retrofit.converter.GsonConverter;
import retrofit.mime.TypedByteArray;
/**
* Created by stephenblack on 12/26/14.
*/
public class ShareRest {
private Context mContext;
private String login;
private String password;
private SharedPreferences prefs;
OkClient client;
public static Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
public ShareRest(Context context) {
client = getOkClient();
mContext = context;
prefs = PreferenceManager.getDefaultSharedPreferences(context);
login = prefs.getString("dexcom_account_name", "");
password = prefs.getString("dexcom_account_password", "");
}
public boolean getBgData() {
if (prefs.getBoolean("share_poll", false) && login.compareTo("") != 0 && password.compareTo("") != 0) {
return loginAndGetData();
} else {
return false;
}
}
public boolean sendBgData(BgReading bg) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
String receiverSn = preferences.getString("share_key", "SM00000000").toUpperCase();
if (prefs.getBoolean("share_upload", false) && login.compareTo("") != 0 && password.compareTo("") != 0 && receiverSn.compareTo("SM00000000") != 0) {
return loginAndSendData(bg);
} else {
return false;
}
}
private boolean loginAndGetData() {
try {
dexcomShareAuthorizeInterface().getSessionId(new ShareAuthenticationBody(password, login), new Callback() {
@Override
public void success(Object o, Response response) {
Log.d("ShareRest", "Success!! got a response on auth.");
String returnedSessionId = new String(((TypedByteArray) response.getBody()).getBytes()).replace("\"", "");
getBgData(returnedSessionId);
}
@Override
public void failure(RetrofitError retrofitError) {
Log.e("RETROFIT ERROR: ", ""+retrofitError.toString());
}
});
return true;
} catch (Exception e) {
Log.e("REST CALL ERROR: ", "BOOOO");
return false;
}
}
private boolean loginAndSendData(final BgReading bg) {
try {
dexcomShareAuthorizeInterface().getSessionId(new ShareAuthenticationBody(password, login), new Callback() {
@Override
public void success(Object o, Response response) {
Log.d("ShareRest", "Success!! got a response on auth.");
String returnedSessionId = new String(((TypedByteArray) response.getBody()).getBytes()).replace("\"", "");
sendBgData(returnedSessionId, bg);
}
@Override
public void failure(RetrofitError retrofitError) {
Log.e("RETROFIT ERROR: ", ""+retrofitError.toString());
}
});
return true;
} catch (Exception e) {
Log.e("REST CALL ERROR: ", "BOOOO");
return false;
}
}
private void getBgData(String sessionId) {
DataFetcher dataFetcher = new DataFetcher(mContext, sessionId);
dataFetcher.execute((Void) null);
}
private void sendBgData(String sessionId, BgReading bg) {
DataSender dataSender = new DataSender(mContext, sessionId, bg);
dataSender.execute((Void) null);
}
private DexcomShareInterface dexcomShareAuthorizeInterface() {
RestAdapter adapter = authoirizeAdapterBuilder().build();
DexcomShareInterface dexcomShareInterface =
adapter.create(DexcomShareInterface.class);
return dexcomShareInterface;
}
private DexcomShareInterface dexcomShareGetBgInterface() {
RestAdapter adapter = getBgAdapterBuilder().build();
DexcomShareInterface dexcomShareInterface =
adapter.create(DexcomShareInterface.class);
return dexcomShareInterface;
}
private DexcomShareInterface dexcomShareSendBgInterface() {
RestAdapter adapter = authoirizeAdapterBuilder().build();
DexcomShareInterface dexcomShareInterface =
adapter.create(DexcomShareInterface.class);
return dexcomShareInterface;
}
private DexcomShareInterface checkSessionActive() {
RestAdapter adapter = getBgAdapterBuilder().build();
DexcomShareInterface checkSessionActive =
adapter.create(DexcomShareInterface.class);
return checkSessionActive;
}
private RestAdapter.Builder authoirizeAdapterBuilder() {
RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();
adapterBuilder
.setClient(client)
.setLogLevel(RestAdapter.LogLevel.FULL).setLog(new AndroidLog("SHAREREST"))
.setEndpoint("https://share1.dexcom.com/ShareWebServices/Services")
.setRequestInterceptor(authorizationRequestInterceptor)
.setConverter(new GsonConverter(new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create()));
return adapterBuilder;
}
private RestAdapter.Builder getBgAdapterBuilder() {
RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();
adapterBuilder
.setClient(client)
.setLogLevel(RestAdapter.LogLevel.FULL).setLog(new AndroidLog("SHAREREST"))
.setEndpoint("https://share1.dexcom.com/ShareWebServices/Services")
.setRequestInterceptor(getBgRequestInterceptor)
.setConverter(new GsonConverter(new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create()));
return adapterBuilder;
}
RequestInterceptor authorizationRequestInterceptor = new RequestInterceptor() {
@Override
public void intercept(RequestInterceptor.RequestFacade request) {
request.addHeader("User-Agent", "Dexcom Share/3.0.2.11 CFNetwork/711.2.23 Darwin/14.0.0");
request.addHeader("Content-Type", "application/json");
request.addHeader("Accept", "application/json");
}
};
RequestInterceptor getBgRequestInterceptor = new RequestInterceptor() {
@Override
public void intercept(RequestInterceptor.RequestFacade request) {
request.addHeader("User-Agent", "Dexcom Share/3.0.2.11 CFNetwork/711.2.23 Darwin/14.0.0");
request.addHeader("Content-Type", "application/json");
request.addHeader("Content-Length", "0");
request.addHeader("Accept", "application/json");
}
};
public OkHttpClient getOkHttpClient() {
try {
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
} };
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setSslSocketFactory(sslSocketFactory);
okHttpClient.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public OkClient getOkClient (){
OkHttpClient client1 = getOkHttpClient();
OkClient _client = new OkClient(client1);
return _client;
}
public Map queryParamMap(String sessionId) {
Map map = new HashMap();
map.put("sessionID", sessionId);
map.put("minutes", String.valueOf(minutesCount()));
map.put("maxCount", String.valueOf(requestCount()));
return map;
}
public class DataFetcher extends AsyncTask {
Context mContext;
String mSessionId;
DataFetcher(Context context, String sessionId) {
mContext = context;
mSessionId = sessionId;
}
@Override
protected Boolean doInBackground(Void... params) {
try {
try {
final ShareGlucose[] shareGlucoses = dexcomShareGetBgInterface().getShareBg(queryParamMap(mSessionId));
Log.d("REST Success: ", "YAY!");
if(shareGlucoses != null && shareGlucoses.length > 0) {
for (ShareGlucose shareGlucose : shareGlucoses) {
shareGlucose.processShareData(mContext);
}
return true;
}
return false;
} catch (Exception e) {
Log.d("REST CALL ERROR: ", "BOOOO");
return false;
}
}
catch (RetrofitError e) { Log.d("Retrofit Error: ", "BOOOO"); }
catch (Exception ex) { Log.d("Unrecognized Error: ", "BOOOO"); }
return false;
}
}
public class DataSender extends AsyncTask {
Context mContext;
String mSessionId;
BgReading mBg;
DataSender(Context context, String sessionId, BgReading bg) {
mContext = context;
mSessionId = sessionId;
mBg = bg;
}
@Override
protected Boolean doInBackground(Void... params) {
try {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
String receiverSn = preferences.getString("share_key", "SM00000000").toUpperCase();
dexcomShareSendBgInterface().uploadBGRecords(querySessionMap(mSessionId), new ShareUploadPayload(receiverSn, mBg), new Callback() {
@Override
public void success(Object o, Response response) {
Log.d("ShareRest", "Success!! Uploaded!!");
}
@Override
public void failure(RetrofitError retrofitError) {
Log.e("RETROFIT ERROR: ", ""+retrofitError.toString());
}
});
}
catch (RetrofitError e) { Log.d("Retrofit Error: ", "BOOOO"); }
catch (Exception ex) { Log.d("Unrecognized Error: ", "BOOOO"); }
return false;
}
}
public int requestCount() {
BgReading bg = BgReading.last();
if(bg != null) {
return 20;
} else if (bg.timestamp < new Date().getTime()) {
return Math.min((int) Math.ceil(((new Date().getTime() - bg.timestamp) / (5 * 1000 * 60))), 10);
} else {
return 1;
}
}
public int minutesCount() {
BgReading bg = BgReading.last();
if(bg != null && bg.timestamp < new Date().getTime()) {
return Math.min((int) Math.ceil(((new Date().getTime() - bg.timestamp) / (1000 * 60))), 1440);
} else {
return 1440;
}
}
public Map querySessionMap(String sessionId) {
Map map = new HashMap();
map.put("sessionID", sessionId);
return map;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ShareModels/ShareUploadPayload.java
================================================
package com.eveningoutpost.dexdrip.ShareModels;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.google.gson.annotations.Expose;
import java.util.ArrayList;
import java.util.List;
/**
* Created by stephenblack on 3/19/15.
*/
public class ShareUploadPayload {
@Expose
public String SN;
@Expose
public Egv[] Egvs;
@Expose
public long TA = -5;
public ShareUploadPayload(String sn, BgReading bg) {
this.SN = sn;
List egvList = new ArrayList();
egvList.add(new Egv(bg));
this.Egvs = egvList.toArray(new Egv[egvList.size()]);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/ShareTest.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.PacketBuilder;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadData;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadDataShare;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.UtilityModels.DexShareAttributes;
import com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.HM10Attributes;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import rx.Observable;
import rx.functions.Action1;
public class ShareTest extends Activity {
private final static String TAG = ShareTest.class.getSimpleName();
Button button;
Button closeButton;
Button readButton;
Button bondButton;
TextView details;
private String mDeviceName;
private String mDeviceAddress;
private boolean is_connected = false;
private boolean reconnecting = false;
SharedPreferences prefs;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private ForegroundServiceStarter foregroundServiceStarter;
private int mConnectionState = STATE_DISCONNECTED;
private BluetoothDevice device;
int mStartMode;
private Context mContext = null;
private static final int STATE_DISCONNECTED = BluetoothProfile.STATE_DISCONNECTED;
private static final int STATE_DISCONNECTING = BluetoothProfile.STATE_DISCONNECTING;
private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING;
private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED;
private BluetoothGattService mShareService;
private BluetoothGattCharacteristic mAuthenticationCharacteristic;
private BluetoothGattCharacteristic mSendDataCharacteristic;
private BluetoothGattCharacteristic mReceiveDataCharacteristic;
private BluetoothGattCharacteristic mHeartBeatCharacteristic;
private BluetoothGattCharacteristic mCommandCharacteristic;
private BluetoothGattCharacteristic mResponseCharacteristic;
//Gatt Tasks
public final int GATT_NOTHING = 0;
public final int GATT_SETUP = 1;
public final int GATT_WRITING_COMMANDS = 2;
public final int GATT_READING_RESPONSE = 3;
public int successfulWrites;
//RXJAVA FUN
Action1 mDataResponseListener;
public ReadDataShare mReadDataShare;
public int currentGattTask;
public int step;
public List writePackets;
public int recordType;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_share_test);
button = (Button) findViewById(R.id.connect);
closeButton = (Button) findViewById(R.id.closeConnect);
bondButton = (Button) findViewById(R.id.bond);
readButton = (Button) findViewById(R.id.read);
details = (TextView) findViewById(R.id.connection_details);
addListenerOnButton();
addListenerOnCloseButton();
IntentFilter intent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mPairReceiver, intent);
}
@Override
public void onDestroy() {
super.onDestroy();
close();
Log.w(TAG, "CLOSING CONNECTION");
}
public void addListenerOnButton() {
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
attemptConnection();
}
});
readButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
attemptRead();
}
});
bondButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
bond(mBluetoothGatt);
}
});
}
public void addListenerOnCloseButton() {
closeButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
close();
details.setText("");
}
});
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt = gatt;
mConnectionState = STATE_CONNECTED;
ActiveBluetoothDevice.connected();
Log.w(TAG, "Connected to GATT server.");
Log.w(TAG, "Connection state: Bonded - " + device.getBondState());
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
currentGattTask = GATT_SETUP;
mBluetoothGatt.discoverServices();
} else {
device.setPin("000000".getBytes());
device.createBond();
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
ActiveBluetoothDevice.disconnected();
Log.w(TAG, "Disconnected from GATT server.");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "Services Discovered: " + status);
authenticateConnection(gatt);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "Characteristic Read");
byte[] value = characteristic.getValue();
if(value != null) {
Log.w(TAG, "VALUE" + value);
} else {
Log.w(TAG, "Characteristic was null");
}
nextGattStep();
} else {
Log.w(TAG, "Characteristic failed to read");
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.w(TAG, "Characteristic changed");
UUID charUuid = characteristic.getUuid();
Log.w(TAG, "Characteristic Update Received: " + charUuid);
if(charUuid.compareTo(mResponseCharacteristic.getUuid()) == 0) {
Log.w(TAG, "mResponseCharacteristic Update");
}
if(charUuid.compareTo(mCommandCharacteristic.getUuid()) == 0) {
Log.w(TAG, "mCommandCharacteristic Update");
}
if(charUuid.compareTo(mHeartBeatCharacteristic.getUuid()) == 0) {
Log.w(TAG, "mHeartBeatCharacteristic Update");
}
if(charUuid.compareTo(mReceiveDataCharacteristic.getUuid()) == 0) {
Log.w(TAG, "mReceiveDataCharacteristic Update");
byte[] value = characteristic.getValue();
if(value != null) {
Log.w(TAG, "Characteristic: " + value);
Log.w(TAG, "Characteristic: " + value.toString());
Log.w(TAG, "Characteristic getstring: " + characteristic.getStringValue(0));
Log.w(TAG, "SUBSCRIBED TO RESPONSE LISTENER");
Observable.just(characteristic.getValue()).subscribe(mDataResponseListener);
} else {
Log.w(TAG, "Characteristic was null");
}
}
Log.w(TAG, "NEW VALUE: " + characteristic.getValue().toString());
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
Log.w(TAG, "Wrote a discriptor, status: " + status);
if(step == 2 && currentGattTask == GATT_SETUP) {
setListeners(2);
} else if(step == 3) {
setListeners(3);
} else if(step == 4) {
setListeners(4);
} else if(step == 5) {
Log.w(TAG, "Done setting Listeners");
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.w(TAG, "Wrote a characteristic: " + status);
nextGattStep();
}
};
public void attemptConnection() {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (device != null) {
details.append("\nConnection state: " + " Device is not null");
mConnectionState = mBluetoothManager.getConnectionState(device, BluetoothProfile.GATT);
}
Log.w(TAG, "Connection state: " + mConnectionState);
details.append("\nConnection state: " + mConnectionState);
if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_DISCONNECTING) {
ActiveBluetoothDevice btDevice = new Select().from(ActiveBluetoothDevice.class)
.orderBy("_ID desc")
.executeSingle();
if (btDevice != null) {
details.append("\nBT Device: " + btDevice.name);
mDeviceName = btDevice.name;
mDeviceAddress = btDevice.address;
mBluetoothAdapter = mBluetoothManager.getAdapter();
boolean newConnection = true;
if(newConnection) {
is_connected = connect(mDeviceAddress);
details.append("\nConnecting...: ");
}
}
}
}
public void attemptRead() {
final ReadDataShare readData = new ReadDataShare(this);
final Action1 systemTimeListener = new Action1() {
@Override
public void call(Long s) {
Log.d(TAG, "Made the full round trip, got " + s + " as the system time");
Log.d("SYSTTIME", "Made the full round trip, got " + s + " as the system time");
final long addativeSystemTimeOffset = new Date().getTime() - s;
Log.d(TAG, "Made the full round trip, got " + addativeSystemTimeOffset + " offset");
Log.d("SYSTTIME", "Made the full round trip, got " + addativeSystemTimeOffset + " offset");
final Action1 calRecordListener = new Action1() {
@Override
public void call(CalRecord[] calRecords) {
Log.d(TAG, "Made the full round trip, got " + calRecords.length + " Cal Records");
Calibration.create(calRecords, addativeSystemTimeOffset, getApplicationContext());
final Action1 sensorRecordListener = new Action1() {
@Override
public void call(SensorRecord[] sensorRecords) {
Log.d(TAG, "Made the full round trip, got " + sensorRecords.length + " Sensor Records");
BgReading.create(sensorRecords, addativeSystemTimeOffset, getApplicationContext());
final Action1 evgRecordListener = new Action1() {
@Override
public void call(EGVRecord[] egvRecords) {
Log.d(TAG, "Made the full round trip, got " + egvRecords.length + " EVG Records");
BgReading.create(egvRecords, addativeSystemTimeOffset, getApplicationContext());
}
};
readData.getRecentEGVs(evgRecordListener);
}
};
readData.getRecentSensorRecords(sensorRecordListener);
}
};
readData.getRecentCalRecords(calRecordListener);
}
};
readData.readSystemTime(systemTimeListener);
}
public void bond(BluetoothGatt gatt) {
reconnecting = true;
attemptConnection();
}
public boolean connect(final String address) {
details.append("\nConnecting to device");
Log.w(TAG, "CONNECTING TO DEVICE");
if (mBluetoothAdapter == null || address == null) {
details.append("\nBT adapter is null");
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
details.append("\nTrying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
} else {
device = mBluetoothAdapter.getRemoteDevice(address);
device.setPin("000000".getBytes());
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
details.append("\nDevice not found. Unable to connect.");
return false;
}
mBluetoothGatt = device.connectGatt(getApplicationContext(), true, mGattCallback);
Log.w(TAG, "Trying to create a new connection.");
details.append("\nTrying to create a new connection to device");
mConnectionState = STATE_CONNECTING;
return true;
}
}
public void authenticateConnection(BluetoothGatt bluetoothGatt) {
Log.w(TAG, "Trying to auth");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String receiverSn = prefs.getString("share_key", "SM00000000").toUpperCase();
if(bluetoothGatt != null) {
mBluetoothGatt = bluetoothGatt;
mShareService = mBluetoothGatt.getService(DexShareAttributes.CradleService);
if (mShareService != null) {
mAuthenticationCharacteristic = mShareService.getCharacteristic(DexShareAttributes.AuthenticationCode);
if(mAuthenticationCharacteristic != null) {
Log.w(TAG, "Auth Characteristic found: " + mAuthenticationCharacteristic.toString());
mAuthenticationCharacteristic.setValue((receiverSn + "000000").getBytes(StandardCharsets.US_ASCII));
currentGattTask = GATT_SETUP;
step = 1;
bluetoothGatt.writeCharacteristic(mAuthenticationCharacteristic);
} else {
Log.w(TAG, "Authentication Characteristic IS NULL");
}
} else {
Log.w(TAG, "CRADLE SERVICE IS NULL");
}
}
}
public void assignCharacteristics() {
mSendDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageReceiver);
mReceiveDataCharacteristic = mShareService.getCharacteristic(DexShareAttributes.ShareMessageResponse);
mHeartBeatCharacteristic = mShareService.getCharacteristic(DexShareAttributes.HeartBeat);
mCommandCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Command);
mResponseCharacteristic = mShareService.getCharacteristic(DexShareAttributes.Response);
}
public void setListeners(int listener_number) {
Log.w(TAG, "Setting Listener: #" + listener_number);
if(listener_number == 1) {
step = 3;
setCharacteristicIndication(mReceiveDataCharacteristic);
} else if(listener_number == 3) {
setCharacteristicIndication(mResponseCharacteristic);
step = 5;
}
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
public void close() {
disconnect();
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
mConnectionState = STATE_DISCONNECTED;
Log.w(TAG, "bt Disconnected");
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic){ setCharacteristicNotification(characteristic, true);}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
Log.w(TAG, "Characteristic setting notification");
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
Log.w(TAG, "UUID FOUND: " + characteristic.getUuid());
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));
Log.w(TAG, "Descriptor found: " + descriptor.getUuid());
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic){ setCharacteristicIndication(characteristic, true);}
public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic, boolean enabled) {
Log.w(TAG, "Characteristic setting notification");
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
Log.w(TAG, "UUID FOUND: " + characteristic.getUuid());
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HM10Attributes.CLIENT_CHARACTERISTIC_CONFIG));
Log.w(TAG, "Descriptor found: " + descriptor.getUuid());
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
if (state == BluetoothDevice.BOND_BONDED) {
Log.d(TAG, "CALLBACK RECIEVED Bonded");
currentGattTask = GATT_SETUP;
mBluetoothGatt.discoverServices();
} else if (state == BluetoothDevice.BOND_NONE){
Log.d(TAG, "CALLBACK RECIEVED: Not Bonded");
Toast.makeText(getApplicationContext(), "unBonded", Toast.LENGTH_LONG).show();
} else if (state == BluetoothDevice.BOND_BONDING) {
Log.d(TAG, "CALLBACK RECIEVED: Trying to bond");
Toast.makeText(getApplicationContext(), "trying to bond", Toast.LENGTH_LONG).show();
}
}
}
};
public void writeCommand(List packets, int aRecordType, Action1 dataResponseListener) {
mDataResponseListener = dataResponseListener;
successfulWrites = 0;
writePackets = packets;
recordType = aRecordType;
step = 0;
currentGattTask = GATT_WRITING_COMMANDS;
gattWritingStep();
}
private void nextGattStep() {
Log.d(TAG, "Next Gatt Step");
step++;
switch (currentGattTask) {
case GATT_NOTHING:
Log.d(TAG, "Next NOTHING: " + step);
break;
case GATT_SETUP:
Log.d(TAG, "Next GATT SETUP: " + step);
gattSetupStep();
break;
case GATT_WRITING_COMMANDS:
Log.d(TAG, "Next GATT WRITING: " + step);
gattWritingStep();
break;
}
}
public void clearGattTask() {
currentGattTask = GATT_NOTHING;
step = 0;
}
private void gattSetupStep() {
step = 1;
assignCharacteristics();
setListeners(1);
}
private void gattWritingStep() {
Log.d(TAG, "Writing command to the Gatt, step: " + step);
int index = step;
if (index <= (writePackets.size() - 1)) {
Log.d(TAG, "Writing: " + writePackets.get(index) + " index: " + index);
mSendDataCharacteristic.setValue(writePackets.get(index));
mBluetoothGatt.writeCharacteristic(mSendDataCharacteristic);
} else {
clearGattTask();
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/StartNewSensor.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TimePicker;
import android.widget.Toast;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import java.util.Calendar;
import java.util.List;
public class StartNewSensor extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "Start Sensor";
private NavigationDrawerFragment mNavigationDrawerFragment;
public Button button;
public DatePicker dp;
public TimePicker tp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Sensor.isActive() == false) {
setContentView(R.layout.activity_start_new_sensor);
button = (Button)findViewById(R.id.startNewSensor);
dp = (DatePicker)findViewById(R.id.datePicker);
tp = (TimePicker)findViewById(R.id.timePicker);
addListenerOnButton();
} else {
Intent intent = new Intent(this, StopSensor.class);
startActivity(intent);
finish();
}
}
@Override
protected void onResume(){
super.onResume();
NavigationDrawerFragment mNavigationDrawerFragment;
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
NavDrawerBuilder navDrawerBuilder = new NavDrawerBuilder(getApplicationContext());
List menu_option_list = navDrawerBuilder.nav_drawer_options;
int menu_position = menu_option_list.indexOf(menu_name);
if (position != menu_position) {
List intent_list = navDrawerBuilder.nav_drawer_intents;
Intent[] intent_array = intent_list.toArray(new Intent[intent_list.size()]);
startActivity(intent_array[position]);
finish();
}
}
public void addListenerOnButton() {
button = (Button)findViewById(R.id.startNewSensor);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Calendar calendar = Calendar.getInstance();
calendar.set(dp.getYear(), dp.getMonth(), dp.getDayOfMonth(),
tp.getCurrentHour(), tp.getCurrentMinute(), 0);
long startTime = calendar.getTime().getTime();
Sensor sensor = Sensor.create(startTime);
Log.w("NEW SENSOR", "Sensor started at " + startTime);
Toast.makeText(getApplicationContext(), "NEW SENSOR STARTED", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), Home.class);
CollectionServiceStarter.newStart(getApplicationContext());
startActivity(intent);
finish();
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/StopSensor.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.Date;
public class StopSensor extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "Stop Sensor";
private NavigationDrawerFragment mNavigationDrawerFragment;
public Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Sensor.isActive() == false) {
Intent intent = new Intent(this, StartNewSensor.class);
startActivity(intent);
finish();
} else {
setContentView(R.layout.activity_stop_sensor);
button = (Button)findViewById(R.id.stop_sensor);
addListenerOnButton();
}
}
@Override
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
public void addListenerOnButton() {
button = (Button)findViewById(R.id.stop_sensor);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Sensor sensor = Sensor.currentSensor();
sensor.stopped_at = new Date().getTime();
Log.w("NEW SENSOR", "Sensor stopped at " + sensor.stopped_at);
sensor.save();
Toast.makeText(getApplicationContext(), "Sensor stopped", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), Home.class);
startActivity(intent);
finish();
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/SystemStatus.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.widget.DrawerLayout;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import java.lang.reflect.Method;
public class SystemStatus extends Activity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "System Status";
private NavigationDrawerFragment mNavigationDrawerFragment;
public TextView collection_method;
public TextView current_device;
public TextView connection_status;
public TextView notes;
public Button restart_collection_service;
public Button forget_device;
public ImageButton refresh;
public SharedPreferences prefs;
public BluetoothManager mBluetoothManager;
public ActiveBluetoothDevice activeBluetoothDevice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_system_status);
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
collection_method = (TextView)findViewById(R.id.collection_method);
connection_status = (TextView)findViewById(R.id.connection_status);
current_device = (TextView)findViewById(R.id.remembered_device);
notes = (TextView)findViewById(R.id.other_notes);
restart_collection_service = (Button)findViewById(R.id.restart_collection_service);
forget_device = (Button)findViewById(R.id.forget_device);
refresh = (ImageButton)findViewById(R.id.refresh_current_values);
set_current_values();
restartButtonListener();
forgetDeviceListener();
refreshButtonListener();
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
private void set_current_values() {
activeBluetoothDevice = ActiveBluetoothDevice.first();
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
setCollectionMethod();
setCurrentDevice();
setConnectionStatus();
setNotes();
}
public void setCollectionMethod() {
collection_method.setText(prefs.getString("dex_collection_method", "BluetoothWixel"));
}
public void setCurrentDevice() {
if(activeBluetoothDevice != null) {
current_device.setText(activeBluetoothDevice.name);
} else {
current_device.setText("None Set");
}
}
public void setConnectionStatus() {
boolean connected = false;
if (mBluetoothManager != null && activeBluetoothDevice != null) {
for (BluetoothDevice bluetoothDevice : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {
if (bluetoothDevice.getAddress().compareTo(activeBluetoothDevice.address) == 0) {
connected = true;
}
}
}
if(connected) {
connection_status.setText("Connected");
} else {
connection_status.setText("Not Connected");
}
}
public void setNotes() {
if(mBluetoothManager == null) {
notes.append("\n- This device does not seem to support bluetooth");
} else {
if(!mBluetoothManager.getAdapter().isEnabled()) {
notes.append("\n- Bluetooth seems to be turned off");
} else {
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){
notes.append("\n- The android version of this device is not compatible with Bluetooth Low Energy");
}
}
}
}
public void restartButtonListener() {
restart_collection_service.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CollectionServiceStarter.restartCollectionService(getApplicationContext());
set_current_values();
}
});
}
public void forgetDeviceListener() {
forget_device.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(mBluetoothManager != null && ActiveBluetoothDevice.first() != null) {
BluetoothAdapter bluetoothAdapter = mBluetoothManager.getAdapter();
if(bluetoothAdapter != null) {
for( BluetoothDevice bluetoothDevice : bluetoothAdapter.getBondedDevices()) {
if(bluetoothDevice.getAddress().compareTo(ActiveBluetoothDevice.first().address) == 0) {
try {
Method m = bluetoothDevice.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(bluetoothDevice, (Object[]) null);
notes.append("\n- Bluetooth unbonded, if using share tell it to forget your device.");
notes.append("\n- Scan for devices again to set connection back up!");
} catch (Exception e) { Log.e("SystemStatus", e.getMessage()); }
}
}
ActiveBluetoothDevice.forget();
bluetoothAdapter.disable();
bluetoothAdapter.enable();
try {
wait(1000);
} catch(Exception e) {
Log.e("SystemStatus", "Error stalling");
}
}
}
CollectionServiceStarter.restartCollectionService(getApplicationContext());
set_current_values();
}
});
}
public void refreshButtonListener() {
refresh.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
set_current_values();
}
});
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Tables/BgReadingTable.java
================================================
package com.eveningoutpost.dexdrip.Tables;
import android.app.ListActivity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.TextView;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.NavigationDrawerFragment;
import com.eveningoutpost.dexdrip.R;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class BgReadingTable extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "BG Data Table";
private NavigationDrawerFragment mNavigationDrawerFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.raw_data_list);
}
@Override
protected void onResume() {
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
getData();
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
private void getData() {
final List latest = BgReading.latest(50);
ListAdapter adapter = new BgReadingAdapter(this, latest);
this.setListAdapter(adapter);
}
public static class BgReadingCursorAdapterViewHolder {
TextView raw_data_id;
TextView raw_data_value;
TextView raw_data_slope;
TextView raw_data_timestamp;
public BgReadingCursorAdapterViewHolder(View root) {
raw_data_id = (TextView) root.findViewById(R.id.raw_data_id);
raw_data_value = (TextView) root.findViewById(R.id.raw_data_value);
raw_data_slope = (TextView) root.findViewById(R.id.raw_data_slope);
raw_data_timestamp = (TextView) root.findViewById(R.id.raw_data_timestamp);
}
}
public static class BgReadingAdapter extends BaseAdapter {
private final Context context;
private final List readings;
public BgReadingAdapter(Context context, List readings) {
this.context = context;
if(readings == null)
readings = new ArrayList<>();
this.readings = readings;
}
public View newView(Context context, ViewGroup parent) {
final View view = LayoutInflater.from(context).inflate(R.layout.raw_data_list_item, parent, false);
final BgReadingCursorAdapterViewHolder holder = new BgReadingCursorAdapterViewHolder(view);
view.setTag(holder);
return view;
}
public void bindView(View view, Context context, BgReading bgReading) {
final BgReadingCursorAdapterViewHolder tag = (BgReadingCursorAdapterViewHolder) view.getTag();
tag.raw_data_id.setText(Double.toString(bgReading.calculated_value));
tag.raw_data_value.setText(Double.toString(bgReading.age_adjusted_raw_value));
tag.raw_data_slope.setText(Double.toString(bgReading.raw_data));
tag.raw_data_timestamp.setText(new Date(bgReading.timestamp).toString());
}
@Override
public int getCount() {
return readings.size();
}
@Override
public BgReading getItem(int position) {
return readings.get(position);
}
@Override
public long getItemId(int position) {
return getItem(position).getId();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = newView(context, parent);
bindView(convertView, context, getItem(position));
return convertView;
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Tables/CalibrationDataTable.java
================================================
package com.eveningoutpost.dexdrip.Tables;
import android.app.ListActivity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.activeandroid.Cache;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.NavigationDrawerFragment;
import com.eveningoutpost.dexdrip.R;
import java.util.ArrayList;
import java.util.List;
public class CalibrationDataTable extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "Calibration Data Table";
private NavigationDrawerFragment mNavigationDrawerFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.raw_data_list);
}
@Override
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
getData();
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
private void getData() {
final List latest = Calibration.latest(50);
CalibrationDataCursorAdapter adapter = new CalibrationDataCursorAdapter(this, latest);
this.setListAdapter(adapter);
}
public static class CalibrationDataCursorAdapterViewHolder {
TextView raw_data_id;
TextView raw_data_value;
TextView raw_data_slope;
TextView raw_data_timestamp;
public CalibrationDataCursorAdapterViewHolder(View root) {
raw_data_id = (TextView) root.findViewById(R.id.raw_data_id);
raw_data_value = (TextView) root.findViewById(R.id.raw_data_value);
raw_data_slope = (TextView) root.findViewById(R.id.raw_data_slope);
raw_data_timestamp = (TextView) root.findViewById(R.id.raw_data_timestamp);
}
}
public static class CalibrationDataCursorAdapter extends BaseAdapter {
private final Context context;
private final List calibrations;
public CalibrationDataCursorAdapter(Context context, List calibrations) {
this.context = context;
if(calibrations == null)
calibrations = new ArrayList<>();
this.calibrations = calibrations;
}
public View newView(Context context, ViewGroup parent) {
final View view = LayoutInflater.from(context).inflate(R.layout.raw_data_list_item, parent, false);
final CalibrationDataCursorAdapterViewHolder holder = new CalibrationDataCursorAdapterViewHolder(view);
view.setTag(holder);
return view;
}
public void bindView(View view, Context context, Calibration calibration) {
final CalibrationDataCursorAdapterViewHolder tag = (CalibrationDataCursorAdapterViewHolder) view.getTag();
tag.raw_data_id.setText(Double.toString(calibration.bg));
tag.raw_data_value.setText(Double.toString(calibration.estimate_raw_at_time_of_calibration));
tag.raw_data_slope.setText(Double.toString(calibration.slope));
tag.raw_data_timestamp.setText(Double.toString(calibration.intercept));
}
@Override
public int getCount() {
return calibrations.size();
}
@Override
public Calibration getItem(int position) {
return calibrations.get(position);
}
@Override
public long getItemId(int position) {
return getItem(position).getId();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = newView(context, parent);
bindView(convertView, context, getItem(position));
return convertView;
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/Tables/SensorDataTable.java
================================================
package com.eveningoutpost.dexdrip.Tables;
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.view.View;
import android.widget.SimpleCursorAdapter;
import com.activeandroid.Cache;
import com.eveningoutpost.dexdrip.NavigationDrawerFragment;
import com.eveningoutpost.dexdrip.R;
import java.util.ArrayList;
public class SensorDataTable extends ListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "Sensor Data Table";
private NavigationDrawerFragment mNavigationDrawerFragment;
private ArrayList results = new ArrayList();
private View mRootView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.raw_data_list);
}
@Override
protected void onResume(){
super.onResume();
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), menu_name, this);
getData();
}
@Override
public void onNavigationDrawerItemSelected(int position) {
mNavigationDrawerFragment.swapContext(position);
}
private void getData() {
Cursor cursor = Cache.openDatabase().rawQuery("Select * from Sensors order by _ID desc", null);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.raw_data_list_item,
cursor,
new String[] { "started_at", "latest_battery_level", "uuid", "uuid" },
new int[] { R.id.raw_data_id, R.id.raw_data_value , R.id.raw_data_slope, R.id.raw_data_timestamp });
this.setListAdapter(adapter);
// ListView listView = (ListView) findViewById(R.id.list);
// listView.setAdapter(adapter);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UsbConnectedActivity.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.SyncingService;
public class UsbConnectedActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(SyncingService.isG4Connected(getApplicationContext())){
Intent checkInIntent = new Intent(getApplicationContext(), CalibrationCheckInActivity.class);
startActivity(checkInIntent);
finish();
} else {
//TODO: Put check for usb wixel in here as an elseif
Intent homeIntent = new Intent(getApplicationContext(), Home.class);
startActivity(homeIntent);
finish();
}
setContentView(R.layout.activity_usb_connected);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgGraphBuilder.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.preference.PreferenceManager;
import android.text.format.DateFormat;
import com.eveningoutpost.dexdrip.Models.BgReading;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import lecho.lib.hellocharts.model.Axis;
import lecho.lib.hellocharts.model.AxisValue;
import lecho.lib.hellocharts.model.Line;
import lecho.lib.hellocharts.model.LineChartData;
import lecho.lib.hellocharts.model.PointValue;
import lecho.lib.hellocharts.model.Viewport;
import lecho.lib.hellocharts.util.Utils;
import lecho.lib.hellocharts.view.Chart;
/**
* Created by stephenblack on 11/15/14.
*/
public class BgGraphBuilder {
public int fuzzer = (1000 * 30 * 5);
public double end_time = (new Date().getTime() + (60000 * 10)) / fuzzer;
public double start_time = end_time - ((60000 * 60 * 24)) / fuzzer;
public Context context;
public SharedPreferences prefs;
public double highMark;
public double lowMark;
public double defaultMinY;
public double defaultMaxY;
public boolean doMgdl;
final int pointSize;
final int axisTextSize;
final int previewAxisTextSize;
final int hoursPreviewStep;
private double endHour;
private final int numValues =(60/5)*24;
private final List bgReadings = BgReading.latestForGraph( numValues, (start_time * fuzzer));
private List inRangeValues = new ArrayList();
private List highValues = new ArrayList();
private List lowValues = new ArrayList();
private List rawInterpretedValues = new ArrayList();
public Viewport viewport;
public BgGraphBuilder(Context context){
this.context = context;
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
this.highMark = Double.parseDouble(prefs.getString("highValue", "170"));
this.lowMark = Double.parseDouble(prefs.getString("lowValue", "70"));
this.doMgdl = (prefs.getString("units", "mgdl").compareTo("mgdl") == 0);
defaultMinY = unitized(40);
defaultMaxY = unitized(250);
pointSize = isXLargeTablet() ? 5 : 3;
axisTextSize = isXLargeTablet() ? 20 : Axis.DEFAULT_TEXT_SIZE_SP;
previewAxisTextSize = isXLargeTablet() ? 12 : 5;
hoursPreviewStep = isXLargeTablet() ? 2 : 1;
}
public LineChartData lineData() {
LineChartData lineData = new LineChartData(defaultLines());
lineData.setAxisYLeft(yAxis());
lineData.setAxisXBottom(xAxis());
return lineData;
}
public LineChartData previewLineData() {
LineChartData previewLineData = new LineChartData(lineData());
previewLineData.setAxisYLeft(yAxis());
previewLineData.setAxisXBottom(previewXAxis());
previewLineData.getLines().get(4).setPointRadius(2);
previewLineData.getLines().get(5).setPointRadius(2);
previewLineData.getLines().get(6).setPointRadius(2);
return previewLineData;
}
public List defaultLines() {
addBgReadingValues();
List lines = new ArrayList();
lines.add(minShowLine());
lines.add(maxShowLine());
lines.add(highLine());
lines.add(lowLine());
lines.add(inRangeValuesLine());
lines.add(lowValuesLine());
lines.add(highValuesLine());
lines.add(rawInterpretedLine());
return lines;
}
public Line highValuesLine() {
Line highValuesLine = new Line(highValues);
highValuesLine.setColor(Utils.COLOR_ORANGE);
highValuesLine.setHasLines(false);
highValuesLine.setPointRadius(pointSize);
highValuesLine.setHasPoints(true);
return highValuesLine;
}
public Line lowValuesLine() {
Line lowValuesLine = new Line(lowValues);
lowValuesLine.setColor(Color.parseColor("#C30909"));
lowValuesLine.setHasLines(false);
lowValuesLine.setPointRadius(pointSize);
lowValuesLine.setHasPoints(true);
return lowValuesLine;
}
public Line inRangeValuesLine() {
Line inRangeValuesLine = new Line(inRangeValues);
inRangeValuesLine.setColor(Utils.COLOR_BLUE);
inRangeValuesLine.setHasLines(false);
inRangeValuesLine.setPointRadius(pointSize);
inRangeValuesLine.setHasPoints(true);
return inRangeValuesLine;
}
public Line rawInterpretedLine() {
Line line = new Line(rawInterpretedValues);
line.setHasLines(false);
line.setPointRadius(1);
line.setHasPoints(true);
return line;
}
private void addBgReadingValues() {
for (BgReading bgReading : bgReadings) {
if (bgReading.raw_calculated != 0 && prefs.getBoolean("interpret_raw", false)) {
rawInterpretedValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(bgReading.raw_calculated)));
} else if (bgReading.calculated_value >= 400) {
highValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(400)));
} else if (unitized(bgReading.calculated_value) >= highMark) {
highValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(bgReading.calculated_value)));
} else if (unitized(bgReading.calculated_value) >= lowMark) {
inRangeValues.add(new PointValue((float) (bgReading.timestamp/fuzzer), (float) unitized(bgReading.calculated_value)));
} else if (bgReading.calculated_value >= 40) {
lowValues.add(new PointValue((float)(bgReading.timestamp/fuzzer), (float) unitized(bgReading.calculated_value)));
} else if (bgReading.calculated_value > 13) {
lowValues.add(new PointValue((float)(bgReading.timestamp/fuzzer), (float) unitized(40)));
}
}
}
public Line highLine() {
List highLineValues = new ArrayList();
highLineValues.add(new PointValue((float)start_time, (float)highMark));
highLineValues.add(new PointValue((float)end_time, (float)highMark));
Line highLine = new Line(highLineValues);
highLine.setHasPoints(false);
highLine.setStrokeWidth(1);
highLine.setColor(Utils.COLOR_ORANGE);
return highLine;
}
public Line lowLine() {
List lowLineValues = new ArrayList();
lowLineValues.add(new PointValue((float)start_time, (float)lowMark));
lowLineValues.add(new PointValue((float)end_time, (float)lowMark));
Line lowLine = new Line(lowLineValues);
lowLine.setHasPoints(false);
lowLine.setAreaTransparency(50);
lowLine.setColor(Color.parseColor("#C30909"));
lowLine.setStrokeWidth(1);
lowLine.setFilled(true);
return lowLine;
}
public Line maxShowLine() {
List maxShowValues = new ArrayList();
maxShowValues.add(new PointValue((float)start_time, (float)defaultMaxY));
maxShowValues.add(new PointValue((float)end_time, (float)defaultMaxY));
Line maxShowLine = new Line(maxShowValues);
maxShowLine.setHasLines(false);
maxShowLine.setHasPoints(false);
return maxShowLine;
}
public Line minShowLine() {
List minShowValues = new ArrayList();
minShowValues.add(new PointValue((float)start_time, (float)defaultMinY));
minShowValues.add(new PointValue((float)end_time, (float)defaultMinY));
Line minShowLine = new Line(minShowValues);
minShowLine.setHasPoints(false);
minShowLine.setHasLines(false);
return minShowLine;
}
/////////AXIS RELATED//////////////
public Axis yAxis() {
Axis yAxis = new Axis();
yAxis.setAutoGenerated(false);
List axisValues = new ArrayList();
for(int j = 1; j <= 12; j += 1) {
if (doMgdl) {
axisValues.add(new AxisValue(j * 50));
} else {
axisValues.add(new AxisValue(j*2));
}
}
yAxis.setValues(axisValues);
yAxis.setHasLines(true);
yAxis.setMaxLabelChars(5);
yAxis.setInside(true);
yAxis.setTextSize(axisTextSize);
return yAxis;
}
public Axis xAxis() {
Axis xAxis = new Axis();
xAxis.setAutoGenerated(false);
List xAxisValues = new ArrayList();
GregorianCalendar now = new GregorianCalendar();
GregorianCalendar today = new GregorianCalendar(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH));
final java.text.DateFormat timeFormat = hourFormat();
timeFormat.setTimeZone(TimeZone.getDefault());
double start_hour_block = today.getTime().getTime();
double timeNow = new Date().getTime();
for(int l=0; l<=24; l++) {
if ((start_hour_block + (60000 * 60 * (l))) < timeNow) {
if((start_hour_block + (60000 * 60 * (l + 1))) >= timeNow) {
endHour = start_hour_block + (60000 * 60 * (l));
l=25;
}
}
}
for(int l=0; l<=24; l++) {
double timestamp = (endHour - (60000 * 60 * l));
xAxisValues.add(new AxisValue((long)(timestamp/fuzzer), (timeFormat.format(timestamp)).toCharArray()));
}
xAxis.setValues(xAxisValues);
xAxis.setHasLines(true);
xAxis.setTextSize(axisTextSize);
return xAxis;
}
private SimpleDateFormat hourFormat() {
return new SimpleDateFormat(DateFormat.is24HourFormat(context) ? "HH" : "h a");
}
private boolean isXLargeTablet() {
return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
public Axis previewXAxis(){
List previewXaxisValues = new ArrayList();
final java.text.DateFormat timeFormat = hourFormat();
timeFormat.setTimeZone(TimeZone.getDefault());
for(int l=0; l<=24; l+=hoursPreviewStep) {
double timestamp = (endHour - (60000 * 60 * l));
previewXaxisValues.add(new AxisValue((long)(timestamp/fuzzer), (timeFormat.format(timestamp)).toCharArray()));
}
Axis previewXaxis = new Axis();
previewXaxis.setValues(previewXaxisValues);
previewXaxis.setHasLines(true);
previewXaxis.setTextSize(previewAxisTextSize);
return previewXaxis;
}
/////////VIEWPORT RELATED//////////////
public Viewport advanceViewport(Chart chart, Chart previewChart) {
viewport = new Viewport(previewChart.getMaximumViewport());
viewport.inset((float)((86400000 / 2.5)/fuzzer), 0);
double distance_to_move = ((new Date().getTime())/fuzzer) - viewport.left - (((viewport.right - viewport.left) /2));
viewport.offset((float) distance_to_move, 0);
return viewport;
}
public double unitized(double value) {
if(doMgdl) {
return value;
} else {
return mmolConvert(value);
}
}
public String unitized_string(double value) {
DecimalFormat df = new DecimalFormat("#");
if (value >= 400) {
return "HIGH";
} else if (value >= 40) {
if(doMgdl) {
df.setMaximumFractionDigits(0);
return df.format(value);
} else {
df.setMaximumFractionDigits(1);
return df.format(mmolConvert(value));
}
} else if (value > 12) {
return "LOW";
} else {
switch((int)value) {
case 0:
return "??0";
case 1:
return "?SN";
case 2:
return "??2";
case 3:
return "?NA";
case 5:
return "?NC";
case 6:
return "?CD";
case 9:
return "?AD";
case 12:
return "?RF";
default:
return "???";
}
}
}
public String unitizedDeltaString(double value) {
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(1);
String delta_sign = "";
if (value > 0.1) { delta_sign = "+"; }
if(doMgdl) {
return delta_sign + df.format(unitized(value)) + " mg/dl";
} else {
return delta_sign + df.format(unitized(value)) + " mmol";
}
}
public double mmolConvert(double mgdl) {
return mgdl * Constants.MGDL_TO_MMOLL;
}
public String unit() {
if(doMgdl){
return "mg/dl";
} else {
return "mmol";
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgSendQueue.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.provider.BaseColumns;
import android.util.Log;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.ShareModels.ShareRest;
import com.eveningoutpost.dexdrip.widgetUpdateService;
import java.util.List;
/**
* Created by stephenblack on 11/7/14.
*/
@Table(name = "BgSendQueue", id = BaseColumns._ID)
public class BgSendQueue extends Model {
@Column(name = "bgReading", index = true)
public BgReading bgReading;
@Column(name = "success", index = true)
public boolean success;
@Column(name = "mongo_success", index = true)
public boolean mongo_success;
@Column(name = "operation_type")
public String operation_type;
public static BgSendQueue nextBgJob() {
return new Select()
.from(BgSendQueue.class)
.where("success = ?", false)
.orderBy("_ID desc")
.limit(1)
.executeSingle();
}
public static List queue() {
return new Select()
.from(BgSendQueue.class)
.where("success = ?", false)
.orderBy("_ID asc")
.limit(20)
.execute();
}
public static List mongoQueue() {
return new Select()
.from(BgSendQueue.class)
.where("mongo_success = ?", false)
.where("operation_type = ?", "create")
.orderBy("_ID asc")
.limit(30)
.execute();
}
public static void addToQueue(BgReading bgReading, String operation_type, Context context) {
PowerManager powerManager = (PowerManager) context.getSystemService(context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"sendQueue");
wakeLock.acquire();
BgSendQueue bgSendQueue = new BgSendQueue();
bgSendQueue.operation_type = operation_type;
bgSendQueue.bgReading = bgReading;
bgSendQueue.success = false;
bgSendQueue.mongo_success = false;
bgSendQueue.save();
Log.d("BGQueue", "New value added to queue!");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Intent updateIntent = new Intent(Intents.ACTION_NEW_BG_ESTIMATE_NO_DATA);
context.sendBroadcast(updateIntent);
context.startService(new Intent(context, widgetUpdateService.class));
if (prefs.getBoolean("cloud_storage_mongodb_enable", false) || prefs.getBoolean("cloud_storage_api_enable", false)) {
Log.w("SENSOR QUEUE:", String.valueOf(bgSendQueue.mongo_success));
if (operation_type.compareTo("create") == 0) {
MongoSendTask task = new MongoSendTask(context, bgSendQueue);
task.execute();
}
}
if(prefs.getBoolean("broadcast_data_through_intents", false)) {
Log.i("SENSOR QUEUE:", "Broadcast data");
final Bundle bundle = new Bundle();
bundle.putDouble(Intents.EXTRA_BG_ESTIMATE, bgReading.calculated_value);
bundle.putDouble(Intents.EXTRA_BG_SLOPE, bgReading.calculated_value_slope);
if(bgReading.hide_slope) {
bundle.putString(Intents.EXTRA_BG_SLOPE_NAME, "9");
} else {
bundle.putString(Intents.EXTRA_BG_SLOPE_NAME, bgReading.slopeName());
}
bundle.putInt(Intents.EXTRA_SENSOR_BATTERY, getBatteryLevel(context));
bundle.putLong(Intents.EXTRA_TIMESTAMP, bgReading.timestamp);
Intent intent = new Intent(Intents.ACTION_NEW_BG_ESTIMATE);
intent.putExtras(bundle);
context.sendBroadcast(intent, Intents.RECEIVER_PERMISSION);
}
if(prefs.getBoolean("broadcast_to_pebble", false)) {
PebbleSync pebbleSync = new PebbleSync();
pebbleSync.sendData(context, bgReading);
}
if(prefs.getBoolean("share_upload", false)) {
ShareRest shareRest = new ShareRest(context);
Log.w("ShareRest", "About to call ShareRest!!");
shareRest.sendBgData(bgReading);
}
wakeLock.release();
}
public void markMongoSuccess() {
mongo_success = true;
save();
}
public static int getBatteryLevel(Context context) {
Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if(level == -1 || scale == -1) {
return 50;
}
return (int)(((float)level / (float)scale) * 100.0f);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CalibrationSendQueue.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.provider.BaseColumns;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.Models.Calibration;
import java.util.List;
/**
* Created by stephenblack on 11/7/14.
*/
@Table(name = "CalibrationSendQueue", id = BaseColumns._ID)
public class CalibrationSendQueue extends Model {
@Column(name = "calibration", index = true)
public Calibration calibration;
@Column(name = "success", index = true)
public boolean success;
@Column(name = "mongo_success", index = true)
public boolean mongo_success;
public static CalibrationSendQueue nextCalibrationJob() {
CalibrationSendQueue job = new Select()
.from(CalibrationSendQueue.class)
.where("success = ?", false)
.orderBy("_ID desc")
.limit(1)
.executeSingle();
return job;
}
public static List queue() {
return new Select()
.from(CalibrationSendQueue.class)
.where("success = ?", false)
.orderBy("_ID asc")
.execute();
}
public static List mongoQueue() {
return new Select()
.from(CalibrationSendQueue.class)
.where("mongo_success = ?", false)
.orderBy("_ID asc")
.limit(30)
.execute();
}
public static void addToQueue(Calibration calibration, Context context) {
CalibrationSendQueue calibrationSendQueue = new CalibrationSendQueue();
calibrationSendQueue.calibration = calibration;
calibrationSendQueue.success = false;
calibrationSendQueue.mongo_success = false;
calibrationSendQueue.save();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean("cloud_storage_mongodb_enable", false) || prefs.getBoolean("cloud_storage_api_enable", false)) {
MongoSendTask task = new MongoSendTask(context, calibrationSendQueue);
task.execute();
}
}
public void markMongoSuccess() {
mongo_success = true;
save();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/CollectionServiceStarter.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.eveningoutpost.dexdrip.Services.DexCollectionService;
import com.eveningoutpost.dexdrip.Services.DexShareCollectionService;
import com.eveningoutpost.dexdrip.Services.WixelReader;
/**
* Created by stephenblack on 12/22/14.
*/
public class CollectionServiceStarter {
private Context mContext;
public static boolean isBTWixel(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String collection_method = prefs.getString("dex_collection_method", "BluetoothWixel");
if(collection_method.compareTo("BluetoothWixel") == 0) {
return true;
}
return false;
}
public static boolean isBTShare(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String collection_method = prefs.getString("dex_collection_method", "BluetoothWixel");
if(collection_method.compareTo("DexcomShare") == 0) {
return true;
}
return false;
}
public static boolean isWifiWixel(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String collection_method = prefs.getString("dex_collection_method", "BluetoothWixel");
if(collection_method.compareTo("WifiWixel") == 0) {
return true;
}
return false;
}
public static void newStart(Context context) {
CollectionServiceStarter collectionServiceStarter = new CollectionServiceStarter(context);
collectionServiceStarter.start(context);
}
public void start(Context context) {
mContext = context;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
String collection_method = prefs.getString("dex_collection_method", "BluetoothWixel");
if(isBTWixel(context)) {
Log.d("DexDrip", "Starting bt wixel collector");
stopWifWixelThread();
stopBtShareService();
startBtWixelService();
} else if(isWifiWixel(context)){
Log.d("DexDrip", "Starting wifi wixel collector");
stopBtWixelService();
stopBtShareService();
startWifWixelThread();
} else if(isBTShare(context)) {
Log.d("DexDrip", "Starting bt share collector");
stopBtWixelService();
stopWifWixelThread();
startBtShareService();
}
Log.d("ColServiceStarter", collection_method);
}
public CollectionServiceStarter(Context context) {
mContext = context;
}
public static void restartCollectionService(Context context) {
CollectionServiceStarter collectionServiceStarter = new CollectionServiceStarter(context);
collectionServiceStarter.stopBtShareService();
collectionServiceStarter.stopBtWixelService();
collectionServiceStarter.stopWifWixelThread();
collectionServiceStarter.start(context);
}
private void startBtWixelService() {
Log.d("ColServiceStarter", "starting bt wixel service");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
mContext.startService(new Intent(mContext, DexCollectionService.class));
}
}
private void stopBtWixelService() {
Log.d("ColServiceStarter", "stopping bt wixel service");
mContext.stopService(new Intent(mContext, DexCollectionService.class));
}
private void startBtShareService() {
Log.d("ColServiceStarter", "starting bt share service");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
mContext.startService(new Intent(mContext, DexShareCollectionService.class));
}
}
private void stopBtShareService() {
Log.d("ColServiceStarter", "stopping bt share service");
mContext.stopService(new Intent(mContext, DexShareCollectionService.class));
}
private void startWifWixelThread() {
WixelReader.sStart(mContext);
}
private void stopWifWixelThread() {
WixelReader.sStop();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/Constants.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
/**
* Various constants
*/
public class Constants {
public static final double MMOLL_TO_MGDL = 18.0182;
public static final double MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL;
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/DexShareAttributes.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import java.math.BigInteger;
import java.util.UUID;
/**
* Created by stephenblack on 2/4/15.
*/
public class DexShareAttributes {
//Share Service String
public static final UUID CradleService= UUID.fromString("F0ABA0B1-EBFA-F96F-28DA-076C35A521DB");
//Share Characteristic Strings
public static final UUID AuthenticationCode = UUID.fromString("F0ABACAC-EBFA-F96F-28DA-076C35A521DB");
public static final UUID ShareMessageReceiver= UUID.fromString("F0ABB20A-EBFA-F96F-28DA-076C35A521DB"); // Max 20 Bytes - Writable
public static final UUID ShareMessageResponse= UUID.fromString("F0ABB20B-EBFA-F96F-28DA-076C35A521DB"); // Max 20 Bytes
public static final UUID Command= UUID.fromString("F0ABB0CC-EBFA-F96F-28DA-076C35A521DB");
public static final UUID Response= UUID.fromString("F0ABB0CD-EBFA-F96F-28DA-076C35A521DB"); // Writable?
public static final UUID HeartBeat= UUID.fromString("F0AB2B18-EBFA-F96F-28DA-076C35A521DB");
//Possible new uuids???? 60bfxxxx-60b0-4d4f-0000-000160c48d70
public static final UUID CradleService2= UUID.fromString("F0ACA0B1-EBFA-F96F-28DA-076C35A521DB");
public static final UUID AuthenticationCode2 = UUID.fromString("F0ACACAC-EBFA-F96F-28DA-076C35A521DB"); // read, write
public static final UUID ShareMessageReceiver2= UUID.fromString("F0ACB20A-EBFA-F96F-28DA-076C35A521DB"); // read, write
public static final UUID ShareMessageResponse2= UUID.fromString("F0ACB20B-EBFA-F96F-28DA-076C35A521DB"); // indicate, read
public static final UUID Command2= UUID.fromString("F0ACB0CC-EBFA-F96F-28DA-076C35A521DB"); // read, write
public static final UUID Response2= UUID.fromString("F0ACB0CD-EBFA-F96F-28DA-076C35A521DB"); // indicate, read, write
public static final UUID HeartBeat2= UUID.fromString("F0AC2B18-EBFA-F96F-28DA-076C35A521DB"); // notify, read
//Device Info
public static final UUID DeviceService= UUID.fromString("00001804-0000-1000-8000-00805f9b34fb");
public static final UUID PowerLevel= UUID.fromString("00002a07-0000-1000-8000-00805f9b34fb");
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/ForegroundServiceStarter.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.eveningoutpost.dexdrip.Home;
import com.eveningoutpost.dexdrip.R;
import com.eveningoutpost.dexdrip.Services.DexShareCollectionService;
/**
* Created by stephenblack on 12/25/14.
*/
public class ForegroundServiceStarter {
private Service mService;
private Context mContext;
private boolean run_service_in_foreground = false;
private int FOREGROUND_ID = 8811;
public ForegroundServiceStarter(Context context, Service service) {
mContext = context;
mService = service;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
run_service_in_foreground = prefs.getBoolean("run_service_in_foreground", false);
}
private Notification notification() {
Intent intent = new Intent(mContext, Home.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
stackBuilder.addParentStack(Home.class);
stackBuilder.addNextIntent(intent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder b=new NotificationCompat.Builder(mService);
b.setOngoing(true);
b.setCategory(Notification.CATEGORY_SERVICE);
// Hide this notification "below the fold" on L+
b.setPriority(Notification.PRIORITY_MIN);
// Don't show this notification on the lock screen on L+
b.setVisibility(Notification.VISIBILITY_SECRET);
b.setContentTitle("xDrip is Running")
.setContentText("xDrip Data collection service is running.")
.setSmallIcon(R.drawable.ic_action_communication_invert_colors_on);
b.setContentIntent(resultPendingIntent);
return(b.build());
}
public void start() {
if (run_service_in_foreground) {
Log.e("FOREGROUND", "should be moving to foreground");
mService.startForeground(FOREGROUND_ID, notification());
}
}
public void stop() {
if (run_service_in_foreground) {
Log.e("FOREGROUND", "should be moving out of foreground");
mService.stopForeground(true);
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/HM10Attributes.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
/**
* Created by stephenblack on 10/26/14.
*/
public class HM10Attributes {
public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
public static String HM_10_SERVICE = "0000ffe0-0000-1000-8000-00805f9b34fb";
public static String HM_RX_TX = "0000ffe1-0000-1000-8000-00805f9b34fb";
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/Intents.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
/**
* For integration.
*/
public interface Intents {
String RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE";
String ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate";
String EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate";
String EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope";
String EXTRA_BG_SLOPE_NAME = "com.eveningoutpost.dexdrip.Extras.BgSlopeName";
String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/MongoSendTask.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.Services.SyncService;
import java.util.ArrayList;
import java.util.List;
/**
* Created by stephenblack on 12/19/14.
*/
public class MongoSendTask extends AsyncTask {
private Context context;
public List bgsQueue = new ArrayList();
public List calibrationsQueue = new ArrayList();
private Exception exception;
public MongoSendTask(Context pContext, BgSendQueue bgSendQueue) {
bgsQueue.add(bgSendQueue);
context = pContext;
}
public MongoSendTask(Context pContext, CalibrationSendQueue calibrationSendQueue) {
calibrationsQueue.add(calibrationSendQueue);
context = pContext;
}
public MongoSendTask(Context pContext) {
calibrationsQueue = CalibrationSendQueue.mongoQueue();
bgsQueue = BgSendQueue.mongoQueue();
context = pContext;
}
public SyncService doInBackground(String... urls) {
try {
List bgReadings = new ArrayList();
List calibrations = new ArrayList();
for (CalibrationSendQueue job : calibrationsQueue) {
calibrations.add(job.calibration);
}
for (BgSendQueue job : bgsQueue) {
bgReadings.add(job.bgReading);
}
if(bgReadings.size() + calibrations.size() > 0) {
NightscoutUploader uploader = new NightscoutUploader(context);
boolean uploadStatus = uploader.upload(bgReadings, calibrations, calibrations);
if (uploadStatus) {
for (CalibrationSendQueue calibration : calibrationsQueue) {
calibration.markMongoSuccess();
}
for (BgSendQueue bgReading : bgsQueue) {
bgReading.markMongoSuccess();
}
}
}
} catch (Exception e) {
this.exception = e;
return null;
}
return new SyncService();
}
// protected void onPostExecute(RSSFeed feed) {
// // TODO: check this.exception
// // TODO: do something with the feed
// }
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/NightscoutUploader.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.BatteryManager;
import android.preference.PreferenceManager;
import android.util.Log;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.WriteConcern;
import org.apache.http.Header;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONObject;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
/**
* THIS CLASS WAS BUILT BY THE NIGHTSCOUT GROUP FOR THEIR NIGHTSCOUT ANDROID UPLOADER
* https://github.com/nightscout/android-uploader/
* I have modified this class to make it fit my needs
* Modifications include field remappings and lists instead of arrays
* A DTO would probably be a better future implementation
* -Stephen Black
*/
public class NightscoutUploader {
private static final String TAG = NightscoutUploader.class.getSimpleName();
private static final int SOCKET_TIMEOUT = 60000;
private static final int CONNECTION_TIMEOUT = 30000;
private Context mContext;
private Boolean enableRESTUpload;
private Boolean enableMongoUpload;
private SharedPreferences prefs;
public NightscoutUploader(Context context) {
mContext = context;
prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
enableRESTUpload = prefs.getBoolean("cloud_storage_api_enable", false);
enableMongoUpload = prefs.getBoolean("cloud_storage_mongodb_enable", false);
}
public boolean upload(BgReading glucoseDataSet, Calibration meterRecord, Calibration calRecord) {
List glucoseDataSets = new ArrayList();
glucoseDataSets.add(glucoseDataSet);
List meterRecords = new ArrayList();
meterRecords.add(meterRecord);
List calRecords = new ArrayList();
calRecords.add(calRecord);
return upload(glucoseDataSets, meterRecords, calRecords);
}
public boolean upload(List glucoseDataSets, List meterRecords, List calRecords) {
boolean mongoStatus = false;
boolean apiStatus = false;
if (enableRESTUpload) {
long start = System.currentTimeMillis();
Log.i(TAG, String.format("Starting upload of %s record using a REST API", glucoseDataSets.size()));
apiStatus = doRESTUpload(prefs, glucoseDataSets, meterRecords, calRecords);
Log.i(TAG, String.format("Finished upload of %s record using a REST API in %s ms", glucoseDataSets.size(), System.currentTimeMillis() - start));
}
if (enableMongoUpload) {
double start = new Date().getTime();
mongoStatus = doMongoUpload(prefs, glucoseDataSets, meterRecords, calRecords);
Log.i(TAG, String.format("Finished upload of %s record using a Mongo in %s ms", glucoseDataSets.size() + meterRecords.size(), System.currentTimeMillis() - start));
}
return apiStatus || mongoStatus;
}
private boolean doRESTUpload(SharedPreferences prefs, List glucoseDataSets, List meterRecords, List calRecords) {
String baseURLSettings = prefs.getString("cloud_storage_api_base", "");
ArrayList baseURIs = new ArrayList();
try {
for (String baseURLSetting : baseURLSettings.split(" ")) {
String baseURL = baseURLSetting.trim();
if (baseURL.isEmpty()) continue;
baseURIs.add(baseURL + (baseURL.endsWith("/") ? "" : "/"));
}
} catch (Exception e) {
Log.e(TAG, "Unable to process API Base URL");
return false;
}
for (String baseURI : baseURIs) {
try {
doRESTUploadTo(baseURI, glucoseDataSets, meterRecords, calRecords);
} catch (Exception e) {
Log.e(TAG, "Unable to do REST API Upload");
return false;
}
}
return true;
}
private void doRESTUploadTo(String baseURI, List glucoseDataSets, List meterRecords, List calRecords) {
try {
int apiVersion = 0;
if (baseURI.endsWith("/v1/")) apiVersion = 1;
String baseURL = null;
String secret = null;
String[] uriParts = baseURI.split("@");
if (uriParts.length == 1 && apiVersion == 0) {
baseURL = uriParts[0];
} else if (uriParts.length == 1 && apiVersion > 0) {
throw new Exception("Starting with API v1, a pass phase is required");
} else if (uriParts.length == 2 && apiVersion > 0) {
secret = uriParts[0];
baseURL = uriParts[1];
} else {
throw new Exception("Unexpected baseURI");
}
String postURL = baseURL + "entries";
Log.i(TAG, "postURL: " + postURL);
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT);
HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
DefaultHttpClient httpclient = new DefaultHttpClient(params);
HttpPost post = new HttpPost(postURL);
Header apiSecretHeader = null;
if (apiVersion > 0) {
if (secret == null || secret.isEmpty()) {
throw new Exception("Starting with API v1, a pass phase is required");
} else {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] bytes = secret.getBytes("UTF-8");
digest.update(bytes, 0, bytes.length);
bytes = digest.digest();
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b: bytes) {
sb.append(String.format("%02x", b & 0xff));
}
String token = sb.toString();
apiSecretHeader = new BasicHeader("api-secret", token);
}
}
if (apiSecretHeader != null) {
post.setHeader(apiSecretHeader);
}
for (BgReading record : glucoseDataSets) {
JSONObject json = new JSONObject();
try {
if (apiVersion >= 1)
populateV1APIBGEntry(json, record);
else
populateLegacyAPIEntry(json, record);
} catch (Exception e) {
Log.w(TAG, "Unable to populate entry");
continue;
}
String jsonString = json.toString();
Log.i(TAG, "SGV JSON: " + jsonString);
try {
StringEntity se = new StringEntity(jsonString);
post.setEntity(se);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
ResponseHandler responseHandler = new BasicResponseHandler();
httpclient.execute(post, responseHandler);
} catch (Exception e) {
Log.w(TAG, "Unable to populate entry");
}
}
if (apiVersion >= 1) {
for (Calibration record : meterRecords) {
JSONObject json = new JSONObject();
try {
populateV1APIMeterReadingEntry(json, record);
} catch (Exception e) {
Log.w(TAG, "Unable to populate entry");
continue;
}
String jsonString = json.toString();
Log.i(TAG, "MBG JSON: " + jsonString);
try {
StringEntity se = new StringEntity(jsonString);
post.setEntity(se);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
ResponseHandler responseHandler = new BasicResponseHandler();
httpclient.execute(post, responseHandler);
} catch (Exception e) {
Log.w(TAG, "Unable to post data");
}
}
}
if (apiVersion >= 1) {
for (Calibration calRecord : calRecords) {
JSONObject json = new JSONObject();
try {
populateV1APICalibrationEntry(json, calRecord);
} catch (Exception e) {
Log.w(TAG, "Unable to populate entry");
continue;
}
String jsonString = json.toString();
Log.i(TAG, "CAL JSON: " + jsonString);
try {
StringEntity se = new StringEntity(jsonString);
post.setEntity(se);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
ResponseHandler responseHandler = new BasicResponseHandler();
httpclient.execute(post, responseHandler);
} catch (Exception e) {
Log.w(TAG, "Unable to post data");
}
}
}
// TODO: this is a quick port from the original code and needs to be checked before release
postDeviceStatus(baseURL, apiSecretHeader, httpclient);
} catch (Exception e) {
Log.w(TAG, "Unable to post data");
}
}
private void populateV1APIBGEntry(JSONObject json, BgReading record) throws Exception {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setTimeZone(TimeZone.getDefault());
json.put("device", "xDrip-"+prefs.getString("dex_collection_method", "BluetoothWixel"));
json.put("date", record.timestamp);
json.put("dateString", format.format(record.timestamp));
json.put("sgv", (int)record.calculated_value);
json.put("direction", record.slopeName());
json.put("type", "sgv");
json.put("filtered", record.filtered_data * 1000);
json.put("unfiltered", record.age_adjusted_raw_value * 1000);
json.put("rssi", 100);
json.put("noise", Integer.valueOf(record.noiseValue()));
}
private void populateLegacyAPIEntry(JSONObject json, BgReading record) throws Exception {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setTimeZone(TimeZone.getDefault());
json.put("device", "xDrip-"+prefs.getString("dex_collection_method", "BluetoothWixel"));
json.put("date", record.timestamp);
json.put("dateString", format.format(record.timestamp));
json.put("sgv", (int)record.calculated_value);
json.put("direction", record.slopeName());
}
private void populateV1APIMeterReadingEntry(JSONObject json, Calibration record) throws Exception {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setTimeZone(TimeZone.getDefault());
json.put("device", "xDrip-"+prefs.getString("dex_collection_method", "BluetoothWixel"));
json.put("type", "mbg");
json.put("date", record.timestamp);
json.put("dateString", format.format(record.timestamp));
json.put("mbg", record.bg);
}
private void populateV1APICalibrationEntry(JSONObject json, Calibration record) throws Exception {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setTimeZone(TimeZone.getDefault());
json.put("device", "xDrip-" + prefs.getString("dex_collection_method", "BluetoothWixel"));
json.put("type", "cal");
json.put("date", record.timestamp);
json.put("dateString", format.format(record.timestamp));
if(record.check_in) {
json.put("slope", (long) (record.first_slope));
json.put("intercept", (long) ((record.first_intercept)));
json.put("scale", record.first_scale);
} else {
json.put("slope", (long) (record.slope * 1000));
json.put("intercept", (long) ((record.intercept * -1000) / (record.slope * 1000)));
json.put("scale", 1);
}
}
// TODO: this is a quick port from original code and needs to be refactored before release
private void postDeviceStatus(String baseURL, Header apiSecretHeader, DefaultHttpClient httpclient) throws Exception {
String devicestatusURL = baseURL + "devicestatus";
Log.i(TAG, "devicestatusURL: " + devicestatusURL);
JSONObject json = new JSONObject();
json.put("uploaderBattery", getBatteryLevel());
String jsonString = json.toString();
HttpPost post = new HttpPost(devicestatusURL);
if (apiSecretHeader != null) {
post.setHeader(apiSecretHeader);
}
StringEntity se = new StringEntity(jsonString);
post.setEntity(se);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
ResponseHandler responseHandler = new BasicResponseHandler();
httpclient.execute(post, responseHandler);
}
private boolean doMongoUpload(SharedPreferences prefs, List glucoseDataSets,
List meterRecords, List calRecords) {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setTimeZone(TimeZone.getDefault());
String dbURI = prefs.getString("cloud_storage_mongodb_uri", null);
String collectionName = prefs.getString("cloud_storage_mongodb_collection", null);
String dsCollectionName = prefs.getString("cloud_storage_mongodb_device_status_collection", "devicestatus");
if (dbURI != null && collectionName != null) {
try {
// connect to db
MongoClientURI uri = new MongoClientURI(dbURI.trim());
MongoClient client = new MongoClient(uri);
// get db
DB db = client.getDB(uri.getDatabase());
// get collection
DBCollection dexcomData = db.getCollection(collectionName.trim());
Log.i(TAG, "The number of EGV records being sent to MongoDB is " + glucoseDataSets.size());
for (BgReading record : glucoseDataSets) {
// make db object
BasicDBObject testData = new BasicDBObject();
testData.put("device", "xDrip-"+prefs.getString("dex_collection_method", "BluetoothWixel"));
testData.put("date", record.timestamp);
testData.put("dateString", format.format(record.timestamp));
testData.put("sgv", Math.round(record.calculated_value));
testData.put("direction", record.slopeName());
testData.put("type", "sgv");
testData.put("filtered", record.filtered_data * 1000);
testData.put("unfiltered", record.age_adjusted_raw_value * 1000 );
testData.put("rssi", 100);
testData.put("noise", Integer.valueOf(record.noiseValue()));
dexcomData.update(testData, testData, true, false, WriteConcern.UNACKNOWLEDGED);
}
Log.i(TAG, "The number of MBG records being sent to MongoDB is " + meterRecords.size());
for (Calibration meterRecord : meterRecords) {
// make db object
BasicDBObject testData = new BasicDBObject();
testData.put("device", "xDrip-"+prefs.getString("dex_collection_method", "BluetoothWixel"));
testData.put("type", "mbg");
testData.put("date", meterRecord.timestamp);
testData.put("dateString", format.format(meterRecord.timestamp));
testData.put("mbg", meterRecord.bg);
dexcomData.update(testData, testData, true, false, WriteConcern.UNACKNOWLEDGED);
}
for (Calibration calRecord : calRecords) {
// make db object
BasicDBObject testData = new BasicDBObject();
testData.put("device", "xDrip-"+prefs.getString("dex_collection_method", "BluetoothWixel"));
testData.put("date", calRecord.timestamp);
testData.put("dateString", format.format(calRecord.timestamp));
if(calRecord.check_in) {
testData.put("slope", (long) (calRecord.first_slope));
testData.put("intercept", (long) ((calRecord.first_intercept)));
testData.put("scale", calRecord.first_scale);
} else {
testData.put("slope", (long) (calRecord.slope * 1000));
testData.put("intercept", (long) ((calRecord.intercept * -1000) / (calRecord.slope * 1000)));
testData.put("scale", 1);
}
testData.put("type", "cal");
dexcomData.update(testData, testData, true, false, WriteConcern.UNACKNOWLEDGED);
}
// TODO: quick port from original code, revisit before release
DBCollection dsCollection = db.getCollection(dsCollectionName);
BasicDBObject devicestatus = new BasicDBObject();
devicestatus.put("uploaderBattery", getBatteryLevel());
devicestatus.put("created_at", new Date());
dsCollection.insert(devicestatus, WriteConcern.UNACKNOWLEDGED);
client.close();
return true;
} catch (Exception e) {
Log.e(TAG, "Unable to upload data to mongo");
}
}
return false;
}
public int getBatteryLevel() {
Intent batteryIntent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if(level == -1 || scale == -1) {
return 50;
}
return (int)(((float)level / (float)scale) * 100.0f);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/Notifications.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.eveningoutpost.dexdrip.AddCalibration;
import com.eveningoutpost.dexdrip.DoubleCalibrationActivity;
import com.eveningoutpost.dexdrip.Home;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.Models.CalibrationRequest;
import com.eveningoutpost.dexdrip.Models.UserNotification;
import com.eveningoutpost.dexdrip.R;
import com.eveningoutpost.dexdrip.Sensor;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
/**
* Created by stephenblack on 11/28/14.
*/
public class Notifications {
public static final long[] vibratePattern = {0,1000,300,1000,300,1000};
public static boolean bg_notifications;
public static boolean bg_vibrate;
public static boolean bg_lights;
public static boolean bg_sound;
public static boolean bg_sound_in_silent;
public static int bg_snooze;
public static String bg_notification_sound;
public static boolean calibration_notifications;
public static boolean calibration_vibrate;
public static boolean calibration_lights;
public static boolean calibration_sound;
public static int calibration_snooze;
public static String calibration_notification_sound;
public static Context mContext;
public static int currentVolume;
public static AudioManager manager;
public static final int BgNotificationId = 001;
public static final int calibrationNotificationId = 002;
public static final int doubleCalibrationNotificationId = 003;
public static final int extraCalibrationNotificationId = 004;
public static final int exportCompleteNotificationId = 005;
public static void setNotificationSettings(Context context) {
mContext = context;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
bg_notifications = prefs.getBoolean("bg_notifications", true);
bg_vibrate = prefs.getBoolean("bg_vibrate", true);
bg_lights = prefs.getBoolean("bg_lights", true);
bg_sound = prefs.getBoolean("bg_play_sound", true);
bg_snooze = Integer.parseInt(prefs.getString("bg_snooze", "20"));
bg_notification_sound = prefs.getString("bg_notification_sound", "content://settings/system/notification_sound");
bg_sound_in_silent = prefs.getBoolean("bg_sound_in_silent", false);
calibration_notifications = prefs.getBoolean("calibration_notifications", true);
calibration_vibrate = prefs.getBoolean("calibration_vibrate", true);
calibration_lights = prefs.getBoolean("calibration_lights", true);
calibration_sound = prefs.getBoolean("calibration_play_sound", true);
calibration_snooze = Integer.parseInt(prefs.getString("calibration_snooze", "20"));
calibration_notification_sound = prefs.getString("calibration_notification_sound", "content://settings/system/notification_sound");
}
public static void notificationSetter(Context context) {
setNotificationSettings(context);
BgGraphBuilder bgGraphBuilder = new BgGraphBuilder(context);
double high = bgGraphBuilder.highMark;
double low = bgGraphBuilder.lowMark;
Sensor sensor = Sensor.currentSensor();
List bgReadings = BgReading.latest(3);
List calibrations = Calibration.allForSensorInLastFourDays();
if(bgReadings.size() < 3) { return; }
if(calibrations.size() < 2) { return; }
BgReading bgReading = bgReadings.get(0);
if (bg_notifications && sensor != null) {
if (bgGraphBuilder.unitized(bgReading.calculated_value) >= high || bgGraphBuilder.unitized(bgReading.calculated_value) <= low) {
if(bgReading.calculated_value > 14) {
if (bgReading.hide_slope) {
bgAlert(bgReading.displayValue(mContext), "");
} else {
bgAlert(bgReading.displayValue(mContext), bgReading.slopeArrow());
}
}
} else {
clearBgAlert();
}
} else {
clearAllBgNotifications();
}
if (calibration_notifications) {
if (bgReadings.size() >= 3) {
if (calibrations.size() == 0 && (new Date().getTime() - bgReadings.get(2).timestamp <= (60000 * 30)) && sensor != null) {
if ((sensor.started_at + (60000 * 60 * 2)) < new Date().getTime()) {
doubleCalibrationRequest();
} else { clearDoubleCalibrationRequest(); }
} else { clearDoubleCalibrationRequest(); }
} else { clearDoubleCalibrationRequest(); }
if (CalibrationRequest.shouldRequestCalibration(bgReading) && (new Date().getTime() - bgReadings.get(2).timestamp <= (60000 * 24))) {
extraCalibrationRequest();
} else { clearExtraCalibrationRequest(); }
if (calibrations.size() >= 1 && Math.abs((new Date().getTime() - calibrations.get(0).timestamp))/(1000*60*60) > 12) {
Log.e("NOTIFICATIONS", "Calibration difference in hours: " + ((new Date().getTime() - calibrations.get(0).timestamp))/(1000*60*60));
calibrationRequest();
} else { clearCalibrationRequest(); }
} else {
clearAllCalibrationNotifications();
}
}
public static void soundAlert(String soundUri) {
manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
int maxVolume = manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
currentVolume = manager.getStreamVolume(AudioManager.STREAM_MUSIC);
manager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume, 0);
Uri notification = Uri.parse(bg_notification_sound);
MediaPlayer player = MediaPlayer.create(mContext, notification);
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
manager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);
}
});
player.start();
}
public static void clearAllBgNotifications() {
notificationDismiss(BgNotificationId);
}
public static void clearAllCalibrationNotifications() {
notificationDismiss(calibrationNotificationId);
notificationDismiss(extraCalibrationNotificationId);
notificationDismiss(doubleCalibrationNotificationId);
}
public static void bgNotificationCreate(String title, String content, Intent intent, int notificationId) {
NotificationCompat.Builder mBuilder = notificationBuilder(title, content, intent);
if (bg_vibrate) { mBuilder.setVibrate(vibratePattern);}
if (bg_lights) { mBuilder.setLights(0xff00ff00, 300, 1000);}
if (bg_sound && !bg_sound_in_silent) { mBuilder.setSound(Uri.parse(bg_notification_sound), AudioAttributes.FLAG_AUDIBILITY_ENFORCED);}
if (bg_sound && bg_sound_in_silent) { soundAlert(bg_notification_sound);}
NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);
mNotifyMgr.cancel(notificationId);
mNotifyMgr.notify(notificationId, mBuilder.build());
}
public static void calibrationNotificationCreate(String title, String content, Intent intent, int notificationId) {
NotificationCompat.Builder mBuilder = notificationBuilder(title, content, intent);
if (calibration_vibrate) { mBuilder.setVibrate(vibratePattern);}
if (calibration_lights) { mBuilder.setLights(0xff00ff00, 300, 1000);}
if (calibration_sound) { mBuilder.setSound(Uri.parse(calibration_notification_sound), AudioAttributes.FLAG_AUDIBILITY_ENFORCED);}
NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);
mNotifyMgr.cancel(notificationId);
mNotifyMgr.notify(notificationId, mBuilder.build());
}
public static void notificationUpdate(String title, String content, Intent intent, int notificationId) {
NotificationCompat.Builder mBuilder = notificationBuilder(title, content, intent);
NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);
mNotifyMgr.notify(notificationId, mBuilder.build());
}
public static NotificationCompat.Builder notificationBuilder(String title, String content, Intent intent) {
return new NotificationCompat.Builder(mContext)
.setSmallIcon(R.drawable.ic_action_communication_invert_colors_on)
.setContentTitle(title)
.setContentText(content)
.setContentIntent(notificationIntent(intent));
}
public static PendingIntent notificationIntent(Intent intent){
return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void notificationDismiss(int notificationId) {
NotificationManager mNotifyMgr = (NotificationManager) mContext.getSystemService(mContext.NOTIFICATION_SERVICE);
mNotifyMgr.cancel(notificationId);
}
public static void bgAlert(String value, String slopeArrow) {
UserNotification userNotification = UserNotification.lastBgAlert();
if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * bg_snooze)))) {
if (userNotification != null) { userNotification.delete(); }
UserNotification newUserNotification = UserNotification.create(value + " " + slopeArrow, "bg_alert");
String title = value + " " + slopeArrow;
String content = "BG LEVEL ALERT: " + value + " " + slopeArrow;
Intent intent = new Intent(mContext, Home.class);
bgNotificationCreate(title, content, intent, BgNotificationId);
} else if ((userNotification != null) && (userNotification.timestamp >= ((new Date().getTime()) - (60000 * bg_snooze)))) {
String title = value + " " + slopeArrow;
String content = "BG LEVEL ALERT: " + value + " " + slopeArrow;
Intent intent = new Intent(mContext, Home.class);
notificationUpdate(title, content, intent, BgNotificationId);
}
}
public static void calibrationRequest() {
UserNotification userNotification = UserNotification.lastCalibrationAlert();
if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * calibration_snooze)))) {
if (userNotification != null) { userNotification.delete(); }
UserNotification newUserNotification = UserNotification.create("12 hours since last Calibration", "calibration_alert");
String title = "Calibration Needed";
String content = "12 hours since last calibration";
Intent intent = new Intent(mContext, AddCalibration.class);
calibrationNotificationCreate(title, content, intent, calibrationNotificationId);
}
}
public static void doubleCalibrationRequest() {
UserNotification userNotification = UserNotification.lastDoubleCalibrationAlert();
if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * calibration_snooze)))) {
if (userNotification != null) { userNotification.delete(); }
UserNotification newUserNotification = UserNotification.create("Double Calibration", "double_calibration_alert");
String title = "Sensor is ready";
String content = "Sensor is ready, please enter a double calibration";
Intent intent = new Intent(mContext, DoubleCalibrationActivity.class);
calibrationNotificationCreate(title, content, intent, calibrationNotificationId);
}
}
public static void extraCalibrationRequest() {
UserNotification userNotification = UserNotification.lastExtraCalibrationAlert();
if ((userNotification == null) || (userNotification.timestamp <= ((new Date().getTime()) - (60000 * calibration_snooze)))) {
if (userNotification != null) { userNotification.delete(); }
UserNotification newUserNotification = UserNotification.create("Extra Calibration Requested", "extra_calibration_alert");
String title = "Calibration Needed";
String content = "A calibration entered now will GREATLY increase performance";
Intent intent = new Intent(mContext, AddCalibration.class);
calibrationNotificationCreate(title, content, intent, extraCalibrationNotificationId);
}
}
public static void clearCalibrationRequest() {
UserNotification userNotification = UserNotification.lastCalibrationAlert();
if (userNotification != null) {
userNotification.delete();
notificationDismiss(calibrationNotificationId);
}
}
public static void clearDoubleCalibrationRequest() {
UserNotification userNotification = UserNotification.lastDoubleCalibrationAlert();
if (userNotification != null) {
userNotification.delete();
notificationDismiss(doubleCalibrationNotificationId);
}
}
public static void clearExtraCalibrationRequest() {
UserNotification userNotification = UserNotification.lastExtraCalibrationAlert();
if (userNotification != null) {
userNotification.delete();
notificationDismiss(extraCalibrationNotificationId);
}
}
public static void clearBgAlert() {
UserNotification userNotification = UserNotification.lastBgAlert();
if (userNotification != null) {
userNotification.delete();
notificationDismiss(BgNotificationId);
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/PebbleSync.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.util.Log;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.getpebble.android.kit.PebbleKit;
import com.getpebble.android.kit.util.PebbleDictionary;
import java.util.Date;
import java.util.UUID;
/**
* Created by THE NIGHTSCOUT PROJECT CONTRIBUTORS (and adapted to fit the needs of this project)
*/
public class PebbleSync {
// CGM_ICON_KEY = 0x0, // TUPLE_CSTRING, MAX 2 BYTES (10)
// CGM_BG_KEY = 0x1, // TUPLE_CSTRING, MAX 4 BYTES (253 OR 22.2)
// CGM_TCGM_KEY = 0x2, // TUPLE_INT, 4 BYTES (CGM TIME)
// CGM_TAPP_KEY = 0x3, // TUPLE_INT, 4 BYTES (APP / PHONE TIME)
// CGM_DLTA_KEY = 0x4, // TUPLE_CSTRING, MAX 5 BYTES (BG DELTA, -100 or -10.0)
// CGM_UBAT_KEY = 0x5, // TUPLE_CSTRING, MAX 3 BYTES (UPLOADER BATTERY, 100)
// CGM_NAME_KEY = 0x6 // TUPLE_CSTRING, MAX 9 BYTES (xDrip)
public static final UUID PEBBLEAPP_UUID = UUID.fromString("2c3f5ab3-7506-44e7-b8d0-2c63de32e1ec");
public static final int ICON_KEY = 0;
public static final int BG_KEY = 1;
public static final int RECORD_TIME_KEY = 2;
public static final int PHONE_TIME_KEY = 3;
public static final int BG_DELTA_KEY = 4;
public static final int UPLOADER_BATTERY_KEY = 5;
public static final int NAME_KEY = 6;
private Context mContext;
private BgGraphBuilder bgGraphBuilder;
private BgReading mBgReading;
public PebbleDictionary buildDictionary() {
PebbleDictionary dictionary = new PebbleDictionary();
dictionary.addString(ICON_KEY, slopeOrdinal());
dictionary.addString(BG_KEY, bgReading());
dictionary.addUint32(RECORD_TIME_KEY, (int) (mBgReading.timestamp / 1000));
dictionary.addUint32(PHONE_TIME_KEY, (int) (new Date().getTime() / 1000));
dictionary.addString(BG_DELTA_KEY, bgDelta());
dictionary.addString(UPLOADER_BATTERY_KEY, phoneBattery());
dictionary.addString(NAME_KEY, "xDrip");
return dictionary;
}
public void sendData(Context context, BgReading bgReading){
mContext = context;
bgGraphBuilder = new BgGraphBuilder(mContext);
mBgReading = BgReading.last();
sendDownload(buildDictionary());
}
public String bgReading() {
return bgGraphBuilder.unitized_string(mBgReading.calculated_value);
}
public String bgDelta() {
String deltaString = bgGraphBuilder.unitized_string((int)(mBgReading.calculated_value_slope * (5 * 60 * 1000)));
if(mBgReading.calculated_value_slope > 0.1) {
return ("+"+deltaString);
} else if(mBgReading.calculated_value_slope > -0.1 && mBgReading.calculated_value_slope < 0.1) {
return "0";
} else {
return deltaString;
}
}
public String phoneBattery() {
return String.valueOf(getBatteryLevel());
}
public String bgUnit() {
return bgGraphBuilder.unit();
}
public void sendDownload(PebbleDictionary dictionary) {
if (PebbleKit.isWatchConnected(mContext)) {
if (dictionary != null && mContext != null) {
Log.d("PEBBLE PUSHER", "Sending data to pebble");
PebbleKit.sendDataToPebble(mContext, PEBBLEAPP_UUID, dictionary);
}
}
}
public int getBatteryLevel() {
Intent batteryIntent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if(level == -1 || scale == -1) {
return 50;
}
return (int)(((float)level / (float)scale) * 100.0f);
}
public String slopeOrdinal(){
double slope_by_minute = mBgReading.calculated_value_slope * 60000;
String arrow = "0";
if (slope_by_minute <= (-3.5)) {
arrow = "7";
} else if (slope_by_minute <= (-2)) {
arrow = "6";
} else if (slope_by_minute <= (-1)) {
arrow = "5";
} else if (slope_by_minute <= (1)) {
arrow = "4";
} else if (slope_by_minute <= (2)) {
arrow = "3";
} else if (slope_by_minute <= (3.5)) {
arrow = "2";
} else {
arrow = "1";
}
if(mBgReading.hide_slope) {
arrow = "9";
}
return arrow;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/RedBearLabAttributes.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import java.util.UUID;
/**
* Created by stephenblack on 2/21/15.
*/
public class RedBearLabAttributes {
public static UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public static UUID REDBEARLAB_SERVICE = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
public static UUID REDBEARLAB_TX = UUID.fromString("713d0002-503e-4c75-ba94-3148f18d941e");
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/RestCalls.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.util.Log;
import com.eveningoutpost.dexdrip.Interfaces.BgReadingInterface;
import com.eveningoutpost.dexdrip.Interfaces.CalibrationInterface;
import com.eveningoutpost.dexdrip.Interfaces.SensorInterface;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.Sensor;
import com.eveningoutpost.dexdrip.Models.User;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.internal.bind.DateTypeAdapter;
import java.util.Date;
import retrofit.Callback;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;
import retrofit.converter.GsonConverter;
/**
* Created by stephenblack on 11/6/14.
*/
public class RestCalls {
private static final String baseUrl = "http://10.0.2.2:3000";
public static Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.create();
public static void sendBgReading(final BgSendQueue bgSendQueue) {
User user = User.currentUser();
bgReadingInterface().createReading(user.uuid, bgSendQueue.bgReading, new Callback() {
@Override
public void success(Gson gsonResponse, Response response) {
bgSendQueue.success = true;
bgSendQueue.save();
BgReading bgReading = bgSendQueue.bgReading;
bgReading.synced = true;
bgReading.save();
}
@Override
public void failure(RetrofitError error) {
Response response = error.getResponse();
Log.w("REST CALL ERROR:", "****************");
Log.w("REST CALL STATUS:", "" + response.getStatus());
Log.w("REST CALL REASON:", response.getReason());
}
}
);
}
public static void updateBgReading(final BgSendQueue bgSendQueue) {
User user = User.currentUser();
bgReadingInterface().updateReading(user.uuid, bgSendQueue.bgReading.uuid, bgSendQueue.bgReading, new Callback() {
@Override
public void success(Gson gsonResponse, Response response) {
Log.w("REST CALL Update Success!:", "****************");
bgSendQueue.success = true;
bgSendQueue.save();
}
@Override
public void failure(RetrofitError error) {
Response response = error.getResponse();
Log.w("REST CALL ERROR:", "****************");
Log.w("REST CALL STATUS:", "" + response.getStatus());
Log.w("REST CALL REASON:", response.getReason());
}
}
);
}
public static void sendCalibration(final CalibrationSendQueue calibrationSendQueue) {
User user = User.currentUser();
calibrationInterface().createCalibration(user.uuid, calibrationSendQueue.calibration, new Callback() {
@Override
public void success(Gson gsonResponse, Response response) {
calibrationSendQueue.success = true;
calibrationSendQueue.save();
Calibration calibration = calibrationSendQueue.calibration;
calibration.save();
}
@Override
public void failure(RetrofitError error) {
Response response = error.getResponse();
Log.w("REST CALL ERROR:", "****************");
Log.w("REST CALL STATUS:", "" + response.getStatus());
Log.w("REST CALL REASON:", response.getReason());
}
}
);
}
public static void sendSensor(final SensorSendQueue sensorSendQueue) {
User user = User.currentUser();
sensorInterface().createSensor(user.uuid, sensorSendQueue.sensor, new Callback() {
@Override
public void success(Gson gsonResponse, Response response) {
sensorSendQueue.success = true;
sensorSendQueue.save();
Sensor sensor = sensorSendQueue.sensor;
sensor.save();
}
@Override
public void failure(RetrofitError error) {
Response response = error.getResponse();
Log.w("REST CALL ERROR:", "****************");
Log.w("REST CALL STATUS:", "" + response.getStatus());
Log.w("REST CALL REASON:", response.getReason());
}
}
);
}
public static BgReadingInterface bgReadingInterface() {
RestAdapter adapter = adapterBuilder().build();
BgReadingInterface bgReadingInterface =
adapter.create(BgReadingInterface.class);
return bgReadingInterface;
}
public static SensorInterface sensorInterface() {
RestAdapter adapter = adapterBuilder().build();
SensorInterface sensorInterface =
adapter.create(SensorInterface.class);
return sensorInterface;
}
public static CalibrationInterface calibrationInterface() {
RestAdapter adapter = adapterBuilder().build();
CalibrationInterface calibrationInterface =
adapter.create(CalibrationInterface.class);
return calibrationInterface;
}
public static RestAdapter.Builder adapterBuilder() {
RestAdapter.Builder adapterBuilder = new RestAdapter.Builder();
adapterBuilder
.setEndpoint(baseUrl)
.setConverter(new GsonConverter(gson))
.setRequestInterceptor(requestInterceptor());
return adapterBuilder;
}
public static RequestInterceptor requestInterceptor(){
RequestInterceptor requestInterceptor = new RequestInterceptor() {
User currentUser = User.currentUser();
@Override
public void intercept(RequestFacade request) {
request.addHeader("email", currentUser.email);
request.addHeader("token", currentUser.token);
}
};
return requestInterceptor;
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/SensorSendQueue.java
================================================
package com.eveningoutpost.dexdrip.UtilityModels;
import android.provider.BaseColumns;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.Sensor;
import java.util.List;
/**
* Created by stephenblack on 11/7/14.
*/
@Table(name = "SensorSendQueue", id = BaseColumns._ID)
public class SensorSendQueue extends Model {
@Column(name = "Sensor", index = true)
public Sensor sensor;
@Column(name = "success", index = true)
public boolean success;
public static SensorSendQueue nextSensorJob() {
SensorSendQueue job = new Select()
.from(SensorSendQueue.class)
.where("success =", false)
.orderBy("_ID desc")
.limit(1)
.executeSingle();
return job;
}
public static List queue() {
return new Select()
.from(SensorSendQueue.class)
.where("success = ?", false)
.orderBy("_ID desc")
.execute();
}
public static void addToQueue(Sensor sensor) {
SensorSendQueue sensorSendQueue = new SensorSendQueue();
sensorSendQueue.sensor = sensor;
sensorSendQueue.success = false;
sensorSendQueue.save();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/utils/DatabaseUtil.java
================================================
package com.eveningoutpost.dexdrip.utils;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.text.format.DateFormat;
import com.activeandroid.Configuration;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import static com.eveningoutpost.dexdrip.utils.FileUtils.*;
/**
* Save the SQL database to file.
*/
public class DatabaseUtil {
public static String saveSql(Context context) {
try {
final String databaseName = new Configuration.Builder(context).create().getDatabaseName();
final String dir = getExternalDir();
makeSureDirectoryExists(dir);
final StringBuilder sb = new StringBuilder();
sb.append(dir);
sb.append("/export");
sb.append(DateFormat.format("yyyyMMdd-kkmmss", System.currentTimeMillis()));
sb.append(".sqlite");
final String filename = sb.toString();
final File sd = Environment.getExternalStorageDirectory();
if (sd.canWrite()) {
final File currentDB = context.getDatabasePath(databaseName);
final File backupDB = new File(filename);
if (currentDB.exists()) {
final FileInputStream srcStream = new FileInputStream(currentDB);
final FileChannel src = srcStream.getChannel();
final FileOutputStream destStream = new FileOutputStream(backupDB);
final FileChannel dst = destStream.getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
srcStream.close();
dst.close();
destStream.close();
}
}
return filename;
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
public static void loadSql(Context context, Uri uri) {
try {
final String databaseName = new Configuration.Builder(context).create().getDatabaseName();
final File currentDB = context.getDatabasePath(databaseName);
final File replacement = new File(uri.getPath());
if (currentDB.canWrite()) {
final FileInputStream srcStream = new FileInputStream(replacement);
final FileChannel src = srcStream.getChannel();
final FileOutputStream destStream = new FileOutputStream(currentDB);
final FileChannel dst = destStream.getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
srcStream.close();
dst.close();
destStream.close();
} else {
throw new RuntimeException("Couldn't write to " + currentDB);
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/utils/FileUtils.java
================================================
package com.eveningoutpost.dexdrip.utils;
import android.os.Environment;
import java.io.File;
public class FileUtils {
public static boolean makeSureDirectoryExists( final String dir ) {
final File file = new File( dir );
return file.exists() || file.mkdirs();
}
public static String getExternalDir() {
final StringBuilder sb = new StringBuilder();
sb.append( Environment.getExternalStorageDirectory().getAbsolutePath() );
sb.append( "/xdrip" );
final String dir = sb.toString();
return dir;
}
public static String combine( final String path1, final String path2 ) {
final File file1 = new File( path1 );
final File file2 = new File( file1, path2 );
return file2.getPath();
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/utils/Preferences.java
================================================
package com.eveningoutpost.dexdrip.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.RingtonePreference;
import android.text.TextUtils;
import android.util.Log;
import com.eveningoutpost.dexdrip.R;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;
import java.util.List;
/**
* A {@link PreferenceActivity} that presents a set of application settings. On
* handset devices, settings are presented as a single list. On tablets,
* settings are split by category, with category headers shown to the left of
* the list of settings.
*
* See
* Android Design: Settings for design guidelines and the Settings
* API Guide for more information on developing a Settings UI.
*/
public class Preferences extends PreferenceActivity {
public static SharedPreferences prefs;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content,
new AllPrefsFragment()).commit();
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// addPreferencesFromResource(R.xml.pref_general);
}
@Override
protected boolean isValidFragment(String fragmentName) {
if (AllPrefsFragment.class.getName().equals(fragmentName)){ return true; }
return false;
}
@Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
@Override
public void onBuildHeaders(List target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null);
} else {
// Set the summary to reflect the new ringtone display
// name.
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
private static void bindPreferenceSummaryToValue(Preference preference) {
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
public static class AllPrefsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_license);
addPreferencesFromResource(R.xml.pref_general);
bindPreferenceSummaryToValue(findPreference("highValue"));
bindPreferenceSummaryToValue(findPreference("lowValue"));
bindPreferenceSummaryToValue(findPreference("units"));
addPreferencesFromResource(R.xml.pref_notifications);
bindPreferenceSummaryToValue(findPreference("bg_snooze"));
addPreferencesFromResource(R.xml.pref_data_source);
addPreferencesFromResource(R.xml.pref_data_sync);
bindPreferenceSummaryToValue(findPreference("cloud_storage_mongodb_uri"));
bindPreferenceSummaryToValue(findPreference("cloud_storage_mongodb_collection"));
bindPreferenceSummaryToValue(findPreference("cloud_storage_mongodb_device_status_collection"));
bindPreferenceSummaryToValue(findPreference("cloud_storage_api_base"));
addPreferencesFromResource(R.xml.pref_advanced_settings);
final Preference collectionMethod = findPreference("dex_collection_method");
final Preference runInForeground = findPreference("run_service_in_foreground");
final Preference wifiRecievers = findPreference("wifi_recievers_addresses");
final Preference predictiveBG = findPreference("predictive_bg");
final Preference interpretRaw = findPreference("interpret_raw");
final Preference shareKey = findPreference("share_key");
final PreferenceCategory collectionCategory = (PreferenceCategory) findPreference("collection_category");
final PreferenceCategory otherCategory = (PreferenceCategory) findPreference("other_category");
final PreferenceScreen calibrationAlertsScreen = (PreferenceScreen) findPreference("calibration_alerts_screen");
final PreferenceCategory alertsCategory = (PreferenceCategory) findPreference("alerts_category");
prefs = getPreferenceManager().getDefaultSharedPreferences(getActivity());
Log.d("PREF", prefs.getString("dex_collection_method", "BluetoothWixel"));
if(prefs.getString("dex_collection_method", "BluetoothWixel").compareTo("DexcomShare") != 0) {
collectionCategory.removePreference(shareKey);
otherCategory.removePreference(interpretRaw);
alertsCategory.addPreference(calibrationAlertsScreen);
} else {
otherCategory.removePreference(predictiveBG);
alertsCategory.removePreference(calibrationAlertsScreen);
prefs.edit().putBoolean("calibration_notifications", false).apply();
}
if(prefs.getString("dex_collection_method", "BluetoothWixel").compareTo("BluetoothWixel") != 0 && prefs.getString("dex_collection_method", "BluetoothWixel").compareTo("DexcomShare") != 0) {
collectionCategory.removePreference(runInForeground);
}
if(prefs.getString("dex_collection_method", "BluetoothWixel").compareTo("WifiWixel") != 0) {
collectionCategory.removePreference(wifiRecievers);
}
bindPreferenceSummaryToValue(collectionMethod);
bindPreferenceSummaryToValue(shareKey);
bindPreferenceSummaryToValue(wifiRecievers);
collectionMethod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if(((String) newValue).compareTo("DexcomShare") != 0) { // NOT USING SHARE
collectionCategory.removePreference(shareKey);
otherCategory.removePreference(interpretRaw);
otherCategory.addPreference(predictiveBG);
alertsCategory.addPreference(calibrationAlertsScreen);
} else {
collectionCategory.addPreference(shareKey);
otherCategory.addPreference(interpretRaw);
otherCategory.removePreference(predictiveBG);
alertsCategory.removePreference(calibrationAlertsScreen);
prefs.edit().putBoolean("calibration_notifications", false).apply();
}
if(((String) newValue).compareTo("BluetoothWixel") != 0 && ((String) newValue).compareTo("DexcomShare") != 0) {
collectionCategory.removePreference(runInForeground);
} else {
collectionCategory.addPreference(runInForeground);
}
if(((String) newValue).compareTo("WifiWixel") != 0) {
collectionCategory.removePreference(wifiRecievers);
} else {
collectionCategory.addPreference(wifiRecievers);
}
String stringValue = newValue.toString();
if (preference instanceof ListPreference) {
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (preference instanceof RingtonePreference) {
if (TextUtils.isEmpty(stringValue)) {
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
preference.setSummary(null);
} else {
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
preference.setSummary(stringValue);
}
CollectionServiceStarter.restartCollectionService(preference.getContext());
return true;
}
});
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/utils/ShareNotification.java
================================================
package com.eveningoutpost.dexdrip.utils;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
/**
* Helper class to show a share notificaiton.
*/
public class ShareNotification {
public static void viewOrShare(String mime, Uri uri, NotificationCompat.Builder builder, Context context) {
final Intent viewFileIntent = new Intent(Intent.ACTION_VIEW);
viewFileIntent.setDataAndType(uri, mime);
ResolveInfo matches = context.getPackageManager().resolveActivity(viewFileIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (matches != null) {
final PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, viewFileIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
addShare(builder, mime, uri, context);
}
} else {
final Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType(mime);
final PendingIntent sharePendingIntent = PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(sharePendingIntent);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void addShare(NotificationCompat.Builder notification, String mime, Uri uri, Context context) {
final Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType(mime);
final PendingIntent sharePendingIntent = PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.addAction(android.R.drawable.ic_menu_share, "Share", sharePendingIntent);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/widgetUpdateService.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.ReadDataShare;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Services.DexShareCollectionService;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.Intents;
import java.util.Calendar;
import java.util.Date;
public class widgetUpdateService extends Service {
public String TAG = "widgetUpdateService";
BroadcastReceiver _broadcastReceiver;
public widgetUpdateService() {}
@Override
public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); }
@Override
public void onCreate() {
super.onCreate();
setFailoverTimer();
_broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {
updateCurrentBgInfo();
}
}
};
registerReceiver(_broadcastReceiver, new IntentFilter(Intent.ACTION_TIME_TICK));
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
setFailoverTimer();
updateCurrentBgInfo();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
if (_broadcastReceiver != null) {
unregisterReceiver(_broadcastReceiver);
}
}
public void setFailoverTimer() { //Keep it alive!
if(AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), xDripWidget.class)).length > 0) {
long retry_in = (1000 * 60 * 5);
Log.d(TAG, "Fallover Restarting in: " + (retry_in / (60 * 1000)) + " minutes");
Calendar calendar = Calendar.getInstance();
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
alarm.set(alarm.RTC_WAKEUP, calendar.getTimeInMillis() + retry_in, PendingIntent.getService(this, 0, new Intent(this, widgetUpdateService.class), 0));
}
}
public void updateCurrentBgInfo() {
Log.d(TAG, "Sending update flag to widget");
int ids[] = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), xDripWidget.class));
Log.d(TAG, "Updating " + ids.length + " widgets");
Intent intent = new Intent(this,xDripWidget.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);
sendBroadcast(intent);
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/xDripWidget.java
================================================
package com.eveningoutpost.dexdrip;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Paint;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.TextView;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Services.DexCollectionService;
import com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Implementation of App Widget functionality.
*/
public class xDripWidget extends AppWidgetProvider {
public static RemoteViews views;
public static Context mContext;
public static String TAG = "xDripWidget";
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
}
}
@Override
public void onEnabled(Context context) {
Log.d(TAG, "Widget enabled");
context.startService(new Intent(context, widgetUpdateService.class));
}
@Override
public void onDisabled(Context context) {
Log.d(TAG, "Widget disabled");
// Enter relevant functionality for when the last widget is disabled
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
mContext = context;
views = new RemoteViews(context.getPackageName(), R.layout.x_drip_widget);
Log.d(TAG, "Update widget signal received");
displayCurrentInfo();
appWidgetManager.updateAppWidget(appWidgetId, views);
}
public static void displayCurrentInfo() {
BgGraphBuilder bgGraphBuilder = new BgGraphBuilder(mContext);
BgReading lastBgreading = BgReading.lastNoSenssor();
if (lastBgreading != null) {
double estimate = 0;
if ((new Date().getTime()) - (60000 * 11) - lastBgreading.timestamp > 0) {
estimate = lastBgreading.calculated_value;
Log.d(TAG, "old value, estimate " + estimate);
views.setTextViewText(R.id.widgetBg, bgGraphBuilder.unitized_string(estimate));
views.setTextViewText(R.id.widgetArrow, "--");
views.setInt(R.id.widgetBg, "setPaintFlags", Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
} else {
estimate = lastBgreading.calculated_value;
String stringEstimate = bgGraphBuilder.unitized_string(estimate);
String slope_arrow = BgReading.slopeArrow((lastBgreading.calculated_value_slope * 60000));
if (lastBgreading.hide_slope) {
slope_arrow = "--";
}
Log.d(TAG, "newish value, estimate " + stringEstimate + slope_arrow);
views.setTextViewText(R.id.widgetBg, stringEstimate);
views.setTextViewText(R.id.widgetArrow, slope_arrow);
views.setInt(R.id.widgetBg, "setPaintFlags", 0);
}
List bgReadingList = BgReading.latest(2);
if(bgReadingList != null && bgReadingList.size() == 2) {
views.setTextViewText(R.id.widgetDelta, bgGraphBuilder.unitizedDeltaString(lastBgreading.calculated_value - bgReadingList.get(1).calculated_value));
} else {
views.setTextViewText(R.id.widgetDelta, "--");
}
int timeAgo =(int) Math.floor((new Date().getTime() - lastBgreading.timestamp)/(1000*60));
if (timeAgo == 1) {
views.setTextViewText(R.id.readingAge, timeAgo + " Minute ago");
} else {
views.setTextViewText(R.id.readingAge, timeAgo + " Minutes ago");
}
if (timeAgo > 15) {
views.setTextColor(R.id.readingAge, Color.parseColor("#FFBB33"));
} else {
views.setTextColor(R.id.readingAge, Color.WHITE);
}
if (bgGraphBuilder.unitized(estimate) <= bgGraphBuilder.lowMark) {
views.setTextColor(R.id.widgetBg, Color.parseColor("#C30909"));
views.setTextColor(R.id.widgetDelta, Color.parseColor("#C30909"));
views.setTextColor(R.id.widgetArrow, Color.parseColor("#C30909"));
} else if (bgGraphBuilder.unitized(estimate) >= bgGraphBuilder.highMark) {
views.setTextColor(R.id.widgetBg, Color.parseColor("#FFBB33"));
views.setTextColor(R.id.widgetDelta, Color.parseColor("#FFBB33"));
views.setTextColor(R.id.widgetArrow, Color.parseColor("#FFBB33"));
} else {
views.setTextColor(R.id.widgetBg, Color.WHITE);
views.setTextColor(R.id.widgetDelta, Color.WHITE);
views.setTextColor(R.id.widgetArrow, Color.WHITE);
}
}
}
}
================================================
FILE: app/src/main/java/com/eveningoutpost/dexdrip/xdrip.java
================================================
package com.eveningoutpost.dexdrip;
import android.app.Application;
import com.crashlytics.android.Crashlytics;
import io.fabric.sdk.android.Fabric;
import org.acra.ACRA;
import org.acra.ReportField;
import org.acra.ReportingInteractionMode;
import org.acra.annotation.ReportsCrashes;
import org.acra.sender.HttpSender;
/**
* Created by stephenblack on 3/21/15.
*/
@ReportsCrashes(
formUri = "https://yoursolace.cloudant.com/acra-xdrip/_design/acra-storage/_update/report",
reportType = HttpSender.Type.JSON,
httpMethod = HttpSender.Method.POST,
formUriBasicAuthLogin = "nateriverldstiondrephery",
formUriBasicAuthPassword = "GEK5Nv7NtMkloAkufNvFgast",
formKey = "", // This is required for backward compatibility but not used
customReportContent = {
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.ANDROID_VERSION,
ReportField.PACKAGE_NAME,
ReportField.REPORT_ID,
ReportField.BUILD,
ReportField.STACK_TRACE
},
mode = ReportingInteractionMode.TOAST,
logcatArguments = {"-t", "500", "-v", "time"},
resToastText = R.string.toast_crash
)
public class xdrip extends Application {
@Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
// The following line triggers the initialization of ACRA
//ACRA.init(this);
}
}
================================================
FILE: app/src/main/res/layout/activity_add_calibration.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_add_comparison.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_bluetooth_scan.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_calibration_check_in.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_calibration_graph.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_calibration_override.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_double_calibration.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_fake_numbers.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_home.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_license_agreement.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_raw_data_table.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_share_test.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_start_new_sensor.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_stop_sensor.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_system_status.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_usb_connected.xml
================================================
================================================
FILE: app/src/main/res/layout/fragment_navigation_drawer.xml
================================================
================================================
FILE: app/src/main/res/layout/listitem_device.xml
================================================
================================================
FILE: app/src/main/res/layout/raw_data_list.xml
================================================
================================================
FILE: app/src/main/res/layout/raw_data_list_item.xml
================================================
================================================
FILE: app/src/main/res/layout/x_drip_widget.xml
================================================
================================================
FILE: app/src/main/res/layout-xlarge/activity_home.xml
================================================
================================================
FILE: app/src/main/res/menu/global.xml
================================================
================================================
FILE: app/src/main/res/menu/menu_bluetooth_scan.xml
================================================
================================================
FILE: app/src/main/res/menu/menu_home.xml
================================================
================================================
FILE: app/src/main/res/menu/menu_share_test.xml
================================================
================================================
FILE: app/src/main/res/menu/menu_system_status.xml
================================================
================================================
FILE: app/src/main/res/values/arrays.xml
================================================
Bluetooth WixelWifi WixelDexcomShareBluetoothWixelWifiWixelDexcomSharemgdlmmolmgdlmmol
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
16dp16dp240dp8dp
================================================
FILE: app/src/main/res/values/strings.xml
================================================
I UNDERSTAND AND AGREExDrip MUST NOT BE USED TO MAKE MEDICAL DECISIONS. 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. xDripHello world!SettingsBluetoothScanConnectedDisconnectedScanStopRefreshExport databaseError: Bluetooth not supported by this deviceUnrecognized DeviceConnecting to deviceRawDataTableCalculatedDataTableAddCalibrationStartNewSensorStopSensorNavDrawerHomeAdd CalibrationStart SensorStop SensorScan for BTRaw Data TableCalibration TableOpen navigation drawerClose navigation drawerEnd User License AgreementExample actionCalibrationCheckInActivityUsbConnectedActivityDex DripEnter CalibrationCalculated Data TableRaw Data TableCalibration TableStart SensorStop SensorScan for BTMainActivityCalibrationDataTableFakeNumbersDoubleCalibrationActivityCalibrationOverrideCalibrationGraphCloud StorageMongoDBEnabledIf you\'re using MongoLab and Azure this should be enabledURIEnter MongoDB URI"Replace example values in {}\'s with your correct valuesmongodb://{user}:{password}@{host}.mongolab.com:{11111}/{database}Collection nameEnter collection nameThis is the name of the collection where the CGM data will be storedentriesDevice Status collection nameEnter Device Status collection name"This is the name of the collection where the battery and other device data will be storeddevicestatusAPI Upload (REST)EnabledThe REST API is an alternative to direct mongodb uploadBase URLEnter Base API URLThis only the base URL, the uploader will automatically append /entries for the POST. API_SECRET on the server should match yourpassphrase in this setting.yourpassphrase@https://{YOUR-SITE}.azurewebsites.net/api/v1Comma separated list of ip:port (for example 37.142.132.220:50005,37.142.132.220:50010,mongodb://user:pass@ds053958.mongolab.com:53958/db/collection)Enter ip addresses and ports of receivers (including mongodb addresses if needed)Broadcast locallyEnable local broadcast of data so other apps (eg. NightWatch) can listen on new valuesShareTestSystemStatusSomething went wrong :( a report has been sent to help fix the issue.EXAMPLEAdd widget
================================================
FILE: app/src/main/res/values/strings_activity_preferences.xml
================================================
PreferencesGeneralEnable social recommendationsRecommendations for people to contact
based on your message history
Display nameJohn SmithAdd friends to messagesAlwaysWhen possibleNever10-1Data & syncSync frequency15 minutes30 minutes1 hour3 hours6 hoursNever153060180360-1System sync settingsNotificationsNew message notificationsRingtoneSilentVibrate
================================================
FILE: app/src/main/res/values/styles.xml
================================================
================================================
FILE: app/src/main/res/values-v14/dimens.xml
================================================
0dp
================================================
FILE: app/src/main/res/values-v21/styles.xml
================================================
================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
64dp
================================================
FILE: app/src/main/res/xml/device_filter.xml
================================================
================================================
FILE: app/src/main/res/xml/pref_advanced_settings.xml
================================================
================================================
FILE: app/src/main/res/xml/pref_data_source.xml
================================================
================================================
FILE: app/src/main/res/xml/pref_data_sync.xml
================================================
================================================
FILE: app/src/main/res/xml/pref_general.xml
================================================
================================================
FILE: app/src/main/res/xml/pref_headers.xml
================================================
================================================
FILE: app/src/main/res/xml/pref_license.xml
================================================
================================================
FILE: app/src/main/res/xml/pref_notifications.xml
================================================
================================================
FILE: app/src/main/res/xml/x_drip_widget_info.xml
================================================
================================================
FILE: battle_of_the_dexes.md
================================================
A few weeks ago I started a new sensor and kicked off the BattleOfTheDexes
I compared my xDrip Alogrithm against the Dexcom 505 Algorithm.
_(obviously its just one sample so nothing conclusive, but the results are in)_
METER | Dexcom | xDrip
-----:|-----:|-----:
105 | 87 | **100**
181 | **188** | 169
166 | 236 | **185**
75 | 53 | **66**
103 | 101 | **103**
118 | 102 | **111**
120 | 154 | **144**
151 | 125 | 137
102 | 95 | **103**
89 | **90** | 98
97 | **106** | 111
Overall MARDs:
* Dexcom: 15.5%
* xDrip: **8.7%**
Note that Dexcoms actual MARD as calculated in studies is 9% I believe so its quite possible I had a bum sensor here. Also note that xDrip got one extra calibration value on the second day (because it asks for one if it thinks things are off at a time when it thinks the calibration will be the most helpful)
I stopped this first comparison here because once I restart the sensor on my Dexcom, xDrip winds up with a huge advantage as it already knows the slope from the last few days of calibrations wheras dexcom will be starting from scratch. I will do more comparisons each time I change sensors!
Want to know more about the project? Check it out [HERE](http://stephenblackwasalreadytaken.github.io/xDrip)
All of the code is available and open source, if you want help getting it running just ask, Its constantly getting updated so either watch the repo in github or follow me on twitter @StephenIsTaken
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.1.3'
apply plugin: 'java'
apply plugin: 'maven'
// compile 'com.mcxiaoke.volley:library:1.0.+'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Wed Dec 10 18:45:32 EST 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: hardware_setup.md
================================================
## What you need to get started
Note, the following describes what I am currently using and recommend, it could definitely change and you can definitely use other components. Just know that this is all that it has been tested with!
* An Android Device
* Must be running 4.3 to support BLE
* Also must have BLE support
* [A Wixel](http://www.pololu.com/product/1337)
* I recommend the one without headers(linked) if you want to use wires, if you plan to use a breadboard or make a custom PCB feel free to get the one with headers.
* An HM-10 BLE Module
* I removed the link as it seems they replaced the HM10 with a cc41, **DO NOT GET A CC41!!!!!** I use the hm10 formerly sold by sunfounder, if you can find one with the pins at the bottom that is the easiest!
* The HM11 has been confirmed working but soldering it is VERY TOUGH
* [Battery Power](http://www.adafruit.com/products/258)
* I use the one linked and have no problem getting through a day, I have not done extensive battery testing at this point
* *EDIT: that one was lasting over 6 days, which seemed like a waste of space, now I use [this 500mAh](http://www.adafruit.com/products/1578) Which gets me two days no problem!
* [Battery Charger](http://www.adafruit.com/products/1904)
* I use this one, its nice and smallish and does the trick.
* If you find a nicer smaller one PLEASE LET ME KNOW (I wound up breaking the top bit off of this so I could make it fit in a new enclosure)
* [Wires](http://www.adafruit.com/product/2051)
* I use these 30AWG silicon wires because they are super small and flexible
* Larger wires will make it harder to keep things nice and compact, keep with a small guage!
* Solder and Soldering Iron
* Or a breadboard if you dont mind the bulk
* Or a custom made PCB (and one for me too please?)
* I used a cheap 15w soldering iron in order to solder and remove the pins from the HM10 (you can probably go a bit higher but I wouldnt go crazy)
* I used a regular not terrifying soldering iron for the rest of it!
* [Resistors](http://www.radioshack.com)
* If you wish to measure the Wixel's battery voltage, you'll need to build a voltage divider using two resistors and a piece of wire
* You'll need a 1/4w 1K Ohm and a 1/4w 2.2K Ohm resistor. 1/8w should work, and be smaller, but it hasn't been tested
* Optional: Small heatshrink tubing to protect the resistors (https://www.adafruit.com/product/344)
## Putting it together!

## For the voltage measurement modification
###### If you have already built the xDrip and are adding this, follow this first step:
* Remove the solder from the VIN and GND pins on the Wixel if possible using a solder sucker or solder wick. If this is not possible, then you will have to work carefully by keeping the holes heated while inserting the resistors. Keep in mind, if you do not have a controllable temperature soldering iron, you risk burning the board or the pads and ruining the Wixel. **I highly recommend getting a solder sucker.**
* You will need to grab a new copy of the Wixel code and upload it to your Wixel for this modification to work. The process is the same as when you first loaded the code onto the Wixel, except you will need to click the "Erase Flash" button first.
###### Building the voltage divider
* Bend the one end of each resistor at a 90 degree angle as close to the resistor as possible

* Using helping hands or tape, face the two resistors towards each other and place them side by side so that the leads are touching at the top

* Solder the touching leads, and then solder on the piece of wire


* Trim the leads of the 90 degree bend so they are flush with the resistors and trim any excess exposed wire from the piece you added to prevent any possible shorts.

* Insert the leads of the voltage divider into the VIN hole and GND hole. The 1K resistor goes into the VIN hole and the 2.2K resistor goes into the GND hole next to it. Additionally, insert the wires from the LiPo charger into the appropriate VIN and GND holes.

* CAREFULLY bend the resistor leads you inserted so the voltage divider is flat against the Wixel

* Solder the VIN and GND pads

* Trim the excess wire from the resistor leads

* The back of your Wixel should look like this

* If you want to add a piece of heat shrink tubing to protect the resistors (highly recommended!), put it on now.

* Trim the wire you added to the voltage divider so that it is long enough to reach P0_0, and then insert it into the hole and solder it.


* Trim the excess leads from the soldered pads on the Wixel

* CAREFULLY heat the heat shrink tubing with the iron. Only touch the tubing for a second to get it to slightly heat up and do this in multiple places. You only want it to shrink enough to not fall off, it does not have to be super tight against the resistors. **DO NOT USE A LIGHTER!**

* Congratulate yourself for building an electronic circuit!
I also tossed it all into a "Crush Proof Pill Box" from CVS (Cost like $2)


================================================
FILE: settings.gradle
================================================
include ':app'
================================================
FILE: xDrip-Experimental.iml
================================================
================================================
FILE: xDrip.iml
================================================