Category Archives: Uncategorized

Array anxiety

Today I was going to create an array into which I would write handles to all existing game objects in the scene. So So I created all the functions I needed to create the array, find a free slot, add and remove game objects into the array, and a debug function to verify consistency.

What I found with the debug function was really strange though!

So I created the array, filled it with -1 (to indicate unused array entries) and printed the array. All entries came out -1, as expected.

Then I wrote the number 3 into the first entry of the array. I was expecting that all the other entries in the array would remain untouched, so I expected them all to be -1. But when I printed the entries they had all been set to 0. Very strange!

So I did an experiment. I only wrote the number 6 into the sixth entry in the array. The result was that entry 0-5 had kept their values, so they were -1. The sixth entry had the value 6. All the following entries had the value 0.

I started suspecting that WRITE_CONTENT would fill the rest of the array with garbage so my next experiment was to first write the value 7 into index 7, and value 6 into index 6. As expected the array was -1 up to entry 5, entry 6 had the value 6 and all following entries was 0. I was onto something.

However, my next test would confuse me. My next test sequence was:
Write value 6 into entry 6
Write value 5 into entry 5
Write value 7 into entry 7
Because my theory was that WRITE_CONTENT was writing trailing zeroes whenever I wrote something to the array I expected the array to look like:
-1
-1
-1
-1
-1
5
0
7
0..

But instead the array was:
-1
-1
-1
-1
-1
5
6
7
0..

So now it looked like the array worked properly.

I went back to writing 6 to 6 and 5 to 5, and it didn’t work.

I had a few ideas of what it could be but none of them fitted and I couldn’t really find a pattern to what was going on. My next test sequence was
Write 0 to entry 0
Write 6 to entry 6
Write 5 to entry 5
Write 7 to entry 7

The result looked like this:
1
-1
-1
-1
33
5
6
7
0..

Now a completely random (to me) value had appeared in the array. 33.

It was a this point I gave up and started looking at the source. I’m generally too lazy to look at the source, but sometimes things just doesn’t make sense I don’t have any choice. So this is the source:

    case WRITE_CONTENT :
    {
      PrgId           =  *(DATA16*)PrimParPointer();
      TmpHandle       =  *(DATA16*)PrimParPointer();
      Index           =  *(DATA32*)PrimParPointer();
      Bytes           =  *(DATA32*)PrimParPointer();
      pDData8         =  (DATA8*)PrimParPointer();

      DspStat         =  FAILBREAK;

#ifdef DEBUG
      printf("ARRAY WRITE_CONTENT CP=%d PP=%d\r\n",TmpPrgId,PrgId);
#endif

      if (PrgId == (PRGID)CURRENT_SLOT)
      {
        PrgId         =  TmpPrgId;
      }

      if (cMemoryGetPointer(PrgId,TmpHandle,&pTmp) == OK)
      {
        ElementSize   =  (DATA32)(*(DESCR*)pTmp).ElementSize;
        if (ElementSize)
        {
          Elements      =  (Index + Bytes + (ElementSize - 1)) / ElementSize;
          ISize         =  Elements * ElementSize;

          pTmp          =  cMemoryResize(PrgId,TmpHandle,Elements);
          if (pTmp != NULL)
          {
            if ((Index >= 0) && (pDData8 != NULL))
            {
              pData8      =  (DATA8*)pTmp;
              Data32      =  0;

              while ((Data32 < Bytes) && (Index < ISize))
              {
                pData8[Index]   =  pDData8[Data32];
                Data32++;
                Index++;
              }
              DspStat     =  NOBREAK;
            }
          }
        }
      }
    }
    break;

The keen of you will notice there is a cMemoryResize() call in there. I was naïvely assuming it would only resize the array if Elements was too great to fit all the data to be written to the array, but I looked into it just to be safe.

void*     cMemoryResize(PRGID PrgId,HANDLER TmpHandle,DATA32 Elements)
{
  DATA32  Size;
  void    *pTmp = NULL;


  if (cMemoryGetPointer(PrgId,TmpHandle,&pTmp) == OK)
  {
    Size    =  Elements * (*(DESCR*)pTmp).ElementSize + sizeof(DESCR);
    pTmp    =  cMemoryReallocate(PrgId,TmpHandle,(GBINDEX)Size);
    if (pTmp != NULL)
    {
      (*(DESCR*)pTmp).Elements  =  Elements;
    }

#ifdef DEBUG
    printf("  Resize P=%1u H=%1u T=%1u S=%8lu A=%8p\r\n",(unsigned int)PrgId,(unsigned int)TmpHandle,(unsigned int)MemoryInstance.pPoolList[PrgId][TmpHandle].Type,(unsigned long)MemoryInstance.pPoolList[PrgId][TmpHandle].Size,MemoryInstance.pPoolList[PrgId][TmpHandle].pPool);
#endif
  }
  if (pTmp != NULL)
  {
    pTmp  =  (*(DESCR*)pTmp).pArray;
  }

  return (pTmp);
}

