Skip to content

Commit

Permalink
继续完成 RFID 函数库
Browse files Browse the repository at this point in the history
  • Loading branch information
DigitalPlatform committed Dec 31, 2018
1 parent a852360 commit 9790701
Show file tree
Hide file tree
Showing 9 changed files with 524 additions and 116 deletions.
206 changes: 160 additions & 46 deletions DigitalPlatform.RFID/ChipMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,21 @@ public Element RemoveElement(ElementOID oid)
}

// 根据物理数据构造 (拆包)
public static LogicChip From(byte[] data)
// parameters:
// block_map 每个 char 表示一个 block 的锁定状态。'l' 表示锁定, '.' 表示没有锁定
public static LogicChip From(byte[] data,
int block_size,
string block_map = "")
{
LogicChip chip = new LogicChip();
chip.Parse(data);
chip.Parse(data, block_size, block_map);
return chip;
}

// 解析 data 内容,初始化本对象
public void Parse(byte[] data)
public void Parse(byte[] data,
int block_size,
string block_map)
{
this._isNew = false;
this._elements.Clear();
Expand All @@ -147,7 +153,31 @@ public void Parse(byte[] data)
if (data[start] == 0)
break; // 有时候用 0 填充了余下的全部 bytes
Element element = Element.Parse(data, start, out int bytes);
Debug.Assert(element.StartOffs == start);
this._elements.Add(element);

for (int i = start / block_size; i < (start + bytes) / block_size; i++)
{
if (GetBlockStatus(block_map, i) == 'l')
element.SetLocked(true);
}

// 检查整个 element 占用的每个 block 的 Locked 状态是否一致
for (int i = start / block_size; i < (start + bytes) / block_size; i++)
{
char ch = GetBlockStatus(block_map, i);
if (element.Locked)
{
if (ch != 'l')
throw new Exception($"元素 {element.ToString()} 内发现锁定状态不一致的块");
}
else
{
if (ch != '.')
throw new Exception($"元素 {element.ToString()} 内发现锁定状态不一致的块");
}
}

start += bytes;
}

Expand All @@ -166,7 +196,7 @@ public void Parse(byte[] data)
// 5) 锁定的元素,和非锁定元素区域内部,可以按照 OID 号码排序
// 上述算法有个优势,就是所有锁定元素中间不一定要 block 边界对齐,这样可以节省一点空间
// 但存在一个小问题: Content Parameter 要占用多少 byte? 如果以后元素数量增多,(因为它后面就是锁定区域)它无法变大怎么办?
public void Sort(int total_bytes, int block_size)
public void Sort(int max_bytes, int block_size)
{
SetContentParameter();
if (this.IsNew == true)
Expand Down Expand Up @@ -224,47 +254,64 @@ public void Sort(int total_bytes, int block_size)
start = result;
}

#if NO
CompactionScheme compact_method = CompactionScheme.Null;
if (element.OID == ElementOID.ContentParameter)
compact_method = CompactionScheme.OctectString;
else if (element.OID == ElementOID.OwnerInstitution
|| element.OID == ElementOID.IllBorrowingInstitution)
compact_method = CompactionScheme.ISIL;
#endif
element.OriginData = Element.Compact((int)element.OID,
element.Text,
compact_method,
CompactionScheme.Null,
false);
//if (start != element.StartOffs)
// throw new Exception($"element {element.ToString()} 的 StartOffs {element.StartOffs} 不符合预期值 {start}");

// 如果是最后一个 element(并且它是 WillLock 类型)
// 需要把尾部对齐 block 边界
if (i == this._elements.Count - 1 && element.WillLock)
{
int result = AdjustCount(block_size, element.OriginData.Length);
int delta = result - element.OriginData.Length;

if (delta != 0)
element.OriginData = Element.AdjustPaddingBytes(element.OriginData, delta);
}

start += element.OriginData.Length;
prev_type = current_type;
prev_element = element;
i++;
}

