Premise Betabrite electronic sign with Premise?

Motorola Premise

etc6849

Senior Member
I found two of these things at a garage sale today for $15 total. They are electronic LED signs, but they have an rs232 port and can be hooked to a pc! Once I noticed the phone jack that was really a serial port on the side, I knew I had to have them to use with Premise.

Anyone developed a driver for these things? The model numbers on the one's I bought are: box says 1036-1211, back of sign says 213C-1 and is made by Adaptive.

What I want to do with it so far: give status of lighting and volume levels, selected component, sound field, subwoofer level, temperature, clock and show what is playing in vista media center.

I'm not sure on how to attempt the last one. I'm hoping the uPnP driver I saw for Premise will also show the title of the show playing in media center, else I may have to wait until a better networked based media center control program comes out and link that ip/port to a virtual UDS-10 in Premise. Any activex controls for working with uPnP or media center that I could use too?
 
$15! What a steal!

I have a BetaBrite sign but haven't tried your driver yet! ;)

However, I have tweaked the driver and hope you find the alterations useful. The attached file expands on the work you've done by adding a File class (representing a message's memory location) and streamlining some of the code. The driver creates seven File objects (A-G) that cannot be renamed nor deleted. The serial Worker object is now hidden and I've renamed some of the properties to conform to the sign's nomenclature.

In the Module's MacroFolder, you'll find a Script Macro called "TestIt". Its code represents how one would normally compose a message and set display attributes.
Code:
with Devices.CustomDevices.BetaBrite.File_A
	.Color = "Red"
	.Mode = "Scroll"
	.Message = "Hello World!"
	.Display = true
end with
Jeff Atwood created a BetaBrite .NET class . I've thought of using it to write a MiniBroker-based driver but never got around to it. Jeff briefly mentions the BetaBrite class in his Coding Horror blog. The CodeProject article is useful and sheds light on the BetaBrite protocol.
 

Attachments

  • BetaBrite_2.png
    BetaBrite_2.png
    15.5 KB · Views: 29
  • BetaBrite_2.zip
    4 KB · Views: 36
Looks neat. I think the one thing that is missing in my driver is reading what is in memory. Right now, if I change volume, I lose what was previously there. I'd like to write a subroutine to read instead of write also, then write back to the sign after 1 second of display the volume.

Also, the way I do things like volume now is not optimum. The display refreshes everything on a write command. If one writes a string instead to only change the numbers, the "Volume: " would not flash!

I saw Jeff's work too and it seems like it would be neat to incorporate it, but it had way too many options for me to wrap my head around at the time.

$15! What a steal!

I have a BetaBrite sign but haven't tried your driver yet! ;)

However, I have tweaked the driver and hope you find the alterations useful. The attached file expands on the work you've done by adding a File class (representing a message's memory location) and streamlining some of the code. The driver creates seven File objects (A-G) that cannot be renamed nor deleted. The serial Worker object is now hidden and I've renamed some of the properties to conform to the sign's nomenclature.

In the Module's MacroFolder, you'll find a Script Macro called "TestIt". Its code represents how one would normally compose a message and set display attributes.
Code:
with Devices.CustomDevices.BetaBrite.File_A
	.Color = "Red"
	.Mode = "Scroll"
	.Message = "Hello World!"
	.Display = true
end with
Jeff Atwood created a BetaBrite .NET class . I've thought of using it to write a MiniBroker-based driver but never got around to it. Jeff briefly mentions the BetaBrite class in his Coding Horror blog. The CodeProject article is useful and sheds light on the BetaBrite protocol.
 
I like how you have used the file class. Very object oriented indeed ;)

There is a small bug I'm working to fix. Our code cannot simply copy the example to initialize the memory as this only initializes it for text files A and B, not C-G! This is easy to fix though.

Also, I believe our signs have 32kB of memory? Right now, the example uses a size of 0800 for file size. This represents the static size of the text file in hex. I'd like to dynamically change the size (but I have no idea how to calculate it as I'm sure the mode, color, font etc settings also count in the file size). $0800 = 2048 dec bytes which would give a 32kB screen room for 16 files. Initially, I just picked A-G at random, but it is clear that we can go up to "P," but this maybe overkill.

