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.

ziggurat29

Member Since 24 Nov 2012
Offline Last Active Mar 07 2014 04:38 PM
-----

Topics I've Started

Unmount and MountSD; do they work on NP2?

08 July 2013 - 04:46 PM

Folks;

Does anyone know definitively whether the APIs:

StorageDevice.Unmount()

and

StorageDevice.MountSD()

do or do not work on the Neduino Plus 2?  From experience?

 

Here is a test app that, for me, fails attempting to Unmount().

//testing StorageDevice.Unmount and StorageDevice.MountSD on the NP2using System;using Microsoft.SPOT;using Microsoft.SPOT.Hardware;using SecretLabs.NETMF.IO;    //NOTE:  you will need to add reference SecretLabs.NETMFIO.IOusing Microsoft.SPOT.IO;      //NOTE:  you will need to add reference Microsoft.SPOT.IOnamespace NP2VolumeMountTest{    public class Program    {	    public static void Main()	    {		    bool bJoy = false;		    try		    {			    //first, get mounted volume names as a sanity check			   				 Debug.Print("listing mounted volumes...");			    VolumeInfo[] volumes = VolumeInfo.GetVolumes();			    foreach (VolumeInfo volumeInfo in volumes)				    { Debug.Print("volume:  " + volumeInfo.Name); }			    Debug.Print("finished listing mounted volumes");		   				 //now, we will try to unmount and re-mount the SD card			    Debug.Print("attempting to unmount SD card...");			    StorageDevice.Unmount(@"SD");			    Debug.Print("unmount success!");			    //from schematic			    //using cpu spi module 3, /CS is B0, /CARDPRESENT is B5, /POWERCTL is B1			    //from firmware .DeviceCodeTargetsNativeSTM32ManagedCodeHardwareCPU.cs			    //public const Cpu.Pin GPIO_PIN_B_0 = (Cpu.Pin)16;			    //public const Cpu.Pin GPIO_PIN_B_1 = (Cpu.Pin)17;			    //public const Cpu.Pin GPIO_PIN_B_5 = (Cpu.Pin)21;			    Debug.Print("attempting to re-mount SD card...");			    StorageDevice.MountSD(@"SD", SPI.SPI_module.SPI3, (Cpu.Pin)16, (Cpu.Pin)21);			    Debug.Print("re-mount success!");			    bJoy = true;		    }		    catch (SystemException e)		    {			    Debug.Print("failure;  exception:  " + e);			    Debug.Print(e.StackTrace);		    }		    Debug.Print("Test application main() terminating.  " + ( bJoy ? "Have a nice day." : "It will be a long day." ) );	    }    }}

Let me know if there is a change that will make it work, and ideally what firmware version you are using.  I myself have tested on firmware versions 4.2.1.0, 4.2.1.1, 4.2.1.2, 4.2.2.0, 4.2.2.1, 4.2.2.2.

 

While looking into a different problem (that of filesystem flushing), I started with the often-suggested workaround of doing an Unmount().  Of course, one would want to remount, right?  Which was the motivation for this test:  to figure out the MountSD parameters, but then I discovered that Unmount fails beforehand.

 