// 如果是最后一个 element(并且它是 WillLock 类型)
// 需要把尾部对齐 block 边界
if (prev_element != null && prev_element.WillLock)
{
int result = AdjustCount(block_size, start);
int delta = result - start;

// 调整 prev_element 的 padding
if (delta != 0)
prev_element.OriginData = Element.AdjustPaddingBytes(prev_element.OriginData, delta);

start = result;
}
}
else
{
foreach (Element element in this._elements)
{
if (element.Locked)
continue;

element.OriginData = Element.Compact((int)element.OID,
element.Text,
CompactionScheme.Null,
false);
}


// 改写状态。Locked 的元素不能动。只能在余下空挡位置,见缝插针组合排列非 Lock 元素
// 组合算法是:每当得到一个区间尺寸,就去查询余下的元素中尺寸组合起来最适合的那些元素
// 可以用一种利用率指标来评价组合好坏。也就是余下的空挡越小,越好
List<int> elements = GetFreeElements();
if (elements.Count == 0)
return; // 没有必要进行排序

bool bRet = GetFreeSegments(total_bytes,
bool bRet = GetFreeSegments(max_bytes,
out List<int> free_segments,
out List<object> anchor_list);

Expand Down Expand Up @@ -353,6 +400,7 @@ void SetElementsPos(
// 填充字节。调整 WillLock 结束点在 block 边界
// area 末尾要调整到 volume 边界
AdjustPadding(
IsTail(area, free_element_layout),
block_size,
area.Volume,
elements);
Expand All @@ -367,7 +415,25 @@ void SetElementsPos(
this._elements.AddRange(results);
}

// 观察一个 OneArea 对象是否在数组中为非 0 Volume 的最后一个
static bool IsTail(OneArea area, List<OneArea> areas)
{
#if NO
for (int i = areas.IndexOf(area) + 1; i < areas.Count; i++)
{
OneArea current = areas[i];
if (current.Volume == 0)
continue;
return false;
}

return true;
#endif
return areas.IndexOf(area) == areas.Count - 1;
}

static void AdjustPadding(
bool is_tail,
int block_size,
int segment_volume,
List<Element> elements)
Expand Down Expand Up @@ -404,13 +470,27 @@ static void AdjustPadding(
prev_type = current_type;
}

if (total < segment_volume)
if (is_tail == false)
{
if (total < segment_volume)
{
int delta = segment_volume - total;
Debug.Assert(delta > 0);
Element element = elements[elements.Count - 1];
// TODO: 注意调整可能导致溢出
element.OriginData = Element.AdjustPaddingBytes(element.OriginData, delta);
}
}
else
{
int delta = segment_volume - total;
Debug.Assert(delta > 0);
Element element = elements[elements.Count - 1];
// TODO: 注意调整可能导致溢出
element.OriginData = Element.AdjustPaddingBytes(element.OriginData, delta);
if (element.WillLock)
{
int result = AdjustCount(block_size, total);
int delta = result - total;
if (delta > 0)
element.OriginData = Element.AdjustPaddingBytes(element.OriginData, delta);
}
}
}

Expand All @@ -426,7 +506,7 @@ static void Sort(List<Element> elements)
return -1;
}
if ((int)b.OID == 1)
return -1;
return 1;

// 比较 WillLock。拟锁定的位置靠后
int lock_a = a.WillLock ? 1 : 0;
Expand Down Expand Up @@ -463,12 +543,13 @@ static List<Element> GetNextGroup(List<object> anchor_list, ref int pos)
}