Documentation from the manual:
Clear Memory/Set Memory Configuration — To Clear Memory just use “E$â€. To Set Memory Configuration 11 (or multiples thereof)
ASCII characters are used to set a sign’s Memory Configuration table. Memory Configuration is a sign’s internal battery-backed up RAM
directory. A message file cannot be written until a Memory Configuration is written first — unless the file is a Priority TEXT file or the default
TEXT file “Aâ€. Also, whenever a Memory Configuration is written, the previous table is overwritten. Memory Configuration uses the following
format: FTPSIZEQQQQ where:
F = One ASCII character that represents the File Label. For valid File Labels, see “Appendix A: Valid File Labels†on page 50.
T = One ASCII character that represents the file type. Valid file types are:
“A†41H = TEXT file
“B†42H = STRING file
“D†43H = DOTS PICTURE file
P = One ASCII character that presents the keyboard protection status, either
“U†55H = Unlocked. Means that the file can be accessed via an IR keyboard.
“L†4CH = Locked. Means that the file can not be accessed via an IR keyboard.
(For a STRING file, “L†must be selected.)
1SIZE = Four ASCII characters that represent the hexadecimal file size in bytes of a TEXT or STRING file. For a DOTS PICTURE
file, the first two bytes = # pixel rows and the last two bytes = the # of pixel columns in the picture.
QQQQ = Four ASCII hexadecimal characters whose format depends on file type used:
• For a TEXT file, the first two characters represent the file’s Start Time and the last two characters represent the Stop Time. For
valid entries, see “Appendix B: Valid Start and Stop times†on page 51.
• For a STRING file, use “0000†as place holders because these four characters have no special meaning
• For a DOTS PICTURE file, this represents the Color Status. Valid entries are “1000†= monochrome, “2000†= 3-color, “4000†=
8-color (The “E8†command is used for RGB signs. See page 26.)
 
Added this code to the file class:

Code:
'set filesize
fileSize = "0800" 'ascii representing size in hex
'AU means text file type and unlock remote use
'FF00 is time loop means loop FF = always 00=12am (but I suspect 00 is irrelevant)
fileProperties =""

for each objFileTmp In this.Parent.GetObjectsByPropertyName("FileLabel")
	fileProperties = objFileTmp.FileLabel & "AU" & fileSize & "FF00" & fileProperties
next
'set up memory
this.Parent.SendCommand sBOT & "E$" & fileProperties & sEOT
 

Attachments

  • BetaBrite_3.zip
    3.9 KB · Views: 38
... I'd like to dynamically change the size ....
SIZE = Four ASCII characters that represent the hexadecimal file size in bytes of a TEXT or STRING file. ...
Use VBScript's len function to calculate the string length of the message to be sent. Convert the resulting value to hex and then use the 'zero padding' technique (see the WeederTech module) to pad the hex value with zeros so that it is always 4 characters long.

Here it is in one line of code (sMessage is a variable that contains the text string):
Code:
sCode = right(string(4, "0") & hex(len(sMessage)), 4)
If sMessage is a string containing 50 characters, sCode will be "0032".
 
Thanks ;) I may not get to adding this for a long time though. Also, my code I added wrote the memory in reverse GFED...
instead of ABCDEFG and this affects how the messages are displayed. I moved the & fileProperties to the front of the for loops expression.

So, you got me what does the debegout thing do in the method? I'm guessing it's required since you are passing data to the sendCommand method of the BetaBrite class? Could you explain the syntax; the help file does not have anything like your syntax in the debug out example.

... I'd like to dynamically change the size ....
SIZE = Four ASCII characters that represent the hexadecimal file size in bytes of a TEXT or STRING file. ...
Use VBScript's len function to calculate the string length of the message to be sent. Convert the resulting value to hex and then use the ZeroLeftPad function (see the WeederTech module) to pad the hex value with zeros so that it is always 4 characters long.
 
"debugout" is documented in Premise Help. It writes a string to Windows' Debug Console. You need a utility program like DebugView to view the Debug Console.

Displaying messages in the Debug Console is a handy way to watch what happens while Premise runs through your code. I use it frequently during development so that I can confirm things work the way I expect. When I'm satisfied everything is working properly, I'll either remove or simply comment out all the debugout statements.
 
Thanks. So the strange looking statements just forward info to the debugger... Then I'm going to guess that .TxTextData = method.Data is what actually is required to pass the data? I'm pretty confused. I studied how to write functions the other day and that made a lot more sense to me. You are calling the method like this: this.Parent.SendCommand someStringToSend How does the compiler know that the string following the class.method belongs to the text propery called data?

Code:
'
debugout "<<SendCommand>>"
debugout "<Send: [" & method.Data & "]>"

with this.Worker
	.TxTextData = method.Data
	.Send = true
end with

PS: If you want to make your BetaBrite look less like an advertising tool try buy some peel and stick smokey colored window treatment. Usually found at the lumberyard near windows or window treatment (not the kind for you car, this is easy to remove/put back). If you disassemble the BetaBrite, you'll see the screen slides out and one side of it is actually smooth. I put the treatment on the smooth side, then slide the Plexiglas back in smooth side out (original side in). Pic is attached. The top BetaBrite has the treatment. The bottom does not. The colors are a lot dimmer and easy on the eyes too. The stuff I used was made by Gila, "window film glare control," smoke CS78
 

