LSL Protocol/OpenRadioCommunication

From Second Life Wiki
Revision as of 19:50, 15 September 2017 by Kyrah Abattoir (talk | contribs) (Fixes a typo in the ASCII conversion table.)
Jump to navigation Jump to search

Open Radio Communication (ORC for short) Is a "binary like" radio system designed for small simple applications, where part of the goal is to have equipments interfere with eachothers.

Channels

The channels used by ORC go from -797386 to -797186 with 200 independent frequencies.

Frequency "friendly" numbers go from 88.1 to 108.1.

API

<source lang="lsl2"> //Open Radio System v0.1

integer POWER_LOW = 0;//whisper integer POWER_MED = 1;//say integer POWER_HI = 2;//shout integer POWER_MAX = 3;//region

integer CHANNEL = -798267; //ORC in decimal basically integer giSubchannel; //This function is used to trim/pad data to length string Size(integer iData,integer iBytes) { string s = (string)iData; while(llStringLength(s)<iBytes) s = "0"+s; if(llStringLength(s)>iBytes) s = llGetSubString(s,-iBytes,-1); return s; }

//////////////////////////////////////////RECEIVER////////////////////////////////////////// //Functions to listen and read an OpenRC datastream // //////////////////////////////////////////RECEIVER////////////////////////////////////////// integer giReceiverPointer; integer giReceiverHandle = -1; integer Receiver(float fFrequency) { integer iFrequency = llAbs((integer)(fFrequency*10)); //set frequency to zero to turn receiver off. if(iFrequency == 0) { if(giReceiverHandle != -1) llListenRemove(giReceiverHandle); giReceiverHandle = -1; return -1; }

// 88.1 to 108.1 expressed as 881 to 1081 -> 200 possible frequencies if(iFrequency < 881) iFrequency = 881; else if(iFrequency > 1081) iFrequency = 1081;

if(giReceiverHandle != -1) llListenRemove(giReceiverHandle); giSubchannel = CHANNEL+iFrequency; giReceiverHandle = llListen(giSubchannel,"","",""); return iFrequency; } ReceiverInit() { //init basically set the pointer to 0 giReceiverPointer = 0; } string ReceiverRead(string sDatastream,integer iBytes) { //Main stream reader, read the number of bytes and move the pointer forward. string sData = llGetSubString(sDatastream,giReceiverPointer,giReceiverPointer + iBytes - 1); giReceiverPointer+=iBytes; return sData; } integer ReceiverReadInt(string sDatastream,integer iBytes) { return (integer)ReceiverRead(sDatastream,iBytes); } string ReceiverReadASCIIChar(string sDatastream) { return ASCII2Char(ReceiverReadInt(sDatastream,3)); } string ReceiverReadASCIIWord(string sDatastream) { //first we attempt to read the header (charcount) integer iLength = ReceiverReadInt(sDatastream,3); if(iLength < 1) iLength = 0; string sBuffer = ""; integer i; for(i=0;i<iLength;i++) sBuffer += ReceiverReadASCIIChar(sDatastream); return sBuffer; }

string ReceiverReadMorseWord(string sDatastream) { //you should check the header manually! (000) string sBuffer = ""; integer iInt;

   do
   {
       iInt = ReceiverReadInt(sDatastream,1);
       if(iInt)
           sBuffer += (string)iInt;
   }
   while(iInt);
   
   return sBuffer;

}

//////////////////////////////////////////SENDER////////////////////////////////////////// //Functions to build and send an OpenRCsend datastream // //////////////////////////////////////////SENDER////////////////////////////////////////// string gsSendBuffer;

//Execute before building a datastream to ensure that the send buffer is clean. SendInit() { gsSendBuffer = ""; }

//Used to add an integer to the datastream, only positive values, you can pick the number of bytes used SendInt(integer iValue,integer iBytes) { gsSendBuffer += Size(llAbs(iValue),iBytes); }

//Used to add an ASCII character to the datastream, each ascii char always use 3 bytes. SendASCIIChar(string sChar) { gsSendBuffer += Char2ASCII(sChar); }

//Used to add an ASCII word to the datastream, words use 3 bytes per character and 3 extra bytes as header. SendASCIIWord(string sWord) { //count the number of chars integer iCount = llStringLength(sWord) % 999; //max word size is 999 chars because 3 bytes max. integer i; SendInt(iCount,3); //header of a word is it's total character count. for(i=0;i<iCount;i++) SendASCIIChar(llGetSubString(sWord,i,i)); }

//Used to send a morse word on the datastream,this start with 000 and end with 000 //requires pre encoded morse! SendMorseWord(string sWord) {

   //count the number of chars
   integer iCount = llStringLength(sWord);
   integer i;
   SendInt(0,3);
   for(i=0;i<iCount;i++)
       SendInt((integer)llGetSubString(sWord,i,i),1);
   SendInt(0,3);

}

