Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Richard

Pages: [1] 2 3
1
µTasker general / Re: Finding device with DHCP IP address
« on: September 01, 2009, 06:13:41 AM »
Thanks for the replies.  I've put this on the back burner for now, but I'll look at the "Session Traversal Utilities for NAT" (STUN) protocol when I get back to it.  See RFC 5389, http://tools.ietf.org/html/rfc5389, and http://en.wikipedia.org/wiki/STUN for more information.

Cheers,
    Richard

2
µTasker general / Re: Finding device with DHCP IP address
« on: June 29, 2009, 05:11:27 AM »
Thanks, Mark, for your amazingly prompt response.

I may have to check out the NetBIOS option if I can't figure out another way of finding the DHCP-assigned local address.  My suspicion is that in solving the rest of this riddle, I'll also find another solution to discovering the local IP address.

My friend's lack of network prowess precludes his performing any router configuration, so both the DMZ and the virtual server options are problematical, as is the assumption that the coffee pot will end up with the same IP address forever.  Imagine the non-deterministic scramble of assigning local addresses to nodes after a major power failure, especially if some laptops and other net-aware appliances on the LAN have been added or removed since the coffee pot was installed.

I can easily set up a free DynDNS account for my friend, but a coffee-pot-based update client may not be so simple to write.  The issue is that DynDNS http://www.dyndns.com/support/clients/ explicitly states, "An update client should only send updates when a change is detected, but some clients send updates at regular intervals (e.g. hourly) whether or not an update is necessary."  How would the coffee machine know if the external IP address changed, i.e., when an update were needed?  The router would know, but if there is any standard way to have a router tell its local clients what its external address is or to have it send some kind of a message when this address changes, I don't know what it is.  And without knowing the external address, the coffee machine would presumably try something like sending out updates based on a timer, which DynDNS explicitly mentions as "abusive updates" and for which they will block the coffee pot from using their service.

I'm going to work on this some more, perhaps after doing some other things that are pressing.  But from your response, I infer that there is no obvious solution.

Oops, maybe there is!  I just heard about "Universal Plug and Play" that looks promising.  From its wikipedia article, it appears that it's quite new: "UPnP was published as a 73-part International Standard, ISO/IEC 29341, in December, 2008."  [Or maybe not, since the "UPnP Vendor's Implementation Guide" is dated 5 Jan 2001.]    And, with 73 parts, there's probably a lot to wrap one's head around.  Furthermore, as I read the article, it seems that the protocol is not really ready for prime time.  There seem to be major security flaws that would have reasonable people disable it.  However, this does mean that a lot of people are working on the problem, and again that it has no obvious solution.

Has anyone looked into implementing UPnP on a uTasker device?

Cheers,
    Richard

3
µTasker general / Finding device with DHCP IP address
« on: June 27, 2009, 04:07:15 AM »
Hi, all.

Imagine that you send a uTasker device -- e.g., an intelligent coffee maker that has a web server on port 4388 -- to your friend to install in his house.  Your friend knows almost nothing about networks, but someone has already set up an Ethernet network for him, so all he has to do is plug in the coffee pot.  He would like to see the coffee pot's web page on his PC (via the LAN), and you'd like to see the web page on your PC (via the Internet). 

What I don't understand:
1) how will your friend know what IP address was assigned to the coffee pot by his DHCP server?
2) how will you convince his router to accept traffic from you for port 4388 and forward it to the coffee pot?  I.e., how do you open port 4388 through the router's NAT?
3) Number 2 comes into play only if you already know your friend's public IP address, which is most likely one that is assigned dynamically by his ISP and subject to change.  There are solutions for this, see e.g., <http://www.dyndns.com/>.  Some routers have a built-in update client -- the module that sends "here-I-am" to the dynamic DNS service at appropriate intervals -- but not all do.  Is there uTasker code for an update client?

Given the push to attach everything in the world to the Internet, this problem must have been addressed somewhere, but I haven't seen where.  I'd appreciate any hints.

Thanks,
    Richard