As you can see it always go to cMemoryRealloc() so let’s have a look at that

void*     cMemoryReallocate(PRGID PrgId,HANDLER Handle,GBINDEX Size)
{
  void    *pTmp;

  pTmp  =  NULL;
  if ((PrgId < MAX_PROGRAMS) && (Handle >= 0) && (Handle < MAX_HANDLES))
  {
    if ((Size > 0) && (Size <= MAX_ARRAY_SIZE))
    {
      if (cMemoryRealloc(MemoryInstance.pPoolList[PrgId][Handle].pPool,&pTmp,(DATA32)Size) == OK)
      {
        MemoryInstance.pPoolList[PrgId][Handle].pPool  =  pTmp;
        MemoryInstance.pPoolList[PrgId][Handle].Size   =  Size;
      }
      else
      {
        pTmp  =  NULL;
        printf("cMemoryReallocate out of memory\r\n");
      }
    }
  }
#ifdef DEBUG
  if (pTmp != NULL)
  {
    printf("  Reallocate  P=%1u H=%1u     S=%8lu A=%8p\r\n",(unsigned int)PrgId,(unsigned int)Handle,(unsigned long)Size,MemoryInstance.pPoolList[PrgId][Handle].pPool);
  }
  else
  {
    printf("  Reallocate error P=%1u H=%1u S=%8lu\r\n",(unsigned int)PrgId,(unsigned int)Handle,(unsigned long)Size);
  }
#endif

  return (pTmp);
}

This in turn is also just doing some sanity checks before entering cMemoryRealloc()

RESULT    cMemoryRealloc(void *pOldMemory,void **ppMemory,DATA32 Size)
{
  RESULT  Result = FAIL;

  *ppMemory  =  realloc(pOldMemory,(size_t)Size);
  if (*ppMemory != NULL)
  {
    Result  =  OK;
  }

  return (Result);
}

As you can see cMemoryRealloc always go to stdlib realloc.

Soo, if I’m not missing anything, WRITE_CONTENT will ALWAYS reallocate the array, and use the realloc() call to move data from the old block to the new. So that explains a lot.

I don’t have a plan for how to handle arrays yet, but it seems like arbitrarily writing into an array isn’t supported by the VM. I will have to dig in deeper to see if there are any work arounds, but it seems like writing to an array isn’t as straight forward as I would have hoped.

I’m still not on top of the LMS syntax but I have the @ and & in mind. Perhaps they can be of help here. Maybe I don’t have to use the bulky READ_CONTENT and WRITE_CONTENT, maybe those are just for writing big amounts of data into an array. I still think I need to use arrays to allocate memory though.

Trying out handles and addresses will be my next project!

Using arrays

For my little game I will be using arrays to represent game objects. I figured I want some sort of object oriented game where I could create a Game Object and use functions to manipulate it.

Since I’m looking to do a top down adventure game I want to build rooms and in each room I want to have objects like enemies, pickups, the player etc. So to do I want to easily be able to manage a bunch of different game objects.

I want something like this (pseudo code)

hGameObject = GameObject_Create()
GameObject_SetPosition( hGameObject, 0, 0 )
GameObject_Render( hGameObject )

Since LMS doesn’t have the concept of complex data structures I figured I could do something like that using arrays. So my principle is simple. A game object is an array of 16 bit values. Each value represent a handle to a component. A component can hold different kinds of data, depending on what the component is.

For example a component can be the world position of the game object, it can be a sprite to be rendered, it may be AI information, it could be an inventory etc. This type of component based game objects is common in the world of making games, and if you’re used to Unity you will immediately recognize what I’m going for. I’ve even borrowed the component names when it makes sense. I’m just that used to Unity. :)

So I created an array like so:

ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

And I created my first component, the Transform component, and added it to my game object like so:

HANDLE  hTransform
ARRAY( CREATE16, 2, hTransform )
ARRAY( WRITE_CONTENT, -1, hTransform, 0, 2, 0 )
ARRAY( WRITE_CONTENT, -1, hTransform, 1, 2, 0 )
ARRAY( WRITE_CONTENT, -1, hGameObject, 0, 2, hTransform )

This was all fine and dandy. So I added my second component, the sprite.

ARRAY( WRITE_CONTENT, -1, hGameObject, 1, 2, hSprite )

The code was spread out in different functions but all in all it looked (something like) this:

subcall GameObject_Create
{
  IN_16   hSprite       // The sprite that the game object should use for rendering
  OUT_16  hGameObject   // The handle this function will create

  // Create root array that will hold handles to all components
  ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

  // Add transform
  HANDLE  hTransform
  ARRAY( CREATE16, 2, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, 0, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hTransform, 1, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hGameObject, 0, 2, hTransform )

  // Add sprite
  ARRAY( WRITE_CONTENT, -1, hGameObject, 1, 2, hSprite )
}

But now the angst begun.

When I read the handle of the transform array I got strange results. I had written 4 to index 0, and when I read I got 772 back. At first I believed the problem was because I wrote 4 in one function and read it back in another function.

