Lua - FlashAir card CONFIG file gets damaged - macos

I am using Toshiba FlashAir card to wirelessly upload photos from my drone to my web server via Lua script installed on FlashAir card. The card works fine most of the time, but sometimes the photos doesn't upload. When I connect to the card via my mac, I get this message, "CONFIG" is damaged and can't be opened.
Not sure why this is happening. The ftpUpload.lua script that does the uploading is listed below:
require("Settings")
local blackList = {}
local dateTable = {}
local parseThreads = 0
local ftpstring = "ftp://"..user..":"..passwd.."#"..server.."/"..serverDir.."/"
local lockdir = "/uploaded/" -- trailing slash required, and folder must already exist
local fileTable = {}
--Options
local sortByFileName = false -- If true sorts alphabetically by file else sorts by modified date
local jpegsOnly = true --Excludes .RAW files if set to true
local function exists(path)
if lfs.attributes(path) then
return true
else
return false
end
end
local function is_uploaded(path)
local hash = fa.hash("md5", path, "")
return exists(lockdir .. hash)
end
local function set_uploaded(path)
local hash = fa.hash("md5", path, "")
local file = io.open(lockdir .. hash, "w")
file:close()
end
local function delete(path)
-- Both of the following methods cause the next photo to be lost / not stored.
fa.remove(path)
-- fa.request("http://127.0.0.1/upload.cgi?DEL="..path)
end
--Format file date to something meanigful
local function FatDateTimeToTable(datetime_fat)
local function getbits(x, from, to)
local mask = bit32.lshift(1, to - from + 1) - 1
local shifted = bit32.rshift(x, from)
return bit32.band(shifted, mask)
end
local fatdate = bit32.rshift(datetime_fat, 16)
local day = getbits(fatdate, 0, 4)
local month = getbits(fatdate, 5, 8)
local year = getbits(fatdate, 9, 15) + 1980
local fattime = getbits(datetime_fat, 0, 15)
local sec = getbits(fattime, 0, 4) * 2
local min = getbits(fattime, 5, 10)
local hour = getbits(fattime, 11, 15)
return {
year = string.format('%02d', year),
month = string.format('%02d', month),
day = string.format('%02d', day),
hour = string.format('%02d', hour),
min = string.format('%02d', min),
sec = string.format('%02d', sec),
}
end
--Looks for value in table
local function exists_in_table(tbl, val)
for i = 1, #tbl do
if (tbl[i] == val) then
return true
end
end
return false
end
local function create_thumbs()
print("Creating Thumbs!")
for i = 1, #dateTable do
local message = "d="..dateTable[i]
local headers = {
["Content-Length"] = string.len(message),
["Content-Type"] = "application/x-www-form-urlencoded"
}
local b, c, h = fa.request{
url = "http://"..server.."/"..serverDir.."/ct.php",
method = "POST",
headers = headers,
body = message
}
end
print("COMPLETE!")
end
local function upload_file(folder, file, subfolder)
local path = folder .. "/" .. file
-- Open the log file
local outfile = io.open(logfile, "a")
outfile:write(file .. " ... ")
local url = ftpstring..subfolder.."/"..file
local response = fa.ftp("put", url, path)
--print("Uploading", url)
--Check to see if it worked, and log the result!
if response ~= nil then
print("Success!")
outfile:write(" Success!\n")
set_uploaded(path)
if delete_after_upload == true then
print("Deleting " .. file)
outfile:write("Deleting " .. file .. "\n")
sleep(1000)
delete(path)
sleep(1000)
end
else
print(" Fail ")
outfile:write(" Fail\n")
end
--Close our log file
outfile:close()
end
local function sort_upload_table()
if (sortByFileName) then
print("Sorting filenames alphabetically")
table.sort(fileTable, function(a,b)
return a.file>b.file
end)
else
print("Sorting filenames by modded date")
table.sort(fileTable, function(a,b)
return a.sortDate>b.sortDate
end)
end
end
local function run_upload()
print("Starting upload")
for i = 1, #fileTable do
local ft = fileTable[i]
print("Uploading:", ft.folder, ft.file, ft.dateString)
upload_file(ft.folder, ft.file, ft.dateString)
end
create_thumbs()
end
local function walk_directory(folder)
parseThreads = parseThreads+1
for file in lfs.dir(folder) do
local path = folder .. "/" .. file
local skip = string.sub( file, 1, 2 ) == "._"
local attr = lfs.attributes(path)
local dt={}
if (not skip) then
print( "Found "..attr.mode..": " .. path )
if attr.mode == "file" then
local dateString = ""
if (attr.modification~=nil) then
dt = FatDateTimeToTable(attr.modification)
dateString = dt.day.."-"..dt.month.."-"..dt.year
end
if not is_uploaded(path) then
if (not exists_in_table(blackList, dateString)) then
local s,f = true, true
if (jpegsOnly) then
s,f = string.find(string.lower(file), ".jpg")
end
if (s and f) then
fileTable[#fileTable+1] =
{
folder = folder,
file = file,
dateString = dateString,
sortDate=dt.year..dt.month..dt.day..dt.hour..dt.min..dt.sec
}
--upload_file(folder, file, dateString)
end
else
print("Skipping ".. dateString.." - Blacklisted")
end
else
print(path .. " previously uploaded, skipping")
end
elseif attr.mode == "directory" then
print("Entering " .. path)
walk_directory(path)
end
end
end
parseThreads = parseThreads-1
if (parseThreads == 0) then
--create_thumbs()
sort_upload_table()
run_upload()
end
end
local function create_folders(folder)
if (#dateTable==0) then
print("ERROR: DID NOT FIND ANY DATES!")
return
end
for i = 1, #dateTable do
local message = "d="..dateTable[i]
local headers = {
["Content-Length"] = string.len(message),
["Content-Type"] = "application/x-www-form-urlencoded"
}
local b, c, h = fa.request{
url = "http://"..server.."/"..serverDir.."/cd.php",
method = "POST",
headers = headers,
body = message
}
if (b~=nil) then
b = string.gsub(b, "\n", "")
b = string.gsub(b, "\r", "")
end
if (b and b == "success") then
print("SUCCESS FROM SERVER FOR FOLDER:"..dateTable[i].."<<")
else
print("FAILED RESPONSE FROM SERVER FOR FOLDER:"..dateTable[i].."<<")
print("ADDING TO BLACKLIST")
blackList[#blackList+1] = dateTable[i]
end
end
print("OK FTP Starting...")
walk_directory(folder)
end
local function get_folders(folder)
parseThreads = parseThreads+1
local tableCount = 1
--Get the date range from the file
for file in lfs.dir(folder) do
local path = folder .. "/" .. file
local skip = string.sub( file, 1, 2 ) == "._"
local attr = lfs.attributes(path)
if (not skip) then
if (attr.mode == "file") then
print( "Datesearch Found "..attr.mode..": " .. path )
local dateString = ""
if (attr.modification~=nil) then
local dt = FatDateTimeToTable(attr.modification)
dateString = dt.day.."-"..dt.month.."-"..dt.year
end
if (not exists_in_table(dateTable, dateString)) then
dateTable[#dateTable+1] = dateString
end
elseif attr.mode == "directory" then
print("Datesearch Entering " .. path)
get_folders(path)
end
end
end
parseThreads = parseThreads-1
if (parseThreads == 0) then
create_folders(folder)
end
end
-- wait for wifi to connect
while string.sub(fa.ReadStatusReg(),13,13) ~= "a" do
print("Wifi not connected. Waiting...")
sleep(1000)
end
sleep(30*1000)
get_folders(folder)

Related

Why Does A For Loop Return "attempt to get length of a Vector3 value"

I have no clue what is wrong with this code, it is literally saying that a for loop that is perfectly fine, is attempting to get a vector3 value.
local locations = {}
local Players = game:GetService("Players")
local function SplitString(String)
local CurrentString = ""
local x = 1
for i = 1, #String do
local FullString = string.sub(String,1,i)
local Character = string.sub(String,i,i)
local CurrentString = string.sub(String, x, i)
print(locations[1])
if Character == "," then
CurrentString = string.sub(String,x,i-1)
table.insert(locations,CurrentString)
x = i + 1
CurrentString = string.sub(String, x , i)
print(locations)
end
--Add the character to the string.
if Character == " " then
x = i + 1
CurrentString = string.sub(String, x, i + 1)
end
if #FullString + 1 == #String then
table.insert(locations, CurrentString)
end
end
end
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(char)
local humanoidrootpart = char:WaitForChild("HumanoidRootPart")
wait(5)
while humanoidrootpart do
local location = humanoidrootpart.position
print(location)
SplitString(location)
print(locations[1])
local RoundLocatX = math.floor(locations[1]*50)/50
local RoundLocatZ = math.floor(locations[3]*50)/50
local RoundLocatXLength = RoundLocatX.length
local RoundLocatZLength = RoundLocatZ.length
if RoundLocatX > 50 then
print('hi')
end
wait(1)
end
end)
end)
This is the error:
ServerScriptService.Terrain Generation:9: attempt to get length of a Vector3 value
I would post this on the roblox forum but they are stupid and require some dumb amount of reading time to be able to post on it.
Your error is pointing at this line :
for i = 1, #String do
and saying that you are trying to get the length of a Vector3 object. That means that #String is not working as expected. So looking at the object you passed into the SplitString function...
local location = humanoidrootpart.position
print(location)
SplitString(location)
Your location variable is a Vector3, not a string, and it doesn't support the length operator, #.
But you don't have to parse it as a string to get the values out of it. Since it is a Vector3, you can simply index the different values in it.
local location = humanoidrootpart.Position
local RoundLocatX = math.floor(location.X * 50) / 50
local RoundLocatZ = math.floor(location.Z * 50) / 50

"for limit must be a number" error in roblox (Data Saving and Loading)

I leveled up my character and got some items, when i rejoined, it didn't load my previous data, It gave me level 0 and didn't load any items (it didn't give any output for level problem, but it gave this output for item problem: 'for' limit must be a number), but PLD.ItemNumber is a number, because It is from "ItemNumber" variable in the saving function. How to fix it? Code:
local DataStoreService = game:GetService("DataStoreService");
local PD = DataStoreService:GetDataStore("PlayerData");
function SaveData(Player)
local TableSave = {};
TableSave.Level = Player.PlayerData.Stats.Level.Value;
local TableItems = {};
local ItemNumber = 0;
for i,v in pairs(Player.PlayerData.Items:GetChildren()) do
ItemNumber = ItemNumber + 1;
TableItems["Item"..ItemNumber]={};
local TI = TableItems["Item"..ItemNumber];
TI.ItemName = v.Name;
TI.Level = v.Level.Value;
TI.Damage = v.Damage.Value;
end
table.insert(TableSave,TableItems);
TableSave.ItemNumber = ItemNumber;
PD:SetAsync(Player.userId,TableSave);
end
function LoadData(Player)
local success, err = pcall(function()
PLD = PD:GetAsync(Player.userId);
end)
if success then
Player.PlayerData.Stats.Level.Value = PLD.Level;
for i = 1,PLD.ItemNumber do
local CurrentItem = Instance.new("Folder");
CurrentItem.Name = PLD[1]["Item"..i].ItemName;
local Lv = Instance.new("IntValue");
Lv.Name = "Level";
Lv.Value = PLD[1]["Item"..i].Level;
Lv.Parent = CurrentItem;
local Dm = Instance.new("IntValue");
Dm.Name = "Damage";
Dm.Value = PLD[1]["Item"..i].Damage;
Dm.Parent = CurrentItem;
CurrentItem.Parent=Player.PlayerData.Items;
end
else
print("ERROR IN GET ASYNC");
end
end
game.Players.PlayerRemoving:Connect(function(plr)
repeat wait() until plr.PlayerData;
SaveData(plr);
end)
game.Players.PlayerAdded:Connect(function(plr)
repeat wait() until plr.PlayerData;
LoadData(plr);
end)

Pandoc: Separate table of contents for each section

I am converting Markdown to HTML with Pandoc. With --toc, Pandoc generates a table of contents and inserts it under the first H1 heading (of which there is only one).
I would like it to have a separate, additional table of contents for each subheading. More specifically, I would like a small local table of contents under each H3.
Can Pandoc do that, and if yes, how?
I received an answer on the pandoc-discuss mailing list in the form of a Lua filter.
Quoting from the author of the solution:
Warning: Assumes that all chapters are heading level 2 — change the chapter_level and toc_level variables to match!
Warning: Assumes that each section/chapter has a unique identifier!
local chapter_level = 2
local toc_level = 3
local headings = {}
local current_chapter = nil
local function collect_headings (head)
if head.level == chapter_level then
local id = head.identifier
current_chapter = {
chapter = id,
toc = {},
}
headings[id] = current_chapter
elseif head.level == toc_level then
if current_chapter then
local toc = current_chapter.toc
toc[#toc+1] = head
end
end
return nil
end
local function build_toc (heads)
local toc = {}
for _,head in ipairs(heads) do
local entry = {
pandoc.Plain{
pandoc.Link(
head.content:clone(), -- text
'#' .. head.identifier, -- target
"", -- empty title
pandoc.Attr(
"", -- empty identifier
{'local-toc-link'} -- class
)
)
}
}
toc[#toc+1] = entry
end
return pandoc.Div(
{ pandoc.BulletList(toc) },
pandoc.Attr( "", {'local-toc'} )
)
end
local function insert_toc (head)
if head.level == chapter_level then
local id = head.identifier
if headings[id] then
local toc = build_toc(
headings[id].toc
)
return {head,toc}
end
end
return nil
end
return {
{ Header = collect_headings },
{ Header = insert_toc },
}

Redis interval query

I have data in the form of a tuple (S, T), where S is string and T is integer. Neither S nor T is unique, while their combination is unique. I need to get all tuples where S1 == S2 and |T1 - T2| <= C. Is is possible to do efficiently with Redis?
One way would be to store the data in a list and do the retrieval with a Lua script. First, for tuples of the form (Sn,Tn), insert it like this:
LPUSH myKey S1:T1
LPUSH myKey S2:T2
... and so on
Then, use the Lua script below:
local function split(div,str)
if (div=='') then return false end
local pos,arr = 0,{}
for st,sp in function() return string.find(str,div,pos,true) end do
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1
end
table.insert(arr,string.sub(str,pos))
return arr
end
local key = KEYS[1]
local sVal = ARGV[1]
local tVal = tonumber(ARGV[2])
local cVal = tonumber(ARGV[3])
local length = redis.call("LLEN", key)
if (tonumber(length) == 0) then
return nil
end
local data = redis.call("LRANGE", key, 0, tonumber(length))
local retval = {}
for index,val in pairs(data) do
local parts = split(":", val)
if (parts[1] == sVal and math.abs(tonumber(parts[2]) - tVal) <= cVal) then
table.insert(retval, val)
end
end
return retval
Save it as script.lua and execute it with:
$ redis-cli "$(cat script.lua)" 1 myKey sValue tValue cValue
This will return all tuples (in Sn:Tn form) that matches S1 == S2 and |T1 - T2| <= C.

generating TTT game tree in lua

I am attempting to write a tic-tac-toe game in lua, and plan on using the minimax algorithm to decide non-human moves. The first step in this involves generating a tree of all possible board states from a single input state. I am trying to recursively do this, but cannot seem to figure out how. (I think) I understand conceptually how this should be done, but am having trouble implementing it in lua.
I am trying to structure my tree in the following manner. Each node is a list with two fields.
{ config = {}, children = {} }
Config is a list of integers (0,1,2) that represent empty, X, and O and defines a TTT board state. Children is a list nodes which are all possible board states one move away from the current node.
Here is my function that I currently have to build the game tree
function tree_builder(board, player)
supertemp = {}
for i in ipairs(board.config) do
--iterate through the current board state.
--for each empty location create a new node
--representing a possible board state
if board.config[i] == 0 then
temp = {config = {}, children = {}}
for j in ipairs(board.config) do
temp.config[j] = board.config[j]
end
temp.config[i] = player
temp.children = tree_builder(temp, opposite(player))
supertemp[i] = temp
end
end
return supertemp
end
The function is called in the following manner:
start_board = {config = {1,0,0,0}, children = {} }
start_board.children = tree_builder(start_board, 1)
When I comment out the recursive element of the function (the line "temp.children = builder(temp, opposite(player))") and only generate the first level of children. the output is correct. When called via code that is conceptually identical to (I am using love2D so formatting is different):
for i in pairs(start_board.children) do
print (start_board.children[i].config)
The three children are:
1,1,0,0
1,0,1,0
1,0,0,1
However, once I add the recursive element, the following is output for the same three children
1,1,2,1
1,1,2,1
1,1,2,1
I have been searching online for help and most of what I have found is conceptual in nature or involves implementation in different languages. I believe I have implemented the recursive element wrongly, but cannot wrap my head around the reasons why.
Don't understand what opposite(player) means in temp.children = tree_builder(temp, opposite(player)).
Notice that a recursion need an end condition.
This is my solution under your structure:
local COL = 3
local ROW = 3
local function printBoard( b )
local output = ""
local i = 1
for _,v in ipairs(b.config) do
output = output .. v .. ( (i % COL == 0) and '\n' or ',' )
i = i + 1
end
print( output )
end
local function shallowCopy( t )
local t2 = {}
for k,v in pairs(t) do
t2[k] = v
end
return t2
end
local MAX_STEP = COL * ROW
local ING = 0
local P1 = 1
local P2 = 2
local TIE = 3
local STATUS = { [P1] = "P1 Win", [P2] = "P2 Win", [TIE] = "Tied" }
local start_board = { config = {P1,0,0,0,0,0,0,0,0}, children = {} }
local function checkIfOver( board, step )
local config = board.config
local over = false
--check rows
for i=0,ROW-1 do
over = true
for j=1,COL do
if 0 == config[i*COL+1] or config[i*COL+j] ~= config[i*COL+1] then
over = false
end
end
if over then
return config[i*COL+1]
end
end
--check cols
for i=1,COL do
over = true
for j=0,ROW-1 do
if 0 == config[i] or config[i] ~= config[i+COL*j] then
over = false
end
end
if over then
return config[i]
end
end
--check diagonals
if config[1] ~= 0 and config[1] == config[5] and config[5] == config[9] then
return config[1]
end
if config[3] ~=0 and config[3] == config[5] and config[5] == config[7] then
return config[3]
end
if step >= MAX_STEP then
return TIE
else
return ING
end
end
local function treeBuilder( board, step )
--check the game is over
local over = checkIfOver( board, step )
if over ~= ING then
printBoard( board )
print( STATUS[over], '\n---------\n' )
return
end
local child
local childCfg
for i,v in ipairs(board.config) do
if 0 == v then
child = { config = {}, children = {} }
childCfg = shallowCopy( board.config )
childCfg[i] = (step % 2 == 0) and P1 or P2
child.config = childCfg
table.insert( board.children, child )
treeBuilder( child, step + 1 )
end
end
end
treeBuilder( start_board, 1 )

Resources