Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.

Emilio x64's Content

There have been 39 items by Emilio x64 (Search limited from 08-May 23)


By content type

See this member's


Sort by                Order  

#52532 New: Netduino 4.3 SDK and VS2012 support!

Posted by Emilio x64 on 03 September 2013 - 06:55 PM in General Discussion

That's the firmware that is on the netduino device or the one that one installs aside VS.2013 (SecretLabs*.dll) ?




#52242 New: Netduino 4.3 SDK and VS2012 support!

Posted by Emilio x64 on 20 August 2013 - 04:52 PM in General Discussion

I installed the 4.3 SDK and needed to use the UdpClient. According to the MSDN it is in the System.Ext.Net namespace of mfpwsextensions.dll (something like that) but when I add that reference I don't see that namespace. Can't find UdpClient anywhere.




#52090 New: Netduino 4.3 SDK and VS2012 support!

Posted by Emilio x64 on 11 August 2013 - 03:37 PM in General Discussion

I suppose the current 4.3 fits well in the Netduino Plus 2, right? Is that the lowest platform the 4.3 NETMF fits?




#52290 Socket.Connect blocks all threads?

Posted by Emilio x64 on 22 August 2013 - 06:46 PM in Netduino Plus 2 (and Netduino Plus 1)

Anybody knows whether these issues are really resolved in 4.3?




#52706 Embarassing SPI question (re: Netduino Helper Max72197221.cs )

Posted by Emilio x64 on 11 September 2013 - 05:12 PM in General Discussion

The "Microsoft Extensible Emulator" is part of the Visual Studio IDE AFAIK. But it is great in allowing you to mimick your end device when you still don't have hardware (I have a design but I am testing some concepts).

 

The MAX7219 emulator code I wrote myself because I wanted to see the state of the chip during debugging (just as if I had a real emulator pOD on a real device) but I have to fix it based on your comments (the NoOp). However, it goes only as far as keeping track of the register values, state and notifying the UI to update the UI accordingly. It does not include a real 7-segment emulator that would ideally read the status of the A-G,DP segment output pins and display accordingly. Perhaps some day I add it, in the meantimeI have to fix the emulator code and find some suppliers for my 7-segment displays




#52589 Embarassing SPI question (re: Netduino Helper Max72197221.cs )

Posted by Emilio x64 on 05 September 2013 - 02:57 PM in General Discussion

Thanks for the clarification, I will change my firmware, I guess you recommed doing the Chip Select (SS) manually rather than letting the .NET Microframework's SPI software do it, right?

 

By emulation I meant the .NET Extensible Emulator where you create a user interface to mimick your device. That's what I did, created a winform to mimick the faceplate of my device where I could interact with buttons (pushbuttons and a dual concentric encoder) as well as a separate winform that would show me in real time the current state of all registers of the "emulated" MAX7219.




#52560 Embarassing SPI question (re: Netduino Helper Max72197221.cs )

Posted by Emilio x64 on 04 September 2013 - 11:31 PM in General Discussion

I am also using a 7219 but since I don't have hardware yet (waiting for the official 4.3) I have worked with emulation by using the Extensible Emulator. Now I read this so to save me some suffering could you clarify this for me to make sure I got it right?

 

  • I understood from the 7219 that the NOOP was used to shift to the slave 7219 but since it was not explicitely mentioned I was sending the NoOP as the first 2 bytes: (a) NOOP(empty_data) and then (B) COMMAND(value). However, reading this thread it seems I had it wrong, so you say IF I want to write to the slave 7219 I would send the COMMAND(value) I need and then follow it by NOOP(dummy)  (two 16 byte transactions but with the NOOP in the 2nd transaction), right?
  • Commands are always 16 bits, address plus data, right?
  • Emulation is not the same as real hardware, according to what I read here, letting the MF SPI s/w do the Loading won't work in this setup right? so you recommend doing the SS (Chip Select/Load) manually making it active before the 2 bytes are sent and inactive AFTER the two bytes are sent.
  • A write to the slave 7219 would require only one LOAD activation/deactivation for the 32 bytes (Command[value] + NoOp[dummy]) OR do it for every 16-bit (2 byte) transaction?

 