After some investigation it turned out that the index for READ_CONTENT and WRITE_CONTENT was the array offset in bytes, not the index based on the size of the array elements. I thought that if I asked to read from index 1 in an array with 16 bit elements the byte offset would be translated to 2, but alas it was not! And to my embarrassment it even say in the code that the index is in bytes, not in elements.

 *  - CMD = READ_CONTENT
 *    -   \param  (DATA16)  PRGID     - Program slot number (must be running) (see \ref prgid)\n
 *    -   \param  (HANDLER) HANDLE    - Array handle\n
 *    -   \param  (DATA32)  INDEX     - Index to first byte to read\n
 *    -   \param  (DATA32)  BYTES     - Number of bytes to read\n
 *    -   \return (DATA8)   ARRAY     - First byte of array to receive data\n
 *
 *\n
 *  - CMD = WRITE_CONTENT
 *    -   \param  (DATA16)  PRGID     - Program slot number (must be running) (see \ref prgid)\n
 *    -   \param  (HANDLER) HANDLE    - Array handle\n
 *    -   \param  (DATA32)  INDEX     - Index to first byte to write\n
 *    -   \param  (DATA32)  BYTES     - Number of bytes to write\n
 *    -   \param  (DATA8)   ARRAY     - First byte of array to deliver data\n

So to get it to work I had to write the code like this:

subcall GameObject_Create
{
  IN_16   hSprite       // The sprite that the game object should use for rendering
  OUT_16  hGameObject   // The handle this function will create

  // Create root array that will hold handles to all components
  ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

  // Add transform
  HANDLE  hTransform
  ARRAY( CREATE16, 2, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, 0, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hTransform, 2, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hGameObject, 0, 2, hTransform )

  // Add sprite
  ARRAY( WRITE_CONTENT, -1, hGameObject, 2, 2, hSprite )
}

That way it worked beautifully. On top of that I also have constants that define the read and write offset of transform. So the whole game object code currently look like this:

/**************************************************************************************************
*
*   Game object functions
*
* Game objects will have a component like structore
* A game object will basically be an array of arrays
* It will be decided what goes in each array
* For example, the first array may contain the transform information such as position
* The second array may contan sprite data, so a reference to a loaded sprite.
*   (Assuming multiple game object may reference the same sprite)
* The third array may contain animation data, such as current frame, time in current frame
* Each array will be defined individually
*
* So, we will create an array of 16 bit values.
* GAMEOBJECT = new DATA16[];
*
* The we will create each "component"
* GAMEOBJECT[ 0 ] = new DATA32[];
*
* The we can populate each component with data
* GAMEOBJECT[ 0 ][ 0 ] = position_x;
*
* The indices will have constants, to make it easier to remember the contents
* GAMEOBJECT[ Transform ][ world_x ] = position_x;
*
* If we would see the multidimensional array as a JSON it would look like this:
* GAMEOBJECT =
* {
*   Transform =     // index 0
*   {               //
*     world_x,      //   index 0
*     world_y       //   index 1
*   },              //
*   Sprite =        // index 1
*   {               //
*     Reference to  //
*     loaded sprite //
*   },
*   Animation =     // index 2
*   {               //
*     frame_time,   //    index 0
*     current_frame //    index 1
*   }
* }
*
**************************************************************************************************/
define COMPONENT_TRANSFORM          0
define COMPONENT_SPRITE             2
define COMPONENT_ANIMATION          4
define NUM_COMPONENTS               3

subcall GameObject_Create
{
  IN_16   hSprite       // The sprite that the game object should use for rendering
  OUT_16  hGameObject   // The handle this function will create

  // Create root array that will hold handles to all components
  ARRAY( CREATE16, NUM_COMPONENTS, hGameObject )

  // Create each component
  CALL( GameObject_AddComponent_Transform, hGameObject )
  CALL( GameObject_AddComponent_Sprite, hGameObject, hSprite )
}

subcall GameObject_AddComponent_Transform
{
  IN_16   hGameObject

  HANDLE  hTransform
  ARRAY( CREATE16, 2, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_X, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_Y, 2, 0 )
  ARRAY( WRITE_CONTENT, -1, hGameObject, COMPONENT_TRANSFORM, 2, hTransform )
}

subcall GameObject_AddComponent_Sprite
{
  IN_16   hGameObject
  IN_16   hSprite

  ARRAY( WRITE_CONTENT, -1, hGameObject, COMPONENT_SPRITE, 2, hSprite )
}

subcall GameObject_GetComponent
{
  IN_16   hGameObject
  IN_32   ComponentIndex
  OUT_16  hComponent

  ARRAY( READ_CONTENT, -1, hGameObject, ComponentIndex, 2, hComponent )
}

