├── .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 | 227 | 229 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 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 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | 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 | 8 | 9 | 10 | 11 | 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 | 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://&