4
NXPTM M522XX, KINETIS and i.MX RT / Re: Handling short power failures
« on: June 07, 2009, 07:29:29 PM »
Hi, Mark.

To preserve key variables, I do as you suggested: I monitor the raw voltage being supplied to the microprocessor.  When it drops below a threshold, I store the active parameters in the RAM parameter block into FLASH.  To handle short outages, I have to be careful to preserve the RAM copies of the parameter blocks during startup.  To do this, I've created a global variable
Code: [Select]
struct tParamStorage {
    char parameterBlock[PAR_BLOCK_SIZE/2];
    char tempParameterBlock[PAR_BLOCK_SIZE/2];
} ramParameterBlocks;
and replaced
Code: [Select]
parameters = uMalloc(sizeof(PARS));                             // get RAM for a local copy of device parameters
temp_pars  = uMalloc(sizeof(TEMPPARS));                      // get space for a backup of all modifiable parameters
with
Code: [Select]
parameters = (PARS *)&ramParameterBlocks.parameterBlock;
temp_pars = (TEMPPARS *)&ramParameterBlocks.tempParameterBlock;

I modified mcf52235_init() to leave ramParameterBlocks uninitialized when it zeroes out the BSS area.
Code: [Select]
    // Make sure that ramParameterBlocks lies in the BSS area (as it certainly should!)
    // and then initialize all the BSS except the ramParameterBlocks area.
    if ((unsigned char *)__BSS_START <= (unsigned char *)&ramParameterBlocks &&
        (unsigned char *)&ramParameterBlocks + PAR_BLOCK_SIZE <= (unsigned char *)__BSS_END) {
    for (sp = (unsigned char *)__BSS_START; sp < (unsigned char *)&ramParameterBlocks; sp++)
    *sp = 0;
    for (sp = (unsigned char *)&ramParameterBlocks + PAR_BLOCK_SIZE; sp < (unsigned char *)__BSS_END; sp++)
    *sp = 0;
    }
    else
        while (1) {}; // hang here to make the problem obvious while debugging.

I check that it has survived a power failure using a 16-bit checksum (based on an old *nix sum algorithm).  The only issue here is to be sure that the checksum, which is stored in the parameter block, is set to a known value, e.g., 0xffff, before the checksum algorithm runs.

If the checksum test fails, I reload the parameters from FLASH or initialize them to default values, based on your original code.

Cheers,
    Richard

5
Hi, Mark.  Thanks for the very fast and helpful response.

I should be more careful about writing emails well after midnight (my time).  In particular, I should have realized why ucTopOfStack doesn't show up in uTasker_full.elf.xMAP; but even with a full night's sleep, I still can't explain why the CW7.1 debugger displays it without any address.

Even if I eventually have to reduce OUR_HEAP_SIZE, I doubt I'll run out of heap very soon.  I no longer use uMalloc() to obtain RAM space for parameter blocks, reducing the amount of required heap space by PAR_BLOCK_SIZE.  I'll post some more information to http://www.utasker.com/forum/index.php?topic=574 to explain what I did instead.

Cheers,
    Richard

6
Hi, Mark.

So far as I can tell, ucTopOfStack, defined as an unsigned char in fnInitialiseHeap(), is never actually used.  Only its address is ever referenced, here in this
Code: [Select]
while (ucPattern <= &ucTopOfStack) {                                 // this pattern is used later for Stack use monitoring
    *ucPattern++ = UNUSED_STACK_PATTERN;
}
Apparently, the compiler never actually allocates a location for the variable.  Indeed, it does not appear in uTasker_full.elf.xMAP.  The result is that the while loop that is supposed to fill the heap with UNUSED_STACK_PATTERN doesn't do anything.

Did I miss something?

I found this because, in my program,
Code: [Select]
pucTopOfHeap += ctOurHeap->need_this_amount;
causes pucTopOfHeap to be set to 0x20008340.  Since there is no memory there, calling fnStackFree() fails with an access error exception on an operand read.  If the while loop in fnInitialiseHeap() actually did anything, an access error would have occurred at that point, as the program was starting up.