/**************************************************************************************************
*
*   Transform functions
*
**************************************************************************************************/
define TRANSFORM_X      0
define TRANSFORM_Y      2
subcall Transform_SetPosition
{
  IN_16     hGameObject
  IN_16     PositionX
  IN_16     PositionY

  HANDLE  hTransform
  CALL( GameObject_GetComponent, hGameObject, COMPONENT_TRANSFORM, hTransform )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_X, 2, PositionX )
  ARRAY( WRITE_CONTENT, -1, hTransform, TRANSFORM_Y, 2, PositionY )

  DATA16 temp
  ARRAY( READ_CONTENT, -1, hTransform, TRANSFORM_X, 2, temp )
  CALL( WriteLog16, 'org  pos x: ', PositionX )
  CALL( WriteLog16, 'read pos x: ', temp )
}

subcall Transform_GetPosition
{
  IN_16     hGameObject
  OUT_16    PositionX
  OUT_16    PositionY

  HANDLE  hTransform
  CALL( GameObject_GetComponent, hGameObject, COMPONENT_TRANSFORM, hTransform )
  ARRAY( READ_CONTENT, -1, hTransform, TRANSFORM_X, 2, PositionX )
  ARRAY( READ_CONTENT, -1, hTransform, TRANSFORM_Y, 2, PositionY )
}

And you can use the game object code like this:

  HANDLE hSprite
  CALL( Sprite_Create, 'spritetest.spr', hSprite )

  HANDLE hHero
  CALL( GameObject_Create, hSprite, hHero )
  CALL( Transform_SetPosition, hHero, 32760, 32761 )

(And here is the code to load and render sprites. The new and improved version)

/**************************************************************************************************
*
*   Graphics functions
*
**************************************************************************************************/
subcall Sprite_Create
{
  IN_S    FileName     128
  OUT_16  SpriteHandle

  HANDLE hFile
  DATA32 FileSize32

  FILE( OPEN_READ, FileName, hFile, FileSize32 )
  ARRAY( CREATE8, FileSize32, SpriteHandle )
  CALL( File_ReadToArray, hFile, SpriteHandle, FileSize32 )
  FILE( CLOSE, hFile )
}

subcall Sprite_Draw
{
  IN_16   SpriteDataHandle
  IN_16   ScreenX
  IN_16   ScreenY

  DATA8   SpriteWidth
  DATA8   SpriteHeight
  DATA32  ReadOfs
  DATA16  WriteX
  DATA16  WriteY
  DATA16  MaxX
  DATA16  MaxY
  DATA8   ReadPixel
  DATA8   WritePixel

  // Read sprite dimensions
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, 0, 1, SpriteWidth )
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, 1, 1, SpriteHeight )

  // Setup
  MOVE8_16( SpriteWidth, MaxX )
  ADD16( MaxX, ScreenX, MaxX )

  MOVE8_16( SpriteHeight, MaxY )
  ADD16( MaxY, ScreenY, MaxY )

  // The whole thing
  MOVE32_32( 2, ReadOfs )
  MOVE16_16( ScreenY, WriteY )

Loop_Y:
  MOVE16_16( ScreenX, WriteX )

Loop_X:
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, ReadOfs, 1, ReadPixel )
  JR_EQ8( ReadPixel, 0, DoneDrawing )   // Don't do any drawing at all
  JR_EQ8( ReadPixel, 1, DrawBlack )
  MOVE8_8( BG_COLOR, WritePixel )       // Set WritePixel to White
  JR( Draw )

DrawBlack:
  MOVE8_8( FG_COLOR, WritePixel )       // Set WritePixel to Black

Draw:
  UI_DRAW( PIXEL, WritePixel, WriteX, WriteY )

DoneDrawing:
  ADD32( ReadOfs, 1, ReadOfs )
  ADD16( WriteX, 1, WriteX )
  JR_LT16( WriteX, MaxX, Loop_X )

  ADD16( WriteY, 1, WriteY )
  JR_LT16( WriteY, MaxY, Loop_Y )
}

So the lesson of the day is, when you are reading from and writing to arrays, the index is in bytes, not in elements.

Sprites to the people!

I’ve done quite a lot of programming today, and I’ve got to say the new tool that automatically compile and download to the Brick is awesome! I’ve also made it so it automatically starts the downloaded program, so it is a real time saver!

In any case, besides modifying the tool so it also starts the downloaded app, I’ve also made an image converted that can output sprites with transparency, and I’ve made a function that read the sprite and draws it on screen on the Brick.

Look!sprites

As you can see there’s a character sprite that are drawn in two different places in this example, and it has three colors. Black, white and transparent.

This is the code to load the sprite:

  HANDLE hFile
  DATA32 FileSize32
  DATA8 BombWidth
  DATA8 BombHeight

  HANDLE BombData
  FILE( OPEN_READ, 'spritetest.spr', hFile, FileSize32 )
  FILE( READ_BYTES, hFile, 1, BombWidth )
  FILE( READ_BYTES, hFile, 1, BombHeight )
  SUB32( FileSize32, 2, FileSize32 )
  ARRAY( CREATE8, FileSize32, BombData )
  CALL( File_ReadToArray, hFile, BombData, FileSize32 )
  FILE( CLOSE, hFile )
