DOCSIS-Toolkit/Logger4/FrequencyOperation.swift

250 lines
14 KiB
Swift

//
// FrequencyOperation.swift
// Logger4
//
// Created by Kilian Hofmann on 15.06.17.
// Copyright © 2017 Kilian Hofmann. All rights reserved.
//
import Cocoa
class FrequencyOperation: Operation {
// DOCSIS 3.0 Upstream Power Limits as per Specification March 5. 2015
let upstreamOne = ["qpsk": "62.18", "8qam": "58.21", "16qam": "58.21", "32qam": "57", "64qam": "57", "128qam": "-"]
let upstreamTwo = ["qpsk": "59.18", "8qam": "55.21", "16qam": "55.21", "32qam": "54", "64qam": "54", "128qam": "-"]
let upstreamThreeOrFour = ["qpsk": "56.18", "8qam": "52.21", "16qam": "52.21", "32qam": "51", "64qam": "51", "128qam": "-"]
let modulationAdjust: NSDictionary = ["qpsk": "-1.18", "8qam": "-0.21", "16qam": "-0.21", "32qam" : "0", "64qam": "0", "128qam": "0.05"]
// XML Parser
let parser: XMLDictionaryParser = XMLDictionaryParser()
// Data handling
var downstream: Data?
var upstream: Data?
var upstreamBool: Bool = false
var downstreamBool: Bool = false
var dir: NSString = ""
override init() {
}
override func main() {
// Get date for folder structure
let time : Date = Date()
let start: Array<String> = (NSApp.delegate as! AppDelegate).justDate.string(from: time).components(separatedBy: ".")
// File manager
let fileManager: FileManager = FileManager.default
// Make all relevant directories if not present
pthread_mutex_lock(&((NSApp.delegate as! AppDelegate).lock))
dir = NSString(format: "~/KDLog/%@.docsisplist2/%@/%@/", start[2], start[1], start[0])
do {
try fileManager.createDirectory(atPath: dir.expandingTildeInPath, withIntermediateDirectories: true, attributes: nil)
}
catch let error as NSError{
NSLog("ERROR ON SUBDIRECTORY CREATION: \(error.localizedDescription)")
}
pthread_mutex_unlock(&((NSApp.delegate as! AppDelegate).lock))
// URL Requests
let requestDownstream: URLRequest = URLRequest.init(url: URL.init(string: UserDefaults.standard.string(forKey: "downstream")!)!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 4)
let requestUpstream: URLRequest = URLRequest.init(url: URL.init(string: UserDefaults.standard.string(forKey: "upstream")!)!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 4)
// Tasks
let taskDownstream: URLSessionDataTask = (NSApp.delegate as! AppDelegate).urlSession.dataTask(with: requestDownstream){data, response, error in
pthread_mutex_lock(&(NSApp.delegate as! AppDelegate).lock)
self.downstream = data
self.downstreamBool = true
self.handleData(date: time)
pthread_mutex_unlock(&(NSApp.delegate as! AppDelegate).lock)
}
let taskUpstream: URLSessionDataTask = (NSApp.delegate as! AppDelegate).urlSession.dataTask(with: requestUpstream){data, response, error in
pthread_mutex_lock(&(NSApp.delegate as! AppDelegate).lock)
self.upstream = data
self.upstreamBool = true
self.handleData(date: time)
pthread_mutex_unlock(&(NSApp.delegate as! AppDelegate).lock)
}
// Start
taskUpstream.resume()
taskDownstream.resume()
}
func handleData(date: Date) {
// Both returned successfully
if upstream != nil && downstream != nil {
// Parse data
upstreamBool = false
downstreamBool = false
let dictionaryUpstream: Dictionary? = parser.dictionary(with: upstream)
let dictionaryDownstream: Dictionary? = parser.dictionary(with: downstream)
upstream = nil
downstream = nil
// Tracking padding adding
var filesModified: [String] = []
// Upstream is valid
if dictionaryUpstream != nil{
var entry: String = ""
var file: NSString = ""
// Grab channels
let channels: AnyObject = (dictionaryUpstream!["upstream_channel"]) as AnyObject
// We have multiple channels
if channels is [Dictionary<String,AnyObject>] {
// Simplify
let channels: [Dictionary<String,AnyObject>] = (channels as! [Dictionary<String,AnyObject>])
// Step through channels
for index in 0..<channels.count {
// Grab channel
let channel: Dictionary<String,AnyObject> = channels[index]
// We do not have an error
if channel["upstream_modulation"] != nil && (channel["frequency"] as! String) != "status_error" {
// Grab power rating in dBmV
let powerInt: Double? = Double(channel["power_level"] as! String)
// We have valid power rating
if powerInt != nil {
// Grab modulation data
let modulation: NSObject = ((channel["upstream_modulation"]!)["modulation"])! as! NSObject
// Grab power adjustment see DOCSIS 3.0 Specification for more Information)
var adjust: String = ""
if modulation.isKind(of: NSArray.self) {
adjust = modulationAdjust[(((modulation as! NSArray)[0] as! NSDictionary)["mod_type"]!) as! String]! as! String
} else{
adjust = modulationAdjust[((modulation as! NSDictionary)["mod_type"]!) as! String]! as! String
}
let adjustInt: Double = Double(adjust)!
// Add timestamp and power to file entry
entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(String(powerInt! + adjustInt));"
// Add threshold to file entry
switch channels.count {
case 2:
entry += "\(upstreamTwo[modulationAdjust.allKeys(for: adjust)[0] as! String]!)"
case 3:
entry += "\(upstreamThreeOrFour[modulationAdjust.allKeys(for: adjust)[0] as! String]!)"
case 4:
entry += "\(upstreamThreeOrFour[modulationAdjust.allKeys(for: adjust)[0] as! String]!)"
default:
entry += "NaN"
}
// Add ranging status
entry += ";\(channel["ranging_status"] as! String)"
// Add file name to path
file = dir.appending("Upstream \(channel["frequency"]!).hex") as NSString
// Track modification
filesModified.append("Upstream \(channel["frequency"]!).hex")
// Write to file
FileOperations.logUpstream(data: entry, toFrequencyLog: file.expandingTildeInPath)
}
}
}
}
// We have a single channel
else if channels is Dictionary<String,AnyObject> {
// Grab channel
let channel: Dictionary<String,AnyObject> = channels as! Dictionary<String,AnyObject>
// We do not have an error
if channel["upstream_modulation"] != nil && channel["frequency"] as! String != "status_error" {
// Grab power rating in dBmV
let powerInt: Double? = Double(channel["power_level"] as! String)
// We have valid power rating
if powerInt != nil {
// Grab modulation data
let modulation: NSObject = ((channel["upstream_modulation"]!)["modulation"])! as! NSObject
// Grab power adjustment see DOCSIS 3.0 Specification for more Information)
var adjust: String = ""
if modulation.isKind(of: NSArray.self) {
adjust = modulationAdjust[(((modulation as! NSArray)[0] as! NSDictionary)["mod_type"]!) as! String]! as! String
} else{
adjust = modulationAdjust[((modulation as! NSDictionary)["mod_type"]!) as! String]! as! String
}
let adjustInt: Double = Double(adjust)!
// Add data to entry
entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(String(powerInt! + adjustInt));\(upstreamOne[modulationAdjust.allKeys(for: adjust)[0] as! String]!);\(channel["ranging_status"] as! String)"
// Add file name to path
file = dir.appending("Upstream \(channel["frequency"]!).hex") as NSString
// Track modifiction
filesModified.append("Upstream \(channel["frequency"]!).hex")
// Write to file
FileOperations.logUpstream(data: entry, toFrequencyLog: file.expandingTildeInPath)
}
}
}
}
// Downstream is valid
if dictionaryDownstream != nil {
var entry: String = ""
var file: NSString = ""
// Grab channels
let channels: AnyObject = (dictionaryDownstream!["downstream_channel"]) as AnyObject
// We have multiple channels
if channels is [Dictionary<String,AnyObject>] {
// Simplify
let channels: [Dictionary<String, AnyObject>] = channels as! [Dictionary<String, AnyObject>]
// Step through channels
for index in 0..<channels.count {
// Grab channel
let channel: Dictionary<String,AnyObject> = channels[index]
// We do not have an error
if channel["frequency"] as! String != "status_error" {
// Add data to entry
entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(channel["power_level"]!);\(channel["snr"]!)"
// Add file name to path
file = dir.appending("Downstream \(channel["frequency"]!).hex") as NSString
// Tracking modification
filesModified.append("Downstream \(channel["frequency"]!).hex")
// Write to file
FileOperations.logDownstream(data: entry, toFrequencyLog: file.expandingTildeInPath)
}
}
}
// We have a single channel
else if channels is Dictionary<String,AnyObject> {
// Grab channel
let channel: Dictionary<String,AnyObject> = channels as! Dictionary<String,AnyObject>
// We do not have an error
if channel["frequency"] as! String != "status_error" {
// Add data to entry
entry = "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));\(channel["power_level"]!);\(channel["snr"]!)\n"
// Add file name to path
file = dir.appending("Downstream \(channel["frequency"]!).hex") as NSString
// Tracking modification
filesModified.append("Downstream \(channel["frequency"]!).hex")
// Write to file
FileOperations.logDownstream(data: entry, toFrequencyLog: file.expandingTildeInPath)
}
}
}
// Update if not modified
let fileManager = FileManager.default
// Get all filenames in directory
let enumerator:FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: dir.expandingTildeInPath)!
// Step through files
for element in enumerator {
// Check if modified
if !filesModified.contains(element as! String) && (element as! String).contains(".hex") {
logDummie(dir: dir, element: element as! String, date: date)
}
}
}
// Update if both nil (no connection to modem possible)
else if (upstreamBool && downstreamBool) {
upstreamBool = false
downstreamBool = false
let fileManager = FileManager.default
// Get all filenames in directory
let enumerator:FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: dir.expandingTildeInPath)!
// Step through files
for element in enumerator {
logDummie(dir: dir, element: element as! String, date: date)
}
}
}
func logDummie(dir: NSString, element: String, date: Date) {
if element.contains("Upstream") {
FileOperations.logUpstream(data: "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));-;-;-", toFrequencyLog: (dir.appending(element) as NSString).expandingTildeInPath)
} else if element.contains("Downstream") {
FileOperations.logDownstream(data: "\((NSApp.delegate as! AppDelegate).justTime.string(from: date));-;-",
toFrequencyLog: (dir.appending(element) as NSString).expandingTildeInPath)
}
}
}