39 Commits

Author SHA1 Message Date
fd9066fa83 Merge branch 'develop' 2014-04-04 10:31:13 -04:30
cd8def574c Added forwarding of camera recenter commands. 2014-04-04 10:30:51 -04:30
7160cd325e Finished the sensor report thread. 2014-04-03 11:30:17 -04:30
fe1710b43e Updated MotorMasks with expansion bits. 2014-04-03 08:50:31 -04:30
16ef871911 Renamed the project. 2014-03-31 11:00:50 -04:30
cc25e8484c Changed the jpeg quality back to 90. 2014-03-18 18:02:58 -04:30
fcd949e427 Merge branch 'develop' 2014-03-14 15:20:26 -04:30
7dfb236326 Changed JPEG quality on transmission. 2014-03-14 15:20:06 -04:30
d260219ddb Merge branch 'develop' 2014-02-11 17:53:52 -04:30
e22c7c94db Merge branch 'robot_control' into develop 2014-02-11 17:52:54 -04:30
7db8c3fcee Added logic for robot control thread management. 2014-02-11 17:52:29 -04:30
89c744181e LCPThread sends BT messages. 2014-02-10 16:36:32 -04:30
6d6608bb67 MotorControlThread receives and sends data. 2014-02-10 15:24:34 -04:30
2fcd92501c Merge branch 'robot_control' into develop 2014-02-05 15:11:49 -04:30
unknown
bc9b44a849 Changed settings. 2014-02-04 17:16:20 -04:30
1c7430edd6 Removed the TCP video streaming code. 2014-01-21 12:19:23 -04:30
f865c39cb7 Started programming the robot control threads. 2014-01-20 12:59:51 -04:30
ab800a2558 Changed the streaming to use UDP. 2014-01-15 14:49:58 -04:30
8e1d50ca32 Testing different frame sizes for transmission. 2014-01-13 14:31:52 -04:30
0645ed1eb6 Merge branch 'release-14.01.10' 2014-01-09 08:21:32 -04:30
8547c168a8 Merge branch 'release-14.01.10' into develop 2014-01-09 08:21:14 -04:30
3b94303096 Fixed memory leak in VideoStreamingThread. 2014-01-09 08:20:11 -04:30
e6d5d3e2e5 Merge branch 'image_transfer' into develop 2014-01-08 15:24:05 -04:30
5cc769ad2e Basic video streaming finished. 2014-01-08 15:21:37 -04:30
f843700235 Started fixing the video streaming code. 2014-01-07 18:12:47 -04:30
21a97c0307 Log statements added to ImageTransferThread. Removed ProtocolMessage hierarchy. 2013-12-18 10:54:47 -04:30
9bcd7107b0 Assorted logic added to ImageTransferThread. Rewrites 2013-12-18 08:24:35 -04:30
aff602d0fc Started coding the image transfer protocol. 2013-12-17 17:03:02 -04:30
5c2cff3c54 Assorted error handling and messaging. 2013-12-16 16:01:22 -04:30
1b88c67ec1 More licensing crap. 2013-12-13 10:50:21 -04:30
e7b42528b3 Fixed the Android Open Source Project copyright notice. 2013-12-13 10:44:13 -04:30
a7d0cabba3 Slapped the Apache License version 2 to the project. 2013-12-13 09:19:49 -04:30
9c2b67395e Removed some useless commented out lines. 2013-12-03 16:33:50 -04:30
ebbacf4feb Fixed some bugs on the image monitor class. 2013-12-03 16:24:59 -04:30
3696a9cfd4 Merge branch 'camera_render' into develop 2013-12-03 15:33:23 -04:30
10d0f36013 Camera preview displays with correct aspect ratio. 2013-12-03 15:31:59 -04:30
5340d3b383 Testing the camera preview. 2013-11-28 16:19:37 -04:30
770f6b2476 Assorted refactorings on CamActivity. 2013-11-28 16:04:18 -04:30
5910c711d8 CameraImageMonitor now follows the Producer/Consumer model. Other assorted minor changes. 2013-11-28 15:48:17 -04:30
42 changed files with 1641 additions and 519 deletions

View File

@@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -1,23 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ve.ucv.ciens.ccg.nxtcam"
android:versionCode="1"
android:versionName="1.0" >
android:versionCode="140404"
android:versionName="14.04.04" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="19" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.bluetooth" android:required="true" />
<uses-feature android:name="android.hardware.wifi" android:required="true" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
@@ -27,8 +42,8 @@
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:screenOrientation="landscape" >
android:screenOrientation="landscape"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
<activity
android:name="ve.ucv.ciens.ccg.nxtcam.MainActivity"
android:label="@string/app_name" >

202
LICENSE.txt Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@@ -1,4 +1,4 @@
NxtCAM
======
NxtAR-cam
=========
Modulo 1 de mi trabajo especial de grado.

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -10,4 +26,11 @@
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".CamActivity" >
<FrameLayout
android:id="@+id/previewLayout"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="0.47" >
</FrameLayout>
</LinearLayout>

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item

View File

@@ -1,4 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<string name="app_name">NxtCAM</string>
@@ -10,7 +26,7 @@
<string name="start_button">Comenzar streaming de video</string>
<string name="title_activity_cam">CamActivity</string>
<string name="ipAddressLabel">Dirección IP de NxtAR</string>
<string name="badIpToast">La dirección IP no es válida</string>
<string name="badIpToast">No se encontró un servidor válido</string>
<string name="emptyIpToast">Rellene el campo de dirección IP</string>
<string name="wifi_on_title">Esta app requiere WiFi</string>
<string name="wifi_on_msg">¿Encender el WiFi?</string>
@@ -29,5 +45,6 @@
<string name="serv_wait">Por favor espere, buscando dispositivo de control</string>
<string name="serv_connected">Conectado con el dispositivo de control</string>
<string name="serv_fail">Falló la conexión con el dispositivo de control</string>
<string name="cam_fail">La cámara es null!</string>
</resources>

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<!--

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<!--

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<!--

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<!--

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->

View File

@@ -1,4 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<string name="app_name">NxtCAM</string>
@@ -10,7 +26,7 @@
<string name="get_server_button">Connect with NxtAR</string>
<string name="start_button">Start video streaming</string>
<string name="ipAddressLabel">NxtAR IP Address</string>
<string name="badIpToast">Invalid IP address</string>
<string name="badIpToast">No proper server found</string>
<string name="emptyIpToast">Fill out the IP address field</string>
<string name="wifi_on_title">This app requires WiFi</string>
<string name="wifi_on_msg">Turn on the WiFi?</string>
@@ -29,5 +45,6 @@
<string name="serv_wait">Please wait, looking for control device</string>
<string name="serv_connected">Connected with the control device</string>
<string name="serv_fail">Could no connect with the control device</string>
<string name="cam_fail">Camera is null!</string>
</resources>

View File