subcall File_ReadToArray
{
  IN_16   FileHandle
  IN_16   ArrayHandle
  IN_32   BytesToRead

  DATA8   TempData
  DATA32  WriteIndex

  MOVE32_32( 0, WriteIndex )

Loop:
  FILE( READ_BYTES, FileHandle, 1, TempData )
  ARRAY( WRITE_CONTENT, -1, ArrayHandle, WriteIndex, 1, TempData )
  ADD32( WriteIndex, 1, WriteIndex )
  JR_LT32( WriteIndex, BytesToRead, Loop )
}

As you can see I’ve created a helper function that take a file handle and load it into an array. I am planning on making a function that accept a filename and return an array handle to completely wrap it up, but in this case I want to read the width and height of the image before reading the rest into an array.

I was also planning on reading the width and height as 16 bit values so a sprite can be bigger than 127 but then I figured I want to have a function that is something like ReadSprite, and it would return a single handle for me to use, and ten I could use that handle with a function like DrawSprite, and the handle would hold both width, height and pixel data.

If I try to do that I would create two arrays. One array would be with three 16 bit numbers, and the first number would be width, second number would be height, and third number would be a handle to an 8 bit array that holds the pixel data. Kinda like a little object. :)

Anyways, here is the code that draws the sprite:

subcall DrawSprite
{
  IN_8    SpriteWidth
  IN_8    SpriteHeight
  IN_16   SpriteDataHandle
  IN_16   ScreenX
  IN_16   ScreenY

  DATA32  ReadOfs
  DATA16  WriteX
  DATA16  WriteY
  DATA16  MaxX
  DATA16  MaxY
  DATA8   ReadPixel
  DATA8   WritePixel

  // Setup
  MOVE8_16( SpriteWidth, MaxX )
  ADD16( MaxX, ScreenX, MaxX )

  MOVE8_16( SpriteHeight, MaxY )
  ADD16( MaxY, ScreenY, MaxY )

  // The whole thing
  MOVE32_32( 0, ReadOfs )
  MOVE16_16( ScreenY, WriteY )

Loop_Y:
  MOVE16_16( ScreenX, WriteX )

Loop_X:
  ARRAY( READ_CONTENT, -1, SpriteDataHandle, ReadOfs, 1, ReadPixel )
  JR_EQ8( ReadPixel, 0, DoneDrawing )   // Don't do any drawing at all
  JR_EQ8( ReadPixel, 1, DrawBlack )
  MOVE8_8( BG_COLOR, WritePixel )       // Set WritePixel to White
  JR( Draw )

DrawBlack:
  MOVE8_8( FG_COLOR, WritePixel )       // Set WritePixel to Black

Draw:
  UI_DRAW( PIXEL, WritePixel, WriteX, WriteY )

DoneDrawing:
  ADD32( ReadOfs, 1, ReadOfs )
  ADD16( WriteX, 1, WriteX )
  JR_LT16( WriteX, MaxX, Loop_X )

  ADD16( WriteY, 1, WriteY )
  JR_LT16( WriteY, MaxY, Loop_Y )
}

Back on track

The idea for this blog was to write about using the LMS programming language on the EV3 Brick and to have a test project to go along with it but the last couple of updates have been about building the DC adapter. It is finally done so I can resume the LMS experimenting. Wohoo!

So I know how to draw RGF files to screen, but RGF files doesn’t allow any transparency. So I’m going to create my own image format that allow transparency. The format will be very simple and adapted for using with the LMS2012 VM.

The first 16 bytes will hold the width of the image, the next 16 bits the height, and every byte from there on will represent a pixel in the image. That’ll be easy enough to parse and draw on the VM.

Even though the EV3 is a 300MHz ARM based Linux computer I am worried about performances, especially since each draw pixel is writing to a bit mask, so I will be looking into the UI STORE command that will store a copy of the screen into a buffer for later use. My plan is to draw up the background for a room, but with only the static elements, and store that into a buffer.

I was considering adding animation to the background too. The VM support up to 3 stored buffers, so it will need to be 3 frames of animation tops. Bit of an odd number to use for animations, but we’ll see. If the Brick is fast enough maybe I don’t have to store each background frame.

Anyways, off to write a sprite converter.

Toodles!

That workflow

So I’ve been mainly using the LabVIEW Mindstorms tool to transfer my compiled apps from my computer to the Brick, but a while ago I found the MonoBrick C# library. It looked and worked great. I could use it to browse the files on my device over Bluetooth, but because it required Bluetooth I didn’t feel comfortable having the Brick running for extended periods of time while I was trying to wrap my head around Xamarin and MonoBrick.

But now that I’ve fixed the DC adapter I don’t mind having that beautiful Brick of mine running all day long, so today I’ve actually fixed a tool that greatly improves my workflow.

It looks like this!filesync2

 

There are two important parts to this tool.

1. It starts compilation of LMS files to RBF files, or conversion of an image to an RGF file
2. It download the compiled RBF or converted RGF to the Brick using MonoBrick