Another problem I just noticed in my setup is that each 7219 drove a 4+2 digit setup (better than 6 individual digits) but unfortunately the 4-digit 7Segment uses 35mA and the 2-digit 7Segment uses 25mA which I guess wouldn't work well with a single Iset resistor (one set would look dimmer than the other). So I will have to probably drive the two 4-digit 7Segments by the main (same current limit) and the two 2-digit 7Segments by the slave 7219 (same current) with the complication that writing a value on either set would require two transactions (one for main to fill the first 4 digits and one for slave to fill the remaining decimal digits) :*(




#52062 Timers not working right, more or less at the speed of light

Posted by Emilio x64 on 09 August 2013 - 08:47 PM in Visual Studio

Also tried by adding this in my emulator.config of the custom emulator project (the code shown above is all in the .NET MF project, not the emulator).

<Emulator>  <Types>    <TimingServices>Microsoft.SPOT.Emulator.Time.TimingServices</TimingServices>  </Types>  <EmulatorComponents>     <TimingServices id="NetduinoPlus2_TimingSvcs">        <SystemClockFrequency>168000000</SystemClockFrequency>     </TimingServices>  </EmulatorComponents></Emulator>

did that in hope that the emulator that runs my project would adjust its timing to 168MHz (Netduino Plus 2) but the result is the same...

 

I can follow what NakChak suggests, using the timestamp (in ticks since powerup) provided on the interrupt callback and pass that down the chain and then compare the initial timestamp with the last (release) timestamp to check if it was more than 2000 ms but that would simply be a workaround, the underlying System.Timer should provide realistic, reliable timing services.

 

Though I could not measure very accurately it appears to me (using a chronometer) that a press/release period of about 2 seconds translates to a NETMF "millisecond" difference of 331 against the expected 2,000.




#52060 Timers not working right, more or less at the speed of light

Posted by Emilio x64 on 09 August 2013 - 07:50 PM in Visual Studio

I am convinced it has to do with the base timer time cycle. As you can see from the debug output that while the timer has been programmed for a time period of 2,000 ms (2 secs) it is expiring (timed out) in three (3) milliseconds, that is quite a difference.

ID_PORT_XFR pressed 582TransferPressed 586> TransferPressedXFER TMR Start 591XFER TMR Stop 593XFER TMR TimedOut 593> TimeoutTransfer 596

From this latest timing, we have the following with the time given in milliseconds:

 

@ 582ms the Program class receives a GPIO Interrupt signaling the TRANSFER button was pressed

@ 586ms the Controller class' TransferPressed() method is called, it puts TransferPressed signal into the queue

@ 591ms the Controller class' main loop (state machine) receives the TransferPressed signal and starts the timer for 2,000 milliseconds

@ 593ms the Controller class' ActionTimers_Tick() handler receives the timeout and stops the 2,000 ms timer and the

                TransferTimeout signal is put out on the queue

@ 596ms the Controller class' main loop (state machine) receives the TransferTimeout signal and processes it.




#52070 Timers not working right, more or less at the speed of light

Posted by Emilio x64 on 10 August 2013 - 07:18 PM in Visual Studio

Changing my SystemClockFrequency to 1.000.000 resulted in the timestamps (passed in the interrupt) to be more realistic though with it a 3./ second push is seen as 2 seconds but the Timer keeps on expiring right away...




#52053 Timers not working right, more or less at the speed of light

Posted by Emilio x64 on 09 August 2013 - 03:34 PM in Visual Studio

Doesn't one of the arguments in the button event/interrupt give you the time an even occurred?

 

You are right about Timers running forever.  I found that out earlier this year and ended up writing a post about it.

 

Regards,

Mark

 

Perhaps it does in the emulator application but that information is AFAIK not available on the NETMF application because it doesn't receive a button event.




#52049 Timers not working right, more or less at the speed of light

Posted by Emilio x64 on 08 August 2013 - 11:01 PM in Visual Studio

In my NETMF application I make use of two types of Timers from System.Threading (is there a better one?).

 

One timer actually times the period of time a button is depressed, if it is less than 2 seconds X happens but if it is pressed for more than 2 seconds then Y happens. This is common in embedded devices.The timer is started when the NETMF application detects that the GPIO pin has gone low (active low) and it also detects when the button is released when the GPIO pin goes high. I am using I/O interrupts on both edges to detect the press/release.

 