My next question is this: can I safely reduce the value of OUR_HEAP_SIZE below the 21K it is set to and by how much?

Since I'm using CodeWarrior and use only uMalloc() and never malloc(), it looks like I can change HEAP_SIZE = 0x1000; to HEAP_SIZE = 0; in M52235EVB_FLASH.lcf.  The note in the file is a little difficult to interpret: by "This can be left as zero..." do you mean that it can be reduced to zero?  If so, it may be enough to save me without reducing OUR_HEAP_SIZE ... for now.

Thanks,
    Richard

P.S. Thinking about your comment,
Quote
If the pattern is not being set it suggests that its address is below the top of heap (system variables plus OUR_HEAP_SIZE)
I've modified the code in fnInitialiseHeap() to be
Code: [Select]
if (pucTopOfHeap <= &ucTopOfStack) {
    while (ucPattern <= &ucTopOfStack) {                                 // this pattern is used later for Stack use monitoring
        *ucPattern++ = UNUSED_STACK_PATTERN;
    }
}
else                   // not enough memory for heap!
    while (1) {}; // hang here to make the problem obvious while debugging.

7
µTasker general / Re: user file guide
« on: June 04, 2009, 10:01:49 PM »
Hi, Aaron & Mark.

Another approach, which works for me, is to use the existing "£v" mechanism with WEB_ESCAPE_LEN set to 5, to allow five-character strings [and don't forget to modify all of the web pages that came with uTasker].

In a static web page, say Z.htm, I put a string of £vX£Y for the various Y values I want to access with my XMLHttpRequest document, doc using doc.open("GET",Z.htm?...params...,false).  The X following £v is a character not already in use that I've programmed to cause fnInsertString() to access fnInsertMyString() that I've written.  It substitutes the second £ with a value passed in by the parameters of the doc.open() request.  Based on that result, it chooses which values to return.  Since the web pages themselves are static, there is no need to worry about wearing out FLASH.

One thing -- very important -- to prevent various browsers from reusing previous, cached values, I've found it necessary to append the current time to the doc.open("GET",...) parameters.  Some browsers can be convinced not to cache results, but this is the only way I've found to force all browsers that I've tried to use new data passed back.  The downside is that the cache is being filled with old values that won't ever be reused.  I think this applies to all AJAX programs.  If I'm wrong, or if someone knows a better way to accomplish this, please let me know!

8
µTasker general / Re: TCP/IP Offload problem with Vista
« on: May 07, 2009, 04:36:38 PM »
Hi, Mark.
Quote
An alternative modification would be to ALSO accept check sum values of 0 when simulating (as well as correct values) since the offloading always sends 0.

I thought of something similar, so I checked the value fnCalcIP_CS() returns.  It was neither 0 nor some other constant.  It didn't seem worth bothering to try to figure out why, but if you program a way to check that the packet's header checksum was 0, I'd be happy to modify my code.

Cheers,
    Richard

9
µTasker general / Re: TCP/IP Offload problem with Vista
« on: May 07, 2009, 06:18:45 AM »
My cure for the checksum problem is the following alteration to the uTasker ip.c code, in the routine fnHandleIP().  I've not checked it thoroughly, but it seems to work for PINGs and displaying web pages.  I prefer this change, which affects only the simulator version of uTasker, to making changes to OS parameters that could slow all networking activities on my PC.

Code: [Select]
#ifndef _WINDOWS
// The header checksum on some Windows machines, especially those with high-speed NICs, is incorrectly calculated,
// presumably expecting a TCP Offload Engine to perform the calculation -- see
// http://en.wikipedia.org/wiki/TCP_Offload_Engine and http://www.utasker.com/forum/index.php?topic=180.

    if (IP_GOOD_CS != fnCalcIP_CS(0, frame->ptEth->ucData, (unsigned short)(IP_MIN_HLEN + olen))) {
        return(0);                                                       // check sum error - quit
    }
#endif // ! _WINDOWS   

There is a second place where the checksum is tested (search for IP_GOOD_CS), but from my experiments with Wireshark, on my machine at least, the body of the PING packet has the correct checksum, so I found no need to remove the second test.  Other people may find it necessary to do so.

Cheers,
    Richard

10
Hi, Mark.
    You state
Quote
Is it possible that you have programmed a MAC address to your boards beginning with a non-zero value? This represents a special form of multi-cast address and it won't receive general Ethernet frame if addressed like that. Ensure that you leave the first byte at 00 to avoid this.
    While that will work, I don't believe that's actually what is required.  Rather, from http://www.iana.org/assignments/ethernet-numbers, I infer that the requirement for avoiding multicast and broadcast is that the second hex digit be even:
Quote
These addresses are physical station addresses, not multicast nor
broadcast, so the second hex digit (reading from the left) will be
even, not odd.
    If I understand what's happening, the bytes are sent from left-to-right, but the bits within the bytes are sent from right-to-left, so making the second hex digit be odd results in a 1 as the first transmitted bit, and this is what designates multicast and broadcast.
    Cheers,
        Richard

11
NXPTM M522XX, KINETIS and i.MX RT / Handling short power failures
« on: April 21, 2009, 11:39:22 PM »
Hi, all.
    In previous projects, I've found that many power outages are so short that RAM values are reliably maintained, even though prudence dictated stopping the CPU when power dropped below a certain level.  If power was again restored within seconds, a surprisingly frequent situation, a quick check of RAM -- e.g., a checksum of a specific area --  if successful, can allow the program to resume as though nothing had happened.  This is the desired result, since going through a full restart may have unpleasant side-effects, including annoying the user.
    Unfortunately, the M5223X CW project startup code zeroes RAM before allowing any user-defined procedures to run.  This is one way to guarantee that external C variables are initialized to zero by default, as required by C semantics.  However, it prevents using my old assembly-language based technique for a silent restart after a very brief outage.
    So I've got three questions:
1) Is it possible to protect a specified part of RAM from being zeroed on power up?  And, of course, it has to be possible to specify which variables are to be put into this part of RAM.
2) Is there some other reasonable way during power up to tell that power has been down for a very short time, at most a few seconds?  If this were possible, I could simply save critical data in FLASH as power went down and restore it after short outages.
3) Is there some other way to respond to failing power that prevents erratic behavior but does not cause a full reset if power comes back quickly?