So before I had to first go to my shell and start java to compile, and then to go the Mindstorms tool to transfer the file, and there where a lot of switching apps, typing and click. Now there is only one app switch and one click, and my program will compile the program and download the compiled app, if the compilation was successful, onto the Brick.

So iterating on things have gone from super cumbersome to super smooth!

I intend to add another important part to the tool, and that is to automatically download and display the log from the Brick, but that’s for later.

If anyone is interested I’d be more than happy to send this program to you. It is written in C# for OSX, so I assume it would be quite tricky to port to Windows, but if anyone is interested then by all means, contact me and we can sort something out!

The final adapter

I had grand plans for my DC adapter. I was going to make a carving out of wood onto which I would attach metal plates that would connect with the Brick where the batteries should really connect, and then I could simply insert and remove the wooden carving and the metal plates would slip into place.

But that didn’t happen.

Instead I ended up going with a refined version of my initial prototype, two paper clips that I soldered into two wires. So that’s what I’ve been doing today. For a bit my desk looked like this:
bild 1-2

 

After some rude words and frustration I ended up with a Brick that look like this from the backside!bild-9

And from the front it looks like this.bild 2-2

 

So now I’ve solved my battery problem for a while and I don’t have to worry about having Bluetooth or Wifi drain my batteries. Yay!

I have absolutely no idea if this is good for the Brick in the long run though, but the battery indicator is showing something that looks about right, and it is still running after a few hours, so I’m assuming it is ok.

AC/DC

A couple of days ago I purchased a DC adapter with a variable DC voltage output, and today I finally got around to connecting it to my Brick. It was scary but worked out beautifully. Look!bild 1

And this is what it will look like on the backside.bild 2

 

It’s just a proof that it is possible, so next step is to make it prettier.  :)  <3

Measurements of electrical current

So I’ve done some measurements on amperes used in various situations on the EV3.

My main takeaway is that once you’ve done something the Brick will need more power, even though you’ve shut down or disconnected the thing that needed more power.

The unit used for my figures is mA and the multimeter I used could only go up to 200 mA so that’s why a lot of the measurements only say >200. That means the Brick was using more than 200 mA. So here are my measurements:

Booting the Brick: Varying between 100 to >200
Idle: 120
Running my Arholma app: 100-110
Running my transparency app: 100-115

Bluetooth active but not paired: 120
Bluetooth pairing/paired: 130
Bluetooth paired and running commander: 115-160
Bluetooth disconnected: 135
Bluetooth disabled: 135

Pairing computer
Searching: 145
Pairing question: 145
Paired with computer: 134
Connected in labview: 138
Memory browsing: 138-140
Downloading file: 140

Shutting down: 100

Idle after reboot: 120
Wifi inserted: 145
Wifi starting: Peak >200, land at 151
Wifi connections: Peak >200, land at 154
Connecting to our wifi: Peak >200, land at 194
Connect to Brick via telnet: >200
Logged in: 197-199
Start SSH service on the Brick: >200
After shutting off wifi: 149
After unplugging the wifi dongle: 127

Idle after reboot: 125
Connected big motor: 139
Motor control app: 142
Running big motor: >200
After running big motor once: 167
After shutting down motor control app: 138
Disconnected big motor: 129

Connected touch sensor: spike 135, land at 130
Touching touch sensor without any app listening: 131
Started port view: 132
Touching in port view: 130
Exiting port view: 129
Disconnected touch sensor: 129

Connected light sensor: spike 140, land 138
Starting port view: 139-140
Exiting port view: 138
Disconnected light sensor: 129

Connected ir: spike 139, land 137
Started port view: 138
Using IR sender: 140
Exit port view: 138
Disconnect ir sensor: 129

Idle: 135
Connected small motor: spike 145, land 143
Started motor control: 140
Running small motor: >200
After running small motor: 167
Exit motor control: 140
Disconnect small motor: 135

Drained batteries and test art

Hello my lovely Lego friends!

There haven’t been a lot of updates in a while. Mostly life things been happening. There have been two threads running in my heads though.

  1. Creating an AC adapter for my EV3
  2. Ideas for the game I want to make

Thread 1: An AC adapter

So I noticed when plugging my wifi dongle into the EV3 that the batteries got drained quicker than .. something that gets drained really fast. Like. A drain pipe that have just been cleaned. Anyways, so I’ve been thinking about creating my own AC adapter. I figure it shouldn’t be more difficult than finding an AC adapter that matches the voltage and electric current of 6 AA-batteries.

The voltage is easy enough, it’s just 1.5V * 6 batteries, so 9V.

The current is tricker. I understand that the current of my AC adapter will decide the limit that the EV3 can get, and it will not force more current onto the Brick, so I could just get an adapter that provide a whole lot of current. But I want to be at least in the ballpark of what the EV3 needs. So I’ve gotten hold of a multimeter. (I’ve had to look up the english translation for these electrical terms, and I’ve got to say, I’m a bit disappointed that a multimeter is called a multimeter in English too)

