Prop Shield Beta Test

Status
Not open for further replies.
Good work Paul - Mine still works! No Issues with IMU unit. Just ran an updated TALKIE sample.

I made PULL request so you can own the non-blocking Talkie edits with sound queue I made.
<edit>: I tested this only against the Prop Shield - but no changes were made that should affect other usage.

I ordered Adafruit APA102's - they'll finally get here Monday . . . UPS shipping ground across country sure is slow - especially when they sit on the order for 2 days - making it Monday to Monday!
 
Last edited:
Success with Raw SerialFlash Hardware Test, but some weird Arduino behavior along the way.

In Arduino 1.6.8/Teensyduino 1.28-beta1, first couple of times I tried to compile, I got a message about the compiler quitting with no error messages. Third time I noticed that compiler output was appearing in another sketch other than the one I was trying to compile and upload.

I quit Arduino and restarted. I closed all the other sketches. Then the test program compiled uploaded and ran.

Code:
Raw SerialFlash Hardware Test


Read Chip Identification:
  JEDEC ID:     EF 40 17
  Part Nummber: W25Q64FV
  Memory Size:  8388608 bytes
  Block Size:   65536 bytes


Reading Chip...


Writing 4096 signatures


Double Checking All Signatures:
  all 4096 signatures read ok


Checking Signature Pairs
  all 2047 signature pairs read ok


Checking Read-While-Write (Program Suspend)
  write 256 bytes at 256
  write time was 443 microseconds.
  read-while-writing: 00 00 00 00 15 F5 95 4B 
  test passed, good read while writing


Checking Read-While-Erase (Erase Suspend)
  erase time was 174105 microseconds.
  erase correctly erased 65536 bytes
  read-while-erasing: 00 00 00 00 15 F5 95 4B 
  test passed, good read while erasing


All Tests Passed  :-)


Test data was written to your chip.  You must run
EraseEverything before using this chip for files.
 
... weird Arduino behavior along the way.

In Arduino 1.6.8/Teensyduino 1.28-beta1, first couple of times I tried to compile, I got a message about the compiler quitting with no error messages. Third time I noticed that compiler output was appearing in another sketch other than the one I was trying to compile and upload.

The IDE has done this as long as I can remember. If you have multiple IDE windows - all compile output registers in the last/current active window. If you change to 'notepad' - output stays on last IDE - but switching to another IDE instance will have the compile output appear only in that 'current' window, not restricted to the one where the compile was initiated.
 
MPL3115A2 Barometer

I tried out the MPL3115A2 barometer on the Prop Shield.
I had success with both the AdaFruit and Sparkfun libraries.

With the Adafruit library, I noticed that there were significant offsets compared to NOAA weather, local altitude and a temperature logger.
I modified the library to output Raw, Tared and Offset data.
Here is a plot of the data with Tare and Offset applied.
Note that at 11 minutes I moved it to the ceiling and then the floor a delta of about 8 ft.
Then at 14 minutes I placed it on top of a warm power supply, then near a muffin fan.
I notice that there are transients in the pressure and altitude as the temperature changes.
I've seen the same phenomenon with the Bosch BMP280 barometer sensor.

Here's the plot:
MPL3115A2_Plot.jpg

And here's the modified Adafruit library code:
Code:
/**************************************************************************/
/*!
    @file     Adafruit_MPL3115A2.cpp
    @author   K.Townsend (Adafruit Industries)
    @license  BSD (see license.txt)

    Example for the MPL3115A2 barometric pressure sensor

    This is a library for the Adafruit MPL3115A2 breakout
    ----> https://www.adafruit.com/products/1893

    Adafruit invests time and resources providing this open source code,
    please support Adafruit and open-source hardware by purchasing
    products from Adafruit!

    @section  HISTORY

    v1.0 - First release
*/
/**************************************************************************/
/****************Modified by R. Wozniak Mar-26-2016************************/

#include <Wire.h>
#include <Adafruit_MPL3115A2.h>

