Wireless M-Bus
Wireless M-Bus Functions
This category contains functions specific to Wireless M-Bus devices.
| API Name | Brief Description |
|---|---|
| api.wmbusSetup() | Changes the configuration of wM-Bus. Multiple variants. See below. |
| api.wmbusSetHeader(cfield, manid, id, ver, devtype, ci) | Sets wM-Bus header. |
| api.wmbusSendFrame(data) | Sends frame through wM-Bus. |
| api.wmbusReceiveFrame() | Waits for data reception from wM-Bus. Multiple variants. See below. |
| api.wmbusReceiveSendFrame(ci, payload, debugOn, useFilter) | Waits for data reception from wM-Bus and sends a modified frame back. |
| api.wmbusSendReceiveFrame(ci, payload, debugOn, useFilter) | Sends a frame and listens for a response in meter role. |
| api.wmbusFilter() | Creates and manages internal table of wM-Bus IDs. Multiple variants. See below. |
api.wmbusSetup()
Changes the configuration of wM-Bus.
| API Name | Brief Description |
|---|---|
| api.wmbusSetup(power, role, mode) | Sets wM-Bus power, role, and mode. |
| api.wmbusSetup("ROLE", role) | Sets wM-Bus role. |
| api.wmbusSetup("MODE", mode) | Sets wM-Bus mode. |
| api.wmbusSetup("IGNORE_CRC", ignore) | Sets CRC ignore. |
| api.wmbusSetup("DISABLE_MADDALENA_ARROW_SUPPORT", disable) | Disables Maddalena Arrow support. |
| api.wmbusSetup("FREQ_OFFSET", offset) | Sets frequency offset. |
| api.wmbusSetup("RX_DUTY_CYCLE", dutyCycle, rxTime, sleepTime) | Sets RX duty cycle. |
| api.wmbusSetup("SONTEX_CONFIG", pingRetry, readRetry, prePing, preRead, dither, demodulation) | Sets SONTEX configuration. |
| api.wmbusSetup("SONTEX_TUNE", address, onlyRough) | Performs Sontex frequency offset scan. |
api.wmbusSetup(power, role, mode)
api.wmbusSetup(10, "master", "T2")
Sets wM-Bus power, role, and mode.
Arguments
- power (integer): wM-Bus power in dBm:
-20,-10,0,2,4, etc. - role (string): wM-Bus role:
"master","slave","meter","concentrator","repeater". - mode (string): wM-Bus mode:
"S1","S2","T1","T2","T1_C","T2_C","R","METRA","SENSUS434","SONTEX433","BUP433","BUP868".
Return
- status (integer):
0for success.-1for failure.
Example
-- Set wM-Bus power to 10 dBm, role to master, and mode to T2
api.wmbusSetup(10, "master", "T2")
--------------------------------
if port == 231 then
if cfg == nil or cfg == '' then
print("Bad WMBUS mode, Specify C1 or T1 or S1")
else
print("New WMBUS mode: "..cfg)
api.wmbusSetup(10, "master", cfg, 1)
end
end
api.wmbusSetup("ROLE", role)
api.wmbusSetup("ROLE", "master")
Sets wM-Bus role.
Arguments
-
"ROLE" (string, command)
❗command - the argument needs to have this exact form❗ -
role (string): wM-Bus role:
"master","slave","meter","concentrator","repeater".
Return
- status (integer):
0for success.-1for failure.
Example
-- Set role to master
api.wmbusSetup("ROLE", "master")
--------------------------------
function onStartup()
print("Starting up MBUS to wMBus script v."..ver)
-- wMBus configuration, header definition
api.wmbusSetup("ROLE", "meter")
api.wmbusSetup("MODE", "T1")
api.wmbusSetup("MODE", mode)
api.wmbusSetup("MODE", "T1_C")
Sets wM-Bus mode.
Arguments
-
"MODE" (string, command)
❗command - the argument needs to have this exact form❗ -
mode (string): wM-Bus mode:
"S1","S2","T1","T2","T1_C","T2_C","R","METRA","SENSUS434","SONTEX433","BUP433","BUP868".
Return
- status (integer):
0for success.-1for failure.
Example
-- Set mode to T1_C
api.wmbusSetup("MODE", "T1_C")
api.wmbusSetup("IGNORE_CRC", ignore)
api.wmbusSetup("IGNORE_CRC", 1)
Sets CRC ignore.
Arguments
-
"IGNORE_CRC" (string, command)
❗command - the argument needs to have this exact form❗ -
ignore (integer):
1for true.0for false.
Return
- status (integer):
0for success.-1for failure.
Example
-- Set CRC ignore to true
api.wmbusSetup("IGNORE_CRC", 1)
--------------------------------
if mode == 1 then
ws("MODE", "T1")
else
ws("MODE", "S1")
end
api.wmbusSetup("DISABLE_MADDALENA_ARROW_SUPPORT", disable)
api.wmbusSetup("DISABLE_MADDALENA_ARROW_SUPPORT", 1)
Disables Maddalena Arrow support.
Arguments
-
"DISABLE_MADDALENA_ARROW_SUPPORT" (string, command)
❗command - the argument needs to have this exact form❗ -
disable (integer):
1for true.0for false.
Return
- status (integer):
- *
0for success. -1for failure.
- *
Example
-- Disable Maddalena Arrow support
api.wmbusSetup("DISABLE_MADDALENA_ARROW_SUPPORT", 1)
api.wmbusSetup("FREQ_OFFSET", offset)
api.wmbusSetup("FREQ_OFFSET", 1000)
Sets frequency offset.
Arguments
-
"FREQ_OFFSET" (string, command)
❗command - the argument needs to have this exact form❗
Optional
- offset (integer, optional): Frequency offset in Hz, range from
-99999to99999.
if no offset is given, this can still be used to return current set offset
Return
- offset (integer): Set frequency offset.
Example
-- Set frequency offset to 1000 Hz
freq = api.wmbusSetup("FREQ_OFFSET", 1000)
print(freq)
--------------------------------
api.wmbusSetup("FREQ_OFFSET", 0)
api.wmbusSetup("RX_DUTY_CYCLE", dutyCycle, rxTime, sleepTime)
api.wmbusSetup("RX_DUTY_CYCLE", 1, 1000, 1000)
Sets RX duty cycle.
Arguments
-
"RX_DUTY_CYCLE" (string, command)
❗command - the argument needs to have this exact form❗
Optional
- dutyCycle (integer, optional): Duty cycle state
1for enabled.0for disabled.
- rxTime (integer, optional): Duty cycle RX time in milliseconds (
-1to skip changing the current settings). - sleepTime (integer, optional): Duty cycle sleep time in milliseconds (
-1to skip changing the current settings).
Return
- dutyCycle (integer): Set duty cycle state.
- rxTime (integer): Set RX time.
- sleepTime (integer): Set sleep time.
Example
-- Set RX duty cycle
dutyCycle, rxTime, sleepTime = api.wmbusSetup("RX_DUTY_CYCLE", 1, 1000, 1000)
print("Duty cycle: " .. dutyCycle .. ", RX time: " .. rxTime .. ", Sleep time: " .. sleepTime)
--------------------------------
api.wmbusSetup("RX_DUTY_CYCLE", m == "S1" and (ndc ~= true) and 1 or 0, 100, 344)
api.wmbusSetup("SONTEX_CONFIG", pingRetry, readRetry, prePing, preRead, dither, demodulation)
api.wmbusSetup("SONTEX_CONFIG", 10, 10, 2000, 2000, 1000)
Sets SONTEX configuration.
Arguments
-
"SONTEX_CONFIG" (string, command)
❗command - the argument needs to have this exact form❗
Optional
- pingRetry (integer, optional): Ping retry value, range from
0to20(-1to skip changing the current settings). - readRetry (integer, optional): Read retry value, range from
0to20(-1to skip changing the current settings). - prePing (integer, optional): Preamble ping value, range from
0to10000(-1to skip changing the current settings). - preRead (integer, optional): Preamble read value, range from
0to10000(-1to skip changing the current settings). - dither (integer, optional): Dither on entry value, range from
0to2000(-1to skip changing the current settings). - demodulation (integer, optional): Demodulation method,
1for new method (oversampling, experimental),0for old method (-1to skip changing the current settings).
Return
- pingRetry (integer): Set ping retry value.
- readRetry (integer): Set read retry value.
- prePing (integer): Set preamble ping value.
- preRead (integer): Set preamble read value.
- dither (integer): Set dither value.
- demodulationMethod (integer): Set demodulation method.
- acceptAnyMeterID (integer): Whether to accept any meter ID.
Example
-- Set Sontex configuration
pingRetry, readRetry, prePing, preRead, dither = api.wmbusSetup("SONTEX_CONFIG", 10, 10, 2000, 2000, 1000)
print("Set arguments: " .. pingRetry .. ", " .. readRetry .. ", " .. prePing .. ", " .. preRead .. ", " .. dither)
api.wmbusSetup("SONTEX_TUNE", address, onlyRough)
api.wmbusSetup("SONTEX_TUNE", 123456, 0)
Performs Sontex frequency offset scan.
Arguments
-
"SONTEX_TUNE" (string, command)
❗command - the argument needs to have this exact form❗ -
address (integer): Address of the device to tune.
Optional
- onlyRough (integer, optional): Set only rough tuning:
1for true.0for false.
Return
- status (integer):
1for success.0for failure.
- bestOffset (integer): Best frequency offset found.
Example
-- Perform Sontex tuning
status, bestOffset = api.wmbusSetup("SONTEX_TUNE", 123456, 0)
print("Status: " .. status .. ", Best Offset: " .. bestOffset)
--------------------------------
for i=1,ls433 do
local tmp = api.getVar(64+i-1)
_, offs = api.wmbusSetup("SONTEX_TUNE", tmp)
s(512+2*(i-1), offs) --set var
end
api.wmbusSetHeader(cfield, manid, id, ver, devtype, ci)
api.wmbusSetHeader(123, 123456, 2, 33, 17)
Sets wM-Bus header.
Arguments
- cfield (integer): wM-Bus C field, max value
0xff. - manid (integer): Manufacturer ID, max value
0xffff. - id (integer): ID of wM-Bus device (32-bit).
- version (integer): Version field, max value
0xff. - devtype (integer): Device type field, max value
0xff. - ci (integer): CI field, max value
0xff.
Return
- status (integer):
0for success.-1for failure.
Example
-- Set wM-Bus header for specific device
print("--- wM-Bus T1 Digital Thermometer ---")
api.wmbusSetup(10, "meter", "T1")
api.wmbusSetHeader(123, 123456, 2, 33, 17)
--------------------------------
function onStartup()
print("Starting up MBUS to wMBus script v."..ver)
-- wMBus configuration, header definition
api.wmbusSetup("ROLE", "meter")
api.wmbusSetup("MODE", "T1")
wmbusID,_,_ = api.getDeviceAddress()
print("wMBus identification: ", string.format("0x%08X", wmbusID))
manIdACR = 1138
cfield = 8 -- RSP_UD, EN13757-4, page 41
cifield = 0xA0 -- CI for app specific - 0xA0 to 0xB7 are allowed
devtype = 0x37 -- radio converter unit (as per Lansen pdf)
version = 16*tonumber(ver:sub(1,1))+tonumber(ver:sub(-1))
api.wmbusSetHeader(cfield,manIdACR, wmbusID, version, devtype, cifield)
api.wmbusSendFrame(data)
api.wmbusSendFrame(frame)
Sends frame through wM-Bus.
Arguments
- data (string): Frame to be sent.
Return
- status (integer): Positive or
0for success, negative for failure.
Example
-- Send wM-Bus frame
api.wmbusSendFrame(frame)
api.wmbusReceiveFrame()
Waits for data reception from wM-Bus.
| API Name | Brief Description |
|---|---|
| api.wmbusReceiveFrame(timeout, id) | Waits for data reception in SONTEX433 mode. |
| api.wmbusReceiveFrame(timeout, debugOn, useFilter) | Waits for data reception in other modes. |
api.wmbusReceiveFrame(timeout, id)
api.wmbusReceiveFrame(2000, 123456)
Waits for data reception from wM-Bus in SONTEX433 mode.
Arguments
- timeout (integer): Maximum time in milliseconds to wait for wM-Bus device answer.
- id (integer): ID of wM-Bus device (32-bit).
Return
- status (integer):
- Positive or
0for success. - negative for failure.
- Positive or
- cField (nil): Unused field, pushed as
nil. - manID (integer): Manufacturer ID (
0x4DEEfor Sontex SA). - devID (integer): Unique 32-bit ID of the wM-Bus device.
- ver (nil): Unused field, pushed as
nil. - devType (nil): Unused field, pushed as
nil. - ciField (nil): Unused field, pushed as
nil. - dataOnly (string): Data-only portion of the frame.
- rawFrame (string): Complete frame, including length and CRC.
- filterIndex (nil): Unused field, pushed as
nil. - rssi (integer): Received Signal Strength Indicator.
- frameType (string): Identifier for SONTEX433:
"SONTEX433". - transportType (string): Error/status message, default
"ERR".
Example
-- Receive wM-Bus data in SONTEX433 mode
status, cField, manID, devID, ver, devType, ciField, dataOnly = api.wmbusReceiveFrame(2000, 123456)
print(status)
print(devID)
print(dataOnly)
api.wmbusReceiveFrame(timeout, debugOn, useFilter)
api.wmbusReceiveFrame(2000, 0, 0)
Waits for data reception from wM-Bus in other modes.
Arguments
- timeout (integer): Maximum time in milliseconds to wait for wM-Bus device answer.
Optional
- debugOn (integer, optional): Debug on:
1for true.0for false.
- useFilter (integer, optional): Use filter:
1for true.0for false.
Return
- status (integer):
- Positive or
0for success. - Negative for failure.
- Positive or
- cField (integer): Control Field from the wM-Bus frame (max value
255). - manID (integer): Manufacturer ID, max value
0xffff. - devID (integer): Unique 32-bit ID of the wM-Bus device.
- ver (integer): Version of the device (max value
0xff). - devType (integer): Device type field (max value
0xff). - ciField (integer): Control Information field.
- dataOnly (string): Received frame payload.
- rawFrame (string): Complete frame without CRC.
- filterIndex (integer): Index of the filter.
- rssi (integer): Received Signal Strength Indicator.
- frameType (string): Frame type:
"F","C","T","S","T2S", or"ERR". - transportType (string): Transport type:
"A","B", or"ERR".
Return (METRA mode)
- status (integer):
- Positive or
0for success. - Negative for failure.
- Positive or
- cField (nil): Unused field, pushed as
nil. - manID (integer): Manufacturer ID (
0x0614for Apator SA). - devID (integer): Unique 32-bit ID of the wM-Bus device.
- ver (nil): Unused field, pushed as
nil. - devType (integer): Device type field (max value
0xff). - ciField (nil): Unused field, pushed as
nil. - dataOnly (string): Data-only portion of the frame.
- rawFrame (string): Complete frame, including length and CRC.
- filterIndex (integer): Index of the filter.
- rssi (integer): Received Signal Strength Indicator.
- frameType (string): Identifier for METRA:
"M". - transportType (string): Error/status message, default
"ERR".
Return (BUP433 and BUP868 modes)
- status (integer):
- Positive or
0for success. - Negative for failure.
- Positive or
- cField (nil): Unused field, pushed as
nil. - manID (integer): Manufacturer ID (
0x4CAEfor Sensus GmbH). - devID (integer): Unique 32-bit ID of the wM-Bus device.
- ver (nil): Unused field, pushed as
nil. - devType (integer): Device type field (max value
0xff). - ciField (nil): Unused field, pushed as
nil. - dataOnly (string): Data-only portion of the frame.
- rawFrame (string): Complete frame, including length and CRC.
- filterIndex (integer): Index of the filter.
- rssi (integer): Received Signal Strength Indicator.
- frameType (string): Identifier for BUP433 and BUP868:
"BUP". - transportType (string): Error/status message, default
"ERR".
Example
-- Receive wM-Bus data with 2000 ms timeout
status, cField, manID, devID, ver, devType, ciField, dataOnly = api.wmbusReceiveFrame(2000)
print(status)
print(devID)
print(dataOnly)
--------------------------------
_,rc,rm,ri,rv,rd,rci,_,raw,FId,rssi,rft,rtt = api.wmbusReceiveFrame(switchMode(), 0)
if raw ~= nil then
print("Rxed!")
break
end
api.wmbusReceiveSendFrame(ci, payload, debugOn, useFilter)
api.wmbusReceiveSendFrame(200, x, 2000)
Waits for data reception from the wM-Bus. After reception, the received frame can be modified and sent back to the device.
Warning: This function is only available when the wM-Bus is in the concentrator role.
Arguments
- ci (integer): CI field.
- payload (string): Payload to be sent.
- timeout (integer): Maximum time in milliseconds to wait for RS485 device answer.
- useFilter (integer, optional): Use filter:
1for true.0for false.
Return
- status (integer):
- Positive or
0for success. - Negative for failure.
- Positive or
- cField (integer): Control Field from the wM-Bus frame (max value
255). - manID (integer): Manufacturer ID, max value
0xffff. - devID (integer): Unique 32-bit ID of the wM-Bus device.
- ver (integer): Version of the device (max value
0xff). - devType (integer): Device type field (max value
0xff). - ciField (integer): Control Information field as received in the frame.
- dataOnly (string): Payload data extracted from the received frame.
- rawFrame (string): Complete received frame without CRCs.
- filterIndex (integer): Index of the filter.
- rssi (integer): Received Signal Strength Indicator.
- frameType (string): Frame type:
"F","C","T","S","T2S", or"ERR". - transportType (string): Transport type:
"A","B", or"ERR".
Example
-- Receive and send wM-Bus frame
x = string.char(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)
status, cField, manID, devID, ver, devType, ciField, dataOnly = api.wmbusReceiveSendFrame(200, x, 2000)
print(status)
print(devID)
print(dataOnly)
api.wmbusSendReceiveFrame(ci, payload, debugOn, useFilter)
api.wmbusSendReceiveFrame(200, x)
Sends a frame with the specified Control Information and payload from a wM-Bus device in the meter role and listens for a response.
Warning: This function is only available when the wM-Bus is in the meter role.
Arguments
- ci (integer): CI field.
- payload (string): Payload to be sent.
- debugOn (integer, optional): Debug on:
1for true.0for false.
- useFilter (integer, optional): Use filter:
1for true.0for false.
Return
- status (integer):
- Positive or
0for success. - Negative for failure.
- Positive or
- cField (integer): wM-Bus C field (max value
255). - manID (integer): Manufacturer ID, max value
0xffff. - devID (integer): ID of wM-Bus device (32-bit).
- ver (integer): Version field, max value
0xff. - devType (integer): Device type field, max value
0xff. - ciField (integer): CI field.
- payload (string): Received frame payload.
- rawFrame (string): Complete frame without CRC.
- rssi (integer): Received Signal Strength Indicator.
Example
-- Send and receive wM-Bus frame
x = string.char(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)
status, cField, manID, devID, ver, devType, ciField, dataOnly = api.wmbusSendReceiveFrame(200, x)
print(status)
print(devID)
print(dataOnly)
api.wmbusFilter()
Creates and manages internal table of wM-Bus IDs.
| API Name | Brief Description |
|---|---|
| api.wmbusFilter("purge") | Purges the table, removing all stored IDs. |
| api.wmbusFilter("populate", filter) | Populates the table with a set of IDs. |
| api.wmbusFilter("show") | Shows the content of filter. |
| api.wmbusFilter("fetch") | Returns length of filter. |
| api.wmbusFilter("show-length") | Shows length of the filter. |
| api.wmbusFilter("show-index", index) | Shows index for defined filter. |
| api.wmbusFilter("add", id) | Adds ID to the filter. |
Warning: This function is only available when the wM-Bus is in the meter role.
api.wmbusFilter("purge")
api.wmbusFilter("purge")
Purges the table, removing all stored IDs.
Arguments
-
"purge" (string, command)
❗command - the argument needs to have this exact form❗
Return
- status (integer):
0on success.
Example
-- Purge wM-Bus filter
api.wmbusFilter("purge")
--------------------------------
function processConfig(ret, port, cfg)
-- port 230 is selected for new filter configuration
if port == 230 then
print("New filter config:")
if cfg == nil or #cfg < 3 then
print("Purge filter, receive all")
api.wmbusFilter("purge")
filterLength = 0
api.setVar(1, filterLength)
api.wmbusFilter("populate", filter)
api.wmbusFilter("populate", filter)
Populates the table with a set of IDs provided as input.
Arguments
-
"populate" (string, command)
❗command - the argument needs to have this exact form❗ -
filter (string): Filter data to populate; must be a multiple of 4 bytes in length.
Return
- status (integer): Number of filters populated on success, negative values on failure.
Example
-- Populate wM-Bus filter
filter = ""
filter = filter .. string.char(0x13, 0x32, 0x67, 0x01) -- 0x01673213
filter = filter .. string.char(0x33, 0x47, 0x85, 0x19) -- 0x19854733
api.wmbusFilter("populate", filter)
--------------------------------
-- UNCOMMENT BELOW IN CASE OF USING VIF DIF FILTERING
api.mbusVifDifFilter("populate",pack.pack("b28", 0x09, -- 0x09 - number of DIF VIF values
0x02, 0x04, 0x78, -- FAB number
0x02, 0x04, 0x6D, -- timestamp
0x02, 0x04, 0x06, -- Energy counter reading - Wh
0x02, 0x04, 0x13, -- Volume counter reading - m3
0x02, 0x04, 0x2b, -- Power [W]
0x02, 0x04, 0x3b, -- Flow [l / h]
0x02, 0x02, 0x5b, -- Flow temperature [deg. C]
0x02, 0x02, 0x5F, -- Return temperature [deg. C]
0x02, 0x02, 0x61)) -- Temperature difference [K]
api.wmbusFilter("show")
api.wmbusFilter("show")
Shows the content of filter.
Arguments
-
"show" (string, command)
❗command - the argument needs to have this exact form❗
Return
- status (integer): Returns the length of the filter table on success.
- entries (string): Concatenated filter entries as a string, each 4 bytes.
Example
-- Show wM-Bus filter
status, entries = api.wmbusFilter("show")
print(entries)
--------------------------------
elseif cmd == 5 then
len, filter = api.wmbusFilter("show")
idchs = 0
for i=1,len do
_,tmp=pack.unpack(string.sub(filter,4*(i-1)+1, 4*i+1), "<I")
idchs = bit.bxor(idchs, tmp)
end
api.wmbusFilter("fetch")
api.wmbusFilter("fetch")
--------------------------------
function onStartup()
print("Starting up WMBUS to LoRaWAN script, V1.3")
ret, filterLength = api.wmbusFilter("fetch")
api.setVar(1, filterLength)
-- Start receiving at C1/T1 mode/frequency
api.wmbusSetup(10, "master","T1", 1)
end
Returns length of filter.
Arguments
-
"fetch" (string, command)
❗command - the argument needs to have this exact form❗
Return
- status (integer):
0if fetch was successful.- Negative values on failure.
- length (integer): Current length of the wM-Bus filter table.
Example
-- Fetch wM-Bus filter
status, length = api.wmbusFilter("fetch")
print(length)
api.wmbusFilter("show-length")
api.wmbusFilter("show-length")
Shows length of the filter.
Arguments
-
"show-length" (string, command)
❗command - the argument needs to have this exact form❗
Return
- length (integer): Length of the wM-Bus filter table.
Example
-- Show length of wM-Bus filter
length = api.wmbusFilter("show-length")
print(length)
api.wmbusFilter("show-index", index)
api.wmbusFilter("show-index", 1)
Shows index for defined filter.
Arguments
-
"show-index" (string, command)
❗command - the argument needs to have this exact form❗ -
index (integer): The index of the filter to show (1-based).
Return
- entry (string): Specific filter entry at the given index; returns an empty string if the index is invalid.
Example
-- Show index of wM-Bus filter
status, entry = api.wmbusFilter("show-index", 1)
print(entry)
--------------------------------
for i=1,len do
_,tmp=pack.unpack(api.wmbusFilter("show-index", i), "<I")
idchs = bit.bxor(idchs, tmp)
end
api.wmbusFilter("add", id)
api.wmbusFilter("add", string.char(0x13, 0x32, 0x67, 0x01))
Adds ID to the filter (max length 4 bytes).
Arguments
-
"add" (string, command)
❗command - the argument needs to have this exact form❗ -
id (string): Single 4-byte filter entry to add.
Return
- status (integer):
- The new filter length on success.
- Negative values on failure.
Example
-- Add wM-Bus filter
id = string.char(0x13, 0x32, 0x67, 0x01) -- 0x01673213
api.wmbusFilter("add", id)
--------------------------------
for i = 1, FLen do
api.wmbusFilter("add", c:sub(1+4*(i-1),i*4))
end