The other timer is a loop processing timer which is used to periodically do the processing of signals and state transitions of my state machine. When a button is pressed for example a Pressed signal is put into the queue and at the next processing loop the signal is picked up from the queue and processed according to the state.

 

Now, I also found out that in NETMF Timers aren't what we are used to in the standard framework, namely that you can't start/stop them the usual way, they start as soon as they are created (unless a delay is specified) and they keep on running forever. The only way to stop it is by Disposing the timer instance and setting it to null so that it is garbage collected. I use 2000 (milliseconds) for the button press/release and originally used 200 ms for the loop processing.

 

Now, I am testing my "virtual device" and see that even if I click quickly on the button (much less than 2 seconds) the timeout signal is raised as if I had pressed the button for more than 2 seconds!!!

 

Am I missing something here? is there perhaps some NETMF setting that controls the time base of the timers? it appears to me that they are running at the speed of light and therefore what is supposed to be 2 seconds turns out to be more like 100 milliseconds!




#52057 Timers not working right, more or less at the speed of light

Posted by Emilio x64 on 09 August 2013 - 04:54 PM in Visual Studio

BTW I added a few Debug.Print() statements to the timer code, first with the standard date format and got that the Start, Stop AND Timeout occurred on the same second (34). 

 

Then I went on to be more accurate and instead print the Milliseconds property of DateTime.Now and this is what I got:

ID_PORT_XFR pressed> TransferPressedXFER TMR Start 663XFER TMR Stop 665XFER TMR TimedOut 665> TimeoutTransfer

The ID_PORT_XFR pressed output was produced by the Program class on its GPIO Interrupt method. The > TransferPressed/TimeoutTransfer output was produced by the main processing loop (ControllerTimer_Tick()) when it gets the signal from the queue.

 

So that confirms that the base frequency of the timer is running at the speed of light where a millisecond is much much much shorter. Where do I set those base timing things as applicable to the Netduino Plus 2 board?




#52056 Timers not working right, more or less at the speed of light

Posted by Emilio x64 on 09 August 2013 - 04:24 PM in Visual Studio

Chris, here are some code snippets relevant to the problem at hand...

class AnyController {private mTimerTransfer;private mTransferTimedOut = false;private void StopTimer(TimerID id){    switch (id)    {        case TimerID.TransferTimer:            if (this.mTimerTransfer != null) {                mTimerTransfer.Dispose();                mTimerTransfer = null;           }           break;              :    }}private void StartTimer(TimerID id, int msDelay, int msPeriod){    switch (id) {       case TimerID.TransferTimer:           mTimerTransfer = new Timer(new TimerCallback(ActionTimers_Tick), TimerID.TransferTimer, msDelay, msPeriod);           mTransferTimedOut = false;           break;            :    }}} // class

Then my Timer event handler on the above class looks like this. It handles several timers but they have the same mechanism so I show only one for brevity.