// 通过 原始尺寸 找到一个元素。返回前会在 elements 中去掉已经找到的元素
static Element FindElementByCount(ref List<Element> elements, int count)
static Element FindElementByCount(ref List<Element> elements,
int count)
{
Element found = null;
foreach (Element element in elements)
{
if (count < 0 && element.Locked)
if (count < 0 && element.WillLock)
{
if (element.OriginData.Length == -count)
{
Expand Down Expand Up @@ -513,13 +594,13 @@ List<int> GetFreeElements()
// 获得当前没有锁定的区段的容量列表
// 返回的数组中,每个整数表示一个区段长度(byte数)
// parameters:
// total_bytes 这是整个芯片的 byte 容量
// max_bytes 这是整个芯片的 byte 容量
// results 返回数值集合。每个元素是一个数值,表示 segment 内可用空间 bytes 数
// anchor_list 便于后期插入操作的锚定列表。里面是所有 locked 类型的元素,还有 null 对象。null 对象位置代表可用的空白区间
// return:
// true 成功
// false 失败
bool GetFreeSegments(int total_bytes,
bool GetFreeSegments(int max_bytes,
out List<int> results,
out List<object> anchor_list)
{
Expand All @@ -536,7 +617,7 @@ bool GetFreeSegments(int total_bytes,

if (locked_elements.Count == 0)
{
results.Add(total_bytes); // 没有任何 locked elements。全部都是可用空间
results.Add(max_bytes); // 没有任何 locked elements。全部都是可用空间
return true;
}

Expand Down Expand Up @@ -575,9 +656,9 @@ bool GetFreeSegments(int total_bytes,
anchor_list.Add(prev_element);
}
// 最后一段空白区
if (start < total_bytes)
if (start < max_bytes)
{
results.Add(total_bytes - start);
results.Add(max_bytes - start);
}

return true;
Expand Down Expand Up @@ -746,7 +827,7 @@ static int AdjustCount(int block_size, int value)
return result;
}

#endregion
#endregion

// 根据当前的所有元素,设置 Content parameter 元素内容
public void SetContentParameter()
Expand All @@ -770,44 +851,77 @@ public void SetContentParameter()
content_parameter.Text = Element.GetHexString(content_parameter.Content);
}

static char NormalMapChar = '.';

// 打包为 byte[] 形态
// TODO: 对于修改的情形,要避开已经 lock 的元素,对元素进行空间布局
public byte[] GetBytes(int total_bytes, int block_size
// bool alignment
)
// parameters:
// block_map 块地图。用
// 字符 'l' 表示原来就是锁定状态的块
// 字符 'w' 表示需要新锁定的块
public byte[] GetBytes(int max_bytes,
int block_size,
out string block_map)
{
block_map = "";

// 先对 elements 排序。确保 PII 和 Content Parameter 元素 index 在前两个
this.Sort(total_bytes, block_size);
this.Sort(max_bytes, block_size);

List<char> map = new List<char>();
int start = 0;
List<byte> results = new List<byte>();
foreach (Element element in this._elements)
{
#if NO
CompactionScheme compact_method = CompactionScheme.Null;
if (element.OID == ElementOID.ContentParameter)
compact_method = CompactionScheme.OctectString;
else if (element.OID == ElementOID.OwnerInstitution
|| element.OID == ElementOID.IllBorrowingInstitution)
compact_method = CompactionScheme.ISIL;
var bytes = Element.Compact((int)element.OID,
element.Text,
compact_method,
false);
#endif
if (element.Locked)
{
if (start != element.StartOffs)
throw new Exception($"element {element.ToString()} 的 StartOffs {element.StartOffs} 不符合预期值 {start}");
}

var bytes = element.OriginData;
results.AddRange(bytes);

// 设置 block map
if (element.WillLock || element.Locked)
{
char ch = NormalMapChar;
if (element.Locked)
ch = 'l';
else if (element.WillLock)
ch = 'w';
for (int i = start / block_size; i < (start + bytes.Length) / block_size; i++)
{
SetBlockStatus(ref map, i, ch);
}
}

start += bytes.Length;
}

if (start > max_bytes)
throw new Exception($"实际产生的 byte 数 {start} 超过限制数 {max_bytes}");

block_map = new string(map.ToArray());
return results.ToArray();
}

static void SetBlockStatus(ref List<char> map, int index, char ch)
{
while (map.Count < index + 1)
{
map.Add(NormalMapChar);
}
map[index] = ch;
}

static char GetBlockStatus(string map, int index)
{
if (index >= map.Length)
return '.';
return map[index];
}

// 根据 XML 数据构造
public static LogicChip FromXml(string xml)
{
Expand Down
Loading

0 comments on commit 9790701

Please sign in to comment.