Thanks for any suggestions.
    - Richard

12
Hi, Mark.

I've looked only at the M5223X releases, so I haven't had to consider the full range of problems.  However, if I understand your message, the identical file might appear in SP9 for the M5223X but SP3 of the SAM7X releases.

My initial thought was to simply increment the SP number by one with each release, so if SAM7X is now at SP3, with M5223X at SP9 being the most recent service pack, the next release, e.g., SAM7X, would be SP10.  I suspect that mightn't go over well with your various (mostly disjoint) groups of users: who wants to go from SP3 to SP10, anyway?

But how about build or revision numbers?  Those wouldn't have to be sequential.  I use SVN (with the TortoiseSVN interface -- very nice!) with a single repository for several projects.  Since the revision number increases by one with every commit, regardless of project, the revision number for any single project can have a large jump from one commit to the next, because the intermediate numbers correspond to other projects.  The tags, however, are simply labels, under my control, so they can increase any way I want, like product version numbers (when does a project go from version 2 to version 3 instead of 2.1?) or like service pack numbers.

If you used a similar scheme, a revision number in the header of each file that you incremented whenever you made a change to the file, then a text file (e.g., the release notes) could list the revision number of each included file.

Another possibility, with several benefits, one of which would be automating the revision number for each file: You could put the uTasker project into an SVN repository.  Then service pack releases could be marked by tags.  Licensed users would be able to download from the repository with a password. 

Unfortunately, I haven't thought about the problem long enough or hard enough to find the "best, right way" to submit an entire CW project to SVN, so I simply put my sources (the files in ...\Applications\uTaskerV1.3 and its subdirectories) into SVN.  For uTasker, you'd have to have a better, more comprehensive plan.  If you do decide to go this route, you'd do us all a great service if you posted the details of the configuration of SVN that you used to control CW projects.