//Send the buffer and purge it's content, you have to set power and frequency here. SendEnd(float fFrequency,integer iPower) { integer iChannel = llAbs((integer)(fFrequency*10)); // 88.1 to 108.1 expressed as 881 to 1081 -> 200 possible frequencies if(iChannel < 881) iChannel = 881; else if(iChannel > 1081) iChannel = 1081;

iChannel += CHANNEL; if(gsSendBuffer == "") return; if(iPower == POWER_LOW) llWhisper(iChannel,gsSendBuffer); else if(iPower == POWER_HI) llShout(iChannel,gsSendBuffer); else if(iPower == POWER_MAX) llRegionSay(iChannel,gsSendBuffer); else llSay(iChannel,gsSendBuffer); gsSendBuffer = ""; }


//////////////////////////////////////////CODEC////////////////////////////////////////// //this is a basic ASCII coder/decoder toolset for char/word // //////////////////////////////////////////CODEC////////////////////////////////////////// //Conversion table to extended ascii, character index + 1 = value. // 1 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 255 (nbsp) string ASCII = "☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´­±‗¾¶§÷¸°¨·¹³²■ "; //Turns the supplied character into a 3 byte integer. string Char2ASCII(string sData) { return Size(llSubStringIndex(ASCII,llGetSubString(sData,0,0)) + 1,3); }

//Turns the supplied integer into it's corresponding character. values wrap around at ORC_ASCII length. string ASCII2Char(integer iCharcode) { iCharcode = llAbs(iCharcode) % (llStringLength(ASCII)+1); if(iCharcode <= 0) return ""; iCharcode--; //shifting of 1 to account for the "" that is at position zero. return llGetSubString(ASCII,iCharcode,iCharcode); }

integer MORSE_SPACE = 1; integer MORSE_SHORT = 2; integer MORSE_LONG = 3;

list MORSE_SYMBOLS = [""," ",".","-"]; string String2Morse(string sData) { string buffer; integer i; integer max = llStringLength(sData); for(i=0;i<max;i++) { integer value = llListFindList(MORSE_SYMBOLS,[llGetSubString(sData,i,i)]); if(value < 0) value = 0; buffer += (string)value; }

   return buffer;

}

string Morse2String(string sData) { string buffer;

   integer i;
   integer max = llStringLength(sData);
   for(i=0;i<max;i++)
       buffer += llList2String(MORSE_SYMBOLS,(integer)llGetSubString(sData,i,i));

return buffer; } </source>

Examples

Sending a simple message with the API

Note that in this example, we are sending int(5) and then a variable length ascii encoded text. It will have to be decoded in the same order to be reserved. <source lang="lsl2"> state_entry() {

   SendInit(); //Required before any transmission to setup the radio systems.
   SendInt(5000,5); //This will add a 5 digit long integer, containing the value 5000 to the buffer.
   SendASCIIWord("Hello world!"); //This will add an ASCII encoded string of variable length to the sending buffer.
   SendEnd(105.5,POWER_MED); //This will send the buffer over channel 105.5 with the "medium" power setting (20 meters range)

} </source>

Receiving a messages with the API

The way variable length ascii encoded texts are stored, the first int(3) contains the length of the character chain, and then every subsequenct in(3) is a character. <source lang="lsl2"> state_entry() {

   Receiver(105.5); //Will start listening for messages on channel 105.5

} listen(integer channel,string name,key id,string datastream) {

   if(channel = giSubchannel && giReceiverHandle != -1)
   {
       ReceiverInit(); //setup the ORC system for reading the datastream
       
       integer value = ReceiverReadInt(datastream,5); //read an Integer value of 5 digits.
       string text = ReceiverReadASCIIWord(datastream); //read a variable length Ascii word.
   }

} </source>