private void ActionTimers_Tick(object sender){    StopTimer((TimerID)sender);    Signals timeoutSignal = Signals.NoOp;    // an enumeration of all signals in the S.M.    switch ((TimerID)sender) {       case TimerID.TransferTimer:          timeoutSignal = Signals.TimeoutTransfer;          mTransferTimedOut = true;    // used to discard the signal if necessary          break;           :    }    if (timeoutSignal != Signals.NoOp) {        mSignalQueue.Enqueue(timeoutSignal);    // of type Queue    }}

Now the Program.cs class in my NETMF I have rigged it so that the TRANSFER button generates a GPIO interrupt on the leading (going low, pressed) and trailing (going high, released) edge. That works well. So there when the interrupt occurs on the leading edge I call the TransferPressed() method on the above class, and TransferReleased() when it is released. These methods are implemented like this in the above class:

class AnyController {  :  public void TransferPressed() {     lock (this.mLock) {         mSignalQueue.Enqueue(Signals.TransferPressed);     }  }  public void TransferReleased() {      lock (this.mLock) {           StopTimer(TimerID.TransferTimer);  // asap           if (!this.mTransferTimedOut)               mSignalQueue.Enqueue(Signals.TransferReleased);           else               this.mTransferTimedOut = false;   // signal is discarded      }  }

And here is the processing of the main timer loop (not seen in the definitions) which executed every 200ms (even tried 75ms) and is in charge of processing the events and state transitions, a state machine... Here shown to the bare minimum for the purpose of clarity showing the mechanism I am using.

private void ControllerTimer_Tick(object sender){     Signals rxsignal = Signals.NoOp;     if (mSignalQueue.Count > 0)         rxsignal = (Signals)mSignalQueue.Dequeue();     switch (this.mState)     {         case States.SomeStateA:              if (rxsignal == Signals.TransferPressed) {                   StartTimer(TimerID.TransferTimer, 0, 2000);  // no delay, 2000ms period              }              else if (rxsignal == Signals.TransferReleased) {                   StopTimer(TimerID.TransferTimer);                   Swap();   // does action related to pressing less than 2 secs              }              else if (rxsignal == Signals.TimeoutReleased) {                   mState = States.OtherState;              }              break;     } // switch state}

That may deserve some extra explanation. The Program NETMF class rigged the GPIO to cauase an interrupt on the leading (going low, pressed) and trailing (going high, released) edges of the GPIO and that is detected properly. When that detects a button pressed associated to that GPIO (The TRANSFER button) it invokes the TransferPressed() public method in the AnyController class. That in turn ALWAYS queues the TransferPressed signal into the signal queue.

 

Now, as I indicated in the OP, if the button is pressed less than 2 seconds it does the standard action, in this case Swap() and remains on the same state. If on the other hand the button is pressed more than 2 seconds the ActionTimers_Tick() event handler would STOP the one shot timer that times the button press AND raises the timeout by putting the TimeoutTransfer signal on the signal queue. It also flags that it has timed out on the mTimedoutTransfer.

 

So, why is that you may ask? well, when the button is pressed more than two seconds the TransferTimeout signal is on the queue, since the button was pressed for more than 2 seconds, the next time in the main processing loop (ControllerTimer_Tick()) it will initiate a state transition. That means that in that particular case the release of the Transfer button would happen AFTER the timeout, and I don't want that release event (related to the timeout) to be passed to the signal queue because it would cause the new state to pop back to the original state (not show) because it also processes the Transfer button. So, what I do in AnyController.TransferReleased() is that IF the mTimedoutTransfer boolean is set then the signal is discarded (note, there might be another press/release pair on the new state), if it is not set (not timed out) then the TransferRelased signal is put on the queue.

 

So, that is the scheme but the problem as I mentioned is that these timers seem to  be working at a frequency of Terahertz or something like that because even if I set the timer to expire at a period of 2000 ms (2,000 ms == 2 secs) and have a time between press/release of MUCH LESS than 2 seconds (not even close, even less than a second) the timer times out first than the release and TransferTimeout signal is processed.




#52013 Netduino Board Support Package?

Posted by Emilio x64 on 07 August 2013 - 12:33 AM in Netduino Plus 2 (and Netduino Plus 1)

In addition to the NETMF 4.3 SDK I also installed the Netduino SDK. Isn't there some "using netduino;" kind of using directive that can/should be used to have access to Netduino-specific things?

 

In my custom emulator how do I set the available RAM/ROM and perhaps speed of the Netduino's core processor? I ask because there must be a way (I think) that the development environment warns me if my code or data segments are too large for the hardware I am targetting.




#51586 Creating Device Emulator project with .NET MF 4.3 SDK throws exception

Posted by Emilio x64 on 19 July 2013 - 09:58 PM in Beta Firmware and Drivers

Well as I mention it is spurious, it may fail several times in a row and then the next one it doesn't crash. I have been developing .NET web & desktop apps for years under a restricted account and haven't encountered any real issues.

 

I tried putting a try/catch on the Main of the Emulator project but even with that it simply crashes back to VS and leaves absolutely no information (log, output) about what went wrong. Even the output window is empty.

 

BTW the Device Emulator project wouldn't load today anymore (didn't have that yesterday because I never existed VS). I had to change the target framework of the Emulator (no the MF application) to .NET 4.5. The target framework drop down would only show standard (not micro) framework versions. The MF application project however DOES show only the Microframework versions in that Target Framework dropdown. So is that okay? should I target my emulator at any of the std. frameworks (4.0, 4.5) ?

 

By trying multiple times and attempting to being extremely fast to do Select All & Copy in the Output window when the crash ocurrs I managed to get this. When it happens this information is left only for a second or two in the output window before it is cleared and replaced by "Found debugger!". I think that needs some attention.

Looking for a device on transport 'Emulator'Launching emulator with command line: '"N:CodeMicroFrameworkMyAppMyDeviceEmulatorbinDebugMyDeviceEmulator.exe" "/waitfordebugger" "/load:C:Program Files (x86)Microsoft .NET Micro Frameworkv4.3AssembliesleMicrosoft.SPOT.Native.pe" "/load:C:Program Files (x86)Microsoft .NET Micro Frameworkv4.3Assemblieslemscorlib.pe" "/load:C:Program Files (x86)Microsoft .NET Micro Frameworkv4.3AssembliesleMicrosoft.SPOT.Graphics.pe" "/load:C:Program Files (x86)Microsoft .NET Micro Frameworkv4.3AssembliesleMicrosoft.SPOT.Hardware.pe" "/load:N:CodeMicroFrameworkMyAppMyDeviceEmulatorbinDebugleMyApp.pe"'Restarting interpreter...Attaching to device...Deployment error: failed to (re)connect debugger engine to debugging target.The debugging target and the debugger engine failed to initialize because of unspecified device errors.The debugger engine thread has terminated unexpectedly with error 'Debugger engine could not attach to debugging target.'.



#51709 Creating Device Emulator project with .NET MF 4.3 SDK throws exception

Posted by Emilio x64 on 26 July 2013 - 03:23 PM in Beta Firmware and Drivers

OK the target is okay. What I have consistently noted is that the emulator tends to crash many times on startup with the same error, that it found the emulator but failed to (re)connect to the emulator.

 

I observe that my custom emulator UI pops up and the Output Window shows "Emulator found..." and many times it crashes a few seconds after that. If I try several times (without any change) then at some point it does connect to the emulator and I see a bunch of messages on the Output Window indicating the progress of loading assemblies and data from the PE file (memory usage, etc.).

 

Even in the cases it crashes I see that before it crashes I can FULLY interact with the WinForms custom emulator UI I created. Operating it does not cause the exception. Why the uF Emulator backend fails to (re)connect on initial loading puzzles me. Sometimes doing a "Clean Project" followed by "Rebuild Solution" does it, but other times it doesn't. Sometimes I have to try like 5-6 times to get it to run.

 

BTW... is there a flag or something in my emulator UI (WinForms) that I can use to wait for the Microsoft Emulator to be READY? I see a message on the Output Window that says "Hello World!" and that's how I know it is ready but I want to disable the UI until that phase is reached.




#51575 Creating Device Emulator project with .NET MF 4.3 SDK throws exception

Posted by Emilio x64 on 19 July 2013 - 03:28 PM in Beta Firmware and Drivers

I am using Visual Studio 2012 Ultimate on a Windows 7 Ultimate x64 OS. I am new to Netduino. I downloaded and installed the .NET MF 4.3 as well as the Netduino 4.3 SDK (couldn't find the link to the x64 version).

 

I opened VS 2012 and created a Device Emulator project but every time I compiled it it gave a warning about missing references to the 4.3 libraries or so, but it would compile. In the project properlies I did see that the Target Framework was EMPTY but clicking on it would list the standard .NET frameworks but NOT the 4.3 Microframework, why?

 

I also created a sample MF console application. I was able to build the solution and run it. On ocassions and without any reason or interaction the whole thing would crash with an exception on the emulator but it wouldn't let me see well (the exception data disappears after the emulator window disappears, it disappears by itself after a little while). And then just the same without change it would work well and I am not doing anything fancy.

 

However, the problem now being that I used it until past midnight multiple times. This morning I started VS.2012 and opened my MF solution and now (no changes) the Device Emulator project would not load. It said I didn't have the Targeting Pack. It simply doesn't load anymore.

 

The same happens with some sample projects I downloaded, they don't load into VS.2012

 

There is a problem with the installer too. Like all security conscious people, I use my Administrator account for just that and have been developing under a restricted user account for years. I noticed that I could not find the samples on my restricted account. As it turned out, the installer placed the Samples files in the Documents folder of the Administrator user (where the install was made for ALL users). I would suggest those files be put in the Public user Documents folder or let the user where to install them.




#51989 Netduino Board Support Package?

Posted by Emilio x64 on 06 August 2013 - 04:22 PM in Netduino Plus 2 (and Netduino Plus 1)

I am planning to use the Netduino Plus 2 (don't know if it is an overkill yet, have to see my memory requirements). I was wondering if there is some Netduino BSP (Board Support Package) that contains the definitions that map Netduino-specific stuff to NETMF ? 

 

For example, I read that in an SDK I should map my own pin definitions (board specific) to the NETMF Cpu.Pin.GPIO_* enumeration. Is there such a thing for Netduino?

 

Also, how do I go about specifying GPIO 16 ??? if that is possible.




#52377 There is no NETwork in Netduino Plus (2) ?

Posted by Emilio x64 on 26 August 2013 - 09:33 PM in General Discussion

Still having problems trying to get my desktop application's Broadcast UDP packets to be received by the emulated netduino on the emulator. Trying to isolate the problem, are there any known issues like "Emulator doesn't have Ethernet connection" ? Is there a way to simulate ethernet cable (un)plugging in the emulator?




#52155 Addressing Netduino Flash memory

Posted by Emilio x64 on 14 August 2013 - 04:08 PM in General Discussion

I recently read that the Netduino Plus 2 (the device I have in mind and am developing for) has a certain amount of Flash Memory available for use by the application.

 

Since my application needs to persist in memory (across boot cycles) several values, I would like to know IF I can really use that flash memory and how I can access it from my NETMF application.




#52157 Addressing Netduino Flash memory

Posted by Emilio x64 on 14 August 2013 - 05:06 PM in General Discussion

Quite true, the flash is not the best place. Does the Netduino Plus 2 comes with a built-in SD Card? and if so, is there some sample code how I can access it? I simply need to read/write configuration data, nothing else, no big files,etc. The problem there would be that given the sizes of SD cards, most of its space would be wasted.




#52196 Roundtrip communication latency

Posted by Emilio x64 on 16 August 2013 - 05:15 PM in General Discussion

I think my NETMF software is nearly on its last phases of development, I just hope it fits in Netduino Plus 2. Anyway, my NETMF application is supposed to run on the Netduino Plus 2 hardware and it would communicate with a service on the desktop to get some live information.

 

So that means the Netduino would send a request to the desktop and get some data in return. Since I haven't had the chance to try that on real hardware I would like to know what you can suggest me for this, USB or Ethernet? and what sort of roundtrip communication times I should be expecting.

 

My .NETMF state machine loop runs every 200ms and the service on the desktop would also be updating information around the same rate perhaps even a bit slower (like 1Hz).




#52243 Roundtrip communication latency

Posted by Emilio x64 on 20 August 2013 - 05:13 PM in General Discussion

Well now that I have been told that USB is not possible without extensive work, Serial is not a possibility either because I don't want to use a legacy system and that the ethernet connection has been suggested as the best....

 

I got my desktop proxy software developed, I got my custom emulator developed and running and also my .NETMF application to run on the Netduino Plus 2. But as it turns out (?) there is no support for UDP or TCP in the 4.3 SDK ?! can anybody shed some light into the subject?

 

In my .NETMF application I need an UDP listener that will exclusively listen for UDP broadcasts from the desktop application, this is basically to respond to the "WHO is out there" question because there is no guarantee whether the embedded device would start running before or after the Desktop proxy "server". I am using VS.2012 with .NETMF 4.3.

 

My .NETMF application then mostly uses a TCP connection to the above named desktop proxy server to send commands and receive a response.

 

When I try to write ANY net code in the NETMF the network communications classes are missing. I added a reference to Microsoft.SPOT.Net but that doesn't have anything of use. I also tried the MFDWSEXTENSIONS.DLL suggested in the MSDN but also, nothing of use.

 

I was looking for TcpClient and UdpClient .NET classes but I can't find them. I tried to then make something equivalent based on the Socket class but also, not available anywhere. I am stuck.




#52289 There is no NETwork in Netduino Plus (2) ?

Posted by Emilio x64 on 22 August 2013 - 05:31 PM in General Discussion

Just found out there is no Async Send in the NETMF Socket class :-( anyway, it got me on the way.





home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.