I also haven't thought about how to coordinate downloading a service pack from one repository and combining those files with the files in my own, separate SVN repository.  It might be more delicate than it appears.

By the way, a side effect of all this discussion is that I discovered I'm already using SP8, not SP7 as I reported in another recent post!

Cheers,
    Richard

13
Hi, Mark.

So far as I can tell, nowhere in any file is there an indication of what level of service pack it represents.  I think it'd be a big help if at least the config.h file had "SP9" or "SP 9" in it somewhere.  In fact, if each file indicated, somewhere in its header information, the last service pack in which it was altered, it'd make keeping up with changes a bit easier for those of us who have to make individual alterations to some of the distributed files.  It might also make it easier to pinpoint possible causes of questions and bug reports.  A user may think he's using SP8 but really have only SP7.

Cheers,
    Richard

14
Thanks, Mark, for your prompt reply.

I should have said that I turned optimizations off to simplify tracing and to make sure that various variables introduced simply for checking their values were not removed. 

Along the way, I tried intermediate values of optimization, and a couple of them caused the compiler itself to fail: while compiling M5223X.c at optimization levels 1 and 2, it tries to write at 0x28 and cannot.  It has no difficulty with optimization levels 0, 3, and 4.  Somewhat scary!  But at least it can compile the project at the two extremes, and those are what most people need.

Cheers,
    Richard

15
Maybe I'm losing my mind...

If I write

double x;
void fn0(void) {
  x = ...;
}


where x is a global, I'll get expected results.  But if I write

void fn0(void) {
  double x;
  x = ...;
}


where x is a local variable, the debugger and the compiler disagree about where x is located, so the displayed value for x in the debugger has the wrong value.  I've single stepped through the assembly code and seen what location gets put into the registers that access the variable; it's not the same as the one attributed to the variable by the debugger.

A similar problem occurs with values passed as function arguments, e.g.,

void fn1(double t) {
  ... = t...;
}


My code is based on uTasker SP 7  -- in particular, in the ColdFire Processor configuration panel, Parameter Passing is set to Register, Integers are 4 bytes, A6 Stack Frames are turned off, the CPU is a 52233 (so Floating Point is automatically selected to be Software), both the Code and Data Models are set to Far (32 bit).  I believe all the other choices are the usual ColdFire ones.

I'm using CodeWarrior 7.1, build 14. I've made the recommended additions and changes to use floating point variables --
1) include (and link) the following files in my project:
    fp_coldfire.a in C:\Program Files\Freescale\CodeWarrior for ColdFire V7.1\ColdFire_Support\Libraries
    C_4i_CF_RegABI_Runtime.a in C:\Program Files\Freescale\CodeWarrior for ColdFire V7.1\ColdFire_Support\Runtime
    C_4i_CF_RegABI_SZ_MSL.a in C:\Program Files\Freescale\CodeWarrior for ColdFire V7.1\ColdFire_Support\msl\MSL_C\MSL_ColdFire\Lib

2) modify ansi_prefix.CF.size.h in C:\Program Files\Freescale\CodeWarrior for ColdFire V7.1\ColdFire_Support\msl\MSL_C\MSL_ColdFire\Include by changing a couple of #defines to give

#if !((__COLDFIRE__ == __MCF5475__ || __COLDFIRE__ == __MCF5485__) && !__option(fp_library))
#define _MSL_FLOATING_POINT 1  // was 0
#undef _MSL_NO_MATH_LIB         // was define
#endif

Unlike Neil's suggestion (topic 399, message 1646), I did not change _MSL_FLOATING_POINT_IO from 0 to 1, because I'm not trying to format or print floating point numbers.

With the exception of this debugging problem, floating point code seems to work just fine with this setup.

My questions are these:
    1) has anyone else observed this problem? and
    2) is there some setting I missed that would make the debugger correctly recognize the location of local variables of type double?
and, of course,
    3) am I losing my mind?

Cheers,
    Richard

Pages: [1] 2 3