diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41d8c63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +Calibration Files/** +Data/** +Protocols/** +.gitmodules +*BpodUserPath.txt \ No newline at end of file diff --git a/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1 GERBER.zip b/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1 GERBER.zip deleted file mode 100644 index fe0efbd..0000000 Binary files a/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1 GERBER.zip and /dev/null differ diff --git a/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.brd b/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.brd deleted file mode 100644 index c89198a..0000000 --- a/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.brd +++ /dev/null @@ -1,603 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Bpod port interface -rev 1S -LED -Emitter -Sensor -+ -- -GND -GND -+V - - - - - - - - - - - -IR emitter -current -adjust - - - - -SIG - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - -<b>Bourns Trimmers and Potentiometers</b><p> -Trim pots, potentiometers, poly-fuses and other components by Bourns. -<h4><i>Created by Bob Starr (rtzaudio@mindspring.com)<br> -Updated 01/08/2005</i></h4> - - -1/4" Square Trimmer - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -3 -1 - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - -<b>EAGLE Design Rules</b> -<p> -Die Standard-Design-Rules sind so gewählt, dass sie für -die meisten Anwendungen passen. Sollte ihre Platine -besondere Anforderungen haben, treffen Sie die erforderlichen -Einstellungen hier und speichern die Design Rules unter -einem neuen Namen ab. -<b>EAGLE Design Rules</b> -<p> -The default Design Rules have been set to cover -a wide range of applications. Your particular design -may have different requirements, so please make the -necessary adjustments and save your customized -design rules under a new name. -<b>Seeed Studio EAGLE Design Rules</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.sch b/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.sch deleted file mode 100644 index bc6d2c4..0000000 --- a/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.sch +++ /dev/null @@ -1,2443 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - -thru-hole vertical Female Header -used as an SMD part -(placed horizontally, at board's edge) - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Package for 4UCONN part #19686 *UNPROVEN* - - - - - - - - - - ->Value ->Name - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - ->Name ->VALUE - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -2mm SMD side-entry connector. tDocu layer indicates the actual physical plastic housing. +/- indicate SparkFun standard batteries and wiring. - - - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - -<b>RJ45 Jack</b> -Simple RJ45, 8-pin connection - connector for common Cat5, Cat5e, and Cat6 Ethernet cables. Footprint not yet proven in production. Connector sku is PRT-00643; Breakout PCB sku is BOB-00716. - - - - - - - - - - - - - - - - - - - - - - -<b>Header 6</b> -Standard 6-pin 0.1" header. Use with straight break away headers (SKU : PRT-00116), right angle break away headers (PRT-00553), swiss pins (PRT-00743), machine pins (PRT-00117), and female headers (PRT-00115). Molex polarized connector foot print use with SKU : PRT-08094 with associated crimp pins and housings. - -NOTES ON THE VARIANTS LOCK and LOCK_LONGPADS... -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Header 2</b> -Standard 2-pin 0.1" header. Use with straight break away headers (SKU : PRT-00116), right angle break away headers (PRT-00553), swiss pins (PRT-00743), machine pins (PRT-00117), and female headers (PRT-00115). Molex polarized connector foot print use with SKU : PRT-08233 with associated crimp pins and housings. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Bourns Trimmers and Potentiometers</b><p> -Trim pots, potentiometers, poly-fuses and other components by Bourns. -<h4><i>Created by Bob Starr (rtzaudio@mindspring.com)<br> -Updated 01/08/2005</i></h4> - - -1/4" Square Trimmer - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -3 -1 - - -1/4" Square Trimmer - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -3 -1 - - -1/4" Square Trimmer - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -3 -1 - - -1/4" Square Trimmer - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -3 -1 - - - - - - - - - - - - - - - - ->NAME ->VALUE -1 -3 - - - - - - - -<b>3362 Series</b><p> -1/4" Square Trimmer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - ->Name ->Value - - -<b>RESISTOR</b><p> -chip - - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - - -1/6W Thru-hole Resistor - *UNPROVEN* - - - - - - ->NAME ->VALUE - - - - - - ->NAME ->VALUE - - - - -1/4W Resistor, 0.4" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1/2W Resistor, 0.5" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1W Resistor, 0.6" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -2W Resistor, 0.8" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -<h3>AXIAL-0.3-KIT</h3> - -Commonly used for 1/4W through-hole resistors. 0.3" pitch between holes.<br> -<br> - -<b>Warning:</b> This is the KIT version of the AXIAL-0.3 package. This package has a smaller diameter top stop mask, which doesn't cover the diameter of the pad. This means only the bottom side of the pads' copper will be exposed. You'll only be able to solder to the bottom side. - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - - -This is the "EZ" version of the standard .3" spaced resistor package.<br> -It has a reduced top mask to make it harder to install upside-down. - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - ->Name ->Value - - -<b>CAPACITOR</b><p> -chip - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>Resistor</b> -Basic schematic elements and footprints for 0603, 1206, and PTH resistors. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.zip b/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.zip new file mode 100644 index 0000000..1dffbda Binary files /dev/null and b/CAD/PCB/MouseBoxPortBreakout/MouseBox_PortBreakout_r1.zip differ diff --git a/Functions/Internal Functions/BpodObject.m b/Functions/Internal Functions/BpodObject.m index 997bde8..d982134 100644 --- a/Functions/Internal Functions/BpodObject.m +++ b/Functions/Internal Functions/BpodObject.m @@ -32,6 +32,7 @@ ProtocolSettings Data BpodPath + BpodUserPath % FS MOD SettingsPath DataPath ProtocolPath @@ -117,31 +118,54 @@ obj.HostOS = system_dependent('getos'); obj.BpodPath = BpodPath; - dir_calfiles = dir( fullfile(obj.BpodPath,'Calibration Files') ); - if length(dir_calfiles) == 0, %then Cal Folder didn't exist. - mkdir(fullfile(obj.BpodPath,'Calibration Files')); - obj.CalibrationTables.LiquidCal = []; - obj.CalibrationTables.SoundCal = []; + %% FS MOD + if exist(fullfile(obj.BpodPath,'BpodUserPath.txt'),'file') == 2 + UserFile = fopen(fullfile(obj.BpodPath,'BpodUserPath.txt'),'r'); + BpodUserPath = fscanf(UserFile,'%s'); + fclose(UserFile); else - % Liquid - try - LiquidCalibrationFilePath = fullfile(obj.BpodPath, 'Calibration Files', 'LiquidCalibration.mat'); - load(LiquidCalibrationFilePath); - obj.CalibrationTables.LiquidCal = LiquidCal; - catch - obj.CalibrationTables.LiquidCal = []; - end - % Sound - try - SoundCalibrationFilePath = fullfile(obj.BpodPath, 'Calibration Files', 'SoundCalibration.mat'); - load(SoundCalibrationFilePath); - obj.CalibrationTables.SoundCal = SoundCal; - catch - obj.CalibrationTables.SoundCal = []; + if ispc + import java.lang.*; + BpodUserPath = fullfile(char(System.getProperty('user.home')), 'BpodUser'); + else + BpodUserPath = fullfile('~', 'BpodUser'); end + UserFile = fopen(fullfile(obj.BpodPath,'BpodUserPath.txt'),'w'); + fprintf(UserFile,'%s',BpodUserPath); + fclose(UserFile); + end + obj.BpodUserPath = BpodUserPath; + if ~isdir(obj.BpodUserPath) + mkdir(obj.BpodUserPath); + warning(['Bpod user directory not found. Directory created at ' obj.BpodUserPath]); + end + %setting up costum folders + if ~isdir(fullfile(obj.BpodUserPath,'Calibration Files')) %then Cal Folder didn't exist. + copyfile(fullfile(obj.BpodPath, 'Calibration Files'),fullfile(obj.BpodUserPath,'Calibration Files')); % FS MOD end + if ~isdir(fullfile(obj.BpodUserPath,'Settings Files')) + copyfile(fullfile(obj.BpodPath, 'Settings Files'), fullfile(obj.BpodUserPath, 'Settings Files')); + end + + % Liquid + try + LiquidCalibrationFilePath = fullfile(obj.BpodUserPath, 'Calibration Files', 'LiquidCalibration.mat'); % FS MOD + load(LiquidCalibrationFilePath); + obj.CalibrationTables.LiquidCal = LiquidCal; + catch + obj.CalibrationTables.LiquidCal = []; + end + % Sound + try + SoundCalibrationFilePath = fullfile(obj.BpodUserPath, 'Calibration Files', 'SoundCalibration.mat'); % FS MOD + load(SoundCalibrationFilePath); + obj.CalibrationTables.SoundCal = SoundCal; + catch + obj.CalibrationTables.SoundCal = []; + end + % Load input channel settings - obj.InputConfigPath = fullfile(obj.BpodPath, 'Settings Files', 'BpodInputConfig.mat'); + obj.InputConfigPath = fullfile(obj.BpodUserPath, 'Settings Files', 'BpodInputConfig.mat'); % FS MOD load(obj.InputConfigPath); obj.InputsEnabled = BpodInputConfig; @@ -155,9 +179,9 @@ obj.UsesPsychToolbox = 0; end %Check for Data folder - dir_data = dir(fullfile(obj.BpodPath,'Data')); + dir_data = dir(fullfile(obj.BpodUserPath,'Data')); % FS MOD if length(dir_data) == 0, %then Data didn't exist. - mkdir(fullfile(obj.BpodPath, 'Data')); + mkdir(fullfile(obj.BpodUserPath, 'Data')); end end function obj = InitializeHardware(obj, portString) @@ -425,7 +449,12 @@ set(obj.GUIHandles.MainFig,'handlevisibility','off'); % Load protocols into selector - ProtocolPath = fullfile(obj.BpodPath,'Protocols'); + %% FS MOD + ProtocolPath = fullfile(obj.BpodUserPath,'Protocols'); + if ~isdir(ProtocolPath) + mkdir(ProtocolPath) + end +%% Candidates = dir(ProtocolPath); ProtocolNames = cell(1); nCandidates = length(Candidates)-2; diff --git a/Functions/Internal Functions/SaveBpodSystemSettings.m b/Functions/Internal Functions/SaveBpodSystemSettings.m index 40130f8..55f93a1 100644 --- a/Functions/Internal Functions/SaveBpodSystemSettings.m +++ b/Functions/Internal Functions/SaveBpodSystemSettings.m @@ -1,4 +1,4 @@ function SaveBpodSystemSettings global BpodSystem BpodSystemSettings = BpodSystem.SystemSettings; -save(fullfile(BpodSystem.BpodPath, 'Settings Files', 'BpodSystemSettings.mat'), 'BpodSystemSettings'); \ No newline at end of file +save(fullfile(BpodSystem.BpodUserPath, 'Settings Files', 'BpodSystemSettings.mat'), 'BpodSystemSettings'); % FS MOD \ No newline at end of file diff --git a/Functions/Launch manager/LaunchManager.m b/Functions/Launch manager/LaunchManager.m index 1239bd8..74a6aba 100644 --- a/Functions/Launch manager/LaunchManager.m +++ b/Functions/Launch manager/LaunchManager.m @@ -91,9 +91,9 @@ function LaunchManager_OpeningFcn(hObject, eventdata, handles, varargin) % Check to see if a folder for this protocol's name exists, and if not, make one % along with default files for the default test subject named "Test Session" -DataPath = fullfile(BpodSystem.BpodPath,'Data',DummySubjectString); +DataPath = fullfile(BpodSystem.BpodUserPath,'Data',DummySubjectString); ProtocolName = BpodSystem.CurrentProtocolName; -ProtocolPath = fullfile(BpodSystem.BpodPath,'Protocols',ProtocolName); +ProtocolPath = fullfile(BpodSystem.BpodUserPath,'Protocols',ProtocolName); SettingsPath = fullfile(DataPath,ProtocolName,'Session Settings'); DefaultSettingsPath = fullfile(ProtocolPath,'SessionSettings.mat'); @@ -113,7 +113,7 @@ function LaunchManager_OpeningFcn(hObject, eventdata, handles, varargin) % Make a list of the names of all subjects who already have a folder for this % protocol. -DataPath = fullfile(BpodSystem.BpodPath,'Data'); +DataPath = fullfile(BpodSystem.BpodUserPath,'Data'); CandidateSubjects = dir(DataPath); SubjectNames = cell(1); nSubjects = 1; @@ -133,7 +133,7 @@ function LaunchManager_OpeningFcn(hObject, eventdata, handles, varargin) end set(handles.listbox1,'String',SubjectNames); -SettingsPath = fullfile(BpodSystem.BpodPath,'Data',DummySubjectString, ProtocolName,'Session Settings'); +SettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',DummySubjectString, ProtocolName,'Session Settings'); Candidates = dir(SettingsPath); nSettingsFiles = 0; SettingsFileNames = cell(1); @@ -211,7 +211,7 @@ function listbox1_Callback(hObject, eventdata, handles) else SelectedName = NameList; end -SettingsPath = fullfile(BpodSystem.BpodPath,'Data',SelectedName,ProtocolName,'Session Settings'); +SettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',SelectedName,ProtocolName,'Session Settings'); Candidates = dir(SettingsPath); nSettingsFiles = 0; SettingsFileNames = cell(1); @@ -268,7 +268,7 @@ function pushbutton1_Callback(hObject, eventdata, handles) if ~isempty(SettingsFileName) && ~isempty(NameList) ProtocolName = BpodSystem.CurrentProtocolName; FormattedDate = [datestr(now, 3) datestr(now, 7) '_' datestr(now, 10)]; - DataFolder = fullfile(BpodSystem.BpodPath,'Data',SubjectName,ProtocolName, 'Session Data'); + DataFolder = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName,ProtocolName, 'Session Data'); Candidates = dir(DataFolder); nSessionsToday = 0; for x = 1:length(Candidates) @@ -278,11 +278,11 @@ function pushbutton1_Callback(hObject, eventdata, handles) end end end - DataPath = fullfile(BpodSystem.BpodPath,'Data',SubjectName,ProtocolName,'Session Data',[SubjectName '_' ProtocolName '_' FormattedDate '_Session' num2str(nSessionsToday+1) '.mat']); - SettingsPath = fullfile(BpodSystem.BpodPath,'Data',SubjectName,ProtocolName, 'Session Settings',[SettingsFileName '.mat']); + DataPath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName,ProtocolName,'Session Data',[SubjectName '_' ProtocolName '_' FormattedDate '_Session' num2str(nSessionsToday+1) '.mat']); + SettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName,ProtocolName, 'Session Settings',[SettingsFileName '.mat']); BpodSystem.DataPath = DataPath; BpodSystem.SettingsPath = SettingsPath; - ProtocolPath = fullfile(BpodSystem.BpodPath,'Protocols',ProtocolName,[ProtocolName '.m']); + ProtocolPath = fullfile(BpodSystem.BpodUserPath,'Protocols',ProtocolName,[ProtocolName '.m']); close(LaunchManager) BpodSystem.Live = 1; BpodSystem.GUIData.ProtocolName = ProtocolName; @@ -331,9 +331,9 @@ function pushbutton2_Callback(hObject, eventdata, handles) % ------------------ NewName = Spaces2Underscores(NewName); % Check to see if subject already exists ProtocolName = BpodSystem.CurrentProtocolName; -Testpath = fullfile(BpodSystem.BpodPath,'Data',NewName); +Testpath = fullfile(BpodSystem.BpodUserPath,'Data',NewName); Testpath2 = fullfile(Testpath,ProtocolName); -ProtocolPath = fullfile(BpodSystem.BpodPath,'Protocols',ProtocolName); +ProtocolPath = fullfile(BpodSystem.BpodUserPath,'Protocols',ProtocolName); NewAnimal = 0; if exist(Testpath) ~= 7 mkdir(Testpath); @@ -397,7 +397,7 @@ function pushbutton3_Callback(hObject, eventdata, handles) catch end if ((OkToDelete == 1) && (~isempty(SelectedName))) - DeletePath = fullfile(BpodSystem.BpodPath,'Data',SelectedName); + DeletePath = fullfile(BpodSystem.BpodUserPath,'Data',SelectedName); rmdir(DeletePath,'s') BpodErrorSound; msgbox([' Entry for ' SelectedName ' deleted!'], 'Modal'); @@ -459,7 +459,7 @@ function pushbutton4_Callback(hObject, eventdata, handles) SubjectName = SubjectNameList{SubjectNameValue}; % Check to see if subject already exists ProtocolName = BpodSystem.CurrentProtocolName; -Testpath = fullfile(BpodSystem.BpodPath,'Data',SubjectName,ProtocolName,'Session Settings',[NewSettingsName '.mat' ]); +Testpath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName,ProtocolName,'Session Settings',[NewSettingsName '.mat' ]); if exist(Testpath) == 0 SettingsPath = Testpath; ProtocolSettings = struct; @@ -502,13 +502,13 @@ function pushbutton5_Callback(hObject, eventdata, handles) Selected = get(handles.listbox2, 'Value'); SettingsFileName = NameList{Selected}; ProtocolName = BpodSystem.CurrentProtocolName; -SettingsPath = fullfile(BpodSystem.BpodPath,'Data',SubjectName,ProtocolName,'Session Settings',[ SettingsFileName '.mat']); +SettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName,ProtocolName,'Session Settings',[ SettingsFileName '.mat']); delete(SettingsPath); BpodErrorSound; msgbox(['Settings file ' SettingsFileName ' deleted!'], 'Modal'); set(handles.listbox2, 'Value', 1); % Update UI with new settings -SettingsPath = fullfile(BpodSystem.BpodPath,'Data',SubjectName, ProtocolName,'Session Settings'); +SettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName, ProtocolName,'Session Settings'); Candidates = dir(SettingsPath); nSettingsFiles = 0; SettingsFileNames = cell(1); @@ -549,7 +549,7 @@ function pushbutton6_Callback(hObject, eventdata, handles) Selected = get(handles.listbox2, 'Value'); SettingsFileName = NameList{Selected}; ProtocolName = BpodSystem.CurrentProtocolName; -SettingsPath = fullfile(BpodSystem.BpodPath,'Data',SubjectName,ProtocolName,'Session Settings',[ SettingsFileName '.mat']); +SettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName,ProtocolName,'Session Settings',[ SettingsFileName '.mat']); BpodSystem.SettingsPath = SettingsPath; evalin('base', ['load(''' SettingsPath ''')']) clc @@ -567,7 +567,7 @@ function pushbutton7_Callback(hObject, eventdata, handles) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) global BpodSystem; -SearchStartPath = fullfile(BpodSystem.BpodPath, 'Data'); +SearchStartPath = fullfile(BpodSystem.BpodUserPath, 'Data'); [Filename Pathname Junk] = uigetfile('*.mat', 'Select settings to import', SearchStartPath); SettingsName = Filename(1:(length(Filename)-4)); TargetSettingsPath = [Pathname Filename]; @@ -582,7 +582,7 @@ function pushbutton7_Callback(hObject, eventdata, handles) Selected = get(handles.listbox1, 'Value'); SubjectName = NameList{Selected}; ProtocolName = BpodSystem.CurrentProtocolName; -DestinationSettingsPath = fullfile(BpodSystem.BpodPath,'Data',SubjectName,ProtocolName,'Session Settings',[ SettingsName '.mat']); +DestinationSettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName,ProtocolName,'Session Settings',[ SettingsName '.mat']); if (exist(DestinationSettingsPath) == 2) msgbox(['"' SettingsName '"' ' already exists in the target folder. Import aborted.']) @@ -593,7 +593,7 @@ function pushbutton7_Callback(hObject, eventdata, handles) copyfile(TargetSettingsPath, DestinationSettingsPath); % Update UI with new settings -SettingsPath = fullfile(BpodSystem.BpodPath,'Data',SubjectName, ProtocolName,'Session Settings'); +SettingsPath = fullfile(BpodSystem.BpodUserPath,'Data',SubjectName, ProtocolName,'Session Settings'); Candidates = dir(SettingsPath); nSettingsFiles = 0; SettingsFileNames = cell(1); diff --git a/Functions/Launch manager/RunProtocol.m b/Functions/Launch manager/RunProtocol.m index 6f5a2ef..3aa370e 100644 --- a/Functions/Launch manager/RunProtocol.m +++ b/Functions/Launch manager/RunProtocol.m @@ -27,7 +27,7 @@ function RunProtocol(Opstring) SelectedProtocol = get(BpodSystem.GUIHandles.ProtocolSelector, 'Value'); SelectedProtocolName = ProtocolNames{SelectedProtocol}; BpodSystem.CurrentProtocolName = SelectedProtocolName; - addpath(fullfile(BpodSystem.BpodPath, 'Protocols', SelectedProtocolName)); + addpath(fullfile(BpodSystem.BpodUserPath, 'Protocols', SelectedProtocolName)); LaunchManager; else if BpodSystem.Pause == 0 @@ -41,11 +41,17 @@ function RunProtocol(Opstring) end end case 'Stop' + %execute user kill script + try + [~,Protocol]=fileparts(fileparts(fileparts(BpodSystem.DataPath))); + run(fullfile(BpodSystem.BpodUserPath,'Protocols',Protocol,'UserKillScript.m')); + catch + end if ~isempty(BpodSystem.CurrentProtocolName) disp(' ') disp([BpodSystem.CurrentProtocolName ' ended.']) end - rmpath(fullfile(BpodSystem.BpodPath, 'Protocols', BpodSystem.CurrentProtocolName)); + rmpath(fullfile(BpodSystem.BpodUserPath, 'Protocols', BpodSystem.CurrentProtocolName)); BpodSystem.BeingUsed = 0; BpodSystem.CurrentProtocolName = ''; BpodSystem.SettingsPath = ''; diff --git a/Functions/Launch manager/SaveBpodProtocolSettings.m b/Functions/Launch manager/SaveBpodProtocolSettings.m index 33a477d..fe6cd26 100644 --- a/Functions/Launch manager/SaveBpodProtocolSettings.m +++ b/Functions/Launch manager/SaveBpodProtocolSettings.m @@ -19,4 +19,8 @@ %} function SaveBpodProtocolSettings global BpodSystem -save(BpodSystem.SettingsPath, 'BpodSystem.ProtocolSettings'); \ No newline at end of file + +% now compatible with recent matlab versions in which you can't save a +% structure field directly (FS MOD) +ProtocolSettings = BpodSystem.ProtocolSettings; +save(BpodSystem.SettingsPath, 'ProtocolSettings'); \ No newline at end of file diff --git a/Functions/LiquidCalibrator/BpodLiquidCalibration.m b/Functions/LiquidCalibrator/BpodLiquidCalibration.m index a0294d1..f21f933 100644 --- a/Functions/LiquidCalibrator/BpodLiquidCalibration.m +++ b/Functions/LiquidCalibrator/BpodLiquidCalibration.m @@ -40,7 +40,7 @@ % Setup calibration BpodSystem.PluginObjects.LiquidCal.PendingMeasurements = cell(1,8); - CalibrationFilePath = fullfile(BpodSystem.BpodPath, 'Calibration Files', 'LiquidCalibration.mat'); + CalibrationFilePath = fullfile(BpodSystem.BpodUserPath, 'Calibration Files', 'LiquidCalibration.mat'); if exist(CalibrationFilePath) == 2 load(CalibrationFilePath); else @@ -329,11 +329,11 @@ function RemoveMeasurement(varargin) BpodSystem.PluginObjects.LiquidCal.CalData(CurrentValve).Coeffs = []; end % Save file - TestSavePath = fullfile(BpodSystem.BpodPath, 'Calibration Files'); + TestSavePath = fullfile(BpodSystem.BpodUserPath, 'Calibration Files'); if exist(TestSavePath) ~= 7 mkdir(TestSavePath); end - SavePath = fullfile(BpodSystem.BpodPath, 'Calibration Files', 'LiquidCalibration.mat'); + SavePath = fullfile(BpodSystem.BpodUserPath, 'Calibration Files', 'LiquidCalibration.mat'); LiquidCal = BpodSystem.PluginObjects.LiquidCal.CalData; LiquidCal(1).LastDateModified = now; save(SavePath, 'LiquidCal'); @@ -696,11 +696,11 @@ function AddCalMeasurements(varargin) % LiquidCalibrationManager to reflect the new pending measurements vector % Save file - TestSavePath = fullfile(BpodSystem.BpodPath, 'Calibration Files'); + TestSavePath = fullfile(BpodSystem.BpodUserPath, 'Calibration Files'); if exist(TestSavePath) ~= 7 mkdir(TestSavePath); end - SavePath = fullfile(BpodSystem.BpodPath, 'Calibration Files', 'LiquidCalibration.mat'); + SavePath = fullfile(BpodSystem.BpodUserPath, 'Calibration Files', 'LiquidCalibration.mat'); LiquidCal = BpodSystem.PluginObjects.LiquidCal.CalData; LiquidCal(1).LastDateModified = now; save(SavePath, 'LiquidCal'); diff --git a/Functions/Plugins/ParameterGUI/BpodParameterGUI.m b/Functions/Plugins/ParameterGUI/BpodParameterGUI.m index c36081b..2724d41 100644 --- a/Functions/Plugins/ParameterGUI/BpodParameterGUI.m +++ b/Functions/Plugins/ParameterGUI/BpodParameterGUI.m @@ -18,7 +18,7 @@ along with this program. If not, see . %} -function varargout = ParameterGUI(varargin) +function varargout = BpodParameterGUI(varargin) % EnhancedParameterGUI('init', ParamStruct) - initializes a GUI with edit boxes for every field in subfield ParamStruct.GUI % EnhancedParameterGUI('sync', ParamStruct) - updates the GUI with fields of @@ -39,7 +39,7 @@ BpodSystem.GUIData.ParameterGUI.ParamNames = cell(1,nParams); BpodSystem.GUIData.ParameterGUI.nParams = nParams; BpodSystem.GUIHandles.ParameterGUI.Labels = zeros(1,nParams); - BpodSystem.GUIHandles.ParameterGUI.Params = zeros(1,nParams); + BpodSystem.GUIHandles.ParameterGUI.Params = cell(1,nParams); BpodSystem.GUIData.ParameterGUI.LastParamValues = cell(1,nParams); if isfield(Params, 'GUIMeta') Meta = Params.GUIMeta; @@ -49,106 +49,164 @@ if isfield(Params, 'GUIPanels') Panels = Params.GUIPanels; PanelNames = fieldnames(Panels); - nPanels = length(PanelNames); else Panels = struct; Panels.Parameters = ParamNames; PanelNames = {'Parameters'}; - nPanels = 1; end + if isfield(Params, 'GUITabs') + Tabs = Params.GUITabs; + else + Tabs = struct; + Tabs.Parameters = PanelNames; + end + TabNames = fieldnames(Tabs); + nTabs = length(TabNames); + Params = Params.GUI; PanelNames = PanelNames(end:-1:1); GUIHeight = 650; - VPos = 10; - HPos = 10; MaxVPos = 0; - BpodSystem.ProtocolFigures.ParameterGUI = figure('Position', [50 50 450 GUIHeight],'name','Parameter GUI','numbertitle','off', 'MenuBar', 'none', 'Resize', 'on'); + MaxHPos = 0; ParamNum = 1; - for p = 1:nPanels - ThisPanelParamNames = Panels.(PanelNames{p}); - ThisPanelParamNames = ThisPanelParamNames(end:-1:1); - nParams = length(ThisPanelParamNames); - ThisPanelHeight = (45*nParams)+5; - uipanel('title', PanelNames{p},'FontSize',12, 'FontWeight', 'Bold', 'BackgroundColor','white','Units','Pixels', 'Position',[HPos VPos 430 ThisPanelHeight]); - InPanelPos = 10; - for i = 1:nParams - ThisParamName = ThisPanelParamNames{i}; - ThisParam = Params.(ThisParamName); - BpodSystem.GUIData.ParameterGUI.ParamNames{ParamNum} = ThisParamName; - if ischar(ThisParam) - BpodSystem.GUIData.ParameterGUI.LastParamValues{ParamNum} = NaN; - else - BpodSystem.GUIData.ParameterGUI.LastParamValues{ParamNum} = ThisParam; - end - if isfield(Meta, ThisParamName) - if isstruct(Meta.(ThisParamName)) - if isfield(Meta.(ThisParamName), 'Style') - ThisParamStyle = Meta.(ThisParamName).Style; - if isfield(Meta.(ThisParamName), 'String') - ThisParamString = Meta.(ThisParamName).String; + BpodSystem.ProtocolFigures.ParameterGUI = figure('Position', [50 50 450 GUIHeight],'name','Parameter GUI','numbertitle','off', 'MenuBar', 'none', 'Resize', 'on'); + BpodSystem.GUIHandles.ParameterGUI.Tabs.TabGroup = uitabgroup(BpodSystem.ProtocolFigures.ParameterGUI); + [~, SettingsFile] = fileparts(BpodSystem.SettingsPath); + SettingsMenu = uimenu(BpodSystem.ProtocolFigures.ParameterGUI,'Label',['Settings: ',SettingsFile,'.']); + uimenu(BpodSystem.ProtocolFigures.ParameterGUI,'Label',['Protocol: ', BpodSystem.CurrentProtocolName,'.']); + [subpath1, ~] = fileparts(BpodSystem.DataPath); [subpath2, ~] = fileparts(subpath1); [subpath3, ~] = fileparts(subpath2); + [~, subject] = fileparts(subpath3); + uimenu(BpodSystem.ProtocolFigures.ParameterGUI,'Label',['Subject: ', subject,'.']); + uimenu(SettingsMenu,'Label','Save','Callback',{@SettingsMenuSave_Callback}); + uimenu(SettingsMenu,'Label','Save as...','Callback',{@SettingsMenuSaveAs_Callback,SettingsMenu}); + for t = 1:nTabs + VPos = 10; + HPos = 10; + ThisTabPanelNames = Tabs.(TabNames{t}); + nPanels = length(ThisTabPanelNames); + BpodSystem.GUIHandles.ParameterGUI.Tabs.(TabNames{t}) = uitab('title', TabNames{t}); + htab = BpodSystem.GUIHandles.ParameterGUI.Tabs.(TabNames{t}); + for p = 1:nPanels + ThisPanelParamNames = Panels.(ThisTabPanelNames{p}); + ThisPanelParamNames = ThisPanelParamNames(end:-1:1); + nParams = length(ThisPanelParamNames); + ThisPanelHeight = (45*nParams)+5; + BpodSystem.GUIHandles.ParameterGUI.Panels.(ThisTabPanelNames{p}) = uipanel(htab,'title', ThisTabPanelNames{p},'FontSize',12, 'FontWeight', 'Bold', 'BackgroundColor','white','Units','Pixels', 'Position',[HPos VPos 430 ThisPanelHeight]); + InPanelPos = 10; + for i = 1:nParams + ThisParamName = ThisPanelParamNames{i}; + ThisParam = Params.(ThisParamName); + BpodSystem.GUIData.ParameterGUI.ParamNames{ParamNum} = ThisParamName; + if ischar(ThisParam) + BpodSystem.GUIData.ParameterGUI.LastParamValues{ParamNum} = NaN; + else + BpodSystem.GUIData.ParameterGUI.LastParamValues{ParamNum} = ThisParam; + end + if isfield(Meta, ThisParamName) + if isstruct(Meta.(ThisParamName)) + if isfield(Meta.(ThisParamName), 'Style') + ThisParamStyle = Meta.(ThisParamName).Style; + if isfield(Meta.(ThisParamName), 'String') + ThisParamString = Meta.(ThisParamName).String; + else + ThisParamString = ''; + end else - ThisParamString = ''; + error(['Style not specified for parameter ' ThisParamName '.']) end else - error(['Style not specified for parameter ' ThisParamName '.']) + error(['GUIMeta entry for ' ThisParamName ' must be a struct.']) end else - error(['GUIMeta entry for ' ThisParamName ' must be a struct.']) + ThisParamStyle = 'edit'; + ThisParamValue = NaN; end - else - ThisParamStyle = 'edit'; - ThisParamValue = NaN; - end - BpodSystem.GUIHandles.ParameterGUI.Labels(ParamNum) = uicontrol('Style', 'text', 'String', ThisParamName, 'Position', [HPos+5 VPos+InPanelPos 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); - switch lower(ThisParamStyle) - case 'edit' - BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 1; - BpodSystem.GUIHandles.ParameterGUI.Params(ParamNum) = uicontrol('Style', 'edit', 'String', num2str(ThisParam), 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); - case 'text' - BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 2; - BpodSystem.GUIHandles.ParameterGUI.Params(ParamNum) = uicontrol('Style', 'text', 'String', num2str(ThisParam), 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); - case 'checkbox' - BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 3; - BpodSystem.GUIHandles.ParameterGUI.Params(ParamNum) = uicontrol('Style', 'checkbox', 'Value', ThisParam, 'String', ' (check to activate)', 'Position', [HPos+220 VPos+InPanelPos+4 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); - case 'popupmenu' - BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 4; - BpodSystem.GUIHandles.ParameterGUI.Params(ParamNum) = uicontrol('Style', 'popupmenu', 'String', ThisParamString, 'Value', ThisParam, 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); - otherwise - error('Invalid parameter style specified. Valid parameters are: ''edit'', ''text'', ''checkbox'', ''popupmenu'''); + BpodSystem.GUIHandles.ParameterGUI.Labels(ParamNum) = uicontrol(htab,'Style', 'text', 'String', ThisParamName, 'Position', [HPos+5 VPos+InPanelPos 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); + switch lower(ThisParamStyle) + case 'edit' + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 1; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = uicontrol(htab,'Style', 'edit', 'String', num2str(ThisParam), 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); + case 'edittext' + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 8; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = uicontrol(htab,'Style', 'edit', 'String', ThisParam, 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); + case 'text' + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 2; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = uicontrol(htab,'Style', 'text', 'String', num2str(ThisParam), 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); + case 'checkbox' + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 3; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = uicontrol(htab,'Style', 'checkbox', 'Value', ThisParam, 'String', ' (check to activate)', 'Position', [HPos+220 VPos+InPanelPos+4 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); + case 'popupmenu' + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 4; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = uicontrol(htab,'Style', 'popupmenu', 'String', ThisParamString, 'Value', ThisParam, 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); + case 'togglebutton' % INCOMPLETE + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 5; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = uicontrol(htab,'Style', 'togglebutton', 'String', ThisParamString, 'Value', ThisParam, 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12, 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center'); + case 'pushbutton' + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 6; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = uicontrol(htab,'Style', 'pushbutton', 'String', ThisParamString,... + 'Value', ThisParam, 'Position', [HPos+220 VPos+InPanelPos+2 200 25], 'FontWeight', 'normal', 'FontSize', 12,... + 'BackgroundColor','white', 'FontName', 'Arial','HorizontalAlignment','Center','Callback',Meta.OdorSettings.Callback); + case 'table' + BpodSystem.GUIData.ParameterGUI.Styles(ParamNum) = 7; + columnNames = fieldnames(Params.(ThisParamName)); + if isfield(Meta.(ThisParamName),'ColumnLabel') + columnLabel = Meta.(ThisParamName).ColumnLabel; + else + columnLabel = columnNames; + end + tableData = []; + for iTableCol = 1:numel(columnNames) + tableData = [tableData, Params.(ThisParamName).(columnNames{iTableCol})]; + end +% tableData(:,2) = tableData(:,2)/sum(tableData(:,2)); + htable = uitable(htab,'data',tableData,'columnname',columnLabel,... + 'ColumnEditable',[true true], 'FontSize', 12); + htable.Position([3 4]) = htable.Extent([3 4]); + htable.Position([1 2]) = [HPos+220 VPos+InPanelPos+2]; + BpodSystem.GUIHandles.ParameterGUI.Params{ParamNum} = htable; + ThisPanelHeight = ThisPanelHeight + (htable.Position(4)-25); + BpodSystem.GUIHandles.ParameterGUI.Panels.(ThisTabPanelNames{p}).Position(4) = ThisPanelHeight; + BpodSystem.GUIData.ParameterGUI.LastParamValues{ParamNum} = htable.Data; + otherwise + error('Invalid parameter style specified. Valid parameters are: ''edit'', ''text'', ''checkbox'', ''popupmenu'', ''togglebutton'', ''pushbutton'''); + end + InPanelPos = InPanelPos + 35; + ParamNum = ParamNum + 1; end - InPanelPos = InPanelPos + 35; - ParamNum = ParamNum + 1; - end - % Check next panel to see if it will fit, otherwise start new column - Wrap = 0; - if p < nPanels - NextPanelParams = Panels.(PanelNames{p+1}); - NextPanelSize = (length(NextPanelParams)*45) + 5; - if VPos + NextPanelSize > GUIHeight - Wrap = 1; + % Check next panel to see if it will fit, otherwise start new column + Wrap = 0; + if p < nPanels + NextPanelParams = Panels.(ThisTabPanelNames{p+1}); + NextPanelSize = (length(NextPanelParams)*45) + 5; + if VPos + ThisPanelHeight + 45 + NextPanelSize > GUIHeight + Wrap = 1; + end end - end - VPos = VPos + ThisPanelHeight + 10; - if Wrap - HPos = HPos + 450; - if VPos > MaxVPos - MaxVPos = VPos; + VPos = VPos + ThisPanelHeight + 10; + if Wrap + HPos = HPos + 450; + if VPos > MaxVPos + MaxVPos = VPos; + end + VPos = 10; + else + if VPos > MaxVPos + MaxVPos = VPos; + end end - VPos = 10; - else - if VPos > MaxVPos - MaxVPos = VPos; + if HPos > MaxHPos + MaxHPos = HPos; end - end - end - set(BpodSystem.ProtocolFigures.ParameterGUI, 'Position', [50 50 HPos+450 MaxVPos+10]); + set(BpodSystem.ProtocolFigures.ParameterGUI, 'Position', [50 50 MaxHPos+450 MaxVPos+45]); + end + end case 'sync' ParamNames = BpodSystem.GUIData.ParameterGUI.ParamNames; nParams = BpodSystem.GUIData.ParameterGUI.nParams; for p = 1:nParams ThisParamName = ParamNames{p}; ThisParamStyle = BpodSystem.GUIData.ParameterGUI.Styles(p); - ThisParamHandle = BpodSystem.GUIHandles.ParameterGUI.Params(p); + ThisParamHandle = BpodSystem.GUIHandles.ParameterGUI.Params{p}; ThisParamLastValue = BpodSystem.GUIData.ParameterGUI.LastParamValues{p}; switch ThisParamStyle case 1 % Edit @@ -158,6 +216,13 @@ elseif Params.GUI.(ThisParamName) ~= ThisParamLastValue set(ThisParamHandle, 'String', num2str(GUIParam)); end + case 8 % Edit Text + GUIParam = get(ThisParamHandle, 'String'); + if ~strcmpi(GUIParam, ThisParamLastValue) + Params.GUI.(ThisParamName) = GUIParam; + elseif ~strcmpi(Params.GUI.(ThisParamName), ThisParamLastValue) + set(ThisParamHandle, 'String', GUIParam); + end case 2 % Text GUIParam = Params.GUI.(ThisParamName); Text = GUIParam; @@ -179,10 +244,85 @@ elseif Params.GUI.(ThisParamName) ~= ThisParamLastValue set(ThisParamHandle, 'Value', GUIParam); end + case 6 %Pushbutton + GUIParam = get(ThisParamHandle, 'Value'); + if GUIParam ~= ThisParamLastValue + Params.GUI.(ThisParamName) = GUIParam; + elseif Params.GUI.(ThisParamName) ~= ThisParamLastValue + set(ThisParamHandle, 'Value', GUIParam); + end + case 7 %Table + GUIParam = ThisParamHandle.Data; + columnNames = fieldnames(Params.GUI.(ThisParamName)); + argData = []; + for iColumn = 1:numel(columnNames) + argData = [argData, Params.GUI.(ThisParamName).(columnNames{iColumn})]; + end + if any(GUIParam(:) ~= ThisParamLastValue(:)) % Change originated in the GUI propagates to TaskParameters + for iColumn = 1:numel(columnNames) + Params.GUI.(ThisParamName).(columnNames{iColumn}) = GUIParam(:,iColumn); + end + elseif any(argData(:) ~= ThisParamLastValue(:)) % Change originated in TaskParameters propagates to the GUI + ThisParamHandle.Data = argData; + end end BpodSystem.GUIData.ParameterGUI.LastParamValues{p} = GUIParam; end + case 'get' + ParamNames = BpodSystem.GUIData.ParameterGUI.ParamNames; + nParams = BpodSystem.GUIData.ParameterGUI.nParams; + for p = 1:nParams + ThisParamName = ParamNames{p}; + ThisParamStyle = BpodSystem.GUIData.ParameterGUI.Styles(p); + ThisParamHandle = BpodSystem.GUIHandles.ParameterGUI.Params{p}; + switch ThisParamStyle + case 1 % Edit + GUIParam = str2double(get(ThisParamHandle, 'String')); + Params.GUI.(ThisParamName) = GUIParam; + case 8 % Edit Text + GUIParam = get(ThisParamHandle, 'String'); + Params.GUI.(ThisParamName) = GUIParam; + case 2 % Text + GUIParam = get(ThisParamHandle, 'String'); + GUIParam = str2double(GUIParam); + Params.GUI.(ThisParamName) = GUIParam; + case 3 % Checkbox + GUIParam = get(ThisParamHandle, 'Value'); + Params.GUI.(ThisParamName) = GUIParam; + case 4 % Popupmenu + GUIParam = get(ThisParamHandle, 'Value'); + Params.GUI.(ThisParamName) = GUIParam; + case 6 % Pushbutton + GUIParam = get(ThisParamHandle, 'Value'); + Params.GUI.(ThisParamName) = GUIParam; + case 7 % Table + GUIParam = ThisParamHandle.Data; + columnNames = fieldnames(Params.GUI.(ThisParamName)); + for iColumn = 1:numel(columnNames) + Params.GUI.(ThisParamName).(columnNames{iColumn}) = GUIParam(:,iColumn); + end + end + end otherwise error('ParameterGUI must be called with a valid op code: ''init'' or ''sync'''); end varargout{1} = Params; + +function SettingsMenuSave_Callback(~, ~, ~) +global BpodSystem +global TaskParameters +ProtocolSettings = BpodParameterGUI('get',TaskParameters); +save(BpodSystem.SettingsPath,'ProtocolSettings') + +function SettingsMenuSaveAs_Callback(~, ~, SettingsMenuHandle) +global BpodSystem +global TaskParameters +ProtocolSettings = BpodParameterGUI('get',TaskParameters); +[file,path] = uiputfile('*.mat','Select a Bpod ProtocolSettings file.',BpodSystem.SettingsPath); +if file>0 + save(fullfile(path,file),'ProtocolSettings') + BpodSystem.SettingsPath = fullfile(path,file); + [~,SettingsName] = fileparts(file); + set(SettingsMenuHandle,'Label',['Settings: ',SettingsName,'.']); +end + diff --git a/Functions/Plugins/Pipeline/Pipeline.m b/Functions/Plugins/Pipeline/Pipeline.m index dc89cda..74886cd 100644 --- a/Functions/Plugins/Pipeline/Pipeline.m +++ b/Functions/Plugins/Pipeline/Pipeline.m @@ -61,7 +61,7 @@ catch end FormattedDate = [datestr(now, 3) datestr(now, 7) '_' datestr(now, 10)]; - DataFolder = fullfile(BpodSystem.BpodPath,'Data',currentAnimalName,BpodSystem.CurrentProtocolName, 'Session Data'); + DataFolder = fullfile(BpodSystem.BpodUserPath,'Data',currentAnimalName,BpodSystem.CurrentProtocolName, 'Session Data'); Candidates = dir(DataFolder); nSessionsToday = 0; for x = 1:length(Candidates) @@ -71,7 +71,7 @@ end end end - DataPath = fullfile(BpodSystem.BpodPath,'Data',currentAnimalName,BpodSystem.CurrentProtocolName,'Session Data',[BpodSystem.GUIData.SubjectName '_' BpodSystem.CurrentProtocolName '_' FormattedDate '_Session' num2str(nSessionsToday+1) '.mat']); + DataPath = fullfile(BpodSystem.BpodUserPath,'Data',currentAnimalName,BpodSystem.CurrentProtocolName,'Session Data',[BpodSystem.GUIData.SubjectName '_' BpodSystem.CurrentProtocolName '_' FormattedDate '_Session' num2str(nSessionsToday+1) '.mat']); BpodSystem.DataPath = DataPath; BpodSystem.Data = struct; BpodSystem.Data.TrialTypes = []; diff --git a/Functions/Plugins/Plots/TrialTypeOutcomePlot.m b/Functions/Plugins/Plots/TrialTypeOutcomePlot.m index f98b64f..729dc15 100644 --- a/Functions/Plugins/Plots/TrialTypeOutcomePlot.m +++ b/Functions/Plugins/Plots/TrialTypeOutcomePlot.m @@ -64,6 +64,9 @@ function TrialTypeOutcomePlot(AxesHandle, Action, varargin) end axes(AxesHandle); MaxTrialType = max(TrialTypeList); + if isnan(MaxTrialType) + MaxTrialType = 1; % for NaN filled TrialTypes, might occur if you determine trial type on the fly + end %plot in specified axes Xdata = 1:nTrialsToShow; Ydata = -TrialTypeList(Xdata); BpodSystem.GUIHandles.FutureTrialLine = line([Xdata,Xdata],[Ydata,Ydata],'LineStyle','none','Marker','o','MarkerEdge','b','MarkerFace','b', 'MarkerSize',6); @@ -84,6 +87,9 @@ function TrialTypeOutcomePlot(AxesHandle, Action, varargin) TrialTypeList = varargin{2}; OutcomeRecord = varargin{3}; MaxTrialType = max(TrialTypeList); + if isnan(MaxTrialType) + MaxTrialType = 1; % for NaN filled TrialTypes, might occur if you determine trial type on the fly + end set(AxesHandle,'YLim',[-MaxTrialType-.5, -.5], 'YTick', -MaxTrialType:1:-1,'YTickLabel', strsplit(num2str(MaxTrialType:-1:-1))); if CurrentTrial<1 CurrentTrial = 1; diff --git a/Functions/Plugins/RechiaOlfactometer/OlfactometerConfig.m b/Functions/Plugins/RechiaOlfactometer/OlfactometerConfig.m index 079621f..737a98d 100644 --- a/Functions/Plugins/RechiaOlfactometer/OlfactometerConfig.m +++ b/Functions/Plugins/RechiaOlfactometer/OlfactometerConfig.m @@ -51,10 +51,13 @@ function OlfactometerConfig_OpeningFcn(hObject, eventdata, handles, varargin) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to OlfactometerConfig (see VARARGIN) +global BpodSystem ha = axes('units','normalized', 'position',[0 0 1 1]); uistack(ha,'bottom'); BG = imread('OlfControlPanel.bmp'); image(BG); axis off; +% FS NOTE: This function not updated to utilize BpodUserPath +% loadBpodPath; if exist(fullfile(BpodPath,'Bpod System Files','OlfConfig.mat')) load OlfConfig diff --git a/Functions/Plugins/RechiaOlfactometer/SetBankFlowRate.m b/Functions/Plugins/RechiaOlfactometer/SetBankFlowRate.m index 8e011e3..fbd027b 100644 --- a/Functions/Plugins/RechiaOlfactometer/SetBankFlowRate.m +++ b/Functions/Plugins/RechiaOlfactometer/SetBankFlowRate.m @@ -1,5 +1,11 @@ function SetBankFlowRate(OlfIP, Bank, FlowRate) -IPString = [num2str(OlfIP(1)) '.' num2str(OlfIP(2)) '.' num2str(OlfIP(3)) '.' num2str(OlfIP(4))]; + +if isnumeric(OlfIP) % in case OlfIP is a number instead of a string + IPString = [num2str(OlfIP(1)) '.' num2str(OlfIP(2)) '.' num2str(OlfIP(3)) '.' num2str(OlfIP(4))]; +else + IPString = OlfIP; +end + try TCPWrite(IPString, 3336, ['WRITE BankFlow' num2str(Bank) '_Actuator ' num2str(FlowRate)]); catch diff --git a/README.md b/README.md index 2d1ca2a..c72b2c5 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ -# Bpod \ No newline at end of file +# Bpod + +Kepecs Lab workspace, forked from Sanworks. + +Used to modify Bpod code for use in Kepecs Lab. +General improvements will be contributed to Sanworks' repo.