So I’m planning on plugging the multimeter between the last battery and the device and see how much current it consume under different circumstances like idle, with motors running and with sensors running. So that’ll be fun! I’ll let you peeps know my findings.

Thread 2: Ideas for the game

I don’t really want to give too much away yet. Not that I’m aiming to make an announcement or anything, but I’d like to have the idea a little bit more concrete before I say anything. But I will show you another picture. This time I’ve been working on a test scene. Some parts of the image I’m happy with and some parts not so much. In any case, here it is:

Test scene

Splash screen and image converter

All this experimenting needs to lead somewhere. I am doing it partly to learn a new platform and partly because I want to make a game for it. I am not sure how to incorporate all the motors and sensor into the game, but I want them to be there somehow. Why bother making the game for the EV3 if I don’t use any of the hardware.

Anyways, I’ve started with the most essential part of the game. The splash screen. :)Game splash pt. 1

To get it onto the Brick I also created an image converter, that can read any file that SDL supports and create an RGF file.

The RGF file format is dead simple. First there are two unsigned byte, one for width and one for height of the image. Then each pixel in the image is stored in a bit. So 8 pixels are stored in 1 byte. Left most pixel is stored in the least significant bit, and rightmost pixel is stored in most significant bit.

This is the source I ended up writing. As you can see I have a hardcoded string for the in and out file names instead of using argv[1] and argv[2], but .. you know. Gotta keep stuff that can be improved. :)

//
//  main.cpp
//  bmpconverter
//
//  Created by Magnus Runesson on 2014-08-17.
//  Copyright (c) 2014 Magnus Runesson. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "CImage.h"

int main(int argc, const char * argv[])
{
    CImage* pImage = new CImage( "splashfont2.png" );

    int outwidth = pImage->m_Width>>3;
    if( pImage->m_Width&7 )
        outwidth++;
    int outsize = outwidth * pImage->m_Height;
    
    unsigned char* outpixels = new unsigned char[ outsize ];

    int x, y;
    int readx;
    int writex;
    int inofs = 0;
    for( y=0; y<pImage->m_Height; y++ )
    {
        readx = pImage->m_Width;
        for( writex=0; writex<outwidth; writex++ )
        {
            int readpixelcount = 8;
            if( writex == outwidth-1 )
                readpixelcount = readx;
            readx -= readpixelcount;
            
            int outofs = (y*outwidth) + writex;

            unsigned char outbyte = 0;
            
            int i;
            for( i=0; i<readpixelcount; i++ )
            {
                unsigned char r = pImage->m_aPixels[ inofs + 0 ];
                unsigned char g = pImage->m_aPixels[ inofs + 1 ];
                unsigned char b = pImage->m_aPixels[ inofs + 2 ];
                unsigned char a = pImage->m_aPixels[ inofs + 3 ];
                
                inofs += 4;
                
                if( a > 127 )
                {
                    if( r < 127 )
                        outbyte |= (1<<i);
                }
            }
            
            outpixels[ outofs ] = outbyte;
        }
    }

    FILE* fout = fopen("splashfont2.rgf", "wb");
    unsigned char widthub = pImage->m_Width;
    unsigned char heightub = pImage->m_Height;
    fwrite( &widthub, 1, 1, fout );
    fwrite( &heightub, 1, 1, fout );
    fwrite( outpixels, 1, outsize, fout);
    fclose(fout);
    
    return 0;
}

So as long as you can read a file into a 32 BPP array in the order I read them you can pretty much plug any image reader into this.

I use SDL for reading images. Here is my CImage class

/*
 *  CImage.h
 *
 *  Created by Magnus Runesson on 1/28/12.
 *  Copyright 2012 Pokewhat. All rights reserved.
 *
 */

#pragma once

class SDL_Surface;

class CImage
{
public:
    CImage(const char* _pszFileName);
    CImage(CImage* _pReference, CImage* _pDiff);
    CImage(unsigned char* _aPixels, int _w, int _h);
    ~CImage();
    void SaveRAW(const char* _pszFileName);

private:
    unsigned int GetRGBA(SDL_Surface* _pSurface, int _x, int _y);
    void LoadSDL(const char* _pszFileName);

public:
    unsigned char* m_aPixels;
    char* m_pszFileName;
    int m_Width, m_Height;
};
/*
 *  CImage.cpp
 *
 *  Created by Magnus Runesson on 1/28/12.
 *  Copyright 2012 Pokewhat. All rights reserved.
 *
 */

#include "CImage.h"
#include "SDL_Image/SDL_Image.h"

void* fileRead(const char* _pszFileName, int* _pDatasize);
void fileWrite(const char* _pszFileName, void* _pImageData, int _Length);
void _fileFree(void* _pData, const void* _pReadData, size_t _Size);