Adafruit_MPL3115A2 baro = Adafruit_MPL3115A2();


  float startTime;
  float acqTime;
  float startPressure;                    // For Tare Values
  float startAltitude;                    // For Tare Values
  float startTemperature;                 // For Tare Values
  float offsetPressureCorr = 102600.00;   // Local Barometric Pressure at startup for correction (Pa) // 100mb = 1Pa,   3377in Hg = 1Pa
  float offsetAltitudeCorr = 63.01;       // Local Altitude at startup for correction (m) 
  float offsetTemperatureCorr = 25.22;    // Local Temperature at startup for correction (Deg C)
  float rawPressure;
  float rawAltitude;
  float rawTemp;

void setup() {
  Serial.begin(9600);
  while (!Serial) ; // wait for serial port open
  Serial.println("Adafruit_MPL3115A2 test!");
  Startup();
}

void loop() {

  acqTime=millis();
  rawPressure = baro.getPressure();
  rawAltitude = baro.getAltitude();
  rawTemp = baro.getTemperature();
  
  printRaw();
  printTare();
  printCorrected();
  delay(100);
}

void Startup()
{
    if (! baro.begin()) {
    Serial.println("Couldnt find sensor");
    return;
    }

  Serial.print("Recording Tare Values... Please wait 1 minute");
  
  baro.getPressure();  //First is reading always wrong
  for (int i=0; i <= 9; i++){ 
  startPressure += baro.getPressure();
  startAltitude += baro.getAltitude();
  startTemperature += baro.getTemperature();
  Serial.print(".");
  }
  startPressure = startPressure/10.0;
  startAltitude = startAltitude/10.0;
  startTemperature = startTemperature/10.0;
  
  Serial.println();
  Serial.print("Startup Tare Values Pressure (Pa), Altitude (m), Temperature (deg C):");
  Serial.print(startPressure,3);
  Serial.print(", ");
  Serial.print(startAltitude,3);
  Serial.print(", ");
  Serial.print(startTemperature,3);
  Serial.println();
  startTime=millis();
}

void printRaw(){

  Serial.println(); Serial.println("Raw MPL3115A3 Values:  Time(Sec), Pressure(Pa), Altitude(m), Temperature(deg C)");
 
  Serial.print((acqTime-startTime)/1000.0f,3);
  Serial.print(", ");

  Serial.print(rawPressure); Serial.print(", ");               // Raw Pressure in Pascals
  //Serial.print(rawPressure/3377,3); Serial.print(", ");      // Raw Pressure in inHG
  //Serial.print(rawPressure/100); Serial.print(", ");         // Raw Pressure in milliBar

  Serial.print(rawAltitude,3);  Serial.print(", ");            // Raw Altitude in meters
  //Serial.print(rawAltitude*3.28084,3);  Serial.print(", ");  // Raw Altitude in ft

  Serial.print(((rawTemp)),3);  Serial.print(", ");            // RawTemperature in Deg C
  //Serial.print(((rawTemp*9/5)),3);                           // Raw Temperature in Deg F
  Serial.println();  
}

void printTare(){

  Serial.println(); Serial.println("Tare Offset Values:  Time(Sec), Pressure(mb), Altitude(ft), Temperature(deg F)");
 
  Serial.print((acqTime-startTime)/1000.0f,3);
  Serial.print(", ");

   float pressure = rawPressure - startPressure;
  //Serial.print(pressure); Serial.print(", ");           // Tare Offset Pressure in Pascals
  //Serial.print(pressure/3377,3); Serial.print(", ");    // Tare Offset Pressure in Pascals Pressure in inHG
  Serial.print(pressure/100); Serial.print(", ");         // Tare Offset Pressure in Pascals Pressure in milliBar

  float altitude = rawAltitude - startAltitude;
  //Serial.print(altitude,3);  Serial.print(", ");        // Tare Offset Altitude in meters
  Serial.print(altitude*3.28084,3);  Serial.print(", ");  // Tare Offset Altitude in ft

  float temp = rawTemp - startTemperature;
  //Serial.print(((temp)),3);  Serial.print(", ");        // Tare Offset Temperature in Deg C
  Serial.print(((temp*9/5)),3);                           // Tare Offset Temperature in Deg F
  Serial.println();  
}