@@ -1,3 +1,19 @@
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
-->
<resources>
<!--

View File

@@ -0,0 +1,37 @@
package ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public class MotorEvent implements Serializable{
private static final long serialVersionUID = 9989L;
public enum motor_t {NONE, MOTOR_A, MOTOR_B, MOTOR_C, MOTOR_AC, RECENTER};
private motor_t motor;
private byte power;
public MotorEvent(){
motor = motor_t.NONE;
power = 0;
}
public void setMotor(motor_t motor){
this.motor = motor;
}
public void setPower(byte power) throws IllegalArgumentException{
if(power > 100 || power < -100){
throw new IllegalArgumentException("Motor power must be a number between -100 and 100");
}else{
this.power = power;
}
}
public motor_t getMotor(){
return this.motor;
}
public byte getPower(){
return this.power;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public class MotorEventACK implements Serializable {
private static final long serialVersionUID = 9989L;
private boolean clientQueueIsFull;
public MotorEventACK(boolean isQueueFull){
this.clientQueueIsFull = isQueueFull;
}
public boolean isClientQueueFull(){
return this.clientQueueIsFull;
}
}

View File

@@ -0,0 +1,8 @@
package ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public class SensorDataMessage implements Serializable{
private static final long serialVersionUID = 9989L;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public final class VideoFrameDataMessage implements Serializable{
private static final long serialVersionUID = 9989L;
public static final int magicNumber = 0x10;
public int imageWidth;
public int imageHeight;
public byte[] data;
public VideoFrameDataMessage(){
imageWidth = -1;
imageHeight = -1;
data = null;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public final class VideoStreamingControlMessage implements Serializable{
private static final long serialVersionUID = 8898L;
public static final int magicNumber = 0x20;
public byte message;
public VideoStreamingControlMessage(){
message = -1;
}
}

View File

@@ -1,8 +1,26 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam;
import ve.ucv.ciens.ccg.nxtcam.camera.CameraPreview;
import ve.ucv.ciens.ccg.nxtcam.network.ImageTransferThread;
import ve.ucv.ciens.ccg.nxtcam.network.NxtBTCommThread;
import ve.ucv.ciens.ccg.nxtcam.network.SensorReportThread;
import ve.ucv.ciens.ccg.nxtcam.network.VideoStreamingThread;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
import ve.ucv.ciens.ccg.nxtcam.utils.ProjectConstants;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Camera;
@@ -12,16 +30,19 @@ import android.support.v4.app.NavUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;
public class CamActivity extends Activity{
private final String TAG = "NXTCAM_CAM";
private final String CLASS_NAME = MainActivity.class.getSimpleName();
private final String CLASS_NAME = CamActivity.class.getSimpleName();
private Camera hwCamera;
private CameraPreview cPreview;
private CameraSetupTask camSetupTask;
private ImageTransferThread imThread;
private VideoStreamingThread imThread;
private NxtBTCommThread botThread;
private SensorReportThread sensorThread;
private String serverIp;
/*******************
@@ -31,12 +52,18 @@ public class CamActivity extends Activity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
cPreview = new CameraPreview(this, hwCamera);
setContentView(cPreview);
setContentView(R.layout.activity_cam);
Intent intent = getIntent();
serverIp = intent.getStringExtra("address");
imThread = new VideoStreamingThread(serverIp);
imThread.start();
botThread = new NxtBTCommThread(serverIp);
botThread.start();
sensorThread = new SensorReportThread(serverIp);
sensorThread.start();
}
@Override
@@ -70,30 +97,57 @@ public class CamActivity extends Activity{
camSetupTask = new CameraSetupTask();
camSetupTask.execute();
imThread = new ImageTransferThread(serverIp);
imThread.start();
// TODO: resumethe imThread, botThread and sensorThread objects.
}
@Override
public void onPause(){
super.onPause();
// TODO: Disconnect and destroy the imThread object.
// TODO: pause the imThread, botThread and sensorThread objects.
if(cPreview != null){
cPreview.removePreviewCallback();
cPreview.setCamera(null);
releaseCamera();
}
}
@Override
public void onDestroy(){
super.onDestroy();
imThread.finish();
imThread = null;
botThread.finish();
botThread = null;
sensorThread.finish();
sensorThread = null;
}
@Override
public void onBackPressed(){
Intent result = new Intent();
setResult(Activity.RESULT_OK, result);
finish();
}
/******************
* My own methods *
******************/
public void startCameraPreview(){
if(hwCamera != null){
Logger.log_d(TAG, CLASS_NAME + ".startCameraPreview() :: Setting camera.");
cPreview = new CameraPreview(this, hwCamera);
cPreview.setCamera(hwCamera);
((FrameLayout)findViewById(R.id.previewLayout)).addView(cPreview);
Logger.log_d(TAG, CLASS_NAME + ".startCameraPreview() :: Camera and content view set.");
}else{
Logger.log_wtf(TAG, CLASS_NAME + ".startCameraPreview() :: CAMERA IS NULL!");
System.exit(1);
Intent result = new Intent();
setResult(ProjectConstants.RESULT_CAMERA_FAILURE, result);
finish();
}
}
@@ -110,6 +164,7 @@ public class CamActivity extends Activity{
@Override
protected Camera doInBackground(Void... params) {
Camera cam = null;
Logger.log_d(TAG, CLASS_NAME + ".doInBackground() :: Opening the camera.");
try{
cam = Camera.open(0);
}catch(Exception e){

View File

@@ -1,10 +1,24 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.Socket;
import ve.ucv.ciens.ccg.nxtcam.dialogs.ConnectRobotDialog;
import ve.ucv.ciens.ccg.nxtcam.dialogs.ConnectRobotDialog.ConnectRobotDialogListener;
@@ -45,6 +59,7 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
private final String TAG = "NXTCAM_MAIN";
private final String CLASS_NAME = MainActivity.class.getSimpleName();
private static final int REQUEST_ENABLE_BT = 1;
private static final int REQUEST_CAM_ACTIVITY = 2;
// Gui components
private Button startButton;
@@ -58,6 +73,7 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
// Variables.
private boolean wifiOnByMe;
private boolean btOnByMe;
private boolean changingActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -67,6 +83,7 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
// Set up fields.
wifiOnByMe = false;
btOnByMe = false;
changingActivity = false;
// Set up gui components.
startButton = (Button)findViewById(R.id.startButton);
@@ -100,12 +117,13 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
public void onPause(){
super.onPause();
if(!changingActivity){
if(btManager.isBTEnabled() && btOnByMe)
btManager.disableBT();
if(wifiManager.isWifiEnabled() && wifiOnByMe)
setWifi(false);
}
}
@Override
public void onDestroy(){
@@ -127,11 +145,18 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
}
protected void onActivityResult(int request, int result, Intent data){
if(request == REQUEST_ENABLE_BT && result == RESULT_OK){
if(request == REQUEST_ENABLE_BT){
if(result == RESULT_OK){
if(!wifiManager.isWifiEnabled())
enableWifi();
}else{
Toast.makeText(this, R.string.bt_on_fail, Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.bt_on_fail, Toast.LENGTH_SHORT).show();
}
}else if(request == REQUEST_CAM_ACTIVITY){
changingActivity = false;
if(result == ProjectConstants.RESULT_CAMERA_FAILURE){
Toast.makeText(this, R.string.cam_fail, Toast.LENGTH_SHORT).show();
}
}
}
@@ -145,8 +170,9 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
if(serverFound){
Logger.log_d(TAG, CLASS_NAME + ".startCamActivity() :: Launching camera activity.");
Intent intent = new Intent(this, CamActivity.class);
changingActivity = true;
intent.putExtra("address", ipAddress);
startActivity(intent);
startActivityForResult(intent, REQUEST_CAM_ACTIVITY);
}else{
Logger.log_d(TAG, CLASS_NAME + ".startCamActivity() :: Cannot launch camera activity.");
Toast.makeText(this, R.string.badIpToast, Toast.LENGTH_SHORT).show();
@@ -297,7 +323,7 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
public ServiceDiscoveryTask(){
// Open a multicast socket and join the project's multicast group.
try{
udpSocket = new MulticastSocket(ProjectConstants.SERVER_UDP_PORT);
udpSocket = new MulticastSocket(ProjectConstants.SERVICE_DISCOVERY_PORT);
InetAddress group = InetAddress.getByName(ProjectConstants.MULTICAST_ADDRESS);
udpSocket.joinGroup(group);
}catch(IOException io){
@@ -315,7 +341,7 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
@Override
protected Boolean doInBackground(Void... params){
boolean result, done = false;
byte[] buffer = (new String("NxtAR server here!")).getBytes();
byte[] buffer = ProjectConstants.SERVICE_DISCOVERY_MESSAGE.getBytes();
// Create a buffer and tell Android we want to receive multicast datagrams.
packet = new DatagramPacket(buffer, buffer.length);
@@ -332,13 +358,8 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
Logger.log_d(TAG, CLASS_NAME + ".run() :: Found a server at " + packet.getAddress().getHostAddress());
String received = new String(packet.getData());
Logger.log_d(TAG, CLASS_NAME + ".doInBackground() :: Packet payload is\n" + received);
if(received.compareTo("NxtAR server here!") == 0)
if(received.compareTo(ProjectConstants.SERVICE_DISCOVERY_MESSAGE) == 0)
done = true;
Socket client1, client2;
client1 = new Socket(packet.getAddress(), ProjectConstants.SERVER_TCP_PORT_1);
client1.close();
client2 = new Socket(packet.getAddress(), ProjectConstants.SERVER_TCP_PORT_2);
client2.close();
}
result = true;
}catch(IOException io){
@@ -367,10 +388,10 @@ public class MainActivity extends Activity implements WifiOnDialogListener, Conn
if(packet != null){
showToast(R.string.serv_connected, Toast.LENGTH_SHORT);
// startCamActivity(result, packet.getAddress().getHostAddress());
startCamActivity(result, packet.getAddress().getHostAddress());
}else{
showToast(R.string.serv_fail, Toast.LENGTH_SHORT);
// startCamActivity(false, null);
startCamActivity(false, null);
}
}
}

View File

@@ -1,16 +1,38 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.camera;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
import android.graphics.Rect;
public class CameraImageMonitor{
private final String TAG = "CAM_MONITOR";
private final String CLASS_NAME = CameraImageMonitor.class.getSimpleName();
private Object imageMonitor;
private byte[] image;
private boolean imgChanged;
private boolean imageProduced;
private boolean imageConsumed;
private Rect imageSize;
private CameraImageMonitor(){
imgChanged = false;
imageProduced = false;
imageConsumed = true;
imageMonitor = new Object();
imageSize = null;
}
private static class SingletonHolder{
@@ -21,34 +43,48 @@ public class CameraImageMonitor{
return SingletonHolder.INSTANCE;
}
public void setImageData(byte[] image){
Logger.log_d(TAG, CLASS_NAME + ".setImageData() :: Copying new image.");
synchronized(image){
this.image = new byte[image.length];
System.arraycopy(image, 0, this.image, 0, image.length);
imgChanged = true;
image.notifyAll();
public void setImageParameters(int width, int height){
imageSize = new Rect(0, 0, width, height);
}
public Rect getImageParameters(){
return imageSize;
}
public void setImageData(byte[] image){
if(imageConsumed){
Logger.log_d(TAG, CLASS_NAME + ".setImageData() :: Copying new image.");
synchronized(this.imageMonitor){
this.image = image;
imageProduced = true;
imageConsumed = false;
this.imageMonitor.notifyAll();
}
System.gc();
Logger.log_d(TAG, CLASS_NAME + ".setImageData() :: Data copy finished.");
}else{
Logger.log_d(TAG, CLASS_NAME + ".setImageData() :: Old image still valid, ignoring new image.");
}
}
public byte[] getImageData(){
byte[] returnImg;
Logger.log_d(TAG, CLASS_NAME + ".getImageData() :: Entry point.");
synchronized(image){
while(!imgChanged){
Logger.log_d(TAG, CLASS_NAME + ".getImageData() :: Waiting for new data.");
try{ image.wait(); }catch(InterruptedException ie){}
synchronized(imageMonitor){
while(!imageProduced){
Logger.log_d(TAG, CLASS_NAME + ".getImageData() :: Waiting for new image.");
try{ imageMonitor.wait(); }catch(InterruptedException ie){ }
}
Logger.log_d(TAG, CLASS_NAME + ".getImageData() :: Retrieving new data.");
returnImg = image.clone();
imgChanged = false;
Logger.log_d(TAG, CLASS_NAME + ".getImageData() :: Retrieving new image.");
returnImg = image;
imageProduced = false;
imageConsumed = true;
}
Logger.log_d(TAG, CLASS_NAME + ".getImageData() :: New data retreived.");
Logger.log_d(TAG, CLASS_NAME + ".getImageData() :: New image retrieved.");
return returnImg;
}
public synchronized boolean hasChanged(){
return imgChanged;
return imageConsumed;
}
}

View File

@@ -1,3 +1,25 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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.
*
* NOTE:
* The getOptimalPreviewSize() function is copied and slightly modified from
* the Android Open Source Project ApiDemos camera preview code available at
* the following url http://goo.gl/thP1e4 from http://android.googlesource.com .
* The ApiDemos code is Copyright (C) 2007 The Android Open Source Project also
* avilable under the Apache License Version 2.0.
*/
package ve.ucv.ciens.ccg.nxtcam.camera;
import java.io.IOException;
@@ -13,85 +35,97 @@ import android.os.Build;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
/** A basic Camera preview class */
@SuppressLint("ViewConstructor")
public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback, Camera.PreviewCallback {
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
private final String TAG = "SURFVIEW";
private final String CLASS_NAME = CameraPreview.class.getSimpleName();
private Size mPreviewSize;
private List<Size> mSupportedPreviewSizes;
private CameraImageMonitor camMonitor;
private CameraImageMonitor imgMonitor;
private Activity parentActivity;
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private Camera mCamera;
private SurfaceHolder holder;
private Camera camera;
private int previewWidth;
private int previewHeight;
@SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera){
super(context);
parentActivity = (Activity)context;
mSurfaceView = new SurfaceView(context);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
// surfaceView = new SurfaceView(context);
holder = getHolder();
holder.addCallback(this);
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB)
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera){
mCamera = camera;
if(mCamera != null){
camMonitor = CameraImageMonitor.getInstance();
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
this.camera = camera;
if(this.camera != null){
Logger.log_d(TAG, CLASS_NAME + ".setCamera() :: Setting camera.");
imgMonitor = CameraImageMonitor.getInstance();
requestLayout();
Logger.log_d(TAG, CLASS_NAME + ".setCamera() :: Camera set.");
}
}
public void surfaceCreated(SurfaceHolder holder){
// The Surface has been created, now tell the camera where to draw the preview.
Logger.log_d(TAG, CLASS_NAME + ".surfaceCreated() :: Creating surface view.");
try {
if(mCamera != null){
mCamera.setPreviewDisplay(holder);
}
if(camera != null)
camera.setPreviewDisplay(holder);
} catch (IOException e) {
Logger.log_d(TAG, "Error setting camera preview: " + e.getMessage());
Logger.log_e(TAG, CLASS_NAME + ".surfaceCreated() :: Error creating camera: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder){
if(mCamera != null){
mCamera.stopPreview();
}
if(camera != null)
camera.stopPreview();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){
if(mHolder.getSurface() == null){
public void surfaceChanged(SurfaceHolder tmpHolder, int format, int w, int h){
int result;
int rotation;
int degrees = 0;
Camera.Parameters camParams;
Logger.log_d(TAG, CLASS_NAME + ".surfaceChanged() :: Method started.");
if(this.holder.getSurface() == null || camera == null){
Logger.log_d(TAG, CLASS_NAME + ".surfaceChanged() :: Holder and/or camera are null.");
return;
}
try{
mCamera.stopPreview();
}catch (Exception e){ }
try{ camera.stopPreview(); }catch (Exception e){ }
requestLayout();
Camera.Parameters camParams = mCamera.getParameters();
/*Size optimal = getOptimalPreviewSize(camParams.getSupportedPreviewSizes(), w, h);
if(ProjectConstants.DEBUG)
Log.d(TAG, CLASS_NAME + ".surfaceChanged() :: Preview size set at (" + optimal.width + ", " + optimal.height + ")");*/
camParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(camParams);
camParams = camera.getParameters();
camParams.getSupportedPreviewSizes();
List<Size> sizes = camParams.getSupportedPreviewSizes();
for(Size size: sizes){
Logger.log_d(TAG, CLASS_NAME + ".surfaceChanged() :: Supported preview size (" + size.width + ", " + size.height + ")");
}
/*Size optimal = getOptimalPreviewSize(sizes, w, h);
Logger.log_d(TAG, CLASS_NAME + ".surfaceChanged() :: Preview size set at (" + optimal.width + ", " + optimal.height + ")");
camParams.setPreviewSize(optimal.width, optimal.height);*/
camParams.setPreviewSize(352, 288);
camera.setParameters(camParams);
/*previewWidth = optimal.width;
previewHeight = optimal.height;*/
previewWidth = 352;
previewHeight = 288;
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(0, info);
int rotation = parentActivity.getWindowManager().getDefaultDisplay().getRotation();
rotation = parentActivity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
@@ -99,41 +133,42 @@ public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback,
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
mCamera.setDisplayOrientation(result);
mCamera.setPreviewCallback(this);
camera.setDisplayOrientation(result);
camera.setPreviewCallback(this);
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
camera.setPreviewDisplay(this.holder);
camera.startPreview();
}catch (Exception e){
Logger.log_d(TAG, CLASS_NAME + ".surfaceChanged() :: Error starting camera preview: " + e.getMessage());
Logger.log_e(TAG, CLASS_NAME + ".surfaceChanged() :: Error starting camera preview: " + e.getMessage());
}
}
@Override
public void onPreviewFrame(byte[] data, Camera camera){
if(imgMonitor.hasChanged())
imgMonitor.setImageParameters(previewWidth, previewHeight);
Logger.log_d(TAG, CLASS_NAME + ".onPreviewFrame() :: Preview received");
Logger.log_d(TAG, CLASS_NAME + ".onPreviewFrame() :: Frame has" + (camMonitor.hasChanged() ? "" : " not") + " changed.");
if(!camMonitor.hasChanged())
camMonitor.setImageData(data);
Logger.log_d(TAG, CLASS_NAME + ".onPreviewFrame() :: Frame has" + (imgMonitor.hasChanged() ? "" : " not") + " been consumed.");
imgMonitor.setImageData(data);
}
public void removePreviewCallback(){
mCamera.setPreviewCallback(null);
if(camera != null)
camera.setPreviewCallback(null);
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
Logger.log_d(TAG, CLASS_NAME + ".getOptimalPreviewSize() :: Method started.");
if (sizes == null) return null;
Size optimalSize = null;
@@ -161,45 +196,9 @@ public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback,
}
}
}
Logger.log_d(TAG, CLASS_NAME + ".getOptimalPreviewSize() :: Method ended.");
Logger.log_d(TAG, CLASS_NAME + ".getOptimalPreviewSize() :: Optimal size is: (" + Integer.toString(optimalSize.width) +
", " + Integer.toString(optimalSize.height) + ")");
return optimalSize;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.dialogs;
import java.util.ArrayList;

View File

@@ -1,3 +1,18 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.dialogs;
import ve.ucv.ciens.ccg.nxtcam.R;

View File

@@ -1,3 +1,18 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.network;
import java.io.IOException;
@@ -213,9 +228,6 @@ public class BTCommunicator{
if(connected){
try{
byte[] message = new byte[bytes];
for(int i = 0; i < message.length; ++i){
message[i] = 0x00;
}
nxtInputStream.read(message, 0, bytes);
return message;
}catch(IOException e){

View File

@@ -1,191 +0,0 @@
package ve.ucv.ciens.ccg.nxtcam.network;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
public class BluetoothManager{
private static final UUID SERIAL_PORT_SERVICE_CLASS_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final String OUI_LEGO = "00:16:53";
private static final String TAG = "BTMNGR";
private boolean connected;
private BluetoothAdapter bt_adapter;
private BluetoothSocket bt_socket = null;
private OutputStream nxt_out_stream = null;
private InputStream nxt_in_stream = null;
private static class SingletonHolder{
public static final BluetoothManager INSTANCE = new BluetoothManager();
}
private BluetoothManager(){
connected = false;
bt_adapter = BluetoothAdapter.getDefaultAdapter();
bt_socket = null;
nxt_in_stream = null;
nxt_out_stream = null;
}
public static BluetoothManager getInstance(){
return SingletonHolder.INSTANCE;
}
public boolean isBTSupported(){
return bt_adapter != null;
}
public boolean isConnected(){
return connected;
}
public boolean isBTEnabled(){
return bt_adapter.isEnabled();
}
public void disableBT(){
bt_adapter.disable();
}
public Set<BluetoothDevice> getPairedDevices(){
return bt_adapter.getBondedDevices();
}
/**
* Sets up a connection with a NXT device.
*
* Verifies if the target device is a valid NXT robot by checking agains Lego's OUI.
* Also creates the socket and the streams associated with the connection
*
* @param mac_address The mac address of the target device.
* @return true if the connection was established succesfully, otherwise false.
* @throws IOException
*/
public boolean establishConnection(String mac_address) throws IOException{
if (!bt_adapter.isEnabled()){
return false;
}
if(connected){
return false;
}
if(bt_adapter.isEnabled()){
if(mac_address == "NONE"){
return false;
}else{
if(mac_address.substring(0, 8).compareTo(OUI_LEGO) != 0){
Log.d(TAG, "establishConnection() :: Not a Lego MAC. Prefix : " + mac_address.substring(0, 8) + " :: OUI : " + OUI_LEGO);
return false;
}else{
try{
Log.d(TAG, "establishConnection() :: Getting device with mac address: " + mac_address);
BluetoothDevice nxtDevice = null;
nxtDevice = bt_adapter.getRemoteDevice(mac_address);
if (nxtDevice == null) {
Log.e(TAG, "establishConnection() :: No device found.");
throw new IOException();
}
Log.d(TAG, "establishConnection() :: Opening socket.");
bt_socket = nxtDevice.createRfcommSocketToServiceRecord(SERIAL_PORT_SERVICE_CLASS_UUID);
Log.d(TAG, "establishConnection() :: Connecting.");
bt_socket.connect();
Log.d(TAG, "establishConnection() :: Opening IO streams.");
nxt_in_stream = bt_socket.getInputStream();
nxt_out_stream = bt_socket.getOutputStream();
Log.d(TAG, "establishConnection() :: Connection established.");
connected = true;
}catch(IOException e){
Log.e(TAG, "establishConnection() :: Connection failed.");
Log.e(TAG, Log.getStackTraceString(e));
connected = false;
throw e;
}
return connected;
}
}
}
return false;
}
/**
* Closes the active connection if any.
*
* Additionally clears the socket and the streams associated to said connection.
*
* @return true if the connection was succesfully closed; false if no connection exists.
* @throws IOException
*/
public boolean stopConnection() throws IOException{
try{
if(bt_socket != null){
Log.d(TAG, "stopConnection() :: Closing connection.");
bt_socket.close();
bt_socket = null;
nxt_in_stream = null;
nxt_out_stream = null;
connected = false;
Log.d(TAG, "stopConnection() :: Connection closed.");
return true;
}
}catch( IOException e){
Log.e(TAG, "stopConnection()");
Log.e(TAG, Log.getStackTraceString(e));
throw e;
}
return false;
}
/**
* Sends a message to the NXT robot.
*
* @param message The data to be sent.
* @throws IOException
*/
public synchronized void writeMessage(byte[] message) throws IOException{
if(connected){
try{
nxt_out_stream.write(message);
nxt_out_stream.flush();
}catch(IOException e){
Log.e(TAG, "writeMessage()");
Log.e(TAG, Log.getStackTraceString(e));
throw e;
}
}
}
/**
* Reads a message sent by the NXT robot.
*
* @return The data received as a byte[] if a valid connection exists, otherwise null.
* @throws IOException
*/
public synchronized byte[] readMessage(int bytes) throws IOException{
if(connected){
try{
byte[] message = new byte[bytes];
for(int i = 0; i < message.length; ++i){
message[i] = 0x00;
}
nxt_in_stream.read(message, 0, bytes);
return message;
}catch(IOException e){
Log.e(TAG, "readMessage()");
Log.e(TAG, Log.getStackTraceString(e));
throw e;
}
}else{
return null;
}
}
}

View File

@@ -1,107 +0,0 @@
package ve.ucv.ciens.ccg.nxtcam.network;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import ve.ucv.ciens.ccg.nxtcam.camera.CameraImageMonitor;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
import ve.ucv.ciens.ccg.nxtcam.utils.ProjectConstants;
public class ImageTransferThread extends Thread{
private final String TAG = "IM_THREAD";
private final String CLASS_NAME = ImageTransferThread.class.getSimpleName();
private boolean pause, done;
private Object threadPauseMonitor;
private CameraImageMonitor camMonitor;
private Socket socket;
private BufferedWriter writer;
private BufferedReader reader;
private byte[] image;
private String serverIp;
public ImageTransferThread(String serverIp){
this.serverIp = serverIp;
pause = false;
done = false;
threadPauseMonitor = new Object();
socket = null;
writer = null;
reader = null;
camMonitor = CameraImageMonitor.getInstance();
}
public void run(){
connectToServer();
if(socket.isConnected()){
Logger.log_e(TAG, CLASS_NAME + ".run() :: Not connected to a server. Finishing thread.");
}else{
while(!done){
checkPause();
image = camMonitor.getImageData();
// TODO: implement image transfer protocol.
}
}
}
private void connectToServer(){
try{
Logger.log_i(TAG, CLASS_NAME + ".connectToServer() :: Connecting to the server at " + serverIp);
socket = new Socket(InetAddress.getByName(serverIp), ProjectConstants.SERVER_TCP_PORT_1);
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Logger.log_i(TAG, CLASS_NAME + ".connectToServer() :: Connection successful.");
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".connectToServer() :: Connection failed with message: " + io.getMessage());
}
}
public void disconnect(){
if(socket != null && socket.isConnected()){
try{
socket.close();
}catch (IOException io) {
Logger.log_e(TAG, CLASS_NAME + ".connectToServer() :: " + io.getMessage());
}
}
}
public synchronized void finish(){
done = true;
Logger.log_i(TAG, CLASS_NAME + ".finish() :: Finishing thread.");
}
private void checkPause(){
synchronized (threadPauseMonitor){
while(pause){
Logger.log_d(TAG, CLASS_NAME + ".checkPause() :: Pause requested.");
try{ threadPauseMonitor.wait(); }catch(InterruptedException ie){}
}
}
}
public synchronized void pauseThread(){
pause = true;
Logger.log_d(TAG, CLASS_NAME + ".pauseThread() :: Pausing thread.");
}
public synchronized void resumeThread(){
Logger.log_d(TAG, CLASS_NAME + ".resumeThread() :: Resuming thread.");
synchronized (threadPauseMonitor) {
pause = false;
threadPauseMonitor.notifyAll();
}
}
public boolean isConnected(){
if(socket != null && socket.isConnected())
return true;
else
return false;
}
}

View File

@@ -1,12 +0,0 @@
package ve.ucv.ciens.ccg.nxtcam.network;
public class LCPThread extends Thread{
public LCPThread(){
}
public void run(){
}
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.network;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import ve.ucv.ciens.ccg.networkdata.MotorEvent;
import ve.ucv.ciens.ccg.networkdata.MotorEventACK;
import ve.ucv.ciens.ccg.nxtcam.robotcontrol.MotorEventQueue;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
import ve.ucv.ciens.ccg.nxtcam.utils.ProjectConstants;
public class MotorControlThread extends Thread {
private static final String TAG = "MOTOR_CONTROL";
private static final String CLASS_NAME = MotorControlThread.class.getSimpleName();
private Socket socket;
private String serverIp;
private MotorEventQueue queue;
private boolean done;
private ObjectInputStream reader;
private ObjectOutputStream writer;
private boolean connected;
public MotorControlThread(String serverIp){
super("Motor Control Thread");
this.serverIp = serverIp;
done = false;
connected = false;
queue = MotorEventQueue.getInstance();
}
@Override
public void run(){
Object msg;
MotorEvent event;
MotorEventACK ack;
if(!connectToServer()){
Logger.log_e(TAG, CLASS_NAME + ".run() :: The thread is not connected to a server. Finishing.");
return;
}else{
while(!done){
// Receive a message and enqueue it;
msg = readMessage();
event = verifyMessage(msg);
if(event != null){
queue.addEvent(event);
Logger.log_i(TAG, CLASS_NAME + ".run() :: Motor control message enqueued.");
Logger.log_i(TAG, CLASS_NAME + ".run() :: Motor ID: " + event.getMotor().toString());
Logger.log_i(TAG, CLASS_NAME + ".run() :: Motor power: " + Byte.toString(event.getPower()));
}else{
Logger.log_i(TAG, CLASS_NAME + ".run() :: Message could not be verified;");
}
// Send corresponding ack;
ack = new MotorEventACK(queue.getSize() >= 10);
try{
writer.writeObject(ack);
Logger.log_i(TAG, CLASS_NAME + ".run() :: First ACK sent.");
}catch(Exception ex){
Logger.log_e(TAG, CLASS_NAME + ".run() :: Exception while sending first ACK: " + ex.getMessage());
break;
}
if(ack.isClientQueueFull()){
while(queue.getSize() >= 10){ }
ack = new MotorEventACK(false);
try{
writer.writeObject(ack);
}catch(Exception ex){
Logger.log_i(TAG, CLASS_NAME + ".run() :: Second ACK sent.");
Logger.log_e(TAG, CLASS_NAME + ".run() :: Exception while sending second ACK: " + ex.getMessage());
break;
}
}
event = null;
ack = null;
msg = null;
}
try{
socket.close();
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".run() :: IOException while closing socket: " + io.getMessage());
}
}
}
public void finish(){
done = true;
}
public boolean connectToServer(){
try{
socket = new Socket(serverIp, ProjectConstants.MOTOR_CONTROL_PORT);
reader = new ObjectInputStream(socket.getInputStream());
writer = new ObjectOutputStream(socket.getOutputStream());
connected = true;
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".connectToServer() :: IOException caught: " + io.getMessage());
connected = false;
}
return connected;
}
private Object readMessage(){
Object message;
try{
message = reader.readObject();
Logger.log_i(TAG, CLASS_NAME + ".readMessage() :: Motor control message received.");
}catch(ClassNotFoundException cn){
Logger.log_e(TAG, CLASS_NAME + ".readMessage() :: ClassNotFoundException caught: " + cn.getMessage());
message = null;
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".readMessage() :: IOException caught: " + io.getMessage());
message = null;
}
return message;
}
private MotorEvent verifyMessage(Object message){
if(message != null && message instanceof MotorEvent){
Logger.log_i(TAG, CLASS_NAME + ".verifyMessage() :: Valid motor control message received.");
return (MotorEvent)message;
}else{
return null;
}
}
public boolean isConnected(){
return connected;
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.network;
import java.io.IOException;
import ve.ucv.ciens.ccg.networkdata.MotorEvent;
import ve.ucv.ciens.ccg.networkdata.MotorEvent.motor_t;
import ve.ucv.ciens.ccg.nxtcam.network.protocols.MotorMasks;
import ve.ucv.ciens.ccg.nxtcam.robotcontrol.MotorEventQueue;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
public class NxtBTCommThread extends Thread{
private static final String TAG = "LCP_THREAD";
private static final String CLASS_NAME = NxtBTCommThread.class.getSimpleName();
private boolean done;
private BTCommunicator btComm;
private MotorControlThread motorControl;
private MotorEventQueue queue;
public NxtBTCommThread(String serverIp){
super("Robot Control Main Thread");
btComm = BTCommunicator.getInstance();
done = false;
motorControl = new MotorControlThread(serverIp);
queue = MotorEventQueue.getInstance();
}
public void run(){
long then, now, delta;
MotorEvent event;
byte[] msg = new byte[2];
motorControl.start();
then = System.currentTimeMillis();
while(!motorControl.isConnected()){
now = System.currentTimeMillis();
delta = now - then;
if(delta > 9000L){
Logger.log_e(TAG, CLASS_NAME + ".run() :: Thread motorControl could not connect to the server.");
return;
}
}
while(!done){
if(btComm.isBTEnabled() && btComm.isConnected()){
msg[0] = 0x00;
msg[1] = 0x00;
event = queue.getNextEvent();
try{
// Set the motor bit.
msg[0] |= (event.getMotor() == motor_t.MOTOR_A) ? MotorMasks.MOTOR_A : 0;
msg[0] |= (event.getMotor() == motor_t.MOTOR_B) ? MotorMasks.MOTOR_B : 0;
msg[0] |= (event.getMotor() == motor_t.MOTOR_C) ? MotorMasks.MOTOR_C : 0;
// Set the direction bit.
if(event.getPower() > 0) msg[0] |= MotorMasks.DIRECTION;
// Set the recenter bits.
msg[0] |= (event.getMotor() == motor_t.RECENTER) ? MotorMasks.RECENTER : 0;
if((msg[0] & MotorMasks.RECENTER) > 0)
Logger.log_i(TAG, CLASS_NAME + ".run(): Recenter received.");
// Set the power byte.
msg[1] = (byte)Math.abs(event.getPower());
// Send the message.
btComm.writeMessage(msg);
Logger.log_i(TAG, CLASS_NAME + ".run() :: Message sent to the robot.");
try{ sleep(40); }catch(InterruptedException ie){ }
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".run() :: IOException sending message to the robot: " + io.getMessage());
}
}else{
Logger.log_e(TAG, CLASS_NAME + ".run() :: The robot disconnected or was never available.");
break;
}
}
}
public void finish(){
done = true;
}
}

View File

@@ -0,0 +1,73 @@
package ve.ucv.ciens.ccg.nxtcam.network;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
import ve.ucv.ciens.ccg.nxtcam.utils.ProjectConstants;
public class SensorReportThread extends Thread{
private static final String TAG = "SENSOR_REPORT";
private static final String CLASS_NAME = SensorReportThread.class.getSimpleName();
private Socket socket;
private String serverIp;
private boolean done;
private OutputStream writer;
private boolean connected;
private BTCommunicator btComm;
public SensorReportThread(String serverIp){
super("Sensor Report Thread");
this.serverIp = serverIp;
done = false;
connected = false;
btComm = BTCommunicator.getInstance();
}
@Override
public void run(){
byte[] lightReading;
if(connectToServer()){
while(!done){
if(btComm.isBTEnabled() && btComm.isConnected()){
try{
lightReading = btComm.readMessage(1);
writer.write(lightReading);
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + "run(): IOException: " + io.getMessage());
done = true;
}
}else{
Logger.log_e(TAG, CLASS_NAME + ".run() :: The robot disconnected or was never available.");
break;
}
}
}else{
Logger.log_e(TAG, CLASS_NAME + ".run() :: Could not connect to the server.");
}
}
public void finish(){
done = true;
}
private boolean connectToServer(){
boolean connected;
try{
socket = new Socket(serverIp, ProjectConstants.SENSOR_REPORT_PORT);
writer = socket.getOutputStream();
connected = true;
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".connectToServer() :: IOException caught: " + io.getMessage());
connected = false;
}
return connected;
}
public boolean isConnected(){
return connected;
}
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.network;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import ve.ucv.ciens.ccg.networkdata.VideoFrameDataMessage;
import ve.ucv.ciens.ccg.nxtcam.camera.CameraImageMonitor;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
import ve.ucv.ciens.ccg.nxtcam.utils.ProjectConstants;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
public class VideoStreamingThread extends Thread{
private final String TAG = "IM_THREAD";
private final String CLASS_NAME = VideoStreamingThread.class.getSimpleName();
private boolean pause, done;
private Object threadPauseMonitor;
private CameraImageMonitor camMonitor;
private Socket socket;
DatagramSocket udpSocket;
private String serverIp;
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public VideoStreamingThread(String serverIp){
super("Video Streaming Thread");
this.serverIp = serverIp;
done = false;
pause = false;
threadPauseMonitor = new Object();
socket = null;
camMonitor = CameraImageMonitor.getInstance();
}
public void run(){
try{
udpSocket = new DatagramSocket();
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".run() :: IOException received creating socket " + io.getMessage());
System.exit(1);
}
while(!done){
synchronized (threadPauseMonitor) {
while(pause){
try{ threadPauseMonitor.wait(); }catch(InterruptedException ie){ };
}
}
sendUdp();
try{
sleep(50L);
}catch(InterruptedException ie){}
}
Logger.log_d(TAG, CLASS_NAME + ".run() :: Thread finish reached.");
}
private byte[] int2ByteArray(int integer){
int shift;
byte[] array = new byte[4];
for(int i = 0; i < 4; i++){
shift = i << 3;
array[3 - i] = (byte)((integer & (0xff << shift)) >>> shift);
}
return array;
}
private void sendUdp(){
int bufferSize;
byte[] image;
byte[] buffer;
byte[] size;
DatagramPacket packet;
VideoFrameDataMessage message;
Rect imageSize;
YuvImage yuvImage;
image = camMonitor.getImageData();
imageSize = camMonitor.getImageParameters();
yuvImage = new YuvImage(image, ImageFormat.NV21, imageSize.width(), imageSize.height(), null);
yuvImage.compressToJpeg(imageSize, 90, outputStream);
message = new VideoFrameDataMessage();
message.data = outputStream.toByteArray();
message.imageWidth = imageSize.width();
message.imageHeight = imageSize.height();
outputStream.reset();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try{
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(message);
oos.flush();
oos.reset();
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".sendUdp() :: IOException received while serializing." + io.getMessage());
return;
}
buffer = baos.toByteArray();
baos.reset();
bufferSize = buffer.length;
size = int2ByteArray(bufferSize);
try{
packet = new DatagramPacket(size, 4, InetAddress.getByName(serverIp), ProjectConstants.VIDEO_STREAMING_PORT);
udpSocket.send(packet);
packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName(serverIp), ProjectConstants.VIDEO_STREAMING_PORT);
udpSocket.send(packet);
}catch(UnknownHostException uo){
Logger.log_e(TAG, CLASS_NAME + ".sendUdp() :: UnknownHostException received " + uo.getMessage());
return;
}catch(IOException io){
Logger.log_e(TAG, CLASS_NAME + ".sendUdp() :: IOException buffer size is " + Integer.toString(buffer.length));
Logger.log_e(TAG, CLASS_NAME + ".sendUdp() :: IOException received while sending " + io.getMessage());
return;
}
}
public void disconnect(){
if(socket != null && socket.isConnected()){
try{
Logger.log_d(TAG, CLASS_NAME + ".disconnect() :: Closing socket.");
socket.close();
}catch (IOException io) {
Logger.log_e(TAG, CLASS_NAME + ".connectToServer() :: " + io.getMessage());
}
}
}
public synchronized void finish(){
done = true;
Logger.log_i(TAG, CLASS_NAME + ".finish() :: Finishing thread.");
}
public void pauseThread(){
synchronized (threadPauseMonitor) {
pause = true;
}
Logger.log_d(TAG, CLASS_NAME + ".pauseThread() :: Pausing thread.");
}
public synchronized void resumeThread(){
Logger.log_d(TAG, CLASS_NAME + ".resumeThread() :: Resuming thread.");
synchronized (threadPauseMonitor) {
pause = false;
threadPauseMonitor.notifyAll();
}
}
public boolean isConnected(){
if(socket != null && socket.isConnected())
return true;
else
return false;
}
}

View File

@@ -1,17 +0,0 @@
package ve.ucv.ciens.ccg.nxtcam.network.protocols;
public abstract class ImageTransferProtocol{
public static enum ProtocolState{
SALUTE, IMG_FOLLOWS, SEND_DATA, PAUSED, WAITING, GOODBYE
}
public static final byte MSG_HELLO = (byte)0x89;
public static final byte MSG_GOODBYE = (byte)0x90;
public static final byte MSG_IMG_DATA = (byte)0x42;
public static final byte CMD_IMG_FOLLOWS = (byte)0x10;
public static final byte CMD_PAUSE = (byte)0x15;
public static final byte CMD_IMG_WAIT = (byte)0x20;
public static final byte ACK_SEND_IMG = (byte)0x40;
public static final byte ACK_IMG_RCVD = (byte)0x50;
}

View File

@@ -1,7 +1,28 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.network.protocols;
import java.security.InvalidParameterException;
import java.util.Arrays;
import ve.ucv.ciens.ccg.nxtcam.utils.Logger;
/**
* <p>Utility class that provides methods to get Lego Communication Protocol PDUs as byte arrays.</p>
**/
public abstract class LegoCommunicationProtocol{
/**
* Command types. Byte 0;
@@ -133,7 +154,7 @@ public abstract class LegoCommunicationProtocol{
if(turn_ratio < -100 || turn_ratio > 100){
throw new InvalidParameterException("Turn ratio out of range.");
}
if(mode_byte != MOTORON && mode_byte != BRAKE && mode_byte != REGULATED){
if(mode_byte < 0x00 || mode_byte > 0x07){
throw new InvalidParameterException("Invalid mode byte.");
}
if(regulation_mode != REGULATION_MODE_IDLE && regulation_mode != REGULATION_MODE_MOTOR_SPEED && regulation_mode != REGULATION_MODE_MOTOR_SYNC){
@@ -143,7 +164,7 @@ public abstract class LegoCommunicationProtocol{
throw new InvalidParameterException("Invalid run state.");
}
message[0] = 0x0C;
message[0] = 0x0D;
message[1] = 0x00;
message[2] = DIRECT_COMMAND_NO_REPLY;
message[3] = SET_OUTPUT_STATE;
@@ -155,9 +176,26 @@ public abstract class LegoCommunicationProtocol{
message[9] = run_state;
message[10] = message[11] = message[12] = message[13] = message[14] = 0x00;
Logger.log_d("LCP", LegoCommunicationProtocol.class.getSimpleName() + "setOutputState(...) :: " + Arrays.toString(message));
return message;
}
/**
* <p>Simpler call to the set motor configuration pdu method.</p>
*
* @param output_port The port in the brick the motor is connected to.
* @param power Motor power. Must be between -100 and 100.
* @return The assembled pdu.
*/
public static byte[] setOutputState(byte output_port, byte power){
if(power == (byte)0){
return setOutputState(output_port, power, (byte)0x00, REGULATION_MODE_IDLE, (byte)0x00, MOTOR_RUN_STATE_IDLE);
}else{
return setOutputState(output_port, power, (byte)(MOTORON + BRAKE), REGULATION_MODE_MOTOR_SPEED, (byte)0x00, MOTOR_RUN_STATE_RUNNING);
}
}
/**
* Motor configuration request pdu. Page 8 of appendix 2.
*

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.network.protocols;
/**
* <p>Bit masks used to code/decode the control instructions sent by NxtAR-cam to
* NxtAR-bot.</p>
* <p>Expansions 1-3 are currently unused.</p>
*/
public abstract class MotorMasks {
public static final byte MOTOR_A = (byte)0x01;
public static final byte MOTOR_B = (byte)0x02;
public static final byte MOTOR_C = (byte)0x04;
public static final byte DIRECTION = (byte)0x08;
public static final byte RECENTER = (byte)0x10;
public static final byte EXPANSION_1 = (byte)0x20;
public static final byte EXPANSION_2 = (byte)0x20;
public static final byte EXPANSION_3 = (byte)0x20;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.network.protocols;
public final class VideoStreamingProtocol{
public static final byte STREAM_CONTROL_END = 0x10;
public static final byte ACK_SEND_NEXT = 0x20;
public static final byte ACK_WAIT = 0x30;
public static final byte FLOW_CONTROL_WAIT = 0x40;
public static final byte FLOW_CONTROL_CONTINUE = 0x50;
public static final byte IMAGE_DATA = 0x60;
public static final byte UNRECOGNIZED = (byte)0xFF;
public static boolean checkValidityOfMessage(byte message){
boolean validity;
switch(message){
case STREAM_CONTROL_END:
case ACK_SEND_NEXT:
case ACK_WAIT:
case FLOW_CONTROL_WAIT:
case FLOW_CONTROL_CONTINUE:
case IMAGE_DATA:
case UNRECOGNIZED:
validity = true;
break;
default:
validity = false;
}
return validity;
}
}

View File

@@ -0,0 +1,61 @@
package ve.ucv.ciens.ccg.nxtcam.robotcontrol;
import java.util.LinkedList;
import java.util.Queue;
import ve.ucv.ciens.ccg.networkdata.MotorEvent;
/**
* <p>A simple monitor class that encapsulates a queue.</p>
* <p>As it name says it stores motor events to be forwarded to the NXT robot.</p>
* <p>This class implements the singleton design pattern.<p>
*
* @author Miguel Angel Astor Romero
*/
public class MotorEventQueue {
/**
* The event queue implemented as a linked list.
*/
private Queue<MotorEvent> motorEvents;
private MotorEventQueue(){
motorEvents = new LinkedList<MotorEvent>();
}
private static class SingletonHolder{
public static final MotorEventQueue instance = new MotorEventQueue();
}
/**
* Return the singleton instance of this class.
* @return The singleton instance.
*/
public static MotorEventQueue getInstance(){
return SingletonHolder.instance;
}
/**
* <p>Get the first event on the queue.</p>
* <p> If there are no events to return this method blocks until some thread calls the addEvent() method.</p>
* @return The event at the front of the queue.
*/
public synchronized MotorEvent getNextEvent(){
while(motorEvents.size() == 0){
try{ wait(); }catch(InterruptedException ie){ }
}
return motorEvents.poll();
}
/**
* <p>Adds an event to the back of the queue.</p>
* @param event The event to add.
*/
public synchronized void addEvent(MotorEvent event){
motorEvents.add(event);
notifyAll();
}
public synchronized int getSize(){
return motorEvents.size();
}
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.utils;
import android.util.Log;

View File

@@ -1,14 +1,39 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* 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 ve.ucv.ciens.ccg.nxtcam.utils;
import java.util.UUID;
import android.app.Activity;
public abstract class ProjectConstants {
public static final int SERVER_UDP_PORT = 8889;
public static final int SERVER_TCP_PORT_1 = 9989;
public static final int SERVER_TCP_PORT_2 = 9990;
// Network related constants.
public static final int SERVICE_DISCOVERY_PORT = 9988;
public static final int VIDEO_STREAMING_PORT = 9989;
public static final int MOTOR_CONTROL_PORT = 9990;
public static final int SENSOR_REPORT_PORT = 9991;
public static final int APP_CONTROL_PORT = 9992;
public static final UUID SERIAL_PORT_SERVICE_CLASS_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public static final String OUI_LEGO = "00:16:53";
public static final String MULTICAST_ADDRESS = "230.0.0.1";
public static final String SERVICE_DISCOVERY_MESSAGE = "NxtAR server here!";
// Activity results.
public static final int RESULT_CAMERA_FAILURE = Activity.RESULT_FIRST_USER + 1;
public static final boolean DEBUG = true;
}