void* fileRead(const char* _pszFileName, int* _pDatasize)
{
    FILE* f = fopen(_pszFileName, "rb");
    if( !f )
        return NULL;
    
    fseek(f, 0, SEEK_END);
    int size = ftell(f);
    fseek(f, 0, SEEK_SET);
    
    void* pRet = malloc(size);
    
    fread(pRet, 1, size, f);
    fclose(f);
    
    *_pDatasize = size;
    return pRet;
}

void fileWrite(const char* _pszFileName, void* _pImageData, int _Length)
{
    FILE* f = fopen(_pszFileName, "wb");
    fwrite(_pImageData, 1, _Length, f);
    fclose(f);
}

void _fileFree(void* _pData, const void* _pReadData, size_t _Size)
{
    free(_pData);
}



CImage::CImage(const char* _pszFileName)
{
    m_aPixels = NULL;
    LoadSDL( _pszFileName );
}

CImage::CImage(unsigned char* _aPixels, int _w, int _h)
{
    m_Width = _w;
    m_Height = _h;

    int size = _w*_h*4;
    m_aPixels = new unsigned char[size];
    
    memcpy(m_aPixels, _aPixels, size);
}

CImage::~CImage()
{
    delete[] m_aPixels;
    m_aPixels = NULL;
}

unsigned int CImage::GetRGBA(SDL_Surface* _pSurface, int _x, int _y)
{
    SDL_PixelFormat* pFormat = _pSurface->format;
    int readofs = (_y * (_pSurface->w)) + _x;
    int r,g,b,a;
    if( _pSurface->format->BytesPerPixel == 2 )
    {
        unsigned short* pData = (unsigned short*)_pSurface->pixels;
        r = ((pData[readofs]&pFormat->Rmask) >> pFormat->Rshift);
        g = ((pData[readofs]&pFormat->Gmask) >> pFormat->Gshift);
        b = ((pData[readofs]&pFormat->Bmask) >> pFormat->Bshift);
        r *= (255/15);
        g *= (255/15);
        b *= (255/15);
        
        if( pFormat->Amask )
        {
            a = ((pData[readofs]&pFormat->Amask) >> pFormat->Ashift);
            a *= (255/15);
        } else
        {
            a = 255;
        }
    }
    else if( _pSurface->format->BytesPerPixel == 4 )
    {
        unsigned int* pData = (unsigned int*)_pSurface->pixels;
        r = ((pData[readofs]&pFormat->Rmask) >> pFormat->Rshift);
        g = ((pData[readofs]&pFormat->Gmask) >> pFormat->Gshift);
        b = ((pData[readofs]&pFormat->Bmask) >> pFormat->Bshift);
        if( pFormat->Amask )
        {
            a = ((pData[readofs]&pFormat->Amask) >> pFormat->Ashift);
        } else {
            a = 255;
        }
    } else
    {
        unsigned char* pData = (unsigned char*)_pSurface->pixels;
        r=pData[readofs*4+0];
        g=pData[readofs*4+1];
        b=pData[readofs*4+2];
        a=pData[readofs*4+3];
    }

    unsigned int ret = (r<<24) + (g<<16) + (b<<8) + a;
    return ret;
}

void CImage::LoadSDL(const char* _pszFileName)
{
    m_pszFileName = strdup(_pszFileName);
    SDL_Surface* pSurface = IMG_Load(_pszFileName);
    if( pSurface == NULL )
    {
        printf("Failed to load texture '%s'\n", _pszFileName);
        return;
    }

    int src_width = pSurface->w;
    int src_height = pSurface->h;

    m_Width = src_width;
    m_Height = src_height;
    
    // Allocated memory needed for the bitmap context
    int texelsSize = m_Width * m_Height * 4;
    m_aPixels = new unsigned char[texelsSize];
    memset(m_aPixels, 0, texelsSize);

    // Convert image to texture
    int x, y;
    for( y=0; y<src_height; y++ )
    {
        for( x=0; x<src_width; x++ )
        {
            unsigned int rgba = GetRGBA(pSurface, x, y);
            int writeofs = (y*m_Width)+x;
            writeofs *= 4;    // 4 bytes per pixel in all of our textures
            m_aPixels[writeofs++] = (rgba>>24) & 0xff;
            m_aPixels[writeofs++] = (rgba>>16) & 0xff;
            m_aPixels[writeofs++] = (rgba>>8) & 0xff;
            int alpha = (rgba) & 0xff;
            m_aPixels[writeofs++] = alpha;
            //int a = (alpha & 0x80) != 0;
            //m_aCollisionMask[collwriteofs] = a;
        }
    }

    //
    SDL_FreeSurface(pSurface);
}

void CImage::SaveRAW(const char* _pszFileName)
{
    FILE* f = fopen(_pszFileName, "w");
    fwrite(m_aPixels, 1, m_Width*m_Height*4, f);
    fclose(f);
}

That image reader have a hack that I’m not proud of. The images that SDL read for me all had bits per pixel, bytes per pixel and the palette set to 0, so in the GetRGBA() method I simply just read 32 bpp RGBA colours if SDL doesn’t report a specific format. Because you know .. this isn’t what I want to spend time on. :)