void printCorrected(){

  Serial.println(); Serial.println("Corrected Values:  Time(Sec), Pressure(mb), Altitude(ft), Temperature(deg F)");
 
  Serial.print((acqTime-startTime)/1000.0f,3);
  Serial.print(", ");

   float pressure = (rawPressure - startPressure) + offsetPressureCorr;
  //Serial.print(pressure); Serial.print(", ");            // Corrected Pressure in Pascals
  //Serial.print(pressure/3377,3); Serial.print(", ");     // Corrected Pressure in inHG
  Serial.print(pressure/100); Serial.print(", ");          // Corrected Pressure in milliBar

  float altitude = rawAltitude - startAltitude + offsetAltitudeCorr;
  //Serial.print(altitude,3);  Serial.print(", ");         // Corrected Altitude in meters
  Serial.print(altitude*3.28084,3);  Serial.print(", ");   // Corrected Altitude in ft

  float temp = rawTemp - startTemperature + offsetTemperatureCorr;
  //Serial.print(((temp)),3);  Serial.print(", ");         // Corrected Temperature in Deg C
  Serial.print(((temp*9/5)+32),3);                         // Corrected Temperature in Deg F
  Serial.println();  
}
 
Last edited:
Fixed a little bug..

Nice work Frank!

Windows10 with Prop board ( -w , -l and -r on foo.txt worked! As of course did -? ):
I pulled the code to libraries and a simple file foo.txt that was "dir > foot.txt" and then "dir >> foot.txt" extended the file and then showed and read the larger version!

Then looking for another file I did the 12K ZIP file : "C:\tCode\libraries\TeensyTransfer\extras\teensytransfer>teensytransfer.exe -w ..\teensytransfer.zip"

Filename was accepted - but too long:: teensytransfer.zip :: TeensyTransfer/issues/4
C:\tCode\libraries\TeensyTransfer\extras\teensytransfer>teensytransfer.exe -w ..\teensytransfer.zip

So now I get this with -l ::
C:\tCode\libraries\TeensyTransfer\extras\teensytransfer>teensytransfer.exe -l
874 foo.txt
12612 teensytransfer.zteensytransfer.zteensytransfer.zteensytransfer.

Now of course I cannot erase that file.
I can write other files after it: ..\..\LICENSE and ..\..\README.md

And I can read those files, of course file names are case sensitive.

I even renamed teensytransfer.zip to Ttrans.zip and wrote that and then "teensytransfer.exe -r Ttrans.zip > ttzip.read" gave a usable file of the right size!

<edit>:
> ... so the problem isn't binary files or file type, but length of file name
> Do you take control of the entire FLASH space? Using :: #include <SerialFlash.h>
> With SerialFlash I can share and use this space in other sketches?
> Can you show how much room is left to show on list?
> I had to make this a comment to compile :: // #define _HAVE_EEPROM

> TYQT is HID aware - is there a way I can enter commands from there?
Seremu (open) \\.\HID#VID_16C0&PID_0486&MI_01#9&B0DB20&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}

And to TYQT serialEvent() works:
Code:
void serialEvent() {
  while (Serial.available())
    Serial.write( Serial.read() );
}

From a comment the other day and the code it seems FrankB knew he could Serial.print(). I put in hacks to get ttransfer.transfer( 1 ); to show the output of 'list' with Serial.print(). Not sure of the value/utility of this - but the TeensyTransfer code could be made a subroutine of other code. Odd that serialEvent() works when (!Serial) never goes true - which is why he was looking for a RAW_HID+USB it seems.
 
Last edited:
I had to make this a comment to compile :: // #define _HAVE_EEPROM
Hm we seem to have different versions ?
What is the error you get ?

I fixed the problem with the length of the filename (buffer-overflow). It is now limited to 63 characters.
Do you take control of the entire FLASH space?
Yes, the SerialFlash library does it :)

With SerialFlash I can share and use this space in other sketches?
Yes.


There was a request for a sorted output of -l (list files):
You can use "sort" to sort the output. The Syntax for Windows is:
Code:
Rem Sort Filesizes:
teensytransfer -l | sort

Code:
Rem Sort Filenames
teensytransfer -l | sort /+10

For reversed sorting, add "/r" to the options. For linux, see "sort --help"


Edit: I think there is a little confusion re: Serial/Seremu:

The Teensy Serial Monitor and TyQt both can work with seremu: You can still use "Serial.print()" in your sketches if you use "Raw Hid". But you get no "COM" device.

