├── .gitignore
├── .idea
├── .name
├── codeStyleSettings.xml
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
├── scopes
│ └── scope_settings.xml
└── vcs.xml
├── LICENSE
├── README.md
├── Virt3DMouse.iml
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── sketchpunk
│ │ └── virt3dmouse
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── sketchpunk
│ │ ├── shared
│ │ ├── ActivityBroadcastReceiver.java
│ │ ├── App.java
│ │ ├── ByteStack.java
│ │ ├── Divider.java
│ │ ├── RecyclerArrayAdapter.java
│ │ ├── RecyclerDivider.java
│ │ ├── RecyclerMultiArrayAdapter.java
│ │ ├── RecyclerViewFragment.java
│ │ ├── Toasty.java
│ │ └── ViewBindHolder.java
│ │ └── virt3dmouse
│ │ ├── BluetoothSerial.java
│ │ ├── GestureTouch.java
│ │ ├── MultiGesture.java
│ │ ├── Vert.java
│ │ ├── activities
│ │ ├── ControlActivity.java
│ │ └── PairListActivity.java
│ │ ├── fragments
│ │ ├── BTPairListFragment.java
│ │ └── CommandListFragment.java
│ │ └── ui
│ │ └── TouchView.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── drawable
│ ├── ic_autorenew_24dp.xml
│ ├── ic_bluetooth_disabled_24dp.xml
│ └── ic_bluetooth_searching_24dp.xml
│ ├── layout-land
│ └── activity_control.xml
│ ├── layout
│ ├── activity_control.xml
│ ├── activity_pair_list.xml
│ └── list_item.xml
│ ├── menu
│ ├── menu_main.xml
│ └── menu_pair.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── blender_files
├── 3dmouse_plugin_alpha.py
├── serial
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-35.pyc
│ │ ├── aio.cpython-35.pyc
│ │ ├── rfc2217.cpython-35.pyc
│ │ ├── rs485.cpython-35.pyc
│ │ ├── serialcli.cpython-35.pyc
│ │ ├── serialjava.cpython-35.pyc
│ │ ├── serialposix.cpython-35.pyc
│ │ ├── serialutil.cpython-35.pyc
│ │ ├── serialwin32.cpython-35.pyc
│ │ └── win32.cpython-35.pyc
│ ├── aio.py
│ ├── rfc2217.py
│ ├── rs485.py
│ ├── serialcli.py
│ ├── serialjava.py
│ ├── serialposix.py
│ ├── serialutil.py
│ ├── serialwin32.py
│ ├── threaded
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ │ └── __init__.cpython-35.pyc
│ ├── tools
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-35.pyc
│ │ │ ├── hexlify_codec.cpython-35.pyc
│ │ │ ├── list_ports.cpython-35.pyc
│ │ │ ├── list_ports_common.cpython-35.pyc
│ │ │ ├── list_ports_linux.cpython-35.pyc
│ │ │ ├── list_ports_osx.cpython-35.pyc
│ │ │ ├── list_ports_posix.cpython-35.pyc
│ │ │ ├── list_ports_windows.cpython-35.pyc
│ │ │ └── miniterm.cpython-35.pyc
│ │ ├── hexlify_codec.py
│ │ ├── list_ports.py
│ │ ├── list_ports_common.py
│ │ ├── list_ports_linux.py
│ │ ├── list_ports_osx.py
│ │ ├── list_ports_posix.py
│ │ ├── list_ports_windows.py
│ │ └── miniterm.py
│ ├── urlhandler
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-35.pyc
│ │ │ ├── protocol_alt.cpython-35.pyc
│ │ │ ├── protocol_hwgrep.cpython-35.pyc
│ │ │ ├── protocol_loop.cpython-35.pyc
│ │ │ ├── protocol_rfc2217.cpython-35.pyc
│ │ │ ├── protocol_socket.cpython-35.pyc
│ │ │ └── protocol_spy.cpython-35.pyc
│ │ ├── protocol_alt.py
│ │ ├── protocol_hwgrep.py
│ │ ├── protocol_loop.py
│ │ ├── protocol_rfc2217.py
│ │ ├── protocol_socket.py
│ │ └── protocol_spy.py
│ └── win32.py
└── serial_mouse5.blend
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Virt3DMouse
--------------------------------------------------------------------------------
/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | xmlns:android
80 | Namespace:
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | xmlns:.*
90 | Namespace:
91 |
92 |
93 | BY_NAME
94 |
95 |
96 |
97 |
98 |
99 |
100 | .*:id
101 | http://schemas.android.com/apk/res/android
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | .*:name
111 | http://schemas.android.com/apk/res/android
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | name
121 | ^$
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | style
131 | ^$
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | .*
141 | ^$
142 |
143 |
144 | BY_NAME
145 |
146 |
147 |
148 |
149 |
150 |
151 | .*:layout_width
152 | http://schemas.android.com/apk/res/android
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | .*:layout_height
162 | http://schemas.android.com/apk/res/android
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | .*:layout_.*
172 | http://schemas.android.com/apk/res/android
173 |
174 |
175 | BY_NAME
176 |
177 |
178 |
179 |
180 |
181 |
182 | .*:width
183 | http://schemas.android.com/apk/res/android
184 |
185 |
186 | BY_NAME
187 |
188 |
189 |
190 |
191 |
192 |
193 | .*:height
194 | http://schemas.android.com/apk/res/android
195 |
196 |
197 | BY_NAME
198 |
199 |
200 |
201 |
202 |
203 |
204 | .*
205 | http://schemas.android.com/apk/res/android
206 |
207 |
208 | BY_NAME
209 |
210 |
211 |
212 |
213 |
214 |
215 | .*
216 | .*
217 |
218 |
219 | BY_NAME
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android Virtual 3D Mouse for Blender 3D
2 | This project was a 2 week sprint to create a proof of concept that you can turn an android device into a 3D mouse that can control a 3d modeling application. Since I'm learning blender and its built in such a way that they make it easy to interface with it, I use that app as the basis of the experiment. This project is solely meant as a submission for the Android Experiements contest. If there is an actual need for this, then I may continue it further but maybe swopping out the serial communications for UDP connection, which should remove the hardware requirements to get android to communicate with windows.
3 |
4 | Youtube video of this in action - https://youtu.be/0j87vnCestY
5 |
6 | ### Prerequisities
7 | - Blender 2.77 - https://www.blender.org/download/
8 | - PySerial
9 | - PL2303 USB UART Board USB to Serial - http://amzn.to/1NlNr8G
10 | - HC-05 Bluetooth Host Serial Transceiver For Arduino - http://amzn.to/1NlNuS2
11 | - Android Studio
12 |
13 | ## Getting Started
14 |
15 | 1. Get blender and setup PySerial.
16 | So the first thing is you have to go download blender. From there, look in the blender_files folder, you will find a folder called serial. This is PySerial for python v3, windows x64. If you have X86 machine, google on how to download pyserial. Copy the serial folder to \blender-2.77-windows64\2.77\python\lib\site-packages. Thats all to it.
17 |
18 | 2. Put together your serial boards together. They're fairly easy to put together. Power -> Power, Gnd -> Gnd, TXD -> RXD, RXD -> TXD. Make sure you set the PL2303 to 3 volt jumper, not 5. The HC-05 board will get power from PL2303, but it only needs 3v. Once plugged in and drivers install (windows10 self installed the drivers). Go to device manager and find what COM port the PL2303 is using.
19 |
20 | 3. Use Android studio and compile the app.
21 |
22 | 4. Now you put everything together. Run blender, open up serial_mouse5.blend in the blender_files folder. (5 stands for 5th attempt, pita to figure it all out but fun). In blender, in the Text Editor area, click run script. This will create a new UI Panel that you can access in the Tools panel, SMouse. All you need to do is change the port to COM then a number of what the PL2303 is using. The Baud can be left alone. All you have to do is press connect and it will create a thread that connects and listens for serial data coming for the COM port. It'll also create a timer modal loop that works as a handler for the thread to push back some commands that need to be run in the UI thread because blender has this context thing that the thread can't use. You can see the debug text I'm outputing in the console. Just go to Window Menu, click "toggle system console" to see it
23 |
24 | 5. On your android device, Pair up to the HC-05 board. The default code should be 1234. Turn on the 3d mouse app, click on the paired device and it should auto connect. From there you should be in control of blender.
25 |
26 | I know, this is kind of a complex setup.
27 |
28 | ## Authors
29 |
30 | * Pedro S. (Vor of SketchpunkLabs) - http://sketchpunklabs.tumblr.com/
31 |
32 | ## Acknowledgments
33 | All the people who wrote various tutorials that I've read about blender, python, how to get android talking to arduino with bluetooth serial. The guy who answered one of my questions on reddit about how to invoke an operators. Plus many more, I couldn't of done this without all their shared knowledge. So thank you everyone.
34 |
--------------------------------------------------------------------------------
/Virt3DMouse.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.2"
6 |
7 | defaultConfig {
8 | applicationId "com.sketchpunk.virt3dmouse"
9 | minSdkVersion 19
10 | targetSdkVersion 21
11 | versionCode 1
12 | versionName "1.0"
13 | resValue "string", "test", "default"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | debug {
21 | applicationIdSuffix ".debug"
22 | versionNameSuffix "-debug"
23 | resValue "string", "test", "debug"
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | compile 'com.android.support:support-v4:21.0.3'
31 | compile 'com.android.support:appcompat-v7:21.0.3'
32 | compile 'com.android.support:recyclerview-v7:21.0.3'
33 | }
34 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Vor\android_sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/sketchpunk/virt3dmouse/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/ActivityBroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.app.Activity;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.support.v4.app.Fragment;
9 | import android.support.v7.app.ActionBarActivity;
10 |
11 | /*
12 | public class MyActivity extends ActionBarActivity implements ActivityBroadcastReceiver.Handler{
13 |
14 | private ActivityBroadcastReceiver mReceiver = null;
15 |
16 | protected void onCreate(Bundle savedInstanceState){
17 | mReceiver = new ActivityBroadcastReceiver(this, Sync.ACT_COMPLETE,AppUpdate.ACT_UPDATE_READY);
18 |
19 | public void onResume(){
20 | mReceiver.register();
21 |
22 | public void onPause(){
23 | mReceiver.unregister();
24 |
25 | public void onBroadcastReceived(Context context, Intent intent){
26 | switch(intent.getAction()){
27 |
28 |
29 | //Broadcast Results of the login.
30 | Intent intent = new Intent(ACT_COMPLETE);
31 | intent.putExtra("STATUS",sendStatus);
32 | intent.putExtra("MSG",sendMsg);
33 | intent.putExtra("NEWUPDATE",newUpdate);
34 | zApp.getContext().sendBroadcast(intent);
35 | */
36 |
37 | public class ActivityBroadcastReceiver extends BroadcastReceiver{
38 | //region Interface, Variables, Constructor, Init
39 | public static interface Handler{ public void onBroadcastReceived(Context context, Intent intent); }
40 |
41 | private final Activity mActivity;
42 | private Handler mHandler = null;
43 |
44 | private IntentFilter mIntentFilter = null;
45 |
46 | public ActivityBroadcastReceiver(ActionBarActivity act,String... filter){
47 | mActivity = act;
48 | if(act instanceof Handler) mHandler = (Handler) act;
49 | init(filter);
50 | }//func
51 |
52 | public ActivityBroadcastReceiver(Fragment frag,String... filter){
53 | mActivity = frag.getActivity();
54 | if(frag instanceof Handler) mHandler = (Handler) frag;
55 | init(filter);
56 | }//func
57 |
58 | private void init(String[] filter){
59 | mIntentFilter = new IntentFilter();
60 | for(int i=0; i < filter.length; i++) mIntentFilter.addAction(filter[i]);
61 | }//func
62 | //endregion
63 |
64 | //region Methods
65 | public void addAction(String action){ mIntentFilter.addAction(action); }//func
66 |
67 | public void register(){ mActivity.registerReceiver(this,mIntentFilter); }
68 | public void unregister(){ mActivity.unregisterReceiver(this); }
69 | //endregion
70 |
71 | //region Events
72 | @Override
73 | public void onReceive(Context context, Intent intent){
74 | if(mHandler != null) mHandler.onBroadcastReceived(context,intent);
75 | }//func
76 | //endregion
77 | }//cls
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/App.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | public class App extends Application {
8 | private static Context mContext = null;
9 | private Thread.UncaughtExceptionHandler mDefaultExceptionHandler = null;
10 |
11 | public void onCreate(){
12 | super.onCreate();
13 | App.mContext = getApplicationContext();
14 |
15 | //mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); //Save Reference to default.
16 | //Thread.setDefaultUncaughtExceptionHandler(mUncaughtExceptionHandler);
17 | }//func
18 |
19 | //region Static Global Functions
20 | public static Context getContext(){ return App.mContext; }//func
21 | public static void broadcast(Intent intent){ App.mContext.sendBroadcast(intent); }//func
22 | //endregion
23 |
24 | //region Error Handling
25 | private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler = new Thread.UncaughtExceptionHandler(){
26 | @Override public void uncaughtException(Thread thread, Throwable throwable){
27 | //Logger.error("Uncaught.Exception",throwable);
28 |
29 | //Pass this exception back to the system (very important).
30 | //if(mDefaultExceptionHandler != null) mDefaultExceptionHandler.uncaughtException(thread,throwable);
31 | }//func
32 | };
33 | //endregion
34 | }//cls
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/ByteStack.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 | import java.util.ArrayList;
3 |
4 | /* TESTING CODE
5 | byte[] bytes = "rawr~woot~amazing".getBytes();
6 | ByteStack stack = new ByteStack(50);
7 |
8 | stack.put(bytes);
9 | stack.getAvailable('~');
10 | //System.out.println(stack.getTill('~', true));
11 | //System.out.println(stack.getTill('~', true));
12 | //System.out.println(stack.getTill('~', true));
13 | //System.out.println(stack.getTill('~', true));
14 | //System.out.println(stack.getTill('~', true));
15 | //System.out.println(stack.getTill('~', true));
16 | System.out.println(stack.getRemaining());
17 | */
18 |
19 |
20 | /* When reading data from a serial connection, it requires several reads to get the message at times
21 | So this class is to buffer the results and makes it easy to get each chunk of data by the
22 | delimiter being used in the stream.
23 | */
24 | public class ByteStack{
25 | //region Properties + Constructor
26 | private byte[] mArray; //Data Storage
27 | private int mAllocated = 0; //Size of storage
28 | private int mWritePos = 0; //THe position that the next write should start on
29 | private int mReadPos = 0; //The position that the next read should start on.
30 |
31 | public ByteStack(int size){
32 | mArray = new byte[size];
33 | mAllocated = size;
34 | }//func
35 | //endregion
36 |
37 | //region Writing to stack
38 |
39 | //copy array data to stack
40 | public boolean put(byte[] ary){ return put(ary,0,ary.length); }
41 | public boolean put(byte[] ary,int offset,int len){
42 | if(len + mWritePos > mAllocated) return false; //Can not write passed allocated space.
43 |
44 | int stop = offset+len;
45 | for(int i=offset; i < stop; i++){
46 | //System.out.println((char) ary[i]);
47 | mArray[mWritePos] = ary[i];
48 | mWritePos++;
49 | }//for
50 |
51 | return true;
52 | }//func
53 | //endregion
54 |
55 | //region Reading from stack
56 |
57 | //Read all the data till a character is found.
58 | //Stack cleaning can be controlled, allows dev to do a few readings
59 | //in a row before wasting processing time re-shifting the data.
60 | public String getTill(char chr,boolean doClear){
61 | if(mWritePos == 0 || mReadPos >= mWritePos) return null;
62 |
63 | //System.out.println("READTILL START");
64 | int i = mReadPos;
65 | boolean isFound = false;
66 | String rtn = null;
67 |
68 | for(; i < mWritePos; i++){
69 | if(mArray[i] == chr){
70 | rtn = new String(mArray,mReadPos,i-mReadPos);
71 | //System.out.format("Found read %d %d %d\n", mReadPos,i , mWritePos);
72 | //System.out.println(rtn);
73 | isFound = true;
74 | mReadPos = i+1;// Set the position start of the next read.
75 | break;
76 | }//if
77 | }//f0r
78 |
79 | if(isFound){
80 | if(mReadPos >= mWritePos){
81 | //System.out.println("EOB - Reset");
82 | mReadPos = 0;
83 | mWritePos = 0;
84 | }else if(doClear) clearRead();
85 | }//if
86 |
87 | return rtn;
88 | }//func
89 |
90 |
91 | public String[] getAvailable(char chr){
92 | ArrayList ary = new ArrayList();
93 | String txt = "";
94 |
95 | //Read all available string that ends with char.
96 | while( (txt = getTill(chr,false)) != null ){
97 | ary.add(txt);
98 | //System.out.println(txt);
99 | }//while
100 |
101 | if(ary.size() > 0){
102 | clearRead(); //do cleanup on read process.
103 | return ary.toArray(new String[ary.size()]);
104 | }//if
105 |
106 | return null;
107 | }//func
108 |
109 | //get whatever is left in the stack
110 | public String getRemaining(){
111 | if(mWritePos == 0) return null;
112 |
113 | String rtn = null;
114 | if(mReadPos < mWritePos){
115 | //System.out.format("Remaining %d\n", mWritePos - mReadPos);
116 | //System.out.format("Found read %d %d \n", mReadPos,mWritePos);
117 | rtn = new String(mArray, mReadPos, mWritePos - mReadPos);
118 | //System.out.println("Da End " + txt);
119 | }//if
120 |
121 | //Reset all positions since the rest of the data has been read.
122 | mWritePos = 0;
123 | mReadPos = 0;
124 |
125 | return rtn;
126 | }//func
127 | //endregion
128 |
129 | //region Stack Maintenance
130 | //This shifts all the unread data to the beginning of the array
131 | //If using this object alot, then there needs to be some cleanup
132 | //Or the allocated space will be used up.
133 | public void clearRead(){
134 | if(mWritePos == 0) return; //No need to do any cleaning. Writing is set back to start.
135 | //System.out.println("CLEAR");
136 | int pos = -1;
137 | for(int i=mReadPos; i < mWritePos; i++) mArray[++pos] = mArray[i];
138 |
139 | mWritePos = pos+1;
140 | mReadPos = 0;
141 | }//func
142 | //endregion
143 | }//cls
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/Divider.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.DashPathEffect;
8 | import android.graphics.Paint;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.util.AttributeSet;
11 | import android.util.DisplayMetrics;
12 | import android.util.TypedValue;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.LinearLayout;
16 |
17 | public class Divider extends View {
18 | private Paint mPaint = null;
19 | private int mHeight = 1;
20 |
21 | public Divider(Context context){ super(context); init("#000000",2,0,0); }
22 | public Divider(Context context, AttributeSet attrs){
23 | super(context, attrs);
24 | init("#707070",10,0,0);
25 |
26 | /*
27 | String color = "#a0a0a0";
28 | int size = 1, dash = 2, gap = 5;
29 |
30 | TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.sp2Divider);
31 | final int n = a.getIndexCount();
32 | */
33 |
34 | /*
35 | for(int i=0; i < n; i++){
36 | int attr = a.getIndex(i);
37 | switch(attr){
38 | case R.styleable.spDivider_lineColor: color = a.getString(attr); break;
39 | case R.styleable.spDivider_lineSize: size = a.getInt(attr,1); break;
40 | case R.styleable.spDivider_lineStyle:
41 | System.out.println("LineSTyle");
42 | System.out.println(a.getInt(attr,0));
43 | switch(a.getInt(attr,0)){
44 | case 0: dash = 0; gap = 0; break; //line
45 | case 1: dash = 2; gap = 5; break; //Dotted
46 | case 2: dash = 7; gap = 11; break; //Dashes
47 | }//switch
48 | break;
49 | }//switch
50 | }//for
51 | */
52 |
53 | //a.recycle();
54 | //init(color, size, dash, gap);
55 | }//func
56 |
57 | private void init(String color,int w, float wDash, float wGap){
58 | System.out.println("Divider.ini");
59 |
60 | DisplayMetrics dm = getResources().getDisplayMetrics() ;
61 | float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, w, dm);
62 |
63 | mPaint = new Paint();
64 | mPaint.setStyle(Paint.Style.STROKE);
65 | mPaint.setColor(Color.parseColor(color));
66 | mPaint.setStrokeWidth(strokeWidth);
67 | if(wDash > 0 && wGap > 0) mPaint.setPathEffect(new DashPathEffect(new float[] {wDash,wGap},0));
68 |
69 | mHeight = w;
70 | setMinimumHeight(w);
71 | setLayerType(View.LAYER_TYPE_SOFTWARE, null);
72 | }//func
73 |
74 | @Override
75 | public void onDraw(Canvas c){
76 | int left = getPaddingLeft(), right = getWidth() - getPaddingRight();
77 | System.out.println("Divider.onDraw");
78 | c.drawLine(left, 0, right, 0, mPaint);
79 | }//func
80 |
81 | @Override
82 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
83 | int width,height
84 | ,widthMode = MeasureSpec.getMode(widthMeasureSpec)
85 | ,widthSize = MeasureSpec.getSize(widthMeasureSpec)
86 | ,heightMode = MeasureSpec.getMode(heightMeasureSpec)
87 | ,heightSize = MeasureSpec.getSize(heightMeasureSpec);
88 |
89 | //Measure Width
90 | if(widthMode == MeasureSpec.EXACTLY) width = widthSize;
91 | else if(widthMode == MeasureSpec.AT_MOST) width = widthSize;
92 | else width = 100;
93 |
94 | //Measure Height
95 | if(heightMode == MeasureSpec.EXACTLY) height = heightSize;
96 | else if(heightMode == MeasureSpec.AT_MOST) height = mHeight;
97 | else height = mHeight;
98 |
99 | setMeasuredDimension(width, height);
100 | }//func
101 | }//cls
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/RecyclerArrayAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | /*
10 | adapter = RecyclerArrayListAdapter(android.R.layout.simple_list_item_1);
11 | adapter.setCallback(new RecyclerArrayListAdapter.Callback(){
12 | @Override public ViewBindHolder onCreateViewHolder(View v){ return new MyViewHolder(view); }
13 | });
14 | */
15 |
16 | public class RecyclerArrayAdapter extends RecyclerView.Adapter{
17 | private T[] mArray = null;
18 | private int mItemLayout = 0;
19 | private Callback mCallBack = null;
20 | private LayoutInflater mInflater = null;
21 |
22 | public static interface Callback{ public ViewBindHolder onCreateViewHolder(View v); }//interface
23 |
24 | public RecyclerArrayAdapter(Context context,int itmLayout){
25 | mItemLayout = itmLayout;
26 | mInflater = LayoutInflater.from(context);
27 | }//func
28 |
29 | //region setter/getters
30 | public void setCallback(Callback cb){ mCallBack = cb; }
31 | public void setArray(T[] ary){ mArray = ary; }
32 | public T get(int pos){ return (mArray != null)? mArray[pos] : null; }
33 | //endregion
34 |
35 | //region Adapter
36 | @Override
37 | public ViewBindHolder onCreateViewHolder(ViewGroup parent, int viewType){
38 | if(mCallBack == null) return null;
39 |
40 | View view = mInflater.inflate(mItemLayout,parent,false);
41 | return mCallBack.onCreateViewHolder(view);
42 | }//func
43 |
44 | @Override
45 | public void onBindViewHolder(ViewBindHolder holder, int position){ holder.bindData(position); }
46 |
47 | @Override public int getItemCount(){ return (mArray != null)? mArray.length : 0; }
48 | //endregion
49 | }//func
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/RecyclerDivider.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Color;
5 | import android.graphics.DashPathEffect;
6 | import android.graphics.Paint;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.view.View;
9 |
10 | public class RecyclerDivider extends RecyclerView.ItemDecoration{
11 | private Paint mPaint = null;
12 | public static enum Style{ DOTTED, DASHED };
13 | public static final int DOTTED = 1;
14 | public static final int DASHED = 2;
15 |
16 | //region Constructor
17 | public RecyclerDivider(){ init("#707070",1,7,11); }//func
18 | public RecyclerDivider(String color){ init(color,1,0,0); }//func
19 | public RecyclerDivider(String color, int w){ init(color,w,0,0); }//func
20 | public RecyclerDivider(String color, int w, float wDash, float wGap){ init(color,w,wDash,wGap); }//func
21 | public RecyclerDivider(String color,int w, Style style){
22 | switch(style){
23 | case DOTTED: init(color,w,2,5); break;
24 | case DASHED: init(color,w,7,11); break;
25 | default: init(color,w,0,0); break;
26 | }//switch
27 | }//func
28 |
29 | private void init(String color,int w, float wDash, float wGap){
30 | mPaint = new Paint();
31 | mPaint.setStyle(Paint.Style.STROKE);
32 | mPaint.setColor(Color.parseColor(color));
33 | mPaint.setStrokeWidth(w);
34 | if(wDash > 0 && wGap > 0) mPaint.setPathEffect(new DashPathEffect(new float[] {wDash,wGap},0));
35 | }//func
36 | //endregion
37 |
38 | @Override
39 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state){
40 | int left = parent.getPaddingLeft();
41 | int right = parent.getWidth() - parent.getPaddingRight();
42 | int top = 0, bottom = 0;
43 | View child;
44 | int childCount = parent.getChildCount();
45 |
46 | parent.setLayerType(View.LAYER_TYPE_SOFTWARE,null); //DashPath Effect does not work unless you turn off hardware accel on view.
47 |
48 | for(int i = 0; i < childCount - 1; i++){
49 | child = parent.getChildAt(i);
50 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
51 |
52 | top = child.getBottom() + params.bottomMargin;
53 | bottom = top;
54 |
55 | c.drawLine(left, top, right, bottom, mPaint);
56 | }//for
57 | }//func
58 |
59 | public static void disableHardwareRendering(View v) {
60 | if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
61 | v.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
62 | }
63 | }
64 |
65 | }//cls
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/RecyclerMultiArrayAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 |
10 | public class RecyclerMultiArrayAdapter extends RecyclerView.Adapter{
11 | private T[][] mArray = null;
12 | private int mItemLayout = 0;
13 | private Callback mCallBack = null;
14 | private LayoutInflater mInflater = null;
15 |
16 | public static interface Callback{ public ViewBindHolder onCreateViewHolder(View v); }//interface
17 |
18 | public RecyclerMultiArrayAdapter(Context context,int itmLayout){
19 | mItemLayout = itmLayout;
20 | mInflater = LayoutInflater.from(context);
21 | }//func
22 |
23 | //region setter/getters
24 | public void setCallback(Callback cb){ mCallBack = cb; }
25 | public void setArray(T[][] ary){ mArray = ary; }
26 | public T[] get(int pos){ return (mArray != null)? mArray[pos] : null; }
27 | //endregion
28 |
29 | //region Adapter
30 | @Override
31 | public ViewBindHolder onCreateViewHolder(ViewGroup parent, int viewType){
32 | if(mCallBack == null) return null;
33 |
34 | View view = mInflater.inflate(mItemLayout,parent,false);
35 | return mCallBack.onCreateViewHolder(view);
36 | }//func
37 |
38 | @Override
39 | public void onBindViewHolder(ViewBindHolder holder, int position){ holder.bindData(position); }
40 |
41 | @Override public int getItemCount(){ return (mArray != null)? mArray.length : 0; }
42 | //endregion
43 | }//func
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/RecyclerViewFragment.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.Gravity;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.FrameLayout;
12 | import android.widget.TextView;
13 |
14 | public class RecyclerViewFragment extends Fragment{
15 | protected RecyclerView mRecyclerView = null;
16 | protected TextView mTextView = null;
17 | protected RecyclerView.LayoutManager mLayoutManager = null;
18 | protected FrameLayout mFrameLayout = null;
19 |
20 | /* Interesting Idea but doesn't work.
21 | public static E DynamicAdd(ActionBarActivity act){
22 | FragmentManager man = act.getFragmentManager();
23 | FragmentTransaction trans = man.beginTransaction();
24 |
25 | E frag = new E();
26 | trans.replace(android.R.id.content,frag);
27 |
28 | return frag;
29 | }//
30 | */
31 |
32 |
33 | //region Fragment Events
34 | @Override
35 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
36 | mLayoutManager = new LinearLayoutManager(getActivity());
37 |
38 | FrameLayout.LayoutParams lpFrame = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
39 | FrameLayout.LayoutParams lpText = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
40 | lpText.gravity = Gravity.CENTER;
41 |
42 | mRecyclerView = new RecyclerView(getActivity());
43 | mRecyclerView.setLayoutParams(lpFrame);
44 | mRecyclerView.setLayoutManager(mLayoutManager);
45 |
46 | mTextView = new TextView(getActivity());
47 | mTextView.setLayoutParams(lpText);
48 | mTextView.setText("Loading");
49 | mTextView.setGravity(Gravity.CENTER);
50 |
51 | mFrameLayout = new FrameLayout(getActivity());
52 | mFrameLayout.setLayoutParams(lpFrame);
53 | mFrameLayout.addView(mRecyclerView);
54 | mFrameLayout.addView(mTextView);
55 | //mFrameLayout.setBackgroundColor(getResources().getColor(android.R.color.holo_green_light)); //Debugging UI Issues.
56 |
57 | return mFrameLayout;
58 | }//func
59 | //endregion
60 |
61 | //region Manage Recycler
62 | public void setRecyclerAdapter(RecyclerView.Adapter adapter){ mRecyclerView.setAdapter(adapter); }
63 | public void addItemDecoration(RecyclerView.ItemDecoration itm){ mRecyclerView.addItemDecoration(itm); }
64 | //endregion
65 |
66 | //region Manage Text Area
67 | public void hideTextView(){ mTextView.setVisibility(View.GONE); }
68 | public void showTextView(){ mTextView.setVisibility(View.VISIBLE); }
69 | public void showTextView(String txt){ mTextView.setText(txt); mTextView.setVisibility(View.VISIBLE); }
70 | public void setTextMsg(String txt){ mTextView.setText(txt); }
71 | //endregion
72 | }//cls
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/Toasty.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.content.Context;
4 | import android.view.Gravity;
5 | import android.widget.Toast;
6 |
7 | public class Toasty{
8 | public static void center(String msg,Boolean isLong){ center(App.getContext(),msg,isLong); }//func
9 |
10 | public static void center(Context context,String msg,Boolean isLong){
11 | Toast toast = Toast.makeText(context,msg,(isLong)?Toast.LENGTH_LONG:Toast.LENGTH_SHORT);
12 | toast.setGravity(Gravity.CENTER, 0, 0);
13 | toast.show();
14 | }//func
15 | }//cls
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/shared/ViewBindHolder.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.shared;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 | public abstract class ViewBindHolder extends RecyclerView.ViewHolder{
7 | public ViewBindHolder(View itemView){ super(itemView); }
8 | public abstract void bindData(int pos);
9 | }//func
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/BluetoothSerial.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse;
2 |
3 | import android.app.Activity;
4 | import android.app.ProgressDialog;
5 | import android.bluetooth.BluetoothAdapter;
6 | import android.bluetooth.BluetoothDevice;
7 | import android.bluetooth.BluetoothSocket;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.os.AsyncTask;
11 | import android.widget.Toast;
12 |
13 | import com.sketchpunk.shared.App;
14 | import com.sketchpunk.shared.ByteStack;
15 |
16 | import java.io.IOException;
17 | import java.io.InputStream;
18 | import java.io.OutputStream;
19 | import java.io.UnsupportedEncodingException;
20 | import java.util.ArrayList;
21 | import java.util.Set;
22 | import java.util.UUID;
23 |
24 | public class BluetoothSerial{
25 | //region Constants
26 | public static final String ACTION_BTCONNECTION = "btserial.conn";
27 | public static final UUID UUID_INSECURE_SPP = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //insecure spp connection code.
28 | public static final int STATE_NOBT = 0;
29 | public static final int STATE_NOENABLED = 1;
30 | public static final int STATE_READY = 5;
31 | public static final int STATE_CONNECTING = 2;
32 | public static final int STATE_NODEVICES = 3;
33 | public static final int STATE_CONNECTED = 4;
34 | public static final int STATE_ERROR = -1;
35 | public static final int STATE_UNKNOWN = -99;
36 | public static final int BTENABLE_REQUEST = 12280;
37 | //endregion
38 |
39 | //region Private Variables
40 | private static boolean mIsConnected = false;
41 | private static String mDeviceAddr = ""; //98:D3:31:80:60:6F
42 |
43 | private static BluetoothAdapter mAdapter = null;
44 | private static BluetoothSocket mSocket = null;
45 | private static Thread mListenerThread = null;
46 | //endregion
47 |
48 | //region Getters/Setters
49 | public static boolean isConnected(){ return mIsConnected; }
50 | public static void setDeviceAddress(String str){ mDeviceAddr = str; }
51 | //endregion
52 |
53 | //region Connectivity Methods
54 | public static int Check(){
55 | mAdapter = BluetoothAdapter.getDefaultAdapter();
56 | if(mAdapter == null) return STATE_NOBT;
57 | if(!mAdapter.isEnabled()) return STATE_NOENABLED;
58 |
59 | return STATE_READY;
60 | }//func
61 |
62 | public static int Connect(){
63 | if(mIsConnected) return STATE_UNKNOWN;
64 |
65 | mAdapter = BluetoothAdapter.getDefaultAdapter();
66 | if(mAdapter == null) return STATE_NOBT;
67 | if(!mAdapter.isEnabled()) return STATE_NOENABLED;
68 |
69 | new ConnectTask().execute();
70 | return STATE_CONNECTING;
71 | }//func
72 |
73 | public static boolean Disconnect(){
74 | mIsConnected = false;
75 | StopListener();
76 |
77 | if(mSocket != null){
78 | try{
79 | mSocket.close();
80 | mSocket = null;
81 | return true;
82 | }catch (IOException e){
83 | e.printStackTrace();
84 | }//try
85 | }//if
86 |
87 | return false;
88 | }//func
89 |
90 | public static synchronized boolean SendData(String txt){
91 | if(mSocket == null || !mIsConnected) return false;
92 | txt += "\n";
93 |
94 | try{
95 | mSocket.getOutputStream().write(txt.getBytes());
96 | return true;
97 | }catch(IOException ex){
98 | ex.printStackTrace();
99 | }//try
100 |
101 | return false;
102 | }//func
103 | //endregion
104 |
105 | //region Misc Methods
106 | public static void SendEnableRequest(Context context){
107 | Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
108 | //context.startActivity(intent);
109 | ((Activity)context).startActivityForResult(intent,BTENABLE_REQUEST);
110 | }//func
111 |
112 | public static String[][] GetPairedDevices(){
113 | Set dlist = mAdapter.getBondedDevices();
114 | int len = dlist.size();
115 |
116 | if(len == 0) return null;
117 |
118 | int i = 0;
119 | String[][] rtn = new String[len][2];
120 | for(BluetoothDevice bt : dlist){
121 | rtn[i][0] = bt.getName();
122 | rtn[i][1] = bt.getAddress();
123 | i++;
124 | }//for
125 |
126 | return rtn;
127 | }//func
128 | //endregion
129 |
130 | //region Thread Controlling
131 | public static boolean StartListener(){
132 | if((mListenerThread != null && mListenerThread.isAlive()) || !mIsConnected) return false;
133 |
134 | mListenerThread = new Thread(new BluetoothListener());
135 | mListenerThread.start();
136 |
137 | return true;
138 | }//func
139 |
140 | public static void StopListener(){
141 | if(mListenerThread != null && mListenerThread.isAlive() && !mListenerThread.isInterrupted())
142 | mListenerThread.interrupt();
143 | }//func
144 | //endregion
145 |
146 | //region Threads
147 | //Connection is blocking, so push that task into a thread. TODO: No longer using Post/Pre, better off making a runnable thread instead.
148 | private static class ConnectTask extends AsyncTask{
149 | //@Override protected void onPreExecute(){ System.out.println("Background onPreExecute"); }
150 | //@Override protected void onPostExecute(Void result){ System.out.println("Background onPostExecute"); }//func
151 | @Override protected Void doInBackground(Void... params){
152 | Intent intent = new Intent(ACTION_BTCONNECTION);
153 | try{
154 | mAdapter.cancelDiscovery();
155 |
156 | BluetoothDevice btDevice = mAdapter.getRemoteDevice(mDeviceAddr);
157 | mSocket = btDevice.createInsecureRfcommSocketToServiceRecord(UUID_INSECURE_SPP); //create a rfcomm spp connection
158 | mSocket.connect();
159 |
160 | intent.putExtra("STATUS", STATE_CONNECTED);
161 | mIsConnected = true;
162 | }catch(IOException e){
163 | e.printStackTrace();
164 | intent.putExtra("STATUS", STATE_ERROR);
165 | }//try
166 |
167 | App.broadcast(intent);
168 | return null;
169 | }//func
170 | }//task
171 |
172 | //Listen on the bluetooth socket for available data
173 | private static class BluetoothListener implements Runnable{
174 | @Override public void run(){
175 | System.out.println("Listener Thread Starting");
176 | InputStream iStream = null;
177 | try{ iStream = mSocket.getInputStream(); }catch(IOException e){ e.printStackTrace(); return; }
178 |
179 | //..............................................
180 | final int bufLen = 50; //Length of buffer to be use to read from serial
181 | int availLen = 0, //How many bytes are available to be read from serial
182 | bRead = 0; //How many bytes are read from serial
183 |
184 | byte[] buf = new byte[bufLen]; //Small byte buffer use to read from serial
185 | ByteStack mReadBuffer = new ByteStack(50); //This is a cache buffer that keeps being added to from stream till delimiter is found.
186 | String[] bufResults = null; //Get the results from the mReadBuffer when performing a full read on the cached data.
187 |
188 | System.out.println("Listener Thread Entering Loop");
189 | //..............................................
190 | while(!Thread.currentThread().isInterrupted() && mIsConnected){
191 | try{
192 | availLen = iStream.available();
193 | if(availLen > 0){
194 | System.out.format("Available %d\n",availLen);
195 | bRead = iStream.read(buf,0,bufLen);
196 | mReadBuffer.put(buf, 0, bRead);
197 |
198 | System.out.format("Read %d\n",bRead);
199 |
200 | bufResults = mReadBuffer.getAvailable('\n');
201 | if(bufResults != null){
202 | for(int i = 0; i < bufResults.length; i++){
203 | System.out.println(bufResults[i]);
204 | }//for
205 | }//for
206 | }//if
207 | }catch(IOException e){ e.printStackTrace(); }
208 | }//while
209 |
210 | try{ iStream.close(); } catch(IOException e){ e.printStackTrace(); }
211 | System.out.println("Listener Thread Ended");
212 | }//func
213 | }//cls
214 | //endregion
215 | }//cls
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/GestureTouch.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse;
2 |
3 | import android.view.MotionEvent;
4 | import android.view.View;
5 | import android.view.ViewConfiguration;
6 |
7 | import com.sketchpunk.shared.App;
8 |
9 | import java.util.ArrayList;
10 |
11 | public class GestureTouch implements View.OnTouchListener{
12 | public static final int GESTURE_UNKNOWN = 0;
13 | public static final int GESTURE_PINCH = 1;
14 | public static final int GESTURE_DBLDRAG = 2;
15 |
16 | final ViewConfiguration viewConfig = ViewConfiguration.get(App.getContext());
17 | int mViewScaledTouchSlop = viewConfig.getScaledTouchSlop();
18 |
19 | //private int mActivePointCnt = 0;
20 | //private int mMaxIndex = 0;
21 | //private Vert mStartPos = new Vert();
22 | //private Vert mCurrentPos = new Vert();
23 | private long mDownTimestamp = 0;
24 | private int mGuestureType = 0;
25 | private int mSampleCnt = 0;
26 | private final int mSampleLimit = 3;
27 | private ArrayList alSample = new ArrayList();
28 |
29 | private Vert[] mInitalPos = new Vert[]{new Vert(),new Vert()};
30 | private Vert[] mCurrentPos = new Vert[]{new Vert(),new Vert()};
31 | private Vert[] mPreviousPos = new Vert[]{new Vert(),new Vert()};
32 |
33 | private void initialTouch(MotionEvent me){
34 | mInitalPos[0].set(me, 0);
35 | mInitalPos[1].reset();
36 | mPreviousPos[0].set(mInitalPos[0]);
37 | mPreviousPos[1].reset();
38 |
39 | mSampleCnt = 0;
40 | alSample.clear();
41 |
42 | mDownTimestamp = System.currentTimeMillis();
43 | //mMaxIndex = 0;
44 | mGuestureType = GESTURE_UNKNOWN;
45 | System.out.println(Vert.DISTANCE_THRESHOLD);
46 | }//func
47 |
48 | private void finalEndTouch(MotionEvent me){
49 | }//func
50 |
51 | private void newTouch(MotionEvent me){
52 | //mActivePointCnt++;
53 |
54 | if(me.getActionIndex() == 1 && me.getPointerCount() == 2){
55 | mInitalPos[1].set( mPreviousPos[1].set(me,1) );
56 |
57 | System.out.println(mInitalPos[0].distance(mInitalPos[1]));
58 | }//if
59 | }//func
60 |
61 | private void endTouch(MotionEvent me){
62 | //mActivePointCnt--;
63 | }//func
64 |
65 |
66 | @Override
67 | public boolean onTouch(View v, MotionEvent me) {
68 | //System.out.println(event.getPointerCount());
69 | int index = me.getActionIndex();
70 | //mMaxIndex = Math.max(mMaxIndex,index); //Get the max fingers ever put on screen.
71 | //if(me.getActionMasked() == MotionEvent.ACTION_MOVE) return true;
72 |
73 | switch(me.getActionMasked()){
74 | case MotionEvent.ACTION_DOWN:
75 | initialTouch(me);
76 | System.out.println("ON DOWN " + Integer.toString(index));
77 | break;
78 | case MotionEvent.ACTION_UP:
79 | finalEndTouch(me);
80 | System.out.println("ON UP " + Integer.toString(index));
81 | break;
82 | case MotionEvent.ACTION_MOVE:
83 | //mCurrentPos.set(me);
84 | //System.out.println("SAMPLE MOVE " + Integer.toString(index));
85 | //System.out.println("ON MOVE " + Integer.toString(me.getPointerCount()));
86 | if(mGuestureType == GESTURE_UNKNOWN){
87 | if(me.getPointerCount() == 2){
88 | mCurrentPos[0].set(me,0);
89 | mCurrentPos[1].set(me, 1);
90 |
91 | //float moveX = Math.abs(mCurrentPos[0].x - mInitalPos[0].x), moveY = Math.abs(mCurrentPos[0].y - mInitalPos[0].y);
92 | //System.out.format("movement %f %f\n",moveX,moveY);
93 |
94 | if( (mInitalPos[0].hasMoved(mCurrentPos[0]) || mInitalPos[0].hasMoved(mCurrentPos[1])) && mSampleCnt < mSampleLimit){
95 | mSampleCnt++;
96 |
97 | Vert[] vert = new Vert[]{new Vert(),new Vert()};
98 | vert[0].set(me, 0);
99 | vert[1].set(me, 1);
100 | alSample.add(vert);
101 |
102 | if(mSampleCnt < mSampleLimit) return true;
103 |
104 | System.out.println(alSample.size());
105 | float x1=0, x2=0, y1=0, y2=0;
106 | for(int i = 0; i < alSample.size(); i++){
107 | x1 += alSample.get(i)[0].x;
108 | x2 += alSample.get(i)[1].x;
109 | y1 += alSample.get(i)[0].y;
110 | y2 += alSample.get(i)[1].y;
111 | }
112 |
113 | x1 = x1 / alSample.size();
114 | x2 = x2 / alSample.size();
115 | y1 = y1 / alSample.size();
116 | y2 = y2 / alSample.size();
117 |
118 | System.out.format("%f %f %f %f",x1,y1,x2,y2);
119 | Vert a = new Vert(x1,y1);
120 | Vert b = new Vert(x2,y2);
121 |
122 | double directA = mInitalPos[0].angle(a);
123 | double directB = mInitalPos[1].angle(b);
124 | System.out.format("Angle %f %f %f\n",directA,directB, directB-directA);
125 |
126 | /*
127 | float distA = mInitalPos[0].distance(mInitalPos[1])
128 | ,distB = mCurrentPos[0].distance(mCurrentPos[1]);
129 |
130 | //TODO, Try with focal point next.
131 | Vert iFocal = mInitalPos[0].midPoint(mInitalPos[1]);
132 | Vert cFocal = mCurrentPos[0].midPoint(mCurrentPos[1]);
133 | float fDistance = iFocal.distance(cFocal);
134 |
135 | double directA = mInitalPos[0].angle(mCurrentPos[0]);
136 | double directB = mInitalPos[1].angle(mCurrentPos[1]);
137 |
138 | System.out.format("Sample %d \n",mSampleCnt);
139 | System.out.format("Angle %f %f %f\n",directA,directB, directB-directA);
140 |
141 | //System.out.format("%s %s focal distance %f\n", iFocal.toString(),cFocal.toString(),fDistance);
142 | System.out.format("%s %s focal distance %f\n", iFocal.toString(),cFocal.toString(),fDistance);
143 | System.out.format("Distance %f %f %f\n", distA,distB, distA-distB);
144 |
145 | Vert diff0 = mInitalPos[0].difference(mCurrentPos[0]);
146 | Vert diff1 = mInitalPos[1].difference(mCurrentPos[1]);
147 | float mxx = (diff0.x * diff1.x);
148 | float myx = (diff0.y * diff1.y);
149 |
150 | float diff1x = mCurrentPos[0].x - mInitalPos[0].x;
151 | float diff1y = mCurrentPos[0].y - mInitalPos[0].y;
152 |
153 | float diff2x = mCurrentPos[1].x - mInitalPos[1].x;
154 | float diff2y = mCurrentPos[1].y - mInitalPos[1].y;
155 |
156 | float mx = (diff1x * diff2x);
157 | float my = (diff1y * diff2y);
158 |
159 | //System.out.format("distance %f %d\n",Math.abs(distA - distB),Vert.MOVEMENT_THRESHOLD);
160 | //System.out.format("direction %f %f\n",mx,my);
161 | //System.out.format("direction %f %f\n",mxx,myx);
162 | //System.out.format("diff x %f %f\n",diff0.x,diff1.x);
163 | //System.out.format("diff x %f %f\n",diff0.y,diff1.y);
164 | if(Math.abs(distA - distB) > Vert.MOVEMENT_THRESHOLD && mxx <= 0 && myx <=0 && fDistance < Vert.DISTANCE_THRESHOLD){
165 | System.out.println("PINCH !!!");
166 | //mGuestureType = GESTURE_PINCH;
167 |
168 | }else if( Math.abs(distB) <= Math.abs(distA + Vert.MOVEMENT_THRESHOLD) && (mxx > 0 || myx > 0)){
169 | System.out.println("DOUBLE DRAG !!!");
170 | //mGuestureType = GESTURE_DBLDRAG;
171 | }//if
172 |
173 | //System.out.println(Math.abs(distA - distB));
174 | //System.out.println(mx);
175 | //System.out.println(my);
176 |
177 | //if(mInitalPos[0].hasDifted(mCurrentPos[0]) || mInitalPos)
178 |
179 | */
180 | //}
181 | //float distance = mCurrentPos[0].set(me,0).distance( mCurrentPos[1].set(me,1) );
182 | //System.out.println(distance);
183 | }//if
184 |
185 | mPreviousPos[0].set(mCurrentPos[0]);
186 | mPreviousPos[1].set(mCurrentPos[1]);
187 | }//if
188 | }//if
189 |
190 | break;
191 | case MotionEvent.ACTION_POINTER_DOWN:
192 | newTouch(me);
193 | System.out.println("ON POINTER DOWN " + Integer.toString(index));
194 | break;
195 | case MotionEvent.ACTION_POINTER_UP:
196 | endTouch(me);
197 |
198 | System.out.println("ON POINTER UP " + Integer.toString(index));
199 | break;
200 | }//switch
201 |
202 | //System.out.println("Total Fingers " + Integer.toString(mPointCount));
203 | return true;
204 | }//func
205 |
206 | }//cls
207 |
208 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/MultiGesture.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse;
2 |
3 | import android.util.FloatMath;
4 | import android.view.MotionEvent;
5 | import android.view.View;
6 | import android.view.ViewConfiguration;
7 |
8 | import com.sketchpunk.shared.App;
9 |
10 | public class MultiGesture implements View.OnTouchListener{
11 | public static interface OnMultiGestureListener{
12 | public void onMultiGesture(int mode, float deltaX, float deltaY);
13 | }//interface
14 |
15 | public static final int MOVEMENT_THRESHOLD = ViewConfiguration.get(App.getContext()).getScaledTouchSlop();
16 | public static final int MODE_PAN = 1;
17 | public static final int MODE_PYAW = 2;
18 | public static final int MODE_ROLL = 4;
19 | public static final int MODE_ZOOM = 3;
20 |
21 | private int mMode = MODE_PAN;
22 | private float[] mPrevious = new float[2];
23 | private float[] mCurrent = new float[2];
24 | private int mSkip = 0; //When switching modes there is an effect
25 |
26 | private OnMultiGestureListener mListener = null;
27 |
28 | public void setOnMultiGestureListener(OnMultiGestureListener listener){ mListener = listener; }//func
29 |
30 | @Override
31 | public boolean onTouch(View v, MotionEvent e){
32 | switch(e.getActionMasked()){
33 | case MotionEvent.ACTION_DOWN: mMode = MODE_PAN;
34 | mPrevious[0] = e.getX();
35 | mPrevious[1] = e.getY();
36 | break; //case MotionEvent.ACTION_UP: break;
37 |
38 | case MotionEvent.ACTION_MOVE:
39 | mCurrent[0] = e.getX();
40 | mCurrent[1] = e.getY();
41 | if(hasMoved()){
42 | float deltaX,deltaY = 0;
43 |
44 | //if(mMode == MODE_ROLL || mMode == MODE_ZOOM) deltaX = getDistance();
45 | //else{
46 | deltaX = mCurrent[0] - mPrevious[0];
47 | deltaY = mCurrent[1] - mPrevious[1];
48 | //}//if
49 | if(mSkip == 0) mListener.onMultiGesture(mMode,deltaX,deltaY);
50 | else mSkip--;
51 |
52 | mPrevious[0] = mCurrent[0];
53 | mPrevious[1] = mCurrent[1];
54 | }//if
55 | break;
56 |
57 | case MotionEvent.ACTION_POINTER_DOWN: mMode = e.getPointerCount(); break;
58 | case MotionEvent.ACTION_POINTER_UP:
59 | int ptrCnt = e.getPointerCount() - 1; //Even though its up the count shows its still there.
60 |
61 | if(mMode == MODE_PYAW && ptrCnt == 1){
62 | mMode = MODE_ROLL;
63 | mSkip = 1;
64 | }else mMode = ptrCnt;
65 | break;
66 | }//switch
67 | return true;
68 | }//func
69 |
70 | private float getDistance(){ return FloatMath.sqrt(FloatMath.pow(mCurrent[0] - mPrevious[0], 2f) + FloatMath.pow(mCurrent[1] - mPrevious[1], 2f)); }//func
71 |
72 | private boolean hasMoved(){
73 | float moveX = Math.abs(mCurrent[0] - mPrevious[0]), moveY = Math.abs(mCurrent[1] - mPrevious[1]);
74 | return (moveX > MOVEMENT_THRESHOLD || moveY > MOVEMENT_THRESHOLD);
75 | }//func
76 |
77 | private float rotation(float[] ary) {
78 | double deltaX = ary[0] - ary[2];
79 | double deltaY = ary[1] - ary[3];
80 | double radians = Math.atan2(deltaY, deltaX);
81 | System.out.println(radians);
82 | return (float) Math.toDegrees(radians);
83 | }
84 |
85 | private Vert midpoint(float[] ary){
86 | float x = (ary[0] - ary[2]) / 2.0f;
87 | float y = (ary[1] - ary[3]) / 2.0f;
88 | return new Vert(x,y);
89 | }
90 |
91 | /*
92 |
93 |
94 | if(ptrCnt < 2) return true;
95 |
96 | for(int i=0; i < 4; i+=2){
97 | mCurrent[i] = e.getX(i/2);
98 | mCurrent[i+1] = e.getY(i/2);
99 | }//for
100 |
101 | System.out.format("Pointer %d %f % f\n", e.getPointerCount(), e.getX(0), e.getY(0));
102 | System.out.println(rotation(mCurrent));
103 |
104 | Vert vert = midpoint(mCurrent);
105 | System.out.format("midpoint %f %f\n",vert.x,vert.y);
106 |
107 | System.arraycopy(mCurrent, 0, mPrevious, 0,4);
108 |
109 |
110 | */
111 |
112 | }//cls
113 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/Vert.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse;
2 |
3 | import android.util.FloatMath;
4 | import android.view.MotionEvent;
5 | import android.view.ViewConfiguration;
6 |
7 | import com.sketchpunk.shared.App;
8 |
9 | public class Vert{
10 | public static final int MOVEMENT_THRESHOLD = ViewConfiguration.get(App.getContext()).getScaledTouchSlop();
11 | public static final int DISTANCE_THRESHOLD = ViewConfiguration.get(App.getContext()).getScaledDoubleTapSlop();
12 |
13 | public float x = 0, y = 0;
14 |
15 | public Vert(){}
16 | public Vert(float fx, float fy){ x = fx; y = fy; }
17 |
18 | public String toString(){ return String.format("VER X:%f Y:%f",x,y); }
19 |
20 | //region Setters
21 | public void reset(){ x=0; y=0; }
22 | public Vert set(Vert v){ x = v.x; y = v.y; return this; }
23 | public Vert set(MotionEvent me, int index){ x = me.getX(index); y = me.getY(index); return this; }//func
24 | public Vert set(MotionEvent me){
25 | int i = me.getActionIndex();
26 | x = me.getX(i);
27 | y = me.getY(i);
28 | return this;
29 | }//func
30 |
31 | //endregion
32 |
33 | //region Calculations
34 | public float distance(Vert v){ return FloatMath.sqrt(FloatMath.pow(x-v.x,2f) + FloatMath.pow(y-v.y,2f)); }//func
35 |
36 | public boolean hasMoved(Vert v){
37 | float moveX = Math.abs(v.x - x), moveY = Math.abs(v.y - y);
38 | return (moveX > MOVEMENT_THRESHOLD || moveY > MOVEMENT_THRESHOLD);
39 | }//func
40 |
41 | public Vert difference(Vert v){ return new Vert(x - v.x,y - v.y); }
42 |
43 | public boolean hasDifted(Vert v){
44 | return ( Math.abs(distance(v)) > MOVEMENT_THRESHOLD );
45 | }//func
46 |
47 | public Vert midPoint(Vert v){
48 | float fx = (x+v.x)/2, fy = (y+v.y)/2;
49 | return new Vert(fx,fy);
50 | }//func
51 |
52 | public double angle(Vert v){
53 | double xdiff = v.x - x, ydiff = v.y - y;
54 | return Math.atan2(ydiff,xdiff) * 180.0 / Math.PI;
55 | }//func
56 | //endregion
57 | }//cls
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/activities/ControlActivity.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse.activities;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import android.support.v4.app.FragmentTransaction;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v7.app.ActionBarActivity;
10 | import android.os.Bundle;
11 | import android.view.Menu;
12 | import android.view.MenuItem;
13 |
14 | import com.sketchpunk.shared.ActivityBroadcastReceiver;
15 | import com.sketchpunk.shared.Toasty;
16 | import com.sketchpunk.virt3dmouse.BluetoothSerial;
17 | import com.sketchpunk.virt3dmouse.MultiGesture;
18 | import com.sketchpunk.virt3dmouse.R;
19 | import com.sketchpunk.virt3dmouse.fragments.CommandListFragment;
20 | import com.sketchpunk.virt3dmouse.ui.TouchView;
21 |
22 | import java.text.DecimalFormat;
23 |
24 | public class ControlActivity extends ActionBarActivity implements MultiGesture.OnMultiGestureListener, ActivityBroadcastReceiver.Handler{
25 | //region Static Methods
26 | public static void show(Context context,String addr,String dName){
27 | Intent intent = new Intent(context,ControlActivity.class);
28 | intent.putExtra("dAddress",addr);
29 | intent.putExtra("dName",dName);
30 | context.startActivity(intent);
31 | }//func
32 | //endregion
33 |
34 | //region Variables
35 | private ActivityBroadcastReceiver mReceiver = null;
36 | private float mFactorPan = 0.3f;
37 | private float mFactorZoom = 0.05f;
38 | private float mFactorRotate = 0.003f;
39 | private DecimalFormat mDFormat = new DecimalFormat("#.##");
40 | private String mDeviceName = "";
41 | private ProgressDialog mProgressDialog = null;
42 | //endregion
43 |
44 | //region Activity Events
45 | //private E findCastViewById(int id){ return (E) findViewById(id); }
46 | //private E $(int id){ return (E) findViewById(id); }
47 | @Override protected void onCreate(Bundle savedInstanceState){
48 | super.onCreate(savedInstanceState);
49 | setContentView(R.layout.activity_control);
50 |
51 | //------------------------------------------
52 | //Get Passed Data
53 | Intent intent = getIntent();
54 | String attr = intent.getStringExtra("dAddress");
55 | mDeviceName = intent.getStringExtra("dName");
56 | if(!attr.isEmpty()) BluetoothSerial.setDeviceAddress(attr);
57 |
58 | //------------------------------------------
59 | mReceiver = new ActivityBroadcastReceiver(this, BluetoothSerial.ACTION_BTCONNECTION);
60 | ((TouchView)findViewById(R.id.Overlay_Target)).setOnMultiGestureListener(this);
61 |
62 | //------------------------------------------
63 | //TODO: Based on device size or orientation, this fragment should be in a slide in menu.
64 | FragmentManager man = getSupportFragmentManager();
65 | FragmentTransaction trans = man.beginTransaction();
66 | CommandListFragment fragment = new CommandListFragment();
67 | trans.add(R.id.ListFragment, fragment);
68 | trans.commit();
69 |
70 | connectBT();
71 | }//func
72 |
73 | protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
74 | if(requestCode == BluetoothSerial.BTENABLE_REQUEST){
75 | if(resultCode == 0){
76 | Toasty.center(this,"You need to accept bluetooth permission to use this app.",true);
77 | return;
78 | }//if
79 | Toasty.center(this, "Try connecting again when bluetooth is ready.", true);
80 | }//if
81 | }//func
82 |
83 | @Override public void onResume(){
84 | super.onResume();
85 | mReceiver.register();
86 | }//func
87 |
88 | @Override protected void onPause(){
89 | super.onPause();
90 | BluetoothSerial.Disconnect();
91 | mReceiver.unregister();
92 | }//func
93 | //endregion
94 |
95 | //region Broadcasts
96 | @Override
97 | public void onBroadcastReceived(Context context, Intent intent){
98 | System.out.println("onBroadcastReceived");
99 | mProgressDialog.hide();
100 |
101 | if(intent.getAction().equals(BluetoothSerial.ACTION_BTCONNECTION)){
102 | switch(intent.getIntExtra("STATUS", BluetoothSerial.STATE_UNKNOWN)){
103 | case BluetoothSerial.STATE_CONNECTED: Toasty.center(this,"Bluetooth device has been successfully connected.",false); break;
104 | case BluetoothSerial.STATE_ERROR: Toasty.center(this,"Unable to connect. Check if device is on.",true); break;
105 | case BluetoothSerial.STATE_UNKNOWN: Toasty.center(this,"Unknown status when connecting to bluetooth device.",true); break;
106 | }//switch
107 |
108 | invalidateOptionsMenu();
109 | }//if
110 | }//func
111 | //endregion
112 |
113 | //region Touch Events
114 | @Override
115 | public void onMultiGesture(int mode, float deltaX, float deltaY){
116 | switch(mode){
117 | case MultiGesture.MODE_PAN:
118 | deltaX = deltaX * -1 * mFactorPan;
119 | deltaY *= mFactorPan;
120 | BluetoothSerial.SendData("pan~" + mDFormat.format(deltaX) + "~" + mDFormat.format(deltaY));
121 |
122 | System.out.format("PAN %f %f \n",deltaX,deltaY);
123 | break;
124 | case MultiGesture.MODE_PYAW:
125 | deltaX *= mFactorRotate;
126 | deltaY *= mFactorRotate;
127 |
128 | BluetoothSerial.SendData("pyaw~" + mDFormat.format(deltaX) + "~" + mDFormat.format(deltaY));
129 | System.out.format("PYAW %f %f \n",deltaX,deltaY);
130 |
131 | break;
132 | case MultiGesture.MODE_ZOOM:
133 | deltaY *= mFactorZoom;
134 |
135 | BluetoothSerial.SendData("zoom~" + mDFormat.format(deltaY));
136 | System.out.format("ZOOM %f \n", deltaY);
137 |
138 | break;
139 | case MultiGesture.MODE_ROLL:
140 | deltaX *= mFactorRotate * -1;
141 | BluetoothSerial.SendData("roll~" + mDFormat.format(deltaX));
142 | System.out.format("Roll %f \n",deltaX);
143 | break;
144 | }//switch
145 | }//func
146 | //endregion
147 |
148 | //region Menu Events
149 | @Override
150 | public boolean onCreateOptionsMenu(Menu menu){
151 | // Inflate the menu; this adds items to the action bar if it is present.
152 | getMenuInflater().inflate(R.menu.menu_main, menu);
153 |
154 | MenuItem mitem = menu.findItem(R.id.mnuConnect);
155 | mitem.setIcon( (BluetoothSerial.isConnected())? R.drawable.ic_bluetooth_searching_24dp : R.drawable.ic_bluetooth_disabled_24dp );
156 |
157 | return true;
158 | }//func
159 |
160 | @Override
161 | public boolean onOptionsItemSelected(MenuItem item){
162 | if(item.getItemId() == R.id.mnuConnect){
163 | if(BluetoothSerial.isConnected()){
164 | if(BluetoothSerial.Disconnect()) Toasty.center(this,"Disconnect Successful",false);
165 | else Toasty.center(this,"Error while disconnecting bluetooth device.",true);
166 |
167 | invalidateOptionsMenu();
168 | }else connectBT();
169 | }//if
170 |
171 | return super.onOptionsItemSelected(item);
172 | }//func
173 | //endregion
174 |
175 | //region Bluetooth Functions
176 | private void connectBT(){
177 | switch(BluetoothSerial.Connect()){
178 | case BluetoothSerial.STATE_NOBT: Toasty.center(this,"There is no Bluetooth Module in the phone",true); break;
179 | case BluetoothSerial.STATE_NOENABLED: BluetoothSerial.SendEnableRequest(this); break;
180 | case BluetoothSerial.STATE_CONNECTING:
181 | if(mProgressDialog == null){
182 | mProgressDialog = new ProgressDialog(this);
183 | mProgressDialog.setTitle("");
184 | mProgressDialog.setMessage("Trying to connect to " + mDeviceName);
185 | mProgressDialog.setCancelable(false);
186 | mProgressDialog.setIndeterminate(true);
187 | }//if
188 |
189 | mProgressDialog.show();
190 | break;
191 | }//switch
192 | }//func
193 | //endregion
194 | }//cls
195 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/activities/PairListActivity.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse.activities;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.ActionBarActivity;
6 | import android.view.Menu;
7 | import android.view.MenuItem;
8 |
9 | import com.sketchpunk.shared.Toasty;
10 | import com.sketchpunk.virt3dmouse.BluetoothSerial;
11 | import com.sketchpunk.virt3dmouse.R;
12 | import com.sketchpunk.virt3dmouse.fragments.BTPairListFragment;
13 |
14 | public class PairListActivity extends ActionBarActivity{
15 | private BTPairListFragment mFragment = null;
16 |
17 | //region Activity Events
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState){
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_pair_list);
22 |
23 | mFragment = (BTPairListFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
24 |
25 | CheckBluetooth();
26 | }//cls
27 |
28 | protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
29 | if(requestCode == BluetoothSerial.BTENABLE_REQUEST){
30 | if(resultCode == 0){
31 | mFragment.setTextMsg("You need to accept bluetooth permission to use this app.");
32 | return;
33 | }//if
34 | mFragment.loadList();
35 | }//if
36 | }//func
37 | //endregion
38 |
39 | //region action menu
40 | @Override
41 | public boolean onCreateOptionsMenu(Menu menu){
42 | getMenuInflater().inflate(R.menu.menu_pair, menu);
43 | return true;
44 | }//func
45 |
46 | @Override
47 | public boolean onOptionsItemSelected(MenuItem item){
48 | if(item.getItemId() == R.id.mnuRefresh) CheckBluetooth();
49 | return super.onOptionsItemSelected(item);
50 | }//func
51 | //endregion
52 |
53 | private void CheckBluetooth(){
54 | switch(BluetoothSerial.Check()){
55 | case BluetoothSerial.STATE_READY: mFragment.loadList(); break;
56 | case BluetoothSerial.STATE_NOBT: mFragment.setTextMsg("Device has no bluetooth"); break;
57 | case BluetoothSerial.STATE_NOENABLED: BluetoothSerial.SendEnableRequest(this); break;
58 | }//switch
59 | }//cls
60 | }//func
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/fragments/BTPairListFragment.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse.fragments;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import com.sketchpunk.shared.RecyclerDivider;
10 | import com.sketchpunk.shared.RecyclerMultiArrayAdapter;
11 | import com.sketchpunk.shared.RecyclerViewFragment;
12 | import com.sketchpunk.shared.ViewBindHolder;
13 | import com.sketchpunk.virt3dmouse.BluetoothSerial;
14 | import com.sketchpunk.virt3dmouse.R;
15 | import com.sketchpunk.virt3dmouse.activities.ControlActivity;
16 |
17 | public class BTPairListFragment extends RecyclerViewFragment{
18 | private RecyclerMultiArrayAdapter mAdapter = null;
19 | private String[][] mDatasource = null;
20 |
21 | public BTPairListFragment(){}
22 |
23 | //region Fragment Events
24 | @Override
25 | public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
26 | View v = super.onCreateView(inflater,container,savedInstanceState);
27 |
28 | mAdapter = new RecyclerMultiArrayAdapter(this.getActivity(),R.layout.list_item);
29 | mAdapter.setCallback(new RecyclerMultiArrayAdapter.Callback(){
30 | @Override public ViewBindHolder onCreateViewHolder(View v){ return (ViewBindHolder) new VHolder(v); }
31 | });
32 |
33 | this.addItemDecoration(new RecyclerDivider());
34 |
35 | return v;
36 | }//func
37 | //endregion
38 |
39 | public void loadList(){
40 | setTextMsg("Loading list...");
41 | mDatasource = BluetoothSerial.GetPairedDevices();
42 | if(mDatasource != null){
43 | mAdapter.setArray(mDatasource);
44 | setRecyclerAdapter(mAdapter);
45 | hideTextView();
46 | }else setTextMsg("No paired devices found");
47 | }//func
48 |
49 | private class VHolder extends ViewBindHolder implements View.OnClickListener{
50 | private TextView mLblTitle = null, mLblDesc = null;
51 | private String mAddr = "";
52 |
53 | public VHolder(View v){
54 | super(v);
55 | v.setOnClickListener(this);
56 | mLblTitle = (TextView) v.findViewById(android.R.id.text1);
57 | }//func
58 |
59 | @Override public void bindData(int pos){
60 | String[] ary = mAdapter.get(pos);
61 | mAddr = ary[1];
62 | mLblTitle.setText(ary[0]);
63 | }//func
64 |
65 | //region Click Events
66 | @Override public void onClick(View v){
67 | ControlActivity.show(getActivity(), mAddr, mLblTitle.getText().toString());
68 | }//func
69 | //endregion
70 | }//cls
71 | }//cls
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/fragments/CommandListFragment.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse.fragments;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.TextView;
10 |
11 | import com.sketchpunk.shared.RecyclerArrayAdapter;
12 | import com.sketchpunk.shared.RecyclerDivider;
13 | import com.sketchpunk.shared.RecyclerMultiArrayAdapter;
14 | import com.sketchpunk.shared.RecyclerViewFragment;
15 | import com.sketchpunk.shared.ViewBindHolder;
16 | import com.sketchpunk.virt3dmouse.BluetoothSerial;
17 | import com.sketchpunk.virt3dmouse.R;
18 |
19 | import java.io.File;
20 | import java.util.Arrays;
21 | import java.util.Date;
22 |
23 | public class CommandListFragment extends RecyclerViewFragment{
24 | private RecyclerMultiArrayAdapter mAdapter = null;
25 | private String[][] mDatasource = {
26 | {"Toggle Edit Mode","exe~bpy.ops.object.editmode_toggle()"}
27 | ,{"Mesh Select All","exe~bpy.ops.mesh.select_all(action='TOGGLE')"}
28 | ,{"Extrude","exe~bpy.ops.view3d.edit_mesh_extrude_move_normal('INVOKE_DEFAULT')"}
29 | ,{"Center Cursor","exe~bpy.ops.view3d.snap_cursor_to_center()"}
30 | ,{"Add Cube","exe~bpy.ops.mesh.primitive_cube_add()"}
31 | ,{"Scale (Z)","exe~bpy.ops.transform.resize('INVOKE_DEFAULT',constraint_axis=(False, False, True))"}
32 | ,{"Scale (XY)","exe~bpy.ops.transform.resize('INVOKE_DEFAULT',constraint_axis=(True, True, False))"}
33 | ,{"Scale (XYZ)","exe~bpy.ops.transform.resize('INVOKE_DEFAULT',constraint_axis=(True, True, True))"}
34 | ,{"Grab (X)","exe~bpy.ops.transform.translate('INVOKE_DEFAULT',constraint_axis=(True, False, False))"}
35 | ,{"Grab (Y)","exe~bpy.ops.transform.translate('INVOKE_DEFAULT',constraint_axis=(False, True, False))"}
36 | ,{"Grab (Z)","exe~bpy.ops.transform.translate('INVOKE_DEFAULT',constraint_axis=(False, False, True))"}
37 | ,{"Rotate (Z)","exe~bpy.ops.transform.rotate('INVOKE_DEFAULT',axis=(0,0,1))"}
38 | ,{"Rotate (X)","exe~bpy.ops.transform.rotate('INVOKE_DEFAULT',axis=(1,0,0))"}
39 | ,{"Rotate (Y)","exe~bpy.ops.transform.rotate('INVOKE_DEFAULT',axis=(0,1,0))"}
40 | };
41 |
42 | public CommandListFragment(){}
43 |
44 | //region Fragment Events
45 | @Override
46 | public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
47 | View v = super.onCreateView(inflater,container,savedInstanceState);
48 |
49 | //..............................................
50 | mAdapter = new RecyclerMultiArrayAdapter(this.getActivity(),R.layout.list_item);
51 | mAdapter.setCallback(new RecyclerMultiArrayAdapter.Callback(){
52 | @Override public ViewBindHolder onCreateViewHolder(View v){ return (ViewBindHolder)new VHolder(v); }
53 | });
54 | mAdapter.setArray(mDatasource);
55 |
56 | //..............................................
57 | setRecyclerAdapter(mAdapter);
58 | addItemDecoration(new RecyclerDivider());
59 | hideTextView();
60 |
61 | return v;
62 | }//func
63 | //endregion
64 |
65 | private class VHolder extends ViewBindHolder implements View.OnClickListener{
66 | private TextView mLblTitle = null, mLblDesc = null;
67 | private String mCmd = "";
68 |
69 | public VHolder(View v){
70 | super(v);
71 | v.setOnClickListener(this);
72 | mLblTitle = (TextView) v.findViewById(android.R.id.text1);
73 | }//func
74 |
75 | @Override
76 | public void bindData(int pos){
77 | String[] ary = mAdapter.get(pos);
78 | mLblTitle.setText(ary[0]);
79 | mCmd = ary[1];
80 | }//func
81 |
82 | //region Click Events
83 | @Override public void onClick(View v){
84 | System.out.println(mLblTitle.getText());
85 | BluetoothSerial.SendData(mCmd);
86 | }//func
87 | //endregion
88 | }//cls
89 | }//cls
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sketchpunk/virt3dmouse/ui/TouchView.java:
--------------------------------------------------------------------------------
1 | package com.sketchpunk.virt3dmouse.ui;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.util.AttributeSet;
8 | import android.view.MotionEvent;
9 | import android.view.GestureDetector;
10 | import android.view.ScaleGestureDetector;
11 | import android.view.View;
12 |
13 | import com.sketchpunk.virt3dmouse.GestureTouch;
14 | import com.sketchpunk.virt3dmouse.MultiGesture;
15 | import com.sketchpunk.virt3dmouse.Vert;
16 |
17 | public class TouchView extends View implements GestureDetector.OnGestureListener,ScaleGestureDetector.OnScaleGestureListener{
18 |
19 | public static interface OnGestureListener{
20 | public void onZoom(); //Pinch
21 | public void onPan(); //Long hold then drag
22 | public void onDrag(float x, float y); //Single Finger drag.
23 | }//interface
24 |
25 | private Paint mPaint = null;
26 | private GestureDetector mGesture;
27 | private ScaleGestureDetector mScaleGesture;
28 | private MultiGesture mMultiGesture;
29 | private boolean mIsLongPress = false;
30 | private boolean mIsScale = false;
31 | private Vert mPreviousPos = null, mCurrentPos = null; //TODO, Don't really need it, swop it for array
32 |
33 | private OnGestureListener mListener = null;
34 |
35 | public TouchView(Context context){ super(context); init(context); }
36 | public TouchView(Context context, AttributeSet attrs) { super(context, attrs); init(context); }
37 |
38 | private void init(Context context){
39 | mPaint = new Paint();
40 | mPaint.setColor(Color.parseColor("#A0000000"));
41 | mPaint.setStyle(Paint.Style.STROKE);
42 |
43 | if(this.isInEditMode()) return;
44 |
45 | mPreviousPos = new Vert();
46 | mCurrentPos = new Vert();
47 |
48 | mMultiGesture = new MultiGesture();
49 | this.setOnTouchListener(mMultiGesture);
50 |
51 |
52 | //mScaleGesture = new ScaleGestureDetector(context,this);
53 | //mGesture = new GestureDetector(context,this);
54 | //mGesture.setIsLongpressEnabled(false);
55 | }//func
56 |
57 | public void setOnMultiGestureListener(MultiGesture.OnMultiGestureListener context){ mMultiGesture.setOnMultiGestureListener(context); }//func
58 |
59 | @Override
60 | public void onDraw(Canvas canvas){
61 | canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mPaint);
62 | }//func
63 |
64 |
65 | //region Gesture Event Handlers
66 | /*
67 | @Override public boolean onTouchEvent(MotionEvent e){
68 | if(!mIsScale && mIsLongPress && e.getActionMasked() == MotionEvent.ACTION_MOVE){
69 | mCurrentPos.set(e);
70 | float deltax = mPreviousPos.x - mCurrentPos.x;
71 | float deltay = mPreviousPos.y - mCurrentPos.y;
72 |
73 | //System.out.format("LongPress %f %f %b\n",deltax, deltay,mIsLongPress);
74 |
75 | if(mListener != null) mListener.onPan();
76 |
77 | mPreviousPos.set(mCurrentPos);
78 | return true;
79 | }//if
80 |
81 | int ptrCnt = e.getPointerCount();
82 | if(ptrCnt == 2) mScaleGesture.onTouchEvent(e);
83 | if(ptrCnt == 1) mGesture.onTouchEvent(e);
84 |
85 | //System.out.format("onTouchEvent %d\n", e.getPointerCount());
86 | return true;
87 | }//func
88 | */
89 |
90 | @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){
91 | //System.out.format("SCROLL %f %f %b\n", distanceX, distanceY,mIsLongPress);
92 |
93 | if(mListener != null) mListener.onDrag(distanceX,distanceY);
94 | return true;
95 | }//func
96 |
97 | @Override public boolean onScale(ScaleGestureDetector detector){
98 | System.out.format("onScale %f %f\n", detector.getScaleFactor(), detector.getCurrentSpan());
99 | if(mListener != null) mListener.onZoom();
100 | return true;
101 | }//func
102 |
103 | @Override public void onLongPress(MotionEvent e){
104 | mIsLongPress = true;
105 | mPreviousPos.set(e,0);
106 | System.out.println("long press");
107 | }
108 | //endregion
109 |
110 | //region Unused events
111 | @Override public boolean onDown(MotionEvent e){ mIsLongPress = false; return true; }//needed to return true to get most of the gestures to work.
112 | @Override public void onShowPress(MotionEvent e){}
113 | @Override public boolean onSingleTapUp(MotionEvent e){ return false; }
114 |
115 | @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY){ return false; }
116 | @Override public boolean onScaleBegin(ScaleGestureDetector detector){ mIsScale = true; return true; }
117 | @Override public void onScaleEnd(ScaleGestureDetector detector){ mIsScale = false; }
118 | //endregion
119 | }//cls
120 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_autorenew_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bluetooth_disabled_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bluetooth_searching_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_control.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_control.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_pair_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_pair.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Virt3DMouse
5 | Hello world!
6 | Settings
7 |
8 |
9 | Hello blank fragment
10 | PairSelectActivity
11 | PairListActivity
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/blender_files/3dmouse_plugin_alpha.py:
--------------------------------------------------------------------------------
1 | import threading
2 | import mathutils
3 | import time
4 | import serial
5 | import bpy
6 | from bpy_extras import view3d_utils
7 | from bpy.props import *
8 |
9 | #https://www.blender.org/api/blender_python_api_2_63_17/bpy.ops.html
10 | #CmdActions.parse("rotate_0_0.1")
11 | #bpy.ops.transform.rotate("INVOKE_DEFAULT")
12 | #bpy.ops.transform.rotate("INVOKE_DEFAULT",axis=(0,0,1))
13 | #bpy.ops.transform.translate("INVOKE_DEFAULT",constraint_axis=(False, False, True))
14 | #bpy.ops.transform.resize("INVOKE_DEFAULT",constraint_axis=(False, False, True))
15 | #
16 | #eval('bpy.ops.transform.rotate("INVOKE_DEFAULT",axis=(0,0,1))')
17 |
18 |
19 | #TODO : See if can find a better way to hold this data then save it to the scene.
20 | def initSceneProperties(scn):
21 | bpy.types.Scene.strSerialPort = StringProperty(name = "Port",default="COM3",description="Enter the com port being used for experiement")
22 | bpy.types.Scene.intSerialBaud = IntProperty(name = "Baud",default=9600,description = "Enter the baud rate in which the serial port is running on")
23 | return
24 |
25 | initSceneProperties(bpy.context.scene)
26 |
27 |
28 | #====================================================================================
29 | #Main Panel for serial settings and buttons to control connection.
30 | class SerialMouseSettingsPanel(bpy.types.Panel):
31 | bl_category = "SMouse"
32 | bl_label = "Settings"
33 | bl_space_type = 'VIEW_3D' #Create in the 3D View
34 | bl_region_type = 'TOOLS' #Put it in the Tools Panel
35 |
36 | def draw(self, context):
37 | layout = self.layout
38 | scn = context.scene
39 | layout.prop(scn,"strSerialPort")
40 | layout.prop(scn,"intSerialBaud")
41 | layout.operator("serialmouse.connection",text="Connect").state = True
42 | layout.operator("serialmouse.connection",text="Disconnect").state = False
43 |
44 |
45 | #====================================================================================
46 | #single operator to connect the state of com connection
47 | class SerialMouse_Connection(bpy.types.Operator):
48 | bl_idname = "serialmouse.connection"
49 | bl_label = "Toggle Connection"
50 | state = BoolProperty(default=True)
51 | def execute(self,context):
52 | #CmdActions.parse("pan~0~1")
53 | #AssembleOverrideContextForView3dOps()
54 | if self.state:
55 | scn = context.scene
56 | #bpy.ops.serialmouse.listener()
57 | #bpy.ops.serial.modal_listener()
58 | SerialListener.Connect(scn["strSerialPort"],scn["intSerialBaud"],context)
59 | else:
60 | #SerialListenerState.Disconnect()
61 | SerialListener.Disconnect()
62 | return{'FINISHED'}
63 |
64 | #====================================================================================
65 | class CmdActions:
66 | def parse(txt):
67 | ary = txt.split("~")
68 | if len(ary) == 0:
69 | return
70 | cmdList[ary[0]](ary)
71 |
72 | def pan(ary):
73 | #get reference to all the areas
74 | area = bpy.context.window_manager.windows[0].screen.areas[1]
75 | viewport = area.regions[4]
76 | rv3d = area.spaces[0].region_3d
77 |
78 | #convert view location's 3D Cords to 2D Cords
79 | locCord = rv3d.view_location
80 | cord = view3d_utils.location_3d_to_region_2d(viewport, rv3d, locCord)
81 |
82 | cord[0] += float(ary[1])
83 | cord[1] += float(ary[2])
84 |
85 | #convert 2d cords to 3d Cords and apply
86 | vec = view3d_utils.region_2d_to_vector_3d(viewport, rv3d, cord)
87 | loc = view3d_utils.region_2d_to_location_3d(viewport, rv3d, cord, vec)
88 | rv3d.view_location = loc
89 |
90 | def zoom(ary):
91 | rv3d = bpy.context.window_manager.windows[0].screen.areas[1].spaces[0].region_3d
92 | rv3d.view_distance += float(ary[1])
93 |
94 | def pyaw(ary):
95 | rv3d = bpy.context.window_manager.windows[0].screen.areas[1].spaces[0].region_3d
96 | rv3d.view_rotation.rotate(mathutils.Euler(( float(ary[2]) , 0 , float(ary[1]) ))) #pitch roll
97 |
98 | #yaw = ob.rotation_euler.z
99 | #pitch = ob.rotation_euler.y
100 | #roll = ob.rotation_euler.x
101 |
102 | def roll(ary):
103 | rv3d = bpy.context.window_manager.windows[0].screen.areas[1].spaces[0].region_3d
104 | rv3d.view_rotation.rotate(mathutils.Euler(( 0 , float(ary[1]) , 0 ))) #pitch roll
105 |
106 | def exe(ary):
107 | SerialListenerHandler.push(ary)
108 |
109 | cmdList = {"exe":CmdActions.exe, "roll":CmdActions.roll, "pan": CmdActions.pan, "zoom": CmdActions.zoom, "pyaw": CmdActions.pyaw }
110 |
111 |
112 | #====================================================================================
113 | class SerialListener:
114 | isActive = False
115 |
116 | def Connect(port,baud,context):
117 | if SerialListener.isActive:
118 | print("Thread is already active")
119 | return
120 | print(bpy.context.edit_object)
121 | SerialListener.isActive = True
122 | t = threading.Thread(target=SerialListener.ThreadWorker,args=(context,port,baud))
123 | t.start()
124 | bpy.ops.serialmouse.listener_handler()
125 |
126 | def Disconnect():
127 | SerialListener.isActive = False
128 | print("Is not Active")
129 |
130 | def ThreadWorker(contextz,port,baud):
131 | print("ThreadProcess Start")
132 | btnState = "btn_a_0"
133 |
134 | obj = serial.Serial(port,baud,timeout=0.1)
135 | buf = b''
136 |
137 | while SerialListener.isActive:
138 | data = obj.readline()
139 | if data.__len__() > 0:
140 | buf += data
141 | if b'\n' in buf:
142 | tmp = buf.decode().strip(' \t\n\r')
143 | buf = b''
144 | CmdActions.parse(tmp)
145 |
146 | obj.close()
147 | print("ThreadProcess End")
148 | SerialListener.isActive = False
149 | return
150 |
151 | #====================================================================================
152 | class SerialListenerHandler(bpy.types.Operator):
153 | bl_idname = 'serialmouse.listener_handler'
154 | bl_label = 'Start Serial Mouse Handler'
155 |
156 | mTimer = None
157 | mQueue = [] #TODO: Find a way to get Queue Object in blender, better for passing data between threads.
158 |
159 | def modal(self, context, event):
160 | if SerialListener.isActive == False:
161 | self.cancel(context)
162 | return {'CANCELLED'}
163 |
164 | if event.type == 'TIMER':
165 | print(len(SerialListenerHandler.mQueue))
166 | if len(SerialListenerHandler.mQueue) != 0:
167 | ary = SerialListenerHandler.mQueue.pop()
168 | try:
169 | exec(ary[1])
170 | except(RuntimeError, TypeError, NameError):
171 | print("Error running " + ary[1])
172 |
173 | return {'PASS_THROUGH'}
174 |
175 | def execute(self, context):
176 | print("Starting Handler...")
177 | man = context.window_manager
178 | self.mTimer = man.event_timer_add(time_step=0.5,window=context.window)
179 | man.modal_handler_add(self)
180 | return {'RUNNING_MODAL'}
181 |
182 | def cancel(self, context):
183 | context.window_manager.event_timer_remove(self.mTimer)
184 | print('Stopping Handler...')
185 |
186 | def push(txt):
187 | SerialListenerHandler.mQueue.append(txt)
188 |
189 |
190 | #====================================================================================
191 | #Register objects
192 | def register():
193 | bpy.utils.register_module(__name__)
194 | #bpy.utils.register_class(CustomPanel)
195 |
196 | def unregister():
197 | bpy.utils.unregister_module(__name__)
198 | #bpy.utils.unregister_class(SerialMouseSettingsPanel)
199 |
200 |
201 | #If running as a script, do the register.
202 | if __name__ == "__main__":
203 | register()
--------------------------------------------------------------------------------
/blender_files/serial/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a wrapper module for different platform implementations
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2001-2016 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | import importlib
11 | import sys
12 |
13 | from serial.serialutil import *
14 | #~ SerialBase, SerialException, to_bytes, iterbytes
15 |
16 | VERSION = '3.0.1'
17 |
18 | if sys.platform == 'cli':
19 | from serial.serialcli import Serial
20 | else:
21 | import os
22 | # chose an implementation, depending on os
23 | if os.name == 'nt': # sys.platform == 'win32':
24 | from serial.serialwin32 import Serial
25 | elif os.name == 'posix':
26 | from serial.serialposix import Serial, PosixPollSerial, VTIMESerial
27 | elif os.name == 'java':
28 | from serial.serialjava import Serial
29 | else:
30 | raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
31 |
32 |
33 | protocol_handler_packages = [
34 | 'serial.urlhandler',
35 | ]
36 |
37 |
38 | def serial_for_url(url, *args, **kwargs):
39 | """\
40 | Get an instance of the Serial class, depending on port/url. The port is not
41 | opened when the keyword parameter 'do_not_open' is true, by default it
42 | is. All other parameters are directly passed to the __init__ method when
43 | the port is instantiated.
44 |
45 | The list of package names that is searched for protocol handlers is kept in
46 | ``protocol_handler_packages``.
47 |
48 | e.g. we want to support a URL ``foobar://``. A module
49 | ``my_handlers.protocol_foobar`` is provided by the user. Then
50 | ``protocol_handler_packages.append("my_handlers")`` would extend the search
51 | path so that ``serial_for_url("foobar://"))`` would work.
52 | """
53 | # check and remove extra parameter to not confuse the Serial class
54 | do_open = not kwargs.pop('do_not_open', False)
55 | # the default is to use the native implementation
56 | klass = Serial
57 | try:
58 | url_lowercase = url.lower()
59 | except AttributeError:
60 | # it's not a string, use default
61 | pass
62 | else:
63 | # if it is an URL, try to import the handler module from the list of possible packages
64 | if '://' in url_lowercase:
65 | protocol = url_lowercase.split('://', 1)[0]
66 | module_name = '.protocol_%s' % (protocol,)
67 | for package_name in protocol_handler_packages:
68 | try:
69 | package = importlib.import_module(package_name)
70 | handler_module = importlib.import_module(module_name, package_name)
71 | except ImportError:
72 | continue
73 | else:
74 | if hasattr(handler_module, 'serial_class_for_url'):
75 | url, klass = handler_module.serial_class_for_url(url)
76 | else:
77 | klass = handler_module.Serial
78 | break
79 | else:
80 | raise ValueError('invalid URL, protocol %r not known' % (protocol,))
81 | # instantiate and open when desired
82 | instance = klass(None, *args, **kwargs)
83 | instance.port = url
84 | if do_open:
85 | instance.open()
86 | return instance
87 |
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/__init__.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/__init__.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/aio.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/aio.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/rfc2217.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/rfc2217.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/rs485.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/rs485.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/serialcli.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/serialcli.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/serialjava.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/serialjava.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/serialposix.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/serialposix.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/serialutil.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/serialutil.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/serialwin32.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/serialwin32.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/__pycache__/win32.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/__pycache__/win32.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/aio.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Experimental implementation of asyncio support.
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 | """\
10 | Support asyncio with serial ports. EXPERIMENTAL
11 |
12 | Posix platforms only, Python 3.4+ only.
13 |
14 | Windows event loops can not wait for serial ports with the current
15 | implementation. It should be possible to get that working though.
16 | """
17 | import asyncio
18 | import serial
19 | import logging
20 |
21 |
22 | class SerialTransport(asyncio.Transport):
23 | def __init__(self, loop, protocol, serial_instance):
24 | self._loop = loop
25 | self._protocol = protocol
26 | self.serial = serial_instance
27 | self._closing = False
28 | self._paused = False
29 | # XXX how to support url handlers too
30 | self.serial.timeout = 0
31 | self.serial.nonblocking()
32 | loop.call_soon(protocol.connection_made, self)
33 | # only start reading when connection_made() has been called
34 | loop.call_soon(loop.add_reader, self.serial.fd, self._read_ready)
35 |
36 | def __repr__(self):
37 | return '{self.__class__.__name__}({self._loop}, {self._protocol}, {self.serial})'.format(self=self)
38 |
39 | def close(self):
40 | if self._closing:
41 | return
42 | self._closing = True
43 | self._loop.remove_reader(self.serial.fd)
44 | self.serial.close()
45 | self._loop.call_soon(self._protocol.connection_lost, None)
46 |
47 | def _read_ready(self):
48 | data = self.serial.read(1024)
49 | if data:
50 | self._protocol.data_received(data)
51 |
52 | def write(self, data):
53 | self.serial.write(data)
54 |
55 | def can_write_eof(self):
56 | return False
57 |
58 | def pause_reading(self):
59 | if self._closing:
60 | raise RuntimeError('Cannot pause_reading() when closing')
61 | if self._paused:
62 | raise RuntimeError('Already paused')
63 | self._paused = True
64 | self._loop.remove_reader(self._sock_fd)
65 | if self._loop.get_debug():
66 | logging.debug("%r pauses reading", self)
67 |
68 | def resume_reading(self):
69 | if not self._paused:
70 | raise RuntimeError('Not paused')
71 | self._paused = False
72 | if self._closing:
73 | return
74 | self._loop.add_reader(self._sock_fd, self._read_ready)
75 | if self._loop.get_debug():
76 | logging.debug("%r resumes reading", self)
77 |
78 | #~ def set_write_buffer_limits(self, high=None, low=None):
79 | #~ def get_write_buffer_size(self):
80 | #~ def writelines(self, list_of_data):
81 | #~ def write_eof(self):
82 | #~ def abort(self):
83 |
84 |
85 | @asyncio.coroutine
86 | def create_serial_connection(loop, protocol_factory, *args, **kwargs):
87 | ser = serial.Serial(*args, **kwargs)
88 | protocol = protocol_factory()
89 | transport = SerialTransport(loop, protocol, ser)
90 | return (transport, protocol)
91 |
92 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
93 | # test
94 | if __name__ == '__main__':
95 | class Output(asyncio.Protocol):
96 | def connection_made(self, transport):
97 | self.transport = transport
98 | print('port opened', transport)
99 | transport.serial.rts = False
100 | transport.write(b'hello world\n')
101 |
102 | def data_received(self, data):
103 | print('data received', repr(data))
104 | self.transport.close()
105 |
106 | def connection_lost(self, exc):
107 | print('port closed')
108 | asyncio.get_event_loop().stop()
109 |
110 | loop = asyncio.get_event_loop()
111 | coro = create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200)
112 | loop.run_until_complete(coro)
113 | loop.run_forever()
114 | loop.close()
115 |
--------------------------------------------------------------------------------
/blender_files/serial/rs485.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # RS485 support
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | """\
11 | The settings for RS485 are stored in a dedicated object that can be applied to
12 | serial ports (where supported).
13 | NOTE: Some implementations may only support a subset of the settings.
14 | """
15 |
16 | import time
17 | import serial
18 |
19 |
20 | class RS485Settings(object):
21 | def __init__(
22 | self,
23 | rts_level_for_tx=True,
24 | rts_level_for_rx=False,
25 | loopback=False,
26 | delay_before_tx=None,
27 | delay_before_rx=None):
28 | self.rts_level_for_tx = rts_level_for_tx
29 | self.rts_level_for_rx = rts_level_for_rx
30 | self.loopback = loopback
31 | self.delay_before_tx = delay_before_tx
32 | self.delay_before_rx = delay_before_rx
33 |
34 |
35 | class RS485(serial.Serial):
36 | """\
37 | A subclass that replaces the write method with one that toggles RTS
38 | according to the RS485 settings.
39 |
40 | NOTE: This may work unreliably on some serial ports (control signals not
41 | synchronized or delayed compared to data). Using delays may be
42 | unreliable (varying times, larger than expected) as the OS may not
43 | support very fine grained delays (no smaller than in the order of
44 | tens of milliseconds).
45 |
46 | NOTE: Some implementations support this natively. Better performance
47 | can be expected when the native version is used.
48 |
49 | NOTE: The loopback property is ignored by this implementation. The actual
50 | behavior depends on the used hardware.
51 |
52 | Usage:
53 |
54 | ser = RS485(...)
55 | ser.rs485_mode = RS485Settings(...)
56 | ser.write(b'hello')
57 | """
58 |
59 | def __init__(self, *args, **kwargs):
60 | super(RS485, self).__init__(*args, **kwargs)
61 | self._alternate_rs485_settings = None
62 |
63 | def write(self, b):
64 | """Write to port, controlling RTS before and after transmitting."""
65 | if self._alternate_rs485_settings is not None:
66 | # apply level for TX and optional delay
67 | self.setRTS(self._alternate_rs485_settings.rts_level_for_tx)
68 | if self._alternate_rs485_settings.delay_before_tx is not None:
69 | time.sleep(self._alternate_rs485_settings.delay_before_tx)
70 | # write and wait for data to be written
71 | super(RS485, self).write(b)
72 | super(RS485, self).flush()
73 | # optional delay and apply level for RX
74 | if self._alternate_rs485_settings.delay_before_rx is not None:
75 | time.sleep(self._alternate_rs485_settings.delay_before_rx)
76 | self.setRTS(self._alternate_rs485_settings.rts_level_for_rx)
77 | else:
78 | super(RS485, self).write(b)
79 |
80 | # redirect where the property stores the settings so that underlying Serial
81 | # instance does not see them
82 | @property
83 | def rs485_mode(self):
84 | """\
85 | Enable RS485 mode and apply new settings, set to None to disable.
86 | See serial.rs485.RS485Settings for more info about the value.
87 | """
88 | return self._alternate_rs485_settings
89 |
90 | @rs485_mode.setter
91 | def rs485_mode(self, rs485_settings):
92 | self._alternate_rs485_settings = rs485_settings
93 |
--------------------------------------------------------------------------------
/blender_files/serial/serialcli.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # Backend for .NET/Mono (IronPython), .NET >= 2
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2008-2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | import clr
11 | import System
12 | import System.IO.Ports
13 | from serial.serialutil import *
14 |
15 |
16 | #~ def device(portnum):
17 | #~ """Turn a port number into a device name"""
18 | #~ return System.IO.Ports.SerialPort.GetPortNames()[portnum]
19 |
20 |
21 | # must invoke function with byte array, make a helper to convert strings
22 | # to byte arrays
23 | sab = System.Array[System.Byte]
24 | def as_byte_array(string):
25 | return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython
26 |
27 | class Serial(SerialBase):
28 | """Serial port implementation for .NET/Mono."""
29 |
30 | BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
31 | 9600, 19200, 38400, 57600, 115200)
32 |
33 | def open(self):
34 | """\
35 | Open port with current settings. This may throw a SerialException
36 | if the port cannot be opened.
37 | """
38 | if self._port is None:
39 | raise SerialException("Port must be configured before it can be used.")
40 | if self.is_open:
41 | raise SerialException("Port is already open.")
42 | try:
43 | self._port_handle = System.IO.Ports.SerialPort(self.portstr)
44 | except Exception as msg:
45 | self._port_handle = None
46 | raise SerialException("could not open port %s: %s" % (self.portstr, msg))
47 |
48 | self._reconfigurePort()
49 | self._port_handle.Open()
50 | self.is_open = True
51 | if not self._dsrdtr:
52 | self._update_dtr_state()
53 | if not self._rtscts:
54 | self._update_rts_state()
55 | self.reset_input_buffer()
56 |
57 | def _reconfigurePort(self):
58 | """Set communication parameters on opened port."""
59 | if not self._port_handle:
60 | raise SerialException("Can only operate on a valid port handle")
61 |
62 | #~ self._port_handle.ReceivedBytesThreshold = 1
63 |
64 | if self._timeout is None:
65 | self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
66 | else:
67 | self._port_handle.ReadTimeout = int(self._timeout*1000)
68 |
69 | # if self._timeout != 0 and self._interCharTimeout is not None:
70 | # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
71 |
72 | if self._write_timeout is None:
73 | self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
74 | else:
75 | self._port_handle.WriteTimeout = int(self._write_timeout*1000)
76 |
77 |
78 | # Setup the connection info.
79 | try:
80 | self._port_handle.BaudRate = self._baudrate
81 | except IOError as e:
82 | # catch errors from illegal baudrate settings
83 | raise ValueError(str(e))
84 |
85 | if self._bytesize == FIVEBITS:
86 | self._port_handle.DataBits = 5
87 | elif self._bytesize == SIXBITS:
88 | self._port_handle.DataBits = 6
89 | elif self._bytesize == SEVENBITS:
90 | self._port_handle.DataBits = 7
91 | elif self._bytesize == EIGHTBITS:
92 | self._port_handle.DataBits = 8
93 | else:
94 | raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
95 |
96 | if self._parity == PARITY_NONE:
97 | self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
98 | elif self._parity == PARITY_EVEN:
99 | self._port_handle.Parity = System.IO.Ports.Parity.Even
100 | elif self._parity == PARITY_ODD:
101 | self._port_handle.Parity = System.IO.Ports.Parity.Odd
102 | elif self._parity == PARITY_MARK:
103 | self._port_handle.Parity = System.IO.Ports.Parity.Mark
104 | elif self._parity == PARITY_SPACE:
105 | self._port_handle.Parity = System.IO.Ports.Parity.Space
106 | else:
107 | raise ValueError("Unsupported parity mode: %r" % self._parity)
108 |
109 | if self._stopbits == STOPBITS_ONE:
110 | self._port_handle.StopBits = System.IO.Ports.StopBits.One
111 | elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
112 | self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
113 | elif self._stopbits == STOPBITS_TWO:
114 | self._port_handle.StopBits = System.IO.Ports.StopBits.Two
115 | else:
116 | raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
117 |
118 | if self._rtscts and self._xonxoff:
119 | self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
120 | elif self._rtscts:
121 | self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
122 | elif self._xonxoff:
123 | self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
124 | else:
125 | self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
126 |
127 | #~ def __del__(self):
128 | #~ self.close()
129 |
130 | def close(self):
131 | """Close port"""
132 | if self.is_open:
133 | if self._port_handle:
134 | try:
135 | self._port_handle.Close()
136 | except System.IO.Ports.InvalidOperationException:
137 | # ignore errors. can happen for unplugged USB serial devices
138 | pass
139 | self._port_handle = None
140 | self.is_open = False
141 |
142 | # - - - - - - - - - - - - - - - - - - - - - - - -
143 |
144 | @property
145 | def in_waiting(self):
146 | """Return the number of characters currently in the input buffer."""
147 | if not self._port_handle:
148 | raise portNotOpenError
149 | return self._port_handle.BytesToRead
150 |
151 | def read(self, size=1):
152 | """\
153 | Read size bytes from the serial port. If a timeout is set it may
154 | return less characters as requested. With no timeout it will block
155 | until the requested number of bytes is read.
156 | """
157 | if not self._port_handle:
158 | raise portNotOpenError
159 | # must use single byte reads as this is the only way to read
160 | # without applying encodings
161 | data = bytearray()
162 | while size:
163 | try:
164 | data.append(self._port_handle.ReadByte())
165 | except System.TimeoutException as e:
166 | break
167 | else:
168 | size -= 1
169 | return bytes(data)
170 |
171 | def write(self, data):
172 | """Output the given string over the serial port."""
173 | if not self._port_handle:
174 | raise portNotOpenError
175 | #~ if not isinstance(data, (bytes, bytearray)):
176 | #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
177 | try:
178 | # must call overloaded method with byte array argument
179 | # as this is the only one not applying encodings
180 | self._port_handle.Write(as_byte_array(data), 0, len(data))
181 | except System.TimeoutException as e:
182 | raise writeTimeoutError
183 | return len(data)
184 |
185 | def reset_input_buffer(self):
186 | """Clear input buffer, discarding all that is in the buffer."""
187 | if not self._port_handle:
188 | raise portNotOpenError
189 | self._port_handle.DiscardInBuffer()
190 |
191 | def reset_output_buffer(self):
192 | """\
193 | Clear output buffer, aborting the current output and
194 | discarding all that is in the buffer.
195 | """
196 | if not self._port_handle:
197 | raise portNotOpenError
198 | self._port_handle.DiscardOutBuffer()
199 |
200 | def _update_break_state(self):
201 | """
202 | Set break: Controls TXD. When active, to transmitting is possible.
203 | """
204 | if not self._port_handle:
205 | raise portNotOpenError
206 | self._port_handle.BreakState = bool(self._break_state)
207 |
208 | def _update_rts_state(self):
209 | """Set terminal status line: Request To Send"""
210 | if not self._port_handle:
211 | raise portNotOpenError
212 | self._port_handle.RtsEnable = bool(self._rts_state)
213 |
214 | def _update_dtr_state(self):
215 | """Set terminal status line: Data Terminal Ready"""
216 | if not self._port_handle:
217 | raise portNotOpenError
218 | self._port_handle.DtrEnable = bool(self._dtr_state)
219 |
220 | @property
221 | def cts(self):
222 | """Read terminal status line: Clear To Send"""
223 | if not self._port_handle:
224 | raise portNotOpenError
225 | return self._port_handle.CtsHolding
226 |
227 | @property
228 | def dsr(self):
229 | """Read terminal status line: Data Set Ready"""
230 | if not self._port_handle:
231 | raise portNotOpenError
232 | return self._port_handle.DsrHolding
233 |
234 | @property
235 | def ri(self):
236 | """Read terminal status line: Ring Indicator"""
237 | if not self._port_handle:
238 | raise portNotOpenError
239 | #~ return self._port_handle.XXX
240 | return False #XXX an error would be better
241 |
242 | @property
243 | def cd(self):
244 | """Read terminal status line: Carrier Detect"""
245 | if not self._port_handle:
246 | raise portNotOpenError
247 | return self._port_handle.CDHolding
248 |
249 | # - - platform specific - - - -
250 | # none
251 |
252 |
253 | # Nur Testfunktion!!
254 | if __name__ == '__main__':
255 | import sys
256 |
257 | s = Serial(0)
258 | sys.stdio.write('%s\n' % s)
259 |
260 | s = Serial()
261 | sys.stdio.write('%s\n' % s)
262 |
263 |
264 | s.baudrate = 19200
265 | s.databits = 7
266 | s.close()
267 | s.port = 0
268 | s.open()
269 | sys.stdio.write('%s\n' % s)
270 |
271 |
--------------------------------------------------------------------------------
/blender_files/serial/serialjava.py:
--------------------------------------------------------------------------------
1 | #!jython
2 | #
3 | # Backend Jython with JavaComm
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2002-2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | from serial.serialutil import *
11 |
12 |
13 | def my_import(name):
14 | mod = __import__(name)
15 | components = name.split('.')
16 | for comp in components[1:]:
17 | mod = getattr(mod, comp)
18 | return mod
19 |
20 |
21 | def detect_java_comm(names):
22 | """try given list of modules and return that imports"""
23 | for name in names:
24 | try:
25 | mod = my_import(name)
26 | mod.SerialPort
27 | return mod
28 | except (ImportError, AttributeError):
29 | pass
30 | raise ImportError("No Java Communications API implementation found")
31 |
32 |
33 | # Java Communications API implementations
34 | # http://mho.republika.pl/java/comm/
35 |
36 | comm = detect_java_comm([
37 | 'javax.comm', # Sun/IBM
38 | 'gnu.io', # RXTX
39 | ])
40 |
41 |
42 | def device(portnumber):
43 | """Turn a port number into a device name"""
44 | enum = comm.CommPortIdentifier.getPortIdentifiers()
45 | ports = []
46 | while enum.hasMoreElements():
47 | el = enum.nextElement()
48 | if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL:
49 | ports.append(el)
50 | return ports[portnumber].getName()
51 |
52 |
53 | class Serial(SerialBase):
54 | """\
55 | Serial port class, implemented with Java Communications API and
56 | thus usable with jython and the appropriate java extension.
57 | """
58 |
59 | def open(self):
60 | """\
61 | Open port with current settings. This may throw a SerialException
62 | if the port cannot be opened.
63 | """
64 | if self._port is None:
65 | raise SerialException("Port must be configured before it can be used.")
66 | if self.is_open:
67 | raise SerialException("Port is already open.")
68 | if type(self._port) == type(''): # strings are taken directly
69 | portId = comm.CommPortIdentifier.getPortIdentifier(self._port)
70 | else:
71 | portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj
72 | try:
73 | self.sPort = portId.open("python serial module", 10)
74 | except Exception as msg:
75 | self.sPort = None
76 | raise SerialException("Could not open port: %s" % msg)
77 | self._reconfigurePort()
78 | self._instream = self.sPort.getInputStream()
79 | self._outstream = self.sPort.getOutputStream()
80 | self.is_open = True
81 |
82 | def _reconfigurePort(self):
83 | """Set communication parameters on opened port."""
84 | if not self.sPort:
85 | raise SerialException("Can only operate on a valid port handle")
86 |
87 | self.sPort.enableReceiveTimeout(30)
88 | if self._bytesize == FIVEBITS:
89 | jdatabits = comm.SerialPort.DATABITS_5
90 | elif self._bytesize == SIXBITS:
91 | jdatabits = comm.SerialPort.DATABITS_6
92 | elif self._bytesize == SEVENBITS:
93 | jdatabits = comm.SerialPort.DATABITS_7
94 | elif self._bytesize == EIGHTBITS:
95 | jdatabits = comm.SerialPort.DATABITS_8
96 | else:
97 | raise ValueError("unsupported bytesize: %r" % self._bytesize)
98 |
99 | if self._stopbits == STOPBITS_ONE:
100 | jstopbits = comm.SerialPort.STOPBITS_1
101 | elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
102 | jstopbits = comm.SerialPort.STOPBITS_1_5
103 | elif self._stopbits == STOPBITS_TWO:
104 | jstopbits = comm.SerialPort.STOPBITS_2
105 | else:
106 | raise ValueError("unsupported number of stopbits: %r" % self._stopbits)
107 |
108 | if self._parity == PARITY_NONE:
109 | jparity = comm.SerialPort.PARITY_NONE
110 | elif self._parity == PARITY_EVEN:
111 | jparity = comm.SerialPort.PARITY_EVEN
112 | elif self._parity == PARITY_ODD:
113 | jparity = comm.SerialPort.PARITY_ODD
114 | elif self._parity == PARITY_MARK:
115 | jparity = comm.SerialPort.PARITY_MARK
116 | elif self._parity == PARITY_SPACE:
117 | jparity = comm.SerialPort.PARITY_SPACE
118 | else:
119 | raise ValueError("unsupported parity type: %r" % self._parity)
120 |
121 | jflowin = jflowout = 0
122 | if self._rtscts:
123 | jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN
124 | jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT
125 | if self._xonxoff:
126 | jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN
127 | jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT
128 |
129 | self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity)
130 | self.sPort.setFlowControlMode(jflowin | jflowout)
131 |
132 | if self._timeout >= 0:
133 | self.sPort.enableReceiveTimeout(int(self._timeout*1000))
134 | else:
135 | self.sPort.disableReceiveTimeout()
136 |
137 | def close(self):
138 | """Close port"""
139 | if self.is_open:
140 | if self.sPort:
141 | self._instream.close()
142 | self._outstream.close()
143 | self.sPort.close()
144 | self.sPort = None
145 | self.is_open = False
146 |
147 | # - - - - - - - - - - - - - - - - - - - - - - - -
148 |
149 | @property
150 | def in_waiting(self):
151 | """Return the number of characters currently in the input buffer."""
152 | if not self.sPort:
153 | raise portNotOpenError
154 | return self._instream.available()
155 |
156 | def read(self, size=1):
157 | """\
158 | Read size bytes from the serial port. If a timeout is set it may
159 | return less characters as requested. With no timeout it will block
160 | until the requested number of bytes is read.
161 | """
162 | if not self.sPort:
163 | raise portNotOpenError
164 | read = bytearray()
165 | if size > 0:
166 | while len(read) < size:
167 | x = self._instream.read()
168 | if x == -1:
169 | if self.timeout >= 0:
170 | break
171 | else:
172 | read.append(x)
173 | return bytes(read)
174 |
175 | def write(self, data):
176 | """Output the given string over the serial port."""
177 | if not self.sPort:
178 | raise portNotOpenError
179 | if not isinstance(data, (bytes, bytearray)):
180 | raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
181 | self._outstream.write(data)
182 | return len(data)
183 |
184 | def reset_input_buffer(self):
185 | """Clear input buffer, discarding all that is in the buffer."""
186 | if not self.sPort:
187 | raise portNotOpenError
188 | self._instream.skip(self._instream.available())
189 |
190 | def reset_output_buffer(self):
191 | """\
192 | Clear output buffer, aborting the current output and
193 | discarding all that is in the buffer.
194 | """
195 | if not self.sPort:
196 | raise portNotOpenError
197 | self._outstream.flush()
198 |
199 | def send_break(self, duration=0.25):
200 | """Send break condition. Timed, returns to idle state after given duration."""
201 | if not self.sPort:
202 | raise portNotOpenError
203 | self.sPort.sendBreak(duration*1000.0)
204 |
205 | def _update_break_state(self):
206 | """Set break: Controls TXD. When active, to transmitting is possible."""
207 | if self.fd is None:
208 | raise portNotOpenError
209 | raise SerialException("The _update_break_state function is not implemented in java.")
210 |
211 | def _update_rts_state(self):
212 | """Set terminal status line: Request To Send"""
213 | if not self.sPort:
214 | raise portNotOpenError
215 | self.sPort.setRTS(self._rts_state)
216 |
217 | def _update_dtr_state(self):
218 | """Set terminal status line: Data Terminal Ready"""
219 | if not self.sPort:
220 | raise portNotOpenError
221 | self.sPort.setDTR(self._dtr_state)
222 |
223 | @property
224 | def cts(self):
225 | """Read terminal status line: Clear To Send"""
226 | if not self.sPort:
227 | raise portNotOpenError
228 | self.sPort.isCTS()
229 |
230 | @property
231 | def dsr(self):
232 | """Read terminal status line: Data Set Ready"""
233 | if not self.sPort:
234 | raise portNotOpenError
235 | self.sPort.isDSR()
236 |
237 | @property
238 | def ri(self):
239 | """Read terminal status line: Ring Indicator"""
240 | if not self.sPort:
241 | raise portNotOpenError
242 | self.sPort.isRI()
243 |
244 | @property
245 | def cd(self):
246 | """Read terminal status line: Carrier Detect"""
247 | if not self.sPort:
248 | raise portNotOpenError
249 | self.sPort.isCD()
250 |
251 |
252 | if __name__ == '__main__':
253 | s = Serial(0,
254 | baudrate=19200, # baudrate
255 | bytesize=EIGHTBITS, # number of databits
256 | parity=PARITY_EVEN, # enable parity checking
257 | stopbits=STOPBITS_ONE, # number of stopbits
258 | timeout=3, # set a timeout value, None for waiting forever
259 | xonxoff=0, # enable software flow control
260 | rtscts=0, # enable RTS/CTS flow control
261 | )
262 | s.setRTS(1)
263 | s.setDTR(1)
264 | s.reset_input_buffer()
265 | s.reset_output_buffer()
266 | s.write('hello')
267 | sys.stdio.write('%r\n' % s.read(5))
268 | sys.stdio.write('%s\n' % s.in_waiting())
269 | del s
270 |
271 |
--------------------------------------------------------------------------------
/blender_files/serial/threaded/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Working with threading and pySerial
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 | """\
10 | Support threading with serial ports.
11 | """
12 | import serial
13 | import threading
14 |
15 |
16 | class Protocol(object):
17 | """\
18 | Protocol as used by the ReaderThread. This base class provides empty
19 | implementations of all methods.
20 | """
21 |
22 | def connection_made(self, transport):
23 | """Called when reader thread is started"""
24 |
25 | def data_received(self, data):
26 | """Called with snippets received from the serial port"""
27 |
28 | def connection_lost(self, exc):
29 | """\
30 | Called when the serial port is closed or the reader loop terminated
31 | otherwise.
32 | """
33 |
34 |
35 | class Packetizer(Protocol):
36 | """
37 | Read binary packets from serial port. Packets are expected to be terminated
38 | with a TERMINATOR byte (null byte by default).
39 |
40 | The class also keeps track of the transport.
41 | """
42 |
43 | TERMINATOR = b'\0'
44 |
45 | def __init__(self):
46 | self.buffer = bytearray()
47 | self.transport = None
48 |
49 | def connection_made(self, transport):
50 | """Store transport"""
51 | self.transport = transport
52 |
53 | def connection_lost(self, exc):
54 | """Forget transport"""
55 | self.transport = None
56 |
57 | def data_received(self, data):
58 | """Buffer received data, find TERMINATOR, call handle_packet"""
59 | self.buffer.extend(data)
60 | while self.TERMINATOR in self.buffer:
61 | packet, self.buffer = self.buffer.split(self.TERMINATOR)
62 | self.handle_packet(packet)
63 |
64 | def handle_packet(self, packet):
65 | """Process packets - to be overridden by subclassing"""
66 | raise NotImplementedError('please implement functionality in handle_packet')
67 |
68 |
69 | class LineReader(Packetizer):
70 | """
71 | Read and write (Unicode) lines from/to serial port.
72 | The encoding is applied.
73 | """
74 |
75 | TERMINATOR = b'\r\n'
76 | ENCODING = 'utf-8'
77 | UNICODE_HANDLING = 'replace'
78 |
79 | def handle_packet(self, packet):
80 | self.handle_line(packet.decode(self.ENCODING, self.UNICODE_HANDLING))
81 |
82 | def handle_line(self, line):
83 | """Process one line - to be overridden by subclassing"""
84 | raise NotImplementedError('please implement functionality in handle_line')
85 |
86 | def write_line(self, text):
87 | """
88 | Write text to the transport. ``text`` is a Unicode string and the encoding
89 | is applied before sending ans also the newline is append.
90 | """
91 | # + is not the best choice but bytes does not support % or .format in py3 and we want a single write call
92 | self.transport.write(text.encode(self.ENCODING, self.UNICODE_HANDLING) + self.TERMINATOR)
93 |
94 |
95 | class ReaderThread(threading.Thread):
96 | """\
97 | Implement a serial port read loop and dispatch to a Protocol instance (like
98 | the asyncio.Protocol) but do it with threads.
99 |
100 | Calls to close() will close the serial port but it is also possible to just
101 | stop() this thread and continue the serial port instance otherwise.
102 | """
103 |
104 | def __init__(self, serial_instance, protocol_factory):
105 | """\
106 | Initialize thread.
107 |
108 | Note that the serial_instance' timeout is set to one second!
109 | Other settings are not changed.
110 | """
111 | super(ReaderThread, self).__init__()
112 | self.daemon = True
113 | self.serial = serial_instance
114 | self.protocol_factory = protocol_factory
115 | self.alive = True
116 | self._lock = threading.Lock()
117 | self._connection_made = threading.Event()
118 | self.protocol = None
119 |
120 | def stop(self):
121 | """Stop the reader thread"""
122 | self.alive = False
123 | self.join(2)
124 |
125 | def run(self):
126 | """Reader loop"""
127 | self.serial.timeout = 1
128 | self.protocol = self.protocol_factory()
129 | try:
130 | self.protocol.connection_made(self)
131 | except Exception as e:
132 | self.alive = False
133 | self.protocol.connection_lost(e)
134 | self._connection_made.set()
135 | return
136 | error = None
137 | self._connection_made.set()
138 | while self.alive and self.serial.is_open:
139 | try:
140 | # read all that is there or wait for one byte (blocking)
141 | data = self.serial.read(self.serial.in_waiting or 1)
142 | except serial.SerialException as e:
143 | # probably some I/O problem such as disconnected USB serial
144 | # adapters -> exit
145 | error = e
146 | break
147 | else:
148 | if data:
149 | # make a separated try-except for called used code
150 | try:
151 | self.protocol.data_received(data)
152 | except Exception as e:
153 | error = e
154 | break
155 | self.alive = False
156 | self.protocol.connection_lost(error)
157 | self.protocol = None
158 |
159 | def write(self, data):
160 | """Thread safe writing (uses lock)"""
161 | with self._lock:
162 | self.serial.write(data)
163 |
164 | def close(self):
165 | """Close the serial port and exit reader thread (uses lock)"""
166 | # use the lock to let other threads finish writing
167 | with self._lock:
168 | # first stop reading, so that closing can be done on idle port
169 | self.stop()
170 | self.serial.close()
171 |
172 | def connect(self):
173 | """
174 | Wait until connection is set up and return the transport and protocol
175 | instances.
176 | """
177 | if self.alive:
178 | self._connection_made.wait()
179 | if not self.alive:
180 | raise RuntimeError('connection_lost already called')
181 | return (self, self.protocol)
182 | else:
183 | raise RuntimeError('already stopped')
184 |
185 | # - - context manager, returns protocol
186 |
187 | def __enter__(self):
188 | """\
189 | Enter context handler. May raise RuntimeError in case the connection
190 | could not be created.
191 | """
192 | self.start()
193 | self._connection_made.wait()
194 | if not self.alive:
195 | raise RuntimeError('connection_lost already called')
196 | return self.protocol
197 |
198 | def __exit__(self, exc_type, exc_val, exc_tb):
199 | """Leave context: close port"""
200 | self.close()
201 |
202 |
203 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
204 | # test
205 | if __name__ == '__main__':
206 | import sys
207 | import time
208 | import traceback
209 |
210 | class PrintLines(LineReader):
211 | def connection_made(self, transport):
212 | super(PrintLines, self).connection_made(transport)
213 | sys.stdout.write('port opened\n')
214 | self.write_line('hello world')
215 |
216 | def handle_line(self, data):
217 | sys.stdout.write('line received: {}\n'.format(repr(data)))
218 |
219 | def connection_lost(self, exc):
220 | if exc:
221 | traceback.print_exc(exc)
222 | sys.stdout.write('port closed\n')
223 |
224 | ser = serial.serial_for_url('loop://', baudrate=115200, timeout=1)
225 | with ReaderThread(ser, PrintLines) as protocol:
226 | protocol.write_line('hello')
227 | time.sleep(2)
228 |
229 | # alternative usage
230 | ser = serial.serial_for_url('loop://', baudrate=115200, timeout=1)
231 | t = ReaderThread(ser, PrintLines)
232 | t.start()
233 | transport, protocol = t.connect()
234 | protocol.write_line('hello')
235 | time.sleep(2)
236 | t.close()
237 |
--------------------------------------------------------------------------------
/blender_files/serial/threaded/__pycache__/__init__.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/threaded/__pycache__/__init__.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__init__.py
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/__init__.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/__init__.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/hexlify_codec.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/hexlify_codec.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/list_ports.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/list_ports.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/list_ports_common.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/list_ports_common.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/list_ports_linux.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/list_ports_linux.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/list_ports_osx.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/list_ports_osx.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/list_ports_posix.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/list_ports_posix.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/list_ports_windows.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/list_ports_windows.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/__pycache__/miniterm.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/tools/__pycache__/miniterm.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/tools/hexlify_codec.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This is a codec to create and decode hexdumps with spaces between characters. used by miniterm.
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2011 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 | """\
10 | Python 'hex' Codec - 2-digit hex with spaces content transfer encoding.
11 | """
12 |
13 | import codecs
14 | import serial
15 |
16 | HEXDIGITS = '0123456789ABCDEF'
17 |
18 | ### Codec APIs
19 |
20 |
21 | def hex_encode(input, errors='strict'):
22 | return (serial.to_bytes([int(h, 16) for h in input.split()]), len(input))
23 |
24 |
25 | def hex_decode(input, errors='strict'):
26 | return (''.join('{:02X} '.format(b) for b in input), len(input))
27 |
28 |
29 | class Codec(codecs.Codec):
30 | def encode(self, input, errors='strict'):
31 | return serial.to_bytes([int(h, 16) for h in input.split()])
32 |
33 | def decode(self, input, errors='strict'):
34 | return ''.join('{:02X} '.format(b) for b in input)
35 |
36 |
37 | class IncrementalEncoder(codecs.IncrementalEncoder):
38 |
39 | def __init__(self, errors='strict'):
40 | self.errors = errors
41 | self.state = 0
42 |
43 | def reset(self):
44 | self.state = 0
45 |
46 | def getstate(self):
47 | return self.state
48 |
49 | def setstate(self, state):
50 | self.state = state
51 |
52 | def encode(self, input, final=False):
53 | state = self.state
54 | encoded = []
55 | for c in input.upper():
56 | if c in HEXDIGITS:
57 | z = HEXDIGITS.index(c)
58 | if state:
59 | encoded.append(z + (state & 0xf0))
60 | state = 0
61 | else:
62 | state = 0x100 + (z << 4)
63 | elif c == ' ': # allow spaces to separate values
64 | if state and self.errors == 'strict':
65 | raise UnicodeError('odd number of hex digits')
66 | state = 0
67 | else:
68 | if self.errors == 'strict':
69 | raise UnicodeError('non-hex digit found: %r' % c)
70 | self.state = state
71 | return serial.to_bytes(encoded)
72 |
73 |
74 | class IncrementalDecoder(codecs.IncrementalDecoder):
75 | def decode(self, input, final=False):
76 | return ''.join('{:02X} '.format(b) for b in input)
77 |
78 |
79 | class StreamWriter(Codec, codecs.StreamWriter):
80 | pass
81 |
82 |
83 | class StreamReader(Codec, codecs.StreamReader):
84 | pass
85 |
86 |
87 | ### encodings module API
88 | def getregentry():
89 | return codecs.CodecInfo(
90 | name='hexlify',
91 | encode=hex_encode,
92 | decode=hex_decode,
93 | incrementalencoder=IncrementalEncoder,
94 | incrementaldecoder=IncrementalDecoder,
95 | streamwriter=StreamWriter,
96 | streamreader=StreamReader,
97 | _is_text_encoding=True,
98 | )
99 |
--------------------------------------------------------------------------------
/blender_files/serial/tools/list_ports.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Serial port enumeration. Console tool and backend selection.
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2011-2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | """\
11 | This module will provide a function called comports that returns an
12 | iterable (generator or list) that will enumerate available com ports. Note that
13 | on some systems non-existent ports may be listed.
14 |
15 | Additionally a grep function is supplied that can be used to search for ports
16 | based on their descriptions or hardware ID.
17 | """
18 |
19 | import sys
20 | import os
21 | import re
22 |
23 | # chose an implementation, depending on os
24 | #~ if sys.platform == 'cli':
25 | #~ else:
26 | if os.name == 'nt': # sys.platform == 'win32':
27 | from serial.tools.list_ports_windows import comports
28 | elif os.name == 'posix':
29 | from serial.tools.list_ports_posix import comports
30 | #~ elif os.name == 'java':
31 | else:
32 | raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
33 |
34 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35 |
36 |
37 | def grep(regexp):
38 | """\
39 | Search for ports using a regular expression. Port name, description and
40 | hardware ID are searched. The function returns an iterable that returns the
41 | same tuples as comport() would do.
42 | """
43 | r = re.compile(regexp, re.I)
44 | for info in comports():
45 | port, desc, hwid = info
46 | if r.search(port) or r.search(desc) or r.search(hwid):
47 | yield info
48 |
49 |
50 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
51 | def main():
52 | import argparse
53 |
54 | parser = argparse.ArgumentParser(description='Serial port enumeration')
55 |
56 | parser.add_argument(
57 | 'regexp',
58 | nargs='?',
59 | help='only show ports that match this regex')
60 |
61 | parser.add_argument(
62 | '-v', '--verbose',
63 | action='store_true',
64 | help='show more messages')
65 |
66 | parser.add_argument(
67 | '-q', '--quiet',
68 | action='store_true',
69 | help='suppress all messages')
70 |
71 | parser.add_argument(
72 | '-n',
73 | type=int,
74 | help='only output the N-th entry')
75 |
76 | args = parser.parse_args()
77 |
78 | hits = 0
79 | # get iteraror w/ or w/o filter
80 | if args.regexp:
81 | if not args.quiet:
82 | sys.stderr.write("Filtered list with regexp: %r\n" % (args.regexp,))
83 | iterator = sorted(grep(args.regexp))
84 | else:
85 | iterator = sorted(comports())
86 | # list them
87 | for n, (port, desc, hwid) in enumerate(iterator, 1):
88 | if args.n is None or args.n == n:
89 | sys.stdout.write("{:20}\n".format(port))
90 | if args.verbose:
91 | sys.stdout.write(" desc: {}\n".format(desc))
92 | sys.stdout.write(" hwid: {}\n".format(hwid))
93 | hits += 1
94 | if not args.quiet:
95 | if hits:
96 | sys.stderr.write("{} ports found\n".format(hits))
97 | else:
98 | sys.stderr.write("no ports found\n")
99 |
100 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
101 | # test
102 | if __name__ == '__main__':
103 | main()
104 |
--------------------------------------------------------------------------------
/blender_files/serial/tools/list_ports_common.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a helper module for the various platform dependent list_port
4 | # implementations.
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 | import re
11 |
12 |
13 | def numsplit(text):
14 | """\
15 | Convert string into a list of texts and numbers in order to support a
16 | natural sorting.
17 | """
18 | result = []
19 | for group in re.split(r'(\d+)', text):
20 | if group:
21 | try:
22 | group = int(group)
23 | except ValueError:
24 | pass
25 | result.append(group)
26 | return result
27 |
28 |
29 | class ListPortInfo(object):
30 | """Info collection base class for serial ports"""
31 |
32 | def __init__(self, device=None):
33 | self.device = device
34 | self.name = None
35 | self.description = 'n/a'
36 | self.hwid = 'n/a'
37 | # USB specific data
38 | self.vid = None
39 | self.pid = None
40 | self.serial_number = None
41 | self.location = None
42 | self.manufacturer = None
43 | self.product = None
44 | self.interface = None
45 |
46 | def usb_description(self):
47 | if self.interface is not None:
48 | return '{} - {}'.format(self.product, self.interface)
49 | elif self.product is not None:
50 | return self.product
51 | else:
52 | return self.name
53 |
54 | def usb_info(self):
55 | return 'USB VID:PID={:04X}:{:04X}{}{}'.format(
56 | self.vid,
57 | self.pid,
58 | ' SER={}'.format(self.serial_number) if self.serial_number is not None else '',
59 | ' LOCATION={}'.format(self.location) if self.location is not None else '',
60 | )
61 |
62 | def apply_usb_info(self):
63 | """update description and hwid from USB data"""
64 | self.description = self.usb_description()
65 | self.hwid = self.usb_info()
66 |
67 | def __eq__(self, other):
68 | return self.device == other.device
69 |
70 | def __lt__(self, other):
71 | return numsplit(self.device) < numsplit(other.device)
72 |
73 | def __str__(self):
74 | return '{} - {}'.format(self.device, self.description)
75 |
76 | def __getitem__(self, index):
77 | """Item access: backwards compatible -> (port, desc, hwid)"""
78 | if index == 0:
79 | return self.device
80 | elif index == 1:
81 | return self.description
82 | elif index == 2:
83 | return self.hwid
84 | else:
85 | raise IndexError('{} > 2'.format(index))
86 |
87 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
88 | # test
89 | if __name__ == '__main__':
90 | print(ListPortInfo('dummy'))
91 |
--------------------------------------------------------------------------------
/blender_files/serial/tools/list_ports_linux.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a module that gathers a list of serial ports including details on
4 | # GNU/Linux systems.
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2011-2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 |
11 | import glob
12 | import os
13 | from serial.tools import list_ports_common
14 |
15 |
16 | class SysFS(list_ports_common.ListPortInfo):
17 | """Wrapper for easy sysfs access and device info"""
18 |
19 | def __init__(self, device):
20 | super(SysFS, self).__init__(device)
21 | self.name = os.path.basename(device)
22 | self.usb_device_path = None
23 | if os.path.exists('/sys/class/tty/%s/device' % (self.name,)):
24 | self.device_path = os.path.realpath('/sys/class/tty/%s/device' % (self.name,))
25 | self.subsystem = os.path.basename(os.path.realpath(os.path.join(self.device_path, 'subsystem')))
26 | else:
27 | self.device_path = None
28 | self.subsystem = None
29 | # check device type
30 | if self.subsystem == 'usb-serial':
31 | self.usb_device_path = os.path.dirname(os.path.dirname(self.device_path))
32 | elif self.subsystem == 'usb':
33 | self.usb_device_path = os.path.dirname(self.device_path)
34 | else:
35 | self.usb_device_path = None
36 | # fill-in info for USB devices
37 | if self.usb_device_path is not None:
38 | self.vid = int(self.read_line(self.usb_device_path, 'idVendor'), 16)
39 | self.pid = int(self.read_line(self.usb_device_path, 'idProduct'), 16)
40 | self.serial_number = self.read_line(self.usb_device_path, 'serial')
41 | self.location = os.path.basename(self.usb_device_path)
42 | self.manufacturer = self.read_line(self.usb_device_path, 'manufacturer')
43 | self.product = self.read_line(self.usb_device_path, 'product')
44 | self.interface = self.read_line(self.device_path, 'interface')
45 |
46 | if self.subsystem in ('usb', 'usb-serial'):
47 | self.apply_usb_info()
48 | #~ elif self.subsystem in ('pnp', 'amba'): # PCI based devices, raspi
49 | elif self.subsystem == 'pnp': # PCI based devices
50 | self.description = self.name
51 | self.hwid = self.read_line(self.device_path, 'id')
52 | elif self.subsystem == 'amba': # raspi
53 | self.description = self.name
54 | self.hwid = os.path.basename(self.device_path)
55 |
56 | def read_line(self, *args):
57 | """\
58 | Helper function to read a single line from a file.
59 | One or more parameters are allowed, they are joined with os.path.join.
60 | Returns None on errors..
61 | """
62 | try:
63 | with open(os.path.join(*args)) as f:
64 | line = f.readline().strip()
65 | return line
66 | except IOError:
67 | return None
68 |
69 |
70 | def comports():
71 | devices = glob.glob('/dev/ttyS*') # built-in serial ports
72 | devices.extend(glob.glob('/dev/ttyUSB*')) # usb-serial with own driver
73 | devices.extend(glob.glob('/dev/ttyACM*')) # usb-serial with CDC-ACM profile
74 | devices.extend(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi)
75 | devices.extend(glob.glob('/dev/rfcomm*')) # BT serial devices
76 | return [info
77 | for info in [SysFS(d) for d in devices]
78 | if info.subsystem != "platform"] # hide non-present internal serial ports
79 |
80 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
81 | # test
82 | if __name__ == '__main__':
83 | for port, desc, hwid in sorted(comports()):
84 | print("%s: %s [%s]" % (port, desc, hwid))
85 |
--------------------------------------------------------------------------------
/blender_files/serial/tools/list_ports_osx.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a module that gathers a list of serial ports including details on OSX
4 | #
5 | # code originally from https://github.com/makerbot/pyserial/tree/master/serial/tools
6 | # with contributions from cibomahto, dgs3, FarMcKon, tedbrandston
7 | # and modifications by cliechti, hoihu, hardkrash
8 | #
9 | # This file is part of pySerial. https://github.com/pyserial/pyserial
10 | # (C) 2013-2015
11 | #
12 | # SPDX-License-Identifier: BSD-3-Clause
13 |
14 |
15 | # List all of the callout devices in OS/X by querying IOKit.
16 |
17 | # See the following for a reference of how to do this:
18 | # http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html#//apple_ref/doc/uid/TP30000384-CIHGEAFD
19 |
20 | # More help from darwin_hid.py
21 |
22 | # Also see the 'IORegistryExplorer' for an idea of what we are actually searching
23 |
24 | import ctypes
25 | from ctypes import util
26 |
27 | from serial.tools import list_ports_common
28 |
29 | iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit'))
30 | cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
31 |
32 | kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault")
33 | kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault")
34 |
35 | kCFStringEncodingMacRoman = 0
36 |
37 | iokit.IOServiceMatching.restype = ctypes.c_void_p
38 |
39 | iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
40 | iokit.IOServiceGetMatchingServices.restype = ctypes.c_void_p
41 |
42 | iokit.IORegistryEntryGetParentEntry.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
43 |
44 | iokit.IORegistryEntryCreateCFProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint32]
45 | iokit.IORegistryEntryCreateCFProperty.restype = ctypes.c_void_p
46 |
47 | iokit.IORegistryEntryGetPath.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
48 | iokit.IORegistryEntryGetPath.restype = ctypes.c_void_p
49 |
50 | iokit.IORegistryEntryGetName.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
51 | iokit.IORegistryEntryGetName.restype = ctypes.c_void_p
52 |
53 | iokit.IOObjectGetClass.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
54 | iokit.IOObjectGetClass.restype = ctypes.c_void_p
55 |
56 | iokit.IOObjectRelease.argtypes = [ctypes.c_void_p]
57 |
58 |
59 | cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32]
60 | cf.CFStringCreateWithCString.restype = ctypes.c_void_p
61 |
62 | cf.CFStringGetCStringPtr.argtypes = [ctypes.c_void_p, ctypes.c_uint32]
63 | cf.CFStringGetCStringPtr.restype = ctypes.c_char_p
64 |
65 | cf.CFNumberGetValue.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p]
66 | cf.CFNumberGetValue.restype = ctypes.c_void_p
67 |
68 | # void CFRelease ( CFTypeRef cf );
69 | cf.CFRelease.argtypes = [ctypes.c_void_p]
70 | cf.CFRelease.restype = None
71 |
72 | # CFNumber type defines
73 | kCFNumberSInt8Type = 1
74 | kCFNumberSInt16Type = 2
75 | kCFNumberSInt32Type = 3
76 | kCFNumberSInt64Type = 4
77 |
78 |
79 | def get_string_property(device_type, property):
80 | """
81 | Search the given device for the specified string property
82 |
83 | @param device_type Type of Device
84 | @param property String to search for
85 | @return Python string containing the value, or None if not found.
86 | """
87 | key = cf.CFStringCreateWithCString(
88 | kCFAllocatorDefault,
89 | property.encode("mac_roman"),
90 | kCFStringEncodingMacRoman)
91 |
92 | CFContainer = iokit.IORegistryEntryCreateCFProperty(
93 | device_type,
94 | key,
95 | kCFAllocatorDefault,
96 | 0)
97 | output = None
98 |
99 | if CFContainer:
100 | output = cf.CFStringGetCStringPtr(CFContainer, 0)
101 | if output is not None:
102 | output = output.decode('mac_roman')
103 | cf.CFRelease(CFContainer)
104 | return output
105 |
106 |
107 | def get_int_property(device_type, property, cf_number_type):
108 | """
109 | Search the given device for the specified string property
110 |
111 | @param device_type Device to search
112 | @param property String to search for
113 | @param cf_number_type CFType number
114 |
115 | @return Python string containing the value, or None if not found.
116 | """
117 | key = cf.CFStringCreateWithCString(
118 | kCFAllocatorDefault,
119 | property.encode("mac_roman"),
120 | kCFStringEncodingMacRoman)
121 |
122 | CFContainer = iokit.IORegistryEntryCreateCFProperty(
123 | device_type,
124 | key,
125 | kCFAllocatorDefault,
126 | 0)
127 |
128 | if CFContainer:
129 | if (cf_number_type == kCFNumberSInt32Type):
130 | number = ctypes.c_uint32()
131 | elif (cf_number_type == kCFNumberSInt16Type):
132 | number = ctypes.c_uint16()
133 | cf.CFNumberGetValue(CFContainer, cf_number_type, ctypes.byref(number))
134 | cf.CFRelease(CFContainer)
135 | return number.value
136 | return None
137 |
138 |
139 | def IORegistryEntryGetName(device):
140 | pathname = ctypes.create_string_buffer(100) # TODO: Is this ok?
141 | iokit.IOObjectGetClass(device, ctypes.byref(pathname))
142 | return pathname.value
143 |
144 |
145 | def GetParentDeviceByType(device, parent_type):
146 | """ Find the first parent of a device that implements the parent_type
147 | @param IOService Service to inspect
148 | @return Pointer to the parent type, or None if it was not found.
149 | """
150 | # First, try to walk up the IOService tree to find a parent of this device that is a IOUSBDevice.
151 | parent_type = parent_type.encode('mac_roman')
152 | while IORegistryEntryGetName(device) != parent_type:
153 | parent = ctypes.c_void_p()
154 | response = iokit.IORegistryEntryGetParentEntry(
155 | device,
156 | "IOService".encode("mac_roman"),
157 | ctypes.byref(parent))
158 | # If we weren't able to find a parent for the device, we're done.
159 | if response != 0:
160 | return None
161 | device = parent
162 | return device
163 |
164 |
165 | def GetIOServicesByType(service_type):
166 | """
167 | returns iterator over specified service_type
168 | """
169 | serial_port_iterator = ctypes.c_void_p()
170 |
171 | iokit.IOServiceGetMatchingServices(
172 | kIOMasterPortDefault,
173 | iokit.IOServiceMatching(service_type.encode('mac_roman')),
174 | ctypes.byref(serial_port_iterator))
175 |
176 | services = []
177 | while iokit.IOIteratorIsValid(serial_port_iterator):
178 | service = iokit.IOIteratorNext(serial_port_iterator)
179 | if not service:
180 | break
181 | services.append(service)
182 | iokit.IOObjectRelease(serial_port_iterator)
183 | return services
184 |
185 |
186 | def location_to_string(locationID):
187 | """
188 | helper to calculate port and bus number from locationID
189 | """
190 | loc = ['{}-'.format(locationID >> 24)]
191 | while locationID & 0xf00000:
192 | if len(loc) > 1:
193 | loc.append('.')
194 | loc.append('{}'.format((locationID >> 20) & 0xf))
195 | locationID <<= 4
196 | return ''.join(loc)
197 |
198 |
199 | class SuitableSerialInterface(object):
200 | pass
201 |
202 |
203 | def scan_interfaces():
204 | """
205 | helper function to scan USB interfaces
206 | returns a list of SuitableSerialInterface objects with name and id attributes
207 | """
208 | interfaces = []
209 | for service in GetIOServicesByType('IOSerialBSDClient'):
210 | device = get_string_property(service, "IOCalloutDevice")
211 | if device:
212 | usb_device = GetParentDeviceByType(service, "IOUSBInterface")
213 | if usb_device:
214 | name = get_string_property(usb_device, "USB Interface Name") or None
215 | locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type) or ''
216 | i = SuitableSerialInterface()
217 | i.id = locationID
218 | i.name = name
219 | interfaces.append(i)
220 | return interfaces
221 |
222 |
223 | def search_for_locationID_in_interfaces(serial_interfaces, locationID):
224 | for interface in serial_interfaces:
225 | if (interface.id == locationID):
226 | return interface.name
227 | return None
228 |
229 |
230 | def comports():
231 | # Scan for all iokit serial ports
232 | services = GetIOServicesByType('IOSerialBSDClient')
233 | ports = []
234 | serial_interfaces = scan_interfaces()
235 | for service in services:
236 | # First, add the callout device file.
237 | device = get_string_property(service, "IOCalloutDevice")
238 | if device:
239 | info = list_ports_common.ListPortInfo(device)
240 | # If the serial port is implemented by IOUSBDevice
241 | usb_device = GetParentDeviceByType(service, "IOUSBDevice")
242 | if usb_device:
243 | # fetch some useful informations from properties
244 | info.vid = get_int_property(usb_device, "idVendor", kCFNumberSInt16Type)
245 | info.pid = get_int_property(usb_device, "idProduct", kCFNumberSInt16Type)
246 | info.serial_number = get_string_property(usb_device, "USB Serial Number")
247 | info.product = get_string_property(usb_device, "USB Product Name") or 'n/a'
248 | info.manufacturer = get_string_property(usb_device, "USB Vendor Name")
249 | locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type)
250 | info.location = location_to_string(locationID)
251 | info.interface = search_for_locationID_in_interfaces(serial_interfaces, locationID)
252 | info.apply_usb_info()
253 | ports.append(info)
254 | return ports
255 |
256 | # test
257 | if __name__ == '__main__':
258 | for port, desc, hwid in sorted(comports()):
259 | print("%s: %s [%s]" % (port, desc, hwid))
260 |
--------------------------------------------------------------------------------
/blender_files/serial/tools/list_ports_posix.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a module that gathers a list of serial ports on POSIXy systems.
4 | # For some specific implementations, see also list_ports_linux, list_ports_osx
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2011-2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 |
11 | """\
12 | The ``comports`` function is expected to return an iterable that yields tuples
13 | of 3 strings: port name, human readable description and a hardware ID.
14 |
15 | As currently no method is known to get the second two strings easily, they are
16 | currently just identical to the port name.
17 | """
18 |
19 | import glob
20 | import sys
21 | import os
22 | from serial.tools import list_ports_common
23 |
24 | # try to detect the OS so that a device can be selected...
25 | plat = sys.platform.lower()
26 |
27 | if plat[:5] == 'linux': # Linux (confirmed)
28 | from serial.tools.list_ports_linux import comports
29 |
30 | elif plat[:6] == 'darwin': # OS X (confirmed)
31 | from serial.tools.list_ports_osx import comports
32 |
33 | elif plat == 'cygwin': # cygwin/win32
34 | # cygwin accepts /dev/com* in many contexts
35 | # (such as 'open' call, explicit 'ls'), but 'glob.glob'
36 | # and bare 'ls' do not; so use /dev/ttyS* instead
37 | def comports():
38 | devices = glob.glob('/dev/ttyS*')
39 | return [list_ports_common.ListPortInfo(d) for d in devices]
40 |
41 | elif plat[:7] == 'openbsd': # OpenBSD
42 | def comports():
43 | devices = glob.glob('/dev/cua*')
44 | return [list_ports_common.ListPortInfo(d) for d in devices]
45 |
46 | elif plat[:3] == 'bsd' or plat[:7] == 'freebsd':
47 |
48 | def comports():
49 | devices = glob.glob('/dev/cua*[!.init][!.lock]')
50 | return [list_ports_common.ListPortInfo(d) for d in devices]
51 |
52 | elif plat[:6] == 'netbsd': # NetBSD
53 | def comports():
54 | """scan for available ports. return a list of device names."""
55 | devices = glob.glob('/dev/dty*')
56 | return [list_ports_common.ListPortInfo(d) for d in devices]
57 |
58 | elif plat[:4] == 'irix': # IRIX
59 | def comports():
60 | """scan for available ports. return a list of device names."""
61 | devices = glob.glob('/dev/ttyf*')
62 | return [list_ports_common.ListPortInfo(d) for d in devices]
63 |
64 | elif plat[:2] == 'hp': # HP-UX (not tested)
65 | def comports():
66 | """scan for available ports. return a list of device names."""
67 | devices = glob.glob('/dev/tty*p0')
68 | return [list_ports_common.ListPortInfo(d) for d in devices]
69 |
70 | elif plat[:5] == 'sunos': # Solaris/SunOS
71 | def comports():
72 | """scan for available ports. return a list of device names."""
73 | devices = glob.glob('/dev/tty*c')
74 | return [list_ports_common.ListPortInfo(d) for d in devices]
75 |
76 | elif plat[:3] == 'aix': # AIX
77 | def comports():
78 | """scan for available ports. return a list of device names."""
79 | devices = glob.glob('/dev/tty*')
80 | return [list_ports_common.ListPortInfo(d) for d in devices]
81 |
82 | else:
83 | # platform detection has failed...
84 | import serial
85 | sys.stderr.write("""\
86 | don't know how to enumerate ttys on this system.
87 | ! I you know how the serial ports are named send this information to
88 | ! the author of this module:
89 |
90 | sys.platform = %r
91 | os.name = %r
92 | pySerial version = %s
93 |
94 | also add the naming scheme of the serial ports and with a bit luck you can get
95 | this module running...
96 | """ % (sys.platform, os.name, serial.VERSION))
97 | raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
98 |
99 | # test
100 | if __name__ == '__main__':
101 | for port, desc, hwid in sorted(comports()):
102 | print("%s: %s [%s]" % (port, desc, hwid))
103 |
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__init__.py
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__pycache__/__init__.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__pycache__/__init__.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__pycache__/protocol_alt.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__pycache__/protocol_alt.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__pycache__/protocol_hwgrep.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__pycache__/protocol_hwgrep.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__pycache__/protocol_loop.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__pycache__/protocol_loop.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__pycache__/protocol_rfc2217.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__pycache__/protocol_rfc2217.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__pycache__/protocol_socket.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__pycache__/protocol_socket.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/__pycache__/protocol_spy.cpython-35.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial/urlhandler/__pycache__/protocol_spy.cpython-35.pyc
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/protocol_alt.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This module implements a special URL handler that allows selecting an
4 | # alternate implementation provided by some backends.
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 | #
11 | # URL format: alt://port[?option[=value][&option[=value]]]
12 | # options:
13 | # - class=X used class named X instead of Serial
14 | #
15 | # example:
16 | # use poll based implementation on Posix (Linux):
17 | # python -m serial.tools.miniterm alt:///dev/ttyUSB0?class=PosixPollSerial
18 |
19 | import sys
20 | import time
21 |
22 | import serial
23 |
24 | try:
25 | import urlparse
26 | except ImportError:
27 | import urllib.parse as urlparse
28 |
29 |
30 | def serial_class_for_url(url):
31 | """extract host and port from an URL string"""
32 | parts = urlparse.urlsplit(url)
33 | if parts.scheme != 'alt':
34 | raise serial.SerialException('expected a string in the form "alt://port[?option[=value][&option[=value]]]": not starting with alt:// (%r)' % (parts.scheme,))
35 | class_name = 'Serial'
36 | try:
37 | for option, values in urlparse.parse_qs(parts.query, True).items():
38 | if option == 'class':
39 | class_name = values[0]
40 | else:
41 | raise ValueError('unknown option: %r' % (option,))
42 | except ValueError as e:
43 | raise serial.SerialException('expected a string in the form "alt://port[?option[=value][&option[=value]]]": %s' % e)
44 | return (''.join([parts.netloc, parts.path]), getattr(serial, class_name))
45 |
46 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
47 | if __name__ == '__main__':
48 | s = serial_for_url('alt:///dev/ttyS0?class=PosixPollSerial')
49 | print(s)
50 |
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/protocol_hwgrep.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This module implements a special URL handler that uses the port listing to
4 | # find ports by searching the string descriptions.
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2011-2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 | #
11 | # URL format: hwgrep://&
12 | #
13 | # where is a Python regexp according to the re module
14 | #
15 | # violating the normal definition for URLs, the charachter `&` is used to
16 | # separate parameters from the arguments (instead of `?`, but the question mark
17 | # is heavily used in regexp'es)
18 | #
19 | # options:
20 | # n= pick the N'th entry instead of the first one (numbering starts at 1)
21 | # skip_busy tries to open port to check if it is busy, fails on posix as ports are not locked!
22 |
23 | import serial
24 | import serial.tools.list_ports
25 |
26 | try:
27 | basestring
28 | except NameError:
29 | basestring = str # python 3
30 |
31 |
32 | class Serial(serial.Serial):
33 | """Just inherit the native Serial port implementation and patch the port property."""
34 |
35 | @serial.Serial.port.setter
36 | def port(self, value):
37 | """translate port name before storing it"""
38 | if isinstance(value, basestring) and value.startswith('hwgrep://'):
39 | serial.Serial.port.__set__(self, self.from_url(value))
40 | else:
41 | serial.Serial.port.__set__(self, value)
42 |
43 | def from_url(self, url):
44 | """extract host and port from an URL string"""
45 | if url.lower().startswith("hwgrep://"):
46 | url = url[9:]
47 | n = 0
48 | test_open = False
49 | args = url.split('&')
50 | regexp = args.pop(0)
51 | for arg in args:
52 | if '=' in arg:
53 | option, value = arg.split('=', 1)
54 | else:
55 | option = arg
56 | value = None
57 | if option == 'n':
58 | # pick n'th element
59 | n = int(value) - 1
60 | if n < 1:
61 | raise ValueError('option "n" expects a positive integer larger than 1: %r' % (value,))
62 | elif option == 'skip_busy':
63 | # open to test if port is available. not the nicest way..
64 | test_open = True
65 | else:
66 | raise ValueError('unknown option: %r' % (option,))
67 | # use a for loop to get the 1st element from the generator
68 | for port, desc, hwid in sorted(serial.tools.list_ports.grep(regexp)):
69 | if test_open:
70 | try:
71 | s = serial.Serial(port)
72 | except serial.SerialException:
73 | # it has some error, skip this one
74 | continue
75 | else:
76 | s.close()
77 | if n:
78 | n -= 1
79 | continue
80 | return port
81 | else:
82 | raise serial.SerialException('no ports found matching regexp %r' % (url,))
83 |
84 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85 | if __name__ == '__main__':
86 | s = Serial(None)
87 | s.port = 'hwgrep://ttyS0'
88 | print(s)
89 |
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/protocol_rfc2217.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This is a thin wrapper to load the rfc2271 implementation.
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2011 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | from serial.rfc2217 import Serial
11 |
--------------------------------------------------------------------------------
/blender_files/serial/urlhandler/protocol_spy.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This module implements a special URL handler that wraps an other port,
4 | # print the traffic for debugging purposes. With this, it is possible
5 | # to debug the serial port traffic on every application that uses
6 | # serial_for_url.
7 | #
8 | # This file is part of pySerial. https://github.com/pyserial/pyserial
9 | # (C) 2015 Chris Liechti
10 | #
11 | # SPDX-License-Identifier: BSD-3-Clause
12 | #
13 | # URL format: spy://port[?option[=value][&option[=value]]]
14 | # options:
15 | # - dev=X a file or device to write to
16 | # - color use escape code to colorize output
17 | # - raw forward raw bytes instead of hexdump
18 | #
19 | # example:
20 | # redirect output to an other terminal window on Posix (Linux):
21 | # python -m serial.tools.miniterm spy:///dev/ttyUSB0?dev=/dev/pts/14\&color
22 |
23 | import sys
24 | import time
25 |
26 | import serial
27 |
28 | try:
29 | import urlparse
30 | except ImportError:
31 | import urllib.parse as urlparse
32 |
33 |
34 | def sixteen(data):
35 | """\
36 | yield tuples of hex and ASCII display in multiples of 16. Includes a
37 | space after 8 bytes and (None, None) after 16 bytes and at the end.
38 | """
39 | n = 0
40 | for b in serial.iterbytes(data):
41 | yield ('{:02X} '.format(ord(b)), b.decode('ascii') if b' ' <= b < b'\x7f' else '.')
42 | n += 1
43 | if n == 8:
44 | yield (' ', '')
45 | elif n >= 16:
46 | yield (None, None)
47 | n = 0
48 | if n > 0:
49 | while n < 16:
50 | n += 1
51 | if n == 8:
52 | yield (' ', '')
53 | yield (' ', ' ')
54 | yield (None, None)
55 |
56 |
57 | def hexdump(data):
58 | """yield lines with hexdump of data"""
59 | values = []
60 | ascii = []
61 | offset = 0
62 | for h, a in sixteen(data):
63 | if h is None:
64 | yield (offset, ' '.join([
65 | ''.join(values),
66 | ''.join(ascii)]))
67 | del values[:]
68 | del ascii[:]
69 | offset += 0x10
70 | else:
71 | values.append(h)
72 | ascii.append(a)
73 |
74 |
75 | class FormatRaw(object):
76 | """Forward only RX and TX data to output."""
77 |
78 | def __init__(self, output, color):
79 | self.output = output
80 | self.color = color
81 | self.rx_color = '\x1b[32m'
82 | self.tx_color = '\x1b[31m'
83 |
84 | def rx(self, data):
85 | if self.color:
86 | self.output.write(self.rx_color)
87 | self.output.write(data)
88 | self.output.flush()
89 |
90 | def tx(self, data):
91 | if self.color:
92 | self.output.write(self.tx_color)
93 | self.output.write(data)
94 | self.output.flush()
95 |
96 | def control(self, name, value):
97 | pass
98 |
99 |
100 | class FormatHexdump(object):
101 | """\
102 | Create a hex dump of RX ad TX data, show when control lines are read or
103 | written.
104 |
105 | output example::
106 |
107 | 000000.000 Q-RX flushInput
108 | 000002.469 RTS inactive
109 | 000002.773 RTS active
110 | 000003.001 TX 48 45 4C 4C 4F HELLO
111 | 000003.102 RX 48 45 4C 4C 4F HELLO
112 |
113 | """
114 |
115 | def __init__(self, output, color):
116 | self.start_time = time.time()
117 | self.output = output
118 | self.color = color
119 | self.rx_color = '\x1b[32m'
120 | self.tx_color = '\x1b[31m'
121 | self.control_color = '\x1b[37m'
122 |
123 | def write_line(self, timestamp, label, value, value2=''):
124 | self.output.write('{:010.3f} {:4} {}{}\n'.format(timestamp, label, value, value2))
125 | self.output.flush()
126 |
127 | def rx(self, data):
128 | if self.color:
129 | self.output.write(self.rx_color)
130 | if data:
131 | for offset, row in hexdump(data):
132 | self.write_line(time.time() - self.start_time, 'RX', '{:04X} '.format(offset), row)
133 | else:
134 | self.write_line(time.time() - self.start_time, 'RX', '')
135 |
136 | def tx(self, data):
137 | if self.color:
138 | self.output.write(self.tx_color)
139 | for offset, row in hexdump(data):
140 | self.write_line(time.time() - self.start_time, 'TX', '{:04X} '.format(offset), row)
141 |
142 | def control(self, name, value):
143 | if self.color:
144 | self.output.write(self.control_color)
145 | self.write_line(time.time() - self.start_time, name, value)
146 |
147 |
148 | class Serial(serial.Serial):
149 | """Just inherit the native Serial port implementation and patch the port property."""
150 |
151 | def __init__(self, *args, **kwargs):
152 | super(Serial, self).__init__(*args, **kwargs)
153 | self.formatter = None
154 | self.show_all = False
155 |
156 | @serial.Serial.port.setter
157 | def port(self, value):
158 | if value is not None:
159 | serial.Serial.port.__set__(self, self.from_url(value))
160 |
161 | def from_url(self, url):
162 | """extract host and port from an URL string"""
163 | parts = urlparse.urlsplit(url)
164 | if parts.scheme != 'spy':
165 | raise serial.SerialException('expected a string in the form "spy://port[?option[=value][&option[=value]]]": not starting with spy:// (%r)' % (parts.scheme,))
166 | # process options now, directly altering self
167 | formatter = FormatHexdump
168 | color = False
169 | output = sys.stderr
170 | try:
171 | for option, values in urlparse.parse_qs(parts.query, True).items():
172 | if option == 'file':
173 | output = open(values[0], 'w')
174 | elif option == 'color':
175 | color = True
176 | elif option == 'raw':
177 | formatter = FormatRaw
178 | elif option == 'all':
179 | self.show_all = True
180 | else:
181 | raise ValueError('unknown option: %r' % (option,))
182 | except ValueError as e:
183 | raise serial.SerialException('expected a string in the form "spy://port[?option[=value][&option[=value]]]": %s' % e)
184 | self.formatter = formatter(output, color)
185 | return ''.join([parts.netloc, parts.path])
186 |
187 | def write(self, tx):
188 | self.formatter.tx(tx)
189 | return super(Serial, self).write(tx)
190 |
191 | def read(self, size=1):
192 | rx = super(Serial, self).read(size)
193 | if rx or self.show_all:
194 | self.formatter.rx(rx)
195 | return rx
196 |
197 | @property
198 | def in_waiting(self):
199 | n = super(Serial, self).in_waiting
200 | if self.show_all:
201 | self.formatter.control('Q-RX', 'in_waiting -> {}'.format(n))
202 | return n
203 |
204 | def flush(self):
205 | self.formatter.control('Q-TX', 'flush')
206 | super(Serial, self).flush()
207 |
208 | def reset_input_buffer(self):
209 | self.formatter.control('Q-RX', 'reset_input_buffer')
210 | super(Serial, self).reset_input_buffer()
211 |
212 | def reset_output_buffer(self):
213 | self.formatter.control('Q-TX', 'reset_output_buffer')
214 | super(Serial, self).reset_output_buffer()
215 |
216 | def send_break(self, duration=0.25):
217 | self.formatter.control('BRK', 'send_break {}s'.format(duration))
218 | super(Serial, self).send_break(duration)
219 |
220 | @serial.Serial.break_condition.setter
221 | def break_condition(self, level):
222 | self.formatter.control('BRK', 'active' if level else 'inactive')
223 | serial.Serial.break_condition.__set__(self, level)
224 |
225 | @serial.Serial.rts.setter
226 | def rts(self, level):
227 | self.formatter.control('RTS', 'active' if level else 'inactive')
228 | serial.Serial.rts.__set__(self, level)
229 |
230 | @serial.Serial.dtr.setter
231 | def dtr(self, level):
232 | self.formatter.control('DTR', 'active' if level else 'inactive')
233 | serial.Serial.dtr.__set__(self, level)
234 |
235 | @serial.Serial.cts.getter
236 | def cts(self):
237 | level = super(Serial, self).cts
238 | self.formatter.control('CTS', 'active' if level else 'inactive')
239 | return level
240 |
241 | @serial.Serial.dsr.getter
242 | def dsr(self):
243 | level = super(Serial, self).dsr
244 | self.formatter.control('DSR', 'active' if level else 'inactive')
245 | return level
246 |
247 | @serial.Serial.ri.getter
248 | def ri(self):
249 | level = super(Serial, self).ri
250 | self.formatter.control('RI', 'active' if level else 'inactive')
251 | return level
252 |
253 | @serial.Serial.cd.getter
254 | def cd(self):
255 | level = super(Serial, self).cd
256 | self.formatter.control('CD', 'active' if level else 'inactive')
257 | return level
258 |
259 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
260 | if __name__ == '__main__':
261 | s = Serial(None)
262 | s.port = 'spy:///dev/ttyS0'
263 | print(s)
264 |
--------------------------------------------------------------------------------
/blender_files/serial_mouse5.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/blender_files/serial_mouse5.blend
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.5.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sketchpunk/android3dblendermouse/981570d481fc6e1a289e9c8cee68045971bf0fbc/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------