Avatar for CKnight

CKnight

Member since Jan 2015 • Last active Jul 2015
  • 3 conversations
  • 20 comments

Most recent activity

  • in Projects
    Avatar for CKnight

    After coming across Espruino and really liking what it had to offer, I was able to convince my team that a port to our hardware could be a really beneficial endeavor. I started work on doing the port, and roped in a team member who helped me get some of the more nuanced things working, such as the SDIO FS usage.

    Bit of a primer
    Janus RC is an M2M company that I work for, we offer fully certified devices for usage on various networks, through the use of Telit brand modems. While not always in the expense range of the maker type of project, we take care of the massive front end costs that accompany network certification, such as PTCRB. Our plug in devices are more akin to what users here would look for. This particular port is for our T2 Terminus, which is an STM32F4 powered device.

    @Gordon - If you have any issues with my documentation/naming schemes of things, just let me know.

    On to the fun stuff
    Enough with the wordy preamble. You want code/examples, and you shall have them!

    We've written some modules that can be used as building blocks for an M2M/cellular application, leaning on the modem's stack to handle basically everything you'd want. Although they are geared for Telit modems, you could simply tool the flow to fit your modem of choice... many basic AT commands overlap as standard (+CREG, for example). The primary goal is autonomous applications since that's what M2M is really all about.

    This is my first Javascript based project, so I'm sure that I've done many things that many not be well executed, or take full advantage of what's available. Criticisms are of course welcome.

    Our current repository for this fork:
    https://github.com/JanusRC/T2-Terminus/t­ree/master/espruinoT2/Janus_JS

    I won't re-write everything here, as I tried to document usage well in our github with a downloadable user guide. For those who don't want to use that .doc version, I tried to mirror it all in our forum, located here.

    Our current modules and code include:

    -Modem

    1. AT Handling to interface to any modem that uses the standard Hayes format (\r\n terminated).
    2. Network registration and checks
    3. SMS sending and reception
    4. Socket control
      4a. Socket Dial to remote host
      4b. Socket Listen for a remote client
      4c. Socket Listen for remote client, with remote control of the console.

    -Other

    1. BMA222 Accelerometer
    2. Some LED PWM fun

    A note about the AT handler:
    AT Command handler, uses an iterative approach to commands since Espruino currently cannot do something like "send AT command, wait for response" in a single loop. It must return to idle state for backend processing of the received data. This will likely improve later with a more streamlined approach. For now, you simply send the command twice to fetch the response.

    Example AT send/receive:

    atc = require("ATC").ATC(Serial6);
    > atc.sendAT('AT',"OK")
    > -1
    > atc.sendAT('AT',"OK")
    > OK
    

    Example registration demo:

    >RunApp(TestProgram)
    =undefined
    Running T2 Test Program
     
    **Running T2 Modem Wakeup App**
    -->Modem On, checking for AT
    -->AT Found, Modem Is Ready
     
    **Running T2 Network Status App**
    -->Modem Type: HE910
    -->SIM Ready
    -->SIM Phone Number: "1815xxxxxxx"
    -->Modem Registered
    -->Signal Quality: +CSQ: 16,3
    -->Modem Ready for Data
    -->Registered to: "Family Mobile"
    -->Modem Firmware: 12.00.006
    -->Network Status Check Complete.
    Test Program Finished.
    >
    
  • in General
    Avatar for CKnight

    I uploaded the fork to our repository for review/use. Right now it's set to use the TerminusT2 hardware in the makefile, but a swap to the discovery the hardware will be correct. I also made some slight adjustments in the clock usage. Now you can define the clock in the makefile, just set the divider so that it matches (8Mhz w/ 8, 16Mhz w/ 16).

    https://github.com/JanusRC/T2-Terminus/t­ree/master/espruinoT2

    The main adjustments that pertain to the SD card are:

    ifdef USE_FILESYSTEM_SDIO
    DEFINES += -DUSE_FILESYSTEM_SDIO
    ifeq ($(FAMILY), STM32F4)
    SOURCES += \
    libs/filesystem/fat_sd/stm32f2_4_diskio.­c \
    libs/filesystem/fat_sd/stm32f2_4_sdio_sd­.c
    else
    SOURCES += \
    libs/filesystem/fat_sd/sdio_diskio.c \
    libs/filesystem/fat_sd/sdio_sdcard.c
    endif 
    else 
    SOURCES += \
    libs/filesystem/fat_sd/spi_diskio.c
    endif 
    endif #!LINUX
    endif 
    

    And in the board.py file:

    'SD' : { 'pin_cmd' : 'D2',
    'pin_d0' : 'C8',
    'pin_d1' : 'C9',
    'pin_d2' : 'C10',
    'pin_d3' : 'C11',
    'pin_clk' : 'C12' },
    

    If you want to use the bitbanged SPI, you'd have to remove the SDIO defines.

    File additions that get called:
    -stm32f2_4_diskio.c
    -stm32f2_4_sdio_sd.c
    -stm32f2_4_sdio_sd.h

    As Clive1 mentioned, it'll work correctly if you boot the device up and initialize the library with the SD card in place. If you remove it and re-insert then it breaks, for now anyway.

  • in General
    Avatar for CKnight

    Oh wow, that totally works. Quick test on a random sd card I have.

    >var spi = new SPI();
    ={  }
    >spi.setup({mosi:D2,miso:C8,sck:C12});
    =undefined
    >E.connectSDCard(spi,C11);
    =undefined
    >console.log(require("fs").readdirSync()­);
    [
      "debug",
      "dtbs",
      "MLO",
      "u-boot.img",
      "zImage",
      "initrd.img",
      "uEnv.txt",
      "ID.txt",
      "SOC.sh",
      "flash-eMMC.txt",
      "App",
      "Drivers",
      "Docs",
      "scripts",
      "autorun.inf",
      "LICENSE.txt",
      "README.htm",
      "README.md",
      "START.htm",
      "uInitrd"
     ]
    =undefined
    Uncaught SyntaxError: Got ?[173] expected EOF
     at line 1 col 41
    console.log(require("fs").readdirSync())­;
    
    
    >console.log(require("fs").readFile("aut­orun.inf"));
    [Autorun]
    shellexecute=START.htm
    icon=Docs\beagle.ico
    label=BeagleBone Getting Started
    action=Open BeagleBone Getting Started Guide
    [DeviceInstall]
    DriverPath=Drivers\Windows\FTDI
    DriverPath=Drivers\Windows\RNDIS
    =undefined
    > 
    

    Not sure if that Syntaxerror is anything of note, but it does work. Just built it for the 32F4DISCOVERY since my other board isn't on hand.

      'SD' :  { 'pin_cs' :  'C11',
                'pin_di' :  'D2',
                'pin_do' :  'C8',
                'pin_clk' :  'C12' },
    

    It didn't like the USE_FILESYSTEM define without at least having the pins declared in the board.py

    That's great though. I'm sure it'll help a lot of people out.

    We're still bound and determined to get the SDIO library working. We have it at least compiling for the Discovery, whether it actually works I dunno yet, going to try that out next.

  • in General
    Avatar for CKnight

    Otherwise as @DrAzzy says, I'll be including the ability to use the SD card on any pins. It won't be SDIO (in fact it'll just be software SPI if you haven't got the SD card connected to a hardware SPI port), but it should work well enough.

    Bitbanged SPI is a nice workaround for pre-existing hardware, and would work pretty well I'd bet. I don't suppose there's any ETA on beta firmware for that is there? If it's remotely close I'll just move to the other peripherals and hang tight.

    The issue is probably that the SDIO driver is designed for the STM32F1 parts, and you're trying to use in on an STM32F4. You could try and change the code so that it would handle STM32F4 too, but that might be quite hard work.

    Yeah I spent quite a while looking at that today and trying to adjust the sdio_* files and various includes to use a discovery board SDIO example, but no real luck yet on that. I'd imagine with the DiscoveryBB using SDIO I won't be the only one to ask though. I should be able to mainly focus on these files for that, right?
    diskio
    sdio_diskio
    sdio_sdcard
    ff

  • in General
    Avatar for CKnight

    So I've gotten my project to a point where I can bring up the primary function and run some basic autonomous cellular demonstrations (I'll pop that code up into the projects section shortly here), and found what needed to be adjusted for 16Mhz operation. However, now that I've got that running I want to try and get my major peripherals up and usable. One of them is an SD card, which unfortunately is connected via SDIO, and I can't get a successful compile.

    Adding this to my board file:

      'SD' :  { 'pin_cmd' :  'D2',
                'pin_d0' :  'C8',
                'pin_d1' :  'C9',
                'pin_d2' :  'C10',
                'pin_d3' :  'C11',
                'pin_clk' :  'C12' },
    

    It matches the HY, conveniently.

    Makefile info:

    else ifdef T2_STM32F4
    EMBEDDED=1
    USE_FILESYSTEM=1
    USE_FILESYSTEM_SDIO=1
    DEFINES += -DUSE_USB_OTG_FS=1
    BOARD=T2_STM32F4
    STLIB=STM32F40_41xxx
    PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm­32f4/lib/startup_stm32f40_41xxx.o
    OPTIMIZEFLAGS+=-O3
    

    I see this in the jsrap_fs.c file

    It is currently only available on boards that contain an SD card slot, such as the Olimexino and the HY. It can not currently be added to boards that did not ship with a card slot.

    But I know that it's possible to use the USE_FILESYSTEM=1 on the STM32F4DISCOVERY with added on SD card slot (saw the thread noting it), but I guess before I continue digging in the wrong areas of code I was just curious if this was even possible in the current build, or what I'd have to modify if it isn't.

    Running a make with one or the other compiles, it's just not happy with both defines on an STM32F4 based build.

  • in General
    Avatar for CKnight

    Okay, so I kinda followed what you have there, expounding on what I had started previously. Now I've written a small function to grab the incoming data and pop the information to a buffer that I can check at any time.

    var mdmBuffer = "";       //Main storage buffer
    var mdmURCBuffer = "";    //URC Buffer
    var mdmParsedBuffer = ""; //AT Response buffer
    
    Serial6.on('data', function (data) {
      //This event grabs incoming data and concatenates it into a buffer
      //The buffer is scanned for identifiable modem AT responses and handles URCs.
      //This assumes a regular cleanup of the main buffer in your flow.
      var idx1 = -1;
      var idx2 = -1;
    
      mdmBuffer += data;
      //Scan for common AT responses, need to search for these as 
      //sometimes you can get multiple CRLF and throw off other checks
      if (mdmBuffer.indexOf("#")>=0 ||
          mdmBuffer.indexOf("+")>=0 ||
          mdmBuffer.indexOf("$")>=0 ||
          mdmBuffer.indexOf(">")>=0 ||
          mdmBuffer.indexOf("ERROR")>=0 ||
          mdmBuffer.indexOf("OK")>=0) {
          //Found one of these
    
        if (mdmBuffer === "\r\nOK\r\n") {
          //Straight up OK response, no other return
          mdmParsedBuffer = "OK";
        }
        if (mdmBuffer === "\r\nERROR\r\n") {
          //Straight up ERROR response, no other return
          mdmParsedBuffer = "ERROR";
        }
    
        if (mdmBuffer.indexOf("#")>=0 ||
            mdmBuffer.indexOf("+")>=0 ||
            mdmBuffer.indexOf("$")>=0) {
          //Found one of these
          //Could be a URC or an AT response
    
          //Put these to a buffer we can call upon at runtime or service through 
          //a set interval. If we print these immediately they may not be read/full.
          if (mdmBuffer.indexOf("OK")>=0) {
            //If there's an OK in here, it's not a URC
            mdmParsedBuffer = mdmParseResponse(mdmBuffer);
    
          }
          else mdmURCBuffer = mdmParseResponse(mdmBuffer);
    
        }
      }
    });
    
    function mdmParseResponse(inSTR) {
      //This function parses out the responses to readable format
      //It recognizes non-AT style responses by the \r\n and just returns them.
    
      if (inSTR !== -1 && inSTR.length > 0) {
        rtnSTR= inSTR;
    
        if (inSTR.indexOf('\r\n',0) !== -1) {
          splitList = inSTR.split('\r\n');
          rtnSTR = splitList[1];
        }
    
      }
    return rtnSTR;
    }
    

    and some little helper functions

    function mdmClearBuffer() {
      //Clears the main buffer
      mdmBuffer = "";
    }
    
    function mdmPrintBuffers() {
      //Prints out the main buffers to console
      console.log("mdmBuffer = " + mdmBuffer);
      console.log("mdmURCBuffer = " + mdmURCBuffer);
      console.log("mdmParsedBuffer = " + mdmParsedBuffer);
    }
    
    function mdmSendAT(data) {
      Serial6.println(data);
    }
    
    

    Output

    mdmSendAT('AT+CREG?')
    =undefined
    mdmPrintBuffers()
    mdmBuffer =
    +CREG: 0,2
    OK
    mdmURCBuffer = +CRE
    mdmParsedBuffer = +CREG: 0,2
    =undefined

    So overall it's similar to what I had before, just done more automatic and doesn't require calling a receive/parsing function separately, which is nice.

    Now the question is how do I actually take this further and if it's even possible, as in, is it possible to automate something that I want done. I'm trying to wrap my head around what normally gets done for this and it's getting a little muddy.

    An example would be something simple like reading an I/O and sending an SMS upon a desired state. I feel like I'm going to be creating a bunch of little functions, and a larger function that gets an interval set and passed the desired small function to run, so that it can run the network checking and whatnot when required.

    Hmm, I feel like this should be moved to the projects/JS area so it's not muddying up the General area.

    • 9 comments
    • 3,635 views
  • in General
    Avatar for CKnight

    Yeah I'd like to have a few options.

    1. A direct cross terminal, which is easily accomplished with the Serialx.on with a write to the oppositng port. I could also put them to a loopback too, I suppose. Right now I've got the xterminal going with USB as my kind of watch port.
    2. What you're suggesting, which is pretty great actually.
    3. A little more autonomous functionality that I could call a send so that higher level functions could be implemented for bigger things such as socket dials.

    Having trouble with #3 right now. Any particular reason this wouldn't work? Right now it's like if I sent anything to the port I can't loop and read or check availability from that port in waiting, it needs to come back to the terminal or I need to utilize setTimeout.

    function Test(inSTR, timeOut) {
      var TO=getTime() + timeOut; //set timeout in seconds
    
      Serial6.println(inSTR);
    
      while (getTime() < TO) {
        if (Serial6.available() > 0) {
          console.log("Success.");
          return 1;
          }
      }
      return -1;
    }
    

    So Test('AT+CREG?',2) simply comes back with a timeout in this case.

    This is probably something silly that I'm not taking into account.

    I've tried implementing other options such as using a Serial6.on to just parse and put to a buffer, but I'm having trouble with what appears to be scoping (my JS is awful, kind of learning as I go).

Actions