If you really need a "COM", you can use the included example-sektech to upload your files, and then switch back to usb-mode "Serial".
Or, you could try to edit the Teensy-core, which would give you both simultanously.

I have'nt found time to do it.

Edit: MAC executable is still unchanged (old) + untested.
 
Last edited:
Hi Paul,

I've done a little video review of the Prop Shield to post on youtube; When are the covers coming off - when can I upload the video?

Thanks

Jon
 
Here is a new build of a calibration app. NXPMotionSense recently changed to a new calibration data set & protocol. This is the first calibration app to write the new format.... so make sure you're running the latest on your Teensy.

This version adds much more info to the GUI.

I've tried to fix the problem(s) that were crashing on Mac. Both Windows and Mac still crash when you quit, but the question is whether they're stable while still running?

http://www.pjrc.com/teensy/beta/imuread/gui.linux64

http://www.pjrc.com/teensy/beta/imuread/gui.mac.zip

http://www.pjrc.com/teensy/beta/imuread/gui.exe

Known issues:

1 - crashes on quit
2 - doesn't confirm calibration written (but the protocol now can do it)
3 - poor ability to reduce variance error
4 - missing accelerometer & gyroscope cal
5 - nothing in the left-side panel yet...
 
Hi Paul,

Might help to have more information/instructions.

First attempt failed. Did not notice that calibration program changed names... So was not getting valid data... Updated to new one...

In App need to select appropriate com port.

Now what? I assume move the board around in many different directions, trying to get a sphere shape. But so far with mine, not able to get a good sphere...
Also so far file->Send Calibration is always grayed out.

MotionSensorCalibration.jpg

Edit: Should mention Windows 10 64bit
 
Downloaded newest version (+lib from github, too).

Works good and stable (Win 10 64Bit).

Perhaps add a Message "Close Serial Monitor", if port is not available.
 
Perhaps add a Message "Close Serial Monitor", if port is not available.

I also noticed that on my WIN10 PC the Motion Sensor Calibration Tool does not read the port unless another program has read it first.

It's OK if I remove the line: while (!Serial) ; // wait for serial port open

Here's a screen capture.
MagCal.jpg
No matter how hard I try, I can't get below 5% error with less that 1% gaps.
Too bad you can't manually delete points, as there are always a few strays.

KurtE: Is there a lot of ferrous metal near your work bench?
 
Last edited:
Right now it is on my nice and tidy(not) desk:
But I also wonder if it has to do with that I have the Teensy mounted above it.
I have also had the issues that the program would not do anything, but then maybe run the Arduino monitor, close it, then run...

My Teensy is mounted exactly the same way as yours. (BTW... have we gotten clearance to post photos yet?)
There's probably magnets in that servo and an iron core transformer in that power brick.

Yes, that works... my workaround also is to momentarily run Arduino Serial Monitor after compiling Calibrate Sensors, or repowering the PropShield.
 
I also noticed that on my WIN10 PC the Motion Sensor Calibration Tool does not read the port unless another program has read it first.

I was seeing that on older versions too - had to first hit the Teensy with TYQT then release port and the app would pick up, only I never diagnosed that far. while(!Serial) should be banned. I'm on Win10x64 - will try calibration again.

Frank: your TeensyTransfer has issues I'll (re)open on Github.
You missed the LONGNAME trashing that ISSUE was about? Two files uploaded below are orphaned trash.
C:\tCode\libraries\TeensyTransfer\extras\teensytransfer>TeensyTransfer -l | sort /r
12612 Ttrans.zip
12612 teensytransfer.zteensytransfer.zteensytransfer.zteensytransfer.
1072 LICENSE
874 foo.txt
696 foofoofoofoo.txtfoofoofoofoo.txtfoofoofoofoo.txtfoofoofoofoo.tx
623 README.md

C:\tCode\libraries\TeensyTransfer\TeensyTransfer.cpp: In member function 'void TeensyTransfer::eeprom_read()':
C:\tCode\libraries\TeensyTransfer\TeensyTransfer.cpp:303:19: error: 'eeprom_size' was not declared in this scope
sz = eeprom_size();
 
Has anyone tried the latest (msg #358) on Macintosh? Is it more stable?

So far I've tested only on 10.7.5 (Lion).
I just ran it on El Capitan 10.11.4 and it ran. Was able to save calibration, and it did not show the issue on windows of needing to open up Arduino monitor...

Crashed on exit
 
Yes it's limited to 63 characters. Thats intended - a question of definition if it is trashing..
Of course, i could print an error and defer upload if the filename is longer than 63 Chracters. Would that be better ?

RE: sz = eeprom_size();
hm. somehow an old version is on github..wonder why. i'll update it.
 
Has anyone tried the latest (msg #358) on Macintosh? Is it more stable?

So far I've tested only on 10.7.5 (Lion).

Just tried it with 10.9.5 on my ancient MacBook Pro. The desktop application runs, but I wasn't able to built the Teensy application in the little time I had for giving it a try. I grabbed files from github yesterday, but nothing would compile without moving files around and changing #include <> to #include "". I suppose I need to learn where to put library files.

So far, I've only seen serial output from the motion-related chips and I haven't been able to make sense of it.
 
GUI.exe :: Motion Sense Calibration Tool : Won't Quit/Close/Exit [Win10x64pro] { three times used TaskMan end task }

Looks good, Error was around 1.7 - but filling all the gaps runs it higher. Sends Calibration - no 'on screen' confirmation that it was received - I do see LED pattern.

nxp_cal5.PNG

After this image I just got Gaps 0.0% with 2% Fit Error.

Got it near (3+ inches) my magnetic closure phone case and got the cool 'solar flare' effect - Would it help to detect those events and suggest starting a new calibration session?

I found going to port:NONE and then back was the only way to restart the sample set?
 
Yes it's limited to 63 characters. Thats intended - a question of definition if it is trashing..
Of course, i could print an error and defer upload if the filename is longer than 63 Chracters. Would that be better ?

File is uploaded - The name is only "foofoofoofoo.txt" but LIST shows it as "696 foofoofoofoo.txtfoofoofoofoo.txtfoofoofoofoo.txtfoofoofoofoo.tx"
I did find I can READ and ERASE it with the original name.
{also with "teensytransfer.zip" displayed as "teensytransfer.zteensytransfer.zteensytransfer.zteensytransfer." }

RE: sz = eeprom_size();
hm. somehow an old version is on github..wonder why. i'll update it.
Let me know what might be odd - should I use the TD1.28b1 SerialFlash library? It seems I have a local copy?
<edit>: Removed local SerialFlash - Sketch works the same, but still need to comment out the "//#define _HAVE_EEPROM" in TeensyTransfer.h
 
Last edited:
I tested the new GUI on Win7 pro 64bit. Only issue was that I had to open the arduino serial monitor once to get past
Code:
while (!Serial) ; // wait for serial port open
Selecting the COM port in the GUI didn't help. Since that also stalls the led heartbeat I though my teensy was faulty for a second. Maybe change the heartbeat to interrupt-based or to change waiting for serial to non-blocking?

Lowest fit error I can get is about 4%
 
Maybe a little off the wall, but for the fun of it, I tried hooking up some Neopixels (Adafruit Jewel with 7 Neopixels) to the shield instead of APA102 leds... I used the Data pin (pin 11). Probably means that you can not use the storage with this hookup, but the Neopixel strandtest worked, after I changed pin=11 and added a setmode/digitalWrite for pin 7.

I mucked up a quick update to the heading program earlier to simply set one of the 6 outer Neopixels Red if the heading/60... Appears to work.
Code:
#include <Adafruit_NeoPixel.h>

#include <NXPMotionSense.h>
#include <Wire.h>
#include <EEPROM.h>

#define PIN 11
#define NUM_LEDS 7 //number of leds in strip length on one side


NXPMotionSense imu;
NXPSensorFusion filter;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(7, PIN, NEO_GRB + NEO_KHZ800);
uint16_t loop_count = 0;

void setup() {
  Serial.begin(9600);
  imu.begin();
  filter.begin();
  pinMode(7, OUTPUT);
  digitalWrite(7, HIGH);

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  for (int i=0; i < 4; i++) {
    strip.setPixelColor(0, i*32, 0, 0);
    strip.show();
    delay(250);
  }

}

void loop() {
  float ax, ay, az;
  float gx, gy, gz;
  float mx, my, mz;
  float heading;

  if (imu.available()) {
    // Read the motion sensors
    imu.readMotionSensor(ax, ay, az, gx, gy, gz, mx, my, mz);

    // Update the SensorFusion filter
    filter.update(gx, gy, gz, ax, ay, az, mx, my, mz);
  }

  //   roll = filter.getRoll();
  //   pitch = filter.getPitch();
  heading = filter.getYaw();

//  Serial.println(heading, 3);

  strip.setPixelColor(0, loop_count & 0x1f, (loop_count >> 5) & 0x1f, (loop_count >> 10) & 0x1f);
  loop_count += 4;
  
  for (int x = 1; x < NUM_LEDS; x++) {
    strip.setPixelColor(x, 0, 0, 0);
  }
  int  iHeading = heading / 60 + 1;
  strip.setPixelColor(iHeading, 80, 0, 0);
  strip.show();
}
 
Got it near (3+ inches) my magnetic closure phone case and got the cool 'solar flare' effect - Would it help to detect those events and suggest starting a new calibration session?

I'm going to try some ideas to handle these cases much better. Ideally, when the gaps are under 20%, it should become possible to automatically purge this bad data, and most of the lower quality data causing the variance error. But rejecting bad data is tricky, because you don't know the good from the bad until you have a solid cal. If you start discarding data on non-random criteria, there's risk of an unstable feedback loop where a less than perfect cal causes wrong assumptions and discards good data that would have led to the cal improving. I worry & lose sleep over such things....

Also on my wish list is displaying obviously bad data in a different color, maybe black or gray.

I've also toyed with the idea of displaying new data in a brighter color, maybe even as a light source, and have it slowly "cool" to the normal color as the data ages. The idea would be to more easily see where you're adding new data, so it'd easier to figure out which way you need to turn.

At this moment I'm finalizing the product pages, so more work on the cal app will come in a tomorrow or Tuesday.
 
Prop Shield + APA102 + FastLED

Here's a link to a short video I made of the Prop Shield + Teensy 3.1 + APA102 + FastLED 3.1
Warning there is an audio track.
https://youtu.be/kmaK-zkpmg8
Video.jpg
Built on NXPMotionSense library and also FastLED V3.1 fadeToBlackBy function.
Pitch = Position
Yaw = Hue
Roll = Saturation

All in all it's pretty responsive for a quickie program.

Here is the code:
Code:
#include <NXPMotionSense.h>
#include <Wire.h>
//#include <EEPROM.h>
#include "FastLED.h"
FASTLED_USING_NAMESPACE

NXPMotionSense imu;
NXPSensorFusion filter;

#define DATA_PIN      11
#define CLK_PIN       13
#define LED_TYPE      APA102
#define COLOR_ORDER   BGR
#define NUM_LEDS      144
CRGB leds[NUM_LEDS];
#define BRIGHTNESS    255
#define FRAMES_PER_SECOND  200
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
uint8_t gHue = 20; // rotating "base color" used by many of the patterns
uint8_t gSat = 255;
uint8_t pos = 72;

void setup() {
  imu.begin();
  filter.begin(100);

  pinMode(7, OUTPUT); 
  digitalWrite(7, HIGH);
  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER,DATA_RATE_MHZ(12)>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);
}

void loop() {
  float ax, ay, az;
  float gx, gy, gz;
  float mx, my, mz;
 
  if (imu.available()) {
    // Read the motion sensors
    imu.readMotionSensor(ax, ay, az, gx, gy, gz, mx, my, mz);

    // Update the SensorFusion filter
    filter.update(gx, gy, gz, ax, ay, az, mx, my, mz);

   gHue = abs(2*filter.getYaw()*255/360);
   gSat = 255-abs(filter.getRoll()*255/360);
   pos = abs((filter.getPitch() * NUM_LEDS / 180) - (NUM_LEDS/2)); 
   fadeToBlackBy( leds, NUM_LEDS, 8);
   leds[pos] += CHSV( gHue, gSat, 255);
   FastLED.show();
  }
}
 
Last edited:
Status
Not open for further replies.
Back
Top