Attachments

  • IMG_1232.JPG
    IMG_1232.JPG
    59.8 KB · Views: 34
... I'm going to guess that .TxTextData = method.Data is what actually is required to pass the data?
...
How does the compiler know that the string following the class.method belongs to the text propery called data?
Premise Builder visually depicts classes, methods, and properties. Refer to the attached image and follow along:
  1. Betabrite is a Class
  2. SendCommand is a Method of the BetaBrite class
  3. Data is a Text Property (a.k.a "Parameter") of the SendCommand method.
So when you call SendCommand you must pass a single text string like so:
this.Parent.SendCommand "SomeKindOfString"

To use "Data" in the method's code, you reference it using "method.Data". It is important to note that a method property's name can be anything you wish and is not limited to the word "Data". For example, it could be "Height" and then you'd reference it using "method.Height".
 

Attachments

  • Class_Method.png
    Class_Method.png
    29.2 KB · Views: 30
Thanks. This makes a lot more sense now! So if you have two text strings for example data1 and data2. You would use the code this.Parent.sendCommand data1 data2 assuming in the module explore view data1 is above data2?

So if you drag data2 so that it's above data1, you have to change your code where ever you call sendCommand? This is interesting.
 
...So if you drag data2 so that it's above data1, you have to change your code where ever you call sendCommand? This is interesting.
That's correct; it's no different than in other programming environments. For example, if I define a function in C# like so:
Code:
public void MyFunction(int MyID, string MyName)
{
// do something
}
I'd call the function like this: MyFunction(123, "Joe Public");

If I redefine the order of the parameters to this:
Code:
public void MyFunction(string MyName, int MyID)
{
// do something
}
then the compiler will carp when it encounters all existing calls to MyFunction ( i.e. MyFunction(123, "Joe Public") ) because the first argument is an Integer type and it now expects a String.

What if both parameters were defined as Strings and you swapped their order? The compiler would have nothing to complain about but all existing calls would be wrong because you'd be passing parameters in the wrong order!

So the moral of the story is: don't swap the order of a method's parameters after you've started using it in your code.

FYI
To clarify Parent and Child objects:
  1. Betabrite is a Class.
  2. File is a Class.
  3. SendCommand is a Method of the Betabrite class.
  4. ClassConstructor is a Method of the Betabrite class.
When the Betabrite object is instantiated, its ClassConstructor method is executed. It creates several File objects as children of Betabrite (i.e. child objects).
So the Betabrite object is the Parent of the File objects.

When the child, File, needs to use its parent's method, SendCommand, it calls it with: this.Parent.SendCommand
 

Attachments

  • Parent_Children.png
    Parent_Children.png
    10.5 KB · Views: 15
Thanks for all your tutoring 123, I really appreciate. I'm not a programmer and the extent of my programming experience is playing with Premise for 2-3 months now.

I can't believe how much I've learned about Premise in such a short period thanks to you and other posts on this site!

Premise is sure to stay in this home for a very long time! On a side note, hopefully this week I can post a new version of the betaBrite driver with dynamic BetaBrite memory allocation and string capability.

...So if you drag data2 so that it's above data1, you have to change your code where ever you call sendCommand? This is interesting.
That's correct; it's no different than in other programming environments. For example, if I define a function in C# like so:
Code:
public void MyFunction(int MyID, string MyName)
{
// do something
}
I'd call the function like this: MyFunction(123, "Joe Public");

If I redefine the order of the parameters to this:
Code:
public void MyFunction(string MyName, int MyID)
{
// do something
}
then the compiler will carp when it encounters all existing calls to MyFunction ( i.e. MyFunction(123, "Joe Public") ) because the first argument is an Integer type and it now expects a String.

What if both parameters were defined as Strings and you swapped their order? The compiler would have nothing to complain about but all existing calls would be wrong because you'd be passing parameters in the wrong order!

So the moral of the story is: don't swap the order of a method's parameters after you've started using it in your code.

FYI
To clarify Parent and Child objects:
  1. Betabrite is a Class.
  2. File is a Class.
  3. SendCommand is a Method of the Betabrite class.
  4. ClassConstructor is a Method of the Betabrite class.
When the Betabrite object is instantiated, its ClassConstructor method is executed. It creates several File objects as children of Betabrite (i.e. child objects).
So the Betabrite object is the Parent of the File objects.

When the child, File, needs to use its parent's method, SendCommand, it calls it with: this.Parent.SendCommand
 
Back
Top