FWIW, I also tried fiddling with the "SD", trying upper, lower, leading slash, trailing slash, and null.  (Examining the source, I didn't really expect those to help, but now you know I did try anyway).

 

Any confirmation that Unmount/MountSD do in fact work on the NP2 is useful, along with whatever beyond what I showed above that is necessary to make those calls work.

 

-knave


Silly Voice Synth on NP2....

26 May 2013 - 02:59 AM

Recently, while looking for some unneeded junk on ebay, I stumbled across a listing for an antique voice synthesiser chip, the SP0256.  It made me remember that I might have some on-hand, and I looked in my junkbox and Lo! and Behold! amongst decaying antistatic foam were a couple samples, replete with the odd-valued crystal it prefers.  So I thought I'd amuse myself for a couple hours and hook it up and reminisce the scarcely intelligible sounds from yesteryear

 

After the fun of a buzzy 'Hello' had worn off, I found myself inspired to do a particular Doors song, but one thing about this chip is that you have to manually specify a sequence of phoneme variants called 'allophones'.  This is a bit time consuming, and so drains the fun, but by now I was doomed because improvement obsession had set in, and so I wasted several days implementing a text-to-speech algorithm for it (don't be too impressed, this is derivative from some research done in the 70s, and some concrete code done in years hence).

 

Anyway, I thought I'd share for your amusement if you're bored.  (well, I can't really promise this will truly cure that, but I did try!):

 

 

While a trivial pursuit, there were some useful things I did learn that I want to share:

 

1)  C#/NetMF is not great at constant data, like for tables of...  'stuff'

  By 'not great' I mean 'horrible'.  The text2speech uses about 2000 rules, consisting of 4 parts:  three patterns and a phoneme sequence to emit for the match.  This is the sort of stuff that in C, etc, you declare something like:

[color=#4b0082;][font="'courier new', courier, monospace;"]   struct thingy { const char* first; const char* second; const char* third; const char* fourth; };[/color][/font]

[color=#4b0082;][font="'courier new', courier, monospace;"]   static const _rules[] = { "l1", "m1", "r1", "f1" }, { "l2", "m2", "r2", "f2" }, };[/color][/font]

and when you did that, the linker would have the sense to put it all in ROM, thereby consuming no RAM.  Because it is read-only; what do you need it in RAM for? (on some processors you need to add some compiler-specific qualifiers, or some linker magikry, but that is not pertinent here).

  On netmf, apparently 'const' and 'readonly' are neither, and netmf will take such a naively constructed array and blithely instantiate it in RAM.  Goodbye RAM, we'll miss you.  And miss it, I did, because I consumed it all (about 105k available to user programs on the NP2) and had none with which to run my program.  This was when I had a little over 300 rules that were derived from the US Navy research.

  So in eagerness I cut a few, and it sounded like crap, but it ran, a little, with about 20K RAM.

 

So 'caveat programmer' on tables of data, I'll describe how I coped and with what results after explaining a few more things....

 

2)  Netmf apps need more than about 15K RAM

  If you go below this, the system will become unstable.  You will need to furiously litter your code with

[color=#000080;][font="'courier new', courier, monospace;"]   Debug.GC(true);[/color][/font]

[font="'courier new', courier, monospace;"][font="arial, helvetica, sans-serif;"]  just to keep it alive.  You'll see memory allocations fail on the debugger output, and your program will run for a little while, but things will come to an end soon enough.[/font][/font]

 

Nothing to say here other than realize that you will need to help netmf out by not getting to rammy with your impls, and that a [color=#000080;][font="'courier new', courier, monospace;"]GC(true)[/color][/font] now and then is most effectacious.

 

3)  An array (i.e. []) of something will cost you RAM

  all the const and readonly in the world apparently will not help you, there will be a RAM based array of references.  Hmm!
 

4)  Too many initializers makes your metadataprocessor mad

  A companion to the RAM consumption problem is a build tool called the 'MetaDataProcessor'.  It evidently processes the data that is meta, but it doesn't like it if you have too much.  It will give you abstruse error messages (one of which I do not have a sample at the ready just now, alas), so like you just cut a few.  Like when you have too many notes in your music score.  Well, you coded them, and it's not like you're just typing them in to keep the blood flowing to your fingers on a cold winter's eve, they're important!

 

I found that the count of items is important, and the type drastically even more so.  Which leads to the next point...

 

5)  NetMF is pretty good at [color=rgb(0,0,128);][font="'courier new', courier, monospace;"]string[/color][/font]s

  strings, which in dotnet and other recent languages of the javainian persuasion, are immutable, and the runtime seems to have some sense in that regard.  So, if you declare a string constant, it's value actually will be stored in the Flash, and not come into RAM until you fiddle with it......

 

So, OK, this last bit is call

What I Did To Cram 2000 Structs Of Read Only Data Into My App And Only Waste 25k Of RAM,

or alternatively

thank Goodness My Processor Is Fast And Doesn't Have Better Things To Do.

 

I'll spare you the details of the 5 or so experiments I did before this final one -- you've been kind (or bored!) enough to read this far.  Ultimately, I:

 

flattened my jagged array into single array

  and a secondary array of offsets to the starts of sections, and then manually treated it as an array-of-arrays in code.

  This helped a little with the RAM usage; a small gain, but a gain nonetheless.

transcoded my binary fields into text fields

  this was surprisingly helpful, because evidently metadataprocessor gets really miffed at initializers for binary fields.  way more so than for text fields.  Hmmm.  I'm going to have to look at this metadataprocessor someday.  Anyway, this made is possible to even compile with a reasonable-sized rule set.  I find it rather puts a damper on your fun if you can't compile, but maybe that's just me....

flattened my structs into a string

  this was a much more tedious, because I was effectively encoding the struct into a delimited format, and scootching the character set to avoid the field delimiter.

  this was the big win by far.  ultimately it was what made it possible to include the total rule set, and still have a healthy bit of RAM left over for the app.  Mind you, in a sane world the RAM cost would be zero.  Thats a '0' with infinitely many '0' after it.  So I'm still a little disappointed (and some of my crypto code is as well because I need tables for my S-boxes etc and compiles fail sporadically because of it but that's a separate rant), but this project was for fun so whatevs.

 

Then, I punished my STM32F4 by making it depersist the encoded rule on-the-fly every time it was needed.  Which really is a lot.  And speech is slow to emit, and so there's time abounding to translate text into speech, and so you can keep it quite fluid if you have a worker thread that emits speech sequences from a queue, separate from your text-to-speech translation process

 

Oh!  That reminds me that there is one other thing I learned in all this:

 

Event Notifications Come In On a High(est!) Priority Thread

  To make the demo, I added an [font="'courier new', courier, monospace;"][color=rgb(0,0,128);]InterruptPort[/color][/font] to execute one of my test sequences.  Click the button, and text to speech something fun, and out comes sound.  EasyPeasy.  But, my speech came out sllooowwww, for a couple seconds, and then picked up the normal pace.  Well, the reason why is that the button event handler gets invoked on a thread executing at priority 4 (highest), and my speech rendering worker thread was running on priority 2 (normal).  So, my text-to-speech was running in a higher-priority thread than my output-to-synthesiser worker thread, and so was taking time away feeding the synth.  Actually, I am impressed that the synthesizer thread was not starved out-right, so kudos to the scheduler implementer, but nonetheless the text to speech needed to be at or less than the priority of the output.  The interrupt handler had nowhere to go but down, and anyway I felt dirty fiddling with it's priority since it was not my thread, and so I made yet another queue for text to speech work.

 

Oh, there were two last things I learned that are worth mentioning:

arrays cost

  For fun I tried setting all my rules to null.  guess what?  I still used 25k.  So that ram usage seems to be for the array of object references, and it WILL be in RAM.  No ROMming for you!

netmf uses utf8

  hahaha I was worried that encoding as a string would incur a UCS16 penalty, but it does seem that netmf uses UT8 for at least it's const string literals.  Hollow victory, though, because once its rom-able, the space is less an issue.  Still, interesting fact to note.

 

Anyway, there it is.  I have spent a little more time than I should have on this, and now that I have posted, perhaps I can dismantle my breadboard and move on with more useful things!....

 


'over the air' update; possible?

23 March 2013 - 08:58 PM

Is there any known facility/technique for updating the deployed application in an unattended fashion programattically in the field?

 

I would like to:

*  connect to my device from afar

*  send an updated application binary -- probably stored on SD

*  instruct the unit to go into some 'mode' whereby the application is updated (the 'deployment', not the firmware.  but hey maybe that too)

*  the restart the application

 

I haven't seen anything like this (or maybe my google fu simply fails me today), hence the question.

 

If not, I imagine I could maybe replace TinyBooter with a custom mechanism for doing this, since TinyBooter is mostly unneeded needed on the Netduino.

 

tia!

-dave


MAC Address label and barcode

28 January 2013 - 04:17 AM

I would like to suggest adding a barcode to the MAC address label placed on the Netduino Plus 2 (and presumably other models).  This would allow more efficient bulk programming, and should only involve a change to the label printing step to include the barcode image, since the process is already is setup to textually indicate the unique-per-unit MAC address.

 

Manual programming is fine for individuals with a couple boards, but is an error-prone hassle for even small volumes.

 

I imagine this has been suggested before, so I am attaching some stuff:

 

*  sample code for a semi-automated programmer.  To use it, you plug in your NP2, scan the barcode label, wait for the beep, and unplug the unit upon completion.  Repeat until you run out of netduinos.

*  some sample labels.  I made two kinds:

  *  a 'long form' label which contains the complete MAC.  This make a label a bit longer than the original in order to get a reliable read.  Code-128B is used.  It has a prefix of 'MAC-' for sanity checking.

  *  a 'short form' label which contains only the last 3 bytes of the MAC, since the first three are presumably the fixed SecretLabs OUI (5c-86-4a).  This makes a label about the same size as the existing one.  It has a prefix of 'MS' for sanity checking.

  the sample code will accept either form.  The text in the label is set to the literal text in the barcode for illustration, but obviously you can print whatever -- maybe the current friendly text for the humans.

 

I used one of those cheap (~$20USD) keyboard wedge style linear scanners.  I printed the barcodes on paper with a laser printer.  Seems to work great -- especially once you know your scanner's happy spot.  It seems if you make the bars taller, the scanner becomes more enthusiastic about reading.

 

The sample code is -- well it's sample code.  You would want to add more user notification and error checking, but this shows the key calls needed to programmatically burn the MAC in, so you can fance it up as desired.  This is a .Net windows form app.  I am just including the main form code -- the rest is boilerplate generated by the wizard.  Ultimately, the interesting bits are all in one method, anyway.

 

It just has one form, with a text box called 'tbMAC'.  The scanner acts like a keyboard, so you keep focus on this control.  The 'TextChanged' event is use to do all the work.  The text is inspected for sanity, and once it is sane, programming happens.

 

Devices are enumerated, checked for sanity, connected-to, and programmed.

//NetduinoBigMACAttack.MainForm.csusing System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Runtime.InteropServices;using Microsoft.NetMicroFramework.Tools.MFDeployTool.Engine;namespace NetduinoMACAttack{    public partial class MainForm : Form    {                        public MainForm()        {            InitializeComponent();        }        private void tbMAC_TextChanged(object sender, EventArgs e)        {            //get the text that has now changed            string strText = ((System.Windows.Forms.TextBox)sender).Text;            //we suport a 'long' form, like this:  "MAC-5c864a012345", and a            //'short' form, like this:  "MS012345"            bool bIsLong = 16 == strText.Length;    //long form length            bool bIsShort = 8 == strText.Length;    //short form length            if (!bIsLong && !bIsShort)    //maybe still typing it in                { return; }            if (bIsShort)    //see if we have the short form prefix            {                if (0 != strText.Substring(0, 2).CompareTo("MS"))    //must start with 'MS' for short form                    { return; }    //horror            }            if (bIsLong)    //see if we have the long form prefix            {                if (0 != strText.Substring(0, 4).CompareTo("MAC-"))    //must start with 'MAC-' for long form                    { return; }    //horror            }            //make MAC from short or long form            byte[] abyMAC = null;            if (bIsShort)    //see if we have the short form prefix            {                byte[] aby1 = { 0x5c, 0x86, 0x4a };                byte[] aby2 = ByteFromHex(strText.Substring(2));                abyMAC = new byte[aby1.Length + aby2.Length];                Buffer.BlockCopy(aby1, 0, abyMAC, 0, aby1.Length);                Buffer.BlockCopy(aby2, 0, abyMAC, aby1.Length, aby2.Length);            }            if (bIsLong)            {                abyMAC = ByteFromHex(strText.Substring(4));            }            if (null == abyMAC || 6 != abyMAC.Length)                { return; }    //horror            //find the netduino and program the MAC            MFDeploy mfdeploy = new MFDeploy();            bool bFoundIt = false;            bool bDidIt = false;            //List all usb thingies available            TransportType[] att = { TransportType.USB };            System.Collections.ObjectModel.ReadOnlyCollection<MFPortDefinition> ports;            ports = mfdeploy.EnumPorts(att);            foreach (MFPortDefinition port in ports)            {                if (0 == port.Name.CompareTo("NetduinoPlus2_Netduino"))                {                    bFoundIt = true;                    MFDevice device = mfdeploy.Connect(port);                    if (null != device )                    {                        if ( device.ConnectToTinyBooter() )                        {                            MFNetworkConfiguration netcfg = new MFNetworkConfiguration(device);                            netcfg.Load();                            netcfg.MacAddress = abyMAC;                            netcfg.Save();                            bDidIt = true;                        }                        device.Dispose();                    }                    break;                }            }            mfdeploy.Dispose();                        if (!bFoundIt)                { MessageBox.Show("Couldn't find a Netduino!"); }            if (!bDidIt)                { MessageBox.Show("Couldn't program a Netduino!"); }                        //issue forth the the blissful sound of joy            MessageBeep(MB_OK);                        //clear the text, since we ate it            ((System.Windows.Forms.TextBox)sender).Text = "";        }        public static byte ByteFromHex(char ch)        {            return (byte)(ch < 'a' ? (ch < 'A' ? ch - '0' : ch - 'A' + 10) : ch - 'a' + 10);        }        public static byte[] ByteFromHex(string str)        {            int nEffectiveStrLen = str.Length & ~1;            byte[] aby = new byte[str.Length / 2];            for (int nS = 0, nB = 0; nS < nEffectiveStrLen; ++nS, ++nB)            {                byte by = (byte)(ByteFromHex(str[nS]) << 4);                ++nS;                by |= (byte)ByteFromHex(str[nS]);                aby[nB] = by;            }            return aby;        }                    #region Lose32        [DllImport("user32.dll")]        static extern void MessageBeep(uint uType);        const uint MB_OK = 0x00000000;        const uint MB_ICONHAND = 0x00000010;        const uint MB_ICONQUESTION = 0x00000020;        const uint MB_ICONEXCLAMATION = 0x00000030;        const uint MB_ICONASTERISK = 0x00000040;        #endregion    }}

 

hope it's useful to someone!


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.