--
-- Copyright (C) 2005 dahua Technologies, All Rights Reserved.
-- 2006-4-25 15:54 Z:\wjj\ven\152\DAHUA\Install.lua
-- 2006-9-21  modified by zhongjl for new partition
--

-- Flash 块的大小为64K
local flashSectorSize = 0x10000;

local Installer = {};
Installer.TotalSize      = 0;    -- 总的要写到Flash中的数据大小
Installer.InProgressSize = 0;	 -- 用来在升级过程中控制进度

-- 通知上层应用程序升级的进度信息
-- params:
--    无
-- return:
--    无
function Installer:notify()
	self.InProgressSize = self.InProgressSize + flashSectorSize;

	local progress = self.InProgressSize / self.TotalSize * 100;
	if(progress > 100) then
		progress = 100;
	end;
	progress = tonumber(string.format("%d", progress));

	-- 注意调用方式,不是self::callback,否则会导致回调出错
	self.callback(0x01, progress);
end

-- 根据应用程序提供的信息判断是否可以升级
-- params:
--    无
-- return:
--    成功返回True, 失败返回False以及失败的原因
function Installer:preInstall()
	-- 这里我们需要考虑那些因数？
	-- 硬件版本号 ？
	-- 原有软件的版本号？
	--
	local board = Global.Hardware.board;
	local hwproduct;
	local hwchannel;
	local hwversion;
	local hwfunction;

	print(string.format("Checking hardware information,board name:%s version:%s",
		board.name, board.version));
	if(board.name ~= "DVRxx04HF-X") then
		return false, "Invalid board";
	end

	--升级程序直接从硬件中取值。意义如下
	--hwproduct取值如下: 2 -- LB; 3 -- LBN; 4 -- LB_ATM; 5 -- GBE; 6 -- LK; 7 -- LS
	--hwproduct取值如下: 2 -- IPC4X5; 3 -- A6; 4 -- A8; 5 -- IPVM;
	--hwchannel取值如下: x -- x chans
	--hwfunction取值如下: 0 -- AUDIO; 1 -- MATRIX; 3 -- LOOP

	if(mtd.getinfo)then
		hwproduct,hwchannel,hwversion,hwfunction = mtd.getinfo();
		print(string.format("Checking hardware id info: product = %x; channel = %x; version = %x; function = %x",
			hwproduct,hwchannel,hwversion,hwfunction));
		if((hwproduct ~= 3) and (hwproduct ~= 4)) then
			print(string.format("product not match"));
			return false, "Invalid board";
		end
	end

	-- 这里我们需要校验不同板本的板子程序是否可以通用,
	-- 如目前LB 1.22的与 LB 2.00的板子就不能通用
	-- if(board.version ~= "1.22") then
	--  print(string.format("XXXXXXXXXXXX"));
	--	return false, "Invalid board version";
	-- end

	local vendor = Global.Vendor;

	if(vendor.Name ~= 'General' and vendor.Name ~= 'General_N6') then
		return false, "Invalid vendor";
	end

	return true;
end

-- 升级完成后的处理,如控制系统重启
-- params:
--    无
-- return:
--    无
function Installer:postInstall()
end

-- 升级Flash分区,对于不同的应用,升级的处理可能不一样
-- params	:
-- part		: 表格,包含分区的起始位置以及结束位置
-- filename	: 在升级包中的文件名
-- return	: 无
function Installer:updatePart(part, filename)
	local myfile = self.ZipArchive:open(filename);
	-- 如果该文件打不开,则不需要对此部分进行升级
	if(not myfile) then
		print(string.format("%s not exist", filename));
		return ;
	end

	local addr   = part.baseAddr;
	local endAddr= part.endAddr;
	local data;
	local fldata;

	-- 跳过前面64字节的头,在新的升级程序版本中不需要对此进行校验
	myfile:seek("set", 64);
	while(addr < endAddr) do
		fldata = mtd.read(addr,flashSectorSize);
		data = myfile:read(flashSectorSize);    -- 读入一块Flash扇区大小的数据

		-- if (fldata and data and (fldata ~= data)) then
		-- 当fldata为空的时候为老的程序，直接擦除

		if(data) then
			if((not fldata) or (data and (fldata ~= data))) then
				mtd.erase(addr);
				mtd.write(addr, data);
			end
		  self:notify();
		  addr   = addr   + flashSectorSize;
		else
		  addr = endAddr;
		end
	end

	myfile:close();
end

function Installer:InstallPlayer(filename)
	local myfile = self.ZipArchive:open(filename);

	-- 如果该文件打不开,则不需要对此部分进行升级
	if(not myfile) then
		return ;
	end

	--
	-- TODO:
	-- 读入自动播放器的内容，通过IDE接口写入到硬盘
	--
end

-- 在这里控制整个升级过程
-- params:
--    无
-- return:
--    成功返回True,失败返回Flase以及错误原因
function Installer:execute()
	--[[
	 分区配置信息表,来自知识库 "Flash 分区规划"
	 0x00000000 － 0x00080000  512K     armboot                                 u-boot
	 0x00080000 － 0x00780000  7168K    kernel + root                           romfs
	 0x00780000 － 0x01380000  12288K   application + modules                   user
	 0x01380000 － 0x01780000  4096K    web                                     web
	 0x01780000 － 0x01B00000  3584K    slave:romfs + kernel + pcidriver        slave
	 0x01B00000 － 0x01B80000  512K     custom                                  custom
	 0x01B80000 － 0x01C40000  768K     logo                                    logo
	 0x01C40000 － 0x01D80000  1280K    config                                  
	 0x01D80000 － 0x02000000  2560K    misc
	]]

	local flashPartions =
	{
		boot		= { baseAddr = 0x00000000  , endAddr = 0x00080000 },
		rootfs	= { baseAddr = 0x00080000  , endAddr = 0x01780000 },
		web		  = { baseAddr = 0x01780000  , endAddr = 0x01B00000 },
		custom  = { baseAddr = 0x01B00000  , endAddr = 0x01B80000 },
		logo		= { baseAddr = 0x01B80000  , endAddr = 0x01C40000 },
		config	= { baseAddr = 0x01C40000  , endAddr = 0x01D80000 },
		misc		= { baseAddr = 0x01D80000  , endAddr = 0x02000000 },
	}

	-- self.ZipArchive 这个变量由外部程序设置,如果没有设置程序不应该运行到这里
	assert(self.ZipArchive);
	local zfile = self.ZipArchive;

	local ret, info = self:preInstall();
	if(not ret) then
		return false, info;
	end

	-- 计算要升级的文件大小以及打印升级文件清单
	local TotalSize = 0;
	print("==>Files in archive");
	for file in zfile:files() do
		print(file.filename);
		TotalSize = TotalSize + file.uncompressed_size;
	end
	self.TotalSize  = TotalSize;     -- 总的文件大小
	mtd.init();
	self:updatePart(flashPartions["boot"],	"u-boot.bin.img");
	--mtd.saveenv();
	self:updatePart(flashPartions["rootfs"],	"romfs-x.cramfs.img");
	--self:updatePart(flashPartions["user"],		"user-x.cramfs.img");
    self:updatePart(flashPartions["web"],		"web-x.cramfs.img");
	--self:updatePart(flashPartions["slave"],		"slave-x.cramfs.img");
	self:updatePart(flashPartions["custom"],	"custom-x.cramfs.img");
	self:updatePart(flashPartions["logo"],		"logo-x.cramfs.img");
	--self:InstallPlayer("autoplayer.bin");
	self:postInstall();
	print("==>Upgrade finished.");
	return